b723dba7f13617ae1be88dee3beb37eae7cc5eb7
[policy/clamp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * Copyright (C) 2021-2022 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.acm.runtime.instantiation;
23
24 import java.util.List;
25 import java.util.UUID;
26 import java.util.function.Function;
27 import java.util.stream.Collectors;
28 import javax.ws.rs.core.Response;
29 import javax.ws.rs.core.Response.Status;
30 import lombok.AllArgsConstructor;
31 import org.onap.policy.clamp.acm.runtime.supervision.SupervisionHandler;
32 import org.onap.policy.clamp.common.acm.exception.AutomationCompositionException;
33 import org.onap.policy.clamp.common.acm.exception.AutomationCompositionRuntimeException;
34 import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
35 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionState;
36 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositions;
37 import org.onap.policy.clamp.models.acm.concepts.Participant;
38 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.InstantiationCommand;
39 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.InstantiationResponse;
40 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.InstantiationUpdate;
41 import org.onap.policy.clamp.models.acm.persistence.provider.AcDefinitionProvider;
42 import org.onap.policy.clamp.models.acm.persistence.provider.AutomationCompositionProvider;
43 import org.onap.policy.clamp.models.acm.persistence.provider.ParticipantProvider;
44 import org.onap.policy.clamp.models.acm.utils.AcmUtils;
45 import org.onap.policy.common.parameters.BeanValidationResult;
46 import org.onap.policy.common.parameters.ObjectValidationResult;
47 import org.onap.policy.common.parameters.ValidationStatus;
48 import org.onap.policy.models.base.PfModelRuntimeException;
49 import org.springframework.stereotype.Service;
50 import org.springframework.transaction.annotation.Transactional;
51
52 /**
53  * This class is dedicated to the Instantiation of Commissioned automation composition.
54  */
55 @Service
56 @Transactional
57 @AllArgsConstructor
58 public class AutomationCompositionInstantiationProvider {
59     private static final String AUTOMATION_COMPOSITION_NODE_ELEMENT_TYPE = "AutomationCompositionElement";
60     private static final String DO_NOT_MATCH = " do not match with ";
61
62     private final AutomationCompositionProvider automationCompositionProvider;
63     private final SupervisionHandler supervisionHandler;
64     private final ParticipantProvider participantProvider;
65     private final AcDefinitionProvider acDefinitionProvider;
66     private static final String ENTRY = "entry ";
67
68     /**
69      * Create automation composition.
70      *
71      * @param compositionId The UUID of the automation composition definition
72      * @param automationComposition the automation composition
73      * @return the result of the instantiation operation
74      */
75     public InstantiationResponse createAutomationComposition(UUID compositionId,
76             AutomationComposition automationComposition) {
77         if (!compositionId.equals(automationComposition.getCompositionId())) {
78             throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
79                     automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
80         }
81         var checkAutomationCompositionOpt =
82                 automationCompositionProvider.findAutomationComposition(automationComposition.getKey().asIdentifier());
83         if (checkAutomationCompositionOpt.isPresent()) {
84             throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
85                     automationComposition.getKey().asIdentifier() + " already defined");
86         }
87
88         var validationResult = validateAutomationComposition(automationComposition);
89         if (!validationResult.isValid()) {
90             throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, validationResult.getResult());
91         }
92         automationComposition = automationCompositionProvider.createAutomationComposition(automationComposition);
93
94         var response = new InstantiationResponse();
95         response.setInstanceId(automationComposition.getInstanceId());
96         response.setAffectedAutomationComposition(automationComposition.getKey().asIdentifier());
97
98         return response;
99     }
100
101     /**
102      * Update automation composition.
103      *
104      * @param compositionId The UUID of the automation composition definition
105      * @param instanceId The UUID of the automation composition instance
106      * @param instanceUpdate the automation composition
107      * @return the result of the update
108      */
109     public InstantiationResponse updateAutomationComposition(UUID compositionId, UUID instanceId,
110             InstantiationUpdate instanceUpdate) {
111         var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
112         if (!compositionId.equals(automationComposition.getCompositionId())) {
113             throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
114                     automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
115         }
116         if (instanceUpdate.getElements() != null) {
117             automationComposition.setElements(instanceUpdate.getElements());
118             var validationResult = validateAutomationComposition(automationComposition);
119             if (!validationResult.isValid()) {
120                 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, validationResult.getResult());
121             }
122             automationComposition = automationCompositionProvider.updateAutomationComposition(automationComposition);
123         }
124
125         if (instanceUpdate.getInstantiationCommand() != null) {
126             issueAutomationCompositionCommand(automationComposition, instanceUpdate.getInstantiationCommand());
127         }
128
129         var response = new InstantiationResponse();
130         response.setInstanceId(instanceId);
131         response.setAffectedAutomationComposition(automationComposition.getKey().asIdentifier());
132         return response;
133     }
134
135     /**
136      * Validate AutomationComposition.
137      *
138      * @param automationComposition AutomationComposition to validate
139      * @return the result of validation
140      */
141     private BeanValidationResult validateAutomationComposition(AutomationComposition automationComposition) {
142
143         var result = new BeanValidationResult("AutomationComposition", automationComposition);
144         var serviceTemplate = acDefinitionProvider.findAcDefinition(automationComposition.getCompositionId());
145         if (serviceTemplate.isEmpty()) {
146             result.addResult(new ObjectValidationResult("ServiceTemplate", "", ValidationStatus.INVALID,
147                     "Commissioned automation composition definition not found"));
148         } else {
149             result.addResult(AcmUtils.validateAutomationComposition(automationComposition, serviceTemplate.get()));
150         }
151         return result;
152     }
153
154     /**
155      * Get Automation Composition.
156      *
157      * @param compositionId The UUID of the automation composition definition
158      * @param instanceId The UUID of the automation composition instance
159      * @return the Automation Composition
160      */
161     @Transactional(readOnly = true)
162     public AutomationComposition getAutomationComposition(UUID compositionId, UUID instanceId) {
163         var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
164         if (!automationComposition.getCompositionId().equals(compositionId)) {
165             throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
166                     "Composition Id " + compositionId + DO_NOT_MATCH + automationComposition.getCompositionId());
167         }
168         return automationComposition;
169     }
170
171     /**
172      * Delete the automation composition with the given name and version.
173      *
174      * @param compositionId The UUID of the automation composition definition
175      * @param instanceId The UUID of the automation composition instance
176      * @return the result of the deletion
177      */
178     public InstantiationResponse deleteAutomationComposition(UUID compositionId, UUID instanceId) {
179         var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
180         if (!compositionId.equals(automationComposition.getCompositionId())) {
181             throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
182                     automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
183         }
184         if (!AutomationCompositionState.UNINITIALISED.equals(automationComposition.getState())) {
185             throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
186                     "Automation composition state is still " + automationComposition.getState());
187         }
188         var response = new InstantiationResponse();
189         automationComposition =
190                 automationCompositionProvider.deleteAutomationComposition(automationComposition.getInstanceId());
191         response.setInstanceId(automationComposition.getInstanceId());
192         response.setAffectedAutomationComposition(automationComposition.getKey().asIdentifier());
193         return response;
194     }
195
196     /**
197      * Get the requested automation compositions.
198      *
199      * @param name the name of the automation composition to get, null for all automation compositions
200      * @param version the version of the automation composition to get, null for all automation compositions
201      * @return the automation compositions
202      */
203     @Transactional(readOnly = true)
204     public AutomationCompositions getAutomationCompositions(UUID compositionId, String name, String version) {
205         var automationCompositions = new AutomationCompositions();
206         automationCompositions.setAutomationCompositionList(
207                 automationCompositionProvider.getAutomationCompositions(compositionId, name, version));
208
209         return automationCompositions;
210     }
211
212     /**
213      * Issue a command to automation compositions, setting their ordered state.
214      *
215      * @param automationComposition the AutomationComposition
216      * @param command the command to issue to automation compositions
217      */
218     public void issueAutomationCompositionCommand(AutomationComposition automationComposition,
219             InstantiationCommand command) {
220
221         if (command.getOrderedState() == null) {
222             throw new AutomationCompositionRuntimeException(Status.BAD_REQUEST,
223                     "ordered state invalid or not specified on command");
224         }
225
226         var participants = participantProvider.getParticipants();
227         if (participants.isEmpty()) {
228             throw new AutomationCompositionRuntimeException(Status.BAD_REQUEST, "No participants registered");
229         }
230         var validationResult = validateIssueAutomationComposition(automationComposition, participants);
231         if (!validationResult.isValid()) {
232             throw new AutomationCompositionRuntimeException(Response.Status.BAD_REQUEST, validationResult.getResult());
233         }
234
235         automationComposition.setCascadedOrderedState(command.getOrderedState());
236         try {
237             supervisionHandler.triggerAutomationCompositionSupervision(automationComposition);
238         } catch (AutomationCompositionException e) {
239             throw new AutomationCompositionRuntimeException(Response.Status.BAD_REQUEST, e.getMessage());
240         }
241         automationCompositionProvider.updateAutomationComposition(automationComposition);
242     }
243
244     private BeanValidationResult validateIssueAutomationComposition(AutomationComposition automationComposition,
245             List<Participant> participants) {
246         var result = new BeanValidationResult("AutomationComposition", automationComposition);
247
248         var participantMap = participants.stream()
249                 .collect(Collectors.toMap(participant -> participant.getKey().asIdentifier(), Function.identity()));
250
251         for (var element : automationComposition.getElements().values()) {
252
253             var subResult = new BeanValidationResult(ENTRY + element.getDefinition().getName(), element);
254             var p = participantMap.get(element.getParticipantId());
255             if (p == null) {
256                 subResult.addResult(new ObjectValidationResult(AUTOMATION_COMPOSITION_NODE_ELEMENT_TYPE,
257                         element.getDefinition().getName(), ValidationStatus.INVALID,
258                         "Participant with ID " + element.getParticipantId() + " is not registered"));
259             } else if (!p.getParticipantType().equals(element.getParticipantType())) {
260                 subResult.addResult(new ObjectValidationResult(AUTOMATION_COMPOSITION_NODE_ELEMENT_TYPE,
261                         element.getDefinition().getName(), ValidationStatus.INVALID,
262                         "Participant with ID " + element.getParticipantType() + " - " + element.getParticipantId()
263                                 + " is not registered"));
264             }
265             result.addResult(subResult);
266         }
267
268         return result;
269     }
270 }