summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cps/README.md5
-rw-r--r--cps/cps-dependencies/pom.xml7
-rw-r--r--cps/cps-parent/pom.xml90
-rw-r--r--cps/cps-rest/docs/api/swagger/openapi.yml34
-rw-r--r--cps/cps-rest/pom.xml37
-rw-r--r--cps/cps-rest/src/main/java/org/onap/cps/rest/controller/CpsRestController.java155
-rw-r--r--cps/cps-rest/src/main/java/org/onap/cps/rest/exceptions/CpsRestExceptionHandler.java98
-rw-r--r--cps/cps-rest/src/main/java/org/onap/cps/rest/exceptions/ErrorMessage.java37
-rw-r--r--cps/cps-rest/src/main/java/org/onap/cps/swagger/config/SpringFoxConfig.java46
-rw-r--r--cps/cps-rest/src/main/resources/application.yml8
-rw-r--r--cps/cps-service/src/main/java/org/onap/cps/api/CpService.java4
-rw-r--r--cps/cps-service/src/main/java/org/onap/cps/api/impl/CpServiceImpl.java28
-rw-r--r--cps/cps-service/src/main/java/org/onap/cps/exceptions/CpsException.java62
-rw-r--r--cps/cps-service/src/main/java/org/onap/cps/exceptions/CpsNotFoundException.java57
-rw-r--r--cps/cps-service/src/main/java/org/onap/cps/exceptions/CpsValidationException.java55
-rw-r--r--cps/cps-service/src/test/groovy/org/onap/cps/api/impl/CpServiceImplSpec.groovy7
16 files changed, 538 insertions, 192 deletions
diff --git a/cps/README.md b/cps/README.md
index d1bf49d8c..d5f0c66f4 100644
--- a/cps/README.md
+++ b/cps/README.md
@@ -29,6 +29,5 @@ java -DDB_HOST=localhost -DDB_USERNAME=cps -DDB_PASSWORD=cps -jar cps-rest/targe
```
* Browse
- * [Swagger UI](http://localhost:8080/swagger-ui/index.html)
- * OpenAPI Specification in [JSON](http://localhost:8080/api/cps/openapi.json)
- or [YAML](http://localhost:8080/api/cps/openapi.yaml) format
+ * [Swagger UI](http://localhost:8080/api/cps/swagger-ui/index.html)
+ * [Api Documentation](http://localhost:8080/api/cps/v3/api-docs)
diff --git a/cps/cps-dependencies/pom.xml b/cps/cps-dependencies/pom.xml
index 6f50cd0fc..ee37b1e0a 100644
--- a/cps/cps-dependencies/pom.xml
+++ b/cps/cps-dependencies/pom.xml
@@ -17,6 +17,7 @@
<hibernate-types.version>2.10.0</hibernate-types.version>
<spock-core.version>2.0-M2-groovy-3.0</spock-core.version>
<springboot.version>2.3.3.RELEASE</springboot.version>
+ <springfox.version>3.0.0</springfox.version>
<swagger.version>2.1.4</swagger.version>
<yangtools.version>5.0.6</yangtools.version>
</properties>
@@ -43,9 +44,9 @@
<version>${swagger.version}</version>
</dependency>
<dependency>
- <groupId>io.swagger.core.v3</groupId>
- <artifactId>swagger-jaxrs2</artifactId>
- <version>${swagger.version}</version>
+ <groupId>io.springfox</groupId>
+ <artifactId>springfox-boot-starter</artifactId>
+ <version>${springfox.version}</version>
</dependency>
<dependency>
<groupId>com.vladmihalcea</groupId>
diff --git a/cps/cps-parent/pom.xml b/cps/cps-parent/pom.xml
index 4984b6194..0fe2e101a 100644
--- a/cps/cps-parent/pom.xml
+++ b/cps/cps-parent/pom.xml
@@ -17,12 +17,9 @@
<properties>
<java.version>11</java.version>
- <maven-resources-plugin.version>3.2.0</maven-resources-plugin.version>
- <maven-dependency-plugin.version>3.1.2</maven-dependency-plugin.version>
- <maven-replacer-plugin.version>1.5.3</maven-replacer-plugin.version>
<oparent.version>3.1.0</oparent.version>
<spring-boot-maven-plugin.version>2.3.3.RELEASE</spring-boot-maven-plugin.version>
- <swagger-ui.version>3.35.0</swagger-ui.version>
+ <swagger-codegen-maven-plugin.version>3.0.18</swagger-codegen-maven-plugin.version>
</properties>
<dependencyManagement>
@@ -79,84 +76,33 @@
</execution>
</executions>
</plugin>
+ <!-- Swagger code generation. -->
<plugin>
- <!-- Download Swagger UI webjar. -->
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-dependency-plugin</artifactId>
- <version>${maven-dependency-plugin.version}</version>
+ <groupId>io.swagger.codegen.v3</groupId>
+ <artifactId>swagger-codegen-maven-plugin</artifactId>
+ <version>${swagger-codegen-maven-plugin.version}</version>
<executions>
<execution>
- <phase>prepare-package</phase>
<goals>
- <goal>unpack</goal>
+ <goal>generate</goal>
</goals>
<configuration>
- <artifactItems>
- <artifactItem>
- <groupId>org.webjars</groupId>
- <artifactId>swagger-ui</artifactId>
- <version>${swagger-ui.version}</version>
- </artifactItem>
- </artifactItems>
- <outputDirectory>
- ${project.build.directory}/swagger-ui-${swagger-ui.version}
- </outputDirectory>
+ <inputSpec>${project.basedir}/docs/api/swagger/openapi.yml</inputSpec>
+ <invokerPackage>org.onap.cps.rest.controller</invokerPackage>
+ <modelPackage>org.onap.cps.rest.model</modelPackage>
+ <apiPackage>org.onap.cps.rest.api</apiPackage>
+ <language>spring</language>
+ <generateSupportingFiles>false</generateSupportingFiles>
+ <configOptions>
+ <sourceFolder>src/gen/java</sourceFolder>
+ <dateLibrary>java11</dateLibrary>
+ <interfaceOnly>true</interfaceOnly>
+ <useTags>true</useTags>
+ </configOptions>
</configuration>
</execution>
</executions>
</plugin>
- <plugin>
- <!-- Copy Swagger UI resources to static resources directory. -->
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-resources-plugin</artifactId>
- <version>${maven-resources-plugin.version}</version>
- <executions>
- <execution>
- <id>copy-resources</id>
- <phase>prepare-package</phase>
- <goals>
- <goal>copy-resources</goal>
- </goals>
- <configuration>
- <outputDirectory>${project.build.outputDirectory}/static/swagger-ui
- </outputDirectory>
- <resources>
- <resource>
- <directory>
- ${project.build.directory}/swagger-ui-${swagger-ui.version}/META-INF/resources/webjars/swagger-ui/${swagger-ui.version}/
- </directory>
- <excludes>
- <exclude>**/*.gz</exclude>
- </excludes>
- </resource>
- </resources>
- </configuration>
- </execution>
- </executions>
- </plugin>
- <plugin>
- <!-- Replace the OpenAPI specification example URL with the local one. -->
- <groupId>com.google.code.maven-replacer-plugin</groupId>
- <artifactId>replacer</artifactId>
- <version>${maven-replacer-plugin.version}</version>
- <executions>
- <execution>
- <phase>prepare-package</phase>
- <goals>
- <goal>replace</goal>
- </goals>
- </execution>
- </executions>
- <configuration>
- <file>${project.build.outputDirectory}/static/swagger-ui/index.html</file>
- <replacements>
- <replacement>
- <token>https://petstore.swagger.io/v2/swagger.json</token>
- <value>/api/cps/openapi.json</value>
- </replacement>
- </replacements>
- </configuration>
- </plugin>
</plugins>
</pluginManagement>
<plugins>
diff --git a/cps/cps-rest/docs/api/swagger/openapi.yml b/cps/cps-rest/docs/api/swagger/openapi.yml
index f116c26ce..9b2ac1ec5 100644
--- a/cps/cps-rest/docs/api/swagger/openapi.yml
+++ b/cps/cps-rest/docs/api/swagger/openapi.yml
@@ -6,13 +6,13 @@ info:
servers:
- url: //localhost:8088/
tags:
- - name: cps-resource
+ - name: cps-rest
description: cps Resource
paths:
/v1/dataspaces/{dataspace-name}/:
delete:
tags:
- - cps-resource
+ - cps-rest
summary: Delete the given dataspace
operationId: deleteDataspace
parameters:
@@ -41,7 +41,7 @@ paths:
/v1/dataspaces/{dataspace-name}/anchors:
get:
tags:
- - cps-resource
+ - cps-rest
summary: Read all anchors, given a dataspace
operationId: getAnchors
parameters:
@@ -69,7 +69,7 @@ paths:
content: {}
post:
tags:
- - cps-resource
+ - cps-rest
summary: Create a new anchor in the given dataspace
operationId: createAnchor
parameters:
@@ -86,9 +86,9 @@ paths:
required:
- file
properties:
- file:
+ multipartFile:
type: string
- description: file
+ description: multipartFile
format: binary
required: true
responses:
@@ -113,7 +113,7 @@ paths:
/v1/dataspaces/{dataspace-name}/anchors/{anchor-name}:
get:
tags:
- - cps-resource
+ - cps-rest
summary: Read an anchor given a anchor and a dataspace
operationId: getAnchor
parameters:
@@ -147,7 +147,7 @@ paths:
content: {}
delete:
tags:
- - cps-resource
+ - cps-rest
summary: Delete an anchor given a anchor and a dataspace
operationId: deleteAnchor
parameters:
@@ -182,7 +182,7 @@ paths:
/v1/dataspaces/{dataspace-name}/anchors/{anchor-name}/nodes:
get:
tags:
- - cps-resource
+ - cps-rest
summary: Get a node given an anchor for the given dataspace
operationId: getNodeByDataspaceAndAnchor
parameters:
@@ -225,7 +225,7 @@ paths:
/v1/dataspaces/{dataspace-name}/modules:
get:
tags:
- - cps-resource
+ - cps-rest
summary: Read all yang modules in the store
operationId: getModule
parameters:
@@ -263,7 +263,7 @@ paths:
content: {}
post:
tags:
- - cps-resource
+ - cps-rest
summary: Create modules for the given dataspace
operationId: createModules
parameters:
@@ -280,9 +280,9 @@ paths:
required:
- file
properties:
- file:
+ multipartFile:
type: string
- description: file
+ description: multipartFile
format: binary
required: true
responses:
@@ -307,7 +307,7 @@ paths:
/v1/dataspaces/{dataspace-name}/nodes:
get:
tags:
- - cps-resource
+ - cps-rest
summary: Get all nodes for a given dataspace using an xpath or schema node identifier
operationId: getNode
parameters:
@@ -343,7 +343,7 @@ paths:
x-codegen-request-body-name: requestBody
post:
tags:
- - cps-resource
+ - cps-rest
summary: Create a node for a given anchor for the given dataspace
operationId: createNode
parameters:
@@ -360,9 +360,9 @@ paths:
required:
- file
properties:
- file:
+ multipartFile:
type: string
- description: file
+ description: multipartFile
format: binary
required: true
responses:
diff --git a/cps/cps-rest/pom.xml b/cps/cps-rest/pom.xml
index 2d125803d..4f8746a36 100644
--- a/cps/cps-rest/pom.xml
+++ b/cps/cps-rest/pom.xml
@@ -43,9 +43,10 @@
<artifactId>swagger-annotations</artifactId>
</dependency>
<dependency>
- <groupId>io.swagger.core.v3</groupId>
- <artifactId>swagger-jaxrs2</artifactId>
+ <groupId>io.springfox</groupId>
+ <artifactId>springfox-boot-starter</artifactId>
</dependency>
+
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
@@ -57,6 +58,22 @@
</exclusion>
</exclusions>
</dependency>
+ <!-- T E S T D E P E N D E N C I E S -->
+ <dependency>
+ <groupId>org.codehaus.groovy</groupId>
+ <artifactId>groovy</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.spockframework</groupId>
+ <artifactId>spock-core</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>cglib</groupId>
+ <artifactId>cglib-nodep</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
@@ -65,20 +82,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
+ <!-- Swagger code generation. -->
<plugin>
- <!-- Download Swagger UI webjar. -->
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-dependency-plugin</artifactId>
- </plugin>
- <plugin>
- <!-- Copy Swagger UI resources to static resources directory. -->
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-resources-plugin</artifactId>
- </plugin>
- <plugin>
- <!-- Replace the OpenAPI specification example URL with the local one. -->
- <groupId>com.google.code.maven-replacer-plugin</groupId>
- <artifactId>replacer</artifactId>
+ <groupId>io.swagger.codegen.v3</groupId>
+ <artifactId>swagger-codegen-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
diff --git a/cps/cps-rest/src/main/java/org/onap/cps/rest/controller/CpsRestController.java b/cps/cps-rest/src/main/java/org/onap/cps/rest/controller/CpsRestController.java
index a577af70e..90c287cda 100644
--- a/cps/cps-rest/src/main/java/org/onap/cps/rest/controller/CpsRestController.java
+++ b/cps/cps-rest/src/main/java/org/onap/cps/rest/controller/CpsRestController.java
@@ -26,13 +26,13 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
-import javax.persistence.PersistenceException;
-import org.hibernate.exception.ConstraintViolationException;
+import javax.validation.Valid;
import org.onap.cps.api.CpService;
+import org.onap.cps.exceptions.CpsException;
+import org.onap.cps.exceptions.CpsValidationException;
+import org.onap.cps.rest.api.CpsRestApi;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.model.parser.api.YangParserException;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
@@ -44,39 +44,70 @@ import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@RestController
-public class CpsRestController {
+public class CpsRestController implements CpsRestApi {
@Autowired
private CpService cpService;
+ @Override
+ public ResponseEntity<Object> createAnchor(@Valid MultipartFile multipartFile, String dataspaceName) {
+ return null;
+ }
+
+ @Override
+ public ResponseEntity<Object> createModules(@Valid MultipartFile multipartFile, String dataspaceName) {
+ final File fileToParse = saveToFile(multipartFile);
+ final SchemaContext schemaContext = cpService.parseAndValidateModel(fileToParse);
+ cpService.storeSchemaContext(schemaContext, dataspaceName);
+ return new ResponseEntity<>("Resource successfully created", HttpStatus.CREATED);
+ }
+
+ @Override
+ public ResponseEntity<Object> createNode(@Valid MultipartFile multipartFile, String dataspaceName) {
+ return null;
+ }
+
+ @Override
+ public ResponseEntity<Object> deleteAnchor(String dataspaceName, String anchorName) {
+ return null;
+ }
+
+ @Override
+ public ResponseEntity<Object> deleteDataspace(String dataspaceName) {
+ return null;
+ }
+
+ @Override
+ public ResponseEntity<Object> getAnchor(String dataspaceName, String anchorName) {
+ return null;
+ }
+
+ @Override
+ public ResponseEntity<Object> getAnchors(String dataspaceName) {
+ return null;
+ }
+
+ @Override
+ public ResponseEntity<Object> getModule(String dataspaceName, @Valid String namespaceName, @Valid String revision) {
+ return null;
+ }
+
+ @Override
+ public ResponseEntity<Object> getNode(@Valid String body, String dataspaceName) {
+ return null;
+ }
+
+ @Override
+ public ResponseEntity<Object> getNodeByDataspaceAndAnchor(@Valid String body, String dataspaceName,
+ String anchorName) {
+ return null;
+ }
+
/*
Old rest endpoints before contract first approach (Need to be removed).
*/
/**
- * Upload a yang model file.
- *
- * @param uploadedFile the yang model Multipart File.
- * @param dataspaceName the dataspace name linked to the model.
- * @return a ResponseEntity.
- */
- @PostMapping("/dataspaces/{dataspace_name}/modules")
- public final ResponseEntity<String> uploadYangModelFile(
- @RequestParam("file") MultipartFile uploadedFile,
- @PathVariable("dataspace_name") String dataspaceName) {
- try {
- final File fileToParse = saveToFile(uploadedFile);
- final SchemaContext schemaContext = cpService.parseAndValidateModel(fileToParse);
- cpService.storeSchemaContext(schemaContext, dataspaceName);
- return new ResponseEntity<String>("Resource successfully created", HttpStatus.CREATED);
- } catch (final YangParserException | ConstraintViolationException e) {
- return new ResponseEntity<String>(e.getMessage(), HttpStatus.BAD_REQUEST);
- } catch (final Exception e) {
- return new ResponseEntity<String>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
- }
- }
-
- /**
* Upload a JSON file.
*
* @param uploadedFile the JSON Multipart file.
@@ -85,16 +116,11 @@ public class CpsRestController {
@PostMapping("/upload-yang-json-data-file")
public final ResponseEntity<String> uploadYangJsonDataFile(
@RequestParam("file") MultipartFile uploadedFile) {
- try {
- validateJsonStructure(uploadedFile);
- final int persistenceObjectId = cpService.storeJsonStructure(new String(uploadedFile.getBytes()));
- return new ResponseEntity<String>(
- "Object stored in CPS with identity: " + persistenceObjectId, HttpStatus.OK);
- } catch (final JsonSyntaxException e) {
- return new ResponseEntity<String>(e.getMessage(), HttpStatus.BAD_REQUEST);
- } catch (final Exception e) {
- return new ResponseEntity<String>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
- }
+ validateJsonStructure(uploadedFile);
+ final int persistenceObjectId = cpService.storeJsonStructure(getJsonString(uploadedFile));
+ return new ResponseEntity<String>(
+ "Object stored in CPS with identity: " + persistenceObjectId, HttpStatus.OK);
+
}
/**
@@ -106,13 +132,7 @@ public class CpsRestController {
@GetMapping("/json-object/{id}")
public final ResponseEntity<String> getJsonObjectById(
@PathVariable("id") final int jsonObjectId) {
- try {
- return new ResponseEntity<String>(cpService.getJsonById(jsonObjectId), HttpStatus.OK);
- } catch (final PersistenceException e) {
- return new ResponseEntity<String>(e.getMessage(), HttpStatus.NOT_FOUND);
- } catch (final Exception e) {
- return new ResponseEntity<String>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
- }
+ return new ResponseEntity<String>(cpService.getJsonById(jsonObjectId), HttpStatus.OK);
}
/**
@@ -124,30 +144,39 @@ public class CpsRestController {
@DeleteMapping("json-object/{id}")
public final ResponseEntity<Object> deleteJsonObjectById(
@PathVariable("id") final int jsonObjectId) {
+ cpService.deleteJsonById(jsonObjectId);
+ return new ResponseEntity<>(HttpStatus.NO_CONTENT);
+ }
+
+ private static void validateJsonStructure(final MultipartFile multipartFile) {
try {
- cpService.deleteJsonById(jsonObjectId);
- return new ResponseEntity<>(HttpStatus.NO_CONTENT);
- } catch (final EmptyResultDataAccessException e) {
- return new ResponseEntity<>(HttpStatus.NOT_FOUND.toString(), HttpStatus.NOT_FOUND);
- } catch (final Exception e) {
- return new ResponseEntity<>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
+ final Gson gson = new Gson();
+ gson.fromJson(getJsonString(multipartFile), Object.class);
+ } catch (JsonSyntaxException e) {
+ throw new CpsValidationException("Not a valid JSON file.", e);
}
}
- private static final void validateJsonStructure(final MultipartFile jsonFile)
- throws JsonSyntaxException, IOException {
- final Gson gson = new Gson();
- gson.fromJson(new String(jsonFile.getBytes()), Object.class);
- }
+ private static File saveToFile(final MultipartFile multipartFile) {
+ try {
+ final File file = File.createTempFile("tempFile", ".yang");
+ file.deleteOnExit();
- private static final File saveToFile(final MultipartFile multipartFile)
- throws IOException {
- final File file = File.createTempFile("tempFile", ".yang");
- file.deleteOnExit();
+ try (OutputStream outputStream = new FileOutputStream(file)) {
+ outputStream.write(multipartFile.getBytes());
+ }
+ return file;
- try (OutputStream outputStream = new FileOutputStream(file)) {
- outputStream.write(multipartFile.getBytes());
+ } catch (IOException e) {
+ throw new CpsException(e);
+ }
+ }
+
+ private static String getJsonString(final MultipartFile multipartFile) {
+ try {
+ return new String(multipartFile.getBytes());
+ } catch (IOException e) {
+ throw new CpsException(e);
}
- return file;
}
} \ No newline at end of file
diff --git a/cps/cps-rest/src/main/java/org/onap/cps/rest/exceptions/CpsRestExceptionHandler.java b/cps/cps-rest/src/main/java/org/onap/cps/rest/exceptions/CpsRestExceptionHandler.java
new file mode 100644
index 000000000..9cf4935d4
--- /dev/null
+++ b/cps/cps-rest/src/main/java/org/onap/cps/rest/exceptions/CpsRestExceptionHandler.java
@@ -0,0 +1,98 @@
+/*
+ * ============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.rest.exceptions;
+
+import org.apache.commons.lang3.exception.ExceptionUtils;
+import org.hibernate.exception.ConstraintViolationException;
+import org.onap.cps.exceptions.CpsException;
+import org.onap.cps.exceptions.CpsNotFoundException;
+import org.onap.cps.exceptions.CpsValidationException;
+import org.onap.cps.rest.controller.CpsRestController;
+import org.springframework.dao.EmptyResultDataAccessException;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+@RestControllerAdvice(assignableTypes = {CpsRestController.class})
+public class CpsRestExceptionHandler {
+
+ /**
+ * Default exception handler.
+ *
+ * @param exception the exception to handle
+ * @return response with response code 500.
+ */
+ @ExceptionHandler
+ public ResponseEntity<Object> handleInternalErrorException(Exception exception) {
+ return buildErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR, exception);
+ }
+
+ /*
+ TODO: Rid off extra dependencies.
+
+ Generic exception handler and CpsException (incl. children) are the only
+ exceptions to be handled here. All the other exceptions which require a special
+ treatment should be rethrown as CpsException in the place of occurrence ->
+ e.g. persistence exceptions are to be handled in cps-ri module.
+ */
+
+ @ExceptionHandler({ConstraintViolationException.class})
+ public ResponseEntity<Object> handleBadRequestException(Exception exception) {
+ return buildErrorResponse(HttpStatus.BAD_REQUEST, exception);
+ }
+
+ @ExceptionHandler({EmptyResultDataAccessException.class})
+ public ResponseEntity<Object> handleNotFoundException(Exception exception) {
+ return buildErrorResponse(HttpStatus.NOT_FOUND, exception);
+ }
+
+ @ExceptionHandler({CpsException.class})
+ public ResponseEntity<Object> handleCpsException(CpsException exception) {
+ return buildErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR, exception.getMessage(), extractDetails(exception));
+ }
+
+ @ExceptionHandler({CpsValidationException.class})
+ public ResponseEntity<Object> handleCpsValidationException(CpsException exception) {
+ return buildErrorResponse(HttpStatus.BAD_REQUEST, exception.getMessage(), extractDetails(exception));
+ }
+
+ @ExceptionHandler({CpsNotFoundException.class})
+ public ResponseEntity<Object> handleCpsNotFoundException(CpsException exception) {
+ return buildErrorResponse(HttpStatus.NOT_FOUND, exception.getMessage(), extractDetails(exception));
+ }
+
+ private static ResponseEntity<Object> buildErrorResponse(HttpStatus status, Exception exception) {
+ return buildErrorResponse(status, exception.getMessage(), ExceptionUtils.getStackTrace(exception));
+ }
+
+ private static ResponseEntity<Object> buildErrorResponse(HttpStatus status, String message, String details) {
+ return new ResponseEntity<>(
+ ErrorMessage.builder().status(status.toString()).message(message).details(details).build(),
+ status
+ );
+ }
+
+ private static String extractDetails(CpsException exception) {
+ return exception.getCause() == null
+ ? exception.getDetails()
+ : ExceptionUtils.getStackTrace(exception.getCause());
+ }
+}
diff --git a/cps/cps-rest/src/main/java/org/onap/cps/rest/exceptions/ErrorMessage.java b/cps/cps-rest/src/main/java/org/onap/cps/rest/exceptions/ErrorMessage.java
new file mode 100644
index 000000000..1f2a0b786
--- /dev/null
+++ b/cps/cps-rest/src/main/java/org/onap/cps/rest/exceptions/ErrorMessage.java
@@ -0,0 +1,37 @@
+/*
+ * ============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.rest.exceptions;
+
+import lombok.Builder;
+import lombok.Data;
+
+/**
+ * Temporary POJO class used as error response model.
+ * TODO: To replace with model class generated from Open API specification.
+ *
+ */
+@Builder
+@Data
+public class ErrorMessage {
+ private String status;
+ private String message;
+ private String details;
+}
+
diff --git a/cps/cps-rest/src/main/java/org/onap/cps/swagger/config/SpringFoxConfig.java b/cps/cps-rest/src/main/java/org/onap/cps/swagger/config/SpringFoxConfig.java
new file mode 100644
index 000000000..73e179511
--- /dev/null
+++ b/cps/cps-rest/src/main/java/org/onap/cps/swagger/config/SpringFoxConfig.java
@@ -0,0 +1,46 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2020 Bell Canada. All rights reserved.
+ * ================================================================================
+ * 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.swagger.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+
+/**
+ * Swagger configuration.
+ */
+@Configuration
+public class SpringFoxConfig {
+
+ /**
+ * Define api configuration.
+ */
+ @Bean
+ public Docket api() {
+ return new Docket(DocumentationType.OAS_30)
+ .select()
+ .apis(RequestHandlerSelectors.any())
+ .paths(PathSelectors.any())
+ .build();
+ }
+}
diff --git a/cps/cps-rest/src/main/resources/application.yml b/cps/cps-rest/src/main/resources/application.yml
index 84f3f79cd..e8af0bcfb 100644
--- a/cps/cps-rest/src/main/resources/application.yml
+++ b/cps/cps-rest/src/main/resources/application.yml
@@ -1,7 +1,7 @@
server:
- port: 8080
- servlet:
- context-path: /api/cps
+ port: 8080
+ servlet:
+ context-path: /api/cps
spring:
main:
@@ -21,8 +21,6 @@ spring:
password: ${DB_PASSWORD}
driverClassName: org.postgresql.Driver
initialization-mode: always
- jersey:
- type: filter
# Actuator
management:
diff --git a/cps/cps-service/src/main/java/org/onap/cps/api/CpService.java b/cps/cps-service/src/main/java/org/onap/cps/api/CpService.java
index 2f735abc7..4d94a4654 100644
--- a/cps/cps-service/src/main/java/org/onap/cps/api/CpService.java
+++ b/cps/cps-service/src/main/java/org/onap/cps/api/CpService.java
@@ -36,7 +36,7 @@ public interface CpService {
* @param yangModelContent the input stream
* @return the schema context
*/
- SchemaContext parseAndValidateModel(final String yangModelContent) throws IOException, YangParserException;
+ SchemaContext parseAndValidateModel(final String yangModelContent);
/**
* Parse and validate a file representing a yang model to generate a schema context.
@@ -44,7 +44,7 @@ public interface CpService {
* @param yangModelFile the yang file
* @return the schema context
*/
- SchemaContext parseAndValidateModel(final File yangModelFile) throws IOException, YangParserException;
+ SchemaContext parseAndValidateModel(final File yangModelFile);
/**
* Store schema context for a yang model.
diff --git a/cps/cps-service/src/main/java/org/onap/cps/api/impl/CpServiceImpl.java b/cps/cps-service/src/main/java/org/onap/cps/api/impl/CpServiceImpl.java
index 45aad3e44..c33746e86 100644
--- a/cps/cps-service/src/main/java/org/onap/cps/api/impl/CpServiceImpl.java
+++ b/cps/cps-service/src/main/java/org/onap/cps/api/impl/CpServiceImpl.java
@@ -26,6 +26,8 @@ import java.io.FileWriter;
import java.io.IOException;
import java.util.Optional;
import org.onap.cps.api.CpService;
+import org.onap.cps.exceptions.CpsException;
+import org.onap.cps.exceptions.CpsValidationException;
import org.onap.cps.spi.DataPersistencyService;
import org.onap.cps.spi.ModelPersistencyService;
import org.onap.cps.utils.YangUtils;
@@ -47,18 +49,28 @@ public class CpServiceImpl implements CpService {
private DataPersistencyService dataPersistencyService;
@Override
- public final SchemaContext parseAndValidateModel(final String yangModelContent) throws IOException,
- YangParserException {
- final File tempFile = File.createTempFile("yang", ".yang");
- try (BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile))) {
- writer.write(yangModelContent);
+ public final SchemaContext parseAndValidateModel(final String yangModelContent) {
+
+ try {
+ final File tempFile = File.createTempFile("yang", ".yang");
+ try (BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile))) {
+ writer.write(yangModelContent);
+ }
+ return parseAndValidateModel(tempFile);
+ } catch (IOException e) {
+ throw new CpsException(e);
}
- return parseAndValidateModel(tempFile);
}
@Override
- public final SchemaContext parseAndValidateModel(final File yangModelFile) throws IOException, YangParserException {
- return YangUtils.parseYangModelFile(yangModelFile);
+ public final SchemaContext parseAndValidateModel(final File yangModelFile) {
+ try {
+ return YangUtils.parseYangModelFile(yangModelFile);
+ } catch (YangParserException e) {
+ throw new CpsValidationException("Yang file validation failed", e.getMessage());
+ } catch (IOException e) {
+ throw new CpsException(e);
+ }
}
@Override
diff --git a/cps/cps-service/src/main/java/org/onap/cps/exceptions/CpsException.java b/cps/cps-service/src/main/java/org/onap/cps/exceptions/CpsException.java
new file mode 100644
index 000000000..b54453cd9
--- /dev/null
+++ b/cps/cps-service/src/main/java/org/onap/cps/exceptions/CpsException.java
@@ -0,0 +1,62 @@
+/*
+ * ============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.exceptions;
+
+import lombok.Getter;
+import org.springframework.core.NestedExceptionUtils;
+
+/**
+ * CP Service exception.
+ */
+public class CpsException extends RuntimeException {
+
+ @Getter
+ String details;
+
+ /**
+ * Constructor.
+ *
+ * @param cause the cause of the exception
+ */
+ public CpsException(Throwable cause) {
+ super(cause.getMessage(), cause);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param message the error message
+ * @param cause the cause of the exception
+ */
+ public CpsException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param message the error message
+ * @param details the error details
+ */
+ public CpsException(String message, String details) {
+ super(message);
+ this.details = details;
+ }
+}
diff --git a/cps/cps-service/src/main/java/org/onap/cps/exceptions/CpsNotFoundException.java b/cps/cps-service/src/main/java/org/onap/cps/exceptions/CpsNotFoundException.java
new file mode 100644
index 000000000..f44fe806c
--- /dev/null
+++ b/cps/cps-service/src/main/java/org/onap/cps/exceptions/CpsNotFoundException.java
@@ -0,0 +1,57 @@
+/*
+ * ============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.exceptions;
+
+import lombok.Getter;
+
+/**
+ * CP Service exception. Indicates the requested data being absent.
+ */
+public class CpsNotFoundException extends CpsException {
+
+ /**
+ * Constructor.
+ *
+ * @param cause the cause of the exception
+ */
+ public CpsNotFoundException(Throwable cause) {
+ super(cause.getMessage(), cause);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param message the error message
+ * @param cause the cause of the exception
+ */
+ public CpsNotFoundException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param message the error message
+ * @param details the error details
+ */
+ public CpsNotFoundException(String message, String details) {
+ super(message, details);
+ }
+}
diff --git a/cps/cps-service/src/main/java/org/onap/cps/exceptions/CpsValidationException.java b/cps/cps-service/src/main/java/org/onap/cps/exceptions/CpsValidationException.java
new file mode 100644
index 000000000..dba9c165b
--- /dev/null
+++ b/cps/cps-service/src/main/java/org/onap/cps/exceptions/CpsValidationException.java
@@ -0,0 +1,55 @@
+/*
+ * ============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.exceptions;
+
+/**
+ * CP Service exception. Indicates the parameter validation failure.
+ */
+public class CpsValidationException extends CpsException {
+
+ /**
+ * Constructor.
+ *
+ * @param cause the cause of the exception
+ */
+ public CpsValidationException(Throwable cause) {
+ super(cause.getMessage(), cause);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param message the error message
+ * @param cause the cause of the exception
+ */
+ public CpsValidationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param message the error message
+ * @param details the error details
+ */
+ public CpsValidationException(String message, String details) {
+ super(message, details);
+ }
+}
diff --git a/cps/cps-service/src/test/groovy/org/onap/cps/api/impl/CpServiceImplSpec.groovy b/cps/cps-service/src/test/groovy/org/onap/cps/api/impl/CpServiceImplSpec.groovy
index 5e6fccb7a..5f42810bd 100644
--- a/cps/cps-service/src/test/groovy/org/onap/cps/api/impl/CpServiceImplSpec.groovy
+++ b/cps/cps-service/src/test/groovy/org/onap/cps/api/impl/CpServiceImplSpec.groovy
@@ -21,11 +21,10 @@
package org.onap.cps.api.impl
import org.onap.cps.TestUtils
+import org.onap.cps.exceptions.CpsValidationException
import org.onap.cps.spi.DataPersistencyService
-
import org.opendaylight.yangtools.yang.common.Revision
import org.opendaylight.yangtools.yang.model.api.SchemaContext
-import org.opendaylight.yangtools.yang.model.parser.api.YangParserException
import spock.lang.Specification
class CpServiceImplSpec extends Specification {
@@ -73,8 +72,8 @@ class CpServiceImplSpec extends Specification {
File file = new File(ClassLoader.getSystemClassLoader().getResource('invalid.yang').getFile())
when: 'the model is parsed and validated'
objectUnderTest.parseAndValidateModel(file)
- then: 'a YangParserException is thrown'
- thrown(YangParserException)
+ then: 'a CpsValidationException is thrown'
+ thrown(CpsValidationException)
}
def 'Store a SchemaContext'() {