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