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