From ccf9b0dc2858265e3a3d7da28a653f6bc7e2e8a3 Mon Sep 17 00:00:00 2001 From: "saul.gill" Date: Fri, 9 Jul 2021 12:10:46 +0100 Subject: Added get json schema endpoints Added runtime-controlloop endpoint to return Json Schema Schema returned can be for specified type within Tosca Service Template Added Camel in runtime endpoint to proxy the Schema endpoint Dependency added to pom for the json schema generation Issue-ID: POLICY-3439 Change-Id: I2a98ce16dfb3761a174c90f4b965d1a37a0d8576 Signed-off-by: saul.gill --- runtime-controlloop/pom.xml | 11 + .../commissioning/CommissioningProvider.java | 56 ++++ .../runtime/main/rest/CommissioningController.java | 332 +++++++++++++-------- 3 files changed, 270 insertions(+), 129 deletions(-) (limited to 'runtime-controlloop') diff --git a/runtime-controlloop/pom.xml b/runtime-controlloop/pom.xml index 2e3b4e902..e436451ff 100644 --- a/runtime-controlloop/pom.xml +++ b/runtime-controlloop/pom.xml @@ -44,6 +44,17 @@ policy-clamp-models ${project.version} + + com.fasterxml.jackson.module + jackson-module-jsonSchema + ${version.jackson} + + + javax.validation + validation-api + + + org.springframework.boot spring-boot-starter-web diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/commissioning/CommissioningProvider.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/commissioning/CommissioningProvider.java index 22809e8c0..f291c4e89 100644 --- a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/commissioning/CommissioningProvider.java +++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/commissioning/CommissioningProvider.java @@ -20,6 +20,11 @@ package org.onap.policy.clamp.controlloop.runtime.commissioning; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.fasterxml.jackson.module.jsonSchema.JsonSchema; +import com.fasterxml.jackson.module.jsonSchema.factories.SchemaFactoryWrapper; import java.io.Closeable; import java.io.IOException; import java.util.ArrayList; @@ -36,10 +41,16 @@ import org.onap.policy.models.base.PfModelException; import org.onap.policy.models.base.PfModelRuntimeException; import org.onap.policy.models.provider.PolicyModelsProvider; import org.onap.policy.models.provider.PolicyModelsProviderFactory; +import org.onap.policy.models.tosca.authorative.concepts.ToscaCapabilityType; import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; +import org.onap.policy.models.tosca.authorative.concepts.ToscaDataType; import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate; +import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeType; +import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyType; +import org.onap.policy.models.tosca.authorative.concepts.ToscaRelationshipType; import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate; import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplates; +import org.onap.policy.models.tosca.authorative.concepts.ToscaTopologyTemplate; import org.onap.policy.models.tosca.authorative.concepts.ToscaTypedEntityFilter; import org.springframework.stereotype.Component; @@ -207,4 +218,49 @@ public class CommissioningProvider implements Closeable { serviceTemplates.setServiceTemplates(modelsProvider.getServiceTemplateList(name, version)); return serviceTemplates.getServiceTemplates().get(0); } + + /** + * Get the requested json schema. + * + * @param section section of the tosca service template to get schema for + * @return the specified tosca service template or section Json Schema + * @throws PfModelException on errors with retrieving the classes + * @throws JsonProcessingException on errors generating the schema + */ + public String getToscaServiceTemplateSchema(String section) throws PfModelException, JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE); + SchemaFactoryWrapper visitor = new SchemaFactoryWrapper(); + + switch (section) { + case "data_types": + mapper.acceptJsonFormatVisitor(mapper.constructType(ToscaDataType.class), visitor); + break; + case "capability_types": + mapper.acceptJsonFormatVisitor(mapper.constructType(ToscaCapabilityType.class), visitor); + break; + case "node_types": + mapper.acceptJsonFormatVisitor(mapper.constructType(ToscaNodeType.class), visitor); + break; + case "relationship_types": + mapper.acceptJsonFormatVisitor(mapper.constructType(ToscaRelationshipType.class), visitor); + break; + case "policy_types": + mapper.acceptJsonFormatVisitor(mapper.constructType(ToscaPolicyType.class), visitor); + break; + case "topology_template": + mapper.acceptJsonFormatVisitor(mapper.constructType(ToscaTopologyTemplate.class), visitor); + break; + case "node_templates": + mapper.acceptJsonFormatVisitor(mapper.constructType(ToscaNodeTemplate.class), visitor); + break; + default: + mapper.acceptJsonFormatVisitor(mapper.constructType(ToscaServiceTemplate.class), visitor); + } + + JsonSchema jsonSchema = visitor.finalSchema(); + String response = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonSchema); + + return response; + } } diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/rest/CommissioningController.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/rest/CommissioningController.java index a03254272..b50e7a0ed 100644 --- a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/rest/CommissioningController.java +++ b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/rest/CommissioningController.java @@ -20,6 +20,11 @@ package org.onap.policy.clamp.controlloop.runtime.main.rest; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.fasterxml.jackson.module.jsonSchema.JsonSchema; +import com.fasterxml.jackson.module.jsonSchema.factories.SchemaFactoryWrapper; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import io.swagger.annotations.ApiResponse; @@ -30,6 +35,7 @@ import io.swagger.annotations.ExtensionProperty; import io.swagger.annotations.ResponseHeader; import java.util.List; import java.util.UUID; +import javax.ws.rs.core.Response.Status; import org.onap.policy.clamp.controlloop.models.messages.rest.commissioning.CommissioningResponse; import org.onap.policy.clamp.controlloop.runtime.commissioning.CommissioningProvider; import org.onap.policy.clamp.controlloop.runtime.main.web.AbstractRestController; @@ -81,39 +87,39 @@ public class CommissioningController extends AbstractRestController { consumes = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML}, produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML}) @ApiOperation( - value = "Commissions control loop definitions", - notes = "Commissions control loop definitions, returning the commissioned control loop definition IDs", - response = CommissioningResponse.class, - tags = {"Control Loop Commissioning API"}, - authorizations = @Authorization(value = AUTHORIZATION_TYPE), - responseHeaders = { - @ResponseHeader( - name = VERSION_MINOR_NAME, - description = VERSION_MINOR_DESCRIPTION, - response = String.class), - @ResponseHeader( - name = VERSION_PATCH_NAME, - description = VERSION_PATCH_DESCRIPTION, - response = String.class), - @ResponseHeader( - name = VERSION_LATEST_NAME, - description = VERSION_LATEST_DESCRIPTION, - response = String.class), - @ResponseHeader( - name = REQUEST_ID_NAME, - description = REQUEST_ID_HDR_DESCRIPTION, - response = UUID.class) - }, - extensions = { - @Extension - ( - name = EXTENSION_NAME, - properties = { - @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION), - @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE) - } - ) - } + value = "Commissions control loop definitions", + notes = "Commissions control loop definitions, returning the commissioned control loop definition IDs", + response = CommissioningResponse.class, + tags = {"Control Loop Commissioning API"}, + authorizations = @Authorization(value = AUTHORIZATION_TYPE), + responseHeaders = { + @ResponseHeader( + name = VERSION_MINOR_NAME, + description = VERSION_MINOR_DESCRIPTION, + response = String.class), + @ResponseHeader( + name = VERSION_PATCH_NAME, + description = VERSION_PATCH_DESCRIPTION, + response = String.class), + @ResponseHeader( + name = VERSION_LATEST_NAME, + description = VERSION_LATEST_DESCRIPTION, + response = String.class), + @ResponseHeader( + name = REQUEST_ID_NAME, + description = REQUEST_ID_HDR_DESCRIPTION, + response = UUID.class) + }, + extensions = { + @Extension + ( + name = EXTENSION_NAME, + properties = { + @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION), + @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE) + } + ) + } ) @ApiResponses( value = { @@ -152,37 +158,37 @@ public class CommissioningController extends AbstractRestController { @DeleteMapping(value = "/commission", produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML}) @ApiOperation(value = "Delete a commissioned control loop", - notes = "Deletes a Commissioned Control Loop, returning optional error details", - response = CommissioningResponse.class, - tags = {"Clamp Control Loop Commissioning API"}, - authorizations = @Authorization(value = AUTHORIZATION_TYPE), - responseHeaders = { - @ResponseHeader( - name = VERSION_MINOR_NAME, - description = VERSION_MINOR_DESCRIPTION, - response = String.class), - @ResponseHeader( - name = VERSION_PATCH_NAME, - description = VERSION_PATCH_DESCRIPTION, - response = String.class), - @ResponseHeader( - name = VERSION_LATEST_NAME, - description = VERSION_LATEST_DESCRIPTION, - response = String.class), - @ResponseHeader( - name = REQUEST_ID_NAME, - description = REQUEST_ID_HDR_DESCRIPTION, - response = UUID.class)}, - extensions = { - @Extension - ( - name = EXTENSION_NAME, - properties = { - @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION), - @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE) - } - ) - } + notes = "Deletes a Commissioned Control Loop, returning optional error details", + response = CommissioningResponse.class, + tags = {"Clamp Control Loop Commissioning API"}, + authorizations = @Authorization(value = AUTHORIZATION_TYPE), + responseHeaders = { + @ResponseHeader( + name = VERSION_MINOR_NAME, + description = VERSION_MINOR_DESCRIPTION, + response = String.class), + @ResponseHeader( + name = VERSION_PATCH_NAME, + description = VERSION_PATCH_DESCRIPTION, + response = String.class), + @ResponseHeader( + name = VERSION_LATEST_NAME, + description = VERSION_LATEST_DESCRIPTION, + response = String.class), + @ResponseHeader( + name = REQUEST_ID_NAME, + description = REQUEST_ID_HDR_DESCRIPTION, + response = UUID.class)}, + extensions = { + @Extension + ( + name = EXTENSION_NAME, + properties = { + @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION), + @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE) + } + ) + } ) @ApiResponses( value = { @@ -226,21 +232,21 @@ public class CommissioningController extends AbstractRestController { @GetMapping(value = "/commission", produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML}) @ApiOperation(value = "Query details of the requested commissioned control loop definitions", - notes = "Queries details of the requested commissioned control loop definitions, " - + "returning all control loop details", - response = ToscaNodeTemplate.class, - tags = {"Clamp Control Loop Commissioning API"}, - authorizations = @Authorization(value = AUTHORIZATION_TYPE), - responseHeaders = { - @ResponseHeader( - name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION, - response = String.class), - @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION, - response = String.class), - @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION, - response = String.class), - @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION, - response = UUID.class)}, + notes = "Queries details of the requested commissioned control loop definitions, " + + "returning all control loop details", + response = ToscaNodeTemplate.class, + tags = {"Clamp Control Loop Commissioning API"}, + authorizations = @Authorization(value = AUTHORIZATION_TYPE), + responseHeaders = { + @ResponseHeader( + name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION, + response = String.class), + @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION, + response = String.class), + @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION, + response = String.class), + @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION, + response = UUID.class)}, extensions = { @Extension ( @@ -295,31 +301,31 @@ public class CommissioningController extends AbstractRestController { @GetMapping(value = "/commission/toscaservicetemplate", produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML}) @ApiOperation(value = "Query details of the requested tosca service templates", - notes = "Queries details of the requested commissioned tosca service template, " - + "returning all tosca service template details", - response = ToscaServiceTemplate.class, - tags = {"Clamp Control Loop Commissioning API"}, - authorizations = @Authorization(value = AUTHORIZATION_TYPE), - responseHeaders = { - @ResponseHeader( - name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION, - response = String.class), - @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION, - response = String.class), - @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION, - response = String.class), - @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION, - response = UUID.class)}, - extensions = { - @Extension - ( - name = EXTENSION_NAME, - properties = { - @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION), - @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE) - } - ) - } + notes = "Queries details of the requested commissioned tosca service template, " + + "returning all tosca service template details", + response = ToscaServiceTemplate.class, + tags = {"Clamp Control Loop Commissioning API"}, + authorizations = @Authorization(value = AUTHORIZATION_TYPE), + responseHeaders = { + @ResponseHeader( + name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION, + response = String.class), + @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION, + response = String.class), + @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION, + response = String.class), + @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION, + response = UUID.class)}, + extensions = { + @Extension + ( + name = EXTENSION_NAME, + properties = { + @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION), + @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE) + } + ) + } ) @ApiResponses( value = { @@ -352,6 +358,74 @@ public class CommissioningController extends AbstractRestController { } + /** + * Retrieves the Json Schema for the specified Tosca Service Template. + * + * @param requestId request ID used in ONAP logging + * @param section section of the tosca service template to get schema for + * @return the specified tosca service template or section Json Schema + */ + // @formatter:off + @GetMapping(value = "/commission/toscaServiceTemplateSchema", + produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML}) + @ApiOperation(value = "Query details of the requested tosca service template json schema", + notes = "Queries details of the requested commissioned tosca service template json schema, " + + "returning all tosca service template json schema details", + response = ToscaServiceTemplate.class, + tags = {"Clamp Control Loop Commissioning API"}, + authorizations = @Authorization(value = AUTHORIZATION_TYPE), + responseHeaders = { + @ResponseHeader( + name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION, + response = String.class), + @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION, + response = String.class), + @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION, + response = String.class), + @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION, + response = UUID.class)}, + extensions = { + @Extension + ( + name = EXTENSION_NAME, + properties = { + @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION), + @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE) + } + ) + } + ) + @ApiResponses( + value = { + @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE), + @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE), + @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE) + } + ) + // @formatter:on + public ResponseEntity queryToscaServiceTemplateJsonSchema( + @RequestHeader( + name = REQUEST_ID_NAME, + required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId, + @ApiParam(value = "Section of Template schema is desired for", required = false) @RequestParam( + value = "section", + required = false, defaultValue = "all") String section) { + try { + return ResponseEntity.ok().body(provider.getToscaServiceTemplateSchema(section)); + + } catch (PfModelRuntimeException | PfModelException e) { + LOGGER.warn("Get of tosca service template json schema failed", e); + var resp = new CommissioningResponse(); + resp.setErrorDetails(e.getErrorResponse().getErrorMessage()); + return ResponseEntity.status(e.getErrorResponse().getResponseCode().getStatusCode()).body(resp); + } catch (JsonProcessingException e) { + LOGGER.warn("Get of tosca service template json schema failed", e); + var resp = new CommissioningResponse(); + resp.setErrorDetails(e.getMessage()); + return ResponseEntity.status(Status.BAD_REQUEST.getStatusCode()).body(resp); + } + } + /** * Queries the elements of a specific control loop. * @@ -364,31 +438,31 @@ public class CommissioningController extends AbstractRestController { @GetMapping(value = "/commission/elements", produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML}) @ApiOperation(value = "Query details of the requested commissioned control loop element definitions", - notes = "Queries details of the requested commissioned control loop element definitions, " - + "returning all control loop elements' details", - response = ToscaNodeTemplate.class, - tags = {"Clamp Control Loop Commissioning API"}, - authorizations = @Authorization(value = AUTHORIZATION_TYPE), - responseHeaders = { - @ResponseHeader( - name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION, - response = String.class), - @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION, - response = String.class), - @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION, - response = String.class), - @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION, - response = UUID.class)}, - extensions = { - @Extension - ( - name = EXTENSION_NAME, - properties = { - @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION), - @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE) - } - ) - } + notes = "Queries details of the requested commissioned control loop element definitions, " + + "returning all control loop elements' details", + response = ToscaNodeTemplate.class, + tags = {"Clamp Control Loop Commissioning API"}, + authorizations = @Authorization(value = AUTHORIZATION_TYPE), + responseHeaders = { + @ResponseHeader( + name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION, + response = String.class), + @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION, + response = String.class), + @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION, + response = String.class), + @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION, + response = UUID.class)}, + extensions = { + @Extension + ( + name = EXTENSION_NAME, + properties = { + @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION), + @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE) + } + ) + } ) @ApiResponses( value = { -- cgit 1.2.3-korg