Merge "Refactored Delete SchemaSet functionality"
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java
index 9c69006..51b2482 100755
--- a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java
@@ -1,7 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2020 Nordix Foundation.
- * Modifications Copyright (C) 2020 Bell Canada.
+ * Modifications Copyright (C) 2020-2022 Bell Canada.
* Modifications Copyright (C) 2021 Pantheon.tech
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -30,6 +30,7 @@
import org.onap.cps.spi.CpsAdminPersistenceService;
import org.onap.cps.spi.entities.AnchorEntity;
import org.onap.cps.spi.entities.DataspaceEntity;
+import org.onap.cps.spi.entities.SchemaSetEntity;
import org.onap.cps.spi.entities.YangResourceModuleReference;
import org.onap.cps.spi.exceptions.AlreadyDefinedException;
import org.onap.cps.spi.exceptions.DataspaceInUseException;
@@ -77,12 +78,12 @@
final int numberOfAssociatedAnchors = anchorRepository.countByDataspace(dataspaceEntity);
if (numberOfAssociatedAnchors != 0) {
throw new DataspaceInUseException(dataspaceName,
- String.format("Dataspace contains %d anchor(s)", numberOfAssociatedAnchors));
+ String.format("Dataspace contains %d anchor(s)", numberOfAssociatedAnchors));
}
final int numberOfAssociatedSchemaSets = schemaSetRepository.countByDataspace(dataspaceEntity);
if (numberOfAssociatedSchemaSets != 0) {
throw new DataspaceInUseException(dataspaceName,
- String.format("Dataspace contains %d schemaset(s)", numberOfAssociatedSchemaSets));
+ String.format("Dataspace contains %d schemaset(s)", numberOfAssociatedSchemaSets));
}
dataspaceRepository.delete(dataspaceEntity);
}
@@ -108,7 +109,17 @@
public Collection<Anchor> getAnchors(final String dataspaceName) {
final var dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
final Collection<AnchorEntity> anchorEntities = anchorRepository.findAllByDataspace(dataspaceEntity);
- return anchorEntities.stream().map(CpsAdminPersistenceServiceImpl::toAnchor).collect(Collectors.toList());
+ return anchorEntities.stream().map(CpsAdminPersistenceServiceImpl::toAnchor).collect(Collectors.toSet());
+ }
+
+ @Override
+ public Collection<Anchor> getAnchors(final String dataspaceName, final String schemaSetName) {
+ final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
+ final SchemaSetEntity schemaSetEntity = schemaSetRepository.getByDataspaceAndName(
+ dataspaceEntity, schemaSetName);
+ return anchorRepository.findAllBySchemaSet(schemaSetEntity)
+ .stream().map(CpsAdminPersistenceServiceImpl::toAnchor)
+ .collect(Collectors.toSet());
}
@Override
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java
index e0f5426..3e39a05 100755
--- a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java
@@ -1,7 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2020 Nordix Foundation
- * Modifications Copyright (C) 2020-2021 Bell Canada.
+ * Modifications Copyright (C) 2020-2022 Bell Canada.
* Modifications Copyright (C) 2021 Pantheon.tech
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -44,17 +44,14 @@
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.exception.ConstraintViolationException;
-import org.onap.cps.spi.CascadeDeleteAllowed;
import org.onap.cps.spi.CpsAdminPersistenceService;
import org.onap.cps.spi.CpsModulePersistenceService;
-import org.onap.cps.spi.entities.AnchorEntity;
import org.onap.cps.spi.entities.SchemaSetEntity;
import org.onap.cps.spi.entities.YangResourceEntity;
import org.onap.cps.spi.entities.YangResourceModuleReference;
import org.onap.cps.spi.exceptions.AlreadyDefinedException;
import org.onap.cps.spi.exceptions.DuplicatedYangResourceException;
import org.onap.cps.spi.exceptions.ModelValidationException;
-import org.onap.cps.spi.exceptions.SchemaSetInUseException;
import org.onap.cps.spi.model.ModuleReference;
import org.onap.cps.spi.repository.AnchorRepository;
import org.onap.cps.spi.repository.DataspaceRepository;
@@ -172,21 +169,16 @@
@Override
@Transactional
- public void deleteSchemaSet(final String dataspaceName, final String schemaSetName,
- final CascadeDeleteAllowed cascadeDeleteAllowed) {
+ public void deleteSchemaSet(final String dataspaceName, final String schemaSetName) {
final var dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
final var schemaSetEntity =
schemaSetRepository.getByDataspaceAndName(dataspaceEntity, schemaSetName);
-
- final Collection<AnchorEntity> anchorEntities = anchorRepository.findAllBySchemaSet(schemaSetEntity);
- if (!anchorEntities.isEmpty()) {
- if (cascadeDeleteAllowed != CascadeDeleteAllowed.CASCADE_DELETE_ALLOWED) {
- throw new SchemaSetInUseException(dataspaceName, schemaSetName);
- }
- fragmentRepository.deleteByAnchorIn(anchorEntities);
- anchorRepository.deleteAll(anchorEntities);
- }
schemaSetRepository.delete(schemaSetEntity);
+ }
+
+ @Override
+ @Transactional
+ public void deleteUnusedYangResourceModules() {
yangResourceRepository.deleteOrphans();
}
@@ -277,6 +269,7 @@
/**
* Convert the specified data integrity violation exception into a CPS duplicated Yang resource exception
* if the cause of the error is a yang checksum database constraint violation.
+ *
* @param originalException the original db exception.
* @param yangResourceEntities the collection of Yang resources involved in the db failure.
* @return an optional converted CPS duplicated Yang resource exception. The optional is empty if the original
@@ -307,6 +300,7 @@
/**
* Get the name of the yang resource having the specified checksum.
+ *
* @param checksum the checksum. Null is supported.
* @param yangResourceEntities the list of yang resources to search among.
* @return the name found or null if none.
@@ -323,6 +317,7 @@
/**
* Get the checksum that caused the constraint violation exception.
+ *
* @param exception the exception having the checksum in error.
* @return the checksum in error or null if not found.
*/
diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsAdminPersistenceServiceSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsAdminPersistenceServiceSpec.groovy
index 4b5b116..2218014 100644
--- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsAdminPersistenceServiceSpec.groovy
+++ b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsAdminPersistenceServiceSpec.groovy
@@ -2,6 +2,7 @@
* ============LICENSE_START=======================================================
* Copyright (C) 2021 Nordix Foundation
* Modifications Copyright (C) 2021 Pantheon.tech
+ * Modifications Copyright (C) 2022 Bell Canada
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -39,7 +40,7 @@
static final String SET_DATA = '/data/anchor.sql'
static final String SAMPLE_DATA_FOR_ANCHORS_WITH_MODULES = '/data/anchors-schemaset-modules.sql'
- static final String DATASPACE_WITH_NO_DATA = 'DATASPACE-002'
+ static final String DATASPACE_WITH_NO_DATA = 'DATASPACE-002-NO-DATA'
static final Integer DELETED_ANCHOR_ID = 3001
static final Long DELETED_FRAGMENT_ID = 4001
@@ -108,12 +109,36 @@
result.size() == expectedAnchors.size()
result.containsAll(expectedAnchors)
where: 'the following data is used'
- dataspaceName || expectedAnchors
- DATASPACE_NAME || [Anchor.builder().name(ANCHOR_NAME1).schemaSetName(SCHEMA_SET_NAME1).dataspaceName(DATASPACE_NAME).build(),
- Anchor.builder().name(ANCHOR_NAME2).schemaSetName(SCHEMA_SET_NAME2).dataspaceName(DATASPACE_NAME).build()]
+ dataspaceName || expectedAnchors
+ DATASPACE_NAME || [Anchor.builder().name(ANCHOR_NAME1).schemaSetName(SCHEMA_SET_NAME1).dataspaceName(DATASPACE_NAME).build(),
+ Anchor.builder().name(ANCHOR_NAME2).schemaSetName(SCHEMA_SET_NAME2).dataspaceName(DATASPACE_NAME).build()]
DATASPACE_WITH_NO_DATA || []
}
+ @Sql([CLEAR_DATA, SET_DATA])
+ def 'Get all anchors associated with schemaset in a dataspace.'() {
+ when: 'anchors are retrieved by dataspace and schema-set'
+ def anchors = objectUnderTest.getAnchors(dataspace, schemasetName)
+ then: ' the response contains expected anchors'
+ anchors == expectedAnchors
+ where:
+ scenario | dataspace | schemasetName || expectedAnchors
+ 'no-anchors' | 'DATASPACE-003' | 'SCHEMA-SET-002-NO-ANCHORS' || Collections.emptySet()
+ 'one-anchor' | 'DATASPACE-001' | 'SCHEMA-SET-001' || Set.of(new Anchor('ANCHOR-001', 'DATASPACE-001', 'SCHEMA-SET-001'))
+ }
+
+ @Sql([CLEAR_DATA, SET_DATA])
+ def 'Error Handling: Get all anchors associated with schemaset in a dataspace.'() {
+ when: 'anchors are retrieved by dataspace and schema-set'
+ def anchors = objectUnderTest.getAnchors(dataspace, schemasetName)
+ then: ' an expected expception is thrown'
+ thrown(expectedException)
+ where:
+ scenario | dataspace | schemasetName || expectedException
+ 'unknown-dataspace' | 'unknown' | 'SCHEMA-SET-002-NO-ANCHORS' || DataspaceNotFoundException
+ 'unknown-schemaset' | 'DATASPACE-001' | 'unknown-schema-set' || SchemaSetNotFoundException
+ }
+
@Sql(CLEAR_DATA)
def 'Get all anchors in unknown dataspace.'() {
when: 'attempt to get all anchors in an unknown dataspace'
@@ -132,7 +157,7 @@
}
@Sql([CLEAR_DATA, SET_DATA])
- def 'delete anchor error scenario: #scenario'(){
+ def 'delete anchor error scenario: #scenario'() {
when: 'delete anchor attempt is performed'
objectUnderTest.deleteAnchor(dataspaceName, anchorName)
then: 'an #expectedException is thrown'
@@ -190,10 +215,10 @@
def thrownException = thrown(expectedException)
thrownException.details.contains(expectedMessageDetails)
where: 'the following data is used'
- scenario | dataspaceName || expectedException | expectedMessageDetails
- 'dataspace name does not exist' | 'unknown' || DataspaceNotFoundException | 'unknown does not exist'
- 'dataspace contains an anchor' | 'DATASPACE-001' || DataspaceInUseException | 'contains 2 anchor(s)'
- 'dataspace contains schemasets' | 'DATASPACE-003' || DataspaceInUseException | 'contains 1 schemaset(s)'
+ scenario | dataspaceName || expectedException | expectedMessageDetails
+ 'dataspace name does not exist' | 'unknown' || DataspaceNotFoundException | 'unknown does not exist'
+ 'dataspace contains an anchor' | 'DATASPACE-001' || DataspaceInUseException | 'contains 2 anchor(s)'
+ 'dataspace contains schemasets' | 'DATASPACE-003' || DataspaceInUseException | 'contains 1 schemaset(s)'
}
}
diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsModulePersistenceServiceIntegrationSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsModulePersistenceServiceIntegrationSpec.groovy
index a223e71..75d6330 100644
--- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsModulePersistenceServiceIntegrationSpec.groovy
+++ b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsModulePersistenceServiceIntegrationSpec.groovy
@@ -1,7 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2021 Nordix Foundation
- * Modifications Copyright (C) 2021 Bell Canada.
+ * Modifications Copyright (C) 2021-2022 Bell Canada.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
@@ -176,50 +176,37 @@
}
@Sql([CLEAR_DATA, SET_DATA])
- def 'Delete schema set with cascade delete prohibited but no anchors using it'() {
+ def 'Delete schema set'() {
when: 'a schema set is deleted with cascade-prohibited option'
- objectUnderTest.deleteSchemaSet(DATASPACE_NAME, SCHEMA_SET_NAME_NO_ANCHORS,
- CASCADE_DELETE_PROHIBITED)
+ objectUnderTest.deleteSchemaSet(DATASPACE_NAME, SCHEMA_SET_NAME_NO_ANCHORS)
then: 'the schema set has been deleted'
schemaSetRepository.findByDataspaceAndName(dataspaceEntity, SCHEMA_SET_NAME_NO_ANCHORS).isPresent() == false
- and: 'any orphaned (not used by any schema set anymore) yang resources are deleted'
- def orphanedResourceId = 3100L
- yangResourceRepository.findById(orphanedResourceId).isPresent() == false
- and: 'any shared (still in use by other schema set) yang resources still persists'
- def sharedResourceId = 3003L
- yangResourceRepository.findById(sharedResourceId).isPresent()
- }
-
- @Sql([CLEAR_DATA, SET_DATA])
- def 'Delete schema set with cascade allowed.'() {
- when: 'a schema set is deleted with cascade-allowed option'
- objectUnderTest.deleteSchemaSet(DATASPACE_NAME, SCHEMA_SET_NAME_WITH_ANCHORS_AND_DATA,
- CASCADE_DELETE_ALLOWED)
- then: 'the schema set has been deleted'
- schemaSetRepository
- .findByDataspaceAndName(dataspaceEntity, SCHEMA_SET_NAME_WITH_ANCHORS_AND_DATA).isPresent() == false
- and: 'the associated anchors are removed'
- def associatedAnchorsIds = [ 6001, 6002 ]
- associatedAnchorsIds.each {anchorRepository.findById(it).isPresent() == false }
- and: 'the fragment(s) under those anchors are removed'
- def fragmentUnderAnchor1Id = 7001L
- fragmentRepository.findById(fragmentUnderAnchor1Id).isPresent() == false
- and: 'the shared resources still persist'
- def sharedResourceIds = [ 3003L, 3004L ]
- sharedResourceIds.each {yangResourceRepository.findById(it).isPresent() }
}
@Sql([CLEAR_DATA, SET_DATA])
def 'Delete schema set error scenario: #scenario.'() {
when: 'attempt to delete a schema set where #scenario'
- objectUnderTest.deleteSchemaSet(dataspaceName, schemaSetName, CASCADE_DELETE_PROHIBITED)
+ objectUnderTest.deleteSchemaSet(dataspaceName, schemaSetName)
then: 'an #expectedException is thrown'
thrown(expectedException)
where: 'the following data is used'
scenario | dataspaceName | schemaSetName || expectedException
'dataspace does not exist' | 'unknown' | 'not-relevant' || DataspaceNotFoundException
'schema set does not exists' | DATASPACE_NAME | 'unknown' || SchemaSetNotFoundException
- 'cascade prohibited but schema set in use' | DATASPACE_NAME | SCHEMA_SET_NAME_WITH_ANCHORS_AND_DATA || SchemaSetInUseException
+ }
+
+ @Sql([CLEAR_DATA, SET_DATA])
+ def 'Delete only orphan Yang Resources'() {
+ given: 'a schema set is deleted and and yang resource is not used anymore'
+ objectUnderTest.deleteSchemaSet(DATASPACE_NAME, SCHEMA_SET_NAME_NO_ANCHORS)
+ when: 'orphan yang resources are deleted'
+ objectUnderTest.deleteUnusedYangResourceModules()
+ then: 'any orphaned (not used by any schema set anymore) yang resources are deleted'
+ def orphanedResourceId = 3100L
+ yangResourceRepository.findById(orphanedResourceId).isPresent() == false
+ and: 'any shared (still in use by other schema set) yang resources still persists'
+ def sharedResourceId = 3003L
+ yangResourceRepository.findById(sharedResourceId).isPresent()
}
def assertSchemaSetPersisted(expectedDataspaceName,
diff --git a/cps-ri/src/test/resources/data/anchor.sql b/cps-ri/src/test/resources/data/anchor.sql
index c9240f7..40fc44c 100644
--- a/cps-ri/src/test/resources/data/anchor.sql
+++ b/cps-ri/src/test/resources/data/anchor.sql
@@ -2,7 +2,7 @@
============LICENSE_START=======================================================
Copyright (C) 2020 Pantheon.tech
Modifications Copyright (C) 2020 Nordix Foundation.
- Modifications Copyright (C) 2021 Bell Canada.
+ Modifications Copyright (C) 2021-2022 Bell Canada.
================================================================================
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -22,13 +22,13 @@
INSERT INTO DATASPACE (ID, NAME) VALUES
(1001, 'DATASPACE-001'),
- (1002, 'DATASPACE-002'),
+ (1002, 'DATASPACE-002-NO-DATA'),
(1003, 'DATASPACE-003');
INSERT INTO SCHEMA_SET (ID, NAME, DATASPACE_ID) VALUES
(2001, 'SCHEMA-SET-001', 1001),
(2002, 'SCHEMA-SET-002', 1001),
- (2003, 'SCHEMA-SET-002', 1003);
+ (2003, 'SCHEMA-SET-002-NO-ANCHORS', 1003);
INSERT INTO ANCHOR (ID, NAME, DATASPACE_ID, SCHEMA_SET_ID) VALUES
(3001, 'ANCHOR-001', 1001, 2001),
diff --git a/cps-service/src/main/java/org/onap/cps/api/CpsAdminService.java b/cps-service/src/main/java/org/onap/cps/api/CpsAdminService.java
index 7ba9599..44f7f77 100755
--- a/cps-service/src/main/java/org/onap/cps/api/CpsAdminService.java
+++ b/cps-service/src/main/java/org/onap/cps/api/CpsAdminService.java
@@ -1,7 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2020 Nordix Foundation
- * Modifications Copyright (C) 2020 Bell Canada.
+ * Modifications Copyright (C) 2020-2022 Bell Canada.
* Modifications Copyright (C) 2021 Pantheon.tech
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,7 +23,6 @@
package org.onap.cps.api;
import java.util.Collection;
-import org.checkerframework.checker.nullness.qual.NonNull;
import org.onap.cps.spi.exceptions.AlreadyDefinedException;
import org.onap.cps.spi.exceptions.CpsException;
import org.onap.cps.spi.model.Anchor;
@@ -39,14 +38,14 @@
* @param dataspaceName dataspace name
* @throws AlreadyDefinedException if dataspace with same name already exists
*/
- void createDataspace(@NonNull String dataspaceName);
+ void createDataspace(String dataspaceName);
/**
* Delete dataspace.
*
* @param dataspaceName the name of the dataspace to delete
*/
- void deleteDataspace(@NonNull String dataspaceName);
+ void deleteDataspace(String dataspaceName);
/**
* Create an Anchor.
@@ -56,7 +55,7 @@
* @param anchorName anchor name
* @throws CpsException if input data is invalid.
*/
- void createAnchor(@NonNull String dataspaceName, @NonNull String schemaSetName, @NonNull String anchorName);
+ void createAnchor(String dataspaceName, String schemaSetName, String anchorName);
/**
* Read all anchors in the given dataspace.
@@ -64,8 +63,16 @@
* @param dataspaceName dataspace name
* @return a collection of anchors
*/
- @NonNull
- Collection<Anchor> getAnchors(@NonNull String dataspaceName);
+ Collection<Anchor> getAnchors(String dataspaceName);
+
+ /**
+ * Read all anchors associated the given schema-set in the given dataspace.
+ *
+ * @param dataspaceName dataspace name
+ * @param schemaSetName schema-set name
+ * @return a collection of anchors
+ */
+ Collection<Anchor> getAnchors(String dataspaceName, String schemaSetName);
/**
* Get an anchor in the given dataspace using the anchor name.
@@ -74,8 +81,7 @@
* @param anchorName anchor name
* @return an anchor
*/
- @NonNull
- Anchor getAnchor(@NonNull String dataspaceName, @NonNull String anchorName);
+ Anchor getAnchor(String dataspaceName, String anchorName);
/**
* Delete anchor by name in given dataspace.
@@ -83,14 +89,13 @@
* @param dataspaceName dataspace name
* @param anchorName anchor name
*/
- void deleteAnchor(@NonNull String dataspaceName, @NonNull String anchorName);
+ void deleteAnchor(String dataspaceName, String anchorName);
/**
* Query anchor names for the given module names in the provided dataspace.
*
- *
* @param dataspaceName dataspace name
- * @param moduleNames a collection of module names
+ * @param moduleNames a collection of module names
* @return a collection of anchor names in the given dataspace. The schema set for each anchor must include all the
* given module names
*/
diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsAdminServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsAdminServiceImpl.java
index d831793..d30a657 100755
--- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsAdminServiceImpl.java
+++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsAdminServiceImpl.java
@@ -1,7 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2020 Nordix Foundation
- * Modifications Copyright (C) 2020 Bell Canada.
+ * Modifications Copyright (C) 2020-2022 Bell Canada.
* Modifications Copyright (C) 2021 Pantheon.tech
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -57,6 +57,11 @@
}
@Override
+ public Collection<Anchor> getAnchors(final String dataspaceName, final String schemaSetName) {
+ return cpsAdminPersistenceService.getAnchors(dataspaceName, schemaSetName);
+ }
+
+ @Override
public Anchor getAnchor(final String dataspaceName, final String anchorName) {
return cpsAdminPersistenceService.getAnchor(dataspaceName, anchorName);
}
diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java
index 1032641..e967817 100644
--- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java
+++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java
@@ -2,6 +2,7 @@
* ============LICENSE_START=======================================================
* Copyright (C) 2020-2021 Nordix Foundation
* Modifications Copyright (C) 2020-2021 Pantheon.tech
+ * Modifications Copyright (C) 2022 Bell Canada
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,23 +25,38 @@
import java.util.Collection;
import java.util.List;
import java.util.Map;
+import org.onap.cps.api.CpsAdminService;
import org.onap.cps.api.CpsModuleService;
import org.onap.cps.spi.CascadeDeleteAllowed;
import org.onap.cps.spi.CpsModulePersistenceService;
+import org.onap.cps.spi.exceptions.SchemaSetInUseException;
+import org.onap.cps.spi.model.Anchor;
import org.onap.cps.spi.model.ModuleReference;
import org.onap.cps.spi.model.SchemaSet;
import org.onap.cps.yang.YangTextSchemaSourceSetBuilder;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
@Service("CpsModuleServiceImpl")
public class CpsModuleServiceImpl implements CpsModuleService {
- @Autowired
private CpsModulePersistenceService cpsModulePersistenceService;
-
- @Autowired
private YangTextSchemaSourceSetCache yangTextSchemaSourceSetCache;
+ private CpsAdminService cpsAdminService;
+
+ /**
+ * Create an instance of CpsModuleServiceImpl.
+ *
+ * @param cpsModulePersistenceService cpsModulePersistenceService
+ * @param yangTextSchemaSourceSetCache yangTextSchemaSourceSetCache
+ * @param cpsAdminService cpsAdminService
+ */
+ public CpsModuleServiceImpl(final CpsModulePersistenceService cpsModulePersistenceService,
+ final YangTextSchemaSourceSetCache yangTextSchemaSourceSetCache, final CpsAdminService cpsAdminService) {
+ this.cpsModulePersistenceService = cpsModulePersistenceService;
+ this.yangTextSchemaSourceSetCache = yangTextSchemaSourceSetCache;
+ this.cpsAdminService = cpsAdminService;
+ }
@Override
public void createSchemaSet(final String dataspaceName, final String schemaSetName,
@@ -53,10 +69,10 @@
@Override
public void createSchemaSetFromModules(final String dataspaceName, final String schemaSetName,
- final Map<String, String> newYangResourcesModuleNameToContentMap,
- final List<ModuleReference> moduleReferences) {
+ final Map<String, String> newYangResourcesModuleNameToContentMap,
+ final List<ModuleReference> moduleReferences) {
cpsModulePersistenceService.storeSchemaSetFromModules(dataspaceName, schemaSetName,
- newYangResourcesModuleNameToContentMap, moduleReferences);
+ newYangResourcesModuleNameToContentMap, moduleReferences);
}
@@ -69,9 +85,18 @@
}
@Override
+ @Transactional
public void deleteSchemaSet(final String dataspaceName, final String schemaSetName,
final CascadeDeleteAllowed cascadeDeleteAllowed) {
- cpsModulePersistenceService.deleteSchemaSet(dataspaceName, schemaSetName, cascadeDeleteAllowed);
+ final Collection<Anchor> anchors = cpsAdminService.getAnchors(dataspaceName, schemaSetName);
+ if (!anchors.isEmpty() && isCascadeDeleteProhibited(cascadeDeleteAllowed)) {
+ throw new SchemaSetInUseException(dataspaceName, schemaSetName);
+ }
+ for (final Anchor anchor : anchors) {
+ cpsAdminService.deleteAnchor(dataspaceName, anchor.getName());
+ }
+ cpsModulePersistenceService.deleteSchemaSet(dataspaceName, schemaSetName);
+ cpsModulePersistenceService.deleteUnusedYangResourceModules();
}
@Override
@@ -84,4 +109,8 @@
final String anchorName) {
return cpsModulePersistenceService.getYangResourceModuleReferences(dataspaceName, anchorName);
}
+
+ private boolean isCascadeDeleteProhibited(final CascadeDeleteAllowed cascadeDeleteAllowed) {
+ return CascadeDeleteAllowed.CASCADE_DELETE_PROHIBITED == cascadeDeleteAllowed;
+ }
}
diff --git a/cps-service/src/main/java/org/onap/cps/spi/CpsAdminPersistenceService.java b/cps-service/src/main/java/org/onap/cps/spi/CpsAdminPersistenceService.java
index 9553700..dd4059d 100755
--- a/cps-service/src/main/java/org/onap/cps/spi/CpsAdminPersistenceService.java
+++ b/cps-service/src/main/java/org/onap/cps/spi/CpsAdminPersistenceService.java
@@ -1,7 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2020 Nordix Foundation.
- * Modifications Copyright (C) 2020 Bell Canada.
+ * Modifications Copyright (C) 2020-2022 Bell Canada.
* Modifications Copyright (C) 2021 Pantheon.tech
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,7 +23,6 @@
package org.onap.cps.spi;
import java.util.Collection;
-import org.checkerframework.checker.nullness.qual.NonNull;
import org.onap.cps.spi.exceptions.AlreadyDefinedException;
import org.onap.cps.spi.model.Anchor;
@@ -38,14 +37,14 @@
* @param dataspaceName dataspace name
* @throws AlreadyDefinedException if dataspace with same name already exists
*/
- void createDataspace(@NonNull String dataspaceName);
+ void createDataspace(String dataspaceName);
/**
* Delete dataspace.
*
* @param dataspaceName the name of the dataspace to delete
*/
- void deleteDataspace(@NonNull String dataspaceName);
+ void deleteDataspace(String dataspaceName);
/**
* Create an Anchor.
@@ -54,7 +53,16 @@
* @param schemaSetName schema set name
* @param anchorName anchor name
*/
- void createAnchor(@NonNull String dataspaceName, @NonNull String schemaSetName, @NonNull String anchorName);
+ void createAnchor(String dataspaceName, String schemaSetName, String anchorName);
+
+ /**
+ * Read all anchors associated the given schema-set in the given dataspace.
+ *
+ * @param dataspaceName dataspace name
+ * @param schemaSetName schema-set name
+ * @return a collection of anchors
+ */
+ Collection<Anchor> getAnchors(String dataspaceName, String schemaSetName);
/**
* Read all anchors in the given a dataspace.
@@ -62,8 +70,7 @@
* @param dataspaceName dataspace name
* @return a collection of anchors
*/
- @NonNull
- Collection<Anchor> getAnchors(@NonNull String dataspaceName);
+ Collection<Anchor> getAnchors(String dataspaceName);
/**
* Query anchor names for the given module names in the provided dataspace.
@@ -83,8 +90,7 @@
* @param anchorName anchor name
* @return an anchor
*/
- @NonNull
- Anchor getAnchor(@NonNull String dataspaceName, @NonNull String anchorName);
+ Anchor getAnchor(String dataspaceName, String anchorName);
/**
* Delete anchor by name in given dataspace.
@@ -92,5 +98,5 @@
* @param dataspaceName dataspace name
* @param anchorName anchor name
*/
- void deleteAnchor(@NonNull String dataspaceName, @NonNull String anchorName);
+ void deleteAnchor(String dataspaceName, String anchorName);
}
diff --git a/cps-service/src/main/java/org/onap/cps/spi/CpsModulePersistenceService.java b/cps-service/src/main/java/org/onap/cps/spi/CpsModulePersistenceService.java
index 9b50f9e..e082734 100755
--- a/cps-service/src/main/java/org/onap/cps/spi/CpsModulePersistenceService.java
+++ b/cps-service/src/main/java/org/onap/cps/spi/CpsModulePersistenceService.java
@@ -1,7 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2020 Nordix Foundation
- * Modifications Copyright (C) 2020 Bell Canada.
+ * Modifications Copyright (C) 2020-2022 Bell Canada.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,8 +24,6 @@
import java.util.Collection;
import java.util.List;
import java.util.Map;
-import org.checkerframework.checker.nullness.qual.NonNull;
-import org.onap.cps.spi.exceptions.DataInUseException;
import org.onap.cps.spi.model.ModuleReference;
/**
@@ -40,8 +38,7 @@
* @param schemaSetName schema set name
* @param yangResourcesNameToContentMap YANG resources (files) map where key is a name and value is content
*/
- void storeSchemaSet(@NonNull String dataspaceName, @NonNull String schemaSetName,
- @NonNull Map<String, String> yangResourcesNameToContentMap);
+ void storeSchemaSet(String dataspaceName, String schemaSetName, Map<String, String> yangResourcesNameToContentMap);
/**
* Stores a schema set from new modules and existing modules.
@@ -49,45 +46,36 @@
* @param dataspaceName Dataspace name
* @param schemaSetName Schema set name
* @param newYangResourcesModuleNameToContentMap YANG resources map where key is a module name and value is content
- * @param moduleReferences List of YANG resources module references
+ * @param moduleReferences List of YANG resources module references
*/
- void storeSchemaSetFromModules(@NonNull String dataspaceName, @NonNull String schemaSetName,
- @NonNull Map<String, String> newYangResourcesModuleNameToContentMap,
- @NonNull List<ModuleReference> moduleReferences);
+ void storeSchemaSetFromModules(String dataspaceName, String schemaSetName,
+ Map<String, String> newYangResourcesModuleNameToContentMap, List<ModuleReference> moduleReferences);
/**
* Deletes Schema Set.
*
- * @param dataspaceName dataspace name
- * @param schemaSetName schema set name
- * @param cascadeDeleteAllowed indicates the allowance to remove associated anchors and data if exist
- * @throws DataInUseException if cascadeDeleteAllowed is set to CASCADE_DELETE_PROHIBITED and there
- * is associated anchor record exists in database
+ * @param dataspaceName dataspace name
+ * @param schemaSetName schema set name
*/
- void deleteSchemaSet(@NonNull String dataspaceName, @NonNull String schemaSetName,
- @NonNull CascadeDeleteAllowed cascadeDeleteAllowed);
+ void deleteSchemaSet(String dataspaceName, String schemaSetName);
/**
* Returns YANG resources per specific dataspace / schemaSetName.
*
- * @param dataspaceName dataspace name
+ * @param dataspaceName dataspace name
* @param schemaSetName schema set name
* @return YANG resources (files) map where key is a name and value is content
*/
- @NonNull
- Map<String, String> getYangSchemaResources(@NonNull String dataspaceName,
- @NonNull String schemaSetName);
+ Map<String, String> getYangSchemaResources(String dataspaceName, String schemaSetName);
/**
* Returns YANG resources per specific dataspace / anchorName.
*
* @param dataspaceName dataspace name
- * @param anchorName anchor name
+ * @param anchorName anchor name
* @return YANG resources (files) map where key is a name and value is content
*/
- @NonNull
- Map<String, String> getYangSchemaSetResources(@NonNull String dataspaceName,
- @NonNull String anchorName);
+ Map<String, String> getYangSchemaSetResources(String dataspaceName, String anchorName);
/**
* Returns YANG resources module references for the given dataspace name.
@@ -105,4 +93,9 @@
* @return a collection of module names and revisions
*/
Collection<ModuleReference> getYangResourceModuleReferences(String dataspaceName, String anchorName);
+
+ /**
+ * Remove unused Yang Resource Modules.
+ */
+ void deleteUnusedYangResourceModules();
}
diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAdminServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAdminServiceImplSpec.groovy
index 6d1f586..fe6e460 100755
--- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAdminServiceImplSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsAdminServiceImplSpec.groovy
@@ -1,7 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2020 Nordix Foundation
- * Modifications Copyright (C) 2020 Bell Canada.
+ * Modifications Copyright (C) 2020-2022 Bell Canada.
* Modifications Copyright (C) 2021 Pantheon.tech
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -56,6 +56,14 @@
objectUnderTest.getAnchors('someDataspace') == anchors
}
+ def 'Retrieve all anchors for schema-set.'() {
+ given: 'that anchor is associated with the dataspace and schemaset'
+ def anchors = [new Anchor()]
+ mockCpsAdminPersistenceService.getAnchors('someDataspace', 'someSchemaSet') >> anchors
+ expect: 'the collection provided by persistence service is returned as result'
+ objectUnderTest.getAnchors('someDataspace', 'someSchemaSet') == anchors
+ }
+
def 'Retrieve anchor for dataspace and provided anchor name.'() {
given: 'that anchor name is associated with the dataspace'
Anchor anchor = new Anchor()
diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy
index 2c23aa1..b020570 100644
--- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy
@@ -2,7 +2,7 @@
* ============LICENSE_START=======================================================
* Copyright (C) 2020-2021 Nordix Foundation
* Modifications Copyright (C) 2020-2021 Pantheon.tech
- * Modifications Copyright (C) 2020-2021 Bell Canada.
+ * Modifications Copyright (C) 2020-2022 Bell Canada.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,8 +23,11 @@
package org.onap.cps.api.impl
import org.onap.cps.TestUtils
+import org.onap.cps.api.CpsAdminService
import org.onap.cps.spi.CpsModulePersistenceService
import org.onap.cps.spi.exceptions.ModelValidationException
+import org.onap.cps.spi.exceptions.SchemaSetInUseException
+import org.onap.cps.spi.model.Anchor
import org.onap.cps.spi.model.ExtendedModuleReference
import org.onap.cps.spi.model.ModuleReference
import org.spockframework.spring.SpringBean
@@ -35,19 +38,21 @@
import org.springframework.cache.caffeine.CaffeineCacheManager
import org.springframework.test.context.ContextConfiguration
import spock.lang.Specification
-
import static org.onap.cps.spi.CascadeDeleteAllowed.CASCADE_DELETE_ALLOWED
import static org.onap.cps.spi.CascadeDeleteAllowed.CASCADE_DELETE_PROHIBITED
@SpringBootTest
@EnableCaching
-@ContextConfiguration(classes = [YangTextSchemaSourceSetCache.class, CpsModuleServiceImpl.class])
+@ContextConfiguration(classes = [YangTextSchemaSourceSetCache, CpsModuleServiceImpl])
class CpsModuleServiceImplSpec extends Specification {
@SpringBean
CpsModulePersistenceService mockModuleStoreService = Mock()
@SpringBean
+ CpsAdminService mockCpsAdminService = Mock()
+
+ @SpringBean
CacheManager cacheManager = new CaffeineCacheManager("yangSchema")
@Autowired
@@ -105,18 +110,51 @@
1 * mockModuleStoreService.getYangSchemaResources('someDataspace', 'someSchemaSet') >> yangResourcesNameToContentMap
}
- def 'Delete set by name and dataspace with #cascadeDeleteOption.'() {
- when: 'schema set deletion is requested'
- objectUnderTest.deleteSchemaSet(dataspaceName, schemaSetname, cascadeDeleteOption)
- then: 'persistence service method is invoked with same parameters'
- mockModuleStoreService.deleteSchemaSet(dataspaceName, schemaSetname, cascadeDeleteOption)
+ def 'Delete schema-set when cascade is allowed.'() {
+ given: '#numberOfAnchors anchors are associated with schemaset'
+ def associatedAnchors = createAnchors(numberOfAnchors)
+ mockCpsAdminService.getAnchors('my-dataspace', 'my-schemaset') >> associatedAnchors
+ when: 'schema set deletion is requested with cascade allowed'
+ objectUnderTest.deleteSchemaSet('my-dataspace', 'my-schemaset', CASCADE_DELETE_ALLOWED)
+ then: 'anchor deletion is called #numberOfAnchors times'
+ numberOfAnchors * mockCpsAdminService.deleteAnchor('my-dataspace', _)
+ and: 'persistence service method is invoked with same parameters'
+ 1 * mockModuleStoreService.deleteSchemaSet('my-dataspace', 'my-schemaset')
+ and: 'orphan yang resources are deleted'
+ 1 * mockModuleStoreService.deleteUnusedYangResourceModules()
where: 'following parameters are used'
- dataspaceName | schemaSetname | cascadeDeleteOption
- 'dataspace-1' | 'schemas-set-1' | CASCADE_DELETE_ALLOWED
- 'dataspace-2' | 'schemas-set-2' | CASCADE_DELETE_PROHIBITED
+ numberOfAnchors << [0, 3]
}
- def 'Get all yang resources module references.'(){
+ def 'Delete schema-set when cascade is prohibited.'() {
+ given: 'no anchors are associated with schemaset'
+ mockCpsAdminService.getAnchors('my-dataspace', 'my-schemaset') >> Collections.emptyList()
+ when: 'schema set deletion is requested with cascade allowed'
+ objectUnderTest.deleteSchemaSet('my-dataspace', 'my-schemaset', CASCADE_DELETE_PROHIBITED)
+ then: 'no anchors are deleted'
+ 0 * mockCpsAdminService.deleteAnchor(_, _)
+ and: 'persistence service method is invoked with same parameters'
+ 1 * mockModuleStoreService.deleteSchemaSet('my-dataspace', 'my-schemaset')
+ and: 'orphan yang resources are deleted'
+ 1 * mockModuleStoreService.deleteUnusedYangResourceModules()
+ }
+
+ def 'Delete schema-set when cascade is prohibited and schema-set has anchors.'() {
+ given: '2 anchors are associated with schemaset'
+ mockCpsAdminService.getAnchors('my-dataspace', 'my-schemaset') >> createAnchors(2)
+ when: 'schema set deletion is requested with cascade allowed'
+ objectUnderTest.deleteSchemaSet('my-dataspace', 'my-schemaset', CASCADE_DELETE_PROHIBITED)
+ then: 'Schema-Set in Use exception is thrown'
+ thrown(SchemaSetInUseException)
+ }
+
+ def createAnchors(int anchorCount) {
+ def anchors = []
+ (0..<anchorCount).each { anchors.add(new Anchor("my-anchor-$it", 'my-dataspace', 'my-schemaset')) }
+ return anchors
+ }
+
+ def 'Get all yang resources module references.'() {
given: 'an already present module reference'
def moduleReferences = [new ExtendedModuleReference()]
mockModuleStoreService.getYangResourceModuleReferences('someDataspaceName') >> moduleReferences
@@ -125,7 +163,7 @@
}
- def 'Get all yang resources module references for the given dataspace name and anchor name.'(){
+ def 'Get all yang resources module references for the given dataspace name and anchor name.'() {
given: 'the module store service service returns a list module references'
def moduleReferences = [new ModuleReference()]
mockModuleStoreService.getYangResourceModuleReferences('someDataspaceName', 'someAnchorName') >> moduleReferences
diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/E2ENetworkSliceSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/E2ENetworkSliceSpec.groovy
index eefa86e..d18bcf5 100755
--- a/cps-service/src/test/groovy/org/onap/cps/api/impl/E2ENetworkSliceSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/E2ENetworkSliceSpec.groovy
@@ -1,7 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2021 Nordix Foundation.
- * Modifications Copyright (C) 2021 Bell Canada.
+ * Modifications Copyright (C) 2021-2022 Bell Canada.
* Modifications Copyright (C) 2021 Pantheon.tech
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,7 +22,6 @@
package org.onap.cps.api.impl
-import java.time.OffsetDateTime
import org.onap.cps.TestUtils
import org.onap.cps.api.CpsAdminService
import org.onap.cps.notification.NotificationService
@@ -38,9 +37,10 @@
def mockDataStoreService = Mock(CpsDataPersistenceService)
def mockCpsAdminService = Mock(CpsAdminService)
def mockNotificationService = Mock(NotificationService)
- def cpsModuleServiceImpl = new CpsModuleServiceImpl()
def cpsDataServiceImpl = new CpsDataServiceImpl()
def mockYangTextSchemaSourceSetCache = Mock(YangTextSchemaSourceSetCache)
+ def cpsModuleServiceImpl = new CpsModuleServiceImpl(mockModuleStoreService,
+ mockYangTextSchemaSourceSetCache,mockCpsAdminService )
def dataspaceName = 'someDataspace'
def anchorName = 'someAnchor'
@@ -52,8 +52,6 @@
cpsDataServiceImpl.cpsAdminService = mockCpsAdminService
cpsDataServiceImpl.yangTextSchemaSourceSetCache = mockYangTextSchemaSourceSetCache
cpsDataServiceImpl.notificationService = mockNotificationService
- cpsModuleServiceImpl.yangTextSchemaSourceSetCache = mockYangTextSchemaSourceSetCache
- cpsModuleServiceImpl.cpsModulePersistenceService = mockModuleStoreService
}
def 'E2E model can be parsed by CPS.'() {