Handle Exceptions in Rest Control Loop Runtime 46/123146/1
authorFrancescoFioraEst <francesco.fiora@est.tech>
Tue, 3 Aug 2021 15:54:30 +0000 (16:54 +0100)
committerFrancesco Fiora <francesco.fiora@est.tech>
Thu, 5 Aug 2021 12:26:45 +0000 (12:26 +0000)
POLICY-3462: Handle Exceptions in Rest Control Loop Runtime
Change-Id: I586f6f6d85f9253cb2a29c70df38c49ca26c5852
Signed-off-by: FrancescoFioraEst <francesco.fiora@est.tech>
runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/commissioning/CommissioningProvider.java
runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/rest/CommissioningController.java
runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/rest/InstantiationController.java
runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/rest/MonitoringQueryController.java
runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/web/GlobalControllerExceptionHandler.java [new file with mode: 0644]

index 891d420..e676cbe 100644 (file)
@@ -30,6 +30,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
+import javax.ws.rs.core.Response.Status;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.MapUtils;
 import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ControlLoopProvider;
@@ -60,6 +61,7 @@ public class CommissioningProvider {
 
     private final PolicyModelsProvider modelsProvider;
     private final ControlLoopProvider clProvider;
+    private final ObjectMapper mapper = new ObjectMapper();
 
     private static final Object lockit = new Object();
 
@@ -72,6 +74,7 @@ public class CommissioningProvider {
     public CommissioningProvider(PolicyModelsProvider modelsProvider, ControlLoopProvider clProvider) {
         this.modelsProvider = modelsProvider;
         this.clProvider = clProvider;
+        mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
     }
 
     /**
@@ -189,8 +192,8 @@ public class CommissioningProvider {
      * @return node types map that only has common properties
      * @throws PfModelException on errors getting node type with common properties
      */
-    private Map<String, ToscaNodeType> getInitialNodeTypesMap(
-        Map<String, ToscaNodeType> fullNodeTypes, boolean common) {
+    private Map<String, ToscaNodeType> getInitialNodeTypesMap(Map<String, ToscaNodeType> fullNodeTypes,
+            boolean common) {
 
         var tempNodeTypesMap = new HashMap<String, ToscaNodeType>();
 
@@ -198,8 +201,7 @@ public class CommissioningProvider {
             var tempToscaNodeType = new ToscaNodeType();
             tempToscaNodeType.setName(key);
 
-            var resultantPropertyMap = findCommonOrInstancePropsInNodeTypes(
-                nodeType, common);
+            var resultantPropertyMap = findCommonOrInstancePropsInNodeTypes(nodeType, common);
 
             if (!resultantPropertyMap.isEmpty()) {
                 tempToscaNodeType.setProperties(resultantPropertyMap);
@@ -209,8 +211,7 @@ public class CommissioningProvider {
         return tempNodeTypesMap;
     }
 
-    private Map<String, ToscaProperty> findCommonOrInstancePropsInNodeTypes(
-        ToscaNodeType nodeType, boolean common) {
+    private Map<String, ToscaProperty> findCommonOrInstancePropsInNodeTypes(ToscaNodeType nodeType, boolean common) {
 
         var tempCommonPropertyMap = new HashMap<String, ToscaProperty>();
         var tempInstancePropertyMap = new HashMap<String, ToscaProperty>();
@@ -246,9 +247,8 @@ public class CommissioningProvider {
      * @return all node types that have common properties including their children
      * @throws PfModelException on errors getting node type with common properties
      */
-    private Map<String, ToscaNodeType> getFinalNodeTypesMap(
-        Map<String, ToscaNodeType> initialNodeTypes,
-        Map<String, ToscaNodeType> filteredNodeTypes) {
+    private Map<String, ToscaNodeType> getFinalNodeTypesMap(Map<String, ToscaNodeType> initialNodeTypes,
+            Map<String, ToscaNodeType> filteredNodeTypes) {
         for (var i = 0; i < initialNodeTypes.size(); i++) {
             initialNodeTypes.forEach((key, nodeType) -> {
                 var tempToscaNodeType = new ToscaNodeType();
@@ -258,7 +258,7 @@ public class CommissioningProvider {
                     tempToscaNodeType.setName(key);
 
                     var finalProps = new HashMap<String, ToscaProperty>(
-                        filteredNodeTypes.get(nodeType.getDerivedFrom()).getProperties());
+                            filteredNodeTypes.get(nodeType.getDerivedFrom()).getProperties());
 
                     tempToscaNodeType.setProperties(finalProps);
                 } else {
@@ -280,16 +280,15 @@ public class CommissioningProvider {
      * @return the node types with common or instance properties
      * @throws PfModelException on errors getting node type properties
      */
-    private Map<String, ToscaNodeType> getCommonOrInstancePropertiesFromNodeTypes(
-        boolean common, String name, String version)
-        throws PfModelException {
+    private Map<String, ToscaNodeType> getCommonOrInstancePropertiesFromNodeTypes(boolean common, String name,
+            String version) throws PfModelException {
         var serviceTemplates = new ToscaServiceTemplates();
         serviceTemplates.setServiceTemplates(modelsProvider.getServiceTemplateList(name, version));
         var tempNodeTypesMap =
-            this.getInitialNodeTypesMap(serviceTemplates.getServiceTemplates().get(0).getNodeTypes(), common);
+                this.getInitialNodeTypesMap(serviceTemplates.getServiceTemplates().get(0).getNodeTypes(), common);
 
-        return this.getFinalNodeTypesMap(
-            serviceTemplates.getServiceTemplates().get(0).getNodeTypes(), tempNodeTypesMap);
+        return this.getFinalNodeTypesMap(serviceTemplates.getServiceTemplates().get(0).getNodeTypes(),
+                tempNodeTypesMap);
 
     }
 
@@ -302,8 +301,7 @@ public class CommissioningProvider {
      * @throws PfModelException on errors getting map of node templates with common or instance properties added
      */
     private Map<String, ToscaNodeTemplate> getDerivedCommonOrInstanceNodeTemplates(
-        Map<String, ToscaNodeTemplate> initialNodeTemplates,
-        Map<String, ToscaNodeType> nodeTypeProps) {
+            Map<String, ToscaNodeTemplate> initialNodeTemplates, Map<String, ToscaNodeType> nodeTypeProps) {
 
         var finalNodeTemplatesMap = new HashMap<String, ToscaNodeTemplate>();
 
@@ -332,18 +330,17 @@ public class CommissioningProvider {
      * @return the nodes templates with common or instance properties
      * @throws PfModelException on errors getting common or instance properties from node_templates
      */
-    public Map<String, ToscaNodeTemplate> getNodeTemplatesWithCommonOrInstanceProperties(
-        boolean common, String name, String version) throws PfModelException {
+    public Map<String, ToscaNodeTemplate> getNodeTemplatesWithCommonOrInstanceProperties(boolean common, String name,
+            String version) throws PfModelException {
 
-        var commonOrInstanceNodeTypeProps =
-            this.getCommonOrInstancePropertiesFromNodeTypes(common, name, version);
+        var commonOrInstanceNodeTypeProps = this.getCommonOrInstancePropertiesFromNodeTypes(common, name, version);
 
         var serviceTemplates = new ToscaServiceTemplates();
         serviceTemplates.setServiceTemplates(modelsProvider.getServiceTemplateList(name, version));
 
         return this.getDerivedCommonOrInstanceNodeTemplates(
-            serviceTemplates.getServiceTemplates().get(0).getToscaTopologyTemplate().getNodeTemplates(),
-            commonOrInstanceNodeTypeProps);
+                serviceTemplates.getServiceTemplates().get(0).getToscaTopologyTemplate().getNodeTemplates(),
+                commonOrInstanceNodeTypeProps);
     }
 
     /**
@@ -368,7 +365,7 @@ public class CommissioningProvider {
      * @return the tosca service template
      * @throws PfModelException on errors getting tosca service template
      */
-    public Map<String, Object> getToscaServiceTemplateReduced(String name, String version) throws PfModelException {
+    public String getToscaServiceTemplateReduced(String name, String version) throws PfModelException {
         var serviceTemplates = new ToscaServiceTemplates();
         serviceTemplates.setServiceTemplates(modelsProvider.getServiceTemplateList(name, version));
 
@@ -381,7 +378,12 @@ public class CommissioningProvider {
         template.put("node_types", fullTemplate.getNodeTypes());
         template.put("topology_template", fullTemplate.getToscaTopologyTemplate());
 
-        return template;
+        try {
+            return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(template);
+
+        } catch (JsonProcessingException e) {
+            throw new PfModelException(Status.BAD_REQUEST, "Converion to Json Schema failed", e);
+        }
     }
 
     /**
@@ -390,41 +392,43 @@ public class CommissioningProvider {
      * @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 {
-        var mapper = new ObjectMapper();
-        mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
+    public String getToscaServiceTemplateSchema(String section) throws PfModelException {
         var 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.getTypeFactory()
-                    .constructCollectionType(List.class, ToscaNodeTemplate.class), visitor);
-                break;
-            default:
-                mapper.acceptJsonFormatVisitor(mapper.constructType(ToscaServiceTemplate.class), visitor);
-        }
+        try {
+            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.getTypeFactory().constructCollectionType(List.class, ToscaNodeTemplate.class),
+                            visitor);
+                    break;
+                default:
+                    mapper.acceptJsonFormatVisitor(mapper.constructType(ToscaServiceTemplate.class), visitor);
+            }
 
-        var jsonSchema = visitor.finalSchema();
-        return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonSchema);
+            var jsonSchema = visitor.finalSchema();
+            return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonSchema);
+        } catch (JsonProcessingException e) {
+            throw new PfModelException(Status.BAD_REQUEST, "Converion to Json Schema failed", e);
+        }
     }
 }
index 8fe3c0c..ec7f14d 100644 (file)
@@ -20,9 +20,6 @@
 
 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 io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
 import io.swagger.annotations.ApiResponse;
@@ -32,18 +29,16 @@ import io.swagger.annotations.Extension;
 import io.swagger.annotations.ExtensionProperty;
 import io.swagger.annotations.ResponseHeader;
 import java.util.List;
+import java.util.Map;
 import java.util.UUID;
 import javax.ws.rs.core.Response.Status;
+import lombok.RequiredArgsConstructor;
 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;
 import org.onap.policy.models.base.PfModelException;
-import org.onap.policy.models.base.PfModelRuntimeException;
 import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate;
 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.http.HttpStatus;
 import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.DeleteMapping;
@@ -58,29 +53,20 @@ import org.springframework.web.bind.annotation.RestController;
  * Class to provide REST end points for creating, deleting, querying commissioned control loops.
  */
 @RestController
+@RequiredArgsConstructor
 public class CommissioningController extends AbstractRestController {
 
-    private static final Logger LOGGER = LoggerFactory.getLogger(CommissioningController.class);
-
     private static final String TAGS = "Clamp Control Loop Commissioning API";
 
     private final CommissioningProvider provider;
 
-    /**
-     * Create Commissioning Controller.
-     *
-     * @param provider the CommissioningProvider
-     */
-    public CommissioningController(CommissioningProvider provider) {
-        this.provider = provider;
-    }
-
     /**
      * Creates a control loop definition.
      *
      * @param requestId request ID used in ONAP logging
      * @param body the body of control loop following TOSCA definition
      * @return a response
+     * @throws PfModelException on errors creating a control loop definition
      */
     // @formatter:off
     @PostMapping(value = "/commission",
@@ -133,17 +119,10 @@ public class CommissioningController extends AbstractRestController {
             @RequestHeader(
                     name = REQUEST_ID_NAME,
                     required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
-            @ApiParam(value = "Entity Body of Control Loop", required = true) @RequestBody ToscaServiceTemplate body) {
-        try {
-            return ResponseEntity.ok().body(provider.createControlLoopDefinitions(body));
-
-        } catch (PfModelRuntimeException | PfModelException e) {
-            LOGGER.warn("Commissioning of the control loops failed", e);
-            var resp = new CommissioningResponse();
-            resp.setErrorDetails(e.getErrorResponse().getErrorMessage());
-            return ResponseEntity.status(e.getErrorResponse().getResponseCode().getStatusCode()).body(resp);
-        }
+            @ApiParam(value = "Entity Body of Control Loop", required = true) @RequestBody ToscaServiceTemplate body)
+            throws PfModelException {
 
+        return ResponseEntity.ok().body(provider.createControlLoopDefinitions(body));
     }
 
     /**
@@ -153,6 +132,7 @@ public class CommissioningController extends AbstractRestController {
      * @param name the name of the control loop definition to delete
      * @param version the version of the control loop definition to delete
      * @return a response
+     * @throws PfModelException on errors deleting a control loop definition
      */
     // @formatter:off
     @DeleteMapping(value = "/commission",
@@ -206,18 +186,10 @@ public class CommissioningController extends AbstractRestController {
                     value = "name") String name,
             @ApiParam(
                     value = "Control Loop definition version",
-                    required = true) @RequestParam("version") String version) {
-
-        try {
-            return ResponseEntity.ok().body(provider.deleteControlLoopDefinition(name, version));
-
-        } catch (PfModelRuntimeException | PfModelException e) {
-            LOGGER.warn("Decommisssioning of control loop failed", e);
-            var resp = new CommissioningResponse();
-            resp.setErrorDetails(e.getErrorResponse().getErrorMessage());
-            return ResponseEntity.status(e.getErrorResponse().getResponseCode().getStatusCode()).body(resp);
-        }
+                    required = true) @RequestParam("version") String version)
+            throws PfModelException {
 
+        return ResponseEntity.ok().body(provider.deleteControlLoopDefinition(name, version));
     }
 
     /**
@@ -227,6 +199,7 @@ public class CommissioningController extends AbstractRestController {
      * @param name the name of the control loop definition to get, null for all definitions
      * @param version the version of the control loop definition to get, null for all definitions
      * @return the control loop definitions
+     * @throws PfModelException on errors getting details of all or specific control loop definitions
      */
     // @formatter:off
     @GetMapping(value = "/commission",
@@ -266,7 +239,7 @@ public class CommissioningController extends AbstractRestController {
         }
     )
     // @formatter:on
-    public ResponseEntity<?> query(
+    public ResponseEntity<List<ToscaNodeTemplate>> query(
             @RequestHeader(
                     name = REQUEST_ID_NAME,
                     required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
@@ -275,18 +248,10 @@ public class CommissioningController extends AbstractRestController {
                     required = false) String name,
             @ApiParam(value = "Control Loop definition version", required = false) @RequestParam(
                     value = "version",
-                    required = false) String version) {
-
-        try {
-            return ResponseEntity.ok().body(provider.getControlLoopDefinitions(name, version));
-
-        } catch (PfModelRuntimeException | PfModelException e) {
-            LOGGER.warn("Get of control loop definitions failed", e);
-            var resp = new CommissioningResponse();
-            resp.setErrorDetails(e.getErrorResponse().getErrorMessage());
-            return ResponseEntity.status(e.getErrorResponse().getResponseCode().getStatusCode()).body(resp);
-        }
+                    required = false) String version)
+            throws PfModelException {
 
+        return ResponseEntity.ok().body(provider.getControlLoopDefinitions(name, version));
     }
 
     /**
@@ -296,6 +261,7 @@ public class CommissioningController extends AbstractRestController {
      * @param name the name of the tosca service template to retrieve
      * @param version the version of the tosca service template to get
      * @return the specified tosca service template
+     * @throws PfModelException on errors getting the Tosca Service Template
      */
     // @formatter:off
     @GetMapping(value = "/commission/toscaservicetemplate",
@@ -335,36 +301,19 @@ public class CommissioningController extends AbstractRestController {
         }
     )
     // @formatter:on
-    public ResponseEntity<?> queryToscaServiceTemplate(
+    public ResponseEntity<String> queryToscaServiceTemplate(
             @RequestHeader(
                     name = REQUEST_ID_NAME,
                     required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
             @ApiParam(value = "Tosca service template name", required = false) @RequestParam(
                     value = "name",
                     required = false) String name,
-            @ApiParam(value = "Tosca service template version", required = true) @RequestParam(
+            @ApiParam(value = "Tosca service template version", required = false) @RequestParam(
                     value = "version",
-                    required = false) String version) {
-
-        try {
-            var mapper = new ObjectMapper();
-            mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
-            var response = mapper.writerWithDefaultPrettyPrinter()
-                .writeValueAsString(provider.getToscaServiceTemplateReduced(name, version));
+                    required = false) String version)
+            throws PfModelException {
 
-            return ResponseEntity.ok().body(response);
-
-        } catch (PfModelRuntimeException | PfModelException e) {
-            LOGGER.warn("Get of tosca service template 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 failed", e);
-            var resp = new CommissioningResponse();
-            resp.setErrorDetails(e.getMessage());
-            return ResponseEntity.status(Status.BAD_REQUEST.getStatusCode()).body(resp);
-        }
+        return ResponseEntity.ok().body(provider.getToscaServiceTemplateReduced(name, version));
     }
 
     /**
@@ -373,6 +322,7 @@ public class CommissioningController extends AbstractRestController {
      * @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
+     * @throws PfModelException on errros getting the Json Schema for the specified Tosca Service Template
      */
     // @formatter:off
     @GetMapping(value = "/commission/toscaServiceTemplateSchema",
@@ -412,27 +362,17 @@ public class CommissioningController extends AbstractRestController {
         }
     )
     // @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));
+    public ResponseEntity<String> 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)
+            throws PfModelException {
 
-        } 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);
-        }
+        return ResponseEntity.ok().body(provider.getToscaServiceTemplateSchema(section));
     }
 
     /**
@@ -443,6 +383,7 @@ public class CommissioningController extends AbstractRestController {
      * @param name the name of the tosca service template to retrieve
      * @param version the version of the tosca service template to get
      * @return the specified tosca service template or section Json Schema
+     * @throws PfModelException on errors getting the Common or Instance Properties
      */
     // @formatter:off
     @GetMapping(value = "/commission/getCommonOrInstanceProperties",
@@ -482,30 +423,23 @@ public class CommissioningController extends AbstractRestController {
         }
     )
     // @formatter:on
-    public ResponseEntity<?> queryToscaServiceCommonOrInstanceProperties(
-        @RequestHeader(
-            name = REQUEST_ID_NAME,
-            required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
-        @ApiParam(value = "Flag, true for common properties, false for instance", required = false) @RequestParam(
-            value = "common",
-            defaultValue = "false",
-            required = false) boolean common,
-        @ApiParam(value = "Tosca service template name", required = false) @RequestParam(
-            value = "name",
-            required = false) String name,
-        @ApiParam(value = "Tosca service template version", required = true) @RequestParam(
-            value = "version",
-            required = false) String version) {
-        try {
-            return ResponseEntity.ok().body(provider.getNodeTemplatesWithCommonOrInstanceProperties(
-                common, name, version));
+    public ResponseEntity<Map<String, ToscaNodeTemplate>> queryToscaServiceCommonOrInstanceProperties(
+            @RequestHeader(
+                    name = REQUEST_ID_NAME,
+                    required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+            @ApiParam(value = "Flag, true for common properties, false for instance", required = false) @RequestParam(
+                    value = "common",
+                    defaultValue = "false",
+                    required = false) boolean common,
+            @ApiParam(value = "Tosca service template name", required = false) @RequestParam(
+                    value = "name",
+                    required = false) String name,
+            @ApiParam(value = "Tosca service template version", required = false) @RequestParam(
+                    value = "version",
+                    required = false) String version)
+            throws PfModelException {
 
-        } catch (PfModelRuntimeException | PfModelException e) {
-            LOGGER.warn("Get of common or instance properties failed", e);
-            var resp = new CommissioningResponse();
-            resp.setErrorDetails(e.getErrorResponse().getErrorMessage());
-            return ResponseEntity.status(e.getErrorResponse().getResponseCode().getStatusCode()).body(resp);
-        }
+        return ResponseEntity.ok().body(provider.getNodeTemplatesWithCommonOrInstanceProperties(common, name, version));
     }
 
     /**
@@ -515,6 +449,7 @@ public class CommissioningController extends AbstractRestController {
      * @param name the name of the control loop definition to get
      * @param version the version of the control loop definition to get
      * @return the control loop element definitions
+     * @throws PfModelException on errors getting the elements of a specific control loop
      */
     // @formatter:off
     @GetMapping(value = "/commission/elements",
@@ -554,35 +489,25 @@ public class CommissioningController extends AbstractRestController {
         }
     )
     // @formatter:on
-    public ResponseEntity<?> queryElements(
+    public ResponseEntity<List<ToscaNodeTemplate>> queryElements(
             @RequestHeader(
                     name = REQUEST_ID_NAME,
                     required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
             @ApiParam(value = "Control Loop definition name", required = false) @RequestParam(
                     value = "name",
                     required = false) String name,
-            @ApiParam(value = "Control Loop definition version", required = true) @RequestParam(
+            @ApiParam(value = "Control Loop definition version", required = false) @RequestParam(
                     value = "version",
-                    required = false) String version) {
-
-        try {
-            List<ToscaNodeTemplate> nodeTemplate = provider.getControlLoopDefinitions(name, version);
-            // Prevent ambiguous queries with multiple returns
-            if (nodeTemplate.size() > 1) {
-                var resp = new CommissioningResponse();
-                resp.setErrorDetails("Multiple ControlLoops are not supported");
-                return ResponseEntity.status(HttpStatus.NOT_ACCEPTABLE).body(resp);
-            }
-
-            List<ToscaNodeTemplate> response = provider.getControlLoopElementDefinitions(nodeTemplate.get(0));
-            return ResponseEntity.ok().body(response);
+                    required = false) String version)
+            throws PfModelException {
 
-        } catch (PfModelRuntimeException | PfModelException e) {
-            LOGGER.warn("Get of control loop element definitions failed", e);
-            var resp = new CommissioningResponse();
-            resp.setErrorDetails(e.getErrorResponse().getErrorMessage());
-            return ResponseEntity.status(e.getErrorResponse().getResponseCode().getStatusCode()).body(resp);
+        List<ToscaNodeTemplate> nodeTemplate = provider.getControlLoopDefinitions(name, version);
+        // Prevent ambiguous queries with multiple returns
+        if (nodeTemplate.size() > 1) {
+            throw new PfModelException(Status.NOT_ACCEPTABLE, "Multiple ControlLoops are not supported");
         }
 
+        List<ToscaNodeTemplate> response = provider.getControlLoopElementDefinitions(nodeTemplate.get(0));
+        return ResponseEntity.ok().body(response);
     }
 }
index 5a320e8..29919f5 100644 (file)
@@ -29,6 +29,7 @@ import io.swagger.annotations.Extension;
 import io.swagger.annotations.ExtensionProperty;
 import io.swagger.annotations.ResponseHeader;
 import java.util.UUID;
+import lombok.RequiredArgsConstructor;
 import org.onap.policy.clamp.controlloop.common.exception.ControlLoopException;
 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoops;
 import org.onap.policy.clamp.controlloop.models.messages.rest.instantiation.InstantiationCommand;
@@ -36,10 +37,6 @@ import org.onap.policy.clamp.controlloop.models.messages.rest.instantiation.Inst
 import org.onap.policy.clamp.controlloop.runtime.instantiation.ControlLoopInstantiationProvider;
 import org.onap.policy.clamp.controlloop.runtime.main.web.AbstractRestController;
 import org.onap.policy.models.base.PfModelException;
-import org.onap.policy.models.base.PfModelRuntimeException;
-import org.onap.policy.models.errors.concepts.ErrorResponseInfo;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.DeleteMapping;
@@ -55,30 +52,21 @@ import org.springframework.web.bind.annotation.RestController;
  * Class to provide REST end points for creating, deleting, query and commanding a control loop definition.
  */
 @RestController
+@RequiredArgsConstructor
 public class InstantiationController extends AbstractRestController {
 
-    private static final Logger LOGGER = LoggerFactory.getLogger(InstantiationController.class);
-
     private static final String TAGS = "Clamp Control Loop Instantiation API";
 
     // The CL provider for instantiation requests
     private final ControlLoopInstantiationProvider provider;
 
-    /**
-     * Create Instantiation Controller.
-     *
-     * @param provider the ControlLoopInstantiationProvider
-     */
-    public InstantiationController(ControlLoopInstantiationProvider provider) {
-        this.provider = provider;
-    }
-
     /**
      * Creates a control loop.
      *
      * @param requestId request ID used in ONAP logging
      * @param controlLoops the control loops
      * @return a response
+     * @throws PfModelException on errors creating a control loop
      */
     // @formatter:off
     @PostMapping(value = "/instantiation",
@@ -128,18 +116,13 @@ public class InstantiationController extends AbstractRestController {
         )
     // @formatter:on
     public ResponseEntity<InstantiationResponse> create(
-            @RequestHeader(name = REQUEST_ID_NAME, required = false)
-            @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
-            @ApiParam(value = "Entity Body of Control Loop", required = true)
-            @RequestBody ControlLoops controlLoops) {
-
-        try {
-            return ResponseEntity.ok().body(provider.createControlLoops(controlLoops));
+            @RequestHeader(
+                    name = REQUEST_ID_NAME,
+                    required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+            @ApiParam(value = "Entity Body of Control Loop", required = true) @RequestBody ControlLoops controlLoops)
+            throws PfModelException {
 
-        } catch (PfModelRuntimeException | PfModelException e) {
-            LOGGER.warn("creation of control loop failed", e);
-            return createInstantiationErrorResponse(e);
-        }
+        return ResponseEntity.ok().body(provider.createControlLoops(controlLoops));
     }
 
     /**
@@ -149,6 +132,7 @@ public class InstantiationController extends AbstractRestController {
      * @param name the name of the control loop to get, null for all control loops
      * @param version the version of the control loop to get, null for all control loops
      * @return the control loops
+     * @throws PfModelException on errors getting commissioning of control loop
      */
     // @formatter:off
     @GetMapping(value = "/instantiation",
@@ -187,22 +171,19 @@ public class InstantiationController extends AbstractRestController {
             }
         )
     // @formatter:on
-    public ResponseEntity<?> query(
-            @RequestHeader(name = REQUEST_ID_NAME, required = false)
-            @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
-            @ApiParam(value = "Control Loop definition name", required = false)
-            @RequestParam(value = "name", required = false) String name,
-            @ApiParam(value = "Control Loop definition version", required = false)
-            @RequestParam(value = "version", required = false) String version) {
-
-        try {
-            return ResponseEntity.ok().body(provider.getControlLoops(name, version));
-
-        } catch (PfModelRuntimeException | PfModelException e) {
-            LOGGER.warn("commisssioning of control loop failed", e);
-            return createInstantiationErrorResponse(e);
-        }
+    public ResponseEntity<ControlLoops> query(
+            @RequestHeader(
+                    name = REQUEST_ID_NAME,
+                    required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+            @ApiParam(value = "Control Loop definition name", required = false) @RequestParam(
+                    value = "name",
+                    required = false) String name,
+            @ApiParam(value = "Control Loop definition version", required = false) @RequestParam(
+                    value = "version",
+                    required = false) String version)
+            throws PfModelException {
 
+        return ResponseEntity.ok().body(provider.getControlLoops(name, version));
     }
 
     /**
@@ -211,6 +192,7 @@ public class InstantiationController extends AbstractRestController {
      * @param requestId request ID used in ONAP logging
      * @param controlLoops the control loops
      * @return a response
+     * @throws PfModelException on errors updating of control loops
      */
     // @formatter:off
     @PutMapping(value = "/instantiation",
@@ -260,18 +242,13 @@ public class InstantiationController extends AbstractRestController {
         )
     // @formatter:on
     public ResponseEntity<InstantiationResponse> update(
-            @RequestHeader(name = REQUEST_ID_NAME, required = false)
-            @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
-            @ApiParam(value = "Entity Body of Control Loop", required = true)
-            @RequestBody ControlLoops controlLoops) {
-
-        try {
-            return ResponseEntity.ok().body(provider.updateControlLoops(controlLoops));
+            @RequestHeader(
+                    name = REQUEST_ID_NAME,
+                    required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+            @ApiParam(value = "Entity Body of Control Loop", required = true) @RequestBody ControlLoops controlLoops)
+            throws PfModelException {
 
-        } catch (PfModelRuntimeException | PfModelException e) {
-            LOGGER.warn("update of control loops failed", e);
-            return createInstantiationErrorResponse(e);
-        }
+        return ResponseEntity.ok().body(provider.updateControlLoops(controlLoops));
     }
 
     /**
@@ -281,6 +258,7 @@ public class InstantiationController extends AbstractRestController {
      * @param name the name of the control loop to delete
      * @param version the version of the control loop to delete
      * @return a response
+     * @throws PfModelException on errors deleting of control loop
      */
     // @formatter:off
     @DeleteMapping(value = "/instantiation",
@@ -328,20 +306,16 @@ public class InstantiationController extends AbstractRestController {
     // @formatter:on
 
     public ResponseEntity<InstantiationResponse> delete(
-            @RequestHeader(name = REQUEST_ID_NAME, required = false)
-            @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
-            @ApiParam(value = "Control Loop definition name", required = true)
-            @RequestParam("name") String name,
-            @ApiParam(value = "Control Loop definition version")
-            @RequestParam(value = "version", required = false) String version) {
-
-        try {
-            return ResponseEntity.ok().body(provider.deleteControlLoop(name, version));
+            @RequestHeader(
+                    name = REQUEST_ID_NAME,
+                    required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+            @ApiParam(value = "Control Loop definition name", required = true) @RequestParam("name") String name,
+            @ApiParam(value = "Control Loop definition version") @RequestParam(
+                    value = "version",
+                    required = false) String version)
+            throws PfModelException {
 
-        } catch (PfModelRuntimeException | PfModelException e) {
-            LOGGER.warn("delete of control loop failed", e);
-            return createInstantiationErrorResponse(e);
-        }
+        return ResponseEntity.ok().body(provider.deleteControlLoop(name, version));
     }
 
     /**
@@ -350,6 +324,8 @@ public class InstantiationController extends AbstractRestController {
      * @param requestId request ID used in ONAP logging
      * @param command the command to issue to control loops
      * @return the control loop definitions
+     * @throws PfModelException on errors issuing a command
+     * @throws ControlLoopException on errors issuing a command
      */
     // @formatter:off
     @PutMapping(value = "/instantiation/command",
@@ -390,29 +366,14 @@ public class InstantiationController extends AbstractRestController {
         )
     // @formatter:on
     public ResponseEntity<InstantiationResponse> issueControlLoopCommand(
-            @RequestHeader(name = REQUEST_ID_NAME, required = false)
-            @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
-            @ApiParam(value = "Entity Body of control loop command", required = true)
-            @RequestBody InstantiationCommand command) {
-
-        try {
-            return ResponseEntity.accepted().body(provider.issueControlLoopCommand(command));
-
-        } catch (PfModelRuntimeException | PfModelException | ControlLoopException e) {
-            LOGGER.warn("creation of control loop failed", e);
-            return createInstantiationErrorResponse(e);
-        }
-    }
+            @RequestHeader(
+                    name = REQUEST_ID_NAME,
+                    required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+            @ApiParam(
+                    value = "Entity Body of control loop command",
+                    required = true) @RequestBody InstantiationCommand command)
+            throws ControlLoopException, PfModelException {
 
-    /**
-     * create a Instantiation Response from an exception.
-     *
-     * @param e the error
-     * @return the Instantiation Response
-     */
-    private ResponseEntity<InstantiationResponse> createInstantiationErrorResponse(ErrorResponseInfo e) {
-        var resp = new InstantiationResponse();
-        resp.setErrorDetails(e.getErrorResponse().getErrorMessage());
-        return ResponseEntity.status(e.getErrorResponse().getResponseCode().getStatusCode()).body(resp);
+        return ResponseEntity.accepted().body(provider.issueControlLoopCommand(command));
     }
 }
index 7ac9500..c4ce5bb 100644 (file)
@@ -30,14 +30,12 @@ import io.swagger.annotations.ExtensionProperty;
 import io.swagger.annotations.ResponseHeader;
 import java.time.Instant;
 import java.util.UUID;
+import lombok.RequiredArgsConstructor;
 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ClElementStatisticsList;
 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantStatisticsList;
 import org.onap.policy.clamp.controlloop.runtime.main.web.AbstractRestController;
 import org.onap.policy.clamp.controlloop.runtime.monitoring.MonitoringProvider;
 import org.onap.policy.models.base.PfModelException;
-import org.onap.policy.models.base.PfModelRuntimeException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -49,21 +47,12 @@ import org.springframework.web.bind.annotation.RestController;
  * This class handles REST endpoints for CL Statistics monitoring.
  */
 @RestController
+@RequiredArgsConstructor
 public class MonitoringQueryController extends AbstractRestController {
 
-    private static final Logger LOGGER = LoggerFactory.getLogger(MonitoringQueryController.class);
     private static final String TAGS = "Clamp Control Loop Monitoring API";
     private final MonitoringProvider provider;
 
-    /**
-     * Create Monitoring Controller.
-     *
-     * @param provider the MonitoringProvider
-     */
-    public MonitoringQueryController(MonitoringProvider provider) {
-        this.provider = provider;
-    }
-
     /**
      * Queries details of control loop participants statistics.
      *
@@ -133,24 +122,17 @@ public class MonitoringQueryController extends AbstractRestController {
                     value = "endTime",
                     required = false) final String endTime) {
 
-        try {
-            Instant startTimestamp = null;
-            Instant endTimestamp = null;
+        Instant startTimestamp = null;
+        Instant endTimestamp = null;
 
-            if (startTime != null) {
-                startTimestamp = Instant.parse(startTime);
-            }
-            if (endTime != null) {
-                endTimestamp = Instant.parse(endTime);
-            }
-            return ResponseEntity.ok().body(provider.fetchFilteredParticipantStatistics(name, version, recordCount,
-                    startTimestamp, endTimestamp));
-
-        } catch (PfModelRuntimeException e) {
-            LOGGER.warn("Monitoring of participants statistics failed", e);
-            return ResponseEntity.status(e.getErrorResponse().getResponseCode().getStatusCode()).build();
+        if (startTime != null) {
+            startTimestamp = Instant.parse(startTime);
         }
-
+        if (endTime != null) {
+            endTimestamp = Instant.parse(endTime);
+        }
+        return ResponseEntity.ok().body(
+                provider.fetchFilteredParticipantStatistics(name, version, recordCount, startTimestamp, endTimestamp));
     }
 
     /**
@@ -208,14 +190,7 @@ public class MonitoringQueryController extends AbstractRestController {
                     value = "version",
                     required = false) final String version) {
 
-        try {
-            return ResponseEntity.ok().body(provider.fetchParticipantStatsPerControlLoop(name, version));
-
-        } catch (PfModelRuntimeException e) {
-            LOGGER.warn("Monitoring of Cl participant statistics failed", e);
-            return ResponseEntity.status(e.getErrorResponse().getResponseCode().getStatusCode()).build();
-        }
-
+        return ResponseEntity.ok().body(provider.fetchParticipantStatsPerControlLoop(name, version));
     }
 
     /**
@@ -273,14 +248,7 @@ public class MonitoringQueryController extends AbstractRestController {
                     value = "version",
                     required = false) final String version) {
 
-        try {
-            return ResponseEntity.ok().body(provider.fetchClElementStatsPerControlLoop(name, version));
-
-        } catch (PfModelRuntimeException e) {
-            LOGGER.warn("Monitoring of Cl Element statistics failed", e);
-            return ResponseEntity.status(e.getErrorResponse().getResponseCode().getStatusCode()).build();
-        }
-
+        return ResponseEntity.ok().body(provider.fetchClElementStatsPerControlLoop(name, version));
     }
 
     /**
@@ -294,6 +262,7 @@ public class MonitoringQueryController extends AbstractRestController {
      * @param startTime the time from which to get statistics
      * @param endTime the time to which to get statistics
      * @return the control loop element statistics
+     * @throws PfModelException on errors getting details of all control loop element statistics per control loop
      */
     // @formatter:off
     @GetMapping(value = "/monitoring/clelement",
@@ -353,26 +322,20 @@ public class MonitoringQueryController extends AbstractRestController {
                     required = false) final String startTime,
             @ApiParam(value = "end time", required = false) @RequestParam(
                     value = "endTime",
-                    required = false) final String endTime) {
-
-        try {
-            Instant startTimestamp = null;
-            Instant endTimestamp = null;
+                    required = false) final String endTime)
+            throws PfModelException {
 
-            if (startTime != null) {
-                startTimestamp = Instant.parse(startTime);
-            }
-            if (endTime != null) {
-                endTimestamp = Instant.parse(endTime);
-            }
-            return ResponseEntity.ok().body(provider.fetchFilteredClElementStatistics(name, version, id, startTimestamp,
-                    endTimestamp, recordCount));
+        Instant startTimestamp = null;
+        Instant endTimestamp = null;
 
-        } catch (PfModelRuntimeException | PfModelException e) {
-            LOGGER.warn("Monitoring of Cl Element statistics failed", e);
-            return ResponseEntity.status(e.getErrorResponse().getResponseCode().getStatusCode()).build();
+        if (startTime != null) {
+            startTimestamp = Instant.parse(startTime);
         }
-
+        if (endTime != null) {
+            endTimestamp = Instant.parse(endTime);
+        }
+        return ResponseEntity.ok().body(provider.fetchFilteredClElementStatistics(name, version, id, startTimestamp,
+                endTimestamp, recordCount));
     }
 
 }
diff --git a/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/web/GlobalControllerExceptionHandler.java b/runtime-controlloop/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/web/GlobalControllerExceptionHandler.java
new file mode 100644 (file)
index 0000000..d093c67
--- /dev/null
@@ -0,0 +1,73 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.runtime.main.web;
+
+import org.onap.policy.clamp.controlloop.common.exception.ControlLoopException;
+import org.onap.policy.clamp.controlloop.models.messages.rest.SimpleResponse;
+import org.onap.policy.models.base.PfModelException;
+import org.onap.policy.models.base.PfModelRuntimeException;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+@RestControllerAdvice
+public class GlobalControllerExceptionHandler {
+
+    /**
+     * Handle ControlLoopException.
+     *
+     * @param ex ControlLoopException
+     * @return ResponseEntity
+     */
+    @ExceptionHandler(ControlLoopException.class)
+    public ResponseEntity<SimpleResponse> handleBadRequest(ControlLoopException ex) {
+        var resp = new SimpleResponse();
+        resp.setErrorDetails(ex.getErrorResponse().getErrorMessage());
+        return ResponseEntity.status(ex.getErrorResponse().getResponseCode().getStatusCode()).body(resp);
+    }
+
+    /**
+     * Handle PfModelRuntimeException.
+     *
+     * @param ex PfModelRuntimeException
+     * @return ResponseEntity
+     */
+    @ExceptionHandler(PfModelRuntimeException.class)
+    public ResponseEntity<SimpleResponse> handleBadRequest(PfModelRuntimeException ex) {
+        var resp = new SimpleResponse();
+        resp.setErrorDetails(ex.getErrorResponse().getErrorMessage());
+        return ResponseEntity.status(ex.getErrorResponse().getResponseCode().getStatusCode()).body(resp);
+    }
+
+    /**
+     * Handle PfModelException.
+     *
+     * @param ex PfModelException
+     * @return ResponseEntity
+     */
+    @ExceptionHandler(PfModelException.class)
+    public ResponseEntity<SimpleResponse> handleBadRequest(PfModelException ex) {
+        var resp = new SimpleResponse();
+        resp.setErrorDetails(ex.getErrorResponse().getErrorMessage());
+        return ResponseEntity.status(ex.getErrorResponse().getResponseCode().getStatusCode()).body(resp);
+    }
+
+}