2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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 * ================================================================================
23 package org.openecomp.sdc.be.components.impl;
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.ComponentException;
36 import org.openecomp.sdc.be.components.lifecycle.LifecycleChangeInfoWithAction;
37 import org.openecomp.sdc.be.config.BeEcompErrorManager;
38 import org.openecomp.sdc.be.config.BeEcompErrorManager.ErrorSeverity;
39 import org.openecomp.sdc.be.dao.api.ActionStatus;
40 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
41 import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields;
42 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
43 import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
44 import org.openecomp.sdc.be.impl.ComponentsUtils;
45 import org.openecomp.sdc.be.impl.WebAppContextWrapper;
46 import org.openecomp.sdc.be.model.*;
47 import org.openecomp.sdc.be.model.category.CategoryDefinition;
48 import org.openecomp.sdc.be.model.category.SubCategoryDefinition;
49 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ToscaOperationFacade;
50 import org.openecomp.sdc.be.model.operations.api.IGraphLockOperation;
51 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
52 import org.openecomp.sdc.be.model.operations.impl.CapabilityTypeOperation;
53 import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
54 import org.openecomp.sdc.be.resources.data.auditing.model.CommonAuditData;
55 import org.openecomp.sdc.be.resources.data.auditing.model.ResourceCommonInfo;
56 import org.openecomp.sdc.be.resources.data.auditing.model.ResourceVersionInfo;
57 import org.openecomp.sdc.be.utils.TypeUtils;
58 import org.openecomp.sdc.common.log.wrappers.Logger;
59 import org.openecomp.sdc.common.util.ThreadLocalsHolder;
60 import org.openecomp.sdc.common.util.ValidationUtils;
61 import org.openecomp.sdc.exception.ResponseFormat;
62 import org.springframework.beans.factory.annotation.Autowired;
63 import org.springframework.stereotype.Component;
64 import org.springframework.web.context.WebApplicationContext;
65 import org.yaml.snakeyaml.Yaml;
67 import javax.servlet.ServletContext;
69 import java.util.Map.Entry;
70 import java.util.function.Function;
71 import java.util.regex.Pattern;
72 import java.util.stream.Collectors;
74 @Component("resourceImportManager")
75 public class ResourceImportManager {
76 static final Pattern PROPERTY_NAME_PATTERN_IGNORE_LENGTH = Pattern.compile("[\\w\\-\\_\\d\\:]+");
78 private ServletContext servletContext;
80 private AuditingManager auditingManager;
81 private ResourceBusinessLogic resourceBusinessLogic;
82 private IGraphLockOperation graphLockOperation;
83 protected ToscaOperationFacade toscaOperationFacade;
85 protected final ComponentsUtils componentsUtils;
86 private final CapabilityTypeOperation capabilityTypeOperation;
88 private ResponseFormatManager responseFormatManager;
90 private static final Logger log = Logger.getLogger(ResourceImportManager.class);
93 public ResourceImportManager(ComponentsUtils componentsUtils, CapabilityTypeOperation capabilityTypeOperation) {
94 this.componentsUtils = componentsUtils;
95 this.capabilityTypeOperation = capabilityTypeOperation;
99 public void setToscaOperationFacade(ToscaOperationFacade toscaOperationFacade) {
100 this.toscaOperationFacade = toscaOperationFacade;
103 public Either<ImmutablePair<Resource, ActionStatus>, ResponseFormat> importNormativeResource(String resourceYml, UploadResourceInfo resourceMetaData, User creator, boolean createNewVersion, boolean needLock) {
105 LifecycleChangeInfoWithAction lifecycleChangeInfo = new LifecycleChangeInfoWithAction();
106 lifecycleChangeInfo.setUserRemarks("certification on import");
107 Function<Resource, Either<Boolean, ResponseFormat>> validator = resource -> resourceBusinessLogic.validatePropertiesDefaultValues(resource);
109 return importCertifiedResource(resourceYml, resourceMetaData, creator, validator, lifecycleChangeInfo, false, createNewVersion, needLock, null, null, false, null, null, false);
112 public Either<ImmutablePair<Resource, ActionStatus>, ResponseFormat> importNormativeResourceFromCsar(String resourceYml, UploadResourceInfo resourceMetaData, User creator, boolean createNewVersion, boolean needLock) {
114 LifecycleChangeInfoWithAction lifecycleChangeInfo = new LifecycleChangeInfoWithAction();
115 lifecycleChangeInfo.setUserRemarks("certification on import");
116 Function<Resource, Either<Boolean, ResponseFormat>> validator = resource -> resourceBusinessLogic.validatePropertiesDefaultValues(resource);
118 return importCertifiedResource(resourceYml, resourceMetaData, creator, validator, lifecycleChangeInfo, false, createNewVersion, needLock, null, null, false, null, null, false);
121 public Either<ImmutablePair<Resource, ActionStatus>, ResponseFormat> importCertifiedResource(String resourceYml, UploadResourceInfo resourceMetaData, User creator, Function<Resource, Either<Boolean, ResponseFormat>> validationFunction,
122 LifecycleChangeInfoWithAction lifecycleChangeInfo, boolean isInTransaction, boolean createNewVersion, boolean needLock, Map<ArtifactOperationEnum, List<ArtifactDefinition>> nodeTypeArtifactsToHandle, List<ArtifactDefinition> nodeTypesNewCreatedArtifacts, boolean forceCertificationAllowed, CsarInfo csarInfo, String nodeName, boolean isNested) {
123 Resource resource = new Resource();
124 ImmutablePair<Resource, ActionStatus> responsePair = new ImmutablePair<>(resource, ActionStatus.CREATED);
125 Either<ImmutablePair<Resource, ActionStatus>, ResponseFormat> response = Either.left(responsePair);
127 String latestCertifiedResourceId = null;
129 boolean shouldBeCertified = nodeTypeArtifactsToHandle == null || nodeTypeArtifactsToHandle.isEmpty();
130 setConstantMetaData(resource, shouldBeCertified);
131 setMetaDataFromJson(resourceMetaData, resource);
133 Either<Boolean, ResponseFormat> validateResourceFromYaml = populateResourceFromYaml(resourceYml, resource);
134 if (validateResourceFromYaml.isRight()) {
135 ResponseFormat validationErrorResponse = validateResourceFromYaml.right().value();
136 auditErrorImport(resourceMetaData, creator, validationErrorResponse, true);
137 return Either.right(validationErrorResponse);
141 Either<Boolean, ResponseFormat> isValidResource = validationFunction.apply(resource);
142 if (isValidResource.isLeft()) {
143 // The flag createNewVersion if false doesn't create new version
144 if (!createNewVersion) {
145 Either<Resource, StorageOperationStatus> latestByName = toscaOperationFacade.getLatestByName(resource.getName());
146 if (latestByName.isLeft()) {
147 return Either.right(componentsUtils.getResponseFormatByResource(ActionStatus.COMPONENT_NAME_ALREADY_EXIST, resource));
150 resource = resourceBusinessLogic.createOrUpdateResourceByImport(resource, creator, true, isInTransaction, needLock, csarInfo, nodeName, isNested).left;
151 Either<Resource, ResponseFormat> changeStateResponse;
153 if (nodeTypeArtifactsToHandle != null && !nodeTypeArtifactsToHandle.isEmpty()) {
154 Either<List<ArtifactDefinition>, ResponseFormat> handleNodeTypeArtifactsRes =
155 resourceBusinessLogic.handleNodeTypeArtifacts(resource, nodeTypeArtifactsToHandle, nodeTypesNewCreatedArtifacts, creator, isInTransaction, false);
156 if (handleNodeTypeArtifactsRes.isRight()) {
157 return Either.right(handleNodeTypeArtifactsRes.right().value());
160 latestCertifiedResourceId = getLatestCertifiedResourceId(resource);
161 changeStateResponse = resourceBusinessLogic.propagateStateToCertified(creator, resource, lifecycleChangeInfo, isInTransaction, needLock, forceCertificationAllowed);
162 if (changeStateResponse.isRight()) {
163 response = Either.right(changeStateResponse.right().value());
166 responsePair = new ImmutablePair<>(changeStateResponse.left().value(), response.left()
168 response = Either.left(responsePair);
172 ResponseFormat validationErrorResponse = isValidResource.right().value();
173 auditErrorImport(resourceMetaData, creator, validationErrorResponse, true);
174 response = Either.right(validationErrorResponse);
178 catch (RuntimeException e) {
179 ResponseFormat exceptionResponse = handleImportResourceException(resourceMetaData, creator, true, e, null);
180 response = Either.right(exceptionResponse);
183 if (latestCertifiedResourceId != null && needLock) {
184 log.debug("unlock resource {}", latestCertifiedResourceId);
185 graphLockOperation.unlockComponent(latestCertifiedResourceId, NodeTypeEnum.Resource);
192 private String getLatestCertifiedResourceId(Resource resource) {
193 Map<String, String> allVersions = resource.getAllVersions();
194 Double latestCertifiedVersion = 0.0;
195 if (allVersions != null) {
196 for (String version : allVersions.keySet()) {
197 Double dVersion = Double.valueOf(version);
198 if ((dVersion > latestCertifiedVersion) && (version.endsWith(".0"))) {
199 latestCertifiedVersion = dVersion;
202 return allVersions.get(String.valueOf(latestCertifiedVersion));
209 public void populateResourceMetadata(UploadResourceInfo resourceMetaData, Resource resource) {
210 if (resource != null && resourceMetaData != null) {
211 resource.setDescription(resourceMetaData.getDescription());
212 resource.setTags(resourceMetaData.getTags());
213 resource.setCategories(resourceMetaData.getCategories());
214 resource.setContactId(resourceMetaData.getContactId());
215 resource.setName(resourceMetaData.getName());
216 resource.setIcon(resourceMetaData.getResourceIconPath());
217 resource.setResourceVendorModelNumber(resourceMetaData.getResourceVendorModelNumber());
218 resource.setResourceType(ResourceTypeEnum.valueOf(resourceMetaData.getResourceType()));
219 if (resourceMetaData.getVendorName() != null) {
220 resource.setVendorName(resourceMetaData.getVendorName());
222 if (resourceMetaData.getVendorRelease() != null) {
223 resource.setVendorRelease(resourceMetaData.getVendorRelease());
228 public Either<ImmutablePair<Resource, ActionStatus>, ResponseFormat> importUserDefinedResource(String resourceYml, UploadResourceInfo resourceMetaData, User creator, boolean isInTransaction) {
230 Resource resource = new Resource();
231 ImmutablePair<Resource, ActionStatus> responsePair = new ImmutablePair<>(resource, ActionStatus.CREATED);
232 Either<ImmutablePair<Resource, ActionStatus>, ResponseFormat> response = Either.left(responsePair);
235 setMetaDataFromJson(resourceMetaData, resource);
237 Either<Boolean, ResponseFormat> validateResourceFromYaml = populateResourceFromYaml(resourceYml, resource);
238 if (validateResourceFromYaml.isRight()) {
239 ResponseFormat validationErrorResponse = validateResourceFromYaml.right().value();
240 auditErrorImport(resourceMetaData, creator, validationErrorResponse, false);
241 return Either.right(validationErrorResponse);
245 // currently import VF isn't supported. In future will be supported
246 // import VF only with CSAR file!!
247 if (ResourceTypeEnum.VF.equals(resource.getResourceType())) {
248 log.debug("Now import VF isn't supported. It will be supported in future with CSAR file only");
249 return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
252 resourceBusinessLogic.validateDerivedFromNotEmpty(creator, resource, AuditingActionEnum.CREATE_RESOURCE);
253 Either<Boolean, ResponseFormat> validatePropertiesTypes = resourceBusinessLogic.validatePropertiesDefaultValues(resource);
255 if (validatePropertiesTypes.isLeft()) {
256 response = Either.left(resourceBusinessLogic.createOrUpdateResourceByImport(resource, creator, false, isInTransaction, true, null, null, false));
259 ResponseFormat validationErrorResponse = validatePropertiesTypes.right().value();
260 auditErrorImport(resourceMetaData, creator, validationErrorResponse, false);
261 response = Either.right(validationErrorResponse);
265 catch (ComponentException e) {
266 response = Either.right(handleImportResourceException(resourceMetaData, creator, false, e,
267 e.getResponseFormat()));
269 catch (RuntimeException e) {
270 response = Either.right(handleImportResourceException(resourceMetaData, creator, false, e, null));
276 Either<Boolean, ResponseFormat> populateResourceFromYaml(String resourceYml, Resource resource) {
277 @SuppressWarnings("unchecked")
278 Either<Boolean, ResponseFormat> eitherResult = Either.left(true);
279 Map<String, Object> toscaJsonAll = (Map<String, Object>) new Yaml().load(resourceYml);
280 Map<String, Object> toscaJson = toscaJsonAll;
282 // Checks if exist and builds the node_types map
283 if (toscaJsonAll.containsKey(TypeUtils.ToscaTagNamesEnum.NODE_TYPES.getElementName()) && resource.getResourceType() != ResourceTypeEnum.CVFC) {
284 toscaJson = new HashMap<>();
285 toscaJson.put(TypeUtils.ToscaTagNamesEnum.NODE_TYPES.getElementName(), toscaJsonAll.get(TypeUtils.ToscaTagNamesEnum.NODE_TYPES.getElementName()));
288 Either<Resource, ResponseFormat> setDerivedFrom = setDerivedFrom(toscaJson, resource);
289 if (setDerivedFrom.isRight()) {
290 return Either.right(setDerivedFrom.right().value());
292 Resource parentResource = setDerivedFrom.left().value();
293 if (StringUtils.isEmpty(resource.getToscaResourceName())) {
294 setToscaResourceName(toscaJson, resource);
296 setAttributes(toscaJson, resource);
297 eitherResult = setCapabilities(toscaJson, resource, parentResource);
298 if (eitherResult.isRight()) {
301 eitherResult = setProperties(toscaJson, resource);
302 if (eitherResult.isRight()) {
305 eitherResult = setRequirements(toscaJson, resource, parentResource);
306 if (eitherResult.isRight()) {
309 setInterfaceLifecycle(toscaJson, resource);
314 private void setToscaResourceName(Map<String, Object> toscaJson, Resource resource) {
315 Either<Map<String, Object>, ResultStatusEnum> toscaElement = ImportUtils.findFirstToscaMapElement(toscaJson, TypeUtils.ToscaTagNamesEnum.NODE_TYPES);
316 if (toscaElement.isLeft() || toscaElement.left().value().size() == 1) {
317 String toscaResourceName = toscaElement.left().value().keySet().iterator().next();
318 resource.setToscaResourceName(toscaResourceName);
322 private void setInterfaceLifecycle(Map<String, Object> toscaJson, Resource resource) {
323 Either<Map<String, Object>, ResultStatusEnum> toscaInterfaces = ImportUtils.findFirstToscaMapElement(toscaJson, TypeUtils.ToscaTagNamesEnum.INTERFACES);
324 if (toscaInterfaces.isLeft()) {
325 Map<String, Object> jsonInterfaces = toscaInterfaces.left().value();
326 Map<String, InterfaceDefinition> moduleInterfaces = new HashMap<>();
327 Iterator<Entry<String, Object>> interfacesNameValue = jsonInterfaces.entrySet().iterator();
328 while (interfacesNameValue.hasNext()) {
329 Entry<String, Object> interfaceNameValue = interfacesNameValue.next();
330 Either<InterfaceDefinition, ResultStatusEnum> eitherInterface = createModuleInterface(interfaceNameValue
332 if (eitherInterface.isRight()) {
333 log.info("error when creating interface:{}, for resource:{}", interfaceNameValue.getKey(), resource.getName());
336 moduleInterfaces.put(interfaceNameValue.getKey(), eitherInterface.left().value());
340 if (moduleInterfaces.size() > 0) {
341 resource.setInterfaces(moduleInterfaces);
346 private Either<InterfaceDefinition, ResultStatusEnum> createModuleInterface(Object interfaceJson) {
347 InterfaceDefinition interf = new InterfaceDefinition();
348 Either<InterfaceDefinition, ResultStatusEnum> result = Either.left(interf);
351 if (interfaceJson instanceof String) {
352 String requirementJsonString = (String) interfaceJson;
353 interf.setType(requirementJsonString);
355 else if (interfaceJson instanceof Map) {
356 Map<String, Object> requirementJsonMap = (Map<String, Object>) interfaceJson;
357 if (requirementJsonMap.containsKey(TypeUtils.ToscaTagNamesEnum.TYPE.getElementName())) {
358 String type = (String) requirementJsonMap.get(TypeUtils.ToscaTagNamesEnum.TYPE.getElementName());
359 interf.setType(type);
360 interf.setUniqueId(type.toLowerCase());
364 result = Either.right(ResultStatusEnum.GENERAL_ERROR);
368 catch (Exception e) {
369 BeEcompErrorManager.getInstance().logBeSystemError("Import Resource- create interface");
370 log.debug("error when creating interface, message:{}", e.getMessage(), e);
371 result = Either.right(ResultStatusEnum.GENERAL_ERROR);
377 private Either<Boolean, ResponseFormat> setRequirements(Map<String, Object> toscaJson, Resource resource, Resource parentResource) {// Note that parentResource can be null
378 Either<Boolean, ResponseFormat> eitherResult = Either.left(true);
379 Either<List<Object>, ResultStatusEnum> toscaRequirements = ImportUtils.findFirstToscaListElement(toscaJson, TypeUtils.ToscaTagNamesEnum.REQUIREMENTS);
380 if (toscaRequirements.isLeft()) {
381 List<Object> jsonRequirements = toscaRequirements.left().value();
382 Map<String, List<RequirementDefinition>> moduleRequirements = new HashMap<>();
383 // Checking for name duplication
384 Set<String> reqNames = new HashSet<>();
385 // Getting flattened list of capabilities of parent node - cap name
387 Either<Map<String, String>, ResponseFormat> reqName2Type = getReqName2Type(parentResource);
388 if (reqName2Type.isRight()) {
389 ResponseFormat responseFormat = reqName2Type.right().value();
390 log.debug("Error during setting requirements of imported resource: {}", responseFormat);
391 return Either.right(responseFormat);
393 Map<String, String> reqName2TypeMap = reqName2Type.left().value();
394 for (Object jsonRequirementObj : jsonRequirements) {
396 Map<String, Object> requirementJsonWrapper = (Map<String, Object>) jsonRequirementObj;
397 String requirementName = requirementJsonWrapper.keySet().iterator().next();
398 String reqNameLowerCase = requirementName.toLowerCase();
399 if (reqNames.contains(reqNameLowerCase)) {
400 log.debug("More than one requirement with same name {} (case-insensitive) in imported TOSCA file is invalid", reqNameLowerCase);
401 return Either.right(componentsUtils.getResponseFormat(ActionStatus.IMPORT_DUPLICATE_REQ_CAP_NAME, "requirement", reqNameLowerCase));
403 reqNames.add(reqNameLowerCase);
404 Either<RequirementDefinition, ResponseFormat> eitherRequirement = createRequirementFromImportFile(requirementJsonWrapper
405 .get(requirementName));
406 if (eitherRequirement.isRight()) {
407 log.info("error when creating Requirement:{}, for resource:{}", requirementName, resource.getName());
408 return Either.right(eitherRequirement.right().value());
410 RequirementDefinition requirementDef = eitherRequirement.left().value();
411 requirementDef.setName(requirementName);
412 if (moduleRequirements.containsKey(requirementDef.getCapability())) {
413 moduleRequirements.get(requirementDef.getCapability()).add(requirementDef);
416 List<RequirementDefinition> list = new ArrayList<>();
417 list.add(requirementDef);
418 moduleRequirements.put(requirementDef.getCapability(), list);
421 // Validating against req/cap of "derived from" node
422 Either<Boolean, ResponseFormat> validateVsParentCap = validateCapNameVsDerived(reqName2TypeMap, requirementDef
423 .getCapability(), requirementDef.getName());
424 if (validateVsParentCap.isRight()) {
425 return Either.right(validateVsParentCap.right().value());
427 if (!validateVsParentCap.left().value()) {
428 log.debug("Requirement with name {} already exists in parent {}", requirementDef.getName(), parentResource
430 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.IMPORT_REQ_CAP_NAME_EXISTS_IN_DERIVED, "requirement", requirementDef
432 .toLowerCase(), parentResource.getName());
433 return Either.right(responseFormat);
436 if (moduleRequirements.size() > 0) {
437 resource.setRequirements(moduleRequirements);
445 private Either<RequirementDefinition, ResponseFormat> createRequirementFromImportFile(Object requirementJson) {
446 RequirementDefinition requirement = new RequirementDefinition();
447 Either<RequirementDefinition, ResponseFormat> result = Either.left(requirement);
450 if (requirementJson instanceof String) {
451 String requirementJsonString = (String) requirementJson;
452 requirement.setCapability(requirementJsonString);
454 else if (requirementJson instanceof Map) {
455 Map<String, Object> requirementJsonMap = (Map<String, Object>) requirementJson;
456 if (requirementJsonMap.containsKey(TypeUtils.ToscaTagNamesEnum.CAPABILITY.getElementName())) {
457 requirement.setCapability((String) requirementJsonMap.get(TypeUtils.ToscaTagNamesEnum.CAPABILITY.getElementName()));
460 if (requirementJsonMap.containsKey(TypeUtils.ToscaTagNamesEnum.NODE.getElementName())) {
461 requirement.setNode((String) requirementJsonMap.get(TypeUtils.ToscaTagNamesEnum.NODE.getElementName()));
464 if (requirementJsonMap.containsKey(TypeUtils.ToscaTagNamesEnum.RELATIONSHIP.getElementName())) {
465 requirement.setRelationship((String) requirementJsonMap.get(TypeUtils.ToscaTagNamesEnum.RELATIONSHIP.getElementName()));
467 if (requirementJsonMap.containsKey(TypeUtils.ToscaTagNamesEnum.OCCURRENCES.getElementName())) {
468 List<Object> occurrencesList = (List) requirementJsonMap.get(TypeUtils.ToscaTagNamesEnum.OCCURRENCES.getElementName());
469 Either<Boolean, ResponseFormat> validateAndSetOccurrencesStatus = validateOccurrences(occurrencesList);
470 if (validateAndSetOccurrencesStatus.isRight()) {
471 result = Either.right(validateAndSetOccurrencesStatus.right().value());
474 if (validateAndSetOccurrencesStatus.left().value()) {
475 requirement.setMinOccurrences(occurrencesList.get(0).toString());
476 requirement.setMaxOccurrences(occurrencesList.get(1).toString());
482 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_YAML));
486 catch (Exception e) {
487 BeEcompErrorManager.getInstance().logBeSystemError("Import Resource - create Requirement");
488 log.debug("error when creating requirement, message:{}", e.getMessage(), e);
489 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_YAML));
495 private Either<Boolean, ResponseFormat> setProperties(Map<String, Object> toscaJson, Resource resource) {
496 Map<String, Object> reducedToscaJson = new HashMap<>(toscaJson);
497 ImportUtils.removeElementFromJsonMap(reducedToscaJson, "capabilities");
498 Either<Boolean, ResponseFormat> result = Either.left(true);
499 Either<Map<String, PropertyDefinition>, ResultStatusEnum> properties = ImportUtils.getProperties(reducedToscaJson);
500 if (properties.isLeft()) {
501 List<PropertyDefinition> propertiesList = new ArrayList<>();
502 Map<String, PropertyDefinition> value = properties.left().value();
504 for (Entry<String, PropertyDefinition> entry : value.entrySet()) {
505 String name = entry.getKey();
506 if (!PROPERTY_NAME_PATTERN_IGNORE_LENGTH.matcher(name).matches()) {
507 log.debug("The property with invalid name {} occured upon import resource {}. ", name, resource.getName());
508 result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromResultStatusEnum(ResultStatusEnum.INVALID_PROPERTY_NAME, JsonPresentationFields.PROPERTY)));
510 PropertyDefinition propertyDefinition = entry.getValue();
511 propertyDefinition.setName(name);
512 propertiesList.add(propertyDefinition);
515 resource.setProperties(propertiesList);
517 else if (properties.right().value() != ResultStatusEnum.ELEMENT_NOT_FOUND) {
518 result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromResultStatusEnum(properties
520 .value(), JsonPresentationFields.PROPERTY)));
525 private ResultStatusEnum setAttributes(Map<String, Object> toscaJson, Resource resource) {
526 ResultStatusEnum result = ResultStatusEnum.OK;
527 Either<Map<String, PropertyDefinition>, ResultStatusEnum> attributes = ImportUtils.getAttributes(toscaJson);
528 if (attributes.isLeft()) {
529 List<PropertyDefinition> attributeList = new ArrayList<>();
530 Map<String, PropertyDefinition> value = attributes.left().value();
532 for (Entry<String, PropertyDefinition> entry : value.entrySet()) {
533 String name = entry.getKey();
534 PropertyDefinition attributeDef = entry.getValue();
535 attributeDef.setName(name);
536 attributeList.add(attributeDef);
539 resource.setAttributes(attributeList);
542 result = attributes.right().value();
547 private Either<Resource, ResponseFormat> setDerivedFrom(Map<String, Object> toscaJson, Resource resource) {
548 Either<String, ResultStatusEnum> toscaDerivedFromElement = ImportUtils.findFirstToscaStringElement(toscaJson, TypeUtils.ToscaTagNamesEnum.DERIVED_FROM);
549 Resource derivedFromResource = null;
550 if (toscaDerivedFromElement.isLeft()) {
551 String derivedFrom = toscaDerivedFromElement.left().value();
552 log.debug("Derived from TOSCA name is {}", derivedFrom);
553 resource.setDerivedFrom(Arrays.asList(new String[]{derivedFrom}));
554 Either<Resource, StorageOperationStatus> latestByToscaResourceName = toscaOperationFacade.getLatestByToscaResourceName(derivedFrom);
556 if (latestByToscaResourceName.isRight()) {
557 StorageOperationStatus operationStatus = latestByToscaResourceName.right().value();
558 if (operationStatus.equals(StorageOperationStatus.NOT_FOUND)) {
559 operationStatus = StorageOperationStatus.PARENT_RESOURCE_NOT_FOUND;
561 log.debug("Error when fetching parent resource {}, error: {}", derivedFrom, operationStatus);
562 ActionStatus convertFromStorageResponse = componentsUtils.convertFromStorageResponse(operationStatus);
563 BeEcompErrorManager.getInstance()
564 .logBeComponentMissingError("Import TOSCA YAML", "resource", derivedFrom);
565 return Either.right(componentsUtils.getResponseFormat(convertFromStorageResponse, derivedFrom));
567 derivedFromResource = latestByToscaResourceName.left().value();
569 return Either.left(derivedFromResource);
572 private Either<Boolean, ResponseFormat> setCapabilities(Map<String, Object> toscaJson, Resource resource, Resource parentResource) {// Note that parentResource can be null
573 Either<Boolean, ResponseFormat> eitherResult = Either.left(true);
574 Either<Map<String, Object>, ResultStatusEnum> toscaCapabilities = ImportUtils.findFirstToscaMapElement(toscaJson, TypeUtils.ToscaTagNamesEnum.CAPABILITIES);
575 if (toscaCapabilities.isLeft()) {
576 Map<String, Object> jsonCapabilities = toscaCapabilities.left().value();
577 Map<String, List<CapabilityDefinition>> moduleCapabilities = new HashMap<>();
578 Iterator<Entry<String, Object>> capabilitiesNameValue = jsonCapabilities.entrySet().iterator();
579 Set<String> capNames = new HashSet<>();
580 // Getting flattened list of capabilities of parent node - cap name
582 Either<Map<String, String>, ResponseFormat> capName2Type = getCapName2Type(parentResource);
583 if (capName2Type.isRight()) {
584 ResponseFormat responseFormat = capName2Type.right().value();
585 log.debug("Error during setting capabilities of imported resource: {}", responseFormat);
586 return Either.right(responseFormat);
588 Map<String, String> capName2TypeMap = capName2Type.left().value();
589 while (capabilitiesNameValue.hasNext()) {
590 Entry<String, Object> capabilityNameValue = capabilitiesNameValue.next();
592 // Validating that no req/cap duplicates exist in imported YAML
593 String capNameLowerCase = capabilityNameValue.getKey().toLowerCase();
594 if (capNames.contains(capNameLowerCase)) {
595 log.debug("More than one capability with same name {} (case-insensitive) in imported TOSCA file is invalid", capNameLowerCase);
596 return Either.right(componentsUtils.getResponseFormat(ActionStatus.IMPORT_DUPLICATE_REQ_CAP_NAME, "capability", capNameLowerCase));
598 capNames.add(capNameLowerCase);
600 Either<CapabilityDefinition, ResponseFormat> eitherCapability = createCapabilityFromImportFile(capabilityNameValue
602 if (eitherCapability.isRight()) {
603 log.debug("error when creating capability:{}, for resource:{}", capabilityNameValue.getKey(), resource
605 return Either.right(eitherCapability.right().value());
608 CapabilityDefinition capabilityDef = eitherCapability.left().value();
609 capabilityDef.setName(capabilityNameValue.getKey());
610 if (moduleCapabilities.containsKey(capabilityDef.getType())) {
611 moduleCapabilities.get(capabilityDef.getType()).add(capabilityDef);
614 List<CapabilityDefinition> list = new ArrayList<>();
615 list.add(capabilityDef);
616 moduleCapabilities.put(capabilityDef.getType(), list);
619 // Validating against req/cap of "derived from" node
620 Either<Boolean, ResponseFormat> validateVsParentCap = validateCapNameVsDerived(capName2TypeMap, capabilityDef
621 .getType(), capabilityDef.getName());
622 if (validateVsParentCap.isRight()) {
623 return Either.right(validateVsParentCap.right().value());
625 if (!validateVsParentCap.left().value()) {
626 // Here parentResource is for sure not null, so it's
628 log.debug("Capability with name {} already exists in parent {}", capabilityDef.getName(), parentResource
630 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.IMPORT_REQ_CAP_NAME_EXISTS_IN_DERIVED, "capability", capabilityDef
632 .toLowerCase(), parentResource.getName());
633 return Either.right(responseFormat);
636 if (moduleCapabilities.size() > 0) {
637 resource.setCapabilities(moduleCapabilities);
645 private Either<Map<String, String>, ResponseFormat> getCapName2Type(Resource parentResource) {
646 Map<String, String> capName2type = new HashMap<>();
647 if (parentResource != null) {
648 Map<String, List<CapabilityDefinition>> capabilities = parentResource.getCapabilities();
649 if (capabilities != null) {
650 for (List<CapabilityDefinition> capDefinitions : capabilities.values()) {
651 for (CapabilityDefinition capDefinition : capDefinitions) {
652 String nameLowerCase = capDefinition.getName().toLowerCase();
653 if (capName2type.get(nameLowerCase) != null) {
654 String parentResourceName = parentResource.getName();
655 log.debug("Resource with name {} has more than one capability with name {}, ignoring case", parentResourceName, nameLowerCase);
656 BeEcompErrorManager.getInstance()
657 .logInternalDataError("Import resource", "Parent resource " + parentResourceName + " of imported resource has one or more capabilities with name " + nameLowerCase, ErrorSeverity.ERROR);
658 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
660 capName2type.put(nameLowerCase, capDefinition.getType());
665 return Either.left(capName2type);
668 private Either<Map<String, String>, ResponseFormat> getReqName2Type(Resource parentResource) {
669 Map<String, String> reqName2type = new HashMap<>();
670 if (parentResource != null) {
671 Map<String, List<RequirementDefinition>> requirements = parentResource.getRequirements();
672 if (requirements != null) {
673 for (List<RequirementDefinition> reqDefinitions : requirements.values()) {
674 for (RequirementDefinition reqDefinition : reqDefinitions) {
675 String nameLowerCase = reqDefinition.getName().toLowerCase();
676 if (reqName2type.get(nameLowerCase) != null) {
677 String parentResourceName = parentResource.getName();
678 log.debug("Resource with name {} has more than one requirement with name {}, ignoring case", parentResourceName, nameLowerCase);
679 BeEcompErrorManager.getInstance()
680 .logInternalDataError("Import resource", "Parent resource " + parentResourceName + " of imported resource has one or more requirements with name " + nameLowerCase, ErrorSeverity.ERROR);
681 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
683 reqName2type.put(nameLowerCase, reqDefinition.getCapability());
688 return Either.left(reqName2type);
691 private Either<Boolean, ResponseFormat> validateCapNameVsDerived(Map<String, String> parentCapName2Type, String childCapabilityType, String reqCapName) {
692 String capNameLowerCase = reqCapName.toLowerCase();
693 log.trace("Validating capability {} vs parent resource", capNameLowerCase);
694 String parentCapType = parentCapName2Type.get(capNameLowerCase);
695 if (parentCapType != null) {
696 if (childCapabilityType.equals(parentCapType)) {
697 log.debug("Capability with name {} is of same type {} for imported resource and its parent - this is OK", capNameLowerCase, childCapabilityType);
698 return Either.left(true);
700 Either<Boolean, StorageOperationStatus> capabilityTypeDerivedFrom = capabilityTypeOperation.isCapabilityTypeDerivedFrom(childCapabilityType, parentCapType);
701 if (capabilityTypeDerivedFrom.isRight()) {
702 log.debug("Couldn't check whether imported resource capability derives from its parent's capability");
703 ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(capabilityTypeDerivedFrom
706 return Either.right(responseFormat);
708 return Either.left(capabilityTypeDerivedFrom.left().value());
710 return Either.left(true);
713 private Either<CapabilityDefinition, ResponseFormat> createCapabilityFromImportFile(Object capabilityJson) {
715 CapabilityDefinition capabilityDefinition = new CapabilityDefinition();
716 Either<CapabilityDefinition, ResponseFormat> result = Either.left(capabilityDefinition);
719 if (capabilityJson instanceof String) {
720 String capabilityJsonString = (String) capabilityJson;
721 capabilityDefinition.setType(capabilityJsonString);
723 else if (capabilityJson instanceof Map) {
724 Map<String, Object> capabilityJsonMap = (Map<String, Object>) capabilityJson;
726 if (capabilityJsonMap.containsKey(TypeUtils.ToscaTagNamesEnum.TYPE.getElementName())) {
727 capabilityDefinition.setType((String) capabilityJsonMap.get(TypeUtils.ToscaTagNamesEnum.TYPE.getElementName()));
730 if (capabilityJsonMap.containsKey(TypeUtils.ToscaTagNamesEnum.VALID_SOURCE_TYPES.getElementName())) {
731 capabilityDefinition.setValidSourceTypes((List<String>) capabilityJsonMap.get(TypeUtils.ToscaTagNamesEnum.VALID_SOURCE_TYPES
735 if (capabilityJsonMap.containsKey(TypeUtils.ToscaTagNamesEnum.DESCRIPTION.getElementName())) {
736 capabilityDefinition.setDescription((String) capabilityJsonMap.get(TypeUtils.ToscaTagNamesEnum.DESCRIPTION.getElementName()));
738 if (capabilityJsonMap.containsKey(TypeUtils.ToscaTagNamesEnum.OCCURRENCES.getElementName())) {
739 List<Object> occurrencesList = (List) capabilityJsonMap.get(TypeUtils.ToscaTagNamesEnum.OCCURRENCES.getElementName());
740 Either<Boolean, ResponseFormat> validateAndSetOccurrencesStatus = validateOccurrences(occurrencesList);
741 if (validateAndSetOccurrencesStatus.isRight()) {
742 result = Either.right(validateAndSetOccurrencesStatus.right().value());
745 if (validateAndSetOccurrencesStatus.left().value()) {
746 capabilityDefinition.setMinOccurrences(occurrencesList.get(0).toString());
747 capabilityDefinition.setMaxOccurrences(occurrencesList.get(1).toString());
750 if (capabilityJsonMap.containsKey(TypeUtils.ToscaTagNamesEnum.PROPERTIES.getElementName())) {
752 Either<Map<String, PropertyDefinition>, ResultStatusEnum> propertiesRes = ImportUtils.getProperties(capabilityJsonMap);
753 if (propertiesRes.isRight()) {
754 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.PROPERTY_NOT_FOUND));
762 .forEach(e -> e.getValue().setName(e.getKey().toLowerCase()));
763 List<ComponentInstanceProperty> capabilityProperties = propertiesRes.left()
767 .map(p -> new ComponentInstanceProperty(p, p
768 .getDefaultValue(), null))
769 .collect(Collectors.toList());
770 capabilityDefinition.setProperties(capabilityProperties);
774 else if (!(capabilityJson instanceof List)) {
776 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_YAML));
780 catch (Exception e) {
781 BeEcompErrorManager.getInstance().logBeSystemError("Import Resource - create capability");
782 log.debug("error when creating capability, message:{}", e.getMessage(), e);
783 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_YAML));
789 private ResponseFormat handleImportResourceException(UploadResourceInfo resourceMetaData, User user, boolean isNormative, RuntimeException e, ResponseFormat responseFormat) {
790 if(responseFormat == null ){
791 responseFormat = getResponseFormatManager().getResponseFormat(ActionStatus.GENERAL_ERROR);
793 String payloadName = (resourceMetaData != null) ? resourceMetaData.getPayloadName() : "";
794 BeEcompErrorManager.getInstance().logBeSystemError("Import Resource " + payloadName);
795 log.debug("Error when importing resource from payload:{} Exception text: {}", payloadName, e.getMessage(), e);
796 auditErrorImport(resourceMetaData, user, responseFormat, isNormative);
797 return responseFormat;
800 private void auditErrorImport(UploadResourceInfo resourceMetaData, User user, ResponseFormat errorResponseWrapper, boolean isNormative) {
801 String version, lifeCycleState;
803 version = TypeUtils.FIRST_CERTIFIED_VERSION_VERSION;
804 lifeCycleState = LifecycleStateEnum.CERTIFIED.name();
808 lifeCycleState = LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.name();
813 if (errorResponseWrapper.getMessageId() != null) {
814 message = errorResponseWrapper.getMessageId() + ": ";
816 message += errorResponseWrapper.getFormattedMessage();
819 AuditEventFactory factory = new AuditImportResourceAdminEventFactory(
820 CommonAuditData.newBuilder()
821 .status(errorResponseWrapper.getStatus())
822 .description(message)
823 .requestId(ThreadLocalsHolder.getUuid())
825 new ResourceCommonInfo(resourceMetaData.getName(), ComponentTypeEnum.RESOURCE.getValue()),
826 ResourceVersionInfo.newBuilder()
827 .state(lifeCycleState)
830 ResourceVersionInfo.newBuilder()
835 getAuditingManager().auditEvent(factory);
839 private void setMetaDataFromJson(UploadResourceInfo resourceMetaData, Resource resource) {
840 this.populateResourceMetadata(resourceMetaData, resource);
841 resource.setCreatorUserId(resourceMetaData.getContactId());
842 List<CategoryDefinition> categories = resourceMetaData.getCategories();
843 calculateResourceIsAbstract(resource, categories);
846 private void calculateResourceIsAbstract(Resource resource, List<CategoryDefinition> categories) {
847 if (categories != null && !categories.isEmpty()) {
848 CategoryDefinition categoryDef = categories.get(0);
849 resource.setAbstract(false);
850 if (categoryDef != null && categoryDef.getName() != null && categoryDef.getName()
851 .equals(Constants.ABSTRACT_CATEGORY_NAME)) {
852 SubCategoryDefinition subCategoryDef = categoryDef.getSubcategories().get(0);
853 if (subCategoryDef != null && subCategoryDef.getName().equals(Constants.ABSTRACT_SUBCATEGORY)) {
854 resource.setAbstract(true);
860 private void setConstantMetaData(Resource resource, boolean shouldBeCertified) {
862 LifecycleStateEnum state;
863 if (shouldBeCertified) {
864 version = TypeUtils.FIRST_CERTIFIED_VERSION_VERSION;
865 state = ImportUtils.Constants.NORMATIVE_TYPE_LIFE_CYCLE;
868 version = ImportUtils.Constants.FIRST_NON_CERTIFIED_VERSION;
869 state = ImportUtils.Constants.NORMATIVE_TYPE_LIFE_CYCLE_NOT_CERTIFIED_CHECKOUT;
871 resource.setVersion(version);
872 resource.setLifecycleState(state);
873 resource.setHighestVersion(ImportUtils.Constants.NORMATIVE_TYPE_HIGHEST_VERSION);
874 resource.setVendorName(ImportUtils.Constants.VENDOR_NAME);
875 resource.setVendorRelease(ImportUtils.Constants.VENDOR_RELEASE);
879 private Either<Boolean, ResponseFormat> validateOccurrences(List<Object> occurrensesList) {
881 if (!ValidationUtils.validateListNotEmpty(occurrensesList)) {
882 log.debug("Occurrenses list empty");
883 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_OCCURRENCES);
884 return Either.right(responseFormat);
887 if (occurrensesList.size() < 2) {
888 log.debug("Occurrenses list size not 2");
889 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_OCCURRENCES);
890 return Either.right(responseFormat);
892 Object minObj = occurrensesList.get(0);
893 Object maxObj = occurrensesList.get(1);
894 Integer minOccurrences;
895 Integer maxOccurrences = null;
896 if (minObj instanceof Integer) {
897 minOccurrences = (Integer) minObj;
900 log.debug("Invalid occurrenses format. low_bound occurrense must be Integer {}", minObj);
901 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_OCCURRENCES);
902 return Either.right(responseFormat);
904 if (minOccurrences < 0) {
905 log.debug("Invalid occurrenses format.low_bound occurrense negative {}", minOccurrences);
906 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_OCCURRENCES);
907 return Either.right(responseFormat);
910 if (maxObj instanceof String) {
911 if ("UNBOUNDED".equals(maxObj)) {
912 return Either.left(true);
915 log.debug("Invalid occurrenses format. Max occurrence is {}", maxObj);
916 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_OCCURRENCES);
917 return Either.right(responseFormat);
921 if (maxObj instanceof Integer) {
922 maxOccurrences = (Integer) maxObj;
925 log.debug("Invalid occurrenses format. Max occurrence is {}", maxObj);
926 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_OCCURRENCES);
927 return Either.right(responseFormat);
930 if (maxOccurrences <= 0 || maxOccurrences < minOccurrences) {
931 log.debug("Invalid occurrenses format. min occurrence is {}, Max occurrence is {}", minOccurrences, maxOccurrences);
932 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_OCCURRENCES);
933 return Either.right(responseFormat);
937 return Either.left(true);
941 public synchronized void init(ServletContext servletContext) {
942 if (this.servletContext == null) {
943 this.servletContext = servletContext;
944 responseFormatManager = ResponseFormatManager.getInstance();
945 resourceBusinessLogic = getResourceBL(servletContext);
949 public boolean isResourceExist(String resourceName) {
950 return resourceBusinessLogic.isResourceExist(resourceName);
953 private ResourceBusinessLogic getResourceBL(ServletContext context) {
954 WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(org.openecomp.sdc.common.api.Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR);
955 WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context);
956 return webApplicationContext.getBean(ResourceBusinessLogic.class);
959 public ServletContext getServletContext() {
960 return servletContext;
963 public AuditingManager getAuditingManager() {
964 return auditingManager;
967 public ResponseFormatManager getResponseFormatManager() {
968 return responseFormatManager;
971 public void setResponseFormatManager(ResponseFormatManager responseFormatManager) {
972 this.responseFormatManager = responseFormatManager;
975 public ResourceBusinessLogic getResourceBusinessLogic() {
976 return resourceBusinessLogic;
980 public void setResourceBusinessLogic(ResourceBusinessLogic resourceBusinessLogic) {
981 this.resourceBusinessLogic = resourceBusinessLogic;
984 public IGraphLockOperation getGraphLockOperation() {
985 return graphLockOperation;
989 public void setGraphLockOperation(IGraphLockOperation graphLockOperation) {
990 this.graphLockOperation = graphLockOperation;
993 public void setServletContext(ServletContext servletContext) {
994 this.servletContext = servletContext;
998 public void setAuditingManager(AuditingManager auditingManager) {
999 this.auditingManager = auditingManager;