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.StateChangeResult;
40 import org.onap.policy.clamp.models.acm.concepts.SubState;
41 import org.onap.policy.clamp.models.acm.persistence.concepts.JpaAutomationComposition;
42 import org.onap.policy.clamp.models.acm.persistence.concepts.JpaAutomationCompositionRollback;
43 import org.onap.policy.clamp.models.acm.persistence.repository.AutomationCompositionElementRepository;
44 import org.onap.policy.clamp.models.acm.persistence.repository.AutomationCompositionRepository;
45 import org.onap.policy.clamp.models.acm.persistence.repository.AutomationCompositionRollbackRepository;
46 import org.onap.policy.clamp.models.acm.utils.AcmUtils;
47 import org.onap.policy.common.parameters.BeanValidationResult;
48 import org.onap.policy.common.parameters.ValidationStatus;
49 import org.onap.policy.models.base.PfConceptKey;
50 import org.onap.policy.models.base.PfKey;
51 import org.onap.policy.models.base.PfModelRuntimeException;
52 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55 import org.springframework.data.domain.Example;
56 import org.springframework.data.domain.Page;
57 import org.springframework.data.domain.Pageable;
58 import org.springframework.stereotype.Service;
59 import org.springframework.transaction.annotation.Isolation;
60 import org.springframework.transaction.annotation.Transactional;
63 * This class provides information on automation composition concepts in the database to callers.
68 public class AutomationCompositionProvider {
69 private static final Logger LOGGER = LoggerFactory.getLogger(AutomationCompositionProvider.class);
70 private static final String DO_NOT_MATCH = " do not match with ";
72 private final AutomationCompositionRepository automationCompositionRepository;
73 private final AutomationCompositionElementRepository acElementRepository;
74 private final AutomationCompositionRollbackRepository acRollbackRepository;
77 * Get automation composition.
79 * @param instanceId the ID of the automation composition to get
80 * @return the automation composition found
82 @Transactional(readOnly = true)
83 public AutomationComposition getAutomationComposition(final UUID instanceId) {
84 var result = automationCompositionRepository.findById(instanceId.toString());
85 if (result.isEmpty()) {
86 throw new PfModelRuntimeException(Status.NOT_FOUND, "AutomationComposition not found");
88 return result.get().toAuthorative();
92 * Find automation composition.
94 * @param instanceId the ID of the automation composition to get
95 * @return the automation composition found
97 @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED)
98 public Optional<AutomationComposition> findAutomationComposition(final UUID instanceId) {
99 var result = automationCompositionRepository.findById(instanceId.toString());
100 return result.stream().map(JpaAutomationComposition::toAuthorative).findFirst();
105 * Create automation composition.
107 * @param automationComposition the automation composition to create
108 * @return the created automation composition
110 public AutomationComposition createAutomationComposition(final AutomationComposition automationComposition) {
111 automationComposition.setInstanceId(UUID.randomUUID());
112 AcmUtils.setCascadedState(automationComposition, DeployState.UNDEPLOYED, LockState.NONE);
113 var result = automationCompositionRepository.save(ProviderUtils.getJpaAndValidate(automationComposition,
114 JpaAutomationComposition::new, "automation composition"));
116 // Return the saved automation composition
117 return result.toAuthorative();
121 * Update automation composition.
123 * @param automationComposition the automation composition to update
124 * @return the updated automation composition
126 public AutomationComposition updateAutomationComposition(
127 @NonNull final AutomationComposition automationComposition) {
128 var result = automationCompositionRepository.save(ProviderUtils.getJpaAndValidate(automationComposition,
129 JpaAutomationComposition::new, "automation composition"));
130 automationCompositionRepository.flush();
131 // Return the saved automation composition
132 return result.toAuthorative();
136 * Get all automation compositions by compositionId.
138 * @param compositionId the compositionId of the automation composition definition
139 * @return all automation compositions found
141 @Transactional(readOnly = true)
142 public List<AutomationComposition> getAcInstancesByCompositionId(UUID compositionId) {
144 .asEntityList(automationCompositionRepository.findByCompositionId(compositionId.toString()));
148 * Get all automation compositions in transition.
150 * @return all automation compositions found
152 @Transactional(readOnly = true)
153 public Set<UUID> getAcInstancesInTransition() {
154 var jpaList = automationCompositionRepository.findByDeployStateIn(List.of(DeployState.DEPLOYING,
155 DeployState.UNDEPLOYING, DeployState.DELETING, DeployState.UPDATING, DeployState.MIGRATING,
156 DeployState.MIGRATION_REVERTING));
157 jpaList.addAll(automationCompositionRepository.findByLockStateIn(
158 List.of(LockState.LOCKING, LockState.UNLOCKING)));
159 jpaList.addAll(automationCompositionRepository.findBySubStateIn(
160 List.of(SubState.PREPARING, SubState.MIGRATION_PRECHECKING, SubState.REVIEWING)));
161 return jpaList.stream().map(JpaAutomationComposition::getInstanceId)
162 .map(UUID::fromString).collect(Collectors.toSet());
166 * Get automation compositions.
168 * @param name the name of the automation composition to get, null to get all automation compositions
169 * @param version the version of the automation composition to get, null to get all automation compositions
170 * @param pageable the Pageable
171 * @return the automation compositions found
173 @Transactional(readOnly = true)
174 public List<AutomationComposition> getAutomationCompositions(@NonNull final UUID compositionId, final String name,
175 final String version,
176 @NonNull final Pageable pageable) {
177 return ProviderUtils.asEntityList(automationCompositionRepository
178 .findAll(createExample(compositionId, name, version), pageable).toList());
181 private Example<JpaAutomationComposition> createExample(final UUID compositionId, final String name,
182 final String version) {
183 var example = new JpaAutomationComposition();
184 example.setCompositionId(compositionId != null ? compositionId.toString() : null);
185 example.setName(name);
186 example.setVersion(version);
187 example.setInstanceId(null);
188 example.setElements(null);
189 example.setDeployState(null);
190 example.setLockState(null);
192 return Example.of(example);
196 * Delete a automation composition.
198 * @param instanceId the ID of the automation composition to get
199 * @return the automation composition deleted
201 public AutomationComposition deleteAutomationComposition(@NonNull final UUID instanceId) {
202 var jpaDeleteAutomationComposition = automationCompositionRepository.findById(instanceId.toString());
203 if (jpaDeleteAutomationComposition.isEmpty()) {
204 var errorMessage = "delete of automation composition \"" + instanceId
205 + "\" failed, automation composition does not exist";
206 throw new PfModelRuntimeException(Response.Status.NOT_FOUND, errorMessage);
209 if (acRollbackRepository.existsById(instanceId.toString())) {
210 acRollbackRepository.deleteById(instanceId.toString());
212 automationCompositionRepository.deleteById(instanceId.toString());
214 return jpaDeleteAutomationComposition.get().toAuthorative();
218 * Delete AutomationCompositionElement.
220 * @param elementId the AutomationCompositionElement Id
222 public void deleteAutomationCompositionElement(@NonNull final UUID elementId) {
223 acElementRepository.deleteById(elementId.toString());
227 * Validate ElementIds.
229 * @param automationComposition the AutomationComposition
230 * @return the BeanValidationResult
232 public BeanValidationResult validateElementIds(final AutomationComposition automationComposition) {
233 var result = new BeanValidationResult(
234 "UUID elements " + automationComposition.getName(), automationComposition);
236 var ids = automationComposition
237 .getElements().values().stream().map(AutomationCompositionElement::getId).toList();
238 var elements = acElementRepository.findAllById(ids.stream().map(UUID::toString).toList());
239 if (automationComposition.getInstanceId() == null) {
240 for (var element : elements) {
242 element.getDescription(), element.getElementId(), ValidationStatus.INVALID, "UUID already used");
245 var instanceId = automationComposition.getInstanceId().toString();
246 for (var element : elements) {
247 if (!instanceId.equals(element.getInstanceId())) {
249 element.getDescription(), element.getElementId(), ValidationStatus.INVALID,
250 "UUID already used");
258 * Save a copy of an automation composition to the copy table in case of a rollback.
260 * @param automationComposition the composition to be copied
262 public void copyAcElementsBeforeUpdate(AutomationComposition automationComposition) {
263 var copy = new AutomationCompositionRollback(automationComposition);
264 var jpaCopy = new JpaAutomationCompositionRollback(copy);
265 acRollbackRepository.save(jpaCopy);
266 acRollbackRepository.flush();
270 * Get the copied automation composition from the RollbackRepository.
272 * @param instanceId the id of the ac instance
273 * @return the acRollback object
275 public AutomationCompositionRollback getAutomationCompositionRollback(UUID instanceId) {
276 var result = acRollbackRepository.findById(instanceId.toString());
277 if (result.isEmpty()) {
278 throw new PfModelRuntimeException(Status.NOT_FOUND, "Instance not found for rollback");
280 return result.get().toAuthorative();
284 * validate that compositionId into the Instance Endpoint is correct.
286 * @param compositionId the compositionId
287 * @param automationComposition the AutomationComposition
289 public static void validateInstanceEndpoint(UUID compositionId,
290 AutomationComposition automationComposition) {
292 if (!compositionId.equals(automationComposition.getCompositionId())) {
293 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
294 automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
299 * Validate that name and version of an AutomationComposition is not already used.
301 * @param acIdentifier the name and version of an AutomationComposition
303 @Transactional(readOnly = true)
304 public void validateNameVersion(ToscaConceptIdentifier acIdentifier) {
305 var acOpt = automationCompositionRepository
306 .findOne(createExample(null, acIdentifier.getName(), acIdentifier.getVersion()))
307 .map(JpaAutomationComposition::toAuthorative);
308 if (acOpt.isPresent()) {
309 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, acIdentifier + " already defined");
314 * Check Compatibility of name version between elements.
316 * @param newDefinition the new name version
317 * @param dbElementDefinition the name version from db
318 * @param instanceId the instanceId
320 public static void checkCompatibility(PfConceptKey newDefinition, PfConceptKey dbElementDefinition,
322 var compatibility = newDefinition.getCompatibility(dbElementDefinition);
323 if (PfKey.Compatibility.DIFFERENT.equals(compatibility)) {
324 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
325 dbElementDefinition + " is not compatible with " + newDefinition);
327 if (PfKey.Compatibility.MAJOR.equals(compatibility) || PfKey.Compatibility.MINOR
328 .equals(compatibility)) {
329 LOGGER.warn("Migrate {}: Version {} has {} compatibility with {} ", instanceId, newDefinition,
330 compatibility, dbElementDefinition);
335 * Retrieves a list of AutomationComposition instances filtered by the specified state change results
336 * and deployment states. The result can be paginated and sorted based on the provided parameters.
338 * @param stateChangeResults a list of StateChangeResult values to filter the AutomationComposition instances
339 * @param deployStates a list of DeployState values to filter the AutomationComposition instances
340 * @param pageable the pagination information including page size and page number
341 * @return a list of AutomationComposition instances that match the specified filters
343 public List<AutomationComposition> getAcInstancesByStateResultDeployState(
344 @NonNull final List<StateChangeResult> stateChangeResults,
345 @NonNull final List<DeployState> deployStates,
346 @NonNull final Pageable pageable) {
347 Page<JpaAutomationComposition> page;
348 if (stateChangeResults.isEmpty() && deployStates.isEmpty()) {
349 page = automationCompositionRepository.findAll(pageable);
350 } else if (!stateChangeResults.isEmpty() && deployStates.isEmpty()) {
351 page = automationCompositionRepository.findByStateChangeResultIn(stateChangeResults, pageable);
352 } else if (stateChangeResults.isEmpty()) {
353 page = automationCompositionRepository.findByDeployStateIn(deployStates, pageable);
355 page = automationCompositionRepository.findByStateChangeResultInAndDeployStateIn(
356 stateChangeResults, deployStates, pageable);
359 return ProviderUtils.asEntityList(page.toList());