484c598ab5c92d8ae8ba8a8a02e673bce1a75f3c
[sdc/sdc-workflow-designer.git] /
1 /*
2  * Copyright © 2018 European Support Limited
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package org.onap.sdc.workflow.services.impl;
18
19 import static org.onap.sdc.workflow.persistence.types.WorkflowVersionState.CERTIFIED;
20
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.util.Collection;
24 import java.util.HashSet;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Optional;
28 import java.util.Set;
29 import java.util.function.Function;
30 import java.util.stream.Collectors;
31 import org.onap.sdc.workflow.persistence.ArtifactRepository;
32 import org.onap.sdc.workflow.persistence.ParameterRepository;
33 import org.onap.sdc.workflow.persistence.types.ArtifactEntity;
34 import org.onap.sdc.workflow.persistence.types.ParameterEntity;
35 import org.onap.sdc.workflow.persistence.types.ParameterRole;
36 import org.onap.sdc.workflow.persistence.types.WorkflowVersion;
37 import org.onap.sdc.workflow.persistence.types.WorkflowVersionState;
38 import org.onap.sdc.workflow.services.WorkflowVersionManager;
39 import org.onap.sdc.workflow.services.exceptions.EntityNotFoundException;
40 import org.onap.sdc.workflow.services.exceptions.InvalidArtifactException;
41 import org.onap.sdc.workflow.services.exceptions.VersionCreationException;
42 import org.onap.sdc.workflow.services.exceptions.VersionModificationException;
43 import org.onap.sdc.workflow.services.exceptions.VersionStateModificationException;
44 import org.onap.sdc.workflow.services.impl.mappers.VersionMapper;
45 import org.onap.sdc.workflow.services.impl.mappers.VersionStateMapper;
46 import org.openecomp.sdc.logging.api.Logger;
47 import org.openecomp.sdc.logging.api.LoggerFactory;
48 import org.openecomp.sdc.versioning.VersioningManager;
49 import org.openecomp.sdc.versioning.dao.types.Version;
50 import org.openecomp.sdc.versioning.dao.types.VersionStatus;
51 import org.openecomp.sdc.versioning.types.VersionCreationMethod;
52 import org.springframework.beans.factory.annotation.Autowired;
53 import org.springframework.stereotype.Service;
54 import org.springframework.util.StringUtils;
55 import org.springframework.web.multipart.MultipartFile;
56
57 @Service("workflowVersionManager")
58 public class WorkflowVersionManagerImpl implements WorkflowVersionManager {
59
60     private static final String VERSION_NOT_EXIST_MSG = "version with id '%s' does not exist for workflow with id '%s'";
61     private final VersioningManager versioningManager;
62     private final ArtifactRepository artifactRepository;
63     private final ParameterRepository parameterRepository;
64     private final VersionMapper versionMapper;
65     private final VersionStateMapper versionStateMapper;
66     private static final Logger LOGGER = LoggerFactory.getLogger(WorkflowVersionManagerImpl.class);
67
68     @Autowired
69     public WorkflowVersionManagerImpl(VersioningManager versioningManager, ArtifactRepository artifactRepository,
70             VersionMapper versionMapper, VersionStateMapper versionStateMapper,
71             ParameterRepository parameterRepository) {
72         this.versioningManager = versioningManager;
73         this.artifactRepository = artifactRepository;
74         this.parameterRepository = parameterRepository;
75         this.versionMapper = versionMapper;
76         this.versionStateMapper = versionStateMapper;
77     }
78
79     @Override
80     public Collection<WorkflowVersion> list(String workflowId, Set<WorkflowVersionState> stateFilter) {
81         Set<VersionStatus> versionStatusFilter =
82                 stateFilter == null ? null :
83                         stateFilter.stream().map(versionStateMapper::workflowVersionStateToVersionStatus)
84                                            .collect(Collectors.toSet());
85
86         return versioningManager.list(workflowId).stream()
87                                 .filter(version -> versionStatusFilter == null || versionStatusFilter.contains(
88                                         version.getStatus()))
89                                 .map(versionMapper::versionToWorkflowVersion)
90                                 .peek(workflowVersion -> loadAndAddParameters(workflowId, workflowVersion))
91                                 .collect(Collectors.toList());
92     }
93
94     @Override
95     public WorkflowVersion get(String workflowId, String versionId) {
96         WorkflowVersion workflowVersion = versionMapper.versionToWorkflowVersion(getVersion(workflowId, versionId));
97         loadAndAddParameters(workflowId, workflowVersion);
98         return workflowVersion;
99     }
100
101     @Override
102     public WorkflowVersion create(String workflowId, String baseVersionId, WorkflowVersion workflowVersion) {
103         List<Version> versions = versioningManager.list(workflowId);
104
105         if (baseVersionId != null) {
106             if (!workflowVersion.getInputs().isEmpty() || !workflowVersion.getOutputs().isEmpty()) {
107                 throw new VersionCreationException(workflowId, baseVersionId, "Inputs/Outputs should not be supplied");
108             }
109             validateVersionExistAndCertified(workflowId, versions, baseVersionId);
110         } else if (!versions.isEmpty()) {
111             throw new VersionCreationException(workflowId);
112         }
113
114         Version version = new Version();
115         version.setDescription(workflowVersion.getDescription());
116         version.setBaseId(baseVersionId);
117         Version createdVersion = versioningManager.create(workflowId, version, VersionCreationMethod.major);
118
119         if (versions.isEmpty()) { // only for first version
120             artifactRepository.createStructure(workflowId, createdVersion.getId());
121             parameterRepository.createStructure(workflowId, createdVersion.getId());
122             updateParameters(workflowId, createdVersion.getId(), workflowVersion.getInputs(), workflowVersion.getOutputs());
123             versioningManager.publish(workflowId, createdVersion, "Add initial data");
124         }
125
126         return get(workflowId, createdVersion.getId());
127     }
128
129     @Override
130     public void update(String workflowId, WorkflowVersion workflowVersion) {
131         Version retrievedVersion = getVersion(workflowId, workflowVersion.getId());
132         if (CERTIFIED.equals(versionStateMapper.versionStatusToWorkflowVersionState(retrievedVersion.getStatus()))) {
133             throw new VersionModificationException(workflowId, workflowVersion.getId());
134         }
135
136         Version version = versionMapper.workflowVersionToVersion(workflowVersion);
137         version.setName(retrievedVersion.getName());
138         version.setStatus(retrievedVersion.getStatus());
139
140         updateParameters(workflowId, version.getId(), workflowVersion.getInputs(), workflowVersion.getOutputs());
141
142         versioningManager.updateVersion(workflowId, version);
143         versioningManager.publish(workflowId, version, "Update version");
144     }
145
146     @Override
147     public WorkflowVersionState getState(String workflowId, String versionId) {
148         return versionStateMapper.versionStatusToWorkflowVersionState(getVersion(workflowId, versionId).getStatus());
149     }
150
151     @Override
152     public void updateState(String workflowId, String versionId, WorkflowVersionState state) {
153         WorkflowVersionState retrievedState =
154                 versionStateMapper.versionStatusToWorkflowVersionState(getVersion(workflowId, versionId).getStatus());
155
156         if (state == CERTIFIED) {
157             try {
158                 versioningManager.submit(workflowId, new Version(versionId),
159                         String.format("Update version state to %s", state.name()));
160             } catch (Exception e) {
161                 throw new VersionStateModificationException(workflowId, versionId, retrievedState, state);
162             }
163         } else {
164             throw new VersionStateModificationException(workflowId, versionId, retrievedState, state);
165         }
166     }
167
168     @Override
169     public void uploadArtifact(String workflowId, String versionId, MultipartFile artifact) {
170         Version retrievedVersion = getVersion(workflowId, versionId);
171         if (CERTIFIED.equals(versionStateMapper.versionStatusToWorkflowVersionState(retrievedVersion.getStatus()))) {
172             throw new VersionModificationException(workflowId, versionId);
173         }
174
175         try (InputStream artifactData = artifact.getInputStream()) {
176             ArtifactEntity artifactEntity =
177                     new ArtifactEntity(StringUtils.cleanPath(artifact.getOriginalFilename()), artifactData);
178             artifactRepository.update(workflowId, versionId, artifactEntity);
179             versioningManager.publish(workflowId, new Version(versionId), "Update Artifact");
180
181         } catch (IOException e) {
182             LOGGER.error(String.format("Upload Artifact failed for workflow id %s and version id %s",
183                     workflowId, versionId),e);
184             throw new InvalidArtifactException(e.getMessage());
185         }
186     }
187
188     @Override
189     public ArtifactEntity getArtifact(String workflowId, String versionId) {
190         getVersion(workflowId, versionId);
191         Optional<ArtifactEntity> artifactOptional = artifactRepository.get(workflowId, versionId);
192         if (!artifactOptional.isPresent()) {
193             LOGGER.error(String.format("Workflow Version Artifact was not found for workflow id %s and version id %s",
194                     workflowId, versionId));
195             throw new EntityNotFoundException(
196                     String.format("Artifact for workflow id %S version id %S was not found", workflowId, versionId));
197         }
198         return artifactOptional.get();
199     }
200
201     @Override
202     public void deleteArtifact(String workflowId, String versionId) {
203         WorkflowVersion retrievedVersion = get(workflowId, versionId);
204         if (CERTIFIED.equals(retrievedVersion.getState())) {
205             LOGGER.error(String.format(
206                     "Workflow Version is certified and can not be edited.Workflow id %s and version id %s", workflowId,
207                     versionId));
208             throw new VersionModificationException(workflowId, versionId);
209         }
210
211         artifactRepository.delete(workflowId, versionId);
212         versioningManager.publish(workflowId, new Version(versionId), "Delete Artifact");
213     }
214
215     private void validateVersionExistAndCertified(String workflowId, List<Version> versions, String versionId) {
216         Version baseVersion = findVersion(versions, versionId).orElseThrow(
217                 () -> new EntityNotFoundException(String.format(VERSION_NOT_EXIST_MSG, versionId, workflowId)));
218
219         if (CERTIFIED != versionStateMapper.versionStatusToWorkflowVersionState(baseVersion.getStatus())) {
220             throw new VersionCreationException(workflowId, versionId, "base version must be CERTIFIED");
221         }
222     }
223
224     private Version getVersion(String workflowId, String versionId) {
225         try {
226             Version version = versioningManager.get(workflowId, new Version(versionId));
227             if (version == null) {
228                 throw new EntityNotFoundException(String.format(VERSION_NOT_EXIST_MSG, versionId, workflowId));
229             }
230             return version;
231         } catch (Exception e) {
232             LOGGER.error(String.format(
233                     "Workflow Version was not found.Workflow id %s and version id %s", workflowId,
234                     versionId),e);
235             throw new EntityNotFoundException(String.format(VERSION_NOT_EXIST_MSG, versionId, workflowId));
236         }
237     }
238
239     private void updateParameters(String workflowId, String versionId, Collection<ParameterEntity> inputs,
240             Collection<ParameterEntity> outputs) {
241         updateVersionParameters(workflowId, versionId, ParameterRole.INPUT, inputs);
242         updateVersionParameters(workflowId, versionId, ParameterRole.OUTPUT, outputs);
243     }
244
245     private void updateVersionParameters(String workflowId, String versionId, ParameterRole role,
246             Collection<ParameterEntity> parameters) {
247
248         Collection<ParameterEntity> retrievedParams = parameterRepository.list(workflowId, versionId, role);
249         Map<String, ParameterEntity> retrievedParamsByName =
250                 retrievedParams.stream().collect(Collectors.toMap(ParameterEntity::getName, Function.identity()));
251
252         Set<String> namesOfParamsToKeep = new HashSet<>();
253         for (ParameterEntity parameter : parameters) {
254
255             ParameterEntity retrievedParam = retrievedParamsByName.get(parameter.getName());
256             if (retrievedParam == null) {
257                 parameterRepository.create(workflowId, versionId, role, parameter);
258             } else {
259                 parameterRepository.update(workflowId, versionId, role, parameter);
260                 namesOfParamsToKeep.add(parameter.getName());
261             }
262         }
263
264         retrievedParams.stream().filter(retrievedParam -> !namesOfParamsToKeep.contains(retrievedParam.getName()))
265                        .forEach(retrievedParam -> parameterRepository
266                                                           .delete(workflowId, versionId, retrievedParam.getId()));
267     }
268
269     private void loadAndAddParameters(String workflowId, WorkflowVersion workflowVersion) {
270         workflowVersion.setInputs(parameterRepository.list(workflowId, workflowVersion.getId(), ParameterRole.INPUT));
271         workflowVersion.setOutputs(parameterRepository.list(workflowId, workflowVersion.getId(), ParameterRole.OUTPUT));
272     }
273
274     private static Optional<Version> findVersion(List<Version> versions, String versionId) {
275         return versions.stream().filter(version -> versionId.equals(version.getId())).findFirst();
276     }
277 }