8fe3c0c88b357f8c46dbc195ff9720e99d433480
[policy/clamp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2021 Nordix Foundation.
4  * ================================================================================
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * SPDX-License-Identifier: Apache-2.0
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.policy.clamp.controlloop.runtime.main.rest;
22
23 import com.fasterxml.jackson.core.JsonProcessingException;
24 import com.fasterxml.jackson.databind.ObjectMapper;
25 import com.fasterxml.jackson.databind.PropertyNamingStrategies;
26 import io.swagger.annotations.ApiOperation;
27 import io.swagger.annotations.ApiParam;
28 import io.swagger.annotations.ApiResponse;
29 import io.swagger.annotations.ApiResponses;
30 import io.swagger.annotations.Authorization;
31 import io.swagger.annotations.Extension;
32 import io.swagger.annotations.ExtensionProperty;
33 import io.swagger.annotations.ResponseHeader;
34 import java.util.List;
35 import java.util.UUID;
36 import javax.ws.rs.core.Response.Status;
37 import org.onap.policy.clamp.controlloop.models.messages.rest.commissioning.CommissioningResponse;
38 import org.onap.policy.clamp.controlloop.runtime.commissioning.CommissioningProvider;
39 import org.onap.policy.clamp.controlloop.runtime.main.web.AbstractRestController;
40 import org.onap.policy.models.base.PfModelException;
41 import org.onap.policy.models.base.PfModelRuntimeException;
42 import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate;
43 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46 import org.springframework.http.HttpStatus;
47 import org.springframework.http.MediaType;
48 import org.springframework.http.ResponseEntity;
49 import org.springframework.web.bind.annotation.DeleteMapping;
50 import org.springframework.web.bind.annotation.GetMapping;
51 import org.springframework.web.bind.annotation.PostMapping;
52 import org.springframework.web.bind.annotation.RequestBody;
53 import org.springframework.web.bind.annotation.RequestHeader;
54 import org.springframework.web.bind.annotation.RequestParam;
55 import org.springframework.web.bind.annotation.RestController;
56
57 /**
58  * Class to provide REST end points for creating, deleting, querying commissioned control loops.
59  */
60 @RestController
61 public class CommissioningController extends AbstractRestController {
62
63     private static final Logger LOGGER = LoggerFactory.getLogger(CommissioningController.class);
64
65     private static final String TAGS = "Clamp Control Loop Commissioning API";
66
67     private final CommissioningProvider provider;
68
69     /**
70      * Create Commissioning Controller.
71      *
72      * @param provider the CommissioningProvider
73      */
74     public CommissioningController(CommissioningProvider provider) {
75         this.provider = provider;
76     }
77
78     /**
79      * Creates a control loop definition.
80      *
81      * @param requestId request ID used in ONAP logging
82      * @param body the body of control loop following TOSCA definition
83      * @return a response
84      */
85     // @formatter:off
86     @PostMapping(value = "/commission",
87             consumes = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML},
88             produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML})
89     @ApiOperation(
90         value = "Commissions control loop definitions",
91         notes = "Commissions control loop definitions, returning the commissioned control loop definition IDs",
92         response = CommissioningResponse.class,
93         tags = {TAGS},
94         authorizations = @Authorization(value = AUTHORIZATION_TYPE),
95         responseHeaders = {
96             @ResponseHeader(
97                 name = VERSION_MINOR_NAME,
98                 description = VERSION_MINOR_DESCRIPTION,
99                 response = String.class),
100             @ResponseHeader(
101                 name = VERSION_PATCH_NAME,
102                 description = VERSION_PATCH_DESCRIPTION,
103                 response = String.class),
104             @ResponseHeader(
105                 name = VERSION_LATEST_NAME,
106                 description = VERSION_LATEST_DESCRIPTION,
107                 response = String.class),
108             @ResponseHeader(
109                 name = REQUEST_ID_NAME,
110                 description = REQUEST_ID_HDR_DESCRIPTION,
111                 response = UUID.class)
112         },
113         extensions = {
114             @Extension
115                 (
116                     name = EXTENSION_NAME,
117                     properties = {
118                         @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
119                         @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
120                     }
121                 )
122         }
123     )
124     @ApiResponses(
125             value = {
126                 @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
127                 @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
128                 @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
129             }
130     )
131     // @formatter:on
132     public ResponseEntity<CommissioningResponse> create(
133             @RequestHeader(
134                     name = REQUEST_ID_NAME,
135                     required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
136             @ApiParam(value = "Entity Body of Control Loop", required = true) @RequestBody ToscaServiceTemplate body) {
137         try {
138             return ResponseEntity.ok().body(provider.createControlLoopDefinitions(body));
139
140         } catch (PfModelRuntimeException | PfModelException e) {
141             LOGGER.warn("Commissioning of the control loops failed", e);
142             var resp = new CommissioningResponse();
143             resp.setErrorDetails(e.getErrorResponse().getErrorMessage());
144             return ResponseEntity.status(e.getErrorResponse().getResponseCode().getStatusCode()).body(resp);
145         }
146
147     }
148
149     /**
150      * Deletes a control loop definition.
151      *
152      * @param requestId request ID used in ONAP logging
153      * @param name the name of the control loop definition to delete
154      * @param version the version of the control loop definition to delete
155      * @return a response
156      */
157     // @formatter:off
158     @DeleteMapping(value = "/commission",
159             produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML})
160     @ApiOperation(value = "Delete a commissioned control loop",
161         notes = "Deletes a Commissioned Control Loop, returning optional error details",
162         response = CommissioningResponse.class,
163         tags = {TAGS},
164         authorizations = @Authorization(value = AUTHORIZATION_TYPE),
165         responseHeaders = {
166             @ResponseHeader(
167                 name = VERSION_MINOR_NAME,
168                 description = VERSION_MINOR_DESCRIPTION,
169                 response = String.class),
170             @ResponseHeader(
171                 name = VERSION_PATCH_NAME,
172                 description = VERSION_PATCH_DESCRIPTION,
173                 response = String.class),
174             @ResponseHeader(
175                 name = VERSION_LATEST_NAME,
176                 description = VERSION_LATEST_DESCRIPTION,
177                 response = String.class),
178             @ResponseHeader(
179                 name = REQUEST_ID_NAME,
180                 description = REQUEST_ID_HDR_DESCRIPTION,
181                 response = UUID.class)},
182         extensions = {
183             @Extension
184                 (
185                     name = EXTENSION_NAME,
186                     properties = {
187                         @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
188                         @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
189                     }
190                 )
191         }
192     )
193     @ApiResponses(
194         value = {
195             @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
196             @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
197             @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
198         }
199     )
200     // @formatter:on
201     public ResponseEntity<CommissioningResponse> delete(
202             @RequestHeader(
203                     name = REQUEST_ID_NAME,
204                     required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
205             @ApiParam(value = "Control Loop definition name", required = true) @RequestParam(
206                     value = "name") String name,
207             @ApiParam(
208                     value = "Control Loop definition version",
209                     required = true) @RequestParam("version") String version) {
210
211         try {
212             return ResponseEntity.ok().body(provider.deleteControlLoopDefinition(name, version));
213
214         } catch (PfModelRuntimeException | PfModelException e) {
215             LOGGER.warn("Decommisssioning of control loop failed", e);
216             var resp = new CommissioningResponse();
217             resp.setErrorDetails(e.getErrorResponse().getErrorMessage());
218             return ResponseEntity.status(e.getErrorResponse().getResponseCode().getStatusCode()).body(resp);
219         }
220
221     }
222
223     /**
224      * Queries details of all or specific control loop definitions.
225      *
226      * @param requestId request ID used in ONAP logging
227      * @param name the name of the control loop definition to get, null for all definitions
228      * @param version the version of the control loop definition to get, null for all definitions
229      * @return the control loop definitions
230      */
231     // @formatter:off
232     @GetMapping(value = "/commission",
233             produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML})
234     @ApiOperation(value = "Query details of the requested commissioned control loop definitions",
235         notes = "Queries details of the requested commissioned control loop definitions, "
236             + "returning all control loop details",
237         response = ToscaNodeTemplate.class,
238         tags = {TAGS},
239         authorizations = @Authorization(value = AUTHORIZATION_TYPE),
240         responseHeaders = {
241             @ResponseHeader(
242                 name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION,
243                 response = String.class),
244             @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION,
245                 response = String.class),
246             @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION,
247                 response = String.class),
248             @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION,
249                 response = UUID.class)},
250         extensions = {
251             @Extension
252                 (
253                     name = EXTENSION_NAME,
254                     properties = {
255                         @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
256                         @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
257                     }
258                 )
259             }
260     )
261     @ApiResponses(
262         value = {
263             @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
264             @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
265             @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
266         }
267     )
268     // @formatter:on
269     public ResponseEntity<?> query(
270             @RequestHeader(
271                     name = REQUEST_ID_NAME,
272                     required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
273             @ApiParam(value = "Control Loop definition name", required = false) @RequestParam(
274                     value = "name",
275                     required = false) String name,
276             @ApiParam(value = "Control Loop definition version", required = false) @RequestParam(
277                     value = "version",
278                     required = false) String version) {
279
280         try {
281             return ResponseEntity.ok().body(provider.getControlLoopDefinitions(name, version));
282
283         } catch (PfModelRuntimeException | PfModelException e) {
284             LOGGER.warn("Get of control loop definitions failed", e);
285             var resp = new CommissioningResponse();
286             resp.setErrorDetails(e.getErrorResponse().getErrorMessage());
287             return ResponseEntity.status(e.getErrorResponse().getResponseCode().getStatusCode()).body(resp);
288         }
289
290     }
291
292     /**
293      * Retrieves the Tosca Service Template.
294      *
295      * @param requestId request ID used in ONAP logging
296      * @param name the name of the tosca service template to retrieve
297      * @param version the version of the tosca service template to get
298      * @return the specified tosca service template
299      */
300     // @formatter:off
301     @GetMapping(value = "/commission/toscaservicetemplate",
302             produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML})
303     @ApiOperation(value = "Query details of the requested tosca service templates",
304         notes = "Queries details of the requested commissioned tosca service template, "
305             + "returning all tosca service template details",
306         response = ToscaServiceTemplate.class,
307         tags = {TAGS},
308         authorizations = @Authorization(value = AUTHORIZATION_TYPE),
309         responseHeaders = {
310             @ResponseHeader(
311                 name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION,
312                 response = String.class),
313             @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION,
314                 response = String.class),
315             @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION,
316                 response = String.class),
317             @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION,
318                 response = UUID.class)},
319         extensions = {
320             @Extension
321                 (
322                     name = EXTENSION_NAME,
323                     properties = {
324                         @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
325                         @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
326                     }
327                 )
328         }
329     )
330     @ApiResponses(
331         value = {
332             @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
333             @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
334             @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
335         }
336     )
337     // @formatter:on
338     public ResponseEntity<?> queryToscaServiceTemplate(
339             @RequestHeader(
340                     name = REQUEST_ID_NAME,
341                     required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
342             @ApiParam(value = "Tosca service template name", required = false) @RequestParam(
343                     value = "name",
344                     required = false) String name,
345             @ApiParam(value = "Tosca service template version", required = true) @RequestParam(
346                     value = "version",
347                     required = false) String version) {
348
349         try {
350             var mapper = new ObjectMapper();
351             mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
352             var response = mapper.writerWithDefaultPrettyPrinter()
353                 .writeValueAsString(provider.getToscaServiceTemplateReduced(name, version));
354
355             return ResponseEntity.ok().body(response);
356
357         } catch (PfModelRuntimeException | PfModelException e) {
358             LOGGER.warn("Get of tosca service template failed", e);
359             var resp = new CommissioningResponse();
360             resp.setErrorDetails(e.getErrorResponse().getErrorMessage());
361             return ResponseEntity.status(e.getErrorResponse().getResponseCode().getStatusCode()).body(resp);
362         } catch (JsonProcessingException e) {
363             LOGGER.warn("Get of tosca service template failed", e);
364             var resp = new CommissioningResponse();
365             resp.setErrorDetails(e.getMessage());
366             return ResponseEntity.status(Status.BAD_REQUEST.getStatusCode()).body(resp);
367         }
368     }
369
370     /**
371      * Retrieves the Json Schema for the specified Tosca Service Template.
372      *
373      * @param requestId request ID used in ONAP logging
374      * @param section section of the tosca service template to get schema for
375      * @return the specified tosca service template or section Json Schema
376      */
377     // @formatter:off
378     @GetMapping(value = "/commission/toscaServiceTemplateSchema",
379         produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML})
380     @ApiOperation(value = "Query details of the requested tosca service template json schema",
381         notes = "Queries details of the requested commissioned tosca service template json schema, "
382             + "returning all tosca service template json schema details",
383         response = ToscaServiceTemplate.class,
384         tags = {TAGS},
385         authorizations = @Authorization(value = AUTHORIZATION_TYPE),
386         responseHeaders = {
387             @ResponseHeader(
388                 name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION,
389                 response = String.class),
390             @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION,
391                 response = String.class),
392             @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION,
393                 response = String.class),
394             @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION,
395                 response = UUID.class)},
396         extensions = {
397             @Extension
398                 (
399                     name = EXTENSION_NAME,
400                     properties = {
401                         @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
402                         @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
403                     }
404                 )
405         }
406     )
407     @ApiResponses(
408         value = {
409             @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
410             @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
411             @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
412         }
413     )
414     // @formatter:on
415     public ResponseEntity<?> queryToscaServiceTemplateJsonSchema(
416         @RequestHeader(
417             name = REQUEST_ID_NAME,
418             required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
419         @ApiParam(value = "Section of Template schema is desired for", required = false) @RequestParam(
420             value = "section",
421             required = false, defaultValue = "all") String section) {
422         try {
423             return ResponseEntity.ok().body(provider.getToscaServiceTemplateSchema(section));
424
425         } catch (PfModelRuntimeException | PfModelException e) {
426             LOGGER.warn("Get of tosca service template json schema failed", e);
427             var resp = new CommissioningResponse();
428             resp.setErrorDetails(e.getErrorResponse().getErrorMessage());
429             return ResponseEntity.status(e.getErrorResponse().getResponseCode().getStatusCode()).body(resp);
430         } catch (JsonProcessingException e) {
431             LOGGER.warn("Get of tosca service template json schema failed", e);
432             var resp = new CommissioningResponse();
433             resp.setErrorDetails(e.getMessage());
434             return ResponseEntity.status(Status.BAD_REQUEST.getStatusCode()).body(resp);
435         }
436     }
437
438     /**
439      * Retrieves the Common or Instance Properties for the specified Tosca Service Template.
440      *
441      * @param requestId request ID used in ONAP logging
442      * @param common a flag, true to get common properties, false to get instance properties
443      * @param name the name of the tosca service template to retrieve
444      * @param version the version of the tosca service template to get
445      * @return the specified tosca service template or section Json Schema
446      */
447     // @formatter:off
448     @GetMapping(value = "/commission/getCommonOrInstanceProperties",
449         produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML})
450     @ApiOperation(value = "Query details of the requested tosca service template common or instance properties",
451         notes = "Queries details of the requested commissioned tosca service template json common"
452             + "or instance properties, returning all tosca service template common or instance property details",
453         response = ToscaServiceTemplate.class,
454         tags = {"Clamp Control Loop Commissioning API"},
455         authorizations = @Authorization(value = AUTHORIZATION_TYPE),
456         responseHeaders = {
457             @ResponseHeader(
458                 name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION,
459                 response = String.class),
460             @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION,
461                 response = String.class),
462             @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION,
463                 response = String.class),
464             @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION,
465                 response = UUID.class)},
466         extensions = {
467             @Extension
468                 (
469                     name = EXTENSION_NAME,
470                     properties = {
471                         @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
472                         @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
473                     }
474                 )
475         }
476     )
477     @ApiResponses(
478         value = {
479             @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
480             @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
481             @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
482         }
483     )
484     // @formatter:on
485     public ResponseEntity<?> queryToscaServiceCommonOrInstanceProperties(
486         @RequestHeader(
487             name = REQUEST_ID_NAME,
488             required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
489         @ApiParam(value = "Flag, true for common properties, false for instance", required = false) @RequestParam(
490             value = "common",
491             defaultValue = "false",
492             required = false) boolean common,
493         @ApiParam(value = "Tosca service template name", required = false) @RequestParam(
494             value = "name",
495             required = false) String name,
496         @ApiParam(value = "Tosca service template version", required = true) @RequestParam(
497             value = "version",
498             required = false) String version) {
499         try {
500             return ResponseEntity.ok().body(provider.getNodeTemplatesWithCommonOrInstanceProperties(
501                 common, name, version));
502
503         } catch (PfModelRuntimeException | PfModelException e) {
504             LOGGER.warn("Get of common or instance properties failed", e);
505             var resp = new CommissioningResponse();
506             resp.setErrorDetails(e.getErrorResponse().getErrorMessage());
507             return ResponseEntity.status(e.getErrorResponse().getResponseCode().getStatusCode()).body(resp);
508         }
509     }
510
511     /**
512      * Queries the elements of a specific control loop.
513      *
514      * @param requestId request ID used in ONAP logging
515      * @param name the name of the control loop definition to get
516      * @param version the version of the control loop definition to get
517      * @return the control loop element definitions
518      */
519     // @formatter:off
520     @GetMapping(value = "/commission/elements",
521             produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML})
522     @ApiOperation(value = "Query details of the requested commissioned control loop element definitions",
523         notes = "Queries details of the requested commissioned control loop element definitions, "
524             + "returning all control loop elements' details",
525         response = ToscaNodeTemplate.class,
526         tags = {TAGS},
527         authorizations = @Authorization(value = AUTHORIZATION_TYPE),
528         responseHeaders = {
529             @ResponseHeader(
530                 name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION,
531                 response = String.class),
532             @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION,
533                 response = String.class),
534             @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION,
535                 response = String.class),
536             @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION,
537                 response = UUID.class)},
538         extensions = {
539             @Extension
540                 (
541                     name = EXTENSION_NAME,
542                     properties = {
543                         @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
544                         @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
545                     }
546                 )
547         }
548     )
549     @ApiResponses(
550         value = {
551             @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
552             @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
553             @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
554         }
555     )
556     // @formatter:on
557     public ResponseEntity<?> queryElements(
558             @RequestHeader(
559                     name = REQUEST_ID_NAME,
560                     required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
561             @ApiParam(value = "Control Loop definition name", required = false) @RequestParam(
562                     value = "name",
563                     required = false) String name,
564             @ApiParam(value = "Control Loop definition version", required = true) @RequestParam(
565                     value = "version",
566                     required = false) String version) {
567
568         try {
569             List<ToscaNodeTemplate> nodeTemplate = provider.getControlLoopDefinitions(name, version);
570             // Prevent ambiguous queries with multiple returns
571             if (nodeTemplate.size() > 1) {
572                 var resp = new CommissioningResponse();
573                 resp.setErrorDetails("Multiple ControlLoops are not supported");
574                 return ResponseEntity.status(HttpStatus.NOT_ACCEPTABLE).body(resp);
575             }
576
577             List<ToscaNodeTemplate> response = provider.getControlLoopElementDefinitions(nodeTemplate.get(0));
578             return ResponseEntity.ok().body(response);
579
580         } catch (PfModelRuntimeException | PfModelException e) {
581             LOGGER.warn("Get of control loop element definitions failed", e);
582             var resp = new CommissioningResponse();
583             resp.setErrorDetails(e.getErrorResponse().getErrorMessage());
584             return ResponseEntity.status(e.getErrorResponse().getResponseCode().getStatusCode()).body(resp);
585         }
586
587     }
588 }