Catalog alignment
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / components / impl / ResourceImportManager.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  * Modifications copyright (c) 2019 Nokia
20  * ================================================================================
21  */
22
23 package org.openecomp.sdc.be.components.impl;
24
25 import fj.data.Either;
26 import org.apache.commons.lang3.StringUtils;
27 import org.apache.commons.lang3.tuple.ImmutablePair;
28 import org.openecomp.sdc.be.auditing.api.AuditEventFactory;
29 import org.openecomp.sdc.be.auditing.impl.AuditingManager;
30 import org.openecomp.sdc.be.auditing.impl.resourceadmin.AuditImportResourceAdminEventFactory;
31 import org.openecomp.sdc.be.components.csar.CsarInfo;
32 import org.openecomp.sdc.be.components.impl.ArtifactsBusinessLogic.ArtifactOperationEnum;
33 import org.openecomp.sdc.be.components.impl.ImportUtils.Constants;
34 import org.openecomp.sdc.be.components.impl.ImportUtils.ResultStatusEnum;
35 import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
36 import org.openecomp.sdc.be.components.impl.exceptions.ComponentException;
37 import org.openecomp.sdc.be.components.lifecycle.LifecycleChangeInfoWithAction;
38 import org.openecomp.sdc.be.config.BeEcompErrorManager;
39 import org.openecomp.sdc.be.config.BeEcompErrorManager.ErrorSeverity;
40 import org.openecomp.sdc.be.dao.api.ActionStatus;
41 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
42 import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields;
43 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
44 import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
45 import org.openecomp.sdc.be.impl.ComponentsUtils;
46 import org.openecomp.sdc.be.impl.WebAppContextWrapper;
47 import org.openecomp.sdc.be.model.ArtifactDefinition;
48 import org.openecomp.sdc.be.model.CapabilityDefinition;
49 import org.openecomp.sdc.be.model.ComponentInstanceProperty;
50 import org.openecomp.sdc.be.model.InterfaceDefinition;
51 import org.openecomp.sdc.be.model.LifecycleStateEnum;
52 import org.openecomp.sdc.be.model.PropertyDefinition;
53 import org.openecomp.sdc.be.model.RequirementDefinition;
54 import org.openecomp.sdc.be.model.Resource;
55 import org.openecomp.sdc.be.model.UploadResourceInfo;
56 import org.openecomp.sdc.be.model.User;
57 import org.openecomp.sdc.be.model.category.CategoryDefinition;
58 import org.openecomp.sdc.be.model.category.SubCategoryDefinition;
59 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ToscaOperationFacade;
60 import org.openecomp.sdc.be.model.operations.api.IGraphLockOperation;
61 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
62 import org.openecomp.sdc.be.model.operations.impl.CapabilityTypeOperation;
63 import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
64 import org.openecomp.sdc.be.resources.data.auditing.model.CommonAuditData;
65 import org.openecomp.sdc.be.resources.data.auditing.model.ResourceCommonInfo;
66 import org.openecomp.sdc.be.resources.data.auditing.model.ResourceVersionInfo;
67 import org.openecomp.sdc.be.utils.TypeUtils;
68 import org.openecomp.sdc.common.log.wrappers.Logger;
69 import org.openecomp.sdc.common.util.ThreadLocalsHolder;
70 import org.openecomp.sdc.common.util.ValidationUtils;
71 import org.openecomp.sdc.exception.ResponseFormat;
72 import org.springframework.beans.factory.annotation.Autowired;
73 import org.springframework.stereotype.Component;
74 import org.springframework.web.context.WebApplicationContext;
75 import org.yaml.snakeyaml.Yaml;
76
77 import javax.servlet.ServletContext;
78 import java.util.ArrayList;
79 import java.util.Arrays;
80 import java.util.HashMap;
81 import java.util.HashSet;
82 import java.util.Iterator;
83 import java.util.List;
84 import java.util.Map;
85 import java.util.Map.Entry;
86 import java.util.Set;
87 import java.util.function.Function;
88 import java.util.regex.Pattern;
89 import java.util.stream.Collectors;
90
91 @Component("resourceImportManager")
92 public class ResourceImportManager {
93     static final Pattern PROPERTY_NAME_PATTERN_IGNORE_LENGTH = Pattern.compile("[\\w\\-\\_\\d\\:]+");
94
95     private ServletContext servletContext;
96
97     private AuditingManager auditingManager;
98     private ResourceBusinessLogic resourceBusinessLogic;
99     private IGraphLockOperation graphLockOperation;
100     protected ToscaOperationFacade toscaOperationFacade;
101
102     protected final ComponentsUtils componentsUtils;
103     private final CapabilityTypeOperation capabilityTypeOperation;
104
105     private ResponseFormatManager responseFormatManager;
106
107     private static final Logger log = Logger.getLogger(ResourceImportManager.class);
108
109     @Autowired
110     public ResourceImportManager(ComponentsUtils componentsUtils, CapabilityTypeOperation capabilityTypeOperation) {
111         this.componentsUtils = componentsUtils;
112         this.capabilityTypeOperation = capabilityTypeOperation;
113     }
114
115     @Autowired
116     public void setToscaOperationFacade(ToscaOperationFacade toscaOperationFacade) {
117         this.toscaOperationFacade = toscaOperationFacade;
118     }
119
120     public ImmutablePair<Resource, ActionStatus> importNormativeResource(String resourceYml, UploadResourceInfo resourceMetaData, User creator, boolean createNewVersion, boolean needLock) {
121
122         LifecycleChangeInfoWithAction lifecycleChangeInfo = new LifecycleChangeInfoWithAction();
123         lifecycleChangeInfo.setUserRemarks("certification on import");
124         Function<Resource, Boolean> validator = resource -> resourceBusinessLogic.validatePropertiesDefaultValues(resource);
125
126         return importCertifiedResource(resourceYml, resourceMetaData, creator, validator, lifecycleChangeInfo, false, createNewVersion, needLock, null, null, false, null, null, false);
127     }
128
129     public ImmutablePair<Resource, ActionStatus> importNormativeResourceFromCsar(String resourceYml, UploadResourceInfo resourceMetaData, User creator, boolean createNewVersion, boolean needLock) {
130
131         LifecycleChangeInfoWithAction lifecycleChangeInfo = new LifecycleChangeInfoWithAction();
132         lifecycleChangeInfo.setUserRemarks("certification on import");
133         Function<Resource, Boolean> validator = resource -> resourceBusinessLogic.validatePropertiesDefaultValues(resource);
134
135         return importCertifiedResource(resourceYml, resourceMetaData, creator, validator, lifecycleChangeInfo, false, createNewVersion, needLock, null, null, false, null, null, false);
136     }
137
138     public ImmutablePair<Resource, ActionStatus> importCertifiedResource(String resourceYml, UploadResourceInfo resourceMetaData, User creator,
139                                                                          Function<Resource, Boolean> validationFunction,
140                                                                          LifecycleChangeInfoWithAction lifecycleChangeInfo, boolean isInTransaction, boolean createNewVersion, boolean needLock, Map<ArtifactOperationEnum, List<ArtifactDefinition>> nodeTypeArtifactsToHandle, List<ArtifactDefinition> nodeTypesNewCreatedArtifacts, boolean forceCertificationAllowed, CsarInfo csarInfo, String nodeName, boolean isNested) {
141         Resource resource = new Resource();
142         ImmutablePair<Resource, ActionStatus> responsePair = new ImmutablePair<>(resource, ActionStatus.CREATED);
143         Either<ImmutablePair<Resource, ActionStatus>, ResponseFormat> response = Either.left(responsePair);
144
145         String latestCertifiedResourceId = null;
146         try {
147             boolean shouldBeCertified = nodeTypeArtifactsToHandle == null || nodeTypeArtifactsToHandle.isEmpty();
148             setConstantMetaData(resource, shouldBeCertified);
149             setMetaDataFromJson(resourceMetaData, resource);
150
151             populateResourceFromYaml(resourceYml, resource);
152
153             Boolean isValidResource = validationFunction.apply(resource);
154                 if (!createNewVersion) {
155                     Either<Resource, StorageOperationStatus> latestByName = toscaOperationFacade.getLatestByName(resource.getName());
156                     if (latestByName.isLeft()) {
157                         throw new ByActionStatusComponentException(ActionStatus.COMPONENT_NAME_ALREADY_EXIST, resource.getName());
158                     }
159                 }
160                 resource = resourceBusinessLogic.createOrUpdateResourceByImport(resource, creator, true, isInTransaction, needLock, csarInfo, nodeName, isNested).left;
161                 Resource changeStateResponse;
162
163                 if (nodeTypeArtifactsToHandle != null && !nodeTypeArtifactsToHandle.isEmpty()) {
164                     Either<List<ArtifactDefinition>, ResponseFormat> handleNodeTypeArtifactsRes =
165                             resourceBusinessLogic.handleNodeTypeArtifacts(resource, nodeTypeArtifactsToHandle, nodeTypesNewCreatedArtifacts, creator, isInTransaction, false);
166                     if (handleNodeTypeArtifactsRes.isRight()) {
167                         //TODO: should be used more correct action
168                         throw new ByActionStatusComponentException(ActionStatus.GENERAL_ERROR);
169                     }
170                 }
171                 latestCertifiedResourceId = getLatestCertifiedResourceId(resource);
172                 changeStateResponse = resourceBusinessLogic.propagateStateToCertified(creator, resource, lifecycleChangeInfo, isInTransaction, needLock, forceCertificationAllowed);
173                 responsePair = new ImmutablePair<>(changeStateResponse, response.left()
174                         .value().right);
175         }
176         catch (RuntimeException e) {
177             handleImportResourceException(resourceMetaData, creator, true, e);
178         }
179         finally {
180             if (latestCertifiedResourceId != null && needLock) {
181                 log.debug("unlock resource {}", latestCertifiedResourceId);
182                 graphLockOperation.unlockComponent(latestCertifiedResourceId, NodeTypeEnum.Resource);
183             }
184         }
185
186         return responsePair;
187     }
188
189     private ResponseFormat getResponseFormatFromComponentException(RuntimeException e) {
190         if(e instanceof ComponentException){
191             return ((ComponentException) e).getResponseFormat() == null ?
192                     componentsUtils.getResponseFormat(((ComponentException) e).getActionStatus(), ((ComponentException) e).getParams()) :
193                     ((ComponentException) e).getResponseFormat();
194         }
195         return null;
196     }
197
198     private String getLatestCertifiedResourceId(Resource resource) {
199         Map<String, String> allVersions = resource.getAllVersions();
200         Double latestCertifiedVersion = 0.0;
201         if (allVersions != null) {
202             for (String version : allVersions.keySet()) {
203                 Double dVersion = Double.valueOf(version);
204                 if ((dVersion > latestCertifiedVersion) && (version.endsWith(".0"))) {
205                     latestCertifiedVersion = dVersion;
206                 }
207             }
208             return allVersions.get(String.valueOf(latestCertifiedVersion));
209         }
210         else {
211             return null;
212         }
213     }
214
215     public void populateResourceMetadata(UploadResourceInfo resourceMetaData, Resource resource) {
216         if (resource != null && resourceMetaData != null) {
217             resource.setDescription(resourceMetaData.getDescription());
218             resource.setTags(resourceMetaData.getTags());
219             resource.setCategories(resourceMetaData.getCategories());
220             resource.setContactId(resourceMetaData.getContactId());
221             resource.setName(resourceMetaData.getName());
222             resource.setIcon(resourceMetaData.getResourceIconPath());
223             resource.setResourceVendorModelNumber(resourceMetaData.getResourceVendorModelNumber());
224             resource.setResourceType(ResourceTypeEnum.valueOf(resourceMetaData.getResourceType()));
225             if (resourceMetaData.getVendorName() != null) {
226                 resource.setVendorName(resourceMetaData.getVendorName());
227             }
228             if (resourceMetaData.getVendorRelease() != null) {
229                 resource.setVendorRelease(resourceMetaData.getVendorRelease());
230             }
231         }
232     }
233
234     public ImmutablePair<Resource, ActionStatus> importUserDefinedResource(String resourceYml, UploadResourceInfo resourceMetaData, User creator, boolean isInTransaction) {
235
236         Resource resource = new Resource();
237         ImmutablePair<Resource, ActionStatus> responsePair = new ImmutablePair<>(resource, ActionStatus.CREATED);
238
239         try {
240             setMetaDataFromJson(resourceMetaData, resource);
241
242             populateResourceFromYaml(resourceYml, resource);
243
244             // currently import VF isn't supported. In future will be supported
245             // import VF only with CSAR file!!
246             if (ResourceTypeEnum.VF == resource.getResourceType()) {
247                 log.debug("Now import VF isn't supported. It will be supported in future with CSAR file only");
248                 throw new ByActionStatusComponentException(ActionStatus.RESTRICTED_OPERATION);
249             }
250
251             resourceBusinessLogic.validateDerivedFromNotEmpty(creator, resource, AuditingActionEnum.CREATE_RESOURCE);
252             Boolean validatePropertiesTypes = resourceBusinessLogic.validatePropertiesDefaultValues(resource);
253
254             responsePair = resourceBusinessLogic.createOrUpdateResourceByImport(resource, creator,
255                         false, isInTransaction, true, null, null, false);
256
257         }
258         catch (RuntimeException e) {
259             handleImportResourceException(resourceMetaData, creator, false, e);
260         }
261         return responsePair;
262
263     }
264
265     void populateResourceFromYaml(String resourceYml, Resource resource) {
266         @SuppressWarnings("unchecked")
267 //        Either<Boolean, ResponseFormat> eitherResult = Either.left(true);
268         Object ymlObj = new Yaml().load(resourceYml);
269         if (ymlObj instanceof Map) {
270             Map<String, Object> toscaJsonAll = (Map<String, Object>) ymlObj;
271             Map<String, Object> toscaJson = toscaJsonAll;
272
273             // Checks if exist and builds the node_types map
274             if (toscaJsonAll.containsKey(TypeUtils.ToscaTagNamesEnum.NODE_TYPES.getElementName()) && resource.getResourceType() != ResourceTypeEnum.CVFC) {
275                 toscaJson = new HashMap<>();
276                 toscaJson.put(TypeUtils.ToscaTagNamesEnum.NODE_TYPES.getElementName(), toscaJsonAll.get(TypeUtils.ToscaTagNamesEnum.NODE_TYPES.getElementName()));
277             }
278             // Derived From
279             Resource parentResource = setDerivedFrom(toscaJson, resource);
280             if (StringUtils.isEmpty(resource.getToscaResourceName())) {
281                 setToscaResourceName(toscaJson, resource);
282             }
283             setAttributes(toscaJson, resource);
284             setCapabilities(toscaJson, resource, parentResource);
285             setProperties(toscaJson, resource);
286             setRequirements(toscaJson, resource, parentResource);
287             setInterfaceLifecycle(toscaJson, resource);
288         }
289         else {
290             throw new ByActionStatusComponentException(ActionStatus.GENERAL_ERROR);
291         }
292
293     }
294
295     private void setToscaResourceName(Map<String, Object> toscaJson, Resource resource) {
296         Either<Map<String, Object>, ResultStatusEnum> toscaElement = ImportUtils.findFirstToscaMapElement(toscaJson, TypeUtils.ToscaTagNamesEnum.NODE_TYPES);
297         if (toscaElement.isLeft() || toscaElement.left().value().size() == 1) {
298             String toscaResourceName = toscaElement.left().value().keySet().iterator().next();
299             resource.setToscaResourceName(toscaResourceName);
300         }
301     }
302
303     private void setInterfaceLifecycle(Map<String, Object> toscaJson, Resource resource) {
304         Either<Map<String, Object>, ResultStatusEnum> toscaInterfaces = ImportUtils.findFirstToscaMapElement(toscaJson, TypeUtils.ToscaTagNamesEnum.INTERFACES);
305         if (toscaInterfaces.isLeft()) {
306             Map<String, Object> jsonInterfaces = toscaInterfaces.left().value();
307             Map<String, InterfaceDefinition> moduleInterfaces = new HashMap<>();
308             Iterator<Entry<String, Object>> interfacesNameValue = jsonInterfaces.entrySet().iterator();
309             while (interfacesNameValue.hasNext()) {
310                 Entry<String, Object> interfaceNameValue = interfacesNameValue.next();
311                 Either<InterfaceDefinition, ResultStatusEnum> eitherInterface = createModuleInterface(interfaceNameValue
312                         .getValue());
313                 if (eitherInterface.isRight()) {
314                     log.info("error when creating interface:{}, for resource:{}", interfaceNameValue.getKey(), resource.getName());
315                 }
316                 else {
317                     moduleInterfaces.put(interfaceNameValue.getKey(), eitherInterface.left().value());
318                 }
319
320             }
321             if (moduleInterfaces.size() > 0) {
322                 resource.setInterfaces(moduleInterfaces);
323             }
324         }
325     }
326
327     private Either<InterfaceDefinition, ResultStatusEnum> createModuleInterface(Object interfaceJson) {
328         InterfaceDefinition interf = new InterfaceDefinition();
329         Either<InterfaceDefinition, ResultStatusEnum> result = Either.left(interf);
330
331         try {
332             if (interfaceJson instanceof String) {
333                 String requirementJsonString = (String) interfaceJson;
334                 interf.setType(requirementJsonString);
335             }
336             else if (interfaceJson instanceof Map) {
337                 Map<String, Object> requirementJsonMap = (Map<String, Object>) interfaceJson;
338                 if (requirementJsonMap.containsKey(TypeUtils.ToscaTagNamesEnum.TYPE.getElementName())) {
339                     String type = (String) requirementJsonMap.get(TypeUtils.ToscaTagNamesEnum.TYPE.getElementName());
340                     interf.setType(type);
341                     interf.setUniqueId(type.toLowerCase());
342                 }
343             }
344             else {
345                 result = Either.right(ResultStatusEnum.GENERAL_ERROR);
346             }
347
348         }
349         catch (Exception e) {
350             BeEcompErrorManager.getInstance().logBeSystemError("Import Resource- create interface");
351             log.debug("error when creating interface, message:{}", e.getMessage(), e);
352             result = Either.right(ResultStatusEnum.GENERAL_ERROR);
353         }
354
355         return result;
356     }
357
358     private void setRequirements(Map<String, Object> toscaJson, Resource resource, Resource parentResource) {// Note that parentResource can be null
359         Either<List<Object>, ResultStatusEnum> toscaRequirements = ImportUtils.findFirstToscaListElement(toscaJson, TypeUtils.ToscaTagNamesEnum.REQUIREMENTS);
360         if (toscaRequirements.isLeft()) {
361             List<Object> jsonRequirements = toscaRequirements.left().value();
362             Map<String, List<RequirementDefinition>> moduleRequirements = new HashMap<>();
363             // Checking for name duplication
364             Set<String> reqNames = new HashSet<>();
365             // Getting flattened list of capabilities of parent node - cap name
366             // to cap type
367             Map<String, String> reqName2TypeMap = getReqName2Type(parentResource);
368             for (Object jsonRequirementObj : jsonRequirements) {
369                 // Requirement
370                 Map<String, Object> requirementJsonWrapper = (Map<String, Object>) jsonRequirementObj;
371                 String requirementName = requirementJsonWrapper.keySet().iterator().next();
372                 String reqNameLowerCase = requirementName.toLowerCase();
373                 if (reqNames.contains(reqNameLowerCase)) {
374                     log.debug("More than one requirement with same name {} (case-insensitive) in imported TOSCA file is invalid", reqNameLowerCase);
375                     throw new ByActionStatusComponentException(ActionStatus.IMPORT_DUPLICATE_REQ_CAP_NAME, "requirement", reqNameLowerCase);
376                 }
377                 reqNames.add(reqNameLowerCase);
378                 RequirementDefinition requirementDef = createRequirementFromImportFile(requirementJsonWrapper
379                         .get(requirementName));
380                 requirementDef.setName(requirementName);
381                 if (moduleRequirements.containsKey(requirementDef.getCapability())) {
382                     moduleRequirements.get(requirementDef.getCapability()).add(requirementDef);
383                 }
384                 else {
385                     List<RequirementDefinition> list = new ArrayList<>();
386                     list.add(requirementDef);
387                     moduleRequirements.put(requirementDef.getCapability(), list);
388                 }
389
390                 // Validating against req/cap of "derived from" node
391                 Boolean validateVsParentCap = validateCapNameVsDerived(reqName2TypeMap, requirementDef
392                         .getCapability(), requirementDef.getName());
393                 if (!validateVsParentCap) {
394                     log.debug("Requirement with name {} already exists in parent {}", requirementDef.getName(), parentResource
395                             .getName());
396                     throw new ByActionStatusComponentException(ActionStatus.IMPORT_REQ_CAP_NAME_EXISTS_IN_DERIVED, "requirement", requirementDef
397                             .getName()
398                             .toLowerCase(), parentResource.getName());
399                 }
400             }
401             if (moduleRequirements.size() > 0) {
402                 resource.setRequirements(moduleRequirements);
403             }
404
405         }
406    }
407
408     private RequirementDefinition createRequirementFromImportFile(Object requirementJson) {
409         RequirementDefinition requirement = new RequirementDefinition();
410
411         if (requirementJson instanceof String) {
412             String requirementJsonString = (String) requirementJson;
413             requirement.setCapability(requirementJsonString);
414         }
415         else if (requirementJson instanceof Map) {
416             Map<String, Object> requirementJsonMap = (Map<String, Object>) requirementJson;
417             if (requirementJsonMap.containsKey(TypeUtils.ToscaTagNamesEnum.CAPABILITY.getElementName())) {
418                 requirement.setCapability((String) requirementJsonMap.get(TypeUtils.ToscaTagNamesEnum.CAPABILITY.getElementName()));
419             }
420
421             if (requirementJsonMap.containsKey(TypeUtils.ToscaTagNamesEnum.NODE.getElementName())) {
422                 requirement.setNode((String) requirementJsonMap.get(TypeUtils.ToscaTagNamesEnum.NODE.getElementName()));
423             }
424
425             if (requirementJsonMap.containsKey(TypeUtils.ToscaTagNamesEnum.RELATIONSHIP.getElementName())) {
426                 requirement.setRelationship((String) requirementJsonMap.get(TypeUtils.ToscaTagNamesEnum.RELATIONSHIP.getElementName()));
427             }
428             if (requirementJsonMap.containsKey(TypeUtils.ToscaTagNamesEnum.OCCURRENCES.getElementName())) {
429                 List<Object> occurrencesList = (List) requirementJsonMap.get(TypeUtils.ToscaTagNamesEnum.OCCURRENCES.getElementName());
430                 validateOccurrences(occurrencesList);
431                 requirement.setMinOccurrences(occurrencesList.get(0).toString());
432                 requirement.setMaxOccurrences(occurrencesList.get(1).toString());
433             }
434         }
435         else {
436             throw new ByActionStatusComponentException(ActionStatus.INVALID_YAML);
437         }
438         return requirement;
439     }
440
441     private void setProperties(Map<String, Object> toscaJson, Resource resource) {
442         Map<String, Object> reducedToscaJson = new HashMap<>(toscaJson);
443         ImportUtils.removeElementFromJsonMap(reducedToscaJson, "capabilities");
444         Either<Map<String, PropertyDefinition>, ResultStatusEnum> properties = ImportUtils.getProperties(reducedToscaJson);
445         if (properties.isLeft()) {
446             List<PropertyDefinition> propertiesList = new ArrayList<>();
447             Map<String, PropertyDefinition> value = properties.left().value();
448             if (value != null) {
449                 for (Entry<String, PropertyDefinition> entry : value.entrySet()) {
450                     String name = entry.getKey();
451                     if (!PROPERTY_NAME_PATTERN_IGNORE_LENGTH.matcher(name).matches()) {
452                         log.debug("The property with invalid name {} occured upon import resource {}. ", name, resource.getName());
453                         throw new ByActionStatusComponentException(componentsUtils.convertFromResultStatusEnum(ResultStatusEnum.INVALID_PROPERTY_NAME, JsonPresentationFields.PROPERTY));
454                     }
455                     PropertyDefinition propertyDefinition = entry.getValue();
456                     propertyDefinition.setName(name);
457                     propertiesList.add(propertyDefinition);
458                 }
459             }
460             resource.setProperties(propertiesList);
461         }
462         else if (properties.right().value() != ResultStatusEnum.ELEMENT_NOT_FOUND) {
463             throw new ByActionStatusComponentException(componentsUtils.convertFromResultStatusEnum(properties
464                     .right()
465                     .value(), JsonPresentationFields.PROPERTY));
466         }
467     }
468
469     private ResultStatusEnum setAttributes(Map<String, Object> toscaJson, Resource resource) {
470         ResultStatusEnum result = ResultStatusEnum.OK;
471         Either<Map<String, PropertyDefinition>, ResultStatusEnum> attributes = ImportUtils.getAttributes(toscaJson);
472         if (attributes.isLeft()) {
473             List<PropertyDefinition> attributeList = new ArrayList<>();
474             Map<String, PropertyDefinition> value = attributes.left().value();
475             if (value != null) {
476                 for (Entry<String, PropertyDefinition> entry : value.entrySet()) {
477                     String name = entry.getKey();
478                     PropertyDefinition attributeDef = entry.getValue();
479                     attributeDef.setName(name);
480                     attributeList.add(attributeDef);
481                 }
482             }
483             resource.setAttributes(attributeList);
484         }
485         else {
486             result = attributes.right().value();
487         }
488         return result;
489     }
490
491     private Resource setDerivedFrom(Map<String, Object> toscaJson, Resource resource) {
492         Either<String, ResultStatusEnum> toscaDerivedFromElement = ImportUtils.findFirstToscaStringElement(toscaJson, TypeUtils.ToscaTagNamesEnum.DERIVED_FROM);
493         Resource derivedFromResource = null;
494         if (toscaDerivedFromElement.isLeft()) {
495             String derivedFrom = toscaDerivedFromElement.left().value();
496             log.debug("Derived from TOSCA name is {}", derivedFrom);
497             resource.setDerivedFrom(Arrays.asList(new String[]{derivedFrom}));
498             Either<Resource, StorageOperationStatus> latestByToscaResourceName = toscaOperationFacade.getLatestByToscaResourceName(derivedFrom);
499
500             if (latestByToscaResourceName.isRight()) {
501                 StorageOperationStatus operationStatus = latestByToscaResourceName.right().value();
502                 if (operationStatus == StorageOperationStatus.NOT_FOUND) {
503                     operationStatus = StorageOperationStatus.PARENT_RESOURCE_NOT_FOUND;
504                 }
505                 log.debug("Error when fetching parent resource {}, error: {}", derivedFrom, operationStatus);
506                 ActionStatus convertFromStorageResponse = componentsUtils.convertFromStorageResponse(operationStatus);
507                 BeEcompErrorManager.getInstance()
508                                    .logBeComponentMissingError("Import TOSCA YAML", "resource", derivedFrom);
509                 throw new ByActionStatusComponentException(convertFromStorageResponse, derivedFrom);
510             }
511             derivedFromResource = latestByToscaResourceName.left().value();
512         }
513         return derivedFromResource;
514     }
515
516     private void setCapabilities(Map<String, Object> toscaJson, Resource resource, Resource parentResource) {// Note that parentResource can be null
517         Either<Map<String, Object>, ResultStatusEnum> toscaCapabilities = ImportUtils.findFirstToscaMapElement(toscaJson, TypeUtils.ToscaTagNamesEnum.CAPABILITIES);
518         if (toscaCapabilities.isLeft()) {
519             Map<String, Object> jsonCapabilities = toscaCapabilities.left().value();
520             Map<String, List<CapabilityDefinition>> moduleCapabilities = new HashMap<>();
521             Iterator<Entry<String, Object>> capabilitiesNameValue = jsonCapabilities.entrySet().iterator();
522             Set<String> capNames = new HashSet<>();
523             // Getting flattened list of capabilities of parent node - cap name
524             // to cap type
525             Map<String, String> capName2TypeMap = getCapName2Type(parentResource);
526             while (capabilitiesNameValue.hasNext()) {
527                 Entry<String, Object> capabilityNameValue = capabilitiesNameValue.next();
528
529                 // Validating that no req/cap duplicates exist in imported YAML
530                 String capNameLowerCase = capabilityNameValue.getKey().toLowerCase();
531                 if (capNames.contains(capNameLowerCase)) {
532                     log.debug("More than one capability with same name {} (case-insensitive) in imported TOSCA file is invalid", capNameLowerCase);
533                     throw new ByActionStatusComponentException(ActionStatus.IMPORT_DUPLICATE_REQ_CAP_NAME, "capability", capNameLowerCase);
534                 }
535                 capNames.add(capNameLowerCase);
536
537                 CapabilityDefinition capabilityDef = createCapabilityFromImportFile(capabilityNameValue
538                         .getValue());
539                 capabilityDef.setName(capabilityNameValue.getKey());
540                 if (moduleCapabilities.containsKey(capabilityDef.getType())) {
541                     moduleCapabilities.get(capabilityDef.getType()).add(capabilityDef);
542                 }
543                 else {
544                     List<CapabilityDefinition> list = new ArrayList<>();
545                     list.add(capabilityDef);
546                     moduleCapabilities.put(capabilityDef.getType(), list);
547                 }
548
549                 // Validating against req/cap of "derived from" node
550                 Boolean validateVsParentCap = validateCapNameVsDerived(capName2TypeMap, capabilityDef
551                         .getType(), capabilityDef.getName());
552
553                 if (!validateVsParentCap) {
554                     // Here parentResource is for sure not null, so it's
555                     // null-safe
556                     log.debug("Capability with name {} already exists in parent {}", capabilityDef.getName(), parentResource
557                             .getName());
558                     throw new ByActionStatusComponentException(ActionStatus.IMPORT_REQ_CAP_NAME_EXISTS_IN_DERIVED, "capability", capabilityDef
559                             .getName()
560                             .toLowerCase(), parentResource.getName());
561                 }
562             }
563             if (moduleCapabilities.size() > 0) {
564                 resource.setCapabilities(moduleCapabilities);
565             }
566         }
567     }
568
569     private Map<String, String> getCapName2Type(Resource parentResource) {
570         Map<String, String> capName2type = new HashMap<>();
571         if (parentResource != null) {
572             Map<String, List<CapabilityDefinition>> capabilities = parentResource.getCapabilities();
573             if (capabilities != null) {
574                 for (List<CapabilityDefinition> capDefinitions : capabilities.values()) {
575                     for (CapabilityDefinition capDefinition : capDefinitions) {
576                         String nameLowerCase = capDefinition.getName().toLowerCase();
577                         if (capName2type.get(nameLowerCase) != null) {
578                             String parentResourceName = parentResource.getName();
579                             log.debug("Resource with name {} has more than one capability with name {}, ignoring case", parentResourceName, nameLowerCase);
580                             BeEcompErrorManager.getInstance()
581                                                .logInternalDataError("Import resource", "Parent resource " + parentResourceName + " of imported resource has one or more capabilities with name " + nameLowerCase, ErrorSeverity.ERROR);
582                             throw new ByActionStatusComponentException(ActionStatus.GENERAL_ERROR);
583                         }
584                         capName2type.put(nameLowerCase, capDefinition.getType());
585                     }
586                 }
587             }
588         }
589         return capName2type;
590     }
591
592     private Map<String, String> getReqName2Type(Resource parentResource) {
593         Map<String, String> reqName2type = new HashMap<>();
594         if (parentResource != null) {
595             Map<String, List<RequirementDefinition>> requirements = parentResource.getRequirements();
596             if (requirements != null) {
597                 for (List<RequirementDefinition> reqDefinitions : requirements.values()) {
598                     for (RequirementDefinition reqDefinition : reqDefinitions) {
599                         String nameLowerCase = reqDefinition.getName().toLowerCase();
600                         if (reqName2type.get(nameLowerCase) != null) {
601                             String parentResourceName = parentResource.getName();
602                             log.debug("Resource with name {} has more than one requirement with name {}, ignoring case", parentResourceName, nameLowerCase);
603                             BeEcompErrorManager.getInstance()
604                                                .logInternalDataError("Import resource", "Parent resource " + parentResourceName + " of imported resource has one or more requirements with name " + nameLowerCase, ErrorSeverity.ERROR);
605                             throw new ByActionStatusComponentException(ActionStatus.GENERAL_ERROR);
606                         }
607                         reqName2type.put(nameLowerCase, reqDefinition.getCapability());
608                     }
609                 }
610             }
611         }
612         return reqName2type;
613     }
614
615     private Boolean validateCapNameVsDerived(Map<String, String> parentCapName2Type, String childCapabilityType, String reqCapName) {
616         String capNameLowerCase = reqCapName.toLowerCase();
617         log.trace("Validating capability {} vs parent resource", capNameLowerCase);
618         String parentCapType = parentCapName2Type.get(capNameLowerCase);
619         if (parentCapType != null) {
620             if (childCapabilityType.equals(parentCapType)) {
621                 log.debug("Capability with name {} is of same type {} for imported resource and its parent - this is OK", capNameLowerCase, childCapabilityType);
622                 return true;
623             }
624             Either<Boolean, StorageOperationStatus> capabilityTypeDerivedFrom = capabilityTypeOperation.isCapabilityTypeDerivedFrom(childCapabilityType, parentCapType);
625             if (capabilityTypeDerivedFrom.isRight()) {
626                 log.debug("Couldn't check whether imported resource capability derives from its parent's capability");
627                 throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(capabilityTypeDerivedFrom
628                         .right()
629                         .value()));
630             }
631             return capabilityTypeDerivedFrom.left().value();
632         }
633         return true;
634     }
635
636     private CapabilityDefinition createCapabilityFromImportFile(Object capabilityJson) {
637
638         CapabilityDefinition capabilityDefinition = new CapabilityDefinition();
639
640         if (capabilityJson instanceof String) {
641             String capabilityJsonString = (String) capabilityJson;
642             capabilityDefinition.setType(capabilityJsonString);
643         }
644         else if (capabilityJson instanceof Map) {
645             Map<String, Object> capabilityJsonMap = (Map<String, Object>) capabilityJson;
646             // Type
647             if (capabilityJsonMap.containsKey(TypeUtils.ToscaTagNamesEnum.TYPE.getElementName())) {
648                 capabilityDefinition.setType((String) capabilityJsonMap.get(TypeUtils.ToscaTagNamesEnum.TYPE.getElementName()));
649             }
650             // ValidSourceTypes
651             if (capabilityJsonMap.containsKey(TypeUtils.ToscaTagNamesEnum.VALID_SOURCE_TYPES.getElementName())) {
652                 capabilityDefinition.setValidSourceTypes((List<String>) capabilityJsonMap.get(TypeUtils.ToscaTagNamesEnum.VALID_SOURCE_TYPES
653                         .getElementName()));
654             }
655             // ValidSourceTypes
656             if (capabilityJsonMap.containsKey(TypeUtils.ToscaTagNamesEnum.DESCRIPTION.getElementName())) {
657                 capabilityDefinition.setDescription((String) capabilityJsonMap.get(TypeUtils.ToscaTagNamesEnum.DESCRIPTION.getElementName()));
658             }
659             if (capabilityJsonMap.containsKey(TypeUtils.ToscaTagNamesEnum.OCCURRENCES.getElementName())) {
660                 List<Object> occurrencesList = (List) capabilityJsonMap.get(TypeUtils.ToscaTagNamesEnum.OCCURRENCES.getElementName());
661                 validateOccurrences(occurrencesList);
662                 capabilityDefinition.setMinOccurrences(occurrencesList.get(0).toString());
663                 capabilityDefinition.setMaxOccurrences(occurrencesList.get(1).toString());
664             }
665             if (capabilityJsonMap.containsKey(TypeUtils.ToscaTagNamesEnum.PROPERTIES.getElementName())) {
666
667                 Either<Map<String, PropertyDefinition>, ResultStatusEnum> propertiesRes = ImportUtils.getProperties(capabilityJsonMap);
668                 if (propertiesRes.isRight()) {
669                     throw new ByActionStatusComponentException(ActionStatus.PROPERTY_NOT_FOUND);
670                 }
671                 else {
672                     propertiesRes.left()
673                                  .value()
674                                  .entrySet()
675                                  .stream()
676                                  .forEach(e -> e.getValue().setName(e.getKey().toLowerCase()));
677                     List<ComponentInstanceProperty> capabilityProperties = propertiesRes.left()
678                                                                                         .value()
679                                                                                         .values()
680                                                                                         .stream()
681                                                                                         .map(p -> new ComponentInstanceProperty(p, p
682                                                                                                 .getDefaultValue(), null))
683                                                                                         .collect(Collectors.toList());
684                     capabilityDefinition.setProperties(capabilityProperties);
685                 }
686             }
687         }
688         else if (!(capabilityJson instanceof List)) {
689             throw new ByActionStatusComponentException(ActionStatus.INVALID_YAML);
690         }
691         return capabilityDefinition;
692     }
693
694     private void handleImportResourceException(UploadResourceInfo resourceMetaData, User user, boolean isNormative, RuntimeException e) {
695         ResponseFormat responseFormat;
696         ComponentException newException;
697         if (e instanceof ComponentException) {
698             ComponentException componentException = (ComponentException)e;
699             responseFormat = componentException.getResponseFormat();
700             if (responseFormat == null) {
701                 responseFormat = getResponseFormatManager().getResponseFormat(componentException.getActionStatus(), componentException.getParams());
702             }
703             newException = componentException;
704         }
705         else{
706             responseFormat = getResponseFormatManager().getResponseFormat(ActionStatus.GENERAL_ERROR);
707             newException = new ByActionStatusComponentException(ActionStatus.GENERAL_ERROR);
708         }
709         String payloadName = (resourceMetaData != null) ? resourceMetaData.getPayloadName() : "";
710         BeEcompErrorManager.getInstance().logBeSystemError("Import Resource " + payloadName);
711         log.debug("Error when importing resource from payload:{} Exception text: {}", payloadName, e.getMessage(), e);
712         auditErrorImport(resourceMetaData, user, responseFormat, isNormative);
713         throw newException;
714     }
715
716     private void auditErrorImport(UploadResourceInfo resourceMetaData, User user, ResponseFormat errorResponseWrapper, boolean isNormative) {
717         String version, lifeCycleState;
718         if (isNormative) {
719             version = TypeUtils.getFirstCertifiedVersionVersion();
720             lifeCycleState = LifecycleStateEnum.CERTIFIED.name();
721         }
722         else {
723             version = "";
724             lifeCycleState = LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.name();
725
726         }
727
728         String message = "";
729         if (errorResponseWrapper.getMessageId() != null) {
730             message = errorResponseWrapper.getMessageId() + ": ";
731         }
732         message += errorResponseWrapper.getFormattedMessage();
733
734
735         AuditEventFactory factory = new AuditImportResourceAdminEventFactory(
736                 CommonAuditData.newBuilder()
737                                .status(errorResponseWrapper.getStatus())
738                                .description(message)
739                                .requestId(ThreadLocalsHolder.getUuid())
740                                .build(),
741                 new ResourceCommonInfo(resourceMetaData.getName(), ComponentTypeEnum.RESOURCE.getValue()),
742                 ResourceVersionInfo.newBuilder()
743                                  .state(lifeCycleState)
744                                  .version(version)
745                                  .build(),
746                 ResourceVersionInfo.newBuilder()
747                                  .state("")
748                                  .version("")
749                                  .build(),
750                 "", user, "");
751         getAuditingManager().auditEvent(factory);
752
753     }
754
755     private void setMetaDataFromJson(UploadResourceInfo resourceMetaData, Resource resource) {
756         this.populateResourceMetadata(resourceMetaData, resource);
757         resource.setCreatorUserId(resourceMetaData.getContactId());
758         List<CategoryDefinition> categories = resourceMetaData.getCategories();
759         calculateResourceIsAbstract(resource, categories);
760     }
761
762     private void calculateResourceIsAbstract(Resource resource, List<CategoryDefinition> categories) {
763         if (categories != null && !categories.isEmpty()) {
764             CategoryDefinition categoryDef = categories.get(0);
765             resource.setAbstract(false);
766             if (categoryDef != null && categoryDef.getName() != null && categoryDef.getName()
767                                                                                    .equals(Constants.ABSTRACT_CATEGORY_NAME)) {
768                 SubCategoryDefinition subCategoryDef = categoryDef.getSubcategories().get(0);
769                 if (subCategoryDef != null && subCategoryDef.getName().equals(Constants.ABSTRACT_SUBCATEGORY)) {
770                     resource.setAbstract(true);
771                 }
772             }
773         }
774     }
775
776     private void setConstantMetaData(Resource resource, boolean shouldBeCertified) {
777         String version;
778         LifecycleStateEnum state;
779         if (shouldBeCertified) {
780             version = TypeUtils.getFirstCertifiedVersionVersion();
781             state = ImportUtils.Constants.NORMATIVE_TYPE_LIFE_CYCLE;
782         }
783         else {
784             version = ImportUtils.Constants.FIRST_NON_CERTIFIED_VERSION;
785             state = ImportUtils.Constants.NORMATIVE_TYPE_LIFE_CYCLE_NOT_CERTIFIED_CHECKOUT;
786         }
787         resource.setVersion(version);
788         resource.setLifecycleState(state);
789         resource.setHighestVersion(ImportUtils.Constants.NORMATIVE_TYPE_HIGHEST_VERSION);
790         resource.setVendorName(ImportUtils.Constants.VENDOR_NAME);
791         resource.setVendorRelease(ImportUtils.Constants.VENDOR_RELEASE);
792
793     }
794
795     private void validateOccurrences(List<Object> occurrensesList) {
796
797         if (!ValidationUtils.validateListNotEmpty(occurrensesList)) {
798             log.debug("Occurrenses list empty");
799             throw new ByActionStatusComponentException(ActionStatus.INVALID_OCCURRENCES);
800         }
801
802         if (occurrensesList.size() < 2) {
803             log.debug("Occurrenses list size not 2");
804             throw new ByActionStatusComponentException(ActionStatus.INVALID_OCCURRENCES);
805         }
806         Object minObj = occurrensesList.get(0);
807         Object maxObj = occurrensesList.get(1);
808         Integer minOccurrences;
809         Integer maxOccurrences;
810         if (minObj instanceof Integer) {
811             minOccurrences = (Integer) minObj;
812         }
813         else {
814             log.debug("Invalid occurrenses format. low_bound occurrense must be Integer {}", minObj);
815             throw new ByActionStatusComponentException(ActionStatus.INVALID_OCCURRENCES);
816         }
817         if (minOccurrences < 0) {
818             log.debug("Invalid occurrenses format.low_bound occurrense negative {}", minOccurrences);
819             throw new ByActionStatusComponentException(ActionStatus.INVALID_OCCURRENCES);
820         }
821
822         if (maxObj instanceof String){
823             if(!"UNBOUNDED".equals(maxObj)) {
824                 log.debug("Invalid occurrenses format. Max occurrence is {}", maxObj);
825                 throw new ByActionStatusComponentException(ActionStatus.INVALID_OCCURRENCES);
826             }
827         }
828         else {
829             if (maxObj instanceof Integer) {
830                 maxOccurrences = (Integer) maxObj;
831             }
832             else {
833                 log.debug("Invalid occurrenses format.  Max occurrence is {}", maxObj);
834                 throw new ByActionStatusComponentException(ActionStatus.INVALID_OCCURRENCES);
835             }
836
837             if (maxOccurrences <= 0 || maxOccurrences < minOccurrences) {
838                 log.debug("Invalid occurrenses format.  min occurrence is {}, Max occurrence is {}", minOccurrences, maxOccurrences);
839                 throw new ByActionStatusComponentException(ActionStatus.INVALID_OCCURRENCES);
840             }
841         }
842     }
843
844     public synchronized void init(ServletContext servletContext) {
845         if (this.servletContext == null) {
846             this.servletContext = servletContext;
847             responseFormatManager = ResponseFormatManager.getInstance();
848             resourceBusinessLogic = getResourceBL(servletContext);
849         }
850     }
851
852     public boolean isResourceExist(String resourceName) {
853         return resourceBusinessLogic.isResourceExist(resourceName);
854     }
855
856     private ResourceBusinessLogic getResourceBL(ServletContext context) {
857         WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(org.openecomp.sdc.common.api.Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR);
858         WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context);
859         return webApplicationContext.getBean(ResourceBusinessLogic.class);
860     }
861
862     public ServletContext getServletContext() {
863         return servletContext;
864     }
865
866     public AuditingManager getAuditingManager() {
867         return auditingManager;
868     }
869
870     public ResponseFormatManager getResponseFormatManager() {
871         return responseFormatManager;
872     }
873
874     public void setResponseFormatManager(ResponseFormatManager responseFormatManager) {
875         this.responseFormatManager = responseFormatManager;
876     }
877
878     public ResourceBusinessLogic getResourceBusinessLogic() {
879         return resourceBusinessLogic;
880     }
881
882     @Autowired
883     public void setResourceBusinessLogic(ResourceBusinessLogic resourceBusinessLogic) {
884         this.resourceBusinessLogic = resourceBusinessLogic;
885     }
886
887     public IGraphLockOperation getGraphLockOperation() {
888         return graphLockOperation;
889     }
890
891     @Autowired
892     public void setGraphLockOperation(IGraphLockOperation graphLockOperation) {
893         this.graphLockOperation = graphLockOperation;
894     }
895
896     public void setServletContext(ServletContext servletContext) {
897         this.servletContext = servletContext;
898     }
899
900     @Autowired
901     public void setAuditingManager(AuditingManager auditingManager) {
902         this.auditingManager = auditingManager;
903     }
904
905
906 }