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