1477ce1414fe3eb96c8615c947af5a275f6f3a46
[sdc.git] / openecomp-be / api / openecomp-sdc-rest-webapp / vendor-software-products-rest / vendor-software-products-rest-services / src / main / java / org / openecomp / sdcrests / vsp / rest / services / OrchestrationTemplateCandidateImpl.java
1 /*
2  * Copyright © 2016-2018 European Support Limited
3  * Copyright © 2021 Nokia
4  * Copyright © 2021 Nordix Foundation
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  * ============LICENSE_END=========================================================
18  * Modifications copyright (c) 2019 Nokia
19  * Modifications copyright (c) 2021 Nordix Foundation
20  * ================================================================================
21  */
22 package org.openecomp.sdcrests.vsp.rest.services;
23
24 import static javax.ws.rs.core.Response.Status.EXPECTATION_FAILED;
25 import static javax.ws.rs.core.Response.Status.NOT_ACCEPTABLE;
26 import static javax.ws.rs.core.Response.Status.NOT_FOUND;
27 import static org.openecomp.core.validation.errors.ErrorMessagesFormatBuilder.getErrorWithParameters;
28 import static org.openecomp.sdc.common.errors.Messages.ERROR_HAS_OCCURRED_WHILE_PERSISTING_THE_ARTIFACT;
29 import static org.openecomp.sdc.common.errors.Messages.ERROR_HAS_OCCURRED_WHILE_REDUCING_THE_ARTIFACT_SIZE;
30 import static org.openecomp.sdc.common.errors.Messages.NO_FILE_WAS_UPLOADED_OR_FILE_NOT_EXIST;
31 import static org.openecomp.sdc.common.errors.Messages.PACKAGE_PROCESS_ERROR;
32 import static org.openecomp.sdc.common.errors.Messages.UNEXPECTED_PROBLEM_HAPPENED_WHILE_GETTING;
33
34 import java.io.ByteArrayInputStream;
35 import java.io.FileOutputStream;
36 import java.io.IOException;
37 import java.io.InputStream;
38 import java.nio.file.Files;
39 import java.nio.file.Path;
40 import java.util.ArrayList;
41 import java.util.Collections;
42 import java.util.HashMap;
43 import java.util.List;
44 import java.util.Map;
45 import java.util.Optional;
46 import java.util.UUID;
47 import javax.activation.DataHandler;
48 import javax.inject.Named;
49 import javax.ws.rs.core.Response;
50 import org.apache.commons.lang3.tuple.Pair;
51 import org.apache.cxf.jaxrs.ext.multipart.Attachment;
52 import org.openecomp.sdc.activitylog.ActivityLogManager;
53 import org.openecomp.sdc.activitylog.ActivityLogManagerFactory;
54 import org.openecomp.sdc.activitylog.dao.type.ActivityLogEntity;
55 import org.openecomp.sdc.activitylog.dao.type.ActivityType;
56 import org.openecomp.sdc.be.csar.storage.ArtifactInfo;
57 import org.openecomp.sdc.be.csar.storage.ArtifactStorageConfig;
58 import org.openecomp.sdc.be.csar.storage.ArtifactStorageManager;
59 import org.openecomp.sdc.be.csar.storage.PackageSizeReducer;
60 import org.openecomp.sdc.be.csar.storage.StorageFactory;
61 import org.openecomp.sdc.be.csar.storage.exception.ArtifactStorageException;
62 import org.openecomp.sdc.common.util.ValidationUtils;
63 import org.openecomp.sdc.common.utils.SdcCommon;
64 import org.openecomp.sdc.datatypes.error.ErrorLevel;
65 import org.openecomp.sdc.datatypes.error.ErrorMessage;
66 import org.openecomp.sdc.logging.api.Logger;
67 import org.openecomp.sdc.logging.api.LoggerFactory;
68 import org.openecomp.sdc.vendorsoftwareproduct.OrchestrationTemplateCandidateManager;
69 import org.openecomp.sdc.vendorsoftwareproduct.OrchestrationTemplateCandidateManagerFactory;
70 import org.openecomp.sdc.vendorsoftwareproduct.VendorSoftwareProductManager;
71 import org.openecomp.sdc.vendorsoftwareproduct.VspManagerFactory;
72 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspDetails;
73 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspUploadStatus;
74 import org.openecomp.sdc.vendorsoftwareproduct.impl.onboarding.OnboardingPackageProcessor;
75 import org.openecomp.sdc.vendorsoftwareproduct.impl.onboarding.validation.CnfPackageValidator;
76 import org.openecomp.sdc.vendorsoftwareproduct.types.OnboardPackageInfo;
77 import org.openecomp.sdc.vendorsoftwareproduct.types.OrchestrationTemplateActionResponse;
78 import org.openecomp.sdc.vendorsoftwareproduct.types.UploadFileResponse;
79 import org.openecomp.sdc.vendorsoftwareproduct.types.ValidationResponse;
80 import org.openecomp.sdc.vendorsoftwareproduct.types.candidateheat.FilesDataStructure;
81 import org.openecomp.sdc.versioning.dao.types.Version;
82 import org.openecomp.sdcrests.vendorsoftwareproducts.types.FileDataStructureDto;
83 import org.openecomp.sdcrests.vendorsoftwareproducts.types.OrchestrationTemplateActionResponseDto;
84 import org.openecomp.sdcrests.vendorsoftwareproducts.types.UploadFileResponseDto;
85 import org.openecomp.sdcrests.vendorsoftwareproducts.types.ValidationResponseDto;
86 import org.openecomp.sdcrests.vendorsoftwareproducts.types.VspUploadStatusDto;
87 import org.openecomp.sdcrests.vsp.rest.OrchestrationTemplateCandidate;
88 import org.openecomp.sdcrests.vsp.rest.mapping.MapFilesDataStructureToDto;
89 import org.openecomp.sdcrests.vsp.rest.mapping.MapUploadFileResponseToUploadFileResponseDto;
90 import org.openecomp.sdcrests.vsp.rest.mapping.MapValidationResponseToDto;
91 import org.springframework.beans.factory.annotation.Autowired;
92 import org.springframework.context.annotation.Scope;
93 import org.springframework.stereotype.Service;
94
95 @Named
96 @Service("orchestrationTemplateCandidate")
97 @Scope(value = "prototype")
98 public class OrchestrationTemplateCandidateImpl implements OrchestrationTemplateCandidate {
99
100     private static final Logger LOGGER = LoggerFactory.getLogger(OrchestrationTemplateCandidateImpl.class);
101     private final OrchestrationTemplateCandidateManager candidateManager;
102     private final VendorSoftwareProductManager vendorSoftwareProductManager;
103     private final ActivityLogManager activityLogManager;
104     private final ArtifactStorageManager artifactStorageManager;
105     private final PackageSizeReducer packageSizeReducer;
106     private final OrchestrationTemplateCandidateUploadManager orchestrationTemplateCandidateUploadManager;
107
108     @Autowired
109     public OrchestrationTemplateCandidateImpl(final OrchestrationTemplateCandidateUploadManager orchestrationTemplateCandidateUploadManager) {
110         this.candidateManager = OrchestrationTemplateCandidateManagerFactory.getInstance().createInterface();
111         this.vendorSoftwareProductManager = VspManagerFactory.getInstance().createInterface();
112         this.activityLogManager = ActivityLogManagerFactory.getInstance().createInterface();
113         LOGGER.info("Instantiating artifactStorageManager");
114         final StorageFactory storageFactory = new StorageFactory();
115         this.artifactStorageManager = storageFactory.createArtifactStorageManager();
116         LOGGER.info("Instantiating packageSizeReducer");
117         this.packageSizeReducer = storageFactory.createPackageSizeReducer().orElse(null);
118         this.orchestrationTemplateCandidateUploadManager = orchestrationTemplateCandidateUploadManager;
119     }
120
121     // Constructor used in test to avoid mock static
122     public OrchestrationTemplateCandidateImpl(final OrchestrationTemplateCandidateManager candidateManager,
123                                               final VendorSoftwareProductManager vendorSoftwareProductManager,
124                                               final ActivityLogManager activityLogManager,
125                                               final ArtifactStorageManager artifactStorageManager,
126                                               final PackageSizeReducer packageSizeReducer,
127                                               final OrchestrationTemplateCandidateUploadManager orchestrationTemplateCandidateUploadManager) {
128         this.candidateManager = candidateManager;
129         this.vendorSoftwareProductManager = vendorSoftwareProductManager;
130         this.activityLogManager = activityLogManager;
131         this.artifactStorageManager = artifactStorageManager;
132         this.packageSizeReducer = packageSizeReducer;
133         this.orchestrationTemplateCandidateUploadManager = orchestrationTemplateCandidateUploadManager;
134     }
135
136     @Override
137     public Response upload(String vspId, String versionId, final Attachment fileToUpload, final String user) {
138         vspId = ValidationUtils.sanitizeInputString(vspId);
139         versionId = ValidationUtils.sanitizeInputString(versionId);
140         final Response response;
141         VspUploadStatusDto vspUploadStatus = null;
142         try {
143             vspUploadStatus = orchestrationTemplateCandidateUploadManager.putUploadInProgress(vspId, versionId, user);
144             final byte[] fileToUploadBytes;
145             final DataHandler dataHandler = fileToUpload.getDataHandler();
146             final var filename = ValidationUtils.sanitizeInputString(dataHandler.getName());
147             ArtifactInfo artifactInfo = null;
148             if (artifactStorageManager.isEnabled()) {
149                 artifactInfo = handleArtifactStorage(vspId, versionId, filename, dataHandler);
150                 fileToUploadBytes = artifactInfo.getBytes();
151             } else {
152                 fileToUploadBytes = fileToUpload.getObject(byte[].class);
153             }
154
155             final var onboardingPackageProcessor =
156                 new OnboardingPackageProcessor(filename, fileToUploadBytes, new CnfPackageValidator(), artifactInfo);
157             final ErrorMessage[] errorMessages = onboardingPackageProcessor.getErrorMessages().toArray(new ErrorMessage[0]);
158             if (onboardingPackageProcessor.hasErrors()) {
159                 return Response.status(NOT_ACCEPTABLE).entity(buildUploadResponseWithError(errorMessages)).build();
160             }
161             final var onboardPackageInfo = onboardingPackageProcessor.getOnboardPackageInfo().orElse(null);
162             if (onboardPackageInfo == null) {
163                 final UploadFileResponseDto uploadFileResponseDto = buildUploadResponseWithError(
164                     new ErrorMessage(ErrorLevel.ERROR, PACKAGE_PROCESS_ERROR.formatMessage(filename)));
165                 return Response.ok(uploadFileResponseDto).build();
166             }
167             final var version = new Version(versionId);
168             final var vspDetails = vendorSoftwareProductManager.getVsp(vspId, version);
169             response = processOnboardPackage(onboardPackageInfo, vspDetails, errorMessages);
170             final UploadFileResponseDto entity = (UploadFileResponseDto) response.getEntity();
171             if (artifactStorageManager.isEnabled()) {
172                 if (!entity.getErrors().isEmpty()) {
173                     artifactStorageManager.delete(artifactInfo);
174                 } else {
175                     artifactStorageManager.put(vspId, versionId + ".reduced", new ByteArrayInputStream(fileToUploadBytes));
176                 }
177             }
178             orchestrationTemplateCandidateUploadManager
179                 .putUploadAsFinished(vspId, versionId, vspUploadStatus.getLockId(), VspUploadStatus.SUCCESS, user);
180         } catch (final Exception ex) {
181             if (vspUploadStatus != null) {
182                 orchestrationTemplateCandidateUploadManager
183                     .putUploadAsFinished(vspId, versionId, vspUploadStatus.getLockId(), VspUploadStatus.ERROR, user);
184             }
185             throw ex;
186         }
187         return response;
188     }
189
190     private ArtifactInfo handleArtifactStorage(final String vspId, final String versionId, final String filename,
191                                                final DataHandler artifactDataHandler) {
192         final Path tempArtifactPath;
193         try {
194             final ArtifactStorageConfig storageConfiguration = artifactStorageManager.getStorageConfiguration();
195
196             final Path folder = Path.of(storageConfiguration.getTempPath()).resolve(vspId).resolve(versionId);
197             tempArtifactPath = folder.resolve(UUID.randomUUID().toString());
198             Files.createDirectories(folder);
199             try (final InputStream packageInputStream = artifactDataHandler.getInputStream();
200                 final var fileOutputStream = new FileOutputStream(tempArtifactPath.toFile())) {
201                 packageInputStream.transferTo(fileOutputStream);
202             }
203         } catch (final Exception e) {
204             throw new ArtifactStorageException(UNEXPECTED_PROBLEM_HAPPENED_WHILE_GETTING.formatMessage(filename));
205         }
206         final ArtifactInfo artifactInfo;
207         try (final InputStream inputStream = Files.newInputStream(tempArtifactPath)) {
208             artifactInfo = artifactStorageManager.upload(vspId, versionId, inputStream);
209         } catch (final Exception e) {
210             LOGGER.error("Package Size Reducer not configured", e);
211             throw new ArtifactStorageException(ERROR_HAS_OCCURRED_WHILE_PERSISTING_THE_ARTIFACT.formatMessage(filename));
212         }
213         try {
214             artifactInfo.setBytes(packageSizeReducer.reduce(tempArtifactPath));
215             Files.delete(tempArtifactPath);
216         } catch (final Exception e) {
217             LOGGER.error("Package Size Reducer not configured", e);
218             throw new ArtifactStorageException(ERROR_HAS_OCCURRED_WHILE_REDUCING_THE_ARTIFACT_SIZE.formatMessage(filename));
219         }
220         return artifactInfo;
221     }
222
223     private Response processOnboardPackage(final OnboardPackageInfo onboardPackageInfo, final VspDetails vspDetails,
224                                            final ErrorMessage... errorMessages) {
225         final UploadFileResponse uploadFileResponse = candidateManager.upload(vspDetails, onboardPackageInfo);
226         final UploadFileResponseDto uploadFileResponseDto = new MapUploadFileResponseToUploadFileResponseDto()
227             .applyMapping(uploadFileResponse, UploadFileResponseDto.class);
228         if (errorMessages.length > 0) {
229             uploadFileResponseDto.setErrors(getErrorMap(errorMessages));
230         }
231         return Response.ok(uploadFileResponseDto).build();
232     }
233
234     private Map<String, List<ErrorMessage>> getErrorMap(ErrorMessage[] errorMessages) {
235         final Map<String, List<ErrorMessage>> errorMap = new HashMap<>();
236         final List<ErrorMessage> errorMessageList = new ArrayList<>();
237         Collections.addAll(errorMessageList, errorMessages);
238         errorMap.put(SdcCommon.UPLOAD_FILE, errorMessageList);
239         return errorMap;
240     }
241
242     private UploadFileResponseDto buildUploadResponseWithError(final ErrorMessage... errorMessages) {
243         final UploadFileResponseDto uploadFileResponseDto = new UploadFileResponseDto();
244         uploadFileResponseDto.setErrors(getErrorMap(errorMessages));
245         return uploadFileResponseDto;
246     }
247
248     @Override
249     public Response get(String vspId, String versionId, String user) throws IOException {
250         Optional<Pair<String, byte[]>> zipFile = candidateManager.get(vspId, new Version(versionId));
251         String fileName;
252         if (zipFile.isPresent()) {
253             fileName = "Candidate." + zipFile.get().getLeft();
254         } else {
255             zipFile = vendorSoftwareProductManager.get(vspId, new Version((versionId)));
256             if (zipFile.isEmpty()) {
257                 ErrorMessage errorMessage = new ErrorMessage(ErrorLevel.ERROR,
258                     getErrorWithParameters(NO_FILE_WAS_UPLOADED_OR_FILE_NOT_EXIST.getErrorMessage(), ""));
259                 LOGGER.error(errorMessage.getMessage());
260                 return Response.status(NOT_FOUND).build();
261             }
262             fileName = "Processed." + zipFile.get().getLeft();
263         }
264         Response.ResponseBuilder response = Response.ok(zipFile.get().getRight());
265         response.header("Content-Disposition", "attachment; filename=" + fileName);
266         return response.build();
267     }
268
269     @Override
270     public Response abort(String vspId, String versionId) {
271         candidateManager.abort(vspId, new Version(versionId));
272         return Response.ok().build();
273     }
274
275     @Override
276     public Response process(String vspId, String versionId, String user) {
277         Version version = new Version(versionId);
278         OrchestrationTemplateActionResponse response = candidateManager.process(vspId, version);
279         activityLogManager.logActivity(new ActivityLogEntity(vspId, version, ActivityType.Upload_Network_Package, user, true, "", ""));
280         OrchestrationTemplateActionResponseDto responseDto = copyOrchestrationTemplateActionResponseToDto(response);
281         return Response.ok(responseDto).build();
282     }
283
284     @Override
285     public Response updateFilesDataStructure(String vspId, String versionId, FileDataStructureDto fileDataStructureDto, String user) {
286         FilesDataStructure fileDataStructure = copyFilesDataStructureDtoToFilesDataStructure(fileDataStructureDto);
287         ValidationResponse response = candidateManager.updateFilesDataStructure(vspId, new Version(versionId), fileDataStructure);
288         if (!response.isValid()) {
289             return Response.status(EXPECTATION_FAILED)
290                 .entity(new MapValidationResponseToDto().applyMapping(response, ValidationResponseDto.class))
291                 .build();
292         }
293         return Response.ok(fileDataStructureDto).build();
294     }
295
296     @Override
297     public Response getFilesDataStructure(String vspId, String versionId, String user) {
298         Optional<FilesDataStructure> filesDataStructure = candidateManager.getFilesDataStructure(vspId, new Version(versionId));
299         if (filesDataStructure.isEmpty()) {
300             filesDataStructure = vendorSoftwareProductManager.getOrchestrationTemplateStructure(vspId, new Version(versionId));
301         }
302         FileDataStructureDto fileDataStructureDto = filesDataStructure
303             .map(dataStructure -> new MapFilesDataStructureToDto().applyMapping(dataStructure, FileDataStructureDto.class))
304             .orElse(new FileDataStructureDto());
305         return Response.ok(fileDataStructureDto).build();
306     }
307
308     private OrchestrationTemplateActionResponseDto copyOrchestrationTemplateActionResponseToDto(OrchestrationTemplateActionResponse response) {
309         OrchestrationTemplateActionResponseDto result = new OrchestrationTemplateActionResponseDto();
310         result.setErrors(response.getErrors());
311         result.setFileNames(response.getFileNames());
312         result.setStatus(response.getStatus());
313         return result;
314     }
315
316     private FilesDataStructure copyFilesDataStructureDtoToFilesDataStructure(FileDataStructureDto fileDataStructureDto) {
317         FilesDataStructure filesDataStructure = new FilesDataStructure();
318         filesDataStructure.setArtifacts(fileDataStructureDto.getArtifacts());
319         filesDataStructure.setModules(fileDataStructureDto.getModules());
320         filesDataStructure.setNested(fileDataStructureDto.getNested());
321         filesDataStructure.setUnassigned(fileDataStructureDto.getUnassigned());
322         return filesDataStructure;
323     }
324 }