diff options
5 files changed, 61 insertions, 20 deletions
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java index d00d2119b1..5aad404e61 100755 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java @@ -93,8 +93,12 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService final DmiPluginRegistration dmiPluginRegistration) { dmiPluginRegistration.validateDmiPluginRegistration(); final DmiPluginRegistrationResponse dmiPluginRegistrationResponse = new DmiPluginRegistrationResponse(); - dmiPluginRegistrationResponse.setRemovedCmHandles( - parseAndRemoveCmHandlesInDmiRegistration(dmiPluginRegistration.getRemovedCmHandles())); + + if (!dmiPluginRegistration.getRemovedCmHandles().isEmpty()) { + dmiPluginRegistrationResponse.setRemovedCmHandles( + parseAndRemoveCmHandlesInDmiRegistration(dmiPluginRegistration.getRemovedCmHandles())); + } + if (!dmiPluginRegistration.getCreatedCmHandles().isEmpty()) { dmiPluginRegistrationResponse.setCreatedCmHandles( parseAndCreateCmHandlesInDmiRegistrationAndSyncModules(dmiPluginRegistration)); @@ -321,15 +325,13 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService final List<String> tobeRemovedCmHandles) { final List<CmHandleRegistrationResponse> cmHandleRegistrationResponses = new ArrayList<>(tobeRemovedCmHandles.size()); + + setState(tobeRemovedCmHandles, CmHandleState.DELETING); + for (final String cmHandleId : tobeRemovedCmHandles) { try { - final YangModelCmHandle yangModelCmHandle = inventoryPersistence.getYangModelCmHandle(cmHandleId); - lcmEventsCmHandleStateHandler.updateCmHandleState(yangModelCmHandle, - CmHandleState.DELETING); deleteCmHandleFromDbAndModuleSyncMap(cmHandleId); cmHandleRegistrationResponses.add(CmHandleRegistrationResponse.createSuccessResponse(cmHandleId)); - lcmEventsCmHandleStateHandler.updateCmHandleState(yangModelCmHandle, - CmHandleState.DELETED); } catch (final DataNodeNotFoundException dataNodeNotFoundException) { log.error("Unable to find dataNode for cmHandleId : {} , caused by : {}", cmHandleId, dataNodeNotFoundException.getMessage()); @@ -347,9 +349,22 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService CmHandleRegistrationResponse.createFailureResponse(cmHandleId, exception)); } } + + setState(tobeRemovedCmHandles, CmHandleState.DELETED); + return cmHandleRegistrationResponses; } + private void setState(final List<String> tobeRemovedCmHandles, final CmHandleState cmHandleState) { + final Map<YangModelCmHandle, CmHandleState> cmHandleIdsToBeRemoved = new HashMap<>(); + for (final String cmHandleId : tobeRemovedCmHandles) { + cmHandleIdsToBeRemoved.put( + inventoryPersistence.getYangModelCmHandle(cmHandleId), + cmHandleState); + } + lcmEventsCmHandleStateHandler.updateCmHandleStateBatch(cmHandleIdsToBeRemoved); + } + private void deleteCmHandleFromDbAndModuleSyncMap(final String cmHandleId) { inventoryPersistence.deleteSchemaSetWithCascade(cmHandleId); inventoryPersistence.deleteListOrListElement("/dmi-registry/cm-handles[@id='" + cmHandleId + "']"); diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy index e6c79f89a1..1ebd69eb60 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy @@ -252,7 +252,7 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { when: 'registration is updated to delete cmhandle' def response = objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration) then: 'the cmHandle state is updated to "DELETING"' - 1 * mockLcmEventsCmHandleStateHandler.updateCmHandleState(_, CmHandleState.DELETING) + 1 * mockLcmEventsCmHandleStateHandler.updateCmHandleStateBatch(_) and: 'method to delete relevant schema set is called once' 1 * mockInventoryPersistence.deleteSchemaSetWithCascade(_) and: 'method to delete relevant list/list element is called once' @@ -264,7 +264,7 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification { assert it.cmHandle == 'cmhandle' } and: 'the cmHandle state is updated to "DELETED"' - 1 * mockLcmEventsCmHandleStateHandler.updateCmHandleState(_, CmHandleState.DELETED) + 1 * mockLcmEventsCmHandleStateHandler.updateCmHandleStateBatch(_) where: scenario | schemaSetExist 'schema-set exists and can be deleted successfully' | true diff --git a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java index 8293f642c7..5b0683e979 100644 --- a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java +++ b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java @@ -461,9 +461,11 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService @Override public void updateDataLeaves(final String dataspaceName, final String anchorName, final String xpath, - final Map<String, Serializable> leaves) { + final Map<String, Serializable> updateLeaves) { final FragmentEntity fragmentEntity = getFragmentWithoutDescendantsByXpath(dataspaceName, anchorName, xpath); - fragmentEntity.setAttributes(jsonObjectMapper.asJsonString(leaves)); + final String currentLeavesAsString = fragmentEntity.getAttributes(); + final String mergedLeaves = mergeLeaves(updateLeaves, currentLeavesAsString); + fragmentEntity.setAttributes(mergedLeaves); fragmentRepository.save(fragmentEntity); } @@ -708,4 +710,14 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService private static boolean isRootXpath(final String xpath) { return "/".equals(xpath) || "".equals(xpath); } + + private String mergeLeaves(final Map<String, Serializable> updateLeaves, final String currentLeavesAsString) { + final Map<String, Serializable> currentLeavesAsMap = currentLeavesAsString.isEmpty() + ? new HashMap<>() : jsonObjectMapper.convertJsonString(currentLeavesAsString, Map.class); + currentLeavesAsMap.putAll(updateLeaves); + if (currentLeavesAsMap.isEmpty()) { + return ""; + } + return jsonObjectMapper.asJsonString(currentLeavesAsMap); + } } diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy index 30d438cb42..01c1dc70ec 100644 --- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy +++ b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy @@ -178,6 +178,25 @@ class CpsDataPersistenceServiceSpec extends Specification { 1 * mockSessionManager.lockAnchor('mySessionId', 'myDataspaceName', 'myAnchorName', 123L) } + def 'update data node leaves: #scenario'(){ + given: 'A node exists for the given xpath' + mockFragmentRepository.getByDataspaceAndAnchorAndXpath(_, _, '/some/xpath') >> new FragmentEntity(xpath: '/some/xpath', attributes: existingAttributes) + when: 'the node leaves are updated' + objectUnderTest.updateDataLeaves('some-dataspace', 'some-anchor', '/some/xpath', newAttributes as Map<String, Serializable>) + then: 'the fragment entity saved has the original and new attributes' + 1 * mockFragmentRepository.save({fragmentEntity -> { + assert fragmentEntity.getXpath() == '/some/xpath' + assert fragmentEntity.getAttributes() == mergedAttributes + }}) + where: 'the following attributes combinations are used' + scenario | existingAttributes | newAttributes | mergedAttributes + 'add new leaf' | '{"existing":"value"}' | ["new":"value"] | '{"existing":"value","new":"value"}' + 'update existing leaf' | '{"existing":"value"}' | ["existing":"value2"] | '{"existing":"value2"}' + 'update nothing with nothing' | '' | [] | '' + 'update with nothing' | '{"existing":"value"}' | [] | '{"existing":"value"}' + 'update with same value' | '{"existing":"value"}' | ["existing":"value"] | '{"existing":"value"}' + } + def 'update data node and descendants: #scenario'(){ given: 'mocked responses' mockFragmentRepository.getByDataspaceAndAnchorAndXpath(_, _, '/test/xpath') >> new FragmentEntity(xpath: '/test/xpath', childFragments: []) diff --git a/cps-service/src/main/java/org/onap/cps/utils/XmlFileUtils.java b/cps-service/src/main/java/org/onap/cps/utils/XmlFileUtils.java index 10e1f50b54..09f2e16c6a 100644 --- a/cps-service/src/main/java/org/onap/cps/utils/XmlFileUtils.java +++ b/cps-service/src/main/java/org/onap/cps/utils/XmlFileUtils.java @@ -50,8 +50,8 @@ import org.xml.sax.SAXException; public class XmlFileUtils { private static final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); - private static final TransformerFactory transformerFactory = TransformerFactory.newInstance(); private static boolean isNewDocumentBuilderFactoryInstance = true; + private static final TransformerFactory transformerFactory = TransformerFactory.newInstance(); private static boolean isNewTransformerFactoryInstance = true; private static final Pattern XPATH_PROPERTY_REGEX = Pattern.compile("\\[@(\\S{1,100})=['\\\"](\\S{1,100})['\\\"]\\]"); @@ -161,15 +161,9 @@ public class XmlFileUtils { } } - private static DocumentBuilderFactory getDocumentBuilderFactory() throws ParserConfigurationException { + private static DocumentBuilderFactory getDocumentBuilderFactory() { + if (isNewDocumentBuilderFactoryInstance) { - documentBuilderFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); - documentBuilderFactory.setFeature("http://xml.org/sax/features/external-general-entities", false); - documentBuilderFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); - documentBuilderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); - documentBuilderFactory.setXIncludeAware(false); - documentBuilderFactory.setExpandEntityReferences(false); - documentBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); documentBuilderFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); documentBuilderFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); isNewDocumentBuilderFactoryInstance = false; @@ -179,6 +173,7 @@ public class XmlFileUtils { } private static TransformerFactory getTransformerFactory() { + if (isNewTransformerFactoryInstance) { transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, ""); |