2721fda2c506fc58b776d37a4f2a2e20d16cb124
[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
21 package org.openecomp.sdc.be.tosca;
22
23
24 import fj.data.Either;
25 import org.apache.commons.codec.binary.Base64;
26 import org.apache.commons.collections.MapUtils;
27 import org.apache.commons.io.output.ByteArrayOutputStream;
28 import org.apache.commons.lang.WordUtils;
29 import org.apache.commons.lang3.tuple.ImmutablePair;
30 import org.apache.commons.lang3.tuple.ImmutableTriple;
31 import org.apache.commons.lang3.tuple.Triple;
32 import org.openecomp.sdc.be.components.impl.ImportUtils;
33 import org.openecomp.sdc.be.config.Configuration.ArtifactTypeConfig;
34 import org.openecomp.sdc.be.config.ConfigurationManager;
35 import org.openecomp.sdc.be.dao.api.ActionStatus;
36 import org.openecomp.sdc.be.dao.cassandra.ArtifactCassandraDao;
37 import org.openecomp.sdc.be.dao.cassandra.CassandraOperationStatus;
38 import org.openecomp.sdc.be.dao.cassandra.SdcSchemaFilesCassandraDao;
39 import org.openecomp.sdc.be.datatypes.elements.OperationDataDefinition;
40 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
41 import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum;
42 import org.openecomp.sdc.be.impl.ComponentsUtils;
43 import org.openecomp.sdc.be.model.ArtifactDefinition;
44 import org.openecomp.sdc.be.model.Component;
45 import org.openecomp.sdc.be.model.ComponentInstance;
46 import org.openecomp.sdc.be.model.InterfaceDefinition;
47 import org.openecomp.sdc.be.model.LifecycleStateEnum;
48 import org.openecomp.sdc.be.model.Resource;
49 import org.openecomp.sdc.be.model.Service;
50 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ToscaOperationFacade;
51 import org.openecomp.sdc.be.model.jsonjanusgraph.utils.ModelConverter;
52 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
53 import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter;
54 import org.openecomp.sdc.be.plugins.CsarEntryGenerator;
55 import org.openecomp.sdc.be.resources.data.DAOArtifactData;
56 import org.openecomp.sdc.be.resources.data.SdcSchemaFilesData;
57 import org.openecomp.sdc.be.tosca.model.ToscaTemplate;
58 import org.openecomp.sdc.be.tosca.utils.OperationArtifactUtil;
59 import org.openecomp.sdc.be.utils.CommonBeUtils;
60 import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum;
61 import org.openecomp.sdc.common.api.ArtifactTypeEnum;
62 import org.openecomp.sdc.common.impl.ExternalConfiguration;
63 import org.openecomp.sdc.common.log.elements.LoggerSupportability;
64 import org.openecomp.sdc.common.log.enums.LoggerSupportabilityActions;
65 import org.openecomp.sdc.common.log.enums.StatusCode;
66 import org.openecomp.sdc.common.log.wrappers.Logger;
67 import org.openecomp.sdc.common.util.GeneralUtility;
68 import org.openecomp.sdc.common.util.ValidationUtils;
69 import org.openecomp.sdc.common.zip.ZipUtils;
70 import org.openecomp.sdc.exception.ResponseFormat;
71 import org.springframework.beans.factory.annotation.Autowired;
72
73 import java.io.BufferedOutputStream;
74 import java.io.ByteArrayInputStream;
75 import java.io.File;
76 import java.io.IOException;
77 import java.util.ArrayList;
78 import java.util.Arrays;
79 import java.util.EnumMap;
80 import java.util.HashMap;
81 import java.util.HashSet;
82 import java.util.List;
83 import java.util.Map;
84 import java.util.Map.Entry;
85 import java.util.Objects;
86 import java.util.Set;
87 import java.util.regex.Matcher;
88 import java.util.regex.Pattern;
89 import java.util.zip.ZipEntry;
90 import java.util.zip.ZipInputStream;
91 import java.util.zip.ZipOutputStream;
92
93 /**
94  * @author tg851x
95  *
96  */
97 @org.springframework.stereotype.Component("csar-utils")
98 public class CsarUtils {
99     private static final Logger log = Logger.getLogger(CsarUtils.class);
100     private static final LoggerSupportability loggerSupportability = LoggerSupportability.getLogger(CsarUtils.class.getName());
101     private static final String PATH_DELIMITER = "/";
102     @Autowired
103     private SdcSchemaFilesCassandraDao sdcSchemaFilesCassandraDao;
104     @Autowired
105     private ArtifactCassandraDao artifactCassandraDao;
106     @Autowired
107     private ComponentsUtils componentsUtils;
108     @Autowired
109     private ToscaExportHandler toscaExportUtils;
110     @Autowired
111     protected ToscaOperationFacade toscaOperationFacade;
112   
113     @Autowired(required = false)
114     private List<CsarEntryGenerator> generators;
115
116     private static final String CONFORMANCE_LEVEL = ConfigurationManager.getConfigurationManager().getConfiguration().getToscaConformanceLevel();
117     private static final String SDC_VERSION = ExternalConfiguration.getAppVersion();
118     public static final String ARTIFACTS_PATH = "Artifacts/";
119     private static final String RESOURCES_PATH = "Resources/";
120     private static final String DEFINITIONS_PATH = "Definitions/";
121     public static final String WORKFLOW_ARTIFACT_DIR = "Workflows"+File.separator+"BPMN"+File.separator;
122     public static final String DEPLOYMENT_ARTIFACTS_DIR = "Deployment"+File.separator;
123     private static final String CSAR_META_VERSION = "1.0";
124     private static final String CSAR_META_PATH_FILE_NAME = "csar.meta";
125     private static final String TOSCA_META_PATH_FILE_NAME = "TOSCA-Metadata/TOSCA.meta";
126     private static final String TOSCA_META_VERSION = "1.0";
127     private static final String CSAR_VERSION = "1.1";
128     public static final String ARTIFACTS = "Artifacts";
129     private static final String DEFINITION = "Definitions";
130     private static final String DEL_PATTERN = "([/\\\\]+)";
131     private static final String WORD_PATTERN = "\\w\\_\\-\\.\\s]+)";
132     public static final String VALID_ENGLISH_ARTIFACT_NAME = "([" + WORD_PATTERN;
133     private static final String VALID_ENGLISH_ARTIFACT_NAME_WITH_DIGITS = "([\\d" + WORD_PATTERN;
134     private static final String ARTIFACT_NAME_UNIQUE_ID = "ArtifactName {}, unique ID {}";
135
136     private static final String VFC_NODE_TYPE_ARTIFACTS_PATH_PATTERN = ARTIFACTS + DEL_PATTERN +
137                                                                               ImportUtils.Constants.USER_DEFINED_RESOURCE_NAMESPACE_PREFIX +
138                                                                               VALID_ENGLISH_ARTIFACT_NAME_WITH_DIGITS + DEL_PATTERN +
139                                                                               VALID_ENGLISH_ARTIFACT_NAME_WITH_DIGITS + DEL_PATTERN +
140                                                                               VALID_ENGLISH_ARTIFACT_NAME_WITH_DIGITS + DEL_PATTERN +
141                                                                               VALID_ENGLISH_ARTIFACT_NAME_WITH_DIGITS;
142
143     public static final String VF_NODE_TYPE_ARTIFACTS_PATH_PATTERN = ARTIFACTS + DEL_PATTERN+
144                                                                              // Artifact Group (i.e Deployment/Informational)
145                                                                              VALID_ENGLISH_ARTIFACT_NAME + DEL_PATTERN +
146                                                                              // Artifact Type
147                                                                              VALID_ENGLISH_ARTIFACT_NAME  + DEL_PATTERN +
148                                                                              // Artifact Any File Name
149                                                                              ".+";
150
151     public static final String SERVICE_TEMPLATE_PATH_PATTERN = DEFINITION + DEL_PATTERN+
152                                                                        // Service Template File Name
153                                                                        VALID_ENGLISH_ARTIFACT_NAME;
154
155     public static final String ARTIFACT_CREATED_FROM_CSAR = "Artifact created from csar";
156     private static final String BLOCK_0_TEMPLATE = "SDC-TOSCA-Meta-File-Version: %s\nSDC-TOSCA-Definitions-Version: %s\n";
157
158     private String versionFirstThreeOctets;
159
160     public CsarUtils() {
161         if(SDC_VERSION != null && !SDC_VERSION.isEmpty()){
162             Matcher matcher = Pattern.compile("(?!\\.)(\\d+(\\.\\d+)+)(?![\\d\\.])").matcher(SDC_VERSION);
163             matcher.find();
164             setVersionFirstThreeOctets(matcher.group(0));
165         } else {
166             setVersionFirstThreeOctets("");
167         }
168     }
169
170     /**
171      *
172      * @param component
173      * @param getFromCS
174      * @param isInCertificationRequest
175      * @return
176      */
177     public Either<byte[], ResponseFormat> createCsar(Component component, boolean getFromCS, boolean isInCertificationRequest) {
178         loggerSupportability.log(LoggerSupportabilityActions.GENERATE_CSAR, StatusCode.STARTED,"Starting to create Csar for component {} ",component.getName());
179         final String createdBy = component.getCreatorFullName();
180         String fileName;
181         Map<String, ArtifactDefinition> toscaArtifacts = component.getToscaArtifacts();
182         ArtifactDefinition artifactDefinition = toscaArtifacts.get(ToscaExportHandler.ASSET_TOSCA_TEMPLATE);
183         fileName = artifactDefinition.getArtifactName();
184
185         String toscaConformanceLevel = ConfigurationManager.getConfigurationManager().getConfiguration().getToscaConformanceLevel();
186         String csarBlock0 = createCsarBlock0(CSAR_META_VERSION, toscaConformanceLevel);
187         byte[] csarBlock0Byte = csarBlock0.getBytes();
188
189         final String toscaBlock0 = createToscaBlock0(TOSCA_META_VERSION, CSAR_VERSION, createdBy, fileName);
190         byte[] toscaBlock0Byte = toscaBlock0.getBytes();
191
192         Either<byte[], ResponseFormat> generateCsarZipResponse = generateCsarZip(csarBlock0Byte, toscaBlock0Byte, component, getFromCS, isInCertificationRequest);
193
194         if (generateCsarZipResponse.isRight()) {
195             return Either.right(generateCsarZipResponse.right().value());
196         }
197         loggerSupportability.log(LoggerSupportabilityActions.GENERATE_CSAR, StatusCode.COMPLETE,"Ended create Csar for component {} ",component.getName());
198         return Either.left(generateCsarZipResponse.left().value());
199     }
200
201     private Either<byte[], ResponseFormat> generateCsarZip(byte[] csarBlock0Byte, byte[] toscaBlock0Byte, Component component, boolean getFromCS, boolean isInCertificationRequest) {
202         try (ByteArrayOutputStream out = new ByteArrayOutputStream();
203              ZipOutputStream zip = new ZipOutputStream(out)) {
204             zip.putNextEntry(new ZipEntry(CSAR_META_PATH_FILE_NAME));
205             zip.write(csarBlock0Byte);
206             zip.putNextEntry(new ZipEntry(TOSCA_META_PATH_FILE_NAME));
207             zip.write(toscaBlock0Byte);
208             Either<ZipOutputStream, ResponseFormat> populateZip = populateZip(component, getFromCS, zip, isInCertificationRequest);
209             if (populateZip.isRight()) {
210                 log.debug("Failed to populate CSAR zip file {}. Please fix DB table accordingly ", populateZip.right().value());
211                 return Either.right(populateZip.right().value());
212             }
213
214             zip.finish();
215             byte[] byteArray = out.toByteArray();
216
217             return Either.left(byteArray);
218         } catch (IOException e) {
219             log.debug("Failed with IOexception to create CSAR zip for component {}. Please fix DB table accordingly ", component.getUniqueId(), e);
220
221             ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR);
222             return Either.right(responseFormat);
223         }
224 }
225
226     private Either<ZipOutputStream, ResponseFormat> populateZip(Component component, boolean getFromCS, ZipOutputStream zip, boolean isInCertificationRequest) throws IOException {
227
228         LifecycleStateEnum lifecycleState = component.getLifecycleState();
229         String componentYaml;
230         Either<ToscaRepresentation, ToscaError> exportComponent;
231         byte[] mainYaml;
232         // <file name, cassandraId, component>
233         List<Triple<String, String, Component>> dependencies = null;
234
235         Map<String, ArtifactDefinition> toscaArtifacts = component.getToscaArtifacts();
236         ArtifactDefinition artifactDefinition = toscaArtifacts.get(ToscaExportHandler.ASSET_TOSCA_TEMPLATE);
237         String fileName = artifactDefinition.getArtifactName();
238
239         if (getFromCS || !(lifecycleState == LifecycleStateEnum.NOT_CERTIFIED_CHECKIN || lifecycleState == LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT)) {
240             String cassandraId = artifactDefinition.getEsId();
241             Either<byte[], ActionStatus> fromCassandra = getFromCassandra(cassandraId);
242             if (fromCassandra.isRight()) {
243                 log.debug(ARTIFACT_NAME_UNIQUE_ID, artifactDefinition.getArtifactName(), artifactDefinition.getUniqueId());
244                 ResponseFormat responseFormat = componentsUtils.getResponseFormat(fromCassandra.right().value());
245                 return Either.right(responseFormat);
246             }
247             mainYaml = fromCassandra.left().value();
248
249         } else {
250             exportComponent = toscaExportUtils.exportComponent(component);
251             if (exportComponent.isRight()) {
252                 log.debug("exportComponent failed", exportComponent.right().value());
253                 ActionStatus convertedFromToscaError = componentsUtils.convertFromToscaError(exportComponent.right().value());
254                 ResponseFormat responseFormat = componentsUtils.getResponseFormat(convertedFromToscaError);
255                 return Either.right(responseFormat);
256             }
257             ToscaRepresentation exportResult = exportComponent.left().value();
258             componentYaml = exportResult.getMainYaml();
259             mainYaml = componentYaml.getBytes();
260             dependencies = exportResult.getDependencies();
261         }
262
263         zip.putNextEntry(new ZipEntry(DEFINITIONS_PATH + fileName));
264         zip.write(mainYaml);
265         //US798487 - Abstraction of complex types
266         if (!ModelConverter.isAtomicComponent(component)){
267             log.debug("Component {} is complex - generating abstract type for it..", component.getName());
268                         writeComponentInterface(component, zip, fileName, false);
269         }
270
271         if (dependencies == null) {
272             Either<ToscaTemplate, ToscaError> dependenciesRes = toscaExportUtils.getDependencies(component);
273             if (dependenciesRes.isRight()) {
274                 log.debug("Failed to retrieve dependencies for component {}, error {}", component.getUniqueId(),
275                         dependenciesRes.right().value());
276                 ActionStatus convertFromToscaError = componentsUtils.convertFromToscaError(dependenciesRes.right().value());
277                 ResponseFormat responseFormat = componentsUtils.getResponseFormat(convertFromToscaError);
278                 return Either.right(responseFormat);
279             }
280             dependencies = dependenciesRes.left().value().getDependencies();
281         }
282
283         //UID <cassandraId,filename,component>
284         Map<String, ImmutableTriple<String,String, Component>> innerComponentsCache = new HashMap<>();
285
286         Either<ZipOutputStream, ResponseFormat> responseFormat = getZipOutputStreamResponseFormatEither(zip, dependencies, innerComponentsCache);
287         if (responseFormat != null) return responseFormat;
288
289         //retrieve SDC.zip from Cassandra
290         Either<byte[], ResponseFormat> latestSchemaFilesFromCassandra = getLatestSchemaFilesFromCassandra();
291
292         if(latestSchemaFilesFromCassandra.isRight()){
293             log.error("Error retrieving SDC Schema files from cassandra" );
294             return Either.right(latestSchemaFilesFromCassandra.right().value());
295         }
296
297         //add files from retrieved SDC.zip to Definitions folder in CSAR
298         Either<ZipOutputStream, ResponseFormat> addSchemaFilesFromCassandra = addSchemaFilesFromCassandra(zip, latestSchemaFilesFromCassandra.left().value());
299
300         if(addSchemaFilesFromCassandra.isRight()){
301             return addSchemaFilesFromCassandra;
302         }
303
304         Either<CsarDefinition, ResponseFormat> collectedComponentCsarDefinition = collectComponentCsarDefinition(component);
305
306         if (collectedComponentCsarDefinition.isRight()) {
307             return Either.right(collectedComponentCsarDefinition.right().value());
308         }
309
310         if (generators != null) {
311                 for (CsarEntryGenerator generator: generators) {
312                     log.debug("Invoking CsarEntryGenerator: {}", generator.getClass().getName());
313                         for (Entry<String, byte[]> pluginGeneratedFile : generator.generateCsarEntries(component).entrySet()) {
314                                 zip.putNextEntry(new ZipEntry(pluginGeneratedFile.getKey()));
315                             zip.write(pluginGeneratedFile.getValue());
316                         }
317                 }
318         }
319
320         return writeAllFilesToCsar(component, collectedComponentCsarDefinition.left().value(), zip, isInCertificationRequest);
321     }
322
323     private Either<ZipOutputStream, ResponseFormat> getZipOutputStreamResponseFormatEither(ZipOutputStream zip, List<Triple<String, String, Component>> dependencies, Map<String, ImmutableTriple<String, String, Component>> innerComponentsCache) throws IOException {
324         String fileName;
325         if (dependencies != null && !dependencies.isEmpty()) {
326             for (Triple<String, String, Component> d : dependencies) {
327                 String cassandraId = d.getMiddle();
328                 Component childComponent = d.getRight();
329                 Either<byte[], ActionStatus> entryData = getEntryData(cassandraId, childComponent);
330
331                 if (entryData.isRight()) {
332                     ResponseFormat responseFormat = componentsUtils.getResponseFormat(entryData.right().value());
333                     return Either.right(responseFormat);
334                 }
335
336                 //fill innerComponentsCache
337                 fileName = d.getLeft();
338                 addComponentToCache(innerComponentsCache, cassandraId, fileName, childComponent);
339                 addInnerComponentsToCache(innerComponentsCache, childComponent);
340             }
341
342             //add inner components to CSAR
343             Either<ZipOutputStream, ResponseFormat> responseFormat = addInnerComponentsToCSAR(zip, innerComponentsCache);
344             if (responseFormat != null) return responseFormat;
345         }
346         return null;
347     }
348
349     private Either<ZipOutputStream, ResponseFormat> addInnerComponentsToCSAR(ZipOutputStream zip, Map<String, ImmutableTriple<String, String, Component>> innerComponentsCache) throws IOException {
350         for (Entry<String, ImmutableTriple<String, String, Component>> innerComponentTripleEntry : innerComponentsCache.entrySet()) {
351
352             ImmutableTriple<String, String, Component> innerComponentTriple = innerComponentTripleEntry.getValue();
353
354             Component innerComponent = innerComponentTriple.getRight();
355             String icFileName = innerComponentTriple.getMiddle();
356
357             // add component to zip
358             Either<byte[], ActionStatus> entryData = getEntryData(innerComponentTriple.getLeft(), innerComponent);
359             if (entryData.isRight()) {
360                 ResponseFormat responseFormat = componentsUtils.getResponseFormat(entryData.right().value());
361                 log.debug("Failed adding to zip component {}, error {}", innerComponentTriple.getLeft(),
362                         entryData.right().value());
363                 return Either.right(responseFormat);
364             }
365             byte[] content = entryData.left().value();
366             zip.putNextEntry(new ZipEntry(DEFINITIONS_PATH + icFileName));
367             zip.write(content);
368
369             // add component interface to zip
370             if (!ModelConverter.isAtomicComponent(innerComponent)) {
371                                         writeComponentInterface(innerComponent, zip, icFileName, true);
372             }
373         }
374         return null;
375     }
376
377     private Either<ZipOutputStream, ResponseFormat> addSchemaFilesFromCassandra(ZipOutputStream zip, byte[] schemaFileZip) {
378
379             final int initSize = 2048;
380
381             log.debug("Starting copy from Schema file zip to CSAR zip");
382             try (final ZipInputStream zipStream = new ZipInputStream(new ByteArrayInputStream(schemaFileZip));
383                  final ByteArrayOutputStream out = new ByteArrayOutputStream();
384                  final BufferedOutputStream bos = new BufferedOutputStream(out, initSize)) {
385
386                 ZipEntry entry;
387                 while ((entry = zipStream.getNextEntry()) != null) {
388                     ZipUtils.checkForZipSlipInRead(entry);
389                     final String entryName = entry.getName();
390                     int readSize = initSize;
391                     final byte[] entryData = new byte[initSize];
392
393                     while ((readSize = zipStream.read(entryData, 0, readSize)) != -1) {
394                         bos.write(entryData, 0, readSize);
395                     }
396
397                     bos.flush();
398                     out.flush();
399                     zip.putNextEntry(new ZipEntry(DEFINITIONS_PATH + entryName));
400                     zip.write(out.toByteArray());
401                     zip.flush();
402                     out.reset();
403                 }
404             } catch (final Exception e) {
405                 log.error("Error while writing the SDC schema file to the CSAR", e);
406                 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
407             }
408
409             log.debug("Finished coppy from Schema file zip to CSAR zip");
410             return Either.left(zip);
411         }
412
413
414
415     private void addInnerComponentsToCache(Map<String, ImmutableTriple<String, String, Component>> componentCache,
416             Component childComponent) {
417
418         List<ComponentInstance> instances = childComponent.getComponentInstances();
419
420         if(instances != null) {
421             instances.forEach(ci -> {
422                 ImmutableTriple<String, String, Component> componentRecord = componentCache.get(ci.getComponentUid());
423                 if (componentRecord == null) {
424                     // all resource must be only once!
425                     Either<Resource, StorageOperationStatus> resource = toscaOperationFacade.getToscaElement(ci.getComponentUid());
426                     Component componentRI = checkAndAddComponent(componentCache, ci, resource);
427
428                     //if not atomic - insert inner components as well
429                     if(!ModelConverter.isAtomicComponent(componentRI)) {
430                         addInnerComponentsToCache(componentCache, componentRI);
431                     }
432                 }
433             });
434         }
435     }
436
437     private Component checkAndAddComponent(Map<String, ImmutableTriple<String, String, Component>> componentCache, ComponentInstance ci, Either<Resource, StorageOperationStatus> resource) {
438         if (resource.isRight()) {
439             log.debug("Failed to fetch resource with id {} for instance {}", ci.getComponentUid(), ci.getName());
440         }
441         Component componentRI = resource.left().value();
442
443         Map<String, ArtifactDefinition> childToscaArtifacts = componentRI.getToscaArtifacts();
444         ArtifactDefinition childArtifactDefinition = childToscaArtifacts.get(ToscaExportHandler.ASSET_TOSCA_TEMPLATE);
445         if (childArtifactDefinition != null) {
446             //add to cache
447             addComponentToCache(componentCache, childArtifactDefinition.getEsId(), childArtifactDefinition.getArtifactName(), componentRI);
448         }
449         return componentRI;
450     }
451
452     private void addComponentToCache(Map<String, ImmutableTriple<String, String, Component>> componentCache,
453             String id, String fileName, Component component) {
454
455         ImmutableTriple<String, String, Component> cachedComponent = componentCache.get(component.getInvariantUUID());
456         if (cachedComponent == null || CommonBeUtils.compareAsdcComponentVersions(component.getVersion(), cachedComponent.getRight().getVersion())) {
457             componentCache.put(component.getInvariantUUID(),
458                     new ImmutableTriple<>(id, fileName, component));
459
460             if(cachedComponent != null) {
461                 //overwriting component with newer version
462                 log.warn("Overwriting component invariantID {} of version {} with a newer version {}", id, cachedComponent.getRight().getVersion(), component.getVersion());
463             }
464         }
465     }
466         private Either<ZipOutputStream, ResponseFormat> writeComponentInterface(Component component, ZipOutputStream zip,
467                         String fileName, boolean isAssociatedComponent) {
468                 try {
469                         Either<ToscaRepresentation, ToscaError> componentInterface = toscaExportUtils
470                                         .exportComponentInterface(component, isAssociatedComponent);
471                         ToscaRepresentation componentInterfaceYaml = componentInterface.left().value();
472                         String mainYaml = componentInterfaceYaml.getMainYaml();
473                         String interfaceFileName = DEFINITIONS_PATH + ToscaExportHandler.getInterfaceFilename(fileName);
474
475                         zip.putNextEntry(new ZipEntry(interfaceFileName));
476                         zip.write(mainYaml.getBytes());
477
478                 } catch (Exception e) {
479                         log.error("#writeComponentInterface - zip writing failed with error: ", e);
480                         return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
481                 }
482
483                 return Either.left(zip);
484         }
485
486         private Either<byte[], ActionStatus> getEntryData(String cassandraId, Component childComponent) {
487                 byte[] content;
488                 if (cassandraId == null || cassandraId.isEmpty()) {
489                         Either<ToscaRepresentation, ToscaError> exportRes = toscaExportUtils.exportComponent(childComponent);
490                         if (exportRes.isRight()) {
491                                 log.debug("Failed to export tosca template for child component {} error {}",
492                                                 childComponent.getUniqueId(), exportRes.right().value());
493                                 return Either.right(componentsUtils.convertFromToscaError(exportRes.right().value()));
494                         }
495                         content = exportRes.left().value().getMainYaml().getBytes();
496                 } else {
497                         Either<byte[], ActionStatus> fromCassandra = getFromCassandra(cassandraId);
498                         if (fromCassandra.isRight()) {
499                                 return Either.right(fromCassandra.right().value());
500                         } else {
501                                 content = fromCassandra.left().value();
502                         }
503                 }
504                 return Either.left(content);
505         }
506
507     private Either<byte[], ResponseFormat> getLatestSchemaFilesFromCassandra() {
508         Either<List<SdcSchemaFilesData>, CassandraOperationStatus> specificSchemaFiles = sdcSchemaFilesCassandraDao.getSpecificSchemaFiles(getVersionFirstThreeOctets(), CONFORMANCE_LEVEL);
509
510         if(specificSchemaFiles.isRight()){
511             log.debug("Failed to get the schema files SDC-Version: {} Conformance-Level {}. Please fix DB table accordingly.", getVersionFirstThreeOctets(), CONFORMANCE_LEVEL);
512             StorageOperationStatus storageStatus = DaoStatusConverter.convertCassandraStatusToStorageStatus(specificSchemaFiles.right().value());
513             ActionStatus convertedFromStorageResponse = componentsUtils.convertFromStorageResponse(storageStatus);
514             return Either.right(componentsUtils.getResponseFormat(convertedFromStorageResponse));
515         }
516
517         List<SdcSchemaFilesData> listOfSchemas = specificSchemaFiles.left().value();
518
519         if(listOfSchemas.isEmpty()){
520             log.debug("Failed to get the schema files SDC-Version: {} Conformance-Level {}", getVersionFirstThreeOctets(), CONFORMANCE_LEVEL);
521             return Either.right(componentsUtils.getResponseFormat(ActionStatus.TOSCA_SCHEMA_FILES_NOT_FOUND, getVersionFirstThreeOctets(), CONFORMANCE_LEVEL));
522         }
523
524         SdcSchemaFilesData schemaFile = listOfSchemas.iterator().next();
525
526         return Either.left(schemaFile.getPayloadAsArray());
527     }
528
529     private Either<byte[], ActionStatus> getFromCassandra(String cassandraId) {
530         Either<DAOArtifactData, CassandraOperationStatus> artifactResponse = artifactCassandraDao.getArtifact(cassandraId);
531
532         if (artifactResponse.isRight()) {
533             log.debug("Failed to fetch artifact from Cassandra by id {} error {} ", cassandraId, artifactResponse.right().value());
534
535             StorageOperationStatus storageStatus = DaoStatusConverter.convertCassandraStatusToStorageStatus(artifactResponse.right().value());
536             ActionStatus convertedFromStorageResponse = componentsUtils.convertFromStorageResponse(storageStatus);
537             return Either.right(convertedFromStorageResponse);
538         }
539         DAOArtifactData artifactData = artifactResponse.left().value();
540         return Either.left(artifactData.getDataAsArray());
541     }
542
543     private String createCsarBlock0(String metaFileVersion, String toscaConformanceLevel) {
544         return String.format(BLOCK_0_TEMPLATE, metaFileVersion, toscaConformanceLevel);
545     }
546
547     private String createToscaBlock0(String metaFileVersion, String csarVersion, String createdBy, String entryDef) {
548         final String block0template = "TOSCA-Meta-File-Version: %s\nCSAR-Version: %s\nCreated-By: %s\nEntry-Definitions: Definitions/%s\n\nName: csar.meta\nContent-Type: text/plain\n";
549         return String.format(block0template, metaFileVersion, csarVersion, createdBy, entryDef);
550     }
551
552     /**
553      * Extracts artifacts of VFCs from CSAR
554      *
555      * @param csar
556      * @return Map of <String, List<ArtifactDefinition>> the contains Lists of artifacts according vfcToscaNamespace
557      */
558     public static Map<String, List<ArtifactDefinition>> extractVfcsArtifactsFromCsar(Map<String, byte[]> csar) {
559
560         Map<String, List<ArtifactDefinition>> artifacts = new HashMap<>();
561         if (csar != null) {
562             log.debug("************* Going to extract VFCs artifacts from Csar. ");
563             Map<String, Set<List<String>>> collectedWarningMessages = new HashMap<>();
564             csar.entrySet().stream()
565                 // filter CSAR entry by node type artifact path
566                 .filter(e -> Pattern.compile(VFC_NODE_TYPE_ARTIFACTS_PATH_PATTERN).matcher(e.getKey()).matches())
567                 // extract ArtifactDefinition from CSAR entry for each entry with matching artifact path
568                 .forEach(e -> addExtractedVfcArtifact(extractVfcArtifact(e, collectedWarningMessages), artifacts));
569             // add counter suffix to artifact labels
570             handleWarningMessages(collectedWarningMessages);
571
572         }
573         return artifacts;
574     }
575
576     /**
577      * Print warnings to log
578      *
579      * @param collectedWarningMessages
580      */
581     public static void handleWarningMessages(Map<String, Set<List<String>>> collectedWarningMessages) {
582         collectedWarningMessages.entrySet().stream()
583                                 // for each vfc
584                                 .forEach(e -> e.getValue().stream()
585                                                // add each warning message to log
586                                                .forEach(args -> log.warn(e.getKey(), args.toArray())));
587
588     }
589
590     private static void addExtractedVfcArtifact(ImmutablePair<String, ArtifactDefinition> extractedVfcArtifact, Map<String, List<ArtifactDefinition>> artifacts) {
591         if (extractedVfcArtifact != null) {
592             List<ArtifactDefinition> currArtifactsList;
593             String vfcToscaNamespace = extractedVfcArtifact.getKey();
594             if (artifacts.containsKey(vfcToscaNamespace)) {
595                 currArtifactsList = artifacts.get(vfcToscaNamespace);
596             } else {
597                 currArtifactsList = new ArrayList<>();
598                 artifacts.put(vfcToscaNamespace, currArtifactsList);
599             }
600             currArtifactsList.add(extractedVfcArtifact.getValue());
601         }
602     }
603
604     private static ImmutablePair<String, ArtifactDefinition> extractVfcArtifact(Entry<String, byte[]> entry, Map<String, Set<List<String>>> collectedWarningMessages) {
605         ArtifactDefinition artifact;
606         String[] parsedCsarArtifactPath = entry.getKey().split(PATH_DELIMITER);
607         Either<ArtifactGroupTypeEnum, Boolean> eitherArtifactGroupType = detectArtifactGroupType(parsedCsarArtifactPath[2].toUpperCase(), collectedWarningMessages);
608         if (eitherArtifactGroupType.isLeft()) {
609             artifact = buildArtifactDefinitionFromCsarArtifactPath(entry, collectedWarningMessages, parsedCsarArtifactPath, eitherArtifactGroupType.left().value());
610         } else {
611             return null;
612         }
613         return new ImmutablePair<>(parsedCsarArtifactPath[1], artifact);
614     }
615
616     private static Either<ArtifactGroupTypeEnum, Boolean> detectArtifactGroupType(String groupType, Map<String, Set<List<String>>> collectedWarningMessages) {
617         Either<ArtifactGroupTypeEnum, Boolean> result;
618         try {
619             ArtifactGroupTypeEnum artifactGroupType = ArtifactGroupTypeEnum.findType(groupType.toUpperCase());
620             if (artifactGroupType == null || (artifactGroupType != ArtifactGroupTypeEnum.INFORMATIONAL && artifactGroupType != ArtifactGroupTypeEnum.DEPLOYMENT)) {
621                 String warningMessage = "Warning - unrecognized artifact group type {} was received.";
622                 List<String> messageArguments = new ArrayList<>();
623                 messageArguments.add(groupType);
624                 if (!collectedWarningMessages.containsKey(warningMessage)) {
625                     Set<List<String>> messageArgumentLists = new HashSet<>();
626                     messageArgumentLists.add(messageArguments);
627                     collectedWarningMessages.put(warningMessage, messageArgumentLists);
628                 } else {
629                     collectedWarningMessages.get(warningMessage).add(messageArguments);
630                 }
631
632                 result = Either.right(false);
633             } else {
634
635                 result = Either.left(artifactGroupType);
636             }
637         } catch (Exception e) {
638             log.debug("detectArtifactGroupType failed with exception", e);
639             result = Either.right(false);
640         }
641         return result;
642     }
643
644     private static ArtifactDefinition buildArtifactDefinitionFromCsarArtifactPath(Entry<String, byte[]> entry, Map<String, Set<List<String>>> collectedWarningMessages, String[] parsedCsarArtifactPath, ArtifactGroupTypeEnum artifactGroupType) {
645         ArtifactDefinition artifact;
646         artifact = new ArtifactDefinition();
647         artifact.setArtifactGroupType(artifactGroupType);
648         artifact.setArtifactType(detectArtifactTypeVFC(artifactGroupType, parsedCsarArtifactPath[3], parsedCsarArtifactPath[1], collectedWarningMessages));
649         artifact.setArtifactName(ValidationUtils.normalizeFileName(parsedCsarArtifactPath[parsedCsarArtifactPath.length - 1]));
650         artifact.setPayloadData(Base64.encodeBase64String(entry.getValue()));
651         artifact.setArtifactDisplayName(artifact.getArtifactName().lastIndexOf('.') > 0 ? artifact.getArtifactName().substring(0, artifact.getArtifactName().lastIndexOf('.')) : artifact.getArtifactName());
652         artifact.setArtifactLabel(ValidationUtils.normalizeArtifactLabel(artifact.getArtifactName()));
653         artifact.setDescription(ARTIFACT_CREATED_FROM_CSAR);
654         artifact.setIsFromCsar(true);
655         artifact.setArtifactChecksum(GeneralUtility.calculateMD5Base64EncodedByByteArray(entry.getValue()));
656         return artifact;
657     }
658
659     public static final class NonMetaArtifactInfo {
660         private final String path;
661         private final String artifactName;
662         private final String displayName;
663         private final String artifactLabel;
664         private final ArtifactTypeEnum artifactType;
665         private final ArtifactGroupTypeEnum artifactGroupType;
666         private String payloadData;
667         private String artifactChecksum;
668         private String artifactUniqueId;
669         private final boolean isFromCsar;
670
671         public NonMetaArtifactInfo(String artifactName, String path, ArtifactTypeEnum artifactType, ArtifactGroupTypeEnum artifactGroupType, byte[] payloadData, String artifactUniqueId, boolean isFromCsar) {
672             super();
673             this.path = path;
674             this.isFromCsar = isFromCsar;
675             this.artifactName = ValidationUtils.normalizeFileName(artifactName);
676             this.artifactType = artifactType;
677             this.artifactGroupType = artifactGroupType;
678             final int pointIndex = artifactName.lastIndexOf('.');
679             if (pointIndex > 0) {
680                 displayName = artifactName.substring(0, pointIndex);
681             } else {
682                 displayName = artifactName;
683             }
684             this.artifactLabel = ValidationUtils.normalizeArtifactLabel(artifactName);
685             if (payloadData != null) {
686                 this.payloadData = Base64.encodeBase64String(payloadData);
687                 this.artifactChecksum = GeneralUtility.calculateMD5Base64EncodedByByteArray(payloadData);
688             }
689             this.artifactUniqueId = artifactUniqueId;
690         }
691
692         public String getPath() {
693             return path;
694         }
695
696         public String getArtifactName() {
697             return artifactName;
698         }
699
700         public ArtifactTypeEnum getArtifactType() {
701             return artifactType;
702         }
703
704         public String getDisplayName() {
705             return displayName;
706         }
707
708         public ArtifactGroupTypeEnum getArtifactGroupType() {
709             return artifactGroupType;
710         }
711
712         public String getArtifactLabel() {
713             return artifactLabel;
714         }
715
716         public boolean isFromCsar(){
717             return isFromCsar;
718         }
719
720         public String getPayloadData() {
721             return payloadData;
722         }
723
724         public String getArtifactChecksum() {
725             return artifactChecksum;
726         }
727
728         public String getArtifactUniqueId() {
729             return artifactUniqueId;
730         }
731
732         public void setArtifactUniqueId(String artifactUniqueId) {
733             this.artifactUniqueId = artifactUniqueId;
734         }
735
736     }
737
738     /**
739      * This method checks the artifact GroupType & Artifact Type. <br>
740      * if there is any problem warning messages are added to collectedWarningMessages
741      *
742      * @param artifactPath
743      * @param collectedWarningMessages
744      * @return
745      */
746     public static Either<NonMetaArtifactInfo, Boolean> validateNonMetaArtifact(String artifactPath, byte[] payloadData, Map<String, Set<List<String>>> collectedWarningMessages) {
747         Either<NonMetaArtifactInfo, Boolean> ret;
748         try {
749             String[] parsedArtifactPath = artifactPath.split(PATH_DELIMITER);
750             // Validate Artifact Group Type
751             Either<ArtifactGroupTypeEnum, Boolean> eitherGroupType = detectArtifactGroupType(parsedArtifactPath[1], collectedWarningMessages);
752             if (eitherGroupType.isLeft()) {
753                 final ArtifactGroupTypeEnum groupTypeEnum = eitherGroupType.left().value();
754
755                 // Validate Artifact Type
756                 String artifactType = parsedArtifactPath[2];
757                 artifactType = detectArtifactTypeVF(groupTypeEnum, artifactType, collectedWarningMessages);
758
759                 String artifactFileNameType = parsedArtifactPath[3];
760                 ret = Either.left(new NonMetaArtifactInfo(artifactFileNameType, artifactPath, ArtifactTypeEnum.findType(artifactType), groupTypeEnum, payloadData, null, true));
761
762             } else {
763                 ret = Either.right(eitherGroupType.right().value());
764             }
765         } catch (Exception e) {
766             log.debug("detectArtifactGroupType failed with exception", e);
767             ret = Either.right(false);
768         }
769         return ret;
770
771     }
772
773     private static String detectArtifactTypeVFC(ArtifactGroupTypeEnum artifactGroupType, String receivedTypeName, String parentVfName, Map<String, Set<List<String>>> collectedWarningMessages) {
774         String warningMessage = "Warning - artifact type {} that was provided for VFC {} is not recognized.";
775         return detectArtifactType(artifactGroupType, receivedTypeName, warningMessage, collectedWarningMessages, parentVfName);
776     }
777
778     private static String detectArtifactTypeVF(ArtifactGroupTypeEnum artifactGroupType, String receivedTypeName, Map<String, Set<List<String>>> collectedWarningMessages) {
779         String warningMessage = "Warning - artifact type {} that was provided for VF is not recognized.";
780         return detectArtifactType(artifactGroupType, receivedTypeName, warningMessage, collectedWarningMessages);
781     }
782
783     private static String detectArtifactType(ArtifactGroupTypeEnum artifactGroupType, String receivedTypeName, String warningMessage, Map<String, Set<List<String>>> collectedWarningMessages, String... arguments) {
784
785         ArtifactTypeEnum artifactType = ArtifactTypeEnum.findType(receivedTypeName);
786         Map<String, ArtifactTypeConfig> resourceValidTypeArtifacts = null;
787
788         if(artifactGroupType != null){
789             switch (artifactGroupType) {
790                 case INFORMATIONAL:
791                     resourceValidTypeArtifacts = ConfigurationManager.getConfigurationManager().getConfiguration()
792                                                                      .getResourceInformationalArtifacts();
793                     break;
794                 case DEPLOYMENT:
795                     resourceValidTypeArtifacts = ConfigurationManager.getConfigurationManager().getConfiguration()
796                                                                      .getResourceDeploymentArtifacts();
797                     break;
798                 default:
799                     break;
800             }
801         }
802
803         Set<String> validArtifactTypes = null;
804         if(resourceValidTypeArtifacts != null){
805             validArtifactTypes = resourceValidTypeArtifacts.keySet();
806         }
807
808         if (validArtifactTypes == null || artifactType == null || !validArtifactTypes.contains(artifactType.getType())) {
809             List<String> messageArguments = new ArrayList<>();
810             messageArguments.add(receivedTypeName);
811             messageArguments.addAll(Arrays.asList(arguments));
812             if (!collectedWarningMessages.containsKey(warningMessage)) {
813                 Set<List<String>> messageArgumentLists = new HashSet<>();
814                 messageArgumentLists.add(messageArguments);
815                 collectedWarningMessages.put(warningMessage, messageArgumentLists);
816             } else {
817                 collectedWarningMessages.get(warningMessage).add(messageArguments);
818             }
819         }
820
821         return artifactType == null ? ArtifactTypeEnum.OTHER.getType() : artifactType.getType();
822     }
823
824     private Either<ZipOutputStream, ResponseFormat> writeAllFilesToCsar(Component mainComponent, CsarDefinition csarDefinition, ZipOutputStream zipstream, boolean isInCertificationRequest) throws IOException{
825         ComponentArtifacts componentArtifacts = csarDefinition.getComponentArtifacts();
826
827         Either<ZipOutputStream, ResponseFormat> writeComponentArtifactsToSpecifiedPath = writeComponentArtifactsToSpecifiedPath(mainComponent, componentArtifacts, zipstream, ARTIFACTS_PATH, isInCertificationRequest);
828
829         if(writeComponentArtifactsToSpecifiedPath.isRight()){
830             return Either.right(writeComponentArtifactsToSpecifiedPath.right().value());
831         }
832
833         ComponentTypeArtifacts mainTypeAndCIArtifacts = componentArtifacts.getMainTypeAndCIArtifacts();
834         writeComponentArtifactsToSpecifiedPath = writeArtifactsInfoToSpecifiedtPath(mainComponent, mainTypeAndCIArtifacts.getComponentArtifacts(), zipstream, ARTIFACTS_PATH, isInCertificationRequest);
835
836         if(writeComponentArtifactsToSpecifiedPath.isRight()){
837             return Either.right(writeComponentArtifactsToSpecifiedPath.right().value());
838         }
839
840         Map<String, ArtifactsInfo> componentInstancesArtifacts = mainTypeAndCIArtifacts.getComponentInstancesArtifacts();
841         Set<String> keySet = componentInstancesArtifacts.keySet();
842
843         String currentPath = ARTIFACTS_PATH + RESOURCES_PATH;
844         for (String keyAssetName : keySet) {
845             ArtifactsInfo artifactsInfo = componentInstancesArtifacts.get(keyAssetName);
846             String pathWithAssetName = currentPath + keyAssetName + PATH_DELIMITER;
847             writeComponentArtifactsToSpecifiedPath = writeArtifactsInfoToSpecifiedtPath(mainComponent, artifactsInfo, zipstream, pathWithAssetName, isInCertificationRequest);
848
849             if(writeComponentArtifactsToSpecifiedPath.isRight()){
850                 return Either.right(writeComponentArtifactsToSpecifiedPath.right().value());
851             }
852         }
853         writeComponentArtifactsToSpecifiedPath = writeOperationsArtifactsToCsar(mainComponent, zipstream);
854
855         if (writeComponentArtifactsToSpecifiedPath.isRight()) {
856             return Either.right(writeComponentArtifactsToSpecifiedPath.right().value());
857         }
858         return Either.left(zipstream);
859     }
860
861     private Either<ZipOutputStream, ResponseFormat> writeOperationsArtifactsToCsar(Component component,
862             ZipOutputStream zipstream) {
863         if (checkComponentBeforeOperation(component)) return Either.left(zipstream);
864         final Map<String, InterfaceDefinition> interfaces = ((Resource) component).getInterfaces();
865         for (Map.Entry<String, InterfaceDefinition> interfaceEntry : interfaces.entrySet()) {
866             for (OperationDataDefinition operation : interfaceEntry.getValue().getOperations().values()) {
867                 try {
868                     if (checkComponentBeforeWrite(component, interfaceEntry, operation)) continue;
869                     final String artifactUUID = operation.getImplementation().getArtifactUUID();
870                     final Either<byte[], ActionStatus> artifactFromCassandra = getFromCassandra(artifactUUID);
871                     final String artifactName = operation.getImplementation().getArtifactName();
872                     if (artifactFromCassandra.isRight()) {
873                         log.error(ARTIFACT_NAME_UNIQUE_ID, artifactName, artifactUUID);
874                         log.error("Failed to get {} payload from DB reason: {}", artifactName,
875                                 artifactFromCassandra.right().value());
876                         return Either.right(componentsUtils.getResponseFormat(
877                                 ActionStatus.ARTIFACT_PAYLOAD_NOT_FOUND_DURING_CSAR_CREATION, "Resource",
878                                 component.getUniqueId(), artifactName, artifactUUID));
879                     }
880                     final byte[] payloadData = artifactFromCassandra.left().value();
881                     zipstream.putNextEntry(new ZipEntry(OperationArtifactUtil.createOperationArtifactPath(
882                             component, null, operation,true)));
883                     zipstream.write(payloadData);
884                 } catch (IOException e) {
885                     log.error("Component Name {},  Interface Name {}, Operation Name {}", component.getNormalizedName(),
886                             interfaceEntry.getKey(), operation.getName());
887                     log.error("Error while writing the operation's artifacts to the CSAR " + "{}", e);
888                     return Either.right(componentsUtils
889                                                 .getResponseFormat(ActionStatus.ERROR_DURING_CSAR_CREATION, "Resource",
890                                                         component.getUniqueId()));
891                 }
892             }
893         }
894         return Either.left(zipstream);
895     }
896
897     private boolean checkComponentBeforeWrite(Component component, Entry<String, InterfaceDefinition> interfaceEntry, OperationDataDefinition operation) {
898         if (Objects.isNull(operation.getImplementation())) {
899             log.debug("Component Name {}, Interface Id {}, Operation Name {} - no Operation Implementation found",
900                     component.getNormalizedName(), interfaceEntry.getValue().getUniqueId(),
901                     operation.getName());
902             return true;
903         }
904         if (Objects.isNull(operation.getImplementation().getArtifactName())) {
905             log.debug("Component Name {}, Interface Id {}, Operation Name {} - no artifact found",
906                     component.getNormalizedName(), interfaceEntry.getValue().getUniqueId(),
907                     operation.getName());
908             return true;
909         }
910         return false;
911     }
912
913     private boolean checkComponentBeforeOperation(Component component) {
914         if (component instanceof Service) {
915             return true;
916         }
917         if (Objects.isNull(((Resource) component).getInterfaces())) {
918             log.debug("Component Name {}- no interfaces found", component.getNormalizedName());
919             return true;
920         }
921         return false;
922     }
923
924     private Either<ZipOutputStream, ResponseFormat> writeComponentArtifactsToSpecifiedPath(Component mainComponent, ComponentArtifacts componentArtifacts, ZipOutputStream zipstream,
925             String currentPath, boolean isInCertificationRequest) throws IOException {
926         Map<String, ComponentTypeArtifacts> componentTypeArtifacts = componentArtifacts.getComponentTypeArtifacts();
927         //Keys are defined:
928         //<Inner Asset TOSCA name (e.g. VFC name)> folder name: <Inner Asset TOSCA name (e.g. VFC name)>_v<version>.
929         //E.g. "org.openecomp.resource.vf.vipr_atm_v1.0"
930         Set<String> componentTypeArtifactsKeys = componentTypeArtifacts.keySet();
931         for (String keyAssetName : componentTypeArtifactsKeys) {
932             ComponentTypeArtifacts componentInstanceArtifacts = componentTypeArtifacts.get(keyAssetName);
933             ArtifactsInfo componentArtifacts2 = componentInstanceArtifacts.getComponentArtifacts();
934             String pathWithAssetName = currentPath + keyAssetName + PATH_DELIMITER;
935             Either<ZipOutputStream, ResponseFormat> writeArtifactsInfoToSpecifiedPath = writeArtifactsInfoToSpecifiedtPath(mainComponent, componentArtifacts2, zipstream, pathWithAssetName, isInCertificationRequest);
936
937             if(writeArtifactsInfoToSpecifiedPath.isRight()){
938                 return writeArtifactsInfoToSpecifiedPath;
939             }
940         }
941
942         return Either.left(zipstream);
943     }
944
945     private Either<ZipOutputStream, ResponseFormat> writeArtifactsInfoToSpecifiedtPath(Component mainComponent, ArtifactsInfo currArtifactsInfo, ZipOutputStream zip, String path, boolean isInCertificationRequest) throws IOException {
946         Map<ArtifactGroupTypeEnum, Map<ArtifactTypeEnum, List<ArtifactDefinition>>> artifactsInfo = currArtifactsInfo
947                                                                                                             .getArtifactsInfo();
948         Set<ArtifactGroupTypeEnum> groupTypeEnumKeySet = artifactsInfo.keySet();
949
950         for (ArtifactGroupTypeEnum artifactGroupTypeEnum : groupTypeEnumKeySet) {
951             String groupTypeFolder = path + WordUtils.capitalizeFully(artifactGroupTypeEnum.getType()) + PATH_DELIMITER;
952
953             Map<ArtifactTypeEnum, List<ArtifactDefinition>> artifactTypesMap = artifactsInfo.get(artifactGroupTypeEnum);
954             Set<ArtifactTypeEnum> artifactTypeEnumKeySet = artifactTypesMap.keySet();
955
956             for (ArtifactTypeEnum artifactTypeEnum : artifactTypeEnumKeySet) {
957                 List<ArtifactDefinition> artifactDefinitionList = artifactTypesMap.get(artifactTypeEnum);
958                                 String artifactTypeFolder = groupTypeFolder + artifactTypeEnum.toString() + PATH_DELIMITER;
959
960                                 if(artifactTypeEnum == ArtifactTypeEnum.WORKFLOW && path.contains(ARTIFACTS_PATH + RESOURCES_PATH)){
961                                         // Ignore this packaging as BPMN artifacts needs to be packaged in different manner
962                                         continue;
963                                 }
964                                 if (artifactTypeEnum == ArtifactTypeEnum.WORKFLOW) {
965                                         artifactTypeFolder += OperationArtifactUtil.BPMN_ARTIFACT_PATH + File.separator;
966                                 }
967
968                 Either<ZipOutputStream, ResponseFormat> writeArtifactDefinition = writeArtifactDefinition(mainComponent, zip, artifactDefinitionList, artifactTypeFolder, isInCertificationRequest);
969
970                 if(writeArtifactDefinition.isRight()){
971                     return writeArtifactDefinition;
972                 }
973             }
974         }
975
976         return Either.left(zip);
977     }
978
979     private Either<ZipOutputStream, ResponseFormat> writeArtifactDefinition(Component mainComponent, ZipOutputStream zip, List<ArtifactDefinition> artifactDefinitionList,
980             String artifactPathAndFolder, boolean isInCertificationRequest) throws IOException {
981
982         ComponentTypeEnum componentType = mainComponent.getComponentType();
983         String heatEnvType = ArtifactTypeEnum.HEAT_ENV.getType();
984
985         for (ArtifactDefinition artifactDefinition : artifactDefinitionList) {
986             if (!isInCertificationRequest && componentType == ComponentTypeEnum.SERVICE
987                         && artifactDefinition.getArtifactType().equals(heatEnvType) ||
988                         //this is placeholder
989                         (artifactDefinition.getEsId() == null && artifactDefinition.getMandatory())){
990                 continue;
991             }
992
993             byte[] payloadData = artifactDefinition.getPayloadData();
994             String artifactFileName = artifactDefinition.getArtifactName();
995
996             if (payloadData == null) {
997                 Either<byte[], ActionStatus> fromCassandra = getFromCassandra(artifactDefinition.getEsId());
998
999                 if (fromCassandra.isRight()) {
1000                     log.debug(ARTIFACT_NAME_UNIQUE_ID, artifactDefinition.getArtifactName(), artifactDefinition.getUniqueId());
1001                     log.debug("Failed to get {} payload from DB reason: {}", artifactFileName, fromCassandra.right().value());
1002                     continue;
1003                 }
1004                 payloadData = fromCassandra.left().value();
1005             }
1006             zip.putNextEntry(new ZipEntry(artifactPathAndFolder + artifactFileName));
1007             zip.write(payloadData);
1008         }
1009
1010         return Either.left(zip);
1011     }
1012
1013     /************************************ Artifacts Structure ******************************************************************/
1014     /**
1015      * The artifacts Definition saved by their structure
1016      */
1017     private class ArtifactsInfo {
1018         //Key is the type of artifacts(Informational/Deployment)
1019         //Value is a map between an artifact type and a list of all artifacts of this type
1020         private Map<ArtifactGroupTypeEnum, Map<ArtifactTypeEnum, List<ArtifactDefinition>>> artifactsInfoField;
1021
1022         public ArtifactsInfo() {
1023             this.artifactsInfoField = new EnumMap<>(ArtifactGroupTypeEnum.class);
1024         }
1025
1026         public Map<ArtifactGroupTypeEnum, Map<ArtifactTypeEnum, List<ArtifactDefinition>>> getArtifactsInfo() {
1027             return artifactsInfoField;
1028         }
1029
1030         public List<ArtifactDefinition> getFlatArtifactsListByType(ArtifactTypeEnum artifactType){
1031             List<ArtifactDefinition> artifacts = new ArrayList<>();
1032             for (List<ArtifactDefinition> artifactsByType:artifactsInfoField.get(artifactType).values()){
1033                 artifacts.addAll(artifactsByType);
1034             }
1035             return artifacts;
1036         }
1037
1038         public void addArtifactsToGroup(ArtifactGroupTypeEnum artifactGroup,Map<ArtifactTypeEnum, List<ArtifactDefinition>> artifactsDefinition){
1039                         if (artifactsInfoField.get(artifactGroup) == null) {
1040                                 artifactsInfoField.put(artifactGroup, artifactsDefinition);
1041                         } else {
1042                                 Map<ArtifactTypeEnum, List<ArtifactDefinition>> artifactTypeEnumListMap =
1043                                                 artifactsInfoField.get(artifactGroup);
1044                                 artifactTypeEnumListMap.putAll(artifactsDefinition);
1045                                 artifactsInfoField.put(artifactGroup, artifactTypeEnumListMap);
1046                         }
1047
1048         }
1049
1050         public boolean isEmpty() {
1051             return artifactsInfoField.isEmpty();
1052         }
1053
1054     }
1055
1056     /**
1057      * The artifacts of the component and of all its composed instances
1058      *
1059      */
1060     private class ComponentTypeArtifacts {
1061         private ArtifactsInfo componentArtifacts;    //component artifacts (describes the Informational Deployment folders)
1062         private Map<String, ArtifactsInfo> componentInstancesArtifacts;        //artifacts of the composed instances mapped by the resourceInstance normalized name (describes the Resources folder)
1063
1064         public ComponentTypeArtifacts() {
1065             componentArtifacts = new ArtifactsInfo();
1066             componentInstancesArtifacts = new HashMap<>();
1067         }
1068
1069         public ArtifactsInfo getComponentArtifacts() {
1070             return componentArtifacts;
1071         }
1072         public void setComponentArtifacts(ArtifactsInfo artifactsInfo) {
1073             this.componentArtifacts = artifactsInfo;
1074         }
1075         public Map<String, ArtifactsInfo> getComponentInstancesArtifacts() {
1076             return componentInstancesArtifacts;
1077         }
1078         public void setComponentInstancesArtifacts(Map<String, ArtifactsInfo> componentInstancesArtifacts) {
1079             this.componentInstancesArtifacts = componentInstancesArtifacts;
1080         }
1081
1082         public void addComponentInstancesArtifacts(String normalizedName, ArtifactsInfo artifactsInfo) {
1083             componentInstancesArtifacts.put(normalizedName, artifactsInfo);
1084         }
1085
1086     }
1087
1088     private class ComponentArtifacts {
1089         //artifacts of the component and CI's artifacts contained in it's composition (represents Informational, Deployment & Resource folders of main component)
1090         private ComponentTypeArtifacts mainTypeAndCIArtifacts;
1091         //artifacts of all component types mapped by their tosca name
1092         private Map<String, ComponentTypeArtifacts> componentTypeArtifacts;
1093
1094         public ComponentArtifacts(){
1095             mainTypeAndCIArtifacts = new ComponentTypeArtifacts();
1096             componentTypeArtifacts = new HashMap<>();
1097         }
1098
1099         public ComponentTypeArtifacts getMainTypeAndCIArtifacts() {
1100             return mainTypeAndCIArtifacts;
1101         }
1102
1103         public void setMainTypeAndCIArtifacts(ComponentTypeArtifacts componentInstanceArtifacts) {
1104             this.mainTypeAndCIArtifacts = componentInstanceArtifacts;
1105         }
1106
1107         public Map<String, ComponentTypeArtifacts> getComponentTypeArtifacts() {
1108             return componentTypeArtifacts;
1109         }
1110
1111         public void setComponentTypeArtifacts(Map<String, ComponentTypeArtifacts> componentTypeArtifacts) {
1112             this.componentTypeArtifacts = componentTypeArtifacts;
1113         }
1114     }
1115
1116     private class CsarDefinition {
1117         private ComponentArtifacts componentArtifacts;
1118
1119         // add list of tosca artifacts and meta describes CSAR zip root
1120
1121         public CsarDefinition(ComponentArtifacts componentArtifacts) {
1122             this.componentArtifacts = componentArtifacts;
1123         }
1124
1125         public ComponentArtifacts getComponentArtifacts() {
1126             return componentArtifacts;
1127         }
1128     }
1129
1130     /************************************ Artifacts Structure END******************************************************************/
1131
1132     private Either<CsarDefinition,ResponseFormat> collectComponentCsarDefinition(Component component){
1133         ComponentArtifacts componentArtifacts = new ComponentArtifacts();
1134         Component updatedComponent = component;
1135
1136         //get service to receive the AII artifacts uploaded to the service
1137         if (updatedComponent.getComponentType() == ComponentTypeEnum.SERVICE) {
1138             Either<Service, StorageOperationStatus> getServiceResponse = toscaOperationFacade.getToscaElement(updatedComponent.getUniqueId());
1139
1140             if(getServiceResponse.isRight()){
1141                 ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(getServiceResponse.right().value());
1142                 return Either.right(componentsUtils.getResponseFormat(actionStatus));
1143             }
1144
1145             updatedComponent = getServiceResponse.left().value();
1146         }
1147
1148         //find the artifacts of the main component, it would have its composed instances artifacts in a separate folder
1149         ComponentTypeArtifacts componentInstanceArtifacts = new ComponentTypeArtifacts();
1150         ArtifactsInfo artifactsInfo = collectComponentArtifacts(updatedComponent);
1151         componentInstanceArtifacts.setComponentArtifacts(artifactsInfo);
1152         componentArtifacts.setMainTypeAndCIArtifacts(componentInstanceArtifacts);
1153
1154         Map<String,ComponentTypeArtifacts> resourceTypeArtifacts = componentArtifacts.getComponentTypeArtifacts();    //artifacts mapped by the component type(tosca name+version)
1155         //get the component instances
1156         List<ComponentInstance> componentInstances = updatedComponent.getComponentInstances();
1157         if (componentInstances!=null){
1158             for (ComponentInstance componentInstance:componentInstances){
1159                 //call recursive to find artifacts for all the path
1160                 Either<Boolean, ResponseFormat> collectComponentInstanceArtifacts = collectComponentInstanceArtifacts(
1161                         updatedComponent, componentInstance, resourceTypeArtifacts, componentInstanceArtifacts);
1162                 if (collectComponentInstanceArtifacts.isRight()){
1163                     return Either.right(collectComponentInstanceArtifacts.right().value());
1164                 }
1165             }
1166         }
1167
1168         if(log.isDebugEnabled()){
1169             printResult(componentArtifacts,updatedComponent.getName());
1170         }
1171
1172         return Either.left(new CsarDefinition(componentArtifacts));
1173     }
1174
1175     private void printResult(ComponentArtifacts componentArtifacts, String name) {
1176         StringBuilder result = new StringBuilder();
1177         result.append("Artifacts of main component " + name + "\n");
1178         ComponentTypeArtifacts componentInstanceArtifacts = componentArtifacts.getMainTypeAndCIArtifacts();
1179         printArtifacts(componentInstanceArtifacts);
1180         result.append("Type Artifacts\n");
1181         for (Map.Entry<String, ComponentTypeArtifacts> typeArtifacts:componentArtifacts.getComponentTypeArtifacts().entrySet()){
1182             result.append("Folder " + typeArtifacts.getKey() + "\n");
1183             result.append(printArtifacts(typeArtifacts.getValue()));
1184         }
1185
1186         if(log.isDebugEnabled()){
1187             log.debug(result.toString());
1188         }
1189     }
1190
1191     private String printArtifacts(ComponentTypeArtifacts componentInstanceArtifacts) {
1192         StringBuilder result = new StringBuilder();
1193         ArtifactsInfo artifactsInfo = componentInstanceArtifacts.getComponentArtifacts();
1194         Map<ArtifactGroupTypeEnum, Map<ArtifactTypeEnum, List<ArtifactDefinition>>> componetArtifacts = artifactsInfo.getArtifactsInfo();
1195         printArtifacts(componetArtifacts);
1196         result = result.append("Resources\n");
1197         for (Map.Entry<String, ArtifactsInfo> resourceInstance:componentInstanceArtifacts.getComponentInstancesArtifacts().entrySet()){
1198             result.append("Folder" + resourceInstance.getKey() + "\n");
1199             result.append(printArtifacts(resourceInstance.getValue().getArtifactsInfo()));
1200         }
1201
1202         return result.toString();
1203     }
1204
1205     private String  printArtifacts(Map<ArtifactGroupTypeEnum, Map<ArtifactTypeEnum, List<ArtifactDefinition>>> componetArtifacts) {
1206         StringBuilder result = new StringBuilder();
1207         for (Map.Entry<ArtifactGroupTypeEnum, Map<ArtifactTypeEnum, List<ArtifactDefinition>>> artifactGroup:componetArtifacts.entrySet()){
1208             result.append("    " + artifactGroup.getKey().getType());
1209             for (Map.Entry<ArtifactTypeEnum, List<ArtifactDefinition>> groupArtifacts:artifactGroup.getValue().entrySet()){
1210                 result.append("        " + groupArtifacts.getKey().getType());
1211                 for (ArtifactDefinition artifact:groupArtifacts.getValue()){
1212                     result.append("            " + artifact.getArtifactDisplayName());
1213                 }
1214             }
1215         }
1216
1217         return result.toString();
1218     }
1219
1220     private ComponentTypeArtifacts collectComponentTypeArtifacts(Map<String, ComponentTypeArtifacts> resourcesArtifacts, ComponentInstance componentInstance,
1221             Component fetchedComponent) {
1222         String toscaComponentName = componentInstance.getToscaComponentName() + "_v" + componentInstance.getComponentVersion();
1223
1224         ComponentTypeArtifacts componentArtifactsInfo = resourcesArtifacts.get(toscaComponentName);
1225         //if there are no artifacts for this component type we need to fetch and build them
1226         if (componentArtifactsInfo==null){
1227             ArtifactsInfo componentArtifacts = collectComponentArtifacts(fetchedComponent);
1228             componentArtifactsInfo = new ComponentTypeArtifacts();
1229             if (!componentArtifacts.isEmpty()){
1230                 componentArtifactsInfo.setComponentArtifacts(componentArtifacts);
1231                 resourcesArtifacts.put(toscaComponentName, componentArtifactsInfo);
1232             }
1233         }
1234         return componentArtifactsInfo;
1235     }
1236
1237     private Either<Boolean, ResponseFormat> collectComponentInstanceArtifacts(Component parentComponent,ComponentInstance componentInstance,
1238             Map<String, ComponentTypeArtifacts> resourcesTypeArtifacts,ComponentTypeArtifacts instanceArtifactsLocation) {
1239         //1. get the component instance component
1240         String componentUid;
1241         if (componentInstance.getOriginType() == OriginTypeEnum.ServiceProxy) {
1242                         componentUid = componentInstance.getSourceModelUid();
1243                 }
1244                 else {
1245                         componentUid = componentInstance.getComponentUid();
1246                 }
1247         Either<Component, StorageOperationStatus> component = toscaOperationFacade.getToscaElement(componentUid);
1248                 if (component.isRight()) {
1249             log.error("Failed to fetch resource with id {} for instance {}",componentUid, parentComponent.getUUID());
1250             return Either.right(componentsUtils.getResponseFormat(ActionStatus.ASSET_NOT_FOUND_DURING_CSAR_CREATION,
1251                     parentComponent.getComponentType().getValue(), parentComponent.getUUID(),
1252                     componentInstance.getOriginType().getComponentType().getValue(), componentUid));
1253         }
1254                 Component fetchedComponent = component.left().value();
1255
1256         //2. fill the artifacts for the current component parent type
1257         ComponentTypeArtifacts componentParentArtifacts = collectComponentTypeArtifacts(resourcesTypeArtifacts, componentInstance, fetchedComponent);
1258
1259         //3. find the artifacts specific to the instance
1260         Map<ArtifactTypeEnum, List<ArtifactDefinition>> componentInstanceSpecificInformationalArtifacts =
1261                 getComponentInstanceSpecificArtifacts(componentInstance.getArtifacts(),
1262                         componentParentArtifacts.getComponentArtifacts().getArtifactsInfo(), ArtifactGroupTypeEnum.INFORMATIONAL);
1263         Map<ArtifactTypeEnum, List<ArtifactDefinition>> componentInstanceSpecificDeploymentArtifacts =
1264                 getComponentInstanceSpecificArtifacts(componentInstance.getDeploymentArtifacts(),
1265                         componentParentArtifacts.getComponentArtifacts().getArtifactsInfo(), ArtifactGroupTypeEnum.DEPLOYMENT);
1266
1267         //4. add the instances artifacts to the component type
1268         ArtifactsInfo artifactsInfo = new ArtifactsInfo();
1269         if (!componentInstanceSpecificInformationalArtifacts.isEmpty()){
1270             artifactsInfo.addArtifactsToGroup(ArtifactGroupTypeEnum.INFORMATIONAL, componentInstanceSpecificInformationalArtifacts);
1271         }
1272         if (!componentInstanceSpecificDeploymentArtifacts.isEmpty()){
1273             artifactsInfo.addArtifactsToGroup(ArtifactGroupTypeEnum.DEPLOYMENT, componentInstanceSpecificDeploymentArtifacts);
1274         }
1275         if (!artifactsInfo.isEmpty()){
1276             instanceArtifactsLocation.addComponentInstancesArtifacts(componentInstance.getNormalizedName(), artifactsInfo);
1277         }
1278
1279         //5. do the same for all the component instances
1280         List<ComponentInstance> componentInstances = fetchedComponent.getComponentInstances();
1281         if (componentInstances!=null){
1282             for (ComponentInstance childComponentInstance:componentInstances){
1283                 Either<Boolean, ResponseFormat> collectComponentInstanceArtifacts = collectComponentInstanceArtifacts(
1284                         fetchedComponent, childComponentInstance, resourcesTypeArtifacts, componentParentArtifacts);
1285                 if (collectComponentInstanceArtifacts.isRight()){
1286                     return collectComponentInstanceArtifacts;
1287                 }
1288             }
1289         }
1290
1291         return Either.left(true);
1292     }
1293
1294     public String getVersionFirstThreeOctets() {
1295         return versionFirstThreeOctets;
1296     }
1297
1298     public void setVersionFirstThreeOctets(String versionFirstThreeOctetes) {
1299         this.versionFirstThreeOctets = versionFirstThreeOctetes;
1300     }
1301     private Map<ArtifactTypeEnum, List<ArtifactDefinition>> getComponentInstanceSpecificArtifacts(Map<String, ArtifactDefinition> componentArtifacts,
1302             Map<ArtifactGroupTypeEnum, Map<ArtifactTypeEnum, List<ArtifactDefinition>>> componentTypeArtifacts, ArtifactGroupTypeEnum artifactGroupTypeEnum) {
1303         Map<ArtifactTypeEnum, List<ArtifactDefinition>> parentArtifacts = componentTypeArtifacts.get(artifactGroupTypeEnum);    //the artfiacts of the component itself and not the instance
1304
1305         Map<ArtifactTypeEnum, List<ArtifactDefinition>> artifactsByTypeOfComponentInstance = new EnumMap<>(ArtifactTypeEnum.class);
1306         if (componentArtifacts!=null){
1307             for (ArtifactDefinition artifact:componentArtifacts.values()){
1308                 ArtifactTypeEnum artifactType = ArtifactTypeEnum.findType(artifact.getArtifactType());
1309                 List<ArtifactDefinition> parentArtifactsByType = null;
1310                 if (parentArtifacts!=null){
1311                     parentArtifactsByType = parentArtifacts.get(artifactType);
1312                 }
1313                 //the artifact is of instance
1314                 if (parentArtifactsByType == null || !parentArtifactsByType.contains(artifact)){
1315                     List<ArtifactDefinition> typeArtifacts = artifactsByTypeOfComponentInstance.get(artifactType);
1316                     if (typeArtifacts == null){
1317                         typeArtifacts = new ArrayList<>();
1318                         artifactsByTypeOfComponentInstance.put(artifactType, typeArtifacts);
1319                     }
1320                     typeArtifacts.add(artifact);
1321                 }
1322             }
1323         }
1324
1325         return artifactsByTypeOfComponentInstance;
1326     }
1327
1328     private ArtifactsInfo collectComponentArtifacts(Component component) {
1329         Map<String, ArtifactDefinition> informationalArtifacts = component.getArtifacts();
1330         Map<ArtifactTypeEnum, List<ArtifactDefinition>> informationalArtifactsByType = collectGroupArtifacts(informationalArtifacts);
1331         Map<String, ArtifactDefinition> deploymentArtifacts = component.getDeploymentArtifacts();
1332         Map<ArtifactTypeEnum, List<ArtifactDefinition>> deploymentArtifactsByType = collectGroupArtifacts(deploymentArtifacts);
1333                 Map<String, ArtifactDefinition> interfaceOperationArtifacts =
1334                                 OperationArtifactUtil.getDistinctInterfaceOperationArtifactsByName(component);
1335                 Map<ArtifactTypeEnum, List<ArtifactDefinition>> interfaceOperationArtifactsByType = collectGroupArtifacts(
1336                                 interfaceOperationArtifacts);
1337         ArtifactsInfo artifactsInfo = new ArtifactsInfo();
1338         if (!informationalArtifactsByType.isEmpty()){
1339             artifactsInfo.addArtifactsToGroup(ArtifactGroupTypeEnum.INFORMATIONAL, informationalArtifactsByType);
1340         }
1341         if (!deploymentArtifactsByType.isEmpty() ){
1342             artifactsInfo.addArtifactsToGroup(ArtifactGroupTypeEnum.DEPLOYMENT, deploymentArtifactsByType);
1343                 }
1344                 //Add component interface operation artifacts
1345                 if(MapUtils.isNotEmpty(interfaceOperationArtifacts)) {
1346                         artifactsInfo.addArtifactsToGroup(ArtifactGroupTypeEnum.DEPLOYMENT, interfaceOperationArtifactsByType);
1347         }
1348
1349         return artifactsInfo;
1350     }
1351
1352     private Map<ArtifactTypeEnum, List<ArtifactDefinition>> collectGroupArtifacts(Map<String, ArtifactDefinition> componentArtifacts) {
1353         Map<ArtifactTypeEnum, List<ArtifactDefinition>> artifactsByType = new EnumMap<>(ArtifactTypeEnum.class);
1354         for (ArtifactDefinition artifact:componentArtifacts.values()){
1355             if (artifact.getArtifactUUID()!=null){
1356                 ArtifactTypeEnum artifactType = ArtifactTypeEnum.findType(artifact.getArtifactType());
1357                 List<ArtifactDefinition> typeArtifacts = artifactsByType.get(artifactType);
1358                 if (typeArtifacts==null){
1359                     typeArtifacts = new ArrayList<>();
1360                     artifactsByType.put(artifactType, typeArtifacts);
1361                 }
1362                 typeArtifacts.add(artifact);
1363             }
1364         }
1365         return artifactsByType;
1366     }
1367 }