Internal Server Error when creating the same data node twice 33/119333/9
authorniamhcore <niamh.core@est.tech>
Mon, 15 Mar 2021 15:54:12 +0000 (15:54 +0000)
committerNiamh Core <niamh.core@est.tech>
Wed, 24 Mar 2021 09:19:24 +0000 (09:19 +0000)
This change adds a generic exception handler class for a already defined object and handles a JsonSyntaxException.

Issue-ID: CPS-290
Signed-off-by: niamhcore <niamh.core@est.tech>
Change-Id: Ie645237b5dd5b8e2b1d074c5613e7da560f57484

19 files changed:
cps-rest/src/main/java/org/onap/cps/rest/exceptions/CpsRestExceptionHandler.java
cps-rest/src/test/groovy/org/onap/cps/rest/controller/AdminRestControllerSpec.groovy
cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy
cps-rest/src/test/groovy/org/onap/cps/rest/exceptions/CpsRestExceptionHandlerSpec.groovy
cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java
cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java
cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java
cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsAdminPersistenceServiceSpec.groovy
cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsDataPersistenceServiceSpec.groovy
cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsModulePersistenceServiceSpec.groovy
cps-service/src/main/java/org/onap/cps/api/CpsAdminService.java
cps-service/src/main/java/org/onap/cps/spi/CpsAdminPersistenceService.java
cps-service/src/main/java/org/onap/cps/spi/exceptions/AlreadyDefinedException.java [new file with mode: 0644]
cps-service/src/main/java/org/onap/cps/spi/exceptions/AnchorAlreadyDefinedException.java [deleted file]
cps-service/src/main/java/org/onap/cps/spi/exceptions/DataspaceAlreadyDefinedException.java [deleted file]
cps-service/src/main/java/org/onap/cps/spi/exceptions/SchemaSetAlreadyDefinedException.java [deleted file]
cps-service/src/main/java/org/onap/cps/utils/YangUtils.java
cps-service/src/test/groovy/org/onap/cps/spi/exceptions/CpsExceptionsSpec.groovy
cps-service/src/test/groovy/org/onap/cps/utils/YangUtilsSpec.groovy

index 7719417..0437e70 100755 (executable)
@@ -1,6 +1,7 @@
 /*
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2020 Pantheon.tech
+ *  Copyright (C) 2021 Nordix Foundation
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -24,6 +25,7 @@ import org.onap.cps.rest.controller.AdminRestController;
 import org.onap.cps.rest.controller.DataRestController;
 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.CpsAdminException;
 import org.onap.cps.spi.exceptions.CpsException;
 import org.onap.cps.spi.exceptions.CpsPathException;
@@ -42,8 +44,6 @@ import org.springframework.web.bind.annotation.RestControllerAdvice;
     QueryRestController.class})
 public class CpsRestExceptionHandler {
 
-    private static final String CHECK_LOGS_FOR_DETAILS  = "Check logs for details.";
-
     private CpsRestExceptionHandler() {
     }
 
@@ -54,8 +54,7 @@ public class CpsRestExceptionHandler {
      * @return response with response code 500.
      */
     @ExceptionHandler
-    public static ResponseEntity<Object> handleInternalServerErrorExceptions(
-        final Exception exception) {
+    public static ResponseEntity<Object> handleInternalServerErrorExceptions(final Exception exception) {
         return buildErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR, exception);
     }
 
@@ -70,7 +69,7 @@ public class CpsRestExceptionHandler {
         return buildErrorResponse(HttpStatus.NOT_FOUND, exception);
     }
 
-    @ExceptionHandler({DataInUseException.class})
+    @ExceptionHandler({DataInUseException.class, AlreadyDefinedException.class})
     public static ResponseEntity<Object> handleDataInUseException(final CpsException exception) {
         return buildErrorResponse(HttpStatus.CONFLICT, exception);
     }
@@ -88,7 +87,7 @@ public class CpsRestExceptionHandler {
         errorMessage.setStatus(status.toString());
         errorMessage.setMessage(exception.getMessage());
         errorMessage.setDetails(exception instanceof CpsException ? ((CpsException) exception).getDetails() :
-            CHECK_LOGS_FOR_DETAILS);
+            "Check logs for details.");
         return new ResponseEntity<>(errorMessage, status);
     }
 }
index 5b5be1c..3387fb4 100755 (executable)
@@ -32,7 +32,7 @@ import org.onap.cps.api.CpsAdminService
 import org.onap.cps.api.CpsDataService
 import org.onap.cps.api.CpsModuleService
 import org.onap.cps.api.CpsQueryService
-import org.onap.cps.spi.exceptions.DataspaceAlreadyDefinedException
+import org.onap.cps.spi.exceptions.AlreadyDefinedException
 import org.onap.cps.spi.exceptions.SchemaSetInUseException
 import org.onap.cps.spi.model.Anchor
 import org.onap.cps.spi.model.SchemaSet
@@ -98,7 +98,7 @@ class AdminRestControllerSpec extends Specification {
         given: 'an endpoint'
             def createDataspaceEndpoint = "$basePath/v1/dataspaces";
         and: 'the service method throws an exception indicating the dataspace is already defined'
-            def thrownException = new DataspaceAlreadyDefinedException("", new RuntimeException())
+            def thrownException = new AlreadyDefinedException(dataspaceName, new RuntimeException())
             mockCpsAdminService.createDataspace(dataspaceName) >> { throw thrownException }
         when: 'post is invoked'
             def response =
@@ -107,7 +107,7 @@ class AdminRestControllerSpec extends Specification {
                                     .param('dataspace-name', dataspaceName))
                             .andReturn().response
         then: 'dataspace creation fails'
-            response.status == HttpStatus.BAD_REQUEST.value()
+            response.status == HttpStatus.CONFLICT.value()
     }
 
     def 'Create schema set from yang file.'() {
index 15627d5..5794f88 100755 (executable)
@@ -33,6 +33,7 @@ import org.onap.cps.api.CpsAdminService
 import org.onap.cps.api.CpsDataService
 import org.onap.cps.api.CpsModuleService
 import org.onap.cps.api.CpsQueryService
+import org.onap.cps.spi.exceptions.AlreadyDefinedException
 import org.onap.cps.spi.exceptions.AnchorNotFoundException
 import org.onap.cps.spi.exceptions.DataNodeNotFoundException
 import org.onap.cps.spi.exceptions.DataspaceNotFoundException
@@ -159,11 +160,12 @@ class DataRestControllerSpec extends Specification {
         then: 'a success response is returned'
             response.status == httpStatus.value()
         where:
-            scenario       | xpath     | exception                                 || httpStatus
-            'no dataspace' | '/x-path' | new DataspaceNotFoundException('')        || HttpStatus.BAD_REQUEST
-            'no anchor'    | '/x-path' | new AnchorNotFoundException('', '')       || HttpStatus.BAD_REQUEST
-            'no data'      | '/x-path' | new DataNodeNotFoundException('', '', '') || HttpStatus.NOT_FOUND
-            'empty path'   | ''        | new IllegalStateException()               || HttpStatus.NOT_IMPLEMENTED
+            scenario          | xpath     | exception                                 || httpStatus
+            'no dataspace'    | '/x-path' | new DataspaceNotFoundException('')        || HttpStatus.BAD_REQUEST
+            'no anchor'       | '/x-path' | new AnchorNotFoundException('', '')       || HttpStatus.BAD_REQUEST
+            'no data'         | '/x-path' | new DataNodeNotFoundException('', '', '') || HttpStatus.NOT_FOUND
+            'empty path'      | ''        | new IllegalStateException()               || HttpStatus.NOT_IMPLEMENTED
+            'already defined' | '/x-path' | new AlreadyDefinedException('', '')       || HttpStatus.CONFLICT
     }
 
     @Unroll
index fb40372..30d5b62 100644 (file)
@@ -33,14 +33,13 @@ import org.onap.cps.api.CpsAdminService
 import org.onap.cps.api.CpsDataService
 import org.onap.cps.api.CpsModuleService
 import org.onap.cps.api.CpsQueryService
-import org.onap.cps.spi.exceptions.AnchorAlreadyDefinedException
+import org.onap.cps.spi.exceptions.AlreadyDefinedException
 import org.onap.cps.spi.exceptions.CpsException
 import org.onap.cps.spi.exceptions.CpsPathException
 import org.onap.cps.spi.exceptions.DataInUseException
 import org.onap.cps.spi.exceptions.DataValidationException
 import org.onap.cps.spi.exceptions.ModelValidationException
 import org.onap.cps.spi.exceptions.NotFoundInDataspaceException
-import org.onap.cps.spi.exceptions.SchemaSetAlreadyDefinedException
 import org.onap.cps.spi.exceptions.SchemaSetInUseException
 import org.spockframework.spring.SpringBean
 import org.springframework.beans.factory.annotation.Autowired
@@ -112,20 +111,14 @@ class CpsRestExceptionHandlerSpec extends Specification {
                     'Description does not exist in dataspace MyDataSpace.')
     }
 
-    @Unroll
-    def 'request with an expectedObjectTypeInMessage object already defined exception returns HTTP Status Bad Request'() {
-        when: 'no data found CPS exception is thrown by the service'
-            setupTestException(exceptionThrown)
+    def 'Request with an object already defined exception returns HTTP Status Conflict.'() {
+        when: 'AlreadyDefinedException exception is thrown by the service'
+            setupTestException(new AlreadyDefinedException("Anchor", existingObjectName, dataspaceName, new Throwable()))
             def response = performTestRequest()
-        then: 'an HTTP Bad Request response is returned with correct message an details'
-            assertTestResponse(response, BAD_REQUEST,
-                    "Duplicate ${expectedObjectTypeInMessage}",
-                    "${expectedObjectTypeInMessage} with name ${existingObjectName} " +
-                            'already exists for dataspace MyDataSpace.')
-        where: 'the following exceptions are thrown'
-            exceptionThrown                                                               || expectedObjectTypeInMessage
-            new SchemaSetAlreadyDefinedException(dataspaceName, existingObjectName, null) || 'Schema Set'
-            new AnchorAlreadyDefinedException(dataspaceName, existingObjectName, null)    || 'Anchor'
+        then: 'a HTTP conflict response is returned with correct message an details'
+            assertTestResponse(response, CONFLICT,
+                    "Already defined exception",
+                    "Anchor with name ${existingObjectName} already exists for ${dataspaceName}.")
     }
 
     @Unroll
index ddbfeb2..1b8f196 100755 (executable)
@@ -27,8 +27,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.exceptions.AnchorAlreadyDefinedException;
-import org.onap.cps.spi.exceptions.DataspaceAlreadyDefinedException;
+import org.onap.cps.spi.exceptions.AlreadyDefinedException;
 import org.onap.cps.spi.model.Anchor;
 import org.onap.cps.spi.repository.AnchorRepository;
 import org.onap.cps.spi.repository.DataspaceRepository;
@@ -54,7 +53,7 @@ public class CpsAdminPersistenceServiceImpl implements CpsAdminPersistenceServic
         try {
             dataspaceRepository.save(new DataspaceEntity(dataspaceName));
         } catch (final DataIntegrityViolationException e) {
-            throw new DataspaceAlreadyDefinedException(dataspaceName, e);
+            throw AlreadyDefinedException.forDataspace(dataspaceName, e);
         }
     }
 
@@ -71,7 +70,7 @@ public class CpsAdminPersistenceServiceImpl implements CpsAdminPersistenceServic
         try {
             anchorRepository.save(anchorEntity);
         } catch (final DataIntegrityViolationException e) {
-            throw new AnchorAlreadyDefinedException(dataspaceName, anchorName, e);
+            throw AlreadyDefinedException.forAnchor(anchorName, dataspaceName, e);
         }
     }
 
index 4cfa78b..26aa4ac 100644 (file)
@@ -36,6 +36,7 @@ import org.onap.cps.spi.FetchDescendantsOption;
 import org.onap.cps.spi.entities.AnchorEntity;
 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.model.DataNode;
 import org.onap.cps.spi.model.DataNodeBuilder;
 import org.onap.cps.spi.query.CpsPathQuery;
@@ -44,6 +45,7 @@ import org.onap.cps.spi.repository.AnchorRepository;
 import org.onap.cps.spi.repository.DataspaceRepository;
 import org.onap.cps.spi.repository.FragmentRepository;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.dao.DataIntegrityViolationException;
 import org.springframework.stereotype.Service;
 
 @Service
@@ -76,7 +78,11 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
         final AnchorEntity anchorEntity = anchorRepository.getByDataspaceAndName(dataspaceEntity, anchorName);
         final FragmentEntity fragmentEntity = convertToFragmentWithAllDescendants(dataspaceEntity, anchorEntity,
             dataNode);
-        fragmentRepository.save(fragmentEntity);
+        try {
+            fragmentRepository.save(fragmentEntity);
+        } catch (final DataIntegrityViolationException exception) {
+            throw  AlreadyDefinedException.forDataNode(dataNode.getXpath(), anchorName, exception);
+        }
     }
 
     /**
@@ -139,7 +145,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
                     .getLeafName(), cpsPathQuery.getLeafValue());
         } else {
             fragmentEntities = fragmentRepository
-                    .getByAnchorAndEndsWithXpath(anchorEntity.getId(), cpsPathQuery.getEndsWith());
+                .getByAnchorAndEndsWithXpath(anchorEntity.getId(), cpsPathQuery.getEndsWith());
         }
         return fragmentEntities.stream()
             .map(fragmentEntity -> toDataNode(fragmentEntity, fetchDescendantsOption))
index 9a8ea6a..9d3298e 100755 (executable)
@@ -36,7 +36,7 @@ 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.YangResourceEntity;
-import org.onap.cps.spi.exceptions.SchemaSetAlreadyDefinedException;
+import org.onap.cps.spi.exceptions.AlreadyDefinedException;
 import org.onap.cps.spi.exceptions.SchemaSetInUseException;
 import org.onap.cps.spi.model.Anchor;
 import org.onap.cps.spi.repository.AnchorRepository;
@@ -84,7 +84,7 @@ public class CpsModulePersistenceServiceImpl implements CpsModulePersistenceServ
         try {
             schemaSetRepository.save(schemaSetEntity);
         } catch (final DataIntegrityViolationException e) {
-            throw new SchemaSetAlreadyDefinedException(dataspaceName, schemaSetName, e);
+            throw AlreadyDefinedException.forSchemaSet(schemaSetName, dataspaceName, e);
         }
     }
 
index fd3e964..7ab099d 100644 (file)
@@ -20,9 +20,8 @@
 package org.onap.cps.spi.impl
 
 import org.onap.cps.spi.CpsAdminPersistenceService
-import org.onap.cps.spi.exceptions.AnchorAlreadyDefinedException
+import org.onap.cps.spi.exceptions.AlreadyDefinedException
 import org.onap.cps.spi.exceptions.AnchorNotFoundException
-import org.onap.cps.spi.exceptions.DataspaceAlreadyDefinedException
 import org.onap.cps.spi.exceptions.DataspaceNotFoundException
 import org.onap.cps.spi.exceptions.SchemaSetNotFoundException
 import org.onap.cps.spi.model.Anchor
@@ -54,7 +53,7 @@ class CpsAdminPersistenceServiceSpec extends CpsPersistenceSpecBase {
         when: 'an attempt is made to create an already existing dataspace'
             objectUnderTest.createDataspace(DATASPACE_NAME)
         then: 'an exception that is is already defined is thrown with the correct details'
-            def thrown = thrown(DataspaceAlreadyDefinedException)
+            def thrown = thrown(AlreadyDefinedException)
             thrown.details.contains(DATASPACE_NAME)
     }
 
@@ -81,7 +80,7 @@ class CpsAdminPersistenceServiceSpec extends CpsPersistenceSpecBase {
             scenario                    | dataspaceName  | schemaSetName     | anchorName     || expectedException
             'dataspace does not exist'  | 'unknown'      | 'not-relevant'    | 'not-relevant' || DataspaceNotFoundException
             'schema set does not exist' | DATASPACE_NAME | 'unknown'         | 'not-relevant' || SchemaSetNotFoundException
-            'anchor already exists'     | DATASPACE_NAME |  SCHEMA_SET_NAME1 | ANCHOR_NAME1   || AnchorAlreadyDefinedException
+            'anchor already exists'     | DATASPACE_NAME |  SCHEMA_SET_NAME1 | ANCHOR_NAME1   || AlreadyDefinedException
     }
 
     @Unroll
index bb0b471..51f7809 100644 (file)
@@ -25,6 +25,7 @@ import com.google.gson.GsonBuilder
 import org.onap.cps.spi.CpsDataPersistenceService
 import org.onap.cps.spi.FetchDescendantsOption
 import org.onap.cps.spi.entities.FragmentEntity
+import org.onap.cps.spi.exceptions.AlreadyDefinedException
 import org.onap.cps.spi.exceptions.AnchorNotFoundException
 import org.onap.cps.spi.exceptions.DataNodeNotFoundException
 import org.onap.cps.spi.exceptions.DataspaceNotFoundException
@@ -35,6 +36,8 @@ import org.springframework.dao.DataIntegrityViolationException
 import org.springframework.test.context.jdbc.Sql
 import spock.lang.Unroll
 
+import javax.validation.ConstraintViolationException
+
 import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
 import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
 
@@ -99,7 +102,8 @@ class CpsDataPersistenceServiceSpec extends CpsPersistenceSpecBase {
             scenario                    | dataspaceName  | anchorName     | dataNode         || expectedException
             'dataspace does not exist'  | 'unknown'      | 'not-relevant' | newDataNode      || DataspaceNotFoundException
             'schema set does not exist' | DATASPACE_NAME | 'unknown'      | newDataNode      || AnchorNotFoundException
-            'anchor already exists'     | DATASPACE_NAME | ANCHOR_NAME1   | existingDataNode || DataIntegrityViolationException
+            'anchor already exists'     | DATASPACE_NAME | ANCHOR_NAME1   | newDataNode      || ConstraintViolationException
+            'datanode already exists'   | DATASPACE_NAME | ANCHOR_NAME1   | existingDataNode || AlreadyDefinedException
     }
 
     @Sql([CLEAR_DATA, SET_DATA])
index d3d3768..441ddb6 100644 (file)
@@ -25,7 +25,7 @@ import org.onap.cps.spi.CpsAdminPersistenceService
 import org.onap.cps.spi.CpsModulePersistenceService
 import org.onap.cps.spi.entities.YangResourceEntity
 import org.onap.cps.spi.exceptions.DataspaceNotFoundException
-import org.onap.cps.spi.exceptions.SchemaSetAlreadyDefinedException
+import org.onap.cps.spi.exceptions.AlreadyDefinedException
 import org.onap.cps.spi.exceptions.SchemaSetInUseException
 import org.onap.cps.spi.exceptions.SchemaSetNotFoundException
 import org.onap.cps.spi.repository.AnchorRepository
@@ -76,7 +76,7 @@ class CpsModulePersistenceServiceSpec extends CpsPersistenceSpecBase {
         where: 'the following data is used'
             scenario                    | dataspaceName  | schemaSetName            || expectedException
             'dataspace does not exist'  | 'unknown'      | 'not-relevant'           || DataspaceNotFoundException
-            'schema set already exists' | DATASPACE_NAME | EXISTING_SCHEMA_SET_NAME || SchemaSetAlreadyDefinedException
+            'schema set already exists' | DATASPACE_NAME | EXISTING_SCHEMA_SET_NAME || AlreadyDefinedException
     }
 
     @Sql([CLEAR_DATA, SET_DATA])
index ed89c43..0379ac2 100755 (executable)
@@ -22,8 +22,8 @@ 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.exceptions.DataspaceAlreadyDefinedException;
 import org.onap.cps.spi.model.Anchor;
 
 /**
@@ -35,7 +35,7 @@ public interface CpsAdminService {
      * Create dataspace.
      *
      * @param dataspaceName dataspace name
-     * @throws DataspaceAlreadyDefinedException if dataspace with same name already exists
+     * @throws AlreadyDefinedException if dataspace with same name already exists
      */
     void createDataspace(@NonNull String dataspaceName);
 
index 06c04ce..f47af5f 100755 (executable)
@@ -23,7 +23,7 @@ package org.onap.cps.spi;
 
 import java.util.Collection;
 import org.checkerframework.checker.nullness.qual.NonNull;
-import org.onap.cps.spi.exceptions.DataspaceAlreadyDefinedException;
+import org.onap.cps.spi.exceptions.AlreadyDefinedException;
 import org.onap.cps.spi.model.Anchor;
 
 /*
@@ -35,7 +35,7 @@ public interface CpsAdminPersistenceService {
      * Create dataspace.
      *
      * @param dataspaceName dataspace name
-     * @throws DataspaceAlreadyDefinedException if dataspace with same name already exists
+     * @throws AlreadyDefinedException if dataspace with same name already exists
      */
     void createDataspace(@NonNull String dataspaceName);
 
diff --git a/cps-service/src/main/java/org/onap/cps/spi/exceptions/AlreadyDefinedException.java b/cps-service/src/main/java/org/onap/cps/spi/exceptions/AlreadyDefinedException.java
new file mode 100644 (file)
index 0000000..9e54f34
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 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;
+
+/**
+ * Already defined exception. Indicates the cps object with same name already exists.
+ */
+
+@SuppressWarnings("squid:S110")  // Team agreed to accept 6 levels of inheritance for CPS Exceptions
+public class AlreadyDefinedException extends CpsAdminException {
+
+    private static final long serialVersionUID = 501929839139881112L;
+
+    /**
+     * 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",
+            String.format("%s with name %s already exists for %s.", objectType, objectName, contextName), cause);
+    }
+
+    /**
+     * 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);
+    }
+
+    public static AlreadyDefinedException forDataspace(final String dataspaceName, final Throwable cause) {
+        return new AlreadyDefinedException(dataspaceName, cause);
+    }
+
+    public static AlreadyDefinedException forAnchor(final String anchorName, final String contextName,
+        final Throwable cause) {
+        return new AlreadyDefinedException("Anchor", anchorName, contextName, cause);
+    }
+
+    public static AlreadyDefinedException forSchemaSet(final String schemaSetName, final String contextName,
+        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);
+    }
+}
diff --git a/cps-service/src/main/java/org/onap/cps/spi/exceptions/AnchorAlreadyDefinedException.java b/cps-service/src/main/java/org/onap/cps/spi/exceptions/AnchorAlreadyDefinedException.java
deleted file mode 100644 (file)
index 2a4abad..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * ============LICENSE_START=======================================================
- *  Copyright (C) 2020 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;
-
-/**
- * Anchor already defined exception. Indicates the an anchor with same name already exists in the same dataspace
- */
-
-@SuppressWarnings("squid:S110")  // Team agreed to accept 6 levels of inheritance for CPS Exceptions
-public class AnchorAlreadyDefinedException extends CpsAdminException {
-
-    private static final long serialVersionUID = 5744381546778730691L;
-
-    /**
-     * Constructor.
-     *
-     * @param dataspaceName the name dataspace
-     * @param anchorName    the name of the schema set
-     * @param cause         the cause of the exception
-     */
-    public AnchorAlreadyDefinedException(final String dataspaceName, final String anchorName, final Throwable cause) {
-        super("Duplicate Anchor",
-            String.format("Anchor with name %s already exists for dataspace %s.", anchorName, dataspaceName), cause);
-    }
-}
diff --git a/cps-service/src/main/java/org/onap/cps/spi/exceptions/DataspaceAlreadyDefinedException.java b/cps-service/src/main/java/org/onap/cps/spi/exceptions/DataspaceAlreadyDefinedException.java
deleted file mode 100644 (file)
index fcc085a..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- *  ============LICENSE_START=======================================================
- *  Copyright (C) 2020 Pantheon.tech
- *  ================================================================================
- *  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;
-
-/**
- * Dataspace already defined exception. Indicates the dataspace with same name already exists.
- */
-
-@SuppressWarnings("squid:S110")  // Team agreed to accept 6 levels of inheritance for CPS Exceptions
-public class DataspaceAlreadyDefinedException extends CpsAdminException {
-
-    private static final long serialVersionUID = -5813793951842079228L;
-
-    /**
-     * Constructor.
-     *
-     * @param dataspaceName dataspace name
-     * @param cause         the cause of this exception
-     */
-    public DataspaceAlreadyDefinedException(final String dataspaceName, final Throwable cause) {
-        super("Duplicate Dataspace.",
-            String.format("Dataspace with name %s already exists.", dataspaceName),
-            cause);
-    }
-}
diff --git a/cps-service/src/main/java/org/onap/cps/spi/exceptions/SchemaSetAlreadyDefinedException.java b/cps-service/src/main/java/org/onap/cps/spi/exceptions/SchemaSetAlreadyDefinedException.java
deleted file mode 100644 (file)
index 1e0b8db..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * ============LICENSE_START=======================================================
- *  Copyright (C) 2020 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;
-
-/**
- * Schema set already defined exception. Indicates the a schema set with same name already exists in the same dataspace
- */
-
-@SuppressWarnings("squid:S110")  // Team agreed to accept 6 levels of inheritance for CPS Exceptions
-public class SchemaSetAlreadyDefinedException extends CpsAdminException {
-
-    private static final long serialVersionUID = 501929839139881112L;
-
-    /**
-     * Constructor.
-     *
-     * @param dataspaceName the name dataspace
-     * @param schemaSetName the name of the schema set
-     * @param cause         the cause of the exception
-     */
-    public SchemaSetAlreadyDefinedException(final String dataspaceName, final String schemaSetName,
-        final Throwable cause) {
-        super("Duplicate Schema Set",
-            String.format("Schema Set with name %s already exists for dataspace %s.", schemaSetName, dataspaceName),
-            cause);
-    }
-}
index 733378e..873e14c 100644 (file)
@@ -21,6 +21,7 @@
 
 package org.onap.cps.utils;
 
+import com.google.gson.JsonSyntaxException;
 import com.google.gson.stream.JsonReader;
 import java.io.IOException;
 import java.io.StringReader;
@@ -93,9 +94,9 @@ public class YangUtils {
             final JsonReader jsonReader = new JsonReader(new StringReader(jsonData));
             jsonParserStream.parse(jsonReader);
 
-        } catch (final IOException | IllegalStateException e) {
+        } catch (final IOException | IllegalStateException | JsonSyntaxException exception) {
             throw new DataValidationException("Failed to parse json data.", String
-                .format("Exception occurred on parsing string %s.", jsonData), e);
+                .format("Exception occurred on parsing string %s.", jsonData), exception);
         }
         return normalizedNodeResult.getResult();
     }
index a4a13ff..d2f43c9 100755 (executable)
@@ -31,18 +31,18 @@ class CpsExceptionsSpec extends Specification {
 
     def 'Creating an exception that the Anchor already exist.'() {
         given: 'an exception dat the Anchor already exist is created'
-            def exception = new AnchorAlreadyDefinedException(dataspaceName, anchorName, rootCause)
+            def exception = new AlreadyDefinedException('Anchor', anchorName, dataspaceName, rootCause)
         expect: 'the exception details contains the correct message with Anchor name and Dataspace name'
-            exception.details == "Anchor with name ${anchorName} already exists for dataspace ${dataspaceName}."
+            exception.details == "Anchor with name ${anchorName} already exists for ${dataspaceName}."
         and: 'the correct root cause is maintained'
             exception.cause == rootCause
     }
 
     def 'Creating an exception that the dataspace already exists.'() {
         given: 'an exception that the dataspace already exists is created'
-            def exception = new DataspaceAlreadyDefinedException(dataspaceName, rootCause)
+            def exception = new AlreadyDefinedException(dataspaceName, rootCause)
         expect: 'the exception details contains the correct message with dataspace name'
-            exception.details == "Dataspace with name ${dataspaceName} already exists."
+            exception.details == "${dataspaceName} already exists."
         and: 'the correct root cause is maintained'
             exception.cause == rootCause
     }
@@ -100,15 +100,6 @@ class CpsExceptionsSpec extends Specification {
                     == "${descriptionOfObject} does not exist in dataspace ${dataspaceName}."
     }
 
-    def 'Creating an exception that the schema set already exists.'() {
-        given: 'an exception that the schema set already exists is created'
-            def exception = new SchemaSetAlreadyDefinedException(dataspaceName, schemaSetName, rootCause)
-        expect: 'the exception details contains the correct message with dataspace and schema set names'
-            exception.details == "Schema Set with name ${schemaSetName} already exists for dataspace ${dataspaceName}."
-        and: 'the correct root cause is maintained'
-            exception.cause == rootCause
-    }
-
     def 'Creating a exception that a schema set cannot be found.'() {
         expect: 'the exception details contains the correct message with dataspace and schema set names'
             (new SchemaSetNotFoundException(dataspaceName, schemaSetName)).details
@@ -134,6 +125,30 @@ class CpsExceptionsSpec extends Specification {
                     == "DataNode with xpath ${xpath} was not found for anchor ${anchorName} and dataspace ${dataspaceName}."
     }
 
+    def 'Creating a exception that a dataspace already exists.'() {
+        expect: 'the exception details contains the correct message with dataspace name.'
+            (AlreadyDefinedException.forDataspace(dataspaceName, rootCause)).details
+                    == "${dataspaceName} already exists."
+    }
+
+    def 'Creating a exception that a anchor already exists.'() {
+        expect: 'the exception details contains the correct message with anchor name and dataspace name.'
+            (AlreadyDefinedException.forAnchor(anchorName, dataspaceName, rootCause)).details
+                    == "Anchor with name ${anchorName} already exists for ${dataspaceName}."
+    }
+
+    def 'Creating a exception that a data node already exists.'() {
+        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}."
+    }
+
+    def 'Creating a exception that a schema set already exists.'() {
+        expect: 'the exception details contains the correct message with schema set and dataspace name.'
+            (AlreadyDefinedException.forSchemaSet(schemaSetName, dataspaceName, rootCause)).details
+                    == "Schema Set with name ${schemaSetName} already exists for ${dataspaceName}."
+    }
+
     def 'Creating a cps path exception.'() {
         given: 'a cps path exception is created'
             def exception = new CpsPathException(providedMessage, providedDetails)
index 826cdd8..0b00cbb 100644 (file)
@@ -54,6 +54,7 @@ class YangUtilsSpec extends Specification {
             invalidJson                                       | description
             '{incomplete json'                                | 'incomplete json'
             '{"test:bookstore": {"address": "Parnell st." }}' | 'json with un-modelled data'
+            '{" }'                                            | 'json with syntax exception'
     }
 
     @Unroll