2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2021-2025 OpenInfra Foundation Europe. All rights reserved.
4 * ================================================================================
5 * Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
19 * SPDX-License-Identifier: Apache-2.0
20 * ============LICENSE_END=========================================================
23 package org.onap.policy.clamp.models.acm.persistence.provider;
25 import jakarta.ws.rs.core.Response;
26 import jakarta.ws.rs.core.Response.Status;
27 import java.util.List;
28 import java.util.Optional;
30 import java.util.UUID;
31 import java.util.stream.Collectors;
32 import lombok.AllArgsConstructor;
33 import lombok.NonNull;
34 import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
35 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElement;
36 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionRollback;
37 import org.onap.policy.clamp.models.acm.concepts.DeployState;
38 import org.onap.policy.clamp.models.acm.concepts.LockState;
39 import org.onap.policy.clamp.models.acm.concepts.SubState;
40 import org.onap.policy.clamp.models.acm.persistence.concepts.JpaAutomationComposition;
41 import org.onap.policy.clamp.models.acm.persistence.concepts.JpaAutomationCompositionRollback;
42 import org.onap.policy.clamp.models.acm.persistence.repository.AutomationCompositionElementRepository;
43 import org.onap.policy.clamp.models.acm.persistence.repository.AutomationCompositionRepository;
44 import org.onap.policy.clamp.models.acm.persistence.repository.AutomationCompositionRollbackRepository;
45 import org.onap.policy.clamp.models.acm.utils.AcmUtils;
46 import org.onap.policy.common.parameters.BeanValidationResult;
47 import org.onap.policy.common.parameters.ValidationStatus;
48 import org.onap.policy.models.base.PfConceptKey;
49 import org.onap.policy.models.base.PfKey;
50 import org.onap.policy.models.base.PfModelRuntimeException;
51 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
54 import org.springframework.data.domain.Example;
55 import org.springframework.data.domain.Pageable;
56 import org.springframework.stereotype.Service;
57 import org.springframework.transaction.annotation.Isolation;
58 import org.springframework.transaction.annotation.Transactional;
61 * This class provides information on automation composition concepts in the database to callers.
66 public class AutomationCompositionProvider {
67 private static final Logger LOGGER = LoggerFactory.getLogger(AutomationCompositionProvider.class);
68 private static final String DO_NOT_MATCH = " do not match with ";
70 private final AutomationCompositionRepository automationCompositionRepository;
71 private final AutomationCompositionElementRepository acElementRepository;
72 private final AutomationCompositionRollbackRepository acRollbackRepository;
75 * Get automation composition.
77 * @param instanceId the ID of the automation composition to get
78 * @return the automation composition found
80 @Transactional(readOnly = true)
81 public AutomationComposition getAutomationComposition(final UUID instanceId) {
82 var result = automationCompositionRepository.findById(instanceId.toString());
83 if (result.isEmpty()) {
84 throw new PfModelRuntimeException(Status.NOT_FOUND, "AutomationComposition not found");
86 return result.get().toAuthorative();
90 * Find automation composition.
92 * @param instanceId the ID of the automation composition to get
93 * @return the automation composition found
95 @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED)
96 public Optional<AutomationComposition> findAutomationComposition(final UUID instanceId) {
97 var result = automationCompositionRepository.findById(instanceId.toString());
98 return result.stream().map(JpaAutomationComposition::toAuthorative).findFirst();
103 * Create automation composition.
105 * @param automationComposition the automation composition to create
106 * @return the created automation composition
108 public AutomationComposition createAutomationComposition(final AutomationComposition automationComposition) {
109 automationComposition.setInstanceId(UUID.randomUUID());
110 AcmUtils.setCascadedState(automationComposition, DeployState.UNDEPLOYED, LockState.NONE);
111 var result = automationCompositionRepository.save(ProviderUtils.getJpaAndValidate(automationComposition,
112 JpaAutomationComposition::new, "automation composition"));
114 // Return the saved automation composition
115 return result.toAuthorative();
119 * Update automation composition.
121 * @param automationComposition the automation composition to update
122 * @return the updated automation composition
124 public AutomationComposition updateAutomationComposition(
125 @NonNull final AutomationComposition automationComposition) {
126 var result = automationCompositionRepository.save(ProviderUtils.getJpaAndValidate(automationComposition,
127 JpaAutomationComposition::new, "automation composition"));
128 automationCompositionRepository.flush();
129 // Return the saved automation composition
130 return result.toAuthorative();
134 * Get all automation compositions by compositionId.
136 * @param compositionId the compositionId of the automation composition definition
137 * @return all automation compositions found
139 @Transactional(readOnly = true)
140 public List<AutomationComposition> getAcInstancesByCompositionId(UUID compositionId) {
142 .asEntityList(automationCompositionRepository.findByCompositionId(compositionId.toString()));
146 * Get all automation compositions in transition.
148 * @return all automation compositions found
150 @Transactional(readOnly = true)
151 public Set<UUID> getAcInstancesInTransition() {
152 var jpaList = automationCompositionRepository.findByDeployStateIn(List.of(DeployState.DEPLOYING,
153 DeployState.UNDEPLOYING, DeployState.DELETING, DeployState.UPDATING, DeployState.MIGRATING,
154 DeployState.MIGRATION_REVERTING));
155 jpaList.addAll(automationCompositionRepository.findByLockStateIn(
156 List.of(LockState.LOCKING, LockState.UNLOCKING)));
157 jpaList.addAll(automationCompositionRepository.findBySubStateIn(
158 List.of(SubState.PREPARING, SubState.MIGRATION_PRECHECKING, SubState.REVIEWING)));
159 return jpaList.stream().map(JpaAutomationComposition::getInstanceId)
160 .map(UUID::fromString).collect(Collectors.toSet());
164 * Get automation compositions.
166 * @param name the name of the automation composition to get, null to get all automation compositions
167 * @param version the version of the automation composition to get, null to get all automation compositions
168 * @param pageable the Pageable
169 * @return the automation compositions found
171 @Transactional(readOnly = true)
172 public List<AutomationComposition> getAutomationCompositions(@NonNull final UUID compositionId, final String name,
173 final String version,
174 @NonNull final Pageable pageable) {
175 return ProviderUtils.asEntityList(automationCompositionRepository
176 .findAll(createExample(compositionId, name, version), pageable).toList());
179 private Example<JpaAutomationComposition> createExample(final UUID compositionId, final String name,
180 final String version) {
181 var example = new JpaAutomationComposition();
182 example.setCompositionId(compositionId != null ? compositionId.toString() : null);
183 example.setName(name);
184 example.setVersion(version);
185 example.setInstanceId(null);
186 example.setElements(null);
187 example.setDeployState(null);
188 example.setLockState(null);
190 return Example.of(example);
194 * Delete a automation composition.
196 * @param instanceId the ID of the automation composition to get
197 * @return the automation composition deleted
199 public AutomationComposition deleteAutomationComposition(@NonNull final UUID instanceId) {
200 var jpaDeleteAutomationComposition = automationCompositionRepository.findById(instanceId.toString());
201 if (jpaDeleteAutomationComposition.isEmpty()) {
202 var errorMessage = "delete of automation composition \"" + instanceId
203 + "\" failed, automation composition does not exist";
204 throw new PfModelRuntimeException(Response.Status.NOT_FOUND, errorMessage);
207 if (acRollbackRepository.existsById(instanceId.toString())) {
208 acRollbackRepository.deleteById(instanceId.toString());
210 automationCompositionRepository.deleteById(instanceId.toString());
212 return jpaDeleteAutomationComposition.get().toAuthorative();
216 * Delete AutomationCompositionElement.
218 * @param elementId the AutomationCompositionElement Id
220 public void deleteAutomationCompositionElement(@NonNull final UUID elementId) {
221 acElementRepository.deleteById(elementId.toString());
225 * Validate ElementIds.
227 * @param automationComposition the AutomationComposition
228 * @return the BeanValidationResult
230 public BeanValidationResult validateElementIds(final AutomationComposition automationComposition) {
231 var result = new BeanValidationResult(
232 "UUID elements " + automationComposition.getName(), automationComposition);
234 var ids = automationComposition
235 .getElements().values().stream().map(AutomationCompositionElement::getId).toList();
236 var elements = acElementRepository.findAllById(ids.stream().map(UUID::toString).toList());
237 if (automationComposition.getInstanceId() == null) {
238 for (var element : elements) {
240 element.getDescription(), element.getElementId(), ValidationStatus.INVALID, "UUID already used");
243 var instanceId = automationComposition.getInstanceId().toString();
244 for (var element : elements) {
245 if (!instanceId.equals(element.getInstanceId())) {
247 element.getDescription(), element.getElementId(), ValidationStatus.INVALID,
248 "UUID already used");
256 * Save a copy of an automation composition to the copy table in case of a rollback.
258 * @param automationComposition the composition to be copied
260 public void copyAcElementsBeforeUpdate(AutomationComposition automationComposition) {
261 var copy = new AutomationCompositionRollback(automationComposition);
262 var jpaCopy = new JpaAutomationCompositionRollback(copy);
263 acRollbackRepository.save(jpaCopy);
264 acRollbackRepository.flush();
268 * Get the copied automation composition from the RollbackRepository.
270 * @param instanceId the id of the ac instance
271 * @return the acRollback object
273 public AutomationCompositionRollback getAutomationCompositionRollback(UUID instanceId) {
274 var result = acRollbackRepository.findById(instanceId.toString());
275 if (result.isEmpty()) {
276 throw new PfModelRuntimeException(Status.NOT_FOUND, "Instance not found for rollback");
278 return result.get().toAuthorative();
282 * validate that compositionId into the Instance Endpoint is correct.
284 * @param compositionId the compositionId
285 * @param automationComposition the AutomationComposition
287 public static void validateInstanceEndpoint(UUID compositionId,
288 AutomationComposition automationComposition) {
290 if (!compositionId.equals(automationComposition.getCompositionId())) {
291 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
292 automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
297 * Validate that name and version of an AutomationComposition is not already used.
299 * @param acIdentifier the name and version of an AutomationComposition
301 @Transactional(readOnly = true)
302 public void validateNameVersion(ToscaConceptIdentifier acIdentifier) {
303 var acOpt = automationCompositionRepository
304 .findOne(createExample(null, acIdentifier.getName(), acIdentifier.getVersion()))
305 .map(JpaAutomationComposition::toAuthorative);
306 if (acOpt.isPresent()) {
307 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, acIdentifier + " already defined");
312 * Check Compatibility of name version between elements.
314 * @param newDefinition the new name version
315 * @param dbElementDefinition the name version from db
316 * @param instanceId the instanceId
318 public static void checkCompatibility(PfConceptKey newDefinition, PfConceptKey dbElementDefinition,
320 var compatibility = newDefinition.getCompatibility(dbElementDefinition);
321 if (PfKey.Compatibility.DIFFERENT.equals(compatibility)) {
322 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
323 dbElementDefinition + " is not compatible with " + newDefinition);
325 if (PfKey.Compatibility.MAJOR.equals(compatibility) || PfKey.Compatibility.MINOR
326 .equals(compatibility)) {
327 LOGGER.warn("Migrate {}: Version {} has {} compatibility with {} ", instanceId, newDefinition,
328 compatibility, dbElementDefinition);