28558cc0220c345b7ac9b1274dd2ca0018220bb5
[policy/clamp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * Copyright (C) 2021 Nordix Foundation.
4  * Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
5  * ================================================================================
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * SPDX-License-Identifier: Apache-2.0
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.onap.policy.clamp.controlloop.runtime.instantiation;
23
24 import com.google.gson.Gson;
25 import com.google.gson.internal.LinkedTreeMap;
26 import com.google.gson.reflect.TypeToken;
27 import java.lang.reflect.Type;
28 import java.util.ArrayList;
29 import java.util.Collection;
30 import java.util.Collections;
31 import java.util.HashMap;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.UUID;
35 import java.util.function.UnaryOperator;
36 import java.util.stream.Collectors;
37 import java.util.stream.Stream;
38 import javax.ws.rs.core.Response;
39 import javax.ws.rs.core.Response.Status;
40 import lombok.AllArgsConstructor;
41 import org.onap.policy.clamp.controlloop.common.exception.ControlLoopException;
42 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop;
43 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElement;
44 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopOrderedState;
45 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopState;
46 import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoops;
47 import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ControlLoopProvider;
48 import org.onap.policy.clamp.controlloop.models.messages.rest.GenericNameVersion;
49 import org.onap.policy.clamp.controlloop.models.messages.rest.instantiation.ControlLoopOrderStateResponse;
50 import org.onap.policy.clamp.controlloop.models.messages.rest.instantiation.ControlLoopPrimed;
51 import org.onap.policy.clamp.controlloop.models.messages.rest.instantiation.ControlLoopPrimedResponse;
52 import org.onap.policy.clamp.controlloop.models.messages.rest.instantiation.InstancePropertiesResponse;
53 import org.onap.policy.clamp.controlloop.models.messages.rest.instantiation.InstantiationCommand;
54 import org.onap.policy.clamp.controlloop.models.messages.rest.instantiation.InstantiationResponse;
55 import org.onap.policy.clamp.controlloop.runtime.commissioning.CommissioningProvider;
56 import org.onap.policy.clamp.controlloop.runtime.supervision.SupervisionHandler;
57 import org.onap.policy.common.parameters.BeanValidationResult;
58 import org.onap.policy.common.parameters.ObjectValidationResult;
59 import org.onap.policy.common.parameters.ValidationResult;
60 import org.onap.policy.common.parameters.ValidationStatus;
61 import org.onap.policy.models.base.PfModelException;
62 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
63 import org.onap.policy.models.tosca.authorative.concepts.ToscaNameVersion;
64 import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate;
65 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
66 import org.springframework.stereotype.Component;
67
68 /**
69  * This class is dedicated to the Instantiation of Commissioned control loop.
70  */
71 @Component
72 @AllArgsConstructor
73 public class ControlLoopInstantiationProvider {
74     private static final String CONTROL_LOOP_NODE_TYPE = "org.onap.policy.clamp.controlloop.ControlLoop";
75     private static final String CONTROL_LOOP_NODE_ELEMENT_TYPE = "ControlLoopElement";
76     private static final String PARTICIPANT_ID_PROPERTY_KEY = "participant_id";
77     private static final String CL_ELEMENT_NAME = "name";
78     private static final String CL_ELEMENT_VERSION = "version";
79     private static final String INSTANCE_TEXT = "_Instance";
80
81     private static final Gson GSON = new Gson();
82
83     private final ControlLoopProvider controlLoopProvider;
84     private final CommissioningProvider commissioningProvider;
85     private final SupervisionHandler supervisionHandler;
86
87     private static final Object lockit = new Object();
88
89     /**
90      * Creates Instance Properties and Control Loop.
91      *
92      * @param serviceTemplate the service template
93      * @return the result of the instantiation operation
94      * @throws PfModelException on creation errors
95      */
96     public InstancePropertiesResponse createInstanceProperties(ToscaServiceTemplate serviceTemplate)
97         throws PfModelException {
98
99         String instanceName = generateSequentialInstanceName();
100         ControlLoop controlLoop = new ControlLoop();
101         Map<UUID, ControlLoopElement> controlLoopElements = new HashMap<>();
102
103         ToscaServiceTemplate toscaServiceTemplate = commissioningProvider
104             .getToscaServiceTemplate(null, null);
105
106         Map<String, ToscaNodeTemplate> persistedNodeTemplateMap = toscaServiceTemplate
107             .getToscaTopologyTemplate().getNodeTemplates();
108
109         Map<String, ToscaNodeTemplate> nodeTemplates =
110             deepCloneNodeTemplate(serviceTemplate);
111
112         nodeTemplates.forEach((key, template) -> {
113             ToscaNodeTemplate newNodeTemplate = new ToscaNodeTemplate();
114             String name = key + instanceName;
115             String version = template.getVersion();
116             String description = template.getDescription() + instanceName;
117             newNodeTemplate.setName(name);
118             newNodeTemplate.setVersion(version);
119             newNodeTemplate.setDescription(description);
120             newNodeTemplate.setProperties(new HashMap<>(template.getProperties()));
121             newNodeTemplate.setType(template.getType());
122             newNodeTemplate.setTypeVersion(template.getTypeVersion());
123             newNodeTemplate.setMetadata(template.getMetadata());
124
125             crateNewControlLoopInstance(instanceName, controlLoop, controlLoopElements, template, newNodeTemplate);
126
127             persistedNodeTemplateMap.put(name, newNodeTemplate);
128         });
129
130         ControlLoops controlLoops = new ControlLoops();
131
132         serviceTemplate.getToscaTopologyTemplate().getNodeTemplates().putAll(persistedNodeTemplateMap);
133
134         controlLoop.setElements(controlLoopElements);
135         controlLoops.getControlLoopList().add(controlLoop);
136
137         return saveInstancePropertiesAndControlLoop(serviceTemplate, controlLoops);
138     }
139
140     /**
141      * Deletes Instance Properties.
142      *
143      * @param name the name of the control loop to delete
144      * @param version the version of the control loop to delete
145      * @return the result of the deletion
146      * @throws PfModelException on deletion errors
147      */
148     public InstantiationResponse deleteInstanceProperties(String name, String version) throws PfModelException {
149
150         String instanceName = getInstancePropertyName(name, version);
151
152         Map<String, ToscaNodeTemplate> filteredToscaNodeTemplateMap = new HashMap<>();
153
154         ToscaServiceTemplate toscaServiceTemplate = commissioningProvider.getToscaServiceTemplate(name, version);
155
156         toscaServiceTemplate.getToscaTopologyTemplate()
157             .getNodeTemplates().forEach((key, nodeTemplate) -> {
158                 if (!nodeTemplate.getName().contains(instanceName)) {
159                     filteredToscaNodeTemplateMap.put(key, nodeTemplate);
160                 }
161             });
162
163         List<ToscaNodeTemplate> filteredToscaNodeTemplateList =
164             toscaServiceTemplate.getToscaTopologyTemplate().getNodeTemplates().values().stream()
165                 .filter(nodeTemplate -> nodeTemplate.getName().contains(instanceName)).collect(Collectors.toList());
166
167         InstantiationResponse response = this.deleteControlLoop(name, version);
168
169         controlLoopProvider.deleteInstanceProperties(filteredToscaNodeTemplateMap, filteredToscaNodeTemplateList);
170
171         return response;
172     }
173
174     /**
175      * Create control loops.
176      *
177      * @param controlLoops the control loop
178      * @return the result of the instantiation operation
179      * @throws PfModelException on creation errors
180      */
181     public InstantiationResponse createControlLoops(ControlLoops controlLoops) throws PfModelException {
182
183         synchronized (lockit) {
184             for (ControlLoop controlLoop : controlLoops.getControlLoopList()) {
185                 var checkControlLoop = controlLoopProvider
186                     .getControlLoop(controlLoop.getKey().asIdentifier());
187                 if (checkControlLoop != null) {
188                     throw new PfModelException(Response.Status.BAD_REQUEST,
189                             controlLoop.getKey().asIdentifier() + " already defined");
190                 }
191             }
192             BeanValidationResult validationResult = validateControlLoops(controlLoops);
193             if (!validationResult.isValid()) {
194                 throw new PfModelException(Response.Status.BAD_REQUEST, validationResult.getResult());
195             }
196             controlLoopProvider.createControlLoops(controlLoops.getControlLoopList());
197         }
198
199         var response = new InstantiationResponse();
200         response.setAffectedControlLoops(controlLoops.getControlLoopList().stream()
201                 .map(cl -> cl.getKey().asIdentifier()).collect(Collectors.toList()));
202
203         return response;
204     }
205
206     /**
207      * Update control loops.
208      *
209      * @param controlLoops the control loop
210      * @return the result of the instantiation operation
211      * @throws PfModelException on update errors
212      */
213     public InstantiationResponse updateControlLoops(ControlLoops controlLoops) throws PfModelException {
214         synchronized (lockit) {
215             BeanValidationResult validationResult = validateControlLoops(controlLoops);
216             if (!validationResult.isValid()) {
217                 throw new PfModelException(Response.Status.BAD_REQUEST, validationResult.getResult());
218             }
219             controlLoopProvider.updateControlLoops(controlLoops.getControlLoopList());
220         }
221
222         var response = new InstantiationResponse();
223         response.setAffectedControlLoops(controlLoops.getControlLoopList().stream()
224                 .map(cl -> cl.getKey().asIdentifier()).collect(Collectors.toList()));
225
226         return response;
227     }
228
229     /**
230      * Validate ControlLoops.
231      *
232      * @param controlLoops ControlLoops to validate
233      * @return the result of validation
234      * @throws PfModelException if controlLoops is not valid
235      */
236     private BeanValidationResult validateControlLoops(ControlLoops controlLoops) throws PfModelException {
237
238         var result = new BeanValidationResult("ControlLoops", controlLoops);
239
240         for (ControlLoop controlLoop : controlLoops.getControlLoopList()) {
241             var subResult = new BeanValidationResult("entry " + controlLoop.getDefinition().getName(), controlLoop);
242
243             List<ToscaNodeTemplate> toscaNodeTemplates = commissioningProvider.getControlLoopDefinitions(
244                     controlLoop.getDefinition().getName(), controlLoop.getDefinition().getVersion());
245
246             if (toscaNodeTemplates.isEmpty()) {
247                 subResult.addResult(new ObjectValidationResult("ControlLoop", controlLoop.getDefinition().getName(),
248                         ValidationStatus.INVALID, "Commissioned control loop definition not FOUND"));
249             } else if (toscaNodeTemplates.size() > 1) {
250                 subResult.addResult(new ObjectValidationResult("ControlLoop", controlLoop.getDefinition().getName(),
251                         ValidationStatus.INVALID, "Commissioned control loop definition not VALID"));
252             } else {
253
254                 List<ToscaNodeTemplate> clElementDefinitions =
255                         commissioningProvider.getControlLoopElementDefinitions(toscaNodeTemplates.get(0));
256
257                 // @formatter:off
258                 Map<String, ToscaConceptIdentifier> definitions = clElementDefinitions
259                         .stream()
260                         .map(nodeTemplate -> nodeTemplate.getKey().asIdentifier())
261                         .collect(Collectors.toMap(ToscaConceptIdentifier::getName, UnaryOperator.identity()));
262                 // @formatter:on
263
264                 for (ControlLoopElement element : controlLoop.getElements().values()) {
265                     subResult.addResult(validateDefinition(definitions, element.getDefinition()));
266                 }
267             }
268             result.addResult(subResult);
269         }
270         return result;
271     }
272
273     /**
274      * Validate ToscaConceptIdentifier, checking if exist in ToscaConceptIdentifiers map.
275      *
276      * @param definitions map of all ToscaConceptIdentifiers
277      * @param definition ToscaConceptIdentifier to validate
278      * @return the validation result
279      */
280     private ValidationResult validateDefinition(Map<String, ToscaConceptIdentifier> definitions,
281             ToscaConceptIdentifier definition) {
282         var result = new BeanValidationResult("entry " + definition.getName(), definition);
283         ToscaConceptIdentifier identifier = definitions.get(definition.getName());
284         if (identifier == null) {
285             result.setResult(ValidationStatus.INVALID, "Not FOUND");
286         } else if (!identifier.equals(definition)) {
287             result.setResult(ValidationStatus.INVALID, "Version not matching");
288         }
289         return (result.isClean() ? null : result);
290     }
291
292     /**
293      * Delete the control loop with the given name and version.
294      *
295      * @param name the name of the control loop to delete
296      * @param version the version of the control loop to delete
297      * @return the result of the deletion
298      * @throws PfModelException on deletion errors
299      */
300     public InstantiationResponse deleteControlLoop(String name, String version) throws PfModelException {
301         var response = new InstantiationResponse();
302         synchronized (lockit) {
303             List<ControlLoop> controlLoops = controlLoopProvider.getControlLoops(name, version);
304             if (controlLoops.isEmpty()) {
305                 throw new PfModelException(Response.Status.NOT_FOUND, "Control Loop not found");
306             }
307             for (ControlLoop controlLoop : controlLoops) {
308                 if (!ControlLoopState.UNINITIALISED.equals(controlLoop.getState())) {
309                     throw new PfModelException(Response.Status.BAD_REQUEST,
310                             "Control Loop State is still " + controlLoop.getState());
311                 }
312             }
313
314             response.setAffectedControlLoops(Collections
315                     .singletonList(controlLoopProvider.deleteControlLoop(name, version).getKey().asIdentifier()));
316         }
317         return response;
318     }
319
320     /**
321      * Get the requested control loops.
322      *
323      * @param name the name of the control loop to get, null for all control loops
324      * @param version the version of the control loop to get, null for all control loops
325      * @return the control loops
326      * @throws PfModelException on errors getting control loops
327      */
328     public ControlLoops getControlLoops(String name, String version) throws PfModelException {
329         var controlLoops = new ControlLoops();
330         controlLoops.setControlLoopList(controlLoopProvider.getControlLoops(name, version));
331
332         return controlLoops;
333     }
334
335     /**
336      * Issue a command to control loops, setting their ordered state.
337      *
338      * @param command the command to issue to control loops
339      * @return the result of the initiation command
340      * @throws PfModelException on errors setting the ordered state on the control loops
341      * @throws ControlLoopException on ordered state invalid
342      */
343     public InstantiationResponse issueControlLoopCommand(InstantiationCommand command)
344             throws ControlLoopException, PfModelException {
345
346         if (command.getOrderedState() == null) {
347             throw new ControlLoopException(Status.BAD_REQUEST, "ordered state invalid or not specified on command");
348         }
349
350         synchronized (lockit) {
351             List<ControlLoop> controlLoops = new ArrayList<>(command.getControlLoopIdentifierList().size());
352             for (ToscaConceptIdentifier id : command.getControlLoopIdentifierList()) {
353                 var controlLoop = controlLoopProvider.getControlLoop(id);
354                 controlLoop.setCascadedOrderedState(command.getOrderedState());
355                 controlLoops.add(controlLoop);
356             }
357             controlLoopProvider.updateControlLoops(controlLoops);
358         }
359
360         supervisionHandler.triggerControlLoopSupervision(command.getControlLoopIdentifierList());
361         var response = new InstantiationResponse();
362         response.setAffectedControlLoops(command.getControlLoopIdentifierList());
363
364         return response;
365     }
366
367     /**
368      * Gets a list of control loops with it's ordered state.
369      *
370      * @param name the name of the control loop to get, null for all control loops
371      * @param version the version of the control loop to get, null for all control loops
372      * @return a list of Instantiation Command
373      * @throws PfModelException on errors getting control loops
374      */
375     public ControlLoopOrderStateResponse getInstantiationOrderState(String name, String version)
376         throws PfModelException {
377
378         List<ControlLoop> controlLoops = controlLoopProvider.getControlLoops(name, version);
379
380         var response = new ControlLoopOrderStateResponse();
381
382         controlLoops.forEach(controlLoop -> {
383             var genericNameVersion = new GenericNameVersion();
384             genericNameVersion.setName(controlLoop.getName());
385             genericNameVersion.setVersion(controlLoop.getVersion());
386             response.getControlLoopIdentifierList().add(genericNameVersion);
387         });
388
389         return response;
390     }
391
392     /**
393      * Saves Instance Properties and Control Loop.
394      * Gets a list of control loops which are primed or de-primed.
395      *
396      * @param name the name of the control loop to get, null for all control loops
397      * @param version the version of the control loop to get, null for all control loops
398      * @return a list of Instantiation Command
399      * @throws PfModelException on errors getting control loops
400      */
401     public ControlLoopPrimedResponse getControlLoopPriming(String name, String version)
402         throws PfModelException {
403
404         List<ControlLoop> controlLoops = controlLoopProvider.getControlLoops(name, version);
405
406         var response = new ControlLoopPrimedResponse();
407
408         controlLoops.forEach(controlLoop -> {
409             var primed = new ControlLoopPrimed();
410             primed.setName(controlLoop.getName());
411             primed.setVersion(controlLoop.getVersion());
412             primed.setPrimed(controlLoop.getPrimed());
413             response.getPrimedControlLoopsList().add(primed);
414         });
415
416         return response;
417     }
418
419     /**
420      * Creates instance element name.
421      *
422      * @param serviceTemplate the service template
423      * @param controlLoops a list of control loops
424      * @return the result of the instance properties and instantiation operation
425      * @throws PfModelException on creation errors
426      */
427     private InstancePropertiesResponse saveInstancePropertiesAndControlLoop(
428         ToscaServiceTemplate serviceTemplate, ControlLoops controlLoops) throws PfModelException {
429
430         var response = new InstancePropertiesResponse();
431
432         Map<String, ToscaNodeTemplate> toscaSavedNodeTemplate;
433
434         synchronized (lockit) {
435             for (ControlLoop controlLoop : controlLoops.getControlLoopList()) {
436                 var checkControlLoop = controlLoopProvider.getControlLoop(controlLoop.getKey().asIdentifier());
437                 if (checkControlLoop != null) {
438                     throw new PfModelException(Response.Status.BAD_REQUEST,
439                         controlLoop.getKey().asIdentifier() + " already defined");
440                 }
441             }
442
443             toscaSavedNodeTemplate = controlLoopProvider.saveInstanceProperties(serviceTemplate);
444
445             controlLoopProvider.createControlLoops(controlLoops.getControlLoopList());
446
447         }
448
449         List<ToscaConceptIdentifier> affectedControlLoops = controlLoops.getControlLoopList().stream()
450             .map(cl -> cl.getKey().asIdentifier()).collect(Collectors.toList());
451
452         List<ToscaConceptIdentifier> toscaAffectedProperties = toscaSavedNodeTemplate.values().stream()
453             .map(template -> template.getKey().asIdentifier()).collect(Collectors.toList());
454
455         response.setAffectedInstanceProperties(Stream.of(affectedControlLoops, toscaAffectedProperties)
456             .flatMap(Collection::stream).collect(Collectors.toList()));
457
458         return response;
459     }
460
461     /**
462      * Crates a new Control Loop instance.
463      * @param instanceName Control Loop Instance name
464      * @param controlLoop empty Control Loop
465      * @param controlLoopElements new Control Loop Element map
466      * @param template original Cloned Tosca Node Template
467      * @param newNodeTemplate new Tosca Node Template
468      */
469     private void crateNewControlLoopInstance(String instanceName, ControlLoop controlLoop,
470                                              Map<UUID, ControlLoopElement> controlLoopElements,
471                                              ToscaNodeTemplate template,
472                                              ToscaNodeTemplate newNodeTemplate) {
473         if (template.getType().equals(CONTROL_LOOP_NODE_TYPE)) {
474             controlLoop.setDefinition(getControlLoopDefinition(newNodeTemplate));
475         }
476
477         if (template.getType().contains(CONTROL_LOOP_NODE_ELEMENT_TYPE)) {
478             ControlLoopElement controlLoopElement = getControlLoopElement(instanceName, newNodeTemplate);
479             controlLoopElements.put(controlLoopElement.getId(), controlLoopElement);
480         }
481
482         controlLoop.setName("PMSH" + instanceName);
483         controlLoop.setVersion(template.getVersion());
484         controlLoop.setDescription("PMSH control loop " + instanceName);
485         controlLoop.setState(ControlLoopState.UNINITIALISED);
486         controlLoop.setOrderedState(ControlLoopOrderedState.UNINITIALISED);
487     }
488
489
490     /**
491      * Get's the instance property name of the control loop.
492      *
493      * @param name the name of the control loop to get, null for all control loops
494      * @param version the version of the control loop to get, null for all control loops
495      * @return the instance name of the control loop instance properties
496      * @throws PfModelException on errors getting control loops
497      */
498     private String getInstancePropertyName(String name, String version) throws PfModelException {
499         List<String> toscaDefinitionsNames =
500             controlLoopProvider.getControlLoops(name, version).stream().map(ControlLoop::getDefinition)
501                 .map(ToscaNameVersion::getName).collect(Collectors.toList());
502
503         return toscaDefinitionsNames.stream().reduce("", (s1, s2) -> {
504
505             if (s2.contains(INSTANCE_TEXT)) {
506                 String[] instances = s2.split(INSTANCE_TEXT);
507
508                 return INSTANCE_TEXT + instances[1];
509             }
510
511             return s1;
512         });
513     }
514
515     /**
516      * Generates Instance Name in sequential order and return it to append to the Node Template Name.
517      *
518      * @return instanceName
519      */
520     private String generateSequentialInstanceName() {
521         List<ToscaNodeTemplate> nodeTemplates = controlLoopProvider.getNodeTemplates(null, null);
522
523         int instanceNumber =
524             nodeTemplates.stream().map(ToscaNodeTemplate::getName)
525                 .filter(name -> name.contains(INSTANCE_TEXT)).map(n -> {
526                     String[] defNameArr = n.split(INSTANCE_TEXT);
527
528                     return Integer.parseInt(defNameArr[1]);
529                 }).reduce(0, Math::max);
530
531         return INSTANCE_TEXT + (instanceNumber + 1);
532     }
533
534     /**
535      * Retrieves Control Loop Definition.
536      *
537      * @param template tosca node template
538      * @return control loop definition
539      */
540     private ToscaConceptIdentifier getControlLoopDefinition(ToscaNodeTemplate template) {
541         ToscaConceptIdentifier definition = new ToscaConceptIdentifier();
542         definition.setName(template.getName());
543         definition.setVersion(template.getVersion());
544
545         return definition;
546     }
547
548     /**
549      * Retrieves Control Loop Element.
550      *
551      * @param instanceName instance name to be appended to participant name
552      * @param template tosca node template
553      * @return a control loop element
554      */
555     @SuppressWarnings("unchecked")
556     private ControlLoopElement getControlLoopElement(String instanceName, ToscaNodeTemplate template) {
557         ControlLoopElement controlLoopElement = new ControlLoopElement();
558         ToscaConceptIdentifier definition = new ToscaConceptIdentifier();
559         definition.setName(template.getName());
560         definition.setVersion(template.getVersion());
561         controlLoopElement.setDefinition(definition);
562
563         LinkedTreeMap<String, Object> participantId = (LinkedTreeMap<String, Object>) template.getProperties()
564             .get(PARTICIPANT_ID_PROPERTY_KEY);
565
566         ToscaConceptIdentifier participantIdAndType = new ToscaConceptIdentifier();
567         participantIdAndType.setName(participantId.get(CL_ELEMENT_NAME) + instanceName);
568         participantIdAndType.setVersion(String.valueOf(participantId.get(CL_ELEMENT_VERSION)));
569
570         controlLoopElement.setParticipantType(participantIdAndType);
571         controlLoopElement.setParticipantId(participantIdAndType);
572
573         return controlLoopElement;
574     }
575
576     /**
577      * Deep clones ToscaNodeTemplate.
578      *
579      * @param serviceTemplate ToscaServiceTemplate
580      * @return a cloned Hash Map of ToscaNodeTemplate
581      */
582     private Map<String, ToscaNodeTemplate> deepCloneNodeTemplate(ToscaServiceTemplate serviceTemplate) {
583         String jsonString = GSON.toJson(serviceTemplate.getToscaTopologyTemplate().getNodeTemplates());
584
585         Type type = new TypeToken<HashMap<String, ToscaNodeTemplate>>() {}.getType();
586
587         return GSON.fromJson(jsonString, type);
588     }
589
590 }