import org.onap.cps.ncmp.rest.model.DmiErrorMessageDmiResponse;
import org.onap.cps.ncmp.rest.model.ErrorMessage;
import org.onap.cps.spi.exceptions.AlreadyDefinedException;
-import org.onap.cps.spi.exceptions.AlreadyDefinedExceptionBatch;
import org.onap.cps.spi.exceptions.CpsException;
import org.onap.cps.spi.exceptions.DataNodeNotFoundException;
import org.onap.cps.spi.exceptions.DataValidationException;
return buildErrorResponse(HttpStatus.BAD_REQUEST, exception);
}
- @ExceptionHandler({AlreadyDefinedException.class, AlreadyDefinedExceptionBatch.class })
+ @ExceptionHandler({AlreadyDefinedException.class})
public static ResponseEntity<Object> handleAlreadyDefinedExceptions(final Exception exception) {
return buildErrorResponse(HttpStatus.CONFLICT, exception);
}
import org.onap.cps.ncmp.rest.mapper.DataOperationRequestMapper
import org.onap.cps.ncmp.rest.util.DeprecationHelper
import org.onap.cps.spi.exceptions.AlreadyDefinedException
-import org.onap.cps.spi.exceptions.AlreadyDefinedExceptionBatch
import org.onap.cps.spi.exceptions.CpsException
import org.onap.cps.spi.exceptions.DataNodeNotFoundException
import org.onap.cps.spi.exceptions.DataValidationException
then: 'an HTTP response is returned with correct message and details'
assertTestResponse(response, expectedErrorCode, expectedErrorMessage, expectedErrorDetails)
where:
- scenario | exception || expectedErrorDetails | expectedErrorMessage | expectedErrorCode
- 'CPS' | new CpsException(sampleErrorMessage, sampleErrorDetails) || sampleErrorDetails | sampleErrorMessage | INTERNAL_SERVER_ERROR
- 'NCMP-server' | new ServerNcmpException(sampleErrorMessage, sampleErrorDetails) || null | sampleErrorMessage | INTERNAL_SERVER_ERROR
- 'NCMP-client' | new DmiRequestException(sampleErrorMessage, sampleErrorDetails) || null | sampleErrorMessage | BAD_REQUEST
- 'DataNode Validation' | new DataNodeNotFoundException('myDataspaceName', 'myAnchorName') || null | 'DataNode not found' | NOT_FOUND
- 'other' | new IllegalStateException(sampleErrorMessage) || null | sampleErrorMessage | INTERNAL_SERVER_ERROR
- 'Data Node Not Found' | new DataNodeNotFoundException('myDataspaceName', 'myAnchorName') || 'DataNode not found' | 'DataNode not found' | NOT_FOUND
- 'Existing entry' | new AlreadyDefinedException('name',null) || 'name already exists' | 'Already defined exception' | CONFLICT
- 'Existing entries' | new AlreadyDefinedExceptionBatch(["x[@id='abc']"]) || 'Check logs for details' | null | CONFLICT
+ scenario | exception || expectedErrorDetails | expectedErrorMessage | expectedErrorCode
+ 'CPS' | new CpsException(sampleErrorMessage, sampleErrorDetails) || sampleErrorDetails | sampleErrorMessage | INTERNAL_SERVER_ERROR
+ 'NCMP-server' | new ServerNcmpException(sampleErrorMessage, sampleErrorDetails) || null | sampleErrorMessage | INTERNAL_SERVER_ERROR
+ 'NCMP-client' | new DmiRequestException(sampleErrorMessage, sampleErrorDetails) || null | sampleErrorMessage | BAD_REQUEST
+ 'DataNode Validation' | new DataNodeNotFoundException('myDataspaceName', 'myAnchorName') || null | 'DataNode not found' | NOT_FOUND
+ 'other' | new IllegalStateException(sampleErrorMessage) || null | sampleErrorMessage | INTERNAL_SERVER_ERROR
+ 'Data Node Not Found' | new DataNodeNotFoundException('myDataspaceName', 'myAnchorName') || 'DataNode not found' | 'DataNode not found' | NOT_FOUND
+ 'Existing entry' | new AlreadyDefinedException('name',null) || 'name already exists' | 'Already defined exception' | CONFLICT
+ 'Existing entries' | AlreadyDefinedException.forDataNodes(['A', 'B'], 'myAnchorName') || '2 data node(s) already exist' | 'Already defined exception' | CONFLICT
}
def 'Post request with exception returns correct HTTP Status.'() {
import org.onap.cps.ncmp.api.models.DmiPluginRegistrationResponse;
import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
import org.onap.cps.spi.FetchDescendantsOption;
-import org.onap.cps.spi.exceptions.AlreadyDefinedExceptionBatch;
+import org.onap.cps.spi.exceptions.AlreadyDefinedException;
import org.onap.cps.spi.exceptions.CpsException;
import org.onap.cps.spi.exceptions.DataNodeNotFoundException;
import org.onap.cps.spi.exceptions.DataValidationException;
try {
lcmEventsCmHandleStateHandler.updateCmHandleStateBatch(cmHandleStatePerCmHandle);
return CmHandleRegistrationResponse.createSuccessResponses(cmHandleIds);
- } catch (final AlreadyDefinedExceptionBatch alreadyDefinedExceptionBatch) {
+ } catch (final AlreadyDefinedException alreadyDefinedException) {
return CmHandleRegistrationResponse.createFailureResponses(
- alreadyDefinedExceptionBatch.getAlreadyDefinedXpaths(),
+ alreadyDefinedException.getAlreadyDefinedObjectNames(),
RegistrationError.CM_HANDLE_ALREADY_EXIST);
} catch (final Exception exception) {
return CmHandleRegistrationResponse.createFailureResponses(cmHandleIds, exception);
import org.onap.cps.api.CpsModuleService;
import org.onap.cps.ncmp.api.impl.exception.NcmpStartUpException;
import org.onap.cps.spi.exceptions.AlreadyDefinedException;
-import org.onap.cps.spi.exceptions.AlreadyDefinedExceptionBatch;
import org.onap.cps.spi.model.Dataspace;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
final String nodeData = "{\"" + dataNodeName + "\":{}}";
try {
cpsDataService.saveData(dataspaceName, anchorName, nodeData, OffsetDateTime.now());
- } catch (final AlreadyDefinedExceptionBatch exception) {
+ } catch (final AlreadyDefinedException exception) {
log.info("Creating new data node '{}' failed as data node already exists", dataNodeName);
} catch (final Exception exception) {
log.debug("Creating data node for subscription model failed: {}", exception.getMessage());
import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse
import org.onap.cps.ncmp.api.models.DmiPluginRegistration
import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
-import org.onap.cps.spi.exceptions.AlreadyDefinedExceptionBatch
+import org.onap.cps.spi.exceptions.AlreadyDefinedException
import org.onap.cps.spi.exceptions.DataNodeNotFoundException
import org.onap.cps.spi.exceptions.DataValidationException
import org.onap.cps.spi.exceptions.SchemaSetNotFoundException
new NcmpServiceCmHandle(cmHandleId: 'cmhandle3')])
and: 'cm-handle creation is successful for 1st and 3rd; failed for 2nd'
def xpath = "somePathWithId[@id='cmhandle2']"
- mockLcmEventsCmHandleStateHandler.updateCmHandleStateBatch(*_) >> { throw new AlreadyDefinedExceptionBatch([xpath]) }
+ mockLcmEventsCmHandleStateHandler.updateCmHandleStateBatch(*_) >> { throw AlreadyDefinedException.forDataNodes([xpath], 'some-context') }
when: 'registration is updated to create cm-handles'
def response = objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
then: 'a response is received for all cm-handles'
assert it.errorText == expectedErrorText
}
where:
- scenario | exception || expectedError | expectedErrorText
- 'cm-handle already exist' | new AlreadyDefinedExceptionBatch(["'path[@id='cmhandle']".toString()]) || CM_HANDLE_ALREADY_EXIST | 'cm-handle already exists'
- 'unknown exception while registering cm-handle' | new RuntimeException('Failed') || UNKNOWN_ERROR | 'Failed'
+ scenario | exception || expectedError | expectedErrorText
+ 'cm-handle already exist' | AlreadyDefinedException.forDataNodes(["path[@id='cmhandle']"], 'some-context') || CM_HANDLE_ALREADY_EXIST | 'cm-handle already exists'
+ 'unknown exception while registering cm-handle' | new RuntimeException('Failed') || UNKNOWN_ERROR | 'Failed'
}
def 'Update CM-Handle: Update Operation Response is added to the response'() {
import org.onap.cps.api.CpsModuleService
import org.onap.cps.ncmp.api.impl.exception.NcmpStartUpException
import org.onap.cps.spi.exceptions.AlreadyDefinedException
-import org.onap.cps.spi.exceptions.AlreadyDefinedExceptionBatch
import org.onap.cps.spi.exceptions.DataValidationException
import org.onap.cps.spi.exceptions.SchemaSetNotFoundException
import org.onap.cps.spi.model.Dataspace
def 'Create top level node fails due to an AlreadyDefined exception'() {
given: 'the saving of the node data will throw an Already Defined exception'
mockCpsDataService.saveData(*_) >>
- { throw new AlreadyDefinedExceptionBatch(['/xpath']) }
+ { throw AlreadyDefinedException.forDataNodes(['/xpath'], "sampleContextName") }
when: 'the method to onboard model is called'
objectUnderTest.onboardSubscriptionModel(yangResourceToContentMap)
then: 'no exception thrown'
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2020 Pantheon.tech
- * Modifications Copyright (C) 2021-2022 Nordix Foundation
+ * Modifications Copyright (C) 2021-2023 Nordix Foundation
* Modifications Copyright (C) 2022 TechMahindra Ltd.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
import org.onap.cps.rest.controller.QueryRestController;
import org.onap.cps.rest.model.ErrorMessage;
import org.onap.cps.spi.exceptions.AlreadyDefinedException;
-import org.onap.cps.spi.exceptions.AlreadyDefinedExceptionBatch;
import org.onap.cps.spi.exceptions.CpsAdminException;
import org.onap.cps.spi.exceptions.CpsException;
import org.onap.cps.spi.exceptions.CpsPathException;
? HttpStatus.NOT_FOUND : HttpStatus.BAD_REQUEST, exception);
}
- @ExceptionHandler({DataInUseException.class, AlreadyDefinedException.class, AlreadyDefinedExceptionBatch.class})
+ @ExceptionHandler({DataInUseException.class, AlreadyDefinedException.class})
public static ResponseEntity<Object> handleDataInUseException(final Exception exception) {
return buildErrorResponse(HttpStatus.CONFLICT, exception);
}
import org.onap.cps.spi.entities.DataspaceEntity;
import org.onap.cps.spi.entities.FragmentEntity;
import org.onap.cps.spi.exceptions.AlreadyDefinedException;
-import org.onap.cps.spi.exceptions.AlreadyDefinedExceptionBatch;
import org.onap.cps.spi.exceptions.ConcurrencyException;
import org.onap.cps.spi.exceptions.CpsAdminException;
import org.onap.cps.spi.exceptions.CpsPathException;
for (final Collection<DataNode> newList : newLists) {
try {
addChildrenDataNodes(anchorEntity, parentNodeXpath, newList);
- } catch (final AlreadyDefinedExceptionBatch e) {
- failedXpaths.addAll(e.getAlreadyDefinedXpaths());
+ } catch (final AlreadyDefinedException alreadyDefinedException) {
+ failedXpaths.addAll(alreadyDefinedException.getAlreadyDefinedObjectNames());
}
}
if (!failedXpaths.isEmpty()) {
- throw new AlreadyDefinedExceptionBatch(failedXpaths);
+ throw AlreadyDefinedException.forDataNodes(failedXpaths, anchorEntity.getName());
}
}
try {
fragmentRepository.save(newChildAsFragmentEntity);
} catch (final DataIntegrityViolationException e) {
- throw AlreadyDefinedException.forDataNode(newChild.getXpath(), anchorEntity.getName(), e);
+ throw AlreadyDefinedException.forDataNodes(Collections.singletonList(newChild.getXpath()),
+ anchorEntity.getName());
}
}
}
}
if (!failedXpaths.isEmpty()) {
- throw new AlreadyDefinedExceptionBatch(failedXpaths);
+ throw AlreadyDefinedException.forDataNodes(failedXpaths, anchorEntity.getName());
}
}
}
}
if (!failedXpaths.isEmpty()) {
- throw new AlreadyDefinedExceptionBatch(failedXpaths);
+ throw AlreadyDefinedException.forDataNodes(failedXpaths, anchorEntity.getName());
}
}
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2021 Nordix Foundation
+ * Copyright (C) 2021-2023 Nordix Foundation
* Modifications Copyright (C) 2021 Pantheon.tech
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
package org.onap.cps.spi.exceptions;
import java.util.Collection;
+import java.util.Collections;
+import lombok.Getter;
/**
* Already defined exception. Indicates the cps object with same name already exists.
public class AlreadyDefinedException extends CpsAdminException {
private static final long serialVersionUID = 501929839139881112L;
+ public static final String ALREADY_DEFINED_EXCEPTION_MESSAGE = "Already defined exception";
+
+ @Getter
+ private final Collection<String> alreadyDefinedObjectNames;
- /**
- * Constructor.
- *
- * @param objectType the object type
- * @param objectName the name of the object
- * @param contextName the context name e.g. Anchor or Dataspace
- * @param cause the cause of the exception
- */
private AlreadyDefinedException(final String objectType, final String objectName, final String contextName,
final Throwable cause) {
- super("Already defined exception",
+ super(ALREADY_DEFINED_EXCEPTION_MESSAGE,
String.format("%s with name %s already exists for %s.", objectType, objectName, contextName), cause);
+ alreadyDefinedObjectNames = Collections.singletonList(objectName);
+ }
+
+ private AlreadyDefinedException(final String objectType, final Collection<String> objectNames,
+ final String contextName) {
+ super(ALREADY_DEFINED_EXCEPTION_MESSAGE,
+ String.format("%d %s already exist for %s.", objectNames.size(), objectType, contextName));
+ alreadyDefinedObjectNames = objectNames;
}
- /**
- * Constructor.
- *
- * @param objectName the name of the object
- * @param cause the cause of the exception
- */
private AlreadyDefinedException(final String objectName, final Throwable cause) {
- super("Already defined exception", String.format("%s already exists.", objectName), cause);
+ super(ALREADY_DEFINED_EXCEPTION_MESSAGE, String.format("%s already exists.", objectName), cause);
+ alreadyDefinedObjectNames = Collections.singletonList(objectName);
}
public static AlreadyDefinedException forDataspace(final String dataspaceName, final Throwable cause) {
return new AlreadyDefinedException("Schema Set", schemaSetName, contextName, cause);
}
- public static AlreadyDefinedException forDataNode(final String xpath, final String contextName,
- final Throwable cause) {
- return new AlreadyDefinedException("Data node", xpath, contextName, cause);
- }
-
- public static AlreadyDefinedException forDataNodes(final Collection<String> xpaths, final String contextName,
- final Throwable cause) {
- final var name = String.format("(one or more) of %s", xpaths);
- return new AlreadyDefinedException("Data node", name, contextName, cause);
+ public static AlreadyDefinedException forDataNodes(final Collection<String> xpaths, final String contextName) {
+ return new AlreadyDefinedException("data node(s)", xpaths, contextName);
}
}
+++ /dev/null
-/*
- * ============LICENSE_START=======================================================
- * Copyright (C) 2022 Nordix Foundation
- * ================================================================================
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * SPDX-License-Identifier: Apache-2.0
- * ============LICENSE_END=========================================================
- */
-
-package org.onap.cps.spi.exceptions;
-
-import java.util.Collection;
-import lombok.Getter;
-
-public class AlreadyDefinedExceptionBatch extends RuntimeException {
-
- @Getter
- private final Collection<String> alreadyDefinedXpaths;
-
- public AlreadyDefinedExceptionBatch(final Collection<String> alreadyDefinedXPaths) {
- this.alreadyDefinedXpaths = alreadyDefinedXPaths;
- }
-}
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2021 Nordix Foundation
+ * Copyright (C) 2021-2023 Nordix Foundation
* Modifications Copyright (C) 2021 Pantheon.tech
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* SPDX-License-Identifier: Apache-2.0
* ============LICENSE_END=========================================================
*/
+
package org.onap.cps.spi.exceptions
import spock.lang.Specification
== "Anchor with name ${anchorName} already exists for ${dataspaceName}."
}
- def 'Creating a exception that a data node already exists.'() {
+ def 'Creating a exception that data nodes already exist.'() {
expect: 'the exception details contains the correct message with xpath and dataspace name.'
- (AlreadyDefinedException.forDataNode(xpath, dataspaceName, rootCause)).details
- == "Data node with name ${xpath} already exists for ${dataspaceName}."
+ (AlreadyDefinedException.forDataNodes([xpath], anchorName)).details
+ == "1 data node(s) already exist for ${anchorName}."
}
def 'Creating a exception that a schema set already exists.'() {
import org.onap.cps.api.CpsDataService
import org.onap.cps.integration.base.FunctionalSpecBase
import org.onap.cps.spi.FetchDescendantsOption
-import org.onap.cps.spi.exceptions.AlreadyDefinedExceptionBatch
+import org.onap.cps.spi.exceptions.AlreadyDefinedException
import org.onap.cps.spi.exceptions.AnchorNotFoundException
import org.onap.cps.spi.exceptions.CpsAdminException
import org.onap.cps.spi.exceptions.CpsPathException
def json = '{"bookstore": {} }'
objectUnderTest.saveData(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, json, now)
then: 'an exception that (one cps paths is) already defined is thrown '
- def exceptionThrown = thrown(AlreadyDefinedExceptionBatch)
- exceptionThrown.alreadyDefinedXpaths == [ '/bookstore' ] as Set
+ def exceptionThrown = thrown(AlreadyDefinedException)
+ exceptionThrown.alreadyDefinedObjectNames == ['/bookstore' ] as Set
cleanup:
restoreBookstoreDataAnchor(1)
}
when: 'attempt to save the list element'
objectUnderTest.saveListElements(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1 , '/bookstore', json, now)
then: 'an exception that (one cps paths is) already defined is thrown '
- def exceptionThrown = thrown(AlreadyDefinedExceptionBatch)
- exceptionThrown.alreadyDefinedXpaths == [ '/bookstore/categories[@code=\'1\']' ] as Set
+ def exceptionThrown = thrown(AlreadyDefinedException)
+ exceptionThrown.alreadyDefinedObjectNames == ['/bookstore/categories[@code=\'1\']' ] as Set
and: 'there is now one extra data nodes'
assert originalCountBookstoreChildNodes + 1 == countDataNodesInBookstore()
cleanup:
when: 'the batches of new list element(s) are saved'
objectUnderTest.saveListElementsBatch(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1 , '/bookstore', [jsonNewElement, jsonExistingElement], now)
then: 'an already defined (batch) exception is thrown for the existing path'
- def exceptionThrown = thrown(AlreadyDefinedExceptionBatch)
- assert exceptionThrown.alreadyDefinedXpaths == [ '/bookstore/categories[@code=\'1\']' ] as Set
+ def exceptionThrown = thrown(AlreadyDefinedException)
+ assert exceptionThrown.alreadyDefinedObjectNames == ['/bookstore/categories[@code=\'1\']' ] as Set
and: 'there is now one extra data node'
assert originalCountBookstoreChildNodes + 1 == countDataNodesInBookstore()
cleanup:
where: 'the following data is used'
scenario | parentXpath | json || expectedException
'parent does not exist' | '/bookstore/categories[@code="unknown"]' | '{"books": [ {"title":"new"} ] } ' || DataNodeNotFoundException
- 'already existing child' | '/bookstore' | '{"categories": [ {"code":"1"} ] }' || AlreadyDefinedExceptionBatch
+ 'already existing child' | '/bookstore' | '{"categories": [ {"code":"1"} ] }' || AlreadyDefinedException
}
def 'Add multiple child data nodes with partial success.'() {
when: 'attempt to add the elements'
objectUnderTest.saveData(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '/bookstore', json, now)
then: 'an already defined (batch) exception is thrown for the existing path'
- def thrown = thrown(AlreadyDefinedExceptionBatch)
- assert thrown.alreadyDefinedXpaths == [ "/bookstore/categories[@code='1']" ] as Set
+ def thrown = thrown(AlreadyDefinedException)
+ assert thrown.alreadyDefinedObjectNames == [ "/bookstore/categories[@code='1']" ] as Set
and: 'the new data node has been added i.e. can be retrieved'
assert objectUnderTest.getDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, '/bookstore/categories[@code="new"]', DIRECT_CHILDREN_ONLY).size() == 1
}