c422b22b5483f814726f4542a99ebdd190e78ef9
[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     /**
222      * Clean Execution.
223      *
224      * @param execIdentificationId the identification Id
225      * @param messageId the messageId
226      */
227     public void cleanExecution(UUID execIdentificationId, UUID messageId) {
228         var process = executionMap.get(execIdentificationId);
229         if (process != null) {
230             if (!process.isDone()) {
231                 process.cancel(true);
232             }
233             executionMap.remove(execIdentificationId);
234         }
235         cacheProvider.getMsgIdentification().put(execIdentificationId, messageId);
236     }
237
238     /**
239      * Handles prime a Composition Definition.
240      *
241      * @param messageId the messageId
242      * @param composition the composition
243      */
244     public void prime(UUID messageId, CompositionDto composition) {
245         cleanExecution(composition.compositionId(), messageId);
246         var result = executor.submit(() -> this.primeProcess(composition));
247         executionMap.put(composition.compositionId(), result);
248     }
249
250     private void primeProcess(CompositionDto composition) {
251         try {
252             listener.prime(composition);
253             executionMap.remove(composition.compositionId());
254         } catch (PfModelException e) {
255             LOGGER.error("Composition Defintion prime failed {} {}", composition.compositionId(), e.getMessage());
256             intermediaryApi.updateCompositionState(composition.compositionId(), AcTypeState.COMMISSIONED,
257                 StateChangeResult.FAILED, "Composition Defintion prime failed");
258         }
259     }
260
261     /**
262      * Handles deprime a Composition Definition.
263      *
264      * @param messageId the messageId
265      * @param composition the composition
266      */
267     public void deprime(UUID messageId, CompositionDto composition) {
268         cleanExecution(composition.compositionId(), messageId);
269         var result = executor.submit(() -> this.deprimeProcess(composition));
270         executionMap.put(composition.compositionId(), result);
271     }
272
273     private void deprimeProcess(CompositionDto composition) {
274         try {
275             listener.deprime(composition);
276             executionMap.remove(composition.compositionId());
277         } catch (PfModelException e) {
278             LOGGER.error("Composition Defintion deprime failed {} {}", composition.compositionId(), e.getMessage());
279             intermediaryApi.updateCompositionState(composition.compositionId(), AcTypeState.PRIMED,
280                 StateChangeResult.FAILED, "Composition Defintion deprime failed");
281         }
282     }
283
284     /**
285      * Closes this stream and releases any system resources associated
286      * with it. If the stream is already closed then invoking this
287      * method has no effect.
288      *
289      * @throws IOException if an I/O error occurs
290      */
291     @Override
292     public void close() throws IOException {
293         executor.shutdown();
294     }
295
296     /**
297      * Handles AutomationComposition Migration.
298      *
299      * @param messageId the messageId
300      * @param compositionElement the information of the Automation Composition Definition Element
301      * @param compositionElementTarget the information of the Automation Composition Definition Element Target
302      * @param instanceElement the information of the Automation Composition Instance Element
303      * @param instanceElementMigrate the information of the Automation Composition Instance Element updated
304      * @param stage the stage
305      */
306     public void migrate(UUID messageId, CompositionElementDto compositionElement,
307         CompositionElementDto compositionElementTarget, InstanceElementDto instanceElement,
308         InstanceElementDto instanceElementMigrate, int stage) {
309         cleanExecution(instanceElement.elementId(), messageId);
310         var result = executor.submit(() ->
311             this.migrateProcess(compositionElement, compositionElementTarget,
312                 instanceElement, instanceElementMigrate, stage));
313         executionMap.put(instanceElement.elementId(), result);
314     }
315
316     private void migrateProcess(CompositionElementDto compositionElement,
317         CompositionElementDto compositionElementTarget, InstanceElementDto instanceElement,
318         InstanceElementDto instanceElementMigrate, int stage) {
319         try {
320             listener.migrate(compositionElement, compositionElementTarget,
321                 instanceElement, instanceElementMigrate, stage);
322         } catch (PfModelException e) {
323             LOGGER.error("Automation composition element migrate failed {} {}",
324                 instanceElement.elementId(), e.getMessage());
325             intermediaryApi.updateAutomationCompositionElementState(
326                 instanceElement.instanceId(), instanceElement.elementId(), DeployState.DEPLOYED,
327                 null, StateChangeResult.FAILED, "Automation composition element migrate failed");
328         }
329         executionMap.remove(instanceElement.elementId());
330     }
331
332     /**
333      * Handles AutomationComposition Migration Precheck.
334      *
335      * @param messageId the messageId
336      * @param compositionElement the information of the Automation Composition Definition Element
337      * @param compositionElementTarget the information of the Automation Composition Definition Element Target
338      * @param instanceElement the information of the Automation Composition Instance Element
339      * @param instanceElementMigrate the information of the Automation Composition Instance Element updated
340      */
341     public void migratePrecheck(UUID messageId, CompositionElementDto compositionElement,
342         CompositionElementDto compositionElementTarget, InstanceElementDto instanceElement,
343         InstanceElementDto instanceElementMigrate) {
344         cleanExecution(instanceElement.elementId(), messageId);
345         var result = executor.submit(() ->
346             this.migratePrecheckProcess(compositionElement, compositionElementTarget, instanceElement,
347                 instanceElementMigrate));
348         executionMap.put(instanceElement.elementId(), result);
349     }
350
351     private void migratePrecheckProcess(CompositionElementDto compositionElement,
352         CompositionElementDto compositionElementTarget, InstanceElementDto instanceElement,
353         InstanceElementDto instanceElementMigrate) {
354         try {
355             listener.migratePrecheck(compositionElement, compositionElementTarget, instanceElement,
356                 instanceElementMigrate);
357         } catch (PfModelException e) {
358             LOGGER.error("Automation composition element migrate precheck failed {} {}",
359                 instanceElement.elementId(), e.getMessage());
360             intermediaryApi.updateAutomationCompositionElementState(
361                 instanceElement.instanceId(), instanceElement.elementId(), DeployState.DEPLOYED,
362                 null, StateChangeResult.FAILED, "Automation composition element migrate precheck failed");
363         }
364         executionMap.remove(instanceElement.elementId());
365     }
366
367     /**
368      * Handles AutomationComposition Prepare Post Deploy.
369      *
370      * @param messageId the messageId
371      * @param compositionElement the information of the Automation Composition Definition Element
372      * @param instanceElement the information of the Automation Composition Instance Element
373      */
374     public void review(UUID messageId, CompositionElementDto compositionElement,
375         InstanceElementDto instanceElement) {
376         cleanExecution(instanceElement.elementId(), messageId);
377         var result = executor.submit(() -> this.reviewProcess(compositionElement, instanceElement));
378         executionMap.put(instanceElement.elementId(), result);
379     }
380
381     private void reviewProcess(CompositionElementDto compositionElement, InstanceElementDto instanceElement) {
382         try {
383             listener.review(compositionElement, instanceElement);
384         } catch (PfModelException e) {
385             LOGGER.error("Automation composition element Review failed {} {}",
386                 instanceElement.elementId(), e.getMessage());
387             intermediaryApi.updateAutomationCompositionElementState(
388                 instanceElement.instanceId(), instanceElement.elementId(), DeployState.DEPLOYED,
389                 null, StateChangeResult.FAILED, "Automation composition element Review failed");
390         }
391         executionMap.remove(instanceElement.elementId());
392     }
393
394     /**
395      * Handles AutomationComposition Prepare Pre Deploy.
396      *
397      * @param messageId the messageId
398      * @param compositionElement the information of the Automation Composition Definition Element
399      * @param instanceElement the information of the Automation Composition Instance Element
400      */
401     public void prepare(UUID messageId, CompositionElementDto compositionElement,
402         InstanceElementDto instanceElement) {
403         cleanExecution(instanceElement.elementId(), messageId);
404         var result = executor.submit(() -> this.prepareProcess(compositionElement, instanceElement));
405         executionMap.put(instanceElement.elementId(), result);
406     }
407
408     private void prepareProcess(CompositionElementDto compositionElement, InstanceElementDto instanceElement) {
409         try {
410             listener.prepare(compositionElement, instanceElement);
411         } catch (PfModelException e) {
412             LOGGER.error("Automation composition element prepare Pre Deploy failed {} {}",
413                 instanceElement.elementId(), e.getMessage());
414             intermediaryApi.updateAutomationCompositionElementState(
415                 instanceElement.instanceId(), instanceElement.elementId(), DeployState.UNDEPLOYED,
416                 null, StateChangeResult.FAILED, "Automation composition element prepare Pre Deploy failed");
417         }
418         executionMap.remove(instanceElement.elementId());
419     }
420 }