diff options
16 files changed, 538 insertions, 192 deletions
diff --git a/cps/README.md b/cps/README.md index d1bf49d8cf..d5f0c66f4c 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 6f50cd0fc1..ee37b1e0a2 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 4984b61942..0fe2e101a5 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 f116c26cec..9b2ac1ec5d 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 2d125803d4..4f8746a366 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 a577af70ec..90c287cdaf 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 0000000000..9cf4935d4e --- /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 0000000000..1f2a0b7860 --- /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 0000000000..73e179511b --- /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 84f3f79cda..e8af0bcfb2 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 2f735abc7d..4d94a46547 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 45aad3e446..c33746e861 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 0000000000..b54453cd90 --- /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 0000000000..f44fe806cf --- /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 0000000000..dba9c165b8 --- /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 5e6fccb7a1..5f42810bd5 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'() { |