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.PfModelRuntimeException;
 
  49 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
 
  50 import org.springframework.data.domain.Example;
 
  51 import org.springframework.data.domain.Pageable;
 
  52 import org.springframework.stereotype.Service;
 
  53 import org.springframework.transaction.annotation.Isolation;
 
  54 import org.springframework.transaction.annotation.Transactional;
 
  57  * This class provides information on automation composition concepts in the database to callers.
 
  62 public class AutomationCompositionProvider {
 
  64     private final AutomationCompositionRepository automationCompositionRepository;
 
  65     private final AutomationCompositionElementRepository acElementRepository;
 
  66     private final AutomationCompositionRollbackRepository acRollbackRepository;
 
  69      * Get automation composition.
 
  71      * @param instanceId the ID of the automation composition to get
 
  72      * @return the automation composition found
 
  74     @Transactional(readOnly = true)
 
  75     public AutomationComposition getAutomationComposition(final UUID instanceId) {
 
  76         var result = automationCompositionRepository.findById(instanceId.toString());
 
  77         if (result.isEmpty()) {
 
  78             throw new PfModelRuntimeException(Status.NOT_FOUND, "AutomationComposition not found");
 
  80         return result.get().toAuthorative();
 
  84      * Find automation composition.
 
  86      * @param instanceId the ID of the automation composition to get
 
  87      * @return the automation composition found
 
  89     @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED)
 
  90     public Optional<AutomationComposition> findAutomationComposition(final UUID instanceId) {
 
  91         var result = automationCompositionRepository.findById(instanceId.toString());
 
  92         return result.stream().map(JpaAutomationComposition::toAuthorative).findFirst();
 
  96      * Find automation composition by automationCompositionId.
 
  98      * @param automationCompositionId the ID of the automation composition to get
 
  99      * @return the automation composition found
 
 101     @Transactional(readOnly = true)
 
 102     public Optional<AutomationComposition> findAutomationComposition(
 
 103         final ToscaConceptIdentifier automationCompositionId) {
 
 104         return automationCompositionRepository
 
 105             .findOne(createExample(null, automationCompositionId.getName(), automationCompositionId.getVersion()))
 
 106             .map(JpaAutomationComposition::toAuthorative);
 
 110      * Create automation composition.
 
 112      * @param automationComposition the automation composition to create
 
 113      * @return the created automation composition
 
 115     public AutomationComposition createAutomationComposition(final AutomationComposition automationComposition) {
 
 116         automationComposition.setInstanceId(UUID.randomUUID());
 
 117         AcmUtils.setCascadedState(automationComposition, DeployState.UNDEPLOYED, LockState.NONE);
 
 118         var result = automationCompositionRepository.save(ProviderUtils.getJpaAndValidate(automationComposition,
 
 119             JpaAutomationComposition::new, "automation composition"));
 
 121         // Return the saved automation composition
 
 122         return result.toAuthorative();
 
 126      * Update automation composition.
 
 128      * @param automationComposition the automation composition to update
 
 129      * @return the updated automation composition
 
 131     public AutomationComposition updateAutomationComposition(
 
 132         @NonNull final AutomationComposition automationComposition) {
 
 133         var result = automationCompositionRepository.save(ProviderUtils.getJpaAndValidate(automationComposition,
 
 134             JpaAutomationComposition::new, "automation composition"));
 
 135         automationCompositionRepository.flush();
 
 136         // Return the saved automation composition
 
 137         return result.toAuthorative();
 
 141      * Get all automation compositions by compositionId.
 
 143      * @param compositionId the compositionId of the automation composition definition
 
 144      * @return all automation compositions found
 
 146     @Transactional(readOnly = true)
 
 147     public List<AutomationComposition> getAcInstancesByCompositionId(UUID compositionId) {
 
 149             .asEntityList(automationCompositionRepository.findByCompositionId(compositionId.toString()));
 
 153      * Get all automation compositions in transition.
 
 155      * @return all automation compositions found
 
 157     @Transactional(readOnly = true)
 
 158     public Set<UUID> getAcInstancesInTransition() {
 
 159         var jpaList = automationCompositionRepository.findByDeployStateIn(List.of(DeployState.DEPLOYING,
 
 160             DeployState.UNDEPLOYING, DeployState.DELETING, DeployState.UPDATING, DeployState.MIGRATING));
 
 161         jpaList.addAll(automationCompositionRepository.findByLockStateIn(
 
 162             List.of(LockState.LOCKING, LockState.UNLOCKING)));
 
 163         jpaList.addAll(automationCompositionRepository.findBySubStateIn(
 
 164             List.of(SubState.PREPARING, SubState.MIGRATION_PRECHECKING, SubState.REVIEWING)));
 
 165         return jpaList.stream().map(JpaAutomationComposition::getInstanceId)
 
 166             .map(UUID::fromString).collect(Collectors.toSet());
 
 170      * Get automation compositions.
 
 172      * @param name     the name of the automation composition to get, null to get all automation compositions
 
 173      * @param version  the version of the automation composition to get, null to get all automation compositions
 
 174      * @param pageable the Pageable
 
 175      * @return the automation compositions found
 
 177     @Transactional(readOnly = true)
 
 178     public List<AutomationComposition> getAutomationCompositions(@NonNull final UUID compositionId, final String name,
 
 179                                                                  final String version,
 
 180                                                                  @NonNull final Pageable pageable) {
 
 181         return ProviderUtils.asEntityList(automationCompositionRepository
 
 182             .findAll(createExample(compositionId, name, version), pageable).toList());
 
 185     private Example<JpaAutomationComposition> createExample(final UUID compositionId, final String name,
 
 186                                                             final String version) {
 
 187         var example = new JpaAutomationComposition();
 
 188         example.setCompositionId(compositionId != null ? compositionId.toString() : null);
 
 189         example.setName(name);
 
 190         example.setVersion(version);
 
 191         example.setInstanceId(null);
 
 192         example.setElements(null);
 
 193         example.setDeployState(null);
 
 194         example.setLockState(null);
 
 196         return Example.of(example);
 
 200      * Delete a automation composition.
 
 202      * @param instanceId the ID of the automation composition to get
 
 203      * @return the automation composition deleted
 
 205     public AutomationComposition deleteAutomationComposition(@NonNull final UUID instanceId) {
 
 206         var jpaDeleteAutomationComposition = automationCompositionRepository.findById(instanceId.toString());
 
 207         if (jpaDeleteAutomationComposition.isEmpty()) {
 
 208             var errorMessage = "delete of automation composition \"" + instanceId
 
 209                 + "\" failed, automation composition does not exist";
 
 210             throw new PfModelRuntimeException(Response.Status.NOT_FOUND, errorMessage);
 
 213         automationCompositionRepository.deleteById(instanceId.toString());
 
 215         return jpaDeleteAutomationComposition.get().toAuthorative();
 
 219      * Delete AutomationCompositionElement.
 
 221      * @param elementId the AutomationCompositionElement Id
 
 223     public void deleteAutomationCompositionElement(@NonNull final UUID elementId) {
 
 224         acElementRepository.deleteById(elementId.toString());
 
 228      * Validate ElementIds.
 
 230      * @param automationComposition the AutomationComposition
 
 231      * @return the BeanValidationResult
 
 233     public BeanValidationResult validateElementIds(final AutomationComposition automationComposition) {
 
 234         var result = new BeanValidationResult(
 
 235             "UUID elements " + automationComposition.getName(), automationComposition);
 
 237         var ids = automationComposition
 
 238             .getElements().values().stream().map(AutomationCompositionElement::getId).toList();
 
 239         var elements = acElementRepository.findAllById(ids.stream().map(UUID::toString).toList());
 
 240         if (automationComposition.getInstanceId() == null) {
 
 241             for (var element : elements) {
 
 243                     element.getDescription(), element.getElementId(), ValidationStatus.INVALID, "UUID already used");
 
 246             var instanceId = automationComposition.getInstanceId().toString();
 
 247             for (var element : elements) {
 
 248                 if (!instanceId.equals(element.getInstanceId())) {
 
 250                         element.getDescription(), element.getElementId(), ValidationStatus.INVALID,
 
 251                         "UUID already used");
 
 259      * Save a copy of an automation composition to the copy table in case of a rollback.
 
 261      * @param automationComposition the composition to be copied
 
 263     public void copyAcElementsBeforeUpdate(AutomationComposition automationComposition) {
 
 264         var copy = new AutomationCompositionRollback(automationComposition);
 
 265         var jpaCopy = new JpaAutomationCompositionRollback(copy);
 
 266         acRollbackRepository.save(jpaCopy);
 
 267         acRollbackRepository.flush();
 
 271      * Get the copied automation composition from the RollbackRepository.
 
 273      * @param instanceId the id of the ac instance
 
 274      * @return the acRollback object
 
 276     public JpaAutomationCompositionRollback getAutomationCompositionRollback(String instanceId) {
 
 277         var result = acRollbackRepository.findById(instanceId);
 
 278         if (result.isEmpty()) {
 
 279             throw new PfModelRuntimeException(Status.NOT_FOUND, "Instance not found for rollback");