Backout "Remove generation of csar.meta"
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / tosca / CsarUtils.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20 package org.openecomp.sdc.be.tosca;
21
22 import fj.F;
23 import fj.data.Either;
24 import java.io.IOException;
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.EnumMap;
28 import java.util.HashMap;
29 import java.util.HashSet;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.Map.Entry;
33 import java.util.Optional;
34 import java.util.Set;
35 import java.util.regex.Pattern;
36 import java.util.zip.ZipEntry;
37 import java.util.zip.ZipOutputStream;
38 import lombok.Getter;
39 import lombok.Setter;
40 import org.apache.commons.codec.binary.Base64;
41 import org.apache.commons.collections.MapUtils;
42 import org.apache.commons.io.output.ByteArrayOutputStream;
43 import org.apache.commons.lang3.tuple.ImmutablePair;
44 import org.openecomp.sdc.be.components.impl.ImportUtils;
45 import org.openecomp.sdc.be.config.ArtifactConfigManager;
46 import org.openecomp.sdc.be.config.ArtifactConfiguration;
47 import org.openecomp.sdc.be.config.ComponentType;
48 import org.openecomp.sdc.be.config.ConfigurationManager;
49 import org.openecomp.sdc.be.dao.api.ActionStatus;
50 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
51 import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum;
52 import org.openecomp.sdc.be.impl.ComponentsUtils;
53 import org.openecomp.sdc.be.model.ArtifactDefinition;
54 import org.openecomp.sdc.be.model.Component;
55 import org.openecomp.sdc.be.model.ComponentInstance;
56 import org.openecomp.sdc.be.model.Service;
57 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ToscaOperationFacade;
58 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
59 import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum;
60 import org.openecomp.sdc.common.api.ArtifactTypeEnum;
61 import org.openecomp.sdc.common.log.elements.LoggerSupportability;
62 import org.openecomp.sdc.common.log.enums.LoggerSupportabilityActions;
63 import org.openecomp.sdc.common.log.enums.StatusCode;
64 import org.openecomp.sdc.common.log.wrappers.Logger;
65 import org.openecomp.sdc.common.util.GeneralUtility;
66 import org.openecomp.sdc.common.util.ValidationUtils;
67 import org.openecomp.sdc.exception.ResponseFormat;
68 import org.springframework.beans.factory.annotation.Autowired;
69
70 @org.springframework.stereotype.Component("csar-utils")
71 public class CsarUtils {
72
73     public static final String ARTIFACTS_PATH = "Artifacts/";
74     public static final String ARTIFACTS = "Artifacts";
75     public static final String ARTIFACT_CREATED_FROM_CSAR = "Artifact created from csar";
76     private static final Logger log = Logger.getLogger(CsarUtils.class);
77     private static final LoggerSupportability loggerSupportability = LoggerSupportability.getLogger(CsarUtils.class.getName());
78     private static final String PATH_DELIMITER = "/";
79     private static final String CSAR_META_VERSION = "1.0";
80     private static final String CSAR_META_PATH_FILE_NAME = "csar.meta";
81     private static final String DEFINITION = "Definitions";
82     private static final String DEL_PATTERN = "([/\\\\]+)";
83     private static final String WORD_PATTERN = "\\w\\_\\@\\-\\.\\s]+)";
84     public static final String VALID_ENGLISH_ARTIFACT_NAME = "([" + WORD_PATTERN;
85     public static final String VF_NODE_TYPE_ARTIFACTS_PATH_PATTERN = ARTIFACTS + DEL_PATTERN +
86         // Artifact Group (i.e Deployment/Informational)
87         VALID_ENGLISH_ARTIFACT_NAME + DEL_PATTERN +
88         // Artifact Type
89         VALID_ENGLISH_ARTIFACT_NAME + DEL_PATTERN +
90         // Artifact Any File Name
91         ".+";
92     public static final String SERVICE_TEMPLATE_PATH_PATTERN = DEFINITION + DEL_PATTERN +
93         // Service Template File Name
94         VALID_ENGLISH_ARTIFACT_NAME;
95     private static final String VALID_ENGLISH_ARTIFACT_NAME_WITH_DIGITS = "([\\d" + WORD_PATTERN;
96     private static final String VFC_NODE_TYPE_ARTIFACTS_PATH_PATTERN =
97         ARTIFACTS + DEL_PATTERN + ImportUtils.Constants.USER_DEFINED_RESOURCE_NAMESPACE_PREFIX + VALID_ENGLISH_ARTIFACT_NAME_WITH_DIGITS + DEL_PATTERN
98             + VALID_ENGLISH_ARTIFACT_NAME_WITH_DIGITS + DEL_PATTERN + VALID_ENGLISH_ARTIFACT_NAME_WITH_DIGITS + DEL_PATTERN
99             + VALID_ENGLISH_ARTIFACT_NAME_WITH_DIGITS;
100     private static final String BLOCK_0_TEMPLATE = "SDC-TOSCA-Meta-File-Version: %s\nSDC-TOSCA-Definitions-Version: %s\n";
101
102     private final ToscaOperationFacade toscaOperationFacade;
103     private final ComponentsUtils componentsUtils;
104     private final MapFromModelCsarGeneratorService mapFromModelCsarGeneratorService;
105
106     @Autowired
107     public CsarUtils(final ToscaOperationFacade toscaOperationFacade,
108                      final ComponentsUtils componentsUtils,
109                      final MapFromModelCsarGeneratorService mapFromModelCsarGeneratorService) {
110         this.toscaOperationFacade = toscaOperationFacade;
111         this.componentsUtils = componentsUtils;
112         this.mapFromModelCsarGeneratorService = mapFromModelCsarGeneratorService;
113     }
114
115     /**
116      * Extracts artifacts of VFCs from CSAR
117      *
118      * @param csar
119      * @return Map of <String, List<ArtifactDefinition>> the contains Lists of artifacts according vfcToscaNamespace
120      */
121     public static Map<String, List<ArtifactDefinition>> extractVfcsArtifactsFromCsar(Map<String, byte[]> csar) {
122         Map<String, List<ArtifactDefinition>> artifacts = new HashMap<>();
123         if (csar != null) {
124             log.debug("************* Going to extract VFCs artifacts from Csar. ");
125             Map<String, Set<List<String>>> collectedWarningMessages = new HashMap<>();
126             csar.entrySet().stream()
127                 // filter CSAR entry by node type artifact path
128                 .filter(e -> Pattern.compile(VFC_NODE_TYPE_ARTIFACTS_PATH_PATTERN).matcher(e.getKey()).matches())
129                 // extract ArtifactDefinition from CSAR entry for each entry with matching artifact path
130                 .forEach(e -> extractVfcArtifact(e, collectedWarningMessages).ifPresent(ip -> addExtractedVfcArtifact(ip, artifacts)));
131             // add counter suffix to artifact labels
132             handleWarningMessages(collectedWarningMessages);
133         }
134         return artifacts;
135     }
136
137     /**
138      * Print warnings to log
139      *
140      * @param collectedWarningMessages
141      */
142     public static void handleWarningMessages(Map<String, Set<List<String>>> collectedWarningMessages) {
143         collectedWarningMessages.entrySet().stream()
144             // for each vfc
145             .forEach(e -> e.getValue().stream()
146                 // add each warning message to log
147                 .forEach(args -> log.warn(e.getKey(), args.toArray())));
148     }
149
150     private static void addExtractedVfcArtifact(ImmutablePair<String, ArtifactDefinition> extractedVfcArtifact,
151                                                 Map<String, List<ArtifactDefinition>> artifacts) {
152         String vfcToscaNamespace = extractedVfcArtifact.getKey();
153         artifacts.computeIfAbsent(vfcToscaNamespace, k -> new ArrayList<>());
154         artifacts.get(vfcToscaNamespace).add(extractedVfcArtifact.getValue());
155     }
156
157     private static Optional<ImmutablePair<String, ArtifactDefinition>> extractVfcArtifact(Entry<String, byte[]> entry,
158                                                                                           Map<String, Set<List<String>>> collectedWarningMessages) {
159         String[] parsedCsarArtifactPath = entry.getKey().split(PATH_DELIMITER);
160         String groupType = parsedCsarArtifactPath[2].toUpperCase();
161         return detectArtifactGroupType(groupType, collectedWarningMessages).left()
162             .map(buildArtifactDefinitionFromCsarArtifactPath(entry, collectedWarningMessages, parsedCsarArtifactPath))
163             .either(ad -> Optional.of(new ImmutablePair<>(parsedCsarArtifactPath[1], ad)), b -> Optional.empty());
164     }
165
166     private static Either<ArtifactGroupTypeEnum, Boolean> detectArtifactGroupType(String groupType,
167                                                                                   Map<String, Set<List<String>>> collectedWarningMessages) {
168         Either<ArtifactGroupTypeEnum, Boolean> result;
169         try {
170             ArtifactGroupTypeEnum artifactGroupType = ArtifactGroupTypeEnum.findType(groupType.toUpperCase());
171             if (artifactGroupType == null || (artifactGroupType != ArtifactGroupTypeEnum.INFORMATIONAL
172                 && artifactGroupType != ArtifactGroupTypeEnum.DEPLOYMENT)) {
173                 String warningMessage = "Warning - unrecognized artifact group type {} was received.";
174                 List<String> messageArguments = new ArrayList<>();
175                 messageArguments.add(groupType);
176                 if (!collectedWarningMessages.containsKey(warningMessage)) {
177                     Set<List<String>> messageArgumentLists = new HashSet<>();
178                     messageArgumentLists.add(messageArguments);
179                     collectedWarningMessages.put(warningMessage, messageArgumentLists);
180                 } else {
181                     collectedWarningMessages.get(warningMessage).add(messageArguments);
182                 }
183                 result = Either.right(false);
184             } else {
185                 result = Either.left(artifactGroupType);
186             }
187         } catch (Exception e) {
188             log.debug("detectArtifactGroupType failed with exception", e);
189             result = Either.right(false);
190         }
191         return result;
192     }
193
194     private static F<ArtifactGroupTypeEnum, ArtifactDefinition> buildArtifactDefinitionFromCsarArtifactPath(Entry<String, byte[]> entry,
195                                                                                                             Map<String, Set<List<String>>> collectedWarningMessages,
196                                                                                                             String[] parsedCsarArtifactPath) {
197         return artifactGroupType -> {
198             ArtifactDefinition artifact;
199             artifact = new ArtifactDefinition();
200             artifact.setArtifactGroupType(artifactGroupType);
201             artifact.setArtifactType(
202                 detectArtifactTypeVFC(artifactGroupType, parsedCsarArtifactPath[3], parsedCsarArtifactPath[1], collectedWarningMessages));
203             artifact.setArtifactName(ValidationUtils.normalizeFileName(parsedCsarArtifactPath[parsedCsarArtifactPath.length - 1]));
204             artifact.setPayloadData(Base64.encodeBase64String(entry.getValue()));
205             artifact.setArtifactDisplayName(
206                 artifact.getArtifactName().lastIndexOf('.') > 0 ? artifact.getArtifactName().substring(0, artifact.getArtifactName().lastIndexOf('.'))
207                     : artifact.getArtifactName());
208             artifact.setArtifactLabel(ValidationUtils.normalizeArtifactLabel(artifact.getArtifactName()));
209             artifact.setDescription(ARTIFACT_CREATED_FROM_CSAR);
210             artifact.setIsFromCsar(true);
211             artifact.setArtifactChecksum(GeneralUtility.calculateMD5Base64EncodedByByteArray(entry.getValue()));
212             return artifact;
213         };
214     }
215
216     /**
217      * This method checks the artifact GroupType & Artifact Type. <br> if there is any problem warning messages are added to collectedWarningMessages
218      *
219      * @param artifactPath
220      * @param collectedWarningMessages
221      * @return
222      */
223     public static Either<NonMetaArtifactInfo, Boolean> validateNonMetaArtifact(String artifactPath, byte[] payloadData,
224                                                                                Map<String, Set<List<String>>> collectedWarningMessages) {
225         try {
226             String[] parsedArtifactPath = artifactPath.split(PATH_DELIMITER);
227             String groupType = parsedArtifactPath[1];
228             String receivedTypeName = parsedArtifactPath[2];
229             String artifactFileNameType = parsedArtifactPath[3];
230             return detectArtifactGroupType(groupType, collectedWarningMessages).left().bind(artifactGroupType -> {
231                 String artifactType = detectArtifactTypeVF(artifactGroupType, receivedTypeName, collectedWarningMessages);
232                 return Either
233                     .left(new NonMetaArtifactInfo(artifactFileNameType, artifactPath, artifactType, artifactGroupType, payloadData, null, true));
234             });
235         } catch (Exception e) {
236             log.debug("detectArtifactGroupType failed with exception", e);
237             return Either.right(false);
238         }
239     }
240
241     private static String detectArtifactTypeVFC(ArtifactGroupTypeEnum artifactGroupType, String receivedTypeName, String parentVfName,
242                                                 Map<String, Set<List<String>>> collectedWarningMessages) {
243         String warningMessage = "Warning - artifact type {} that was provided for VFC {} is not recognized.";
244         return detectArtifactType(artifactGroupType, receivedTypeName, warningMessage, collectedWarningMessages, parentVfName);
245     }
246
247     private static String detectArtifactTypeVF(ArtifactGroupTypeEnum artifactGroupType, String receivedTypeName,
248                                                Map<String, Set<List<String>>> collectedWarningMessages) {
249         String warningMessage = "Warning - artifact type {} that was provided for VF is not recognized.";
250         return detectArtifactType(artifactGroupType, receivedTypeName, warningMessage, collectedWarningMessages);
251     }
252
253     private static String detectArtifactType(final ArtifactGroupTypeEnum artifactGroupType, final String receivedTypeName,
254                                              final String warningMessage, final Map<String, Set<List<String>>> collectedWarningMessages,
255                                              final String... arguments) {
256         final ArtifactConfiguration artifactConfiguration = ArtifactConfigManager.getInstance()
257             .find(receivedTypeName, artifactGroupType, ComponentType.RESOURCE).orElse(null);
258         if (artifactConfiguration == null) {
259             final List<String> messageArguments = new ArrayList<>();
260             messageArguments.add(receivedTypeName);
261             messageArguments.addAll(Arrays.asList(arguments));
262             if (!collectedWarningMessages.containsKey(warningMessage)) {
263                 final Set<List<String>> messageArgumentLists = new HashSet<>();
264                 messageArgumentLists.add(messageArguments);
265                 collectedWarningMessages.put(warningMessage, messageArgumentLists);
266             } else {
267                 collectedWarningMessages.get(warningMessage).add(messageArguments);
268             }
269         }
270         return artifactConfiguration == null ? ArtifactTypeEnum.OTHER.getType() : receivedTypeName;
271     }
272
273     /**
274      * @param component
275      * @param getFromCS
276      * @param isInCertificationRequest
277      * @return
278      */
279     public Either<byte[], ResponseFormat> createCsar(final Component component, final boolean getFromCS, final boolean isInCertificationRequest) {
280         loggerSupportability
281             .log(LoggerSupportabilityActions.GENERATE_CSAR, StatusCode.STARTED, "Starting to create Csar for component {} ", component.getName());
282         final String toscaConformanceLevel = ConfigurationManager.getConfigurationManager().getConfiguration().getToscaConformanceLevel();
283         final byte[] csarBlock0Byte = createCsarBlock0(CSAR_META_VERSION, toscaConformanceLevel).getBytes();
284
285         return generateCsarZip(csarBlock0Byte,
286             isAsdPackage(component), component, getFromCS, isInCertificationRequest).left().map(responseFormat -> {
287             loggerSupportability
288                 .log(LoggerSupportabilityActions.GENERATE_CSAR, StatusCode.COMPLETE, "Ended create Csar for component {} ", component.getName());
289             return responseFormat;
290         });
291     }
292
293     private boolean isAsdPackage(final Component component) {
294         final Either<CsarDefinition, ResponseFormat> collectedComponentCsarDefinition = collectComponentCsarDefinition(component);
295         if (collectedComponentCsarDefinition.isLeft()) {
296             final ComponentArtifacts componentArtifacts = collectedComponentCsarDefinition.left().value().getComponentArtifacts();
297             if (componentArtifacts != null) {
298                 final ComponentTypeArtifacts mainTypeAndCIArtifacts = componentArtifacts.getMainTypeAndCIArtifacts();
299                 if (mainTypeAndCIArtifacts != null) {
300                     final ArtifactsInfo artifactsInfo = mainTypeAndCIArtifacts.getComponentArtifacts();
301                     if (artifactsInfo != null) {
302                         final Map<ArtifactGroupTypeEnum, Map<String, List<ArtifactDefinition>>> artifactsInfosMap = artifactsInfo.getArtifactsInfo();
303                         if (MapUtils.isNotEmpty(artifactsInfosMap) && artifactsInfosMap.containsKey(ArtifactGroupTypeEnum.DEPLOYMENT)) {
304                             return artifactsInfosMap.get(ArtifactGroupTypeEnum.DEPLOYMENT).containsKey(ArtifactTypeEnum.ASD_PACKAGE.getType());
305                         }
306                     }
307                 }
308             }
309         }
310         return false;
311     }
312
313     private Either<byte[], ResponseFormat> generateCsarZip(byte[] csarBlock0Byte,
314                                                            boolean isAsdPackage,
315                                                            Component component,
316                                                            boolean getFromCS,
317                                                            boolean isInCertificationRequest) {
318         try (final ByteArrayOutputStream out = new ByteArrayOutputStream(); ZipOutputStream zip = new ZipOutputStream(out)) {
319             zip.putNextEntry(new ZipEntry(CSAR_META_PATH_FILE_NAME));
320             zip.write(csarBlock0Byte);
321             Either<ZipOutputStream, ResponseFormat> populateZip = mapFromModelCsarGeneratorService.generateCsarZip(
322                 component, getFromCS, zip, isInCertificationRequest, isAsdPackage);
323             if (populateZip.isRight()) {
324                 log.debug("Failed to populate CSAR zip file {}. Please fix DB table accordingly ", populateZip.right().value());
325                 return Either.right(populateZip.right().value());
326             }
327             zip.finish();
328             return Either.left(out.toByteArray());
329         } catch (IOException e) {
330             log.debug("Failed with IOexception to create CSAR zip for component {}. Please fix DB table accordingly ", component.getUniqueId(), e);
331             ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR);
332             return Either.right(responseFormat);
333         }
334     }
335
336     private String createCsarBlock0(String metaFileVersion, String toscaConformanceLevel) {
337         return String.format(BLOCK_0_TEMPLATE, metaFileVersion, toscaConformanceLevel);
338     }
339
340     /************************************ Artifacts Structure END******************************************************************/
341
342     private Either<CsarDefinition, ResponseFormat> collectComponentCsarDefinition(Component component) {
343         ComponentArtifacts componentArtifacts = new ComponentArtifacts();
344         Component updatedComponent = component;
345
346         //get service to receive the AII artifacts uploaded to the service
347         if (updatedComponent.getComponentType() == ComponentTypeEnum.SERVICE) {
348             Either<Service, StorageOperationStatus> getServiceResponse = toscaOperationFacade.getToscaElement(updatedComponent.getUniqueId());
349
350             if (getServiceResponse.isRight()) {
351                 ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(getServiceResponse.right().value());
352                 return Either.right(componentsUtils.getResponseFormat(actionStatus));
353             }
354
355             updatedComponent = getServiceResponse.left().value();
356         }
357
358         //find the artifacts of the main component, it would have its composed instances artifacts in a separate folder
359         ComponentTypeArtifacts componentInstanceArtifacts = new ComponentTypeArtifacts();
360         ArtifactsInfo artifactsInfo = collectComponentArtifacts(updatedComponent);
361         componentInstanceArtifacts.setComponentArtifacts(artifactsInfo);
362         componentArtifacts.setMainTypeAndCIArtifacts(componentInstanceArtifacts);
363
364         Map<String, ComponentTypeArtifacts> resourceTypeArtifacts = componentArtifacts
365             .getComponentTypeArtifacts();    //artifacts mapped by the component type(tosca name+version)
366         //get the component instances
367         List<ComponentInstance> componentInstances = updatedComponent.getComponentInstances();
368         if (componentInstances != null) {
369             for (ComponentInstance componentInstance : componentInstances) {
370                 //call recursive to find artifacts for all the path
371                 Either<Boolean, ResponseFormat> collectComponentInstanceArtifacts = collectComponentInstanceArtifacts(
372                     updatedComponent, componentInstance, resourceTypeArtifacts, componentInstanceArtifacts);
373                 if (collectComponentInstanceArtifacts.isRight()) {
374                     return Either.right(collectComponentInstanceArtifacts.right().value());
375                 }
376             }
377         }
378
379         if (log.isDebugEnabled()) {
380             printResult(componentArtifacts, updatedComponent.getName());
381         }
382
383         return Either.left(new CsarDefinition(componentArtifacts));
384     }
385
386     private void printResult(ComponentArtifacts componentArtifacts, String name) {
387         StringBuilder result = new StringBuilder();
388         result.append("Artifacts of main component " + name + "\n");
389         ComponentTypeArtifacts componentInstanceArtifacts = componentArtifacts.getMainTypeAndCIArtifacts();
390         printArtifacts(componentInstanceArtifacts);
391         result.append("Type Artifacts\n");
392         for (Entry<String, ComponentTypeArtifacts> typeArtifacts : componentArtifacts.getComponentTypeArtifacts().entrySet()) {
393             result.append("Folder " + typeArtifacts.getKey() + "\n");
394             result.append(printArtifacts(typeArtifacts.getValue()));
395         }
396
397         if (log.isDebugEnabled()) {
398             log.debug(result.toString());
399         }
400     }
401
402     /************************************ Artifacts Structure ******************************************************************/
403
404     private String printArtifacts(ComponentTypeArtifacts componentInstanceArtifacts) {
405         StringBuilder result = new StringBuilder();
406         ArtifactsInfo artifactsInfo = componentInstanceArtifacts.getComponentArtifacts();
407         Map<ArtifactGroupTypeEnum, Map<String, List<ArtifactDefinition>>> componentArtifacts = artifactsInfo.getArtifactsInfo();
408         printArtifacts(componentArtifacts);
409         result = result.append("Resources\n");
410         for (Entry<String, ArtifactsInfo> resourceInstance : componentInstanceArtifacts.getComponentInstancesArtifacts().entrySet()) {
411             result.append("Folder" + resourceInstance.getKey() + "\n");
412             result.append(printArtifacts(resourceInstance.getValue().getArtifactsInfo()));
413         }
414
415         return result.toString();
416     }
417
418     private String printArtifacts(Map<ArtifactGroupTypeEnum, Map<String, List<ArtifactDefinition>>> componetArtifacts) {
419         StringBuilder result = new StringBuilder();
420         for (Entry<ArtifactGroupTypeEnum, Map<String, List<ArtifactDefinition>>> artifactGroup : componetArtifacts.entrySet()) {
421             result.append("    " + artifactGroup.getKey().getType());
422             for (Entry<String, List<ArtifactDefinition>> groupArtifacts : artifactGroup.getValue().entrySet()) {
423                 result.append("        " + groupArtifacts.getKey());
424                 for (ArtifactDefinition artifact : groupArtifacts.getValue()) {
425                     result.append("            " + artifact.getArtifactDisplayName());
426                 }
427             }
428         }
429
430         return result.toString();
431     }
432
433     private ComponentTypeArtifacts collectComponentTypeArtifacts(Component fetchedComponent) {
434         ArtifactsInfo componentArtifacts = collectComponentArtifacts(fetchedComponent);
435         ComponentTypeArtifacts componentArtifactsInfo = new ComponentTypeArtifacts();
436         if (componentArtifacts.isNotEmpty()) {
437             componentArtifactsInfo.setComponentArtifacts(componentArtifacts);
438         }
439         return componentArtifactsInfo;
440     }
441
442     private Either<Boolean, ResponseFormat> collectComponentInstanceArtifacts(Component parentComponent, ComponentInstance componentInstance,
443                                                                               Map<String, ComponentTypeArtifacts> resourcesTypeArtifacts,
444                                                                               ComponentTypeArtifacts instanceArtifactsLocation) {
445         //1. get the component instance component
446         String componentUid;
447         if (componentInstance.getOriginType() == OriginTypeEnum.ServiceProxy) {
448             componentUid = componentInstance.getSourceModelUid();
449         } else {
450             componentUid = componentInstance.getComponentUid();
451         }
452         Either<Component, StorageOperationStatus> component = toscaOperationFacade.getToscaElement(componentUid);
453         if (component.isRight()) {
454             log.error("Failed to fetch resource with id {} for instance {}", componentUid, parentComponent.getUUID());
455             return Either.right(componentsUtils.getResponseFormat(ActionStatus.ASSET_NOT_FOUND_DURING_CSAR_CREATION,
456                 parentComponent.getComponentType().getValue(), parentComponent.getUUID(),
457                 componentInstance.getOriginType().getComponentType().getValue(), componentUid));
458         }
459         Component fetchedComponent = component.left().value();
460
461         //2. fill the artifacts for the current component parent type
462         String toscaComponentName =
463             componentInstance.getToscaComponentName() + "_v" + componentInstance.getComponentVersion();
464
465         // if there are no artifacts for this component type we need to fetch and build them
466         ComponentTypeArtifacts componentParentArtifacts = Optional
467             .ofNullable(resourcesTypeArtifacts.get(toscaComponentName))
468             .orElseGet(() -> collectComponentTypeArtifacts(fetchedComponent));
469
470         if (componentParentArtifacts.getComponentArtifacts().isNotEmpty()) {
471             resourcesTypeArtifacts.put(toscaComponentName, componentParentArtifacts);
472         }
473
474         //3. find the artifacts specific to the instance
475         Map<String, List<ArtifactDefinition>> componentInstanceSpecificInformationalArtifacts =
476             getComponentInstanceSpecificArtifacts(componentInstance.getArtifacts(),
477                 componentParentArtifacts.getComponentArtifacts().getArtifactsInfo(), ArtifactGroupTypeEnum.INFORMATIONAL);
478         Map<String, List<ArtifactDefinition>> componentInstanceSpecificDeploymentArtifacts =
479             getComponentInstanceSpecificArtifacts(componentInstance.getDeploymentArtifacts(),
480                 componentParentArtifacts.getComponentArtifacts().getArtifactsInfo(), ArtifactGroupTypeEnum.DEPLOYMENT);
481
482         //4. add the instances artifacts to the component type
483         ArtifactsInfo artifactsInfo = new ArtifactsInfo();
484         if (!componentInstanceSpecificInformationalArtifacts.isEmpty()) {
485             artifactsInfo.addArtifactsToGroup(ArtifactGroupTypeEnum.INFORMATIONAL, componentInstanceSpecificInformationalArtifacts);
486         }
487         if (!componentInstanceSpecificDeploymentArtifacts.isEmpty()) {
488             artifactsInfo.addArtifactsToGroup(ArtifactGroupTypeEnum.DEPLOYMENT, componentInstanceSpecificDeploymentArtifacts);
489         }
490         if (!artifactsInfo.isEmpty()) {
491             instanceArtifactsLocation.addComponentInstancesArtifacts(componentInstance.getNormalizedName(), artifactsInfo);
492         }
493
494         //5. do the same for all the component instances
495         List<ComponentInstance> componentInstances = fetchedComponent.getComponentInstances();
496         if (componentInstances != null) {
497             for (ComponentInstance childComponentInstance : componentInstances) {
498                 Either<Boolean, ResponseFormat> collectComponentInstanceArtifacts = collectComponentInstanceArtifacts(
499                     fetchedComponent, childComponentInstance, resourcesTypeArtifacts, componentParentArtifacts);
500                 if (collectComponentInstanceArtifacts.isRight()) {
501                     return collectComponentInstanceArtifacts;
502                 }
503             }
504         }
505
506         return Either.left(true);
507     }
508
509     private Map<String, List<ArtifactDefinition>> getComponentInstanceSpecificArtifacts(Map<String, ArtifactDefinition> componentArtifacts,
510                                                                                         Map<ArtifactGroupTypeEnum, Map<String, List<ArtifactDefinition>>> componentTypeArtifacts,
511                                                                                         ArtifactGroupTypeEnum artifactGroupTypeEnum) {
512         Map<String, List<ArtifactDefinition>> parentArtifacts = componentTypeArtifacts
513             .get(artifactGroupTypeEnum);    //the artfiacts of the component itself and not the instance
514
515         Map<String, List<ArtifactDefinition>> artifactsByTypeOfComponentInstance = new HashMap<>();
516         if (componentArtifacts != null) {
517             for (ArtifactDefinition artifact : componentArtifacts.values()) {
518                 List<ArtifactDefinition> parentArtifactsByType = null;
519                 if (parentArtifacts != null) {
520                     parentArtifactsByType = parentArtifacts.get(artifact.getArtifactType());
521                 }
522                 //the artifact is of instance
523                 if (parentArtifactsByType == null || !parentArtifactsByType.contains(artifact)) {
524                     List<ArtifactDefinition> typeArtifacts = artifactsByTypeOfComponentInstance.get(artifact.getArtifactType());
525                     if (typeArtifacts == null) {
526                         typeArtifacts = new ArrayList<>();
527                         artifactsByTypeOfComponentInstance.put(artifact.getArtifactType(), typeArtifacts);
528                     }
529                     typeArtifacts.add(artifact);
530                 }
531             }
532         }
533
534         return artifactsByTypeOfComponentInstance;
535     }
536
537     private ArtifactsInfo collectComponentArtifacts(Component component) {
538         Map<String, ArtifactDefinition> informationalArtifacts = component.getArtifacts();
539         Map<String, List<ArtifactDefinition>> informationalArtifactsByType = collectGroupArtifacts(informationalArtifacts);
540         Map<String, ArtifactDefinition> deploymentArtifacts = component.getDeploymentArtifacts();
541         Map<String, List<ArtifactDefinition>> deploymentArtifactsByType = collectGroupArtifacts(deploymentArtifacts);
542         ArtifactsInfo artifactsInfo = new ArtifactsInfo();
543         if (!informationalArtifactsByType.isEmpty()) {
544             artifactsInfo.addArtifactsToGroup(ArtifactGroupTypeEnum.INFORMATIONAL, informationalArtifactsByType);
545         }
546         if (!deploymentArtifactsByType.isEmpty()) {
547             artifactsInfo.addArtifactsToGroup(ArtifactGroupTypeEnum.DEPLOYMENT, deploymentArtifactsByType);
548         }
549
550         return artifactsInfo;
551     }
552
553     private Map<String, List<ArtifactDefinition>> collectGroupArtifacts(
554         final Map<String, ArtifactDefinition> componentArtifacts) {
555         final Map<String, List<ArtifactDefinition>> artifactsByType = new HashMap<>();
556         for (final ArtifactDefinition artifact : componentArtifacts.values()) {
557             if (artifact.getArtifactUUID() != null) {
558                 artifactsByType.putIfAbsent(artifact.getArtifactType(), new ArrayList<>());
559                 final List<ArtifactDefinition> typeArtifacts = artifactsByType.get(artifact.getArtifactType());
560                 typeArtifacts.add(artifact);
561             }
562         }
563         return artifactsByType;
564     }
565
566
567     @Getter
568     public static final class NonMetaArtifactInfo {
569
570         private final String path;
571         private final String artifactName;
572         private final String displayName;
573         private final String artifactLabel;
574         private final String artifactType;
575         private final ArtifactGroupTypeEnum artifactGroupType;
576         private final String payloadData;
577         private final String artifactChecksum;
578         private final boolean isFromCsar;
579         @Setter
580         private String artifactUniqueId;
581
582         public NonMetaArtifactInfo(final String artifactName, final String path, final String artifactType,
583                                    final ArtifactGroupTypeEnum artifactGroupType, final byte[] payloadData, final String artifactUniqueId,
584                                    final boolean isFromCsar) {
585             this.path = path;
586             this.isFromCsar = isFromCsar;
587             this.artifactName = ValidationUtils.normalizeFileName(artifactName);
588             this.artifactType = artifactType;
589             this.artifactGroupType = artifactGroupType;
590             final int pointIndex = artifactName.lastIndexOf('.');
591             if (pointIndex > 0) {
592                 displayName = artifactName.substring(0, pointIndex);
593             } else {
594                 displayName = artifactName;
595             }
596             this.artifactLabel = ValidationUtils.normalizeArtifactLabel(artifactName);
597             if (payloadData == null) {
598                 this.payloadData = null;
599                 this.artifactChecksum = null;
600             } else {
601                 this.payloadData = Base64.encodeBase64String(payloadData);
602                 this.artifactChecksum = GeneralUtility.calculateMD5Base64EncodedByByteArray(payloadData);
603             }
604             this.artifactUniqueId = artifactUniqueId;
605         }
606     }
607
608     /**
609      * The artifacts Definition saved by their structure
610      */
611     private class ArtifactsInfo {
612         //Key is the type of artifacts(Informational/Deployment)
613
614         //Value is a map between an artifact type and a list of all artifacts of this type
615         private Map<ArtifactGroupTypeEnum, Map<String, List<ArtifactDefinition>>> artifactsInfoField;
616
617         public ArtifactsInfo() {
618             this.artifactsInfoField = new EnumMap<>(ArtifactGroupTypeEnum.class);
619         }
620
621         public Map<ArtifactGroupTypeEnum, Map<String, List<ArtifactDefinition>>> getArtifactsInfo() {
622             return artifactsInfoField;
623         }
624
625         public void addArtifactsToGroup(ArtifactGroupTypeEnum artifactGroup, Map<String, List<ArtifactDefinition>> artifactsDefinition) {
626             if (artifactsInfoField.get(artifactGroup) == null) {
627                 artifactsInfoField.put(artifactGroup, artifactsDefinition);
628             } else {
629                 Map<String, List<ArtifactDefinition>> artifactTypeEnumListMap = artifactsInfoField.get(artifactGroup);
630                 artifactTypeEnumListMap.putAll(artifactsDefinition);
631                 artifactsInfoField.put(artifactGroup, artifactTypeEnumListMap);
632             }
633         }
634
635         public boolean isEmpty() {
636             return artifactsInfoField.isEmpty();
637         }
638
639         public boolean isNotEmpty() {
640             return !isEmpty();
641         }
642     }
643
644     /**
645      * The artifacts of the component and of all its composed instances
646      */
647     private class ComponentTypeArtifacts {
648
649         private ArtifactsInfo componentArtifacts;    //component artifacts (describes the Informational Deployment folders)
650
651         private Map<String, ArtifactsInfo> componentInstancesArtifacts;        //artifacts of the composed instances mapped by the resourceInstance normalized name (describes the Resources folder)
652
653         public ComponentTypeArtifacts() {
654             componentArtifacts = new ArtifactsInfo();
655             componentInstancesArtifacts = new HashMap<>();
656         }
657
658         public ArtifactsInfo getComponentArtifacts() {
659             return componentArtifacts;
660         }
661
662         public void setComponentArtifacts(ArtifactsInfo artifactsInfo) {
663             this.componentArtifacts = artifactsInfo;
664         }
665
666         public Map<String, ArtifactsInfo> getComponentInstancesArtifacts() {
667             return componentInstancesArtifacts;
668         }
669
670         public void addComponentInstancesArtifacts(String normalizedName, ArtifactsInfo artifactsInfo) {
671             componentInstancesArtifacts.put(normalizedName, artifactsInfo);
672         }
673     }
674
675     private class ComponentArtifacts {
676
677         //artifacts of the component and CI's artifacts contained in it's composition (represents Informational, Deployment & Resource folders of main component)
678         private ComponentTypeArtifacts mainTypeAndCIArtifacts;
679         //artifacts of all component types mapped by their tosca name
680         private Map<String, ComponentTypeArtifacts> componentTypeArtifacts;
681
682         public ComponentArtifacts() {
683             mainTypeAndCIArtifacts = new ComponentTypeArtifacts();
684             componentTypeArtifacts = new HashMap<>();
685         }
686
687         public ComponentTypeArtifacts getMainTypeAndCIArtifacts() {
688             return mainTypeAndCIArtifacts;
689         }
690
691         public void setMainTypeAndCIArtifacts(ComponentTypeArtifacts componentInstanceArtifacts) {
692             this.mainTypeAndCIArtifacts = componentInstanceArtifacts;
693         }
694
695         public Map<String, ComponentTypeArtifacts> getComponentTypeArtifacts() {
696             return componentTypeArtifacts;
697         }
698     }
699
700     private class CsarDefinition {
701
702         private ComponentArtifacts componentArtifacts;
703
704         // add list of tosca artifacts and meta describes CSAR zip root
705         public CsarDefinition(ComponentArtifacts componentArtifacts) {
706             this.componentArtifacts = componentArtifacts;
707         }
708
709         public ComponentArtifacts getComponentArtifacts() {
710             return componentArtifacts;
711         }
712     }
713 }
714