Fix adding null schema to non list properties
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / tosca / CommonCsarGenerator.java
1 /*
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2023 Nordix Foundation. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20 package org.openecomp.sdc.be.tosca;
21
22 import static org.openecomp.sdc.be.dao.api.ActionStatus.ARTIFACT_PAYLOAD_NOT_FOUND_DURING_CSAR_CREATION;
23 import static org.openecomp.sdc.be.dao.api.ActionStatus.ERROR_DURING_CSAR_CREATION;
24 import static org.openecomp.sdc.be.tosca.ComponentCache.MergeStrategy.overwriteIfSameVersions;
25 import static org.openecomp.sdc.be.tosca.FJToVavrHelper.Try0.fromEither;
26 import static org.openecomp.sdc.be.tosca.FJToVavrHelper.Try0.javaListToVavrList;
27 import static org.openecomp.sdc.common.api.Constants.ADDITIONAL_TYPE_DEFINITIONS;
28
29 import com.google.common.primitives.Bytes;
30 import fj.F;
31 import fj.data.Either;
32 import io.vavr.Tuple2;
33 import io.vavr.control.Try;
34 import java.io.BufferedOutputStream;
35 import java.io.ByteArrayInputStream;
36 import java.io.File;
37 import java.io.IOException;
38 import java.nio.charset.StandardCharsets;
39 import java.nio.file.Path;
40 import java.nio.file.Paths;
41 import java.text.SimpleDateFormat;
42 import java.util.ArrayList;
43 import java.util.Collections;
44 import java.util.Date;
45 import java.util.EnumMap;
46 import java.util.HashMap;
47 import java.util.HashSet;
48 import java.util.List;
49 import java.util.Map;
50 import java.util.Map.Entry;
51 import java.util.Objects;
52 import java.util.Optional;
53 import java.util.Set;
54 import java.util.TimeZone;
55 import java.util.function.Function;
56 import java.util.function.Predicate;
57 import java.util.function.Supplier;
58 import java.util.regex.Matcher;
59 import java.util.regex.Pattern;
60 import java.util.stream.Collectors;
61 import java.util.stream.Stream;
62 import java.util.zip.ZipEntry;
63 import java.util.zip.ZipInputStream;
64 import java.util.zip.ZipOutputStream;
65 import org.apache.commons.collections.CollectionUtils;
66 import org.apache.commons.collections.MapUtils;
67 import org.apache.commons.io.output.ByteArrayOutputStream;
68 import org.apache.commons.lang.StringUtils;
69 import org.apache.commons.lang3.tuple.ImmutableTriple;
70 import org.apache.commons.lang3.tuple.Triple;
71 import org.apache.commons.text.WordUtils;
72 import org.onap.sdc.tosca.services.YamlUtil;
73 import org.openecomp.sdc.be.components.impl.exceptions.ByResponseFormatComponentException;
74 import org.openecomp.sdc.be.config.CategoryBaseTypeConfig;
75 import org.openecomp.sdc.be.config.ConfigurationManager;
76 import org.openecomp.sdc.be.dao.api.ActionStatus;
77 import org.openecomp.sdc.be.dao.cassandra.ArtifactCassandraDao;
78 import org.openecomp.sdc.be.dao.cassandra.CassandraOperationStatus;
79 import org.openecomp.sdc.be.dao.cassandra.SdcSchemaFilesCassandraDao;
80 import org.openecomp.sdc.be.data.model.ToscaImportByModel;
81 import org.openecomp.sdc.be.datatypes.components.ResourceMetadataDataDefinition;
82 import org.openecomp.sdc.be.datatypes.elements.ArtifactDataDefinition;
83 import org.openecomp.sdc.be.datatypes.elements.OperationDataDefinition;
84 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
85 import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum;
86 import org.openecomp.sdc.be.impl.ComponentsUtils;
87 import org.openecomp.sdc.be.model.ArtifactDefinition;
88 import org.openecomp.sdc.be.model.Component;
89 import org.openecomp.sdc.be.model.ComponentInstance;
90 import org.openecomp.sdc.be.model.InterfaceDefinition;
91 import org.openecomp.sdc.be.model.LifecycleStateEnum;
92 import org.openecomp.sdc.be.model.Resource;
93 import org.openecomp.sdc.be.model.Service;
94 import org.openecomp.sdc.be.model.category.CategoryDefinition;
95 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ToscaOperationFacade;
96 import org.openecomp.sdc.be.model.jsonjanusgraph.utils.ModelConverter;
97 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
98 import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter;
99 import org.openecomp.sdc.be.model.operations.impl.ModelOperation;
100 import org.openecomp.sdc.be.plugins.CsarEntryGenerator;
101 import org.openecomp.sdc.be.resources.data.DAOArtifactData;
102 import org.openecomp.sdc.be.tosca.utils.OperationArtifactUtil;
103 import org.openecomp.sdc.be.utils.TypeUtils;
104 import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum;
105 import org.openecomp.sdc.common.api.ArtifactTypeEnum;
106 import org.openecomp.sdc.common.impl.ExternalConfiguration;
107 import org.openecomp.sdc.common.log.enums.EcompLoggerErrorCode;
108 import org.openecomp.sdc.common.util.GeneralUtility;
109 import org.openecomp.sdc.common.zip.ZipUtils;
110 import org.openecomp.sdc.exception.ResponseFormat;
111 import org.slf4j.Logger;
112 import org.slf4j.LoggerFactory;
113 import org.springframework.beans.factory.annotation.Autowired;
114 import org.yaml.snakeyaml.DumperOptions;
115 import org.yaml.snakeyaml.DumperOptions.FlowStyle;
116 import org.yaml.snakeyaml.Yaml;
117
118 /**
119  * Generates a Network Service CSAR based on a SERVICE component and wraps it in a SDC CSAR entry.
120  */
121 @org.springframework.stereotype.Component("commonCsarGenerator")
122 public class CommonCsarGenerator {
123
124     private static final Logger LOGGER = LoggerFactory.getLogger(CommonCsarGenerator.class);
125     public static final String ARTIFACTS_PATH = "Artifacts/";
126     private static final String RESOURCES_PATH = "Resources/";
127     private static final String PATH_DELIMITER = "/";
128     private static final String SERVICE_MANIFEST = "NS.mf";
129     private static final String ARTIFACT_NAME_UNIQUE_ID = "ArtifactName {}, unique ID {}";
130     private static final String TOSCA_META_PATH_FILE_NAME = "TOSCA-Metadata/TOSCA.meta";
131     private static final String TOSCA_META_VERSION = "1.0";
132     private static final String CSAR_VERSION = "1.1";
133     private static final String SDC_VERSION = ExternalConfiguration.getAppVersion();
134     public static final String NODES_YML = "nodes.yml";
135     private static final String CONFORMANCE_LEVEL = ConfigurationManager.getConfigurationManager().getConfiguration().getToscaConformanceLevel();
136     private final ToscaOperationFacade toscaOperationFacade;
137     private final ComponentsUtils componentsUtils;
138     private final ToscaExportHandler toscaExportUtils;
139     private final List<CsarEntryGenerator> generators;
140     private final ArtifactCassandraDao artifactCassandraDao;
141     private final String versionFirstThreeOctets;
142     private final SdcSchemaFilesCassandraDao sdcSchemaFilesCassandraDao;
143     private final ModelOperation modelOperation;
144
145     @Autowired
146     public CommonCsarGenerator(
147         final ToscaOperationFacade toscaOperationFacade,
148         final ComponentsUtils componentsUtils,
149         final ToscaExportHandler toscaExportUtils,
150         final List<CsarEntryGenerator> generators,
151         final ArtifactCassandraDao artifactCassandraDao,
152         final SdcSchemaFilesCassandraDao sdcSchemaFilesCassandraDao,
153         final ModelOperation modelOperation) {
154         this.toscaOperationFacade = toscaOperationFacade;
155         this.componentsUtils = componentsUtils;
156         this.toscaExportUtils = toscaExportUtils;
157         this.generators = generators;
158         this.artifactCassandraDao = artifactCassandraDao;
159         this.versionFirstThreeOctets = readVersionFirstThreeOctets();
160         this.sdcSchemaFilesCassandraDao = sdcSchemaFilesCassandraDao;
161         this.modelOperation = modelOperation;
162     }
163
164     private String readVersionFirstThreeOctets() {
165         if (StringUtils.isEmpty(SDC_VERSION)) {
166             return "";
167         }
168         // change regex to avoid DoS sonar issue
169         Matcher matcher = Pattern.compile("(?!\\.)(\\d{1,9}(\\.\\d{1,9}){1,9})(?![\\d\\.])").matcher(SDC_VERSION);
170         matcher.find();
171         return matcher.group(0);
172     }
173
174     /**
175      * Generates a Network Service CSAR based on a SERVICE component that has category configured in
176      * CategoriesToGenerateNsd enum and wraps it in a SDC CSAR entry.
177      *
178      * @param component the component to create the NS CSAR from
179      * @return an entry to be added in the Component CSAR by SDC
180      */
181     public Either<ZipOutputStream, ResponseFormat> generateCsarZip(Component component,
182                                                                    boolean getFromCS,
183                                                                    ZipOutputStream zip,
184                                                                    boolean isInCertificationRequest,
185                                                                    boolean isAsdPackage,
186                                                                    String definitionsPath,
187                                                                    boolean addDependencies,
188                                                                    boolean isSkipImports) throws IOException {
189         ArtifactDefinition artifactDef = component.getToscaArtifacts().get(ToscaExportHandler.ASSET_TOSCA_TEMPLATE);
190         Either<ToscaRepresentation, ResponseFormat> toscaRepresentation = fetchToscaRepresentation(component, getFromCS, artifactDef, isSkipImports);
191
192         // This should not be done but in order to keep the refactoring small enough we stop here.
193         // TODO: Refactor the rest of this function
194         byte[] mainYaml;
195         List<Triple<String, String, Component>> dependencies;
196         if (toscaRepresentation.isLeft()) {
197             mainYaml = toscaRepresentation.left().value().getMainYaml();
198             dependencies = toscaRepresentation.left().value().getDependencies().getOrElse(new ArrayList<>());
199         } else {
200             return Either.right(toscaRepresentation.right().value());
201         }
202         final String fileName = artifactDef.getArtifactName();
203         final byte[] toscaBlock0Byte =
204             createToscaBlock0(TOSCA_META_VERSION, CSAR_VERSION, component.getCreatorFullName(), fileName, isAsdPackage, definitionsPath).getBytes();
205         zip.putNextEntry(new ZipEntry(TOSCA_META_PATH_FILE_NAME));
206         zip.write(toscaBlock0Byte);
207         zip.putNextEntry(new ZipEntry(definitionsPath + fileName));
208         zip.write(mainYaml);
209         LifecycleStateEnum lifecycleState = component.getLifecycleState();
210         if (addDependencies) {
211             addServiceMf(component, zip, lifecycleState, isInCertificationRequest, fileName, mainYaml, definitionsPath);
212             //US798487 - Abstraction of complex types
213             if (hasToWriteComponentSubstitutionType(component)) {
214                 LOGGER.debug("Component {} is complex - generating abstract type for it..", component.getName());
215                 dependencies.addAll(writeComponentInterface(component, zip, fileName, definitionsPath));
216             }
217             //UID <cassandraId,filename,component>
218             Either<ZipOutputStream, ResponseFormat> zipOutputStreamOrResponseFormat =
219                 getZipOutputStreamResponseFormatEither(zip, dependencies, definitionsPath);
220             if (zipOutputStreamOrResponseFormat != null && zipOutputStreamOrResponseFormat.isRight()) {
221                 return zipOutputStreamOrResponseFormat;
222             }
223         }
224         if (component.getModel() == null) {
225             //retrieve SDC.zip from Cassandra
226             Either<byte[], ResponseFormat> latestSchemaFiles = getLatestSchemaFilesFromCassandra();
227             if (latestSchemaFiles.isRight()) {
228                 LOGGER.error("Error retrieving SDC Schema files from cassandra");
229                 return Either.right(latestSchemaFiles.right().value());
230             }
231             final byte[] schemaFileZip = latestSchemaFiles.left().value();
232             final List<String> nodesFromPackage = findNonRootNodesFromPackage(dependencies);
233             //add files from retrieved SDC.zip to Definitions folder in CSAR
234             addSchemaFilesFromCassandra(zip, schemaFileZip, nodesFromPackage, definitionsPath);
235         } else {
236             //retrieve schema files by model from Cassandra
237             addSchemaFilesByModel(zip, component.getModel(), definitionsPath, addDependencies,
238                 dependencies.stream().map(d -> d.getRight()).collect(Collectors.toList()));
239         }
240         Either<CsarDefinition, ResponseFormat> collectedComponentCsarDefinition = collectComponentCsarDefinition(component);
241         if (collectedComponentCsarDefinition.isRight()) {
242             return Either.right(collectedComponentCsarDefinition.right().value());
243         }
244         if (generators != null) {
245             for (CsarEntryGenerator generator : generators) {
246                 LOGGER.debug("Invoking CsarEntryGenerator: {}", generator.getClass().getName());
247                 for (Map.Entry<String, byte[]> pluginGeneratedFile : generator.generateCsarEntries(component).entrySet()) {
248                     zip.putNextEntry(new ZipEntry(pluginGeneratedFile.getKey()));
249                     zip.write(pluginGeneratedFile.getValue());
250                 }
251             }
252         }
253         return writeAllFilesToCsar(component, collectedComponentCsarDefinition.left().value(), zip, isInCertificationRequest);
254     }
255
256     private Either<ToscaRepresentation, ResponseFormat> fetchToscaRepresentation(Component component, boolean getFromCS,
257                                                                                  ArtifactDefinition artifactDef, boolean isSkipImports) {
258         LifecycleStateEnum lifecycleState = component.getLifecycleState();
259         boolean shouldBeFetchedFromCassandra =
260             getFromCS || !(lifecycleState == LifecycleStateEnum.NOT_CERTIFIED_CHECKIN || lifecycleState == LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT);
261         Either<ToscaRepresentation, ResponseFormat> toscaRepresentation =
262             shouldBeFetchedFromCassandra ? fetchToscaRepresentation(artifactDef) : generateToscaRepresentation(component, isSkipImports);
263         return toscaRepresentation.left()
264             .bind(iff(myd -> !myd.getDependencies().isDefined(), myd -> fetchToscaTemplateDependencies(myd.getMainYaml(), component)));
265     }
266
267     private Either<ToscaRepresentation, ResponseFormat> fetchToscaTemplateDependencies(byte[] mainYml, Component component) {
268         return toscaExportUtils.getDependencies(component).right().map(toscaError -> {
269             LOGGER.debug("Failed to retrieve dependencies for component {}, error {}", component.getUniqueId(), toscaError);
270             return componentsUtils.getResponseFormat(componentsUtils.convertFromToscaError(toscaError));
271         }).left().map(tt -> ToscaRepresentation.make(mainYml, tt));
272     }
273
274     private Either<ToscaRepresentation, ResponseFormat> fetchToscaRepresentation(ArtifactDefinition artifactDef) {
275         return getFromCassandra(artifactDef.getEsId()).right().map(as -> {
276             LOGGER.debug(ARTIFACT_NAME_UNIQUE_ID, artifactDef.getArtifactName(), artifactDef.getUniqueId());
277             return componentsUtils.getResponseFormat(as);
278         }).left().map(ToscaRepresentation::make);
279     }
280
281     private Either<byte[], ActionStatus> getFromCassandra(String cassandraId) {
282         return artifactCassandraDao.getArtifact(cassandraId).right().map(operationstatus -> {
283             LOGGER.info("Failed to fetch artifact from Cassandra by id {} error {}.", cassandraId, operationstatus);
284             StorageOperationStatus storageStatus = DaoStatusConverter.convertCassandraStatusToStorageStatus(operationstatus);
285             return componentsUtils.convertFromStorageResponse(storageStatus);
286         }).left().map(DAOArtifactData::getDataAsArray);
287     }
288
289     private static <L, R> F<L, Either<L, R>> iff(Predicate<L> p, Function<L, Either<L, R>> ifTrue) {
290         return l -> p.test(l) ? ifTrue.apply(l) : Either.left(l);
291     }
292
293     private static <A, B> F<A, B> iff(Predicate<A> p, Supplier<B> s, Function<A, B> orElse) {
294         return a -> p.test(a) ? s.get() : orElse.apply(a);
295     }
296
297     private void addServiceMf(Component component, ZipOutputStream zip, LifecycleStateEnum lifecycleState, boolean isInCertificationRequest,
298                               String fileName, byte[] mainYaml, String definitionsPath) throws IOException {
299         // add mf
300         if ((component.getComponentType() == ComponentTypeEnum.SERVICE) && (lifecycleState != LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT)) {
301             String serviceName = component.getName();
302             String createdBy = component.getCreatorUserId();
303             String serviceVersion;
304             if (isInCertificationRequest) {
305                 int tmp = Integer.valueOf(component.getVersion().split("\\.")[0]) + 1;
306                 serviceVersion = String.valueOf(tmp) + ".0";
307             } else {
308                 serviceVersion = component.getVersion();
309             }
310             SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss'Z'");
311             format.setTimeZone(TimeZone.getTimeZone("UTC"));
312             Date date = new Date();
313             String releaseTime = format.format(date);
314             if (component.getCategories() == null || component.getCategories().get(0) == null) {
315                 return;
316             }
317             String serviceType = component.getCategories().get(0).getName();
318             String description = component.getDescription();
319             String serviceTemplate = definitionsPath + fileName;
320             String hash = GeneralUtility.calculateMD5Base64EncodedByByteArray(mainYaml);
321             String nsMfBlock0 = createNsMfBlock0(serviceName, createdBy, serviceVersion, releaseTime, serviceType, description, serviceTemplate,
322                 hash);
323             byte[] nsMfBlock0Byte = nsMfBlock0.getBytes();
324             zip.putNextEntry(new ZipEntry(SERVICE_MANIFEST));
325             zip.write(nsMfBlock0Byte);
326         }
327     }
328
329     private String createNsMfBlock0(String serviceName, String createdBy, String serviceVersion, String releaseTime, String serviceType,
330                                     String description, String serviceTemplate, String hash) {
331         final String block0template = "metadata??\n" + "ns_product_name: %s\n" + "ns_provider_id: %s\n" + "ns_package_version: %s\n" +
332             "ns_release_data_time: %s\n" + "ns_type: %s\n" + "ns_package_description: %s\n\n" + "Source: %s\n" + "Algorithm: MD5\n" + "Hash: %s\n\n";
333         return String.format(block0template, serviceName, createdBy, serviceVersion, releaseTime, serviceType, description, serviceTemplate, hash);
334     }
335
336     private boolean hasToWriteComponentSubstitutionType(final Component component) {
337         final Map<String, CategoryBaseTypeConfig> serviceNodeTypesConfig =
338             ConfigurationManager.getConfigurationManager().getConfiguration().getServiceBaseNodeTypes();
339         List<CategoryDefinition> categories = component.getCategories();
340         if (CollectionUtils.isNotEmpty(categories) && MapUtils.isNotEmpty(serviceNodeTypesConfig)
341             && serviceNodeTypesConfig.get(categories.get(0).getName()) != null) {
342             boolean doNotExtendBaseType = serviceNodeTypesConfig.get(categories.get(0).getName()).isDoNotExtendBaseType();
343             if (doNotExtendBaseType) {
344                 return false;
345             }
346         }
347         if (component instanceof Service) {
348             return !ModelConverter.isAtomicComponent(component) && ((Service) component).isSubstituteCandidate();
349         }
350         return !ModelConverter.isAtomicComponent(component);
351     }
352
353     private Either<ZipOutputStream, ResponseFormat> writeComponentInterface(Either<ToscaRepresentation, ToscaError> interfaceRepresentation,
354                                                                             ZipOutputStream zip, String fileName, String definitionsPath) {
355         // TODO: This should not be done but we need this to keep the refactoring small enough to be easily reviewable
356         return writeComponentInterface(interfaceRepresentation, fileName, ZipWriter.live(zip), definitionsPath)
357             .map(void0 -> Either.<ZipOutputStream, ResponseFormat>left(zip)).recover(th -> {
358                 LOGGER.error("#writeComponentInterface - zip writing failed with error: ", th);
359                 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
360             }).get();
361     }
362
363     private Try<Void> writeComponentInterface(
364         Either<ToscaRepresentation, ToscaError> interfaceRepresentation, String fileName, ZipWriter zw, String definitionsPath) {
365         Either<byte[], ToscaError> yml = interfaceRepresentation.left()
366             .map(ToscaRepresentation::getMainYaml);
367         return fromEither(yml, ToscaErrorException::new).flatMap(zw.write(definitionsPath + ToscaExportHandler.getInterfaceFilename(fileName)));
368     }
369
370     private List<Triple<String, String, Component>> writeComponentInterface(final Component component, final ZipOutputStream zip,
371                                                                             final String fileName, final String definitionsPath) {
372         final Either<ToscaRepresentation, ToscaError> interfaceRepresentation = toscaExportUtils.exportComponentInterface(component, false);
373         writeComponentInterface(interfaceRepresentation, zip, fileName, definitionsPath);
374         return interfaceRepresentation.left().value().getDependencies().getOrElse(new ArrayList<>());
375     }
376
377     private Either<ZipOutputStream, ResponseFormat> getZipOutputStreamResponseFormatEither(ZipOutputStream zip,
378                                                                                            List<Triple<String, String, Component>> dependencies,
379                                                                                            String definitionsPath)
380         throws IOException {
381         ComponentCache
382             innerComponentsCache = ComponentCache.overwritable(overwriteIfSameVersions()).onMerge((oldValue, newValue) ->
383             LOGGER.warn("Overwriting component invariantID {} of version {} with a newer version {}", oldValue.getId(),
384                 oldValue.getComponentVersion(),
385                 newValue.getComponentVersion()));
386         if (dependencies != null && !dependencies.isEmpty()) {
387             for (Triple<String, String, Component> d : dependencies) {
388                 String cassandraId = d.getMiddle();
389                 Component childComponent = d.getRight();
390                 Either<byte[], ResponseFormat> entryData = getEntryData(cassandraId, childComponent).right().map(componentsUtils::getResponseFormat);
391                 if (entryData.isRight()) {
392                     return Either.right(entryData.right().value());
393                 }
394                 //fill innerComponentsCache
395                 String fileName = d.getLeft();
396                 innerComponentsCache.put(cassandraId, fileName, childComponent);
397                 addInnerComponentsToCache(innerComponentsCache, childComponent);
398             }
399             //add inner components to CSAR
400             return addInnerComponentsToCSAR(zip, innerComponentsCache, definitionsPath);
401         }
402         return null;
403     }
404
405     private Either<ZipOutputStream, ResponseFormat> addInnerComponentsToCSAR(ZipOutputStream zip, ComponentCache innerComponentsCache,
406                                                                              String definitionsPath)
407         throws IOException {
408         for (ImmutableTriple<String, String, Component> ict : innerComponentsCache.iterable()) {
409             Component innerComponent = ict.getRight();
410             String icFileName = ict.getMiddle();
411             // add component to zip
412             Either<Tuple2<byte[], ZipEntry>, ResponseFormat> zipEntry = toZipEntry(ict, definitionsPath);
413             // TODO: this should not be done, we should instead compose this either further,
414
415             // but in order to keep this refactoring small, we'll stop here.
416             if (zipEntry.isRight()) {
417                 return Either.right(zipEntry.right().value());
418             }
419             Tuple2<byte[], ZipEntry> value = zipEntry.left().value();
420             zip.putNextEntry(value._2);
421             zip.write(value._1);
422             // add component interface to zip
423             if (hasToWriteComponentSubstitutionType(innerComponent)) {
424                 writeComponentInterface(innerComponent, zip, icFileName, definitionsPath);
425             }
426         }
427         return null;
428     }
429
430     private Either<Tuple2<byte[], ZipEntry>, ResponseFormat> toZipEntry(ImmutableTriple<String, String, Component> cachedEntry,
431                                                                         String definitionsPath) {
432         String cassandraId = cachedEntry.getLeft();
433         String fileName = cachedEntry.getMiddle();
434         Component innerComponent = cachedEntry.getRight();
435         return getEntryData(cassandraId, innerComponent).right().map(status -> {
436             LOGGER.debug("Failed adding to zip component {}, error {}", cassandraId, status);
437             return componentsUtils.getResponseFormat(status);
438         }).left().map(content -> new Tuple2<>(content, new ZipEntry(definitionsPath + fileName)));
439     }
440
441     private void addInnerComponentsToCache(ComponentCache componentCache, Component childComponent) {
442         javaListToVavrList(childComponent.getComponentInstances()).filter(ci -> componentCache.notCached(ci.getComponentUid())).forEach(ci -> {
443             // all resource must be only once!
444             Either<Resource, StorageOperationStatus> resource = toscaOperationFacade.getToscaElement(ci.getComponentUid());
445             Component componentRI = checkAndAddComponent(componentCache, ci, resource);
446             //if not atomic - insert inner components as well
447
448             // TODO: This could potentially create a StackOverflowException if the call stack
449
450             // happens to be too large. Tail-recursive optimization should be used here.
451             if (!ModelConverter.isAtomicComponent(componentRI)) {
452                 addInnerComponentsToCache(componentCache, componentRI);
453             }
454         });
455     }
456
457     private Component checkAndAddComponent(ComponentCache componentCache, ComponentInstance ci, Either<Resource, StorageOperationStatus> resource) {
458         if (resource.isRight()) {
459             LOGGER.debug("Failed to fetch resource with id {} for instance {}", ci.getComponentUid(), ci.getName());
460         }
461         Component componentRI = resource.left().value();
462         Map<String, ArtifactDefinition> childToscaArtifacts = componentRI.getToscaArtifacts();
463         ArtifactDefinition childArtifactDefinition = childToscaArtifacts.get(ToscaExportHandler.ASSET_TOSCA_TEMPLATE);
464         if (childArtifactDefinition != null) {
465             //add to cache
466             componentCache.put(childArtifactDefinition.getEsId(), childArtifactDefinition.getArtifactName(), componentRI);
467         }
468         return componentRI;
469     }
470
471     private Either<byte[], ActionStatus> getEntryData(String cassandraId, Component childComponent) {
472         if (cassandraId == null || cassandraId.isEmpty()) {
473             return toscaExportUtils.exportComponent(childComponent).right().map(toscaErrorToActionStatus(childComponent)).left()
474                 .map(ToscaRepresentation::getMainYaml);
475         } else {
476             return getFromCassandra(cassandraId);
477         }
478     }
479
480     private F<ToscaError, ActionStatus> toscaErrorToActionStatus(Component childComponent) {
481         return toscaError -> {
482             LOGGER.debug("Failed to export tosca template for child component {} error {}", childComponent.getUniqueId(), toscaError);
483             return componentsUtils.convertFromToscaError(toscaError);
484         };
485     }
486
487     private Either<byte[], ResponseFormat> getLatestSchemaFilesFromCassandra() {
488         String fto = versionFirstThreeOctets;
489         return sdcSchemaFilesCassandraDao.getSpecificSchemaFiles(fto, CONFORMANCE_LEVEL).right().map(schemaFilesFetchDBError(fto)).left()
490             .bind(iff(List::isEmpty, () -> schemaFileFetchError(fto), s -> Either.left(s.iterator().next().getPayloadAsArray())));
491     }
492
493     private F<CassandraOperationStatus, ResponseFormat> schemaFilesFetchDBError(String firstThreeOctets) {
494         return cos -> {
495             LOGGER.debug("Failed to get the schema files SDC-Version: {} Conformance-Level {}. Please fix DB table accordingly.", firstThreeOctets,
496                 CONFORMANCE_LEVEL);
497             StorageOperationStatus sos = DaoStatusConverter.convertCassandraStatusToStorageStatus(cos);
498             return componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(sos));
499         };
500     }
501
502     private Either<byte[], ResponseFormat> schemaFileFetchError(String firstThreeOctets) {
503         LOGGER.debug("Failed to get the schema files SDC-Version: {} Conformance-Level {}", firstThreeOctets, CONFORMANCE_LEVEL);
504         return Either.right(componentsUtils.getResponseFormat(ActionStatus.TOSCA_SCHEMA_FILES_NOT_FOUND, firstThreeOctets, CONFORMANCE_LEVEL));
505     }
506
507     /**
508      * Create a list of all derived nodes found on the package
509      *
510      * @param dependencies all node dependencies
511      * @return a list of nodes
512      */
513     private List<String> findNonRootNodesFromPackage(final List<Triple<String, String, Component>> dependencies) {
514         final List<String> nodes = new ArrayList<>();
515         if (CollectionUtils.isNotEmpty(dependencies)) {
516             final String NATIVE_ROOT = "tosca.nodes.Root";
517             dependencies.forEach(dependency -> {
518                 if (dependency.getRight() instanceof Resource) {
519                     final Resource resource = (Resource) dependency.getRight();
520                     if (CollectionUtils.isNotEmpty(resource.getDerivedList())) {
521                         resource.getDerivedList().stream().filter(node -> !nodes.contains(node) && !NATIVE_ROOT.equalsIgnoreCase(node))
522                             .forEach(node -> nodes.add(node));
523                     }
524                 }
525             });
526         }
527         return nodes;
528     }
529
530     /**
531      * Writes to a CSAR zip from casandra schema data
532      *
533      * @param zipOutputStream  stores the input stream content
534      * @param schemaFileZip    zip data from Cassandra
535      * @param nodesFromPackage list of all nodes found on the onboarded package
536      */
537     private void addSchemaFilesFromCassandra(final ZipOutputStream zipOutputStream, final byte[] schemaFileZip, final List<String> nodesFromPackage,
538                                              final String definitionsPath) {
539         final int initSize = 2048;
540         LOGGER.debug("Starting copy from Schema file zip to CSAR zip");
541         try (final ZipInputStream zipInputStream = new ZipInputStream(new ByteArrayInputStream(schemaFileZip));
542             final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
543             final BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(byteArrayOutputStream, initSize)) {
544             ZipEntry entry;
545             while ((entry = zipInputStream.getNextEntry()) != null) {
546                 ZipUtils.checkForZipSlipInRead(entry);
547                 final String entryName = entry.getName();
548                 int readSize = initSize;
549                 final byte[] entryData = new byte[initSize];
550                 if (shouldZipEntryBeHandled(entryName)) {
551                     if (NODES_YML.equalsIgnoreCase(entryName)) {
552                         handleNode(zipInputStream, byteArrayOutputStream, nodesFromPackage);
553                     } else {
554                         while ((readSize = zipInputStream.read(entryData, 0, readSize)) != -1) {
555                             bufferedOutputStream.write(entryData, 0, readSize);
556                         }
557                         bufferedOutputStream.flush();
558                     }
559                     byteArrayOutputStream.flush();
560                     zipOutputStream.putNextEntry(new ZipEntry(definitionsPath + entryName));
561                     zipOutputStream.write(byteArrayOutputStream.toByteArray());
562                     zipOutputStream.flush();
563                     byteArrayOutputStream.reset();
564                 }
565             }
566         } catch (final Exception e) {
567             LOGGER.error("Error while writing the SDC schema file to the CSAR", e);
568             throw new ByResponseFormatComponentException(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
569         }
570         LOGGER.debug("Finished copy from Schema file zip to CSAR zip");
571     }
572
573     /**
574      * Handles the nodes.yml zip entry, updating the nodes.yml to avoid duplicated nodes on it.
575      *
576      * @param zipInputStream        the zip entry to be read
577      * @param byteArrayOutputStream an output stream in which the data is written into a byte array.
578      * @param nodesFromPackage      list of all nodes found on the onboarded package
579      */
580     private void handleNode(final ZipInputStream zipInputStream, final ByteArrayOutputStream byteArrayOutputStream,
581                             final List<String> nodesFromPackage) throws IOException {
582         final Map<String, Object> nodesFromArtifactFile = readYamlZipEntry(zipInputStream);
583         final Map<String, Object> nodesYaml = updateNodeYml(nodesFromPackage, nodesFromArtifactFile);
584         updateZipEntry(byteArrayOutputStream, nodesYaml);
585     }
586
587     /**
588      * Updates the zip entry from the given parameters
589      *
590      * @param byteArrayOutputStream an output stream in which the data is written into a byte array.
591      * @param nodesYaml             a Map of nodes to be written
592      */
593     private void updateZipEntry(final ByteArrayOutputStream byteArrayOutputStream, final Map<String, Object> nodesYaml) throws IOException {
594         if (MapUtils.isNotEmpty(nodesYaml)) {
595             byteArrayOutputStream.write(new YamlUtil().objectToYaml(nodesYaml).getBytes());
596         }
597     }
598
599     /**
600      * Filters and removes all duplicated nodes found
601      *
602      * @param nodesFromPackage      a List of all derived nodes found on the given package
603      * @param nodesFromArtifactFile represents the nodes.yml file stored in Cassandra
604      * @return a nodes Map updated
605      */
606     private Map<String, Object> updateNodeYml(final List<String> nodesFromPackage, final Map<String, Object> nodesFromArtifactFile) {
607         if (MapUtils.isNotEmpty(nodesFromArtifactFile)) {
608             final String nodeTypeBlock = TypeUtils.ToscaTagNamesEnum.NODE_TYPES.getElementName();
609             final Map<String, Object> nodeTypes = (Map<String, Object>) nodesFromArtifactFile.get(nodeTypeBlock);
610             nodesFromPackage.stream().filter(nodeTypes::containsKey).forEach(nodeTypes::remove);
611             nodesFromArtifactFile.replace(nodeTypeBlock, nodeTypes);
612         }
613         return nodesFromArtifactFile;
614     }
615
616     /**
617      * Writes a new zip entry
618      *
619      * @param zipInputStream the zip entry to be read
620      * @return a map of the given zip entry
621      */
622     private Map<String, Object> readYamlZipEntry(final ZipInputStream zipInputStream) throws IOException {
623         final int initSize = 2048;
624         final StringBuilder zipEntry = new StringBuilder();
625         final byte[] buffer = new byte[initSize];
626         int read = 0;
627         while ((read = zipInputStream.read(buffer, 0, initSize)) >= 0) {
628             zipEntry.append(new String(buffer, 0, read));
629         }
630         return (Map<String, Object>) new Yaml().load(zipEntry.toString());
631     }
632
633     /**
634      * Checks if the zip entry should or should not be added to the CSAR based on the given global type list
635      *
636      * @param entryName the zip entry name
637      * @return true if the zip entry should be handled
638      */
639     private boolean shouldZipEntryBeHandled(final String entryName) {
640         return ConfigurationManager.getConfigurationManager().getConfiguration().getGlobalCsarImports().stream()
641             .anyMatch(entry -> entry.contains(entryName));
642     }
643
644     private void addSchemaFilesByModel(final ZipOutputStream zipOutputStream, final String modelName,
645                                        final String definitionsPath, final boolean isSingleImportsFile,
646                                        final List<Component> dependencies) {
647         try {
648             final Set<Path> writtenEntryPathList = new HashSet<>();
649             final Path defsPath = Path.of(definitionsPath);
650             final Map<Path, byte[]> contentToMerge = new HashMap<>();
651             final List<ToscaImportByModel> modelDefaultImportList = modelOperation.findAllModelImports(modelName, true);
652             for (final ToscaImportByModel toscaImportByModel : modelDefaultImportList) {
653                 var importPath = Path.of(toscaImportByModel.getFullPath());
654                 if (!isSingleImportsFile) {
655                     if (ADDITIONAL_TYPE_DEFINITIONS.equals(Paths.get(String.valueOf(importPath)).normalize().toString())) {
656                         final Path entryPath = defsPath.resolve(importPath);
657                         contentToMerge.put(entryPath, toscaImportByModel.getContent().getBytes(StandardCharsets.UTF_8));
658                     } else {
659                         if (writtenEntryPathList.contains(defsPath.resolve(importPath))) {
660                             importPath = ToscaDefaultImportHelper.addModelAsFilePrefix(importPath, toscaImportByModel.getModelId());
661                         }
662                         final Path entryPath = defsPath.resolve(importPath);
663                         writtenEntryPathList.add(entryPath);
664                         contentToMerge.put(entryPath, toscaImportByModel.getContent().getBytes(StandardCharsets.UTF_8));
665                     }
666                 } else {
667                     if (writtenEntryPathList.contains(defsPath.resolve(importPath))) {
668                         importPath = ToscaDefaultImportHelper.addModelAsFilePrefix(importPath, toscaImportByModel.getModelId());
669                     }
670                     final Path entryPath = defsPath.resolve(importPath);
671                     zipOutputStream.putNextEntry(new ZipEntry(entryPath.toString()));
672                     writtenEntryPathList.add(entryPath);
673                     final byte[] content = toscaImportByModel.getContent().getBytes(StandardCharsets.UTF_8);
674                     zipOutputStream.write(content, 0, content.length);
675                     zipOutputStream.closeEntry();
676                 }
677             }
678             if (!isSingleImportsFile) {
679                 byte[] mergingContent = new byte[0];
680                 for (Map.Entry<Path, byte[]> entry : contentToMerge.entrySet()) {
681                     if (ADDITIONAL_TYPE_DEFINITIONS.equals(Paths.get(String.valueOf(entry.getKey())).normalize().toString())) {
682                         mergingContent = mergeContent(mergingContent, entry.getValue());
683                     } else {
684                         final var zipEntry = new ZipEntry(entry.getKey().toString());
685                         zipOutputStream.putNextEntry(zipEntry);
686                         writtenEntryPathList.add(entry.getKey());
687                         mergingContent = mergeContent(mergingContent, entry.getValue());
688                         mergingContent = updateMergingContentFromDependencies(mergingContent, dependencies);
689                         zipOutputStream.write(mergingContent, 0, mergingContent.length);
690                         zipOutputStream.closeEntry();
691                     }
692                 }
693             }
694         } catch (final IOException e) {
695             LOGGER.error(String.valueOf(EcompLoggerErrorCode.BUSINESS_PROCESS_ERROR), CsarUtils.class.getName(),
696                 "Error while writing the schema files by model to the CSAR", e);
697             throw new ByResponseFormatComponentException(componentsUtils.getResponseFormat(ActionStatus.CSAR_TOSCA_IMPORTS_ERROR));
698         }
699     }
700
701     private byte[] updateMergingContentFromDependencies(final byte[] mergingContent, final List<Component> dependencies) {
702         final DumperOptions options = new DumperOptions();
703         options.setDefaultFlowStyle(FlowStyle.BLOCK);
704         final Yaml yaml = new Yaml(options);
705         final Map<String, Object> stringObjectMap = (Map<String, Object>) yaml.load(new String(mergingContent));
706         final Map<String, Object> nodeTypes = (Map<String, Object>) stringObjectMap.get("node_types");
707         for (final Component dependency : dependencies) {
708             final Map<String, Object> dependencyAsMap = yaml.load(yaml.dumpAsMap(dependency));
709             final String toscaResourceName = ((ResourceMetadataDataDefinition) dependency.getComponentMetadataDefinition()
710                     .getMetadataDataDefinition()).getToscaResourceName();
711             final Map<String, Object> nodeType = (Map<String, Object>) nodeTypes.get(toscaResourceName);
712             final Map<String, Object> propertiesFromDependency = (Map<String, Object>) ((List) dependencyAsMap.get("properties"))
713                     .stream().collect(Collectors.toMap(s -> ((Map<String, Object>) s).get("name"), s -> s));
714             if (MapUtils.isNotEmpty(nodeType) && MapUtils.isNotEmpty(propertiesFromDependency)) {
715                 final Map<String, Object> propertiesFromMergingContent = (Map<String, Object>) nodeType.get("properties");
716                 final Map<String, Object> updatedMap = updatePropertiesFromDependency(propertiesFromMergingContent, propertiesFromDependency);
717                 nodeType.replace("properties", updatedMap);
718                 nodeTypes.replace(toscaResourceName, nodeType);
719             }
720         }
721         stringObjectMap.replace("node_types", nodeTypes);
722         return yaml.dumpAsMap(stringObjectMap).getBytes();
723     }
724
725     private Map<String, Object> updatePropertiesFromDependency(final Map<String, Object> propertiesFromMergingContent,
726                                                                final Map<String, Object> propertiesFromDependency) {
727         final Map<String, Object> result = new HashMap<>();
728         for (final Entry<String, Object> entry : propertiesFromDependency.entrySet()) {
729             final Map<String, Object> propertiesMap = new HashMap<>();
730             final String key = entry.getKey();
731             final Object value = entry.getValue();
732             if (propertiesFromMergingContent instanceof Map) {
733                 final Object object = propertiesFromMergingContent.get(key);
734                 if (object instanceof Map) {
735                     ((Map<String, Object>) object).keySet().forEach(s ->
736                         propertiesMap.put(s, getValue(s, (Map<String, Object>) value))
737                     );
738                 } else {
739                     propertiesMap.putAll(createProperties(value));
740                 }
741             } else {
742                 propertiesMap.putAll(createProperties(value));
743             }
744             result.put(key, propertiesMap);
745         }
746         return result;
747     }
748
749     private Object getValue(final String key, Map<String, Object> value) {
750         final String mappedKey = mapKey(key);
751         if (mappedKey.equals("schemaType") && value.get(mappedKey) != null) {
752             return Collections.singletonMap("type", value.get(mappedKey));
753         }
754         return value.get(mappedKey);
755     }
756
757     private String mapKey(final String key) {
758         if (key.equals("entry_schema")) {
759             return "schemaType";
760         }
761         if (key.equals("default")) {
762             return "defaultValue";
763         }
764         return key;
765     }
766
767     @SuppressWarnings("unchecked")
768     private Map<String, Object> createProperties(final Object value) {
769         final Map<String, Object> propertiesMap = new HashMap<>();
770         propertiesMap.put("type", ((Map<String, Object>) value).get("type"));
771         propertiesMap.put("required", ((Map<String, Object>) value).get("required"));
772         final Object entrySchema = getValue("entry_schema", (Map<String, Object>) value);
773         if (entrySchema != null) {
774             propertiesMap.put("entry_schema", entrySchema);
775         }
776         return propertiesMap;
777     }
778
779     private byte[] mergeContent(final byte[] first, final byte[] second) {
780         byte[] merged = new byte[0];
781         final Map<String, Object> firstMap = new Yaml().load(new String(first));
782         final Map<String, Object> secondMap = new Yaml().load(new String(second));
783         if (MapUtils.isNotEmpty(secondMap)) {
784             final DumperOptions options = new DumperOptions();
785             options.setDefaultFlowStyle(FlowStyle.BLOCK);
786             final Yaml yaml = new Yaml(options);
787             for (final Entry<String, Object> secondMapEntry : secondMap.entrySet()) {
788                 final Map<String, Object> newMap = new HashMap<>();
789                 if (secondMapEntry.getKey().endsWith("_types")) {
790                     if (MapUtils.isNotEmpty(firstMap) && firstMap.containsKey(secondMapEntry.getKey())) {
791                         final Map<String, Object> secondMapEntryValue = (Map<String, Object>) secondMapEntry.getValue();
792                         final Map<String, Object> firstMapValue = (Map<String, Object>) firstMap.get(secondMapEntry.getKey());
793                         secondMapEntryValue.putAll(firstMapValue);
794                         newMap.put(secondMapEntry.getKey(), secondMapEntryValue);
795                     } else {
796                         newMap.put(secondMapEntry.getKey(), secondMapEntry.getValue());
797                     }
798                 } else {
799                     newMap.put(secondMapEntry.getKey(), secondMapEntry.getValue());
800                 }
801                 merged = Bytes.concat(merged, yaml.dumpAsMap(newMap).getBytes());
802             }
803         }
804         return merged;
805     }
806
807     private Either<CsarDefinition, ResponseFormat> collectComponentCsarDefinition(Component component) {
808         ComponentArtifacts componentArtifacts = new ComponentArtifacts();
809         Component updatedComponent = component;
810
811         //get service to receive the AII artifacts uploaded to the service
812         if (updatedComponent.getComponentType() == ComponentTypeEnum.SERVICE) {
813             Either<Service, StorageOperationStatus> getServiceResponse = toscaOperationFacade.getToscaElement(updatedComponent.getUniqueId());
814
815             if (getServiceResponse.isRight()) {
816                 ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(getServiceResponse.right().value());
817                 return Either.right(componentsUtils.getResponseFormat(actionStatus));
818             }
819
820             updatedComponent = getServiceResponse.left().value();
821         }
822
823         //find the artifacts of the main component, it would have its composed instances artifacts in a separate folder
824         ComponentTypeArtifacts componentInstanceArtifacts = new ComponentTypeArtifacts();
825         ArtifactsInfo artifactsInfo = collectComponentArtifacts(updatedComponent);
826         componentInstanceArtifacts.setComponentArtifacts(artifactsInfo);
827         componentArtifacts.setMainTypeAndCIArtifacts(componentInstanceArtifacts);
828
829         Map<String, ComponentTypeArtifacts> resourceTypeArtifacts = componentArtifacts
830             .getComponentTypeArtifacts();    //artifacts mapped by the component type(tosca name+version)
831         //get the component instances
832         List<ComponentInstance> componentInstances = updatedComponent.getComponentInstances();
833         if (componentInstances != null) {
834             for (ComponentInstance componentInstance : componentInstances) {
835                 //call recursive to find artifacts for all the path
836                 Either<Boolean, ResponseFormat> collectComponentInstanceArtifacts = collectComponentInstanceArtifacts(
837                     updatedComponent, componentInstance, resourceTypeArtifacts, componentInstanceArtifacts);
838                 if (collectComponentInstanceArtifacts.isRight()) {
839                     return Either.right(collectComponentInstanceArtifacts.right().value());
840                 }
841             }
842         }
843
844         if (LOGGER.isDebugEnabled()) {
845             printResult(componentArtifacts, updatedComponent.getName());
846         }
847
848         return Either.left(new CsarDefinition(componentArtifacts));
849     }
850
851     private void printResult(ComponentArtifacts componentArtifacts, String name) {
852         StringBuilder result = new StringBuilder();
853         result.append("Artifacts of main component " + name + "\n");
854         ComponentTypeArtifacts componentInstanceArtifacts = componentArtifacts.getMainTypeAndCIArtifacts();
855         printArtifacts(componentInstanceArtifacts);
856         result.append("Type Artifacts\n");
857         for (Map.Entry<String, ComponentTypeArtifacts> typeArtifacts : componentArtifacts.getComponentTypeArtifacts().entrySet()) {
858             result.append("Folder " + typeArtifacts.getKey() + "\n");
859             result.append(printArtifacts(typeArtifacts.getValue()));
860         }
861
862         if (LOGGER.isDebugEnabled()) {
863             LOGGER.debug(result.toString());
864         }
865     }
866
867     private String printArtifacts(ComponentTypeArtifacts componentInstanceArtifacts) {
868         StringBuilder result = new StringBuilder();
869         ArtifactsInfo artifactsInfo = componentInstanceArtifacts.getComponentArtifacts();
870         Map<ArtifactGroupTypeEnum, Map<String, List<ArtifactDefinition>>> componentArtifacts = artifactsInfo.getArtifactsInfo();
871         printArtifacts(componentArtifacts);
872         result = result.append("Resources\n");
873         for (Map.Entry<String, ArtifactsInfo> resourceInstance : componentInstanceArtifacts.getComponentInstancesArtifacts().entrySet()) {
874             result.append("Folder" + resourceInstance.getKey() + "\n");
875             result.append(printArtifacts(resourceInstance.getValue().getArtifactsInfo()));
876         }
877
878         return result.toString();
879     }
880
881     private String printArtifacts(Map<ArtifactGroupTypeEnum, Map<String, List<ArtifactDefinition>>> componetArtifacts) {
882         StringBuilder result = new StringBuilder();
883         for (Map.Entry<ArtifactGroupTypeEnum, Map<String, List<ArtifactDefinition>>> artifactGroup : componetArtifacts.entrySet()) {
884             result.append("    " + artifactGroup.getKey().getType());
885             for (Map.Entry<String, List<ArtifactDefinition>> groupArtifacts : artifactGroup.getValue().entrySet()) {
886                 result.append("        " + groupArtifacts.getKey());
887                 for (ArtifactDefinition artifact : groupArtifacts.getValue()) {
888                     result.append("            " + artifact.getArtifactDisplayName());
889                 }
890             }
891         }
892
893         return result.toString();
894     }
895
896     private Either<Boolean, ResponseFormat> collectComponentInstanceArtifacts(Component parentComponent, ComponentInstance componentInstance,
897                                                                               Map<String, ComponentTypeArtifacts> resourcesTypeArtifacts,
898                                                                               ComponentTypeArtifacts instanceArtifactsLocation) {
899         //1. get the component instance component
900         String componentUid;
901         if (componentInstance.getOriginType() == OriginTypeEnum.ServiceProxy) {
902             componentUid = componentInstance.getSourceModelUid();
903         } else {
904             componentUid = componentInstance.getComponentUid();
905         }
906         Either<Component, StorageOperationStatus> component = toscaOperationFacade.getToscaElement(componentUid);
907         if (component.isRight()) {
908             LOGGER.error("Failed to fetch resource with id {} for instance {}", componentUid, parentComponent.getUUID());
909             return Either.right(componentsUtils.getResponseFormat(ActionStatus.ASSET_NOT_FOUND_DURING_CSAR_CREATION,
910                 parentComponent.getComponentType().getValue(), parentComponent.getUUID(),
911                 componentInstance.getOriginType().getComponentType().getValue(), componentUid));
912         }
913         Component fetchedComponent = component.left().value();
914
915         //2. fill the artifacts for the current component parent type
916         String toscaComponentName =
917             componentInstance.getToscaComponentName() + "_v" + componentInstance.getComponentVersion();
918
919         // if there are no artifacts for this component type we need to fetch and build them
920         ComponentTypeArtifacts componentParentArtifacts = Optional
921             .ofNullable(resourcesTypeArtifacts.get(toscaComponentName))
922             .orElseGet(() -> collectComponentTypeArtifacts(fetchedComponent));
923
924         if (componentParentArtifacts.getComponentArtifacts().isNotEmpty()) {
925             resourcesTypeArtifacts.put(toscaComponentName, componentParentArtifacts);
926         }
927
928         //3. find the artifacts specific to the instance
929         Map<String, List<ArtifactDefinition>> componentInstanceSpecificInformationalArtifacts =
930             getComponentInstanceSpecificArtifacts(componentInstance.getArtifacts(),
931                 componentParentArtifacts.getComponentArtifacts().getArtifactsInfo(), ArtifactGroupTypeEnum.INFORMATIONAL);
932         Map<String, List<ArtifactDefinition>> componentInstanceSpecificDeploymentArtifacts =
933             getComponentInstanceSpecificArtifacts(componentInstance.getDeploymentArtifacts(),
934                 componentParentArtifacts.getComponentArtifacts().getArtifactsInfo(), ArtifactGroupTypeEnum.DEPLOYMENT);
935
936         //4. add the instances artifacts to the component type
937         ArtifactsInfo artifactsInfo = new ArtifactsInfo();
938         if (!componentInstanceSpecificInformationalArtifacts.isEmpty()) {
939             artifactsInfo.addArtifactsToGroup(ArtifactGroupTypeEnum.INFORMATIONAL, componentInstanceSpecificInformationalArtifacts);
940         }
941         if (!componentInstanceSpecificDeploymentArtifacts.isEmpty()) {
942             artifactsInfo.addArtifactsToGroup(ArtifactGroupTypeEnum.DEPLOYMENT, componentInstanceSpecificDeploymentArtifacts);
943         }
944         if (!artifactsInfo.isEmpty()) {
945             instanceArtifactsLocation.addComponentInstancesArtifacts(componentInstance.getNormalizedName(), artifactsInfo);
946         }
947
948         //5. do the same for all the component instances
949         List<ComponentInstance> componentInstances = fetchedComponent.getComponentInstances();
950         if (componentInstances != null) {
951             for (ComponentInstance childComponentInstance : componentInstances) {
952                 Either<Boolean, ResponseFormat> collectComponentInstanceArtifacts = collectComponentInstanceArtifacts(
953                     fetchedComponent, childComponentInstance, resourcesTypeArtifacts, componentParentArtifacts);
954                 if (collectComponentInstanceArtifacts.isRight()) {
955                     return collectComponentInstanceArtifacts;
956                 }
957             }
958         }
959
960         return Either.left(true);
961     }
962
963     private Map<String, List<ArtifactDefinition>> getComponentInstanceSpecificArtifacts(Map<String, ArtifactDefinition> componentArtifacts,
964                                                                                         Map<ArtifactGroupTypeEnum, Map<String, List<ArtifactDefinition>>> componentTypeArtifacts,
965                                                                                         ArtifactGroupTypeEnum artifactGroupTypeEnum) {
966         Map<String, List<ArtifactDefinition>> parentArtifacts = componentTypeArtifacts
967             .get(artifactGroupTypeEnum);    //the artfiacts of the component itself and not the instance
968
969         Map<String, List<ArtifactDefinition>> artifactsByTypeOfComponentInstance = new HashMap<>();
970         if (componentArtifacts != null) {
971             for (ArtifactDefinition artifact : componentArtifacts.values()) {
972                 List<ArtifactDefinition> parentArtifactsByType = null;
973                 if (parentArtifacts != null) {
974                     parentArtifactsByType = parentArtifacts.get(artifact.getArtifactType());
975                 }
976                 //the artifact is of instance
977                 if (parentArtifactsByType == null || !parentArtifactsByType.contains(artifact)) {
978                     List<ArtifactDefinition> typeArtifacts = artifactsByTypeOfComponentInstance.get(artifact.getArtifactType());
979                     if (typeArtifacts == null) {
980                         typeArtifacts = new ArrayList<>();
981                         artifactsByTypeOfComponentInstance.put(artifact.getArtifactType(), typeArtifacts);
982                     }
983                     typeArtifacts.add(artifact);
984                 }
985             }
986         }
987
988         return artifactsByTypeOfComponentInstance;
989     }
990
991     private ComponentTypeArtifacts collectComponentTypeArtifacts(Component fetchedComponent) {
992         ArtifactsInfo componentArtifacts = collectComponentArtifacts(fetchedComponent);
993         ComponentTypeArtifacts componentArtifactsInfo = new ComponentTypeArtifacts();
994         if (componentArtifacts.isNotEmpty()) {
995             componentArtifactsInfo.setComponentArtifacts(componentArtifacts);
996         }
997         return componentArtifactsInfo;
998     }
999
1000     private ArtifactsInfo collectComponentArtifacts(Component component) {
1001         Map<String, ArtifactDefinition> informationalArtifacts = component.getArtifacts();
1002         Map<String, List<ArtifactDefinition>> informationalArtifactsByType = collectGroupArtifacts(informationalArtifacts);
1003         Map<String, ArtifactDefinition> deploymentArtifacts = component.getDeploymentArtifacts();
1004         Map<String, List<ArtifactDefinition>> deploymentArtifactsByType = collectGroupArtifacts(deploymentArtifacts);
1005         ArtifactsInfo artifactsInfo = new ArtifactsInfo();
1006         if (!informationalArtifactsByType.isEmpty()) {
1007             artifactsInfo.addArtifactsToGroup(ArtifactGroupTypeEnum.INFORMATIONAL, informationalArtifactsByType);
1008         }
1009         if (!deploymentArtifactsByType.isEmpty()) {
1010             artifactsInfo.addArtifactsToGroup(ArtifactGroupTypeEnum.DEPLOYMENT, deploymentArtifactsByType);
1011         }
1012
1013         return artifactsInfo;
1014     }
1015
1016     private Map<String, List<ArtifactDefinition>> collectGroupArtifacts(
1017         final Map<String, ArtifactDefinition> componentArtifacts) {
1018         final Map<String, List<ArtifactDefinition>> artifactsByType = new HashMap<>();
1019         for (final ArtifactDefinition artifact : componentArtifacts.values()) {
1020             if (artifact.getArtifactUUID() != null) {
1021                 artifactsByType.putIfAbsent(artifact.getArtifactType(), new ArrayList<>());
1022                 final List<ArtifactDefinition> typeArtifacts = artifactsByType.get(artifact.getArtifactType());
1023                 typeArtifacts.add(artifact);
1024             }
1025         }
1026         return artifactsByType;
1027     }
1028
1029     private Either<ZipOutputStream, ResponseFormat> writeAllFilesToCsar(Component mainComponent, CsarDefinition csarDefinition,
1030                                                                         ZipOutputStream zipstream, boolean isInCertificationRequest)
1031         throws IOException {
1032         ComponentArtifacts componentArtifacts = csarDefinition.getComponentArtifacts();
1033         Either<ZipOutputStream, ResponseFormat> writeComponentArtifactsToSpecifiedPath = writeComponentArtifactsToSpecifiedPath(mainComponent,
1034             componentArtifacts, zipstream, ARTIFACTS_PATH, isInCertificationRequest);
1035         if (writeComponentArtifactsToSpecifiedPath.isRight()) {
1036             return Either.right(writeComponentArtifactsToSpecifiedPath.right().value());
1037         }
1038         ComponentTypeArtifacts mainTypeAndCIArtifacts = componentArtifacts.getMainTypeAndCIArtifacts();
1039         writeComponentArtifactsToSpecifiedPath = writeArtifactsInfoToSpecifiedPath(mainComponent, mainTypeAndCIArtifacts.getComponentArtifacts(),
1040             zipstream, ARTIFACTS_PATH, isInCertificationRequest);
1041         if (writeComponentArtifactsToSpecifiedPath.isRight()) {
1042             return Either.right(writeComponentArtifactsToSpecifiedPath.right().value());
1043         }
1044         Map<String, ArtifactsInfo> componentInstancesArtifacts = mainTypeAndCIArtifacts.getComponentInstancesArtifacts();
1045         String currentPath = ARTIFACTS_PATH + RESOURCES_PATH;
1046         for (String keyAssetName : componentInstancesArtifacts.keySet()) {
1047             ArtifactsInfo artifactsInfo = componentInstancesArtifacts.get(keyAssetName);
1048             String pathWithAssetName = currentPath + keyAssetName + PATH_DELIMITER;
1049             writeComponentArtifactsToSpecifiedPath = writeArtifactsInfoToSpecifiedPath(mainComponent, artifactsInfo, zipstream, pathWithAssetName,
1050                 isInCertificationRequest);
1051             if (writeComponentArtifactsToSpecifiedPath.isRight()) {
1052                 return Either.right(writeComponentArtifactsToSpecifiedPath.right().value());
1053             }
1054         }
1055         writeComponentArtifactsToSpecifiedPath = writeOperationsArtifactsToCsar(mainComponent, zipstream);
1056         if (writeComponentArtifactsToSpecifiedPath.isRight()) {
1057             return Either.right(writeComponentArtifactsToSpecifiedPath.right().value());
1058         }
1059         return Either.left(zipstream);
1060     }
1061
1062     private Either<ZipOutputStream, ResponseFormat> writeOperationsArtifactsToCsar(Component component, ZipOutputStream zipstream) {
1063         if (checkComponentBeforeOperation(component)) {
1064             return Either.left(zipstream);
1065         }
1066         for (Map.Entry<String, InterfaceDefinition> interfaceEntry : ((Resource) component).getInterfaces().entrySet()) {
1067             for (OperationDataDefinition operation : interfaceEntry.getValue().getOperations().values()) {
1068                 try {
1069                     if (checkComponentBeforeWrite(component, interfaceEntry, operation)) {
1070                         continue;
1071                     }
1072                     final String artifactUUID = operation.getImplementation().getArtifactUUID();
1073                     if (artifactUUID == null) {
1074                         continue;
1075                     }
1076                     final Either<byte[], ActionStatus> artifactFromCassandra = getFromCassandra(artifactUUID);
1077                     final String artifactName = operation.getImplementation().getArtifactName();
1078                     if (artifactFromCassandra.isRight()) {
1079                         LOGGER.error(ARTIFACT_NAME_UNIQUE_ID, artifactName, artifactUUID);
1080                         LOGGER.error("Failed to get {} payload from DB reason: {}", artifactName, artifactFromCassandra.right().value());
1081                         return Either.right(componentsUtils.getResponseFormat(
1082                             ARTIFACT_PAYLOAD_NOT_FOUND_DURING_CSAR_CREATION, "Resource", component.getUniqueId(), artifactName, artifactUUID));
1083                     }
1084                     zipstream.putNextEntry(new ZipEntry(OperationArtifactUtil.createOperationArtifactPath(component, null, operation, true)));
1085                     zipstream.write(artifactFromCassandra.left().value());
1086                 } catch (IOException e) {
1087                     LOGGER.error("Component Name {},  Interface Name {}, Operation Name {}", component.getNormalizedName(), interfaceEntry.getKey(),
1088                         operation.getName());
1089                     LOGGER.error("Error while writing the operation's artifacts to the CSAR", e);
1090                     return Either.right(componentsUtils.getResponseFormat(ERROR_DURING_CSAR_CREATION, "Resource", component.getUniqueId()));
1091                 }
1092             }
1093         }
1094         return Either.left(zipstream);
1095     }
1096
1097     private boolean checkComponentBeforeWrite(Component component, Map.Entry<String, InterfaceDefinition> interfaceEntry,
1098                                               OperationDataDefinition operation) {
1099         final ArtifactDataDefinition implementation = operation.getImplementation();
1100         if (implementation == null) {
1101             LOGGER.debug("Component Name {}, Interface Id {}, Operation Name {} - no Operation Implementation found", component.getNormalizedName(),
1102                 interfaceEntry.getValue().getUniqueId(), operation.getName());
1103             return true;
1104         }
1105         final String artifactName = implementation.getArtifactName();
1106         if (artifactName == null) {
1107             LOGGER.debug("Component Name {}, Interface Id {}, Operation Name {} - no artifact found", component.getNormalizedName(),
1108                 interfaceEntry.getValue().getUniqueId(), operation.getName());
1109             return true;
1110         }
1111         if (OperationArtifactUtil.artifactNameIsALiteralValue(artifactName)) {
1112             LOGGER.debug("Component Name {}, Interface Id {}, Operation Name {} - artifact name is a literal value rather than an SDC artifact",
1113                 component.getNormalizedName(), interfaceEntry.getValue().getUniqueId(), operation.getName());
1114             return true;
1115         }
1116         return false;
1117     }
1118
1119     private boolean checkComponentBeforeOperation(Component component) {
1120         if (component instanceof Service) {
1121             return true;
1122         }
1123         if (Objects.isNull(((Resource) component).getInterfaces())) {
1124             LOGGER.debug("Component Name {}- no interfaces found", component.getNormalizedName());
1125             return true;
1126         }
1127         return false;
1128     }
1129
1130     private Either<ZipOutputStream, ResponseFormat> writeArtifactsInfoToSpecifiedPath(final Component mainComponent,
1131                                                                                       final ArtifactsInfo currArtifactsInfo,
1132                                                                                       final ZipOutputStream zip, final String path,
1133                                                                                       final boolean isInCertificationRequest) throws IOException {
1134         final Map<ArtifactGroupTypeEnum, Map<String, List<ArtifactDefinition>>> artifactsInfo = currArtifactsInfo.getArtifactsInfo();
1135         for (final ArtifactGroupTypeEnum artifactGroupTypeEnum : artifactsInfo.keySet()) {
1136             final String groupTypeFolder = path + WordUtils.capitalizeFully(artifactGroupTypeEnum.getType()) + PATH_DELIMITER;
1137             final Map<String, List<ArtifactDefinition>> artifactTypesMap = artifactsInfo.get(artifactGroupTypeEnum);
1138             for (final String artifactType : artifactTypesMap.keySet()) {
1139                 final List<ArtifactDefinition> artifactDefinitionList = artifactTypesMap.get(artifactType);
1140                 String artifactTypeFolder = groupTypeFolder + artifactType + PATH_DELIMITER;
1141                 if (ArtifactTypeEnum.WORKFLOW.getType().equals(artifactType) && path.contains(ARTIFACTS_PATH + RESOURCES_PATH)) {
1142                     // Ignore this packaging as BPMN artifacts needs to be packaged in different manner
1143                     continue;
1144                 }
1145                 if (ArtifactTypeEnum.WORKFLOW.getType().equals(artifactType)) {
1146                     artifactTypeFolder += OperationArtifactUtil.BPMN_ARTIFACT_PATH + File.separator;
1147                 } else if (ArtifactTypeEnum.ONBOARDED_PACKAGE.getType().equals(artifactType)) {
1148                     // renaming legacy folder ONBOARDED_PACKAGE to the new folder ETSI_PACKAGE
1149                     artifactTypeFolder = artifactTypeFolder
1150                         .replace(ArtifactTypeEnum.ONBOARDED_PACKAGE.getType(), ArtifactTypeEnum.ETSI_PACKAGE.getType());
1151                 }
1152                 // TODO: We should not do this but in order to keep this refactoring small enough,
1153
1154                 // we'll leave this as is for now
1155                 List<ArtifactDefinition> collect = filterArtifactDefinitionToZip(mainComponent, artifactDefinitionList, isInCertificationRequest)
1156                     .collect(Collectors.toList());
1157                 for (ArtifactDefinition ad : collect) {
1158                     zip.putNextEntry(new ZipEntry(artifactTypeFolder + ad.getArtifactName()));
1159                     zip.write(ad.getPayloadData());
1160                 }
1161             }
1162         }
1163         return Either.left(zip);
1164     }
1165
1166     private Stream<ArtifactDefinition> filterArtifactDefinitionToZip(Component mainComponent, List<ArtifactDefinition> artifactDefinitionList,
1167                                                                      boolean isInCertificationRequest) {
1168         return artifactDefinitionList.stream().filter(shouldBeInZip(isInCertificationRequest, mainComponent)).map(this::fetchPayLoadData)
1169             .filter(Either::isLeft).map(e -> e.left().value());
1170     }
1171
1172     private Predicate<ArtifactDefinition> shouldBeInZip(boolean isInCertificationRequest, Component component) {
1173         return artifactDefinition -> !(!isInCertificationRequest && component.isService() && artifactDefinition.isHeatEnvType() || artifactDefinition
1174             .hasNoMandatoryEsId());
1175     }
1176
1177     private Either<ArtifactDefinition, ActionStatus> fetchPayLoadData(ArtifactDefinition ad) {
1178         byte[] payloadData = ad.getPayloadData();
1179         if (payloadData == null) {
1180             return getFromCassandra(ad.getEsId()).left().map(pd -> {
1181                 ad.setPayload(pd);
1182                 return ad;
1183             }).right().map(as -> {
1184                 LOGGER.debug(ARTIFACT_NAME_UNIQUE_ID, ad.getArtifactName(), ad.getUniqueId());
1185                 LOGGER.debug("Failed to get {} payload from DB reason: {}", ad.getArtifactName(), as);
1186                 return as;
1187             });
1188         } else {
1189             return Either.left(ad);
1190         }
1191     }
1192
1193     private Either<ZipOutputStream, ResponseFormat> writeComponentArtifactsToSpecifiedPath(Component mainComponent,
1194                                                                                            ComponentArtifacts componentArtifacts,
1195                                                                                            ZipOutputStream zipstream, String currentPath,
1196                                                                                            boolean isInCertificationRequest) throws IOException {
1197         Map<String, ComponentTypeArtifacts> componentTypeArtifacts = componentArtifacts.getComponentTypeArtifacts();
1198         //Keys are defined:
1199
1200         //<Inner Asset TOSCA name (e.g. VFC name)> folder name: <Inner Asset TOSCA name (e.g. VFC name)>_v<version>.
1201
1202         //E.g. "org.openecomp.resource.vf.vipr_atm_v1.0"
1203         Set<String> componentTypeArtifactsKeys = componentTypeArtifacts.keySet();
1204         for (String keyAssetName : componentTypeArtifactsKeys) {
1205             ComponentTypeArtifacts componentInstanceArtifacts = componentTypeArtifacts.get(keyAssetName);
1206             ArtifactsInfo componentArtifacts2 = componentInstanceArtifacts.getComponentArtifacts();
1207             String pathWithAssetName = currentPath + keyAssetName + PATH_DELIMITER;
1208             Either<ZipOutputStream, ResponseFormat> writeArtifactsInfoToSpecifiedPath = writeArtifactsInfoToSpecifiedPath(mainComponent,
1209                 componentArtifacts2, zipstream, pathWithAssetName, isInCertificationRequest);
1210             if (writeArtifactsInfoToSpecifiedPath.isRight()) {
1211                 return writeArtifactsInfoToSpecifiedPath;
1212             }
1213         }
1214         return Either.left(zipstream);
1215     }
1216
1217     private Either<ToscaRepresentation, ResponseFormat> generateToscaRepresentation(Component component, boolean isSkipImports) {
1218         return toscaExportUtils.exportComponent(component, isSkipImports).right().map(toscaError -> {
1219             LOGGER.debug("exportComponent failed {}", toscaError);
1220             return componentsUtils.getResponseFormat(componentsUtils.convertFromToscaError(toscaError));
1221         });
1222     }
1223
1224     private String createToscaBlock0(String metaFileVersion, String csarVersion, String createdBy, String entryDef, boolean isAsdPackage,
1225                                      String definitionsPath) {
1226         final String block0template = "TOSCA-Meta-File-Version: %s\nCSAR-Version: %s\nCreated-By: %s\nEntry-Definitions: "
1227             + definitionsPath + "%s\n%s\nName: csar.meta\nContent-Type: text/plain\n";
1228         return String.format(block0template, metaFileVersion, csarVersion, createdBy, entryDef, isAsdPackage ? "entry_definition_type: asd" : "");
1229     }
1230
1231     private class CsarDefinition {
1232
1233         private ComponentArtifacts componentArtifacts;
1234
1235         // add list of tosca artifacts and meta describes CSAR zip root
1236         public CsarDefinition(ComponentArtifacts componentArtifacts) {
1237             this.componentArtifacts = componentArtifacts;
1238         }
1239
1240         public ComponentArtifacts getComponentArtifacts() {
1241             return componentArtifacts;
1242         }
1243     }
1244
1245     private class ComponentArtifacts {
1246
1247         //artifacts of the component and CI's artifacts contained in it's composition (represents Informational, Deployment & Resource folders of main component)
1248         private ComponentTypeArtifacts mainTypeAndCIArtifacts;
1249         //artifacts of all component types mapped by their tosca name
1250         private Map<String, ComponentTypeArtifacts> componentTypeArtifacts;
1251
1252         public ComponentArtifacts() {
1253             mainTypeAndCIArtifacts = new ComponentTypeArtifacts();
1254             componentTypeArtifacts = new HashMap<>();
1255         }
1256
1257         public ComponentTypeArtifacts getMainTypeAndCIArtifacts() {
1258             return mainTypeAndCIArtifacts;
1259         }
1260
1261         public void setMainTypeAndCIArtifacts(ComponentTypeArtifacts componentInstanceArtifacts) {
1262             this.mainTypeAndCIArtifacts = componentInstanceArtifacts;
1263         }
1264
1265         public Map<String, ComponentTypeArtifacts> getComponentTypeArtifacts() {
1266             return componentTypeArtifacts;
1267         }
1268     }
1269
1270     /**
1271      * The artifacts of the component and of all its composed instances
1272      */
1273     private class ComponentTypeArtifacts {
1274
1275         private ArtifactsInfo componentArtifacts;    //component artifacts (describes the Informational Deployment folders)
1276
1277         private Map<String, ArtifactsInfo> componentInstancesArtifacts;        //artifacts of the composed instances mapped by the resourceInstance normalized name (describes the Resources folder)
1278
1279         public ComponentTypeArtifacts() {
1280             componentArtifacts = new ArtifactsInfo();
1281             componentInstancesArtifacts = new HashMap<>();
1282         }
1283
1284         public ArtifactsInfo getComponentArtifacts() {
1285             return componentArtifacts;
1286         }
1287
1288         public void setComponentArtifacts(ArtifactsInfo artifactsInfo) {
1289             this.componentArtifacts = artifactsInfo;
1290         }
1291
1292         public Map<String, ArtifactsInfo> getComponentInstancesArtifacts() {
1293             return componentInstancesArtifacts;
1294         }
1295
1296         public void addComponentInstancesArtifacts(String normalizedName, ArtifactsInfo artifactsInfo) {
1297             componentInstancesArtifacts.put(normalizedName, artifactsInfo);
1298         }
1299     }
1300
1301     /**
1302      * The artifacts Definition saved by their structure
1303      */
1304     private class ArtifactsInfo {
1305         //Key is the type of artifacts(Informational/Deployment)
1306
1307         //Value is a map between an artifact type and a list of all artifacts of this type
1308         private Map<ArtifactGroupTypeEnum, Map<String, List<ArtifactDefinition>>> artifactsInfoField;
1309
1310         public ArtifactsInfo() {
1311             this.artifactsInfoField = new EnumMap<>(ArtifactGroupTypeEnum.class);
1312         }
1313
1314         public Map<ArtifactGroupTypeEnum, Map<String, List<ArtifactDefinition>>> getArtifactsInfo() {
1315             return artifactsInfoField;
1316         }
1317
1318         public void addArtifactsToGroup(ArtifactGroupTypeEnum artifactGroup, Map<String, List<ArtifactDefinition>> artifactsDefinition) {
1319             if (artifactsInfoField.get(artifactGroup) == null) {
1320                 artifactsInfoField.put(artifactGroup, artifactsDefinition);
1321             } else {
1322                 Map<String, List<ArtifactDefinition>> artifactTypeEnumListMap = artifactsInfoField.get(artifactGroup);
1323                 artifactTypeEnumListMap.putAll(artifactsDefinition);
1324                 artifactsInfoField.put(artifactGroup, artifactTypeEnumListMap);
1325             }
1326         }
1327
1328         public boolean isEmpty() {
1329             return artifactsInfoField.isEmpty();
1330         }
1331
1332         public boolean isNotEmpty() {
1333             return !isEmpty();
1334         }
1335     }
1336
1337     public static class ToscaErrorException extends Exception {
1338
1339         ToscaErrorException(ToscaError error) {
1340             super("Error while exporting component's interface (toscaError:" + error + ")");
1341         }
1342     }
1343
1344
1345 }