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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * SPDX-License-Identifier: Apache-2.0
19 * ============LICENSE_END=========================================================
22 package org.onap.policy.clamp.acm.runtime.instantiation;
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;
53 * This class is dedicated to the Instantiation of Commissioned automation composition.
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 ";
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 ";
69 * Create automation composition.
71 * @param compositionId The UUID of the automation composition definition
72 * @param automationComposition the automation composition
73 * @return the result of the instantiation operation
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);
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");
88 var validationResult = validateAutomationComposition(automationComposition);
89 if (!validationResult.isValid()) {
90 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, validationResult.getResult());
92 automationComposition = automationCompositionProvider.createAutomationComposition(automationComposition);
94 var response = new InstantiationResponse();
95 response.setInstanceId(automationComposition.getInstanceId());
96 response.setAffectedAutomationComposition(automationComposition.getKey().asIdentifier());
102 * Update automation composition.
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
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);
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());
122 automationComposition = automationCompositionProvider.updateAutomationComposition(automationComposition);
125 if (instanceUpdate.getInstantiationCommand() != null) {
126 issueAutomationCompositionCommand(automationComposition, instanceUpdate.getInstantiationCommand());
129 var response = new InstantiationResponse();
130 response.setInstanceId(instanceId);
131 response.setAffectedAutomationComposition(automationComposition.getKey().asIdentifier());
136 * Validate AutomationComposition.
138 * @param automationComposition AutomationComposition to validate
139 * @return the result of validation
141 private BeanValidationResult validateAutomationComposition(AutomationComposition automationComposition) {
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"));
149 result.addResult(AcmUtils.validateAutomationComposition(automationComposition, serviceTemplate.get()));
155 * Get Automation Composition.
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
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());
168 return automationComposition;
172 * Delete the automation composition with the given name and version.
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
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);
184 if (!AutomationCompositionState.UNINITIALISED.equals(automationComposition.getState())) {
185 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
186 "Automation composition state is still " + automationComposition.getState());
188 var response = new InstantiationResponse();
189 automationComposition =
190 automationCompositionProvider.deleteAutomationComposition(automationComposition.getInstanceId());
191 response.setInstanceId(automationComposition.getInstanceId());
192 response.setAffectedAutomationComposition(automationComposition.getKey().asIdentifier());
197 * Get the requested automation compositions.
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
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));
209 return automationCompositions;
213 * Issue a command to automation compositions, setting their ordered state.
215 * @param automationComposition the AutomationComposition
216 * @param command the command to issue to automation compositions
218 public void issueAutomationCompositionCommand(AutomationComposition automationComposition,
219 InstantiationCommand command) {
221 if (command.getOrderedState() == null) {
222 throw new AutomationCompositionRuntimeException(Status.BAD_REQUEST,
223 "ordered state invalid or not specified on command");
226 var participants = participantProvider.getParticipants();
227 if (participants.isEmpty()) {
228 throw new AutomationCompositionRuntimeException(Status.BAD_REQUEST, "No participants registered");
230 var validationResult = validateIssueAutomationComposition(automationComposition, participants);
231 if (!validationResult.isValid()) {
232 throw new AutomationCompositionRuntimeException(Response.Status.BAD_REQUEST, validationResult.getResult());
235 automationComposition.setCascadedOrderedState(command.getOrderedState());
237 supervisionHandler.triggerAutomationCompositionSupervision(automationComposition);
238 } catch (AutomationCompositionException e) {
239 throw new AutomationCompositionRuntimeException(Response.Status.BAD_REQUEST, e.getMessage());
241 automationCompositionProvider.updateAutomationComposition(automationComposition);
244 private BeanValidationResult validateIssueAutomationComposition(AutomationComposition automationComposition,
245 List<Participant> participants) {
246 var result = new BeanValidationResult("AutomationComposition", automationComposition);
248 var participantMap = participants.stream()
249 .collect(Collectors.toMap(participant -> participant.getKey().asIdentifier(), Function.identity()));
251 for (var element : automationComposition.getElements().values()) {
253 var subResult = new BeanValidationResult(ENTRY + element.getDefinition().getName(), element);
254 var p = participantMap.get(element.getParticipantId());
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"));
265 result.addResult(subResult);