24b7f3adc8776db002f8b216de0b5d3e594fca9b
[policy/clamp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2023-2024 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.acm.participant.intermediary.handler;
22
23 import io.opentelemetry.context.Context;
24 import java.io.Closeable;
25 import java.io.IOException;
26 import java.util.Map;
27 import java.util.UUID;
28 import java.util.concurrent.ConcurrentHashMap;
29 import java.util.concurrent.ExecutorService;
30 import java.util.concurrent.Executors;
31 import java.util.concurrent.Future;
32 import lombok.RequiredArgsConstructor;
33 import org.onap.policy.clamp.acm.participant.intermediary.api.AutomationCompositionElementListener;
34 import org.onap.policy.clamp.acm.participant.intermediary.api.CompositionDto;
35 import org.onap.policy.clamp.acm.participant.intermediary.api.CompositionElementDto;
36 import org.onap.policy.clamp.acm.participant.intermediary.api.InstanceElementDto;
37 import org.onap.policy.clamp.acm.participant.intermediary.api.ParticipantIntermediaryApi;
38 import org.onap.policy.clamp.models.acm.concepts.AcTypeState;
39 import org.onap.policy.clamp.models.acm.concepts.DeployState;
40 import org.onap.policy.clamp.models.acm.concepts.LockState;
41 import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
42 import org.onap.policy.models.base.PfModelException;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45 import org.springframework.stereotype.Component;
46
47 @Component
48 @RequiredArgsConstructor
49 public class ThreadHandler implements Closeable {
50     private static final Logger LOGGER = LoggerFactory.getLogger(ThreadHandler.class);
51
52     private final AutomationCompositionElementListener listener;
53     private final ParticipantIntermediaryApi intermediaryApi;
54     private final CacheProvider cacheProvider;
55
56     private final Map<UUID, Future> executionMap = new ConcurrentHashMap<>();
57
58     private final ExecutorService executor =
59             Context.taskWrapping(Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()));
60
61     /**
62      * Handle a deploy on a automation composition element.
63      *
64      * @param messageId the messageId
65      * @param compositionElement the information of the Automation Composition Definition Element
66      * @param instanceElement the information of the Automation Composition Instance Element
67      */
68     public void deploy(UUID messageId, CompositionElementDto compositionElement, InstanceElementDto instanceElement) {
69         cleanExecution(instanceElement.elementId(), messageId);
70         var result = executor.submit(() -> this.deployProcess(compositionElement, instanceElement));
71         executionMap.put(instanceElement.elementId(), result);
72     }
73
74     private void deployProcess(CompositionElementDto compositionElement, InstanceElementDto instanceElement) {
75         try {
76             listener.deploy(compositionElement, instanceElement);
77         } catch (PfModelException e) {
78             LOGGER.error("Automation composition element deploy failed {} {}", instanceElement.elementId(),
79                 e.getMessage());
80             intermediaryApi.updateAutomationCompositionElementState(instanceElement.instanceId(),
81                 instanceElement.elementId(), DeployState.UNDEPLOYED, null, StateChangeResult.FAILED,
82                 "Automation composition element deploy failed");
83         }
84         executionMap.remove(instanceElement.elementId());
85     }
86
87     /**
88      * Handle an udeploy on a automation composition element.
89      *
90      * @param messageId the messageId
91      * @param compositionElement the information of the Automation Composition Definition Element
92      * @param instanceElement the information of the Automation Composition Instance Element
93      */
94     public void undeploy(UUID messageId, CompositionElementDto compositionElement, InstanceElementDto instanceElement) {
95         cleanExecution(instanceElement.elementId(), messageId);
96         var result = executor.submit(() -> this.undeployProcess(compositionElement, instanceElement));
97         executionMap.put(instanceElement.elementId(), result);
98     }
99
100     private void undeployProcess(CompositionElementDto compositionElement, InstanceElementDto instanceElement) {
101         try {
102             listener.undeploy(compositionElement, instanceElement);
103         } catch (PfModelException e) {
104             LOGGER.error(
105                 "Automation composition element undeploy failed {} {}", instanceElement.elementId(), e.getMessage());
106             intermediaryApi.updateAutomationCompositionElementState(instanceElement.instanceId(),
107                 instanceElement.elementId(), DeployState.DEPLOYED, null,
108                 StateChangeResult.FAILED, "Automation composition element undeploy failed");
109         }
110         executionMap.remove(instanceElement.elementId());
111     }
112
113     /**
114      * Handle a automation composition element lock.
115      *
116      * @param messageId the messageId
117      * @param compositionElement the information of the Automation Composition Definition Element
118      * @param instanceElement the information of the Automation Composition Instance Element
119      */
120     public void lock(UUID messageId, CompositionElementDto compositionElement, InstanceElementDto instanceElement) {
121         cleanExecution(instanceElement.elementId(), messageId);
122         var result = executor.submit(() -> this.lockProcess(compositionElement, instanceElement));
123         executionMap.put(instanceElement.elementId(), result);
124     }
125
126     private void lockProcess(CompositionElementDto compositionElement, InstanceElementDto instanceElement) {
127         try {
128             listener.lock(compositionElement, instanceElement);
129         } catch (PfModelException e) {
130             LOGGER.error("Automation composition element lock failed {} {}",
131                 instanceElement.elementId(), e.getMessage());
132             intermediaryApi.updateAutomationCompositionElementState(instanceElement.instanceId(),
133                 instanceElement.elementId(), null, LockState.UNLOCKED, StateChangeResult.FAILED,
134                 "Automation composition element lock failed");
135         }
136         executionMap.remove(instanceElement.elementId());
137     }
138
139     /**
140      * Handle a automation composition element unlock.
141      *
142      * @param messageId the messageId
143      * @param compositionElement the information of the Automation Composition Definition Element
144      * @param instanceElement the information of the Automation Composition Instance Element
145      */
146     public void unlock(UUID messageId, CompositionElementDto compositionElement, InstanceElementDto instanceElement) {
147         cleanExecution(instanceElement.elementId(), messageId);
148         var result = executor.submit(() -> this.unlockProcess(compositionElement, instanceElement));
149         executionMap.put(instanceElement.elementId(), result);
150     }
151
152     private void unlockProcess(CompositionElementDto compositionElement, InstanceElementDto instanceElement) {
153         try {
154             listener.unlock(compositionElement, instanceElement);
155         } catch (PfModelException e) {
156             LOGGER.error("Automation composition element unlock failed {} {}",
157                 instanceElement.elementId(), e.getMessage());
158             intermediaryApi.updateAutomationCompositionElementState(instanceElement.instanceId(),
159                 instanceElement.elementId(), null, LockState.LOCKED, StateChangeResult.FAILED,
160                 "Automation composition element unlock failed");
161         }
162         executionMap.remove(instanceElement.elementId());
163     }
164
165     /**
166      * Handle a automation composition element delete.
167      *
168      * @param messageId the messageId
169      * @param compositionElement the information of the Automation Composition Definition Element
170      * @param instanceElement the information of the Automation Composition Instance Element
171      */
172     public void delete(UUID messageId, CompositionElementDto compositionElement, InstanceElementDto instanceElement) {
173         cleanExecution(instanceElement.elementId(), messageId);
174         var result = executor.submit(() -> this.deleteProcess(compositionElement, instanceElement));
175         executionMap.put(instanceElement.elementId(), result);
176     }
177
178     private void deleteProcess(CompositionElementDto compositionElement, InstanceElementDto instanceElement) {
179         try {
180             listener.delete(compositionElement, instanceElement);
181         } catch (PfModelException e) {
182             LOGGER.error("Automation composition element delete failed {} {}",
183                 instanceElement.elementId(), e.getMessage());
184             intermediaryApi.updateAutomationCompositionElementState(
185                 instanceElement.instanceId(), instanceElement.elementId(), DeployState.UNDEPLOYED, null,
186                 StateChangeResult.FAILED, "Automation composition element delete failed");
187         }
188         executionMap.remove(instanceElement.elementId());
189     }
190
191     /**
192      * Handle a automation composition element properties update.
193      *
194      * @param messageId the messageId
195      * @param compositionElement the information of the Automation Composition Definition Element
196      * @param instanceElement the information of the Automation Composition Instance Element
197      * @param instanceElementUpdated the information of the Automation Composition Instance Element updated
198      */
199     public void update(UUID messageId, CompositionElementDto compositionElement, InstanceElementDto instanceElement,
200                        InstanceElementDto instanceElementUpdated) {
201         cleanExecution(instanceElement.elementId(), messageId);
202         var result = executor.submit(() ->
203             this.updateProcess(compositionElement, instanceElement, instanceElementUpdated));
204         executionMap.put(instanceElement.elementId(), result);
205     }
206
207     private void updateProcess(CompositionElementDto compositionElement, InstanceElementDto instanceElement,
208                                InstanceElementDto instanceElementUpdated) {
209         try {
210             listener.update(compositionElement, instanceElement, instanceElementUpdated);
211         } catch (PfModelException e) {
212             LOGGER.error("Automation composition element update failed {} {}",
213                 instanceElement.elementId(), e.getMessage());
214             intermediaryApi.updateAutomationCompositionElementState(instanceElement.instanceId(),
215                 instanceElement.elementId(), DeployState.DEPLOYED, null,
216                 StateChangeResult.FAILED, "Automation composition element update failed");
217         }
218         executionMap.remove(instanceElement.elementId());
219     }
220
221     private void cleanExecution(UUID execIdentificationId, UUID messageId) {
222         var process = executionMap.get(execIdentificationId);
223         if (process != null) {
224             if (!process.isDone()) {
225                 process.cancel(true);
226             }
227             executionMap.remove(execIdentificationId);
228         }
229         cacheProvider.getMsgIdentification().put(execIdentificationId, messageId);
230     }
231
232     /**
233      * Handles prime a Composition Definition.
234      *
235      * @param messageId the messageId
236      * @param composition the composition
237      */
238     public void prime(UUID messageId, CompositionDto composition) {
239         cleanExecution(composition.compositionId(), messageId);
240         var result = executor.submit(() -> this.primeProcess(composition));
241         executionMap.put(composition.compositionId(), result);
242     }
243
244     private void primeProcess(CompositionDto composition) {
245         try {
246             listener.prime(composition);
247             executionMap.remove(composition.compositionId());
248         } catch (PfModelException e) {
249             LOGGER.error("Composition Defintion prime failed {} {}", composition.compositionId(), e.getMessage());
250             intermediaryApi.updateCompositionState(composition.compositionId(), AcTypeState.COMMISSIONED,
251                 StateChangeResult.FAILED, "Composition Defintion prime failed");
252         }
253     }
254
255     /**
256      * Handles deprime a Composition Definition.
257      *
258      * @param messageId the messageId
259      * @param composition the composition
260      */
261     public void deprime(UUID messageId, CompositionDto composition) {
262         cleanExecution(composition.compositionId(), messageId);
263         var result = executor.submit(() -> this.deprimeProcess(composition));
264         executionMap.put(composition.compositionId(), result);
265     }
266
267     private void deprimeProcess(CompositionDto composition) {
268         try {
269             listener.deprime(composition);
270             executionMap.remove(composition.compositionId());
271         } catch (PfModelException e) {
272             LOGGER.error("Composition Defintion deprime failed {} {}", composition.compositionId(), e.getMessage());
273             intermediaryApi.updateCompositionState(composition.compositionId(), AcTypeState.PRIMED,
274                 StateChangeResult.FAILED, "Composition Defintion deprime failed");
275         }
276     }
277
278     /**
279      * Closes this stream and releases any system resources associated
280      * with it. If the stream is already closed then invoking this
281      * method has no effect.
282      *
283      * @throws IOException if an I/O error occurs
284      */
285     @Override
286     public void close() throws IOException {
287         executor.shutdown();
288     }
289
290     /**
291      * Handles AutomationComposition Migration.
292      *
293      * @param messageId the messageId
294      * @param compositionElement the information of the Automation Composition Definition Element
295      * @param compositionElementTarget the information of the Automation Composition Definition Element Target
296      * @param instanceElement the information of the Automation Composition Instance Element
297      * @param instanceElementMigrate the information of the Automation Composition Instance Element updated
298      */
299     public void migrate(UUID messageId, CompositionElementDto compositionElement,
300         CompositionElementDto compositionElementTarget, InstanceElementDto instanceElement,
301         InstanceElementDto instanceElementMigrate) {
302         cleanExecution(instanceElement.elementId(), messageId);
303         var result = executor.submit(() ->
304             this.migrateProcess(compositionElement, compositionElementTarget, instanceElement, instanceElementMigrate));
305         executionMap.put(instanceElement.elementId(), result);
306     }
307
308     private void migrateProcess(CompositionElementDto compositionElement,
309         CompositionElementDto compositionElementTarget, InstanceElementDto instanceElement,
310         InstanceElementDto instanceElementMigrate) {
311         try {
312             listener.migrate(compositionElement, compositionElementTarget, instanceElement, instanceElementMigrate, 0);
313         } catch (PfModelException e) {
314             LOGGER.error("Automation composition element migrate failed {} {}",
315                 instanceElement.elementId(), e.getMessage());
316             intermediaryApi.updateAutomationCompositionElementState(
317                 instanceElement.instanceId(), instanceElement.elementId(), DeployState.DEPLOYED,
318                 null, StateChangeResult.FAILED, "Automation composition element migrate failed");
319         }
320         executionMap.remove(instanceElement.elementId());
321     }
322
323     /**
324      * Handles AutomationComposition Migration Precheck.
325      *
326      * @param messageId the messageId
327      * @param compositionElement the information of the Automation Composition Definition Element
328      * @param compositionElementTarget the information of the Automation Composition Definition Element Target
329      * @param instanceElement the information of the Automation Composition Instance Element
330      * @param instanceElementMigrate the information of the Automation Composition Instance Element updated
331      */
332     public void migratePrecheck(UUID messageId, CompositionElementDto compositionElement,
333         CompositionElementDto compositionElementTarget, InstanceElementDto instanceElement,
334         InstanceElementDto instanceElementMigrate) {
335         cleanExecution(instanceElement.elementId(), messageId);
336         var result = executor.submit(() ->
337             this.migratePrecheckProcess(compositionElement, compositionElementTarget, instanceElement,
338                 instanceElementMigrate));
339         executionMap.put(instanceElement.elementId(), result);
340     }
341
342     private void migratePrecheckProcess(CompositionElementDto compositionElement,
343         CompositionElementDto compositionElementTarget, InstanceElementDto instanceElement,
344         InstanceElementDto instanceElementMigrate) {
345         try {
346             listener.migratePrecheck(compositionElement, compositionElementTarget, instanceElement,
347                 instanceElementMigrate);
348         } catch (PfModelException e) {
349             LOGGER.error("Automation composition element migrate precheck failed {} {}",
350                 instanceElement.elementId(), e.getMessage());
351             intermediaryApi.updateAutomationCompositionElementState(
352                 instanceElement.instanceId(), instanceElement.elementId(), DeployState.DEPLOYED,
353                 null, StateChangeResult.FAILED, "Automation composition element migrate precheck failed");
354         }
355         executionMap.remove(instanceElement.elementId());
356     }
357
358     /**
359      * Handles AutomationComposition Prepare Post Deploy.
360      *
361      * @param messageId the messageId
362      * @param compositionElement the information of the Automation Composition Definition Element
363      * @param instanceElement the information of the Automation Composition Instance Element
364      */
365     public void review(UUID messageId, CompositionElementDto compositionElement,
366         InstanceElementDto instanceElement) {
367         cleanExecution(instanceElement.elementId(), messageId);
368         var result = executor.submit(() -> this.reviewProcess(compositionElement, instanceElement));
369         executionMap.put(instanceElement.elementId(), result);
370     }
371
372     private void reviewProcess(CompositionElementDto compositionElement, InstanceElementDto instanceElement) {
373         try {
374             listener.review(compositionElement, instanceElement);
375         } catch (PfModelException e) {
376             LOGGER.error("Automation composition element Review failed {} {}",
377                 instanceElement.elementId(), e.getMessage());
378             intermediaryApi.updateAutomationCompositionElementState(
379                 instanceElement.instanceId(), instanceElement.elementId(), DeployState.DEPLOYED,
380                 null, StateChangeResult.FAILED, "Automation composition element Review failed");
381         }
382         executionMap.remove(instanceElement.elementId());
383     }
384
385     /**
386      * Handles AutomationComposition Prepare Pre Deploy.
387      *
388      * @param messageId the messageId
389      * @param compositionElement the information of the Automation Composition Definition Element
390      * @param instanceElement the information of the Automation Composition Instance Element
391      */
392     public void prepare(UUID messageId, CompositionElementDto compositionElement,
393         InstanceElementDto instanceElement) {
394         cleanExecution(instanceElement.elementId(), messageId);
395         var result = executor.submit(() -> this.prepareProcess(compositionElement, instanceElement));
396         executionMap.put(instanceElement.elementId(), result);
397     }
398
399     private void prepareProcess(CompositionElementDto compositionElement, InstanceElementDto instanceElement) {
400         try {
401             listener.prepare(compositionElement, instanceElement);
402         } catch (PfModelException e) {
403             LOGGER.error("Automation composition element prepare Pre Deploy failed {} {}",
404                 instanceElement.elementId(), e.getMessage());
405             intermediaryApi.updateAutomationCompositionElementState(
406                 instanceElement.instanceId(), instanceElement.elementId(), DeployState.UNDEPLOYED,
407                 null, StateChangeResult.FAILED, "Automation composition element prepare Pre Deploy failed");
408         }
409         executionMap.remove(instanceElement.elementId());
410     }
411 }