0078d226c12142101131a8303b6e2a60428a8609
[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.services.types.WorkflowVersionState.CERTIFIED;
20
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.util.Collection;
24 import java.util.Comparator;
25 import java.util.HashSet;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Optional;
29 import java.util.Set;
30 import java.util.function.Function;
31 import java.util.stream.Collectors;
32
33 import org.onap.sdc.workflow.persistence.ArtifactRepository;
34 import org.onap.sdc.workflow.persistence.ParameterRepository;
35 import org.onap.sdc.workflow.persistence.types.ArtifactEntity;
36 import org.onap.sdc.workflow.persistence.types.ParameterEntity;
37 import org.onap.sdc.workflow.persistence.types.ParameterRole;
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.exceptions.VersionStateModificationMissingArtifactException;
45 import org.onap.sdc.workflow.services.exceptions.WorkflowModificationException;
46 import org.onap.sdc.workflow.services.impl.mappers.VersionMapper;
47 import org.onap.sdc.workflow.services.impl.mappers.VersionStateMapper;
48 import org.onap.sdc.workflow.services.types.WorkflowVersion;
49 import org.onap.sdc.workflow.services.types.WorkflowVersionState;
50 import org.openecomp.sdc.logging.api.Logger;
51 import org.openecomp.sdc.logging.api.LoggerFactory;
52 import org.openecomp.sdc.versioning.ItemManager;
53 import org.openecomp.sdc.versioning.VersioningManager;
54 import org.openecomp.sdc.versioning.dao.types.Version;
55 import org.openecomp.sdc.versioning.dao.types.VersionStatus;
56 import org.openecomp.sdc.versioning.types.Item;
57 import org.openecomp.sdc.versioning.types.ItemStatus;
58 import org.openecomp.sdc.versioning.types.VersionCreationMethod;
59 import org.springframework.beans.factory.annotation.Autowired;
60 import org.springframework.stereotype.Service;
61 import org.springframework.util.StringUtils;
62 import org.springframework.web.multipart.MultipartFile;
63
64 @Service("workflowVersionManager")
65 public class WorkflowVersionManagerImpl implements WorkflowVersionManager {
66
67     private static final String VERSION_NOT_EXIST_MSG = "version with id '%s' does not exist for workflow with id '%s'";
68     private final VersioningManager versioningManager;
69     private final ItemManager itemManager;
70     private final ArtifactRepository artifactRepository;
71     private final ParameterRepository parameterRepository;
72     private final VersionMapper versionMapper;
73     private final VersionStateMapper versionStateMapper;
74     private static final Logger LOGGER = LoggerFactory.getLogger(WorkflowVersionManagerImpl.class);
75
76     @Autowired
77     public WorkflowVersionManagerImpl(VersioningManager versioningManager, ArtifactRepository artifactRepository,
78             VersionMapper versionMapper, VersionStateMapper versionStateMapper, ItemManager itemManager,
79             ParameterRepository parameterRepository) {
80         this.itemManager = itemManager;
81         this.versioningManager = versioningManager;
82         this.artifactRepository = artifactRepository;
83         this.parameterRepository = parameterRepository;
84         this.versionMapper = versionMapper;
85         this.versionStateMapper = versionStateMapper;
86     }
87
88     @Override
89     public Collection<WorkflowVersion> list(String workflowId, Set<WorkflowVersionState> stateFilter) {
90         Set<VersionStatus> versionStatusFilter =
91                 stateFilter == null ? null :
92                         stateFilter.stream().map(versionStateMapper::workflowVersionStateToVersionStatus)
93                                            .collect(Collectors.toSet());
94
95         return versioningManager.list(workflowId).stream()
96                                 .filter(version -> versionStatusFilter == null || versionStatusFilter.contains(
97                                         version.getStatus()))
98                                 .map(versionMapper::versionToWorkflowVersion)
99                                 .sorted(Comparator.comparing(WorkflowVersion::getName).reversed())
100                                 .peek(workflowVersion -> loadAndAddParameters(workflowId, workflowVersion))
101                                 .collect(Collectors.toList());
102     }
103
104     @Override
105     public WorkflowVersion get(String workflowId, String versionId) {
106         WorkflowVersion workflowVersion = versionMapper.versionToWorkflowVersion(getVersion(workflowId, versionId));
107         loadAndAddParameters(workflowId, workflowVersion);
108         workflowVersion.setHasArtifact(artifactRepository.isExist(workflowId,versionId));
109         return workflowVersion;
110     }
111
112     @Override
113     public WorkflowVersion create(String workflowId, String baseVersionId, WorkflowVersion workflowVersion) {
114         validateWorkflowStatus(workflowId);
115         List<Version> versions = versioningManager.list(workflowId);
116
117         if (baseVersionId != null) {
118             if (!workflowVersion.getInputs().isEmpty() || !workflowVersion.getOutputs().isEmpty()) {
119                 throw new VersionCreationException(workflowId, baseVersionId, "Inputs/Outputs should not be supplied");
120             }
121             validateVersionExistAndCertified(workflowId, versions, baseVersionId);
122         } else if (!versions.isEmpty()) {
123             throw new VersionCreationException(workflowId);
124         }
125
126         Version version = new Version();
127         version.setDescription(workflowVersion.getDescription());
128         version.setBaseId(baseVersionId);
129         Version createdVersion = versioningManager.create(workflowId, version, VersionCreationMethod.major);
130
131         if (versions.isEmpty()) { // only for first version
132             artifactRepository.createStructure(workflowId, createdVersion.getId());
133             parameterRepository.createStructure(workflowId, createdVersion.getId());
134             updateParameters(workflowId, createdVersion.getId(), workflowVersion.getInputs(), workflowVersion.getOutputs());
135             versioningManager.publish(workflowId, createdVersion, "Add initial data");
136         }
137
138         return get(workflowId, createdVersion.getId());
139     }
140
141     @Override
142     public void update(String workflowId, WorkflowVersion workflowVersion) {
143         validateWorkflowStatus(workflowId);
144         Version retrievedVersion = getVersion(workflowId, workflowVersion.getId());
145         if (CERTIFIED.equals(versionStateMapper.versionStatusToWorkflowVersionState(retrievedVersion.getStatus()))) {
146             throw new VersionModificationException(workflowId, workflowVersion.getId());
147         }
148
149         Version version = versionMapper.workflowVersionToVersion(workflowVersion);
150         version.setName(retrievedVersion.getName());
151         version.setStatus(retrievedVersion.getStatus());
152
153         updateParameters(workflowId, version.getId(), workflowVersion.getInputs(), workflowVersion.getOutputs());
154
155         versioningManager.updateVersion(workflowId, version);
156
157         Version updatedVersion = versioningManager.get(workflowId, version);
158         if(updatedVersion.getState().isDirty()) {
159             versioningManager.publish(workflowId, version, "Update version");
160         }
161     }
162
163
164     @Override
165     public WorkflowVersionState getState(String workflowId, String versionId) {
166         return versionStateMapper.versionStatusToWorkflowVersionState(getVersion(workflowId, versionId).getStatus());
167     }
168
169     @Override
170     public void updateState(String workflowId, String versionId, WorkflowVersionState newState) {
171         WorkflowVersionState currentState = getState(workflowId, versionId);
172         if (newState == CERTIFIED) {
173             if(!artifactRepository.isExist(workflowId,versionId)){
174                 throw new VersionStateModificationMissingArtifactException(workflowId, versionId, currentState,
175                         newState);
176             }
177             try {
178                 versioningManager.submit(workflowId, new Version(versionId),
179                         String.format("Update version state to %s", newState.name()));
180             } catch (Exception submitException) {
181                 throw new VersionStateModificationException(workflowId, versionId, currentState, newState,
182                         submitException);
183             }
184         } else {
185             throw new VersionStateModificationException(workflowId, versionId, currentState, newState);
186         }
187     }
188
189     @Override
190     public void uploadArtifact(String workflowId, String versionId, MultipartFile artifact) {
191         validateWorkflowStatus(workflowId);
192         Version retrievedVersion = getVersion(workflowId, versionId);
193         if (CERTIFIED.equals(versionStateMapper.versionStatusToWorkflowVersionState(retrievedVersion.getStatus()))) {
194             throw new VersionModificationException(workflowId, versionId);
195         }
196
197         try (InputStream artifactData = artifact.getInputStream()) {
198             ArtifactEntity artifactEntity =
199                     new ArtifactEntity(StringUtils.cleanPath(artifact.getOriginalFilename()), artifactData);
200             artifactRepository.update(workflowId, versionId, artifactEntity);
201             Version updatedVersion = versioningManager.get(workflowId, new Version(versionId));
202             if(updatedVersion.getState().isDirty()) {
203                 versioningManager.publish(workflowId, updatedVersion, "Update artifact");
204             }
205
206         } catch (IOException e) {
207             LOGGER.error(String.format("Upload Artifact failed for workflow id %s and version id %s",
208                     workflowId, versionId),e);
209             throw new InvalidArtifactException(e.getMessage());
210         }
211     }
212
213     @Override
214     public ArtifactEntity getArtifact(String workflowId, String versionId) {
215         getVersion(workflowId, versionId);
216         Optional<ArtifactEntity> artifactOptional = artifactRepository.get(workflowId, versionId);
217         if (!artifactOptional.isPresent()) {
218             LOGGER.error("Workflow Version Artifact was not found for workflow id {} and version id {}",
219                     workflowId, versionId);
220             throw new EntityNotFoundException(
221                     String.format("Artifact for workflow id %s version id %s was not found", workflowId, versionId));
222         }
223         return artifactOptional.get();
224     }
225
226     @Override
227     public void deleteArtifact(String workflowId, String versionId) {
228         validateWorkflowStatus(workflowId);
229         WorkflowVersion retrievedVersion = get(workflowId, versionId);
230         if (CERTIFIED.equals(retrievedVersion.getState())) {
231             LOGGER.error("Workflow Version is certified and can not be edited.Workflow id {} and version id {}",
232                     workflowId, versionId);
233             throw new VersionModificationException(workflowId, versionId);
234         }
235
236         artifactRepository.delete(workflowId, versionId);
237         versioningManager.publish(workflowId, new Version(versionId), "Delete Artifact");
238     }
239
240     private void validateVersionExistAndCertified(String workflowId, List<Version> versions, String versionId) {
241         Version baseVersion = findVersion(versions, versionId).orElseThrow(
242                 () -> new EntityNotFoundException(String.format(VERSION_NOT_EXIST_MSG, versionId, workflowId)));
243
244         if (CERTIFIED != versionStateMapper.versionStatusToWorkflowVersionState(baseVersion.getStatus())) {
245             throw new VersionCreationException(workflowId, versionId, "base version must be CERTIFIED");
246         }
247     }
248
249     private Version getVersion(String workflowId, String versionId) {
250         try {
251             Version version = versioningManager.get(workflowId, new Version(versionId));
252             if (version == null) {
253                 throw new EntityNotFoundException(String.format(VERSION_NOT_EXIST_MSG, versionId, workflowId));
254             }
255             return version;
256         } catch (Exception e) {
257             LOGGER.error(String.format(
258                     "Workflow Version was not found.Workflow id %s and version id %s", workflowId,
259                     versionId),e);
260             throw new EntityNotFoundException(String.format(VERSION_NOT_EXIST_MSG, versionId, workflowId));
261         }
262     }
263
264     private void updateParameters(String workflowId, String versionId, Collection<ParameterEntity> inputs,
265             Collection<ParameterEntity> outputs) {
266         updateVersionParameters(workflowId, versionId, ParameterRole.INPUT, inputs);
267         updateVersionParameters(workflowId, versionId, ParameterRole.OUTPUT, outputs);
268     }
269
270     private void updateVersionParameters(String workflowId, String versionId, ParameterRole role,
271             Collection<ParameterEntity> parameters) {
272
273         Collection<ParameterEntity> retrievedParams = parameterRepository.list(workflowId, versionId, role);
274         Map<String, ParameterEntity> retrievedParamsByName =
275                 retrievedParams.stream().collect(Collectors.toMap(ParameterEntity::getName, Function.identity()));
276
277         Set<String> namesOfParamsToKeep = new HashSet<>();
278         for (ParameterEntity parameter : parameters) {
279
280             ParameterEntity retrievedParam = retrievedParamsByName.get(parameter.getName());
281             if (retrievedParam == null) {
282                 parameterRepository.create(workflowId, versionId, role, parameter);
283             } else {
284                 parameter.setId(retrievedParam.getId());
285                 parameterRepository.update(workflowId, versionId, role, parameter);
286                 namesOfParamsToKeep.add(parameter.getName());
287             }
288         }
289
290         retrievedParams.stream().filter(retrievedParam -> !namesOfParamsToKeep.contains(retrievedParam.getName()))
291                        .forEach(retrievedParam -> parameterRepository
292                                                           .delete(workflowId, versionId, retrievedParam.getId()));
293     }
294
295     private void loadAndAddParameters(String workflowId, WorkflowVersion workflowVersion) {
296         workflowVersion.setInputs(parameterRepository.list(workflowId, workflowVersion.getId(), ParameterRole.INPUT));
297         workflowVersion.setOutputs(parameterRepository.list(workflowId, workflowVersion.getId(), ParameterRole.OUTPUT));
298     }
299
300     private static Optional<Version> findVersion(List<Version> versions, String versionId) {
301         return versions.stream().filter(version -> versionId.equals(version.getId())).findFirst();
302     }
303
304     void validateWorkflowStatus(String workflowId) {
305         Item workflowItem = itemManager.get(workflowId);
306         if (ItemStatus.ARCHIVED.equals(workflowItem.getStatus())) {
307             throw new WorkflowModificationException(workflowId);
308         }
309     }
310
311 }