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