Add validator to check atleast one non null field check
[nonrtric/plt/rappmanager.git] / participants / participant-impl-dme / src / main / java / org / oransc / participant / dme / handler / AutomationCompositionElementHandler.java
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2023 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.oransc.participant.dme.handler;
22
23 import com.fasterxml.jackson.core.JsonProcessingException;
24 import jakarta.validation.Validation;
25 import jakarta.validation.ValidationException;
26 import java.lang.invoke.MethodHandles;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.UUID;
30 import java.util.concurrent.ConcurrentHashMap;
31 import java.util.stream.Collectors;
32 import lombok.AccessLevel;
33 import lombok.Getter;
34 import lombok.RequiredArgsConstructor;
35 import org.apache.http.HttpStatus;
36 import org.onap.policy.clamp.acm.participant.intermediary.api.AutomationCompositionElementListener;
37 import org.onap.policy.clamp.acm.participant.intermediary.api.ParticipantIntermediaryApi;
38 import org.onap.policy.clamp.models.acm.concepts.AcElementDeploy;
39 import org.onap.policy.clamp.models.acm.concepts.AcTypeState;
40 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElementDefinition;
41 import org.onap.policy.clamp.models.acm.concepts.DeployState;
42 import org.onap.policy.clamp.models.acm.concepts.LockState;
43 import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
44 import org.onap.policy.clamp.models.acm.utils.AcmUtils;
45 import org.onap.policy.common.utils.coder.Coder;
46 import org.onap.policy.common.utils.coder.CoderException;
47 import org.onap.policy.common.utils.coder.StandardCoder;
48 import org.onap.policy.models.base.PfModelException;
49 import org.oransc.participant.dme.exception.DmeException;
50 import org.oransc.participant.dme.models.ConfigurationEntity;
51 import org.oransc.participant.dme.models.DataConsumerEntity;
52 import org.oransc.participant.dme.models.DataProducerEntity;
53 import org.oransc.participant.dme.models.InfoTypeEntity;
54 import org.oransc.participant.dme.restclient.AcDmeClient;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
57 import org.springframework.stereotype.Component;
58
59 @Component
60 @RequiredArgsConstructor
61 public class AutomationCompositionElementHandler implements AutomationCompositionElementListener {
62
63     private static final Coder CODER = new StandardCoder();
64
65     private static final Logger LOGGER = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
66
67     private final ParticipantIntermediaryApi intermediaryApi;
68
69     private final AcDmeClient acDmeClient;
70
71     // Map of acElement Id and DME services
72     @Getter(AccessLevel.PACKAGE)
73     private final Map<UUID, ConfigurationEntity> configRequestMap = new ConcurrentHashMap<>();
74
75     @Override
76     public void undeploy(UUID automationCompositionId, UUID automationCompositionElementId) throws DmeException {
77         var configurationEntity = configRequestMap.get(automationCompositionElementId);
78         if (configurationEntity != null && acDmeClient.isDmeHealthy()) {
79             if (configurationEntity.getDataConsumerEntities() != null) {
80                 acDmeClient.deleteDataConsumer(configurationEntity.getDataConsumerEntities().stream()
81                                                        .map(DataConsumerEntity::getDataConsumerId)
82                                                        .collect(Collectors.toSet()));
83             }
84             if (configurationEntity.getDataProducerEntities() != null) {
85                 acDmeClient.deleteDataProducer(configurationEntity.getDataProducerEntities().stream()
86                                                        .map(DataProducerEntity::getDataProducerId)
87                                                        .collect(Collectors.toSet()));
88             }
89             configRequestMap.remove(automationCompositionElementId);
90             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId,
91                     automationCompositionElementId, DeployState.UNDEPLOYED, null, StateChangeResult.NO_ERROR,
92                     "Undeployed");
93         } else {
94             LOGGER.warn("Failed to connect with DME. Service configuration is: {}", configurationEntity);
95             throw new DmeException(HttpStatus.SC_SERVICE_UNAVAILABLE, "Unable to connect with DME");
96         }
97     }
98
99     @Override
100     public void deploy(UUID automationCompositionId, AcElementDeploy element, Map<String, Object> properties)
101             throws DmeException {
102         try {
103             var configurationEntity = CODER.convert(properties, ConfigurationEntity.class);
104             var violations = Validation.buildDefaultValidatorFactory().getValidator().validate(configurationEntity);
105             if (violations.isEmpty()) {
106                 if (acDmeClient.isDmeHealthy()) {
107                     if (configurationEntity.getInfoTypeEntities() != null) {
108                         acDmeClient.createInfoType(configurationEntity.getInfoTypeEntities().stream().collect(
109                                 Collectors.toMap(InfoTypeEntity::getInfoTypeId, InfoTypeEntity::getPayload)));
110                     }
111                     if (configurationEntity.getDataProducerEntities() != null) {
112                         acDmeClient.createDataProducer(configurationEntity.getDataProducerEntities().stream().collect(
113                                 Collectors.toMap(DataProducerEntity::getDataProducerId,
114                                         DataProducerEntity::getPayload)));
115                     }
116                     if (configurationEntity.getDataConsumerEntities() != null) {
117                         acDmeClient.createDataConsumer(configurationEntity.getDataConsumerEntities().stream().collect(
118                                 Collectors.toMap(DataConsumerEntity::getDataConsumerId,
119                                         DataConsumerEntity::getPayload)));
120                     }
121
122                     configRequestMap.put(element.getId(), configurationEntity);
123                     intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, element.getId(),
124                             DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Deployed");
125                 } else {
126                     intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, element.getId(),
127                             DeployState.UNDEPLOYED, null, StateChangeResult.FAILED, "Unable to connect with DME ");
128                     throw new DmeException(HttpStatus.SC_SERVICE_UNAVAILABLE, "Unable to connect with DME");
129                 }
130             } else {
131                 LOGGER.error("Violations found in the config request parameters: {}", violations);
132                 throw new ValidationException("Constraint violations in the config request");
133             }
134         } catch (JsonProcessingException | ValidationException | CoderException | DmeException e) {
135             intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, element.getId(),
136                     DeployState.UNDEPLOYED, null, StateChangeResult.FAILED, e.getMessage());
137             throw new DmeException(HttpStatus.SC_BAD_REQUEST, "Invalid Configuration", e);
138         }
139     }
140
141     @Override
142     public void lock(UUID instanceId, UUID elementId) {
143         intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId, null, LockState.LOCKED,
144                 StateChangeResult.NO_ERROR, "Locked");
145     }
146
147     @Override
148     public void unlock(UUID instanceId, UUID elementId) {
149         intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId, null, LockState.UNLOCKED,
150                 StateChangeResult.NO_ERROR, "Unlocked");
151     }
152
153     @Override
154     public void delete(UUID instanceId, UUID elementId) {
155         intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId, DeployState.DELETED, null,
156                 StateChangeResult.NO_ERROR, "Deleted");
157     }
158
159     @Override
160     public void update(UUID instanceId, AcElementDeploy element, Map<String, Object> properties) {
161         intermediaryApi.updateAutomationCompositionElementState(instanceId, element.getId(), DeployState.DEPLOYED, null,
162                 StateChangeResult.NO_ERROR, "Update not supported");
163     }
164
165     @Override
166     public void prime(UUID compositionId, List<AutomationCompositionElementDefinition> elementDefinitionList) {
167         intermediaryApi.updateCompositionState(compositionId, AcTypeState.PRIMED, StateChangeResult.NO_ERROR, "Primed");
168     }
169
170     @Override
171     public void deprime(UUID compositionId) {
172         intermediaryApi.updateCompositionState(compositionId, AcTypeState.COMMISSIONED, StateChangeResult.NO_ERROR,
173                 "Deprimed");
174     }
175
176     @Override
177     public void handleRestartComposition(UUID compositionId,
178             List<AutomationCompositionElementDefinition> elementDefinitionList, AcTypeState state) {
179         var finalState = AcTypeState.PRIMED.equals(state) || AcTypeState.PRIMING.equals(state) ? AcTypeState.PRIMED
180                                  : AcTypeState.COMMISSIONED;
181         intermediaryApi.updateCompositionState(compositionId, finalState, StateChangeResult.NO_ERROR, "Restarted");
182     }
183
184     @Override
185     public void handleRestartInstance(UUID automationCompositionId, AcElementDeploy element,
186             Map<String, Object> properties, DeployState deployState, LockState lockState) throws PfModelException {
187         if (DeployState.DEPLOYING.equals(deployState)) {
188             deploy(automationCompositionId, element, properties);
189             return;
190         }
191         if (DeployState.UNDEPLOYING.equals(deployState) || DeployState.DEPLOYED.equals(deployState)
192                     || DeployState.UPDATING.equals(deployState)) {
193             try {
194                 var configurationEntity = CODER.convert(properties, ConfigurationEntity.class);
195                 configRequestMap.put(element.getId(), configurationEntity);
196             } catch (ValidationException | CoderException e) {
197                 throw new DmeException(HttpStatus.SC_BAD_REQUEST, "Invalid Configuration", e);
198             }
199         }
200         if (DeployState.UNDEPLOYING.equals(deployState)) {
201             undeploy(automationCompositionId, element.getId());
202             return;
203         }
204         deployState = AcmUtils.deployCompleted(deployState);
205         lockState = AcmUtils.lockCompleted(deployState, lockState);
206         intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, element.getId(), deployState,
207                 lockState, StateChangeResult.NO_ERROR, "Restarted");
208     }
209
210     @Override
211     public void migrate(UUID automationCompositionId, AcElementDeploy element, UUID compositionTargetId,
212             Map<String, Object> properties) {
213         intermediaryApi.updateAutomationCompositionElementState(automationCompositionId, element.getId(),
214                 DeployState.DEPLOYED, null, StateChangeResult.NO_ERROR, "Migrated");
215     }
216 }