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=========================================================
21 package org.openecomp.sdc.be.components.impl;
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.EnumMap;
26 import java.util.HashMap;
27 import java.util.HashSet;
28 import java.util.Iterator;
29 import java.util.List;
31 import java.util.Map.Entry;
33 import java.util.function.Function;
34 import java.util.stream.Collectors;
36 import javax.servlet.ServletContext;
38 import org.apache.commons.lang3.tuple.ImmutablePair;
39 import org.openecomp.sdc.be.auditing.api.IAuditingManager;
40 import org.openecomp.sdc.be.components.impl.ImportUtils.Constants;
41 import org.openecomp.sdc.be.components.impl.ImportUtils.ResultStatusEnum;
42 import org.openecomp.sdc.be.components.impl.ImportUtils.ToscaTagNamesEnum;
43 import org.openecomp.sdc.be.components.lifecycle.LifecycleChangeInfoWithAction;
44 import org.openecomp.sdc.be.config.BeEcompErrorManager;
45 import org.openecomp.sdc.be.config.BeEcompErrorManager.ErrorSeverity;
46 import org.openecomp.sdc.be.dao.api.ActionStatus;
47 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
48 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
49 import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
50 import org.openecomp.sdc.be.impl.ComponentsUtils;
51 import org.openecomp.sdc.be.impl.WebAppContextWrapper;
52 import org.openecomp.sdc.be.model.AttributeDefinition;
53 import org.openecomp.sdc.be.model.CapabilityDefinition;
54 import org.openecomp.sdc.be.model.ComponentInstanceProperty;
55 import org.openecomp.sdc.be.model.InterfaceDefinition;
56 import org.openecomp.sdc.be.model.LifecycleStateEnum;
57 import org.openecomp.sdc.be.model.PropertyDefinition;
58 import org.openecomp.sdc.be.model.RequirementDefinition;
59 import org.openecomp.sdc.be.model.Resource;
60 import org.openecomp.sdc.be.model.UploadResourceInfo;
61 import org.openecomp.sdc.be.model.User;
62 import org.openecomp.sdc.be.model.category.CategoryDefinition;
63 import org.openecomp.sdc.be.model.category.SubCategoryDefinition;
64 import org.openecomp.sdc.be.model.operations.api.IGraphLockOperation;
65 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
66 import org.openecomp.sdc.be.model.operations.impl.CapabilityTypeOperation;
67 import org.openecomp.sdc.be.model.operations.impl.ResourceOperation;
68 import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
69 import org.openecomp.sdc.common.config.EcompErrorName;
70 import org.openecomp.sdc.common.datastructure.AuditingFieldsKeysEnum;
71 import org.openecomp.sdc.common.util.ValidationUtils;
72 import org.openecomp.sdc.exception.ResponseFormat;
73 import org.slf4j.Logger;
74 import org.slf4j.LoggerFactory;
75 import org.springframework.beans.factory.annotation.Autowired;
76 import org.springframework.stereotype.Component;
77 import org.springframework.web.context.WebApplicationContext;
78 import org.yaml.snakeyaml.Yaml;
80 import fj.data.Either;
82 @Component("resourceImportManager")
83 public class ResourceImportManager {
85 private ServletContext servletContext;
88 private IAuditingManager auditingManager;
91 private ResourceBusinessLogic resourceBusinessLogic;
94 private IGraphLockOperation graphLockOperation;
97 protected ComponentsUtils componentsUtils;
100 protected ResourceOperation resourceOperation;
103 protected CapabilityTypeOperation capabilityTypeOperation;
105 private ResponseFormatManager responseFormatManager;
107 private static Logger log = LoggerFactory.getLogger(ResourceImportManager.class.getName());
109 public Either<ImmutablePair<Resource, ActionStatus>, ResponseFormat> importNormativeResource(String resourceYml, UploadResourceInfo resourceMetaData, User creator, boolean createNewVersion, boolean needLock) {
111 LifecycleChangeInfoWithAction lifecycleChangeInfo = new LifecycleChangeInfoWithAction();
112 lifecycleChangeInfo.setUserRemarks("certification on import");
113 Function<Resource, Either<Boolean, ResponseFormat>> validator = (resource) -> resourceBusinessLogic.validatePropertiesDefaultValues(resource);
115 return importCertifiedResource(resourceYml, resourceMetaData, creator, validator, lifecycleChangeInfo, false, createNewVersion, needLock);
118 public Either<ImmutablePair<Resource, ActionStatus>, ResponseFormat> importCertifiedResource(String resourceYml, UploadResourceInfo resourceMetaData, User creator, Function<Resource, Either<Boolean, ResponseFormat>> validationFunction,
119 LifecycleChangeInfoWithAction lifecycleChangeInfo, boolean isInTransaction, boolean createNewVersion, boolean needLock) {
120 Resource resource = new Resource();
121 ImmutablePair<Resource, ActionStatus> responsePair = new ImmutablePair<Resource, ActionStatus>(resource, ActionStatus.CREATED);
122 Either<ImmutablePair<Resource, ActionStatus>, ResponseFormat> response = Either.left(responsePair);
124 String latestCertifiedResourceId = null;
126 setConstantMetaData(resource);
127 setMetaDataFromJson(resourceMetaData, resource);
129 Either<Boolean, ResponseFormat> validateResourceFromYaml = populateResourceFromYaml(resourceYml, resource, isInTransaction);
130 if (validateResourceFromYaml.isRight()) {
131 ResponseFormat validationErrorResponse = validateResourceFromYaml.right().value();
132 auditErrorImport(resourceMetaData, creator, validationErrorResponse, true);
133 return Either.right(validationErrorResponse);
137 Either<Boolean, ResponseFormat> isValidResource = validationFunction.apply(resource);
138 if (isValidResource.isLeft()) {
139 // The flag createNewVersion if false doesn't create new version
140 if (!createNewVersion) {
141 Either<Resource, StorageOperationStatus> latestByName = resourceOperation.getLatestByName(resource.getName(), isInTransaction);
142 if (latestByName.isLeft()) {
143 return Either.right(componentsUtils.getResponseFormatByResource(ActionStatus.COMPONENT_NAME_ALREADY_EXIST, resource));
147 response = resourceBusinessLogic.createOrUpdateResourceByImport(resource, creator, true, isInTransaction, needLock);
148 if (response.isLeft()) {
149 resource = response.left().value().left;
150 latestCertifiedResourceId = getLatestCertifiedResourceId(resource);
151 Either<Resource, ResponseFormat> certificationResponse = resourceBusinessLogic.propagateStateToCertified(creator, resource, lifecycleChangeInfo, isInTransaction, needLock);
152 if (certificationResponse.isRight()) {
153 response = Either.right(certificationResponse.right().value());
155 responsePair = new ImmutablePair<Resource, ActionStatus>(certificationResponse.left().value(), response.left().value().right);
156 response = Either.left(responsePair);
160 ResponseFormat validationErrorResponse = isValidResource.right().value();
161 auditErrorImport(resourceMetaData, creator, validationErrorResponse, true);
162 response = Either.right(validationErrorResponse);
165 } catch (RuntimeException e) {
166 ResponseFormat exceptionResponse = handleImportResourceExecption(resourceMetaData, creator, true, e);
167 response = Either.right(exceptionResponse);
169 if (latestCertifiedResourceId != null && needLock) {
170 log.debug("unlock resource {}", latestCertifiedResourceId);
171 graphLockOperation.unlockComponent(latestCertifiedResourceId, NodeTypeEnum.Resource);
178 private String getLatestCertifiedResourceId(Resource resource) {
179 Map<String, String> allVersions = resource.getAllVersions();
180 Double latestCertifiedVersion = 0.0;
181 if (allVersions != null) {
182 for (String version : allVersions.keySet()) {
183 Double dVersion = Double.valueOf(version);
184 if ((dVersion > latestCertifiedVersion) && (version.endsWith(".0"))) {
185 latestCertifiedVersion = dVersion;
188 return allVersions.get(String.valueOf(latestCertifiedVersion));
194 public Either<ImmutablePair<Resource, ActionStatus>, ResponseFormat> importUserDefinedResource(String resourceYml, UploadResourceInfo resourceMetaData, User creator, boolean isReusable, boolean isInTransaction) {
196 Resource resource = new Resource();
197 ImmutablePair<Resource, ActionStatus> responsePair = new ImmutablePair<Resource, ActionStatus>(resource, ActionStatus.CREATED);
198 Either<ImmutablePair<Resource, ActionStatus>, ResponseFormat> response = Either.left(responsePair);
201 setMetaDataFromJson(resourceMetaData, resource);
203 Either<Boolean, ResponseFormat> validateResourceFromYaml = populateResourceFromYaml(resourceYml, resource, isInTransaction);
204 if (validateResourceFromYaml.isRight()) {
205 ResponseFormat validationErrorResponse = validateResourceFromYaml.right().value();
206 auditErrorImport(resourceMetaData, creator, validationErrorResponse, false);
207 return Either.right(validationErrorResponse);
211 // currently import VF isn't supported. In future will be supported
212 // import VF only with CSER file!!
213 if (ResourceTypeEnum.VF.equals(resource.getResourceType())) {
214 log.debug("Now import VF isn't supported. It will be supported in future with CSER file only");
215 return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
218 Either<Boolean, ResponseFormat> validateDerivedFromNotEmpty = resourceBusinessLogic.validateDerivedFromNotEmpty(creator, resource, AuditingActionEnum.CREATE_RESOURCE);
219 if (validateDerivedFromNotEmpty.isRight()) {
220 return Either.right(validateDerivedFromNotEmpty.right().value());
223 Either<Boolean, ResponseFormat> validatePropertiesTypes = resourceBusinessLogic.validatePropertiesDefaultValues(resource);
225 if (validatePropertiesTypes.isLeft()) {
226 response = resourceBusinessLogic.createOrUpdateResourceByImport(resource, creator, false, isInTransaction, true);
228 ResponseFormat validationErrorResponse = validatePropertiesTypes.right().value();
229 auditErrorImport(resourceMetaData, creator, validationErrorResponse, false);
230 response = Either.right(validationErrorResponse);
233 } catch (RuntimeException e) {
234 ResponseFormat exceptionResponse = handleImportResourceExecption(resourceMetaData, creator, false, e);
235 response = Either.right(exceptionResponse);
242 private Either<Boolean, ResponseFormat> populateResourceFromYaml(String resourceYml, Resource resource, boolean inTransaction) {
243 @SuppressWarnings("unchecked")
244 Either<Boolean, ResponseFormat> eitherResult = Either.left(true);
245 Map<String, Object> toscaJsonAll = (Map<String, Object>) new Yaml().load(resourceYml);
246 Map<String, Object> toscaJson = toscaJsonAll;
248 // Checks if exist and builds the node_types map
249 if (toscaJsonAll.containsKey(ToscaTagNamesEnum.NODE_TYPES.getElementName())) {
250 toscaJson = new HashMap<String, Object>();
251 toscaJson.put(ToscaTagNamesEnum.NODE_TYPES.getElementName(), toscaJsonAll.get(ToscaTagNamesEnum.NODE_TYPES.getElementName()));
254 Either<Resource, ResponseFormat> setDerivedFrom = setDerivedFrom(toscaJson, resource, inTransaction);
255 if (setDerivedFrom.isRight()) {
256 return Either.right(setDerivedFrom.right().value());
258 Resource parentResource = setDerivedFrom.left().value();
259 setToscaResourceName(toscaJson, resource);
260 setAttributes(toscaJson, resource);
261 eitherResult = setCapabilities(toscaJson, resource, parentResource);
262 if (eitherResult.isRight())
264 setProperties(toscaJson, resource);
265 eitherResult = setRequirements(toscaJson, resource, parentResource);
266 if (eitherResult.isRight())
268 setInterfaceLifecycle(toscaJson, resource);
273 private void setToscaResourceName(Map<String, Object> toscaJson, Resource resource) {
274 Either<Map<String, Object>, ResultStatusEnum> toscaElement = ImportUtils.findFirstToscaMapElement(toscaJson, ToscaTagNamesEnum.NODE_TYPES);
275 if (toscaElement.isLeft() || toscaElement.left().value().size() == 1) {
276 String toscaResourceName = toscaElement.left().value().keySet().iterator().next();
277 resource.setToscaResourceName(toscaResourceName);
281 private void setInterfaceLifecycle(Map<String, Object> toscaJson, Resource resource) {
282 Either<Map<String, Object>, ResultStatusEnum> toscaInterfaces = ImportUtils.findFirstToscaMapElement(toscaJson, ToscaTagNamesEnum.INTERFACES);
283 if (toscaInterfaces.isLeft()) {
284 Map<String, Object> jsonInterfaces = toscaInterfaces.left().value();
285 Map<String, InterfaceDefinition> moduleInterfaces = new HashMap<String, InterfaceDefinition>();
286 Iterator<Entry<String, Object>> interfacesNameValue = jsonInterfaces.entrySet().iterator();
287 while (interfacesNameValue.hasNext()) {
288 Entry<String, Object> interfaceNameValue = interfacesNameValue.next();
289 Either<InterfaceDefinition, ResultStatusEnum> eitherInterface = createModuleInterface(interfaceNameValue.getValue());
290 if (eitherInterface.isRight()) {
291 log.info("error when creating interface:{}, for resource:{}", interfaceNameValue.getKey(), resource.getName());
293 moduleInterfaces.put(interfaceNameValue.getKey(), eitherInterface.left().value());
297 if (moduleInterfaces.size() > 0) {
298 resource.setInterfaces(moduleInterfaces);
303 private Either<InterfaceDefinition, ResultStatusEnum> createModuleInterface(Object interfaceJson) {
304 InterfaceDefinition interf = new InterfaceDefinition();
305 Either<InterfaceDefinition, ResultStatusEnum> result = Either.left(interf);
308 if (interfaceJson instanceof String) {
309 String requirementJsonString = (String) interfaceJson;
310 interf.setType(requirementJsonString);
311 } else if (interfaceJson instanceof Map) {
312 Map<String, Object> requirementJsonMap = (Map<String, Object>) interfaceJson;
313 if (requirementJsonMap.containsKey(ToscaTagNamesEnum.TYPE.getElementName())) {
314 String type = (String) requirementJsonMap.get(ToscaTagNamesEnum.TYPE.getElementName());
315 interf.setType(type);
316 interf.setUniqueId(type.toLowerCase());
319 result = Either.right(ResultStatusEnum.GENERAL_ERROR);
322 } catch (Exception e) {
323 BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "Import Resource- create interface");
324 BeEcompErrorManager.getInstance().logBeSystemError("Import Resource- create interface");
325 log.debug("error when creating interface, message:{}", e.getMessage(), e);
326 result = Either.right(ResultStatusEnum.GENERAL_ERROR);
332 private Either<Boolean, ResponseFormat> setRequirements(Map<String, Object> toscaJson, Resource resource, Resource parentResource) {// Note that parentResource can be null
333 Either<Boolean, ResponseFormat> eitherResult = Either.left(true);
334 Either<List<Object>, ResultStatusEnum> toscaRequirements = ImportUtils.findFirstToscaListElement(toscaJson, ToscaTagNamesEnum.REQUIREMENTS);
335 if (toscaRequirements.isLeft()) {
336 List<Object> jsonRequirements = toscaRequirements.left().value();
337 Map<String, List<RequirementDefinition>> moduleRequirements = new HashMap<String, List<RequirementDefinition>>();
338 // Checking for name duplication
339 Set<String> reqNames = new HashSet<>();
340 // Getting flattened list of capabilities of parent node - cap name
342 Either<Map<String, String>, ResponseFormat> reqName2Type = getReqName2Type(parentResource);
343 if (reqName2Type.isRight()) {
344 ResponseFormat responseFormat = reqName2Type.right().value();
345 log.debug("Error during setting requirements of imported resource: {}", responseFormat);
346 return Either.right(responseFormat);
348 Map<String, String> reqName2TypeMap = reqName2Type.left().value();
349 for (Object jsonRequirementObj : jsonRequirements) {
351 Map<String, Object> requirementJsonWrapper = (Map<String, Object>) jsonRequirementObj;
352 String requirementName = requirementJsonWrapper.keySet().iterator().next();
353 String reqNameLowerCase = requirementName.toLowerCase();
354 if (reqNames.contains(reqNameLowerCase)) {
355 log.debug("More than one requirement with same name {} (case-insensitive) in imported TOSCA file is invalid", reqNameLowerCase);
356 return Either.right(componentsUtils.getResponseFormat(ActionStatus.IMPORT_DUPLICATE_REQ_CAP_NAME, "requirement", reqNameLowerCase));
358 reqNames.add(reqNameLowerCase);
359 Either<RequirementDefinition, ResponseFormat> eitherRequirement = createRequirementFromImportFile(requirementJsonWrapper.get(requirementName));
360 if (eitherRequirement.isRight()) {
361 log.info("error when creating Requirement:{}, for resource:{}", requirementName, resource.getName());
362 return Either.right(eitherRequirement.right().value());
364 RequirementDefinition requirementDef = eitherRequirement.left().value();
365 requirementDef.setName(requirementName);
366 if (moduleRequirements.containsKey(requirementDef.getCapability())) {
367 moduleRequirements.get(requirementDef.getCapability()).add(requirementDef);
369 List<RequirementDefinition> list = new ArrayList<RequirementDefinition>();
370 list.add(requirementDef);
371 moduleRequirements.put(requirementDef.getCapability(), list);
374 // Validating against req/cap of "derived from" node
375 Either<Boolean, ResponseFormat> validateVsParentCap = validateCapNameVsDerived(reqName2TypeMap, requirementDef.getCapability(), requirementDef.getName());
376 if (validateVsParentCap.isRight()) {
377 return Either.right(validateVsParentCap.right().value());
379 if (!validateVsParentCap.left().value()) {
380 log.debug("Requirement with name {} already exists in parent {}", requirementDef.getName(), parentResource.getName());
381 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.IMPORT_REQ_CAP_NAME_EXISTS_IN_DERIVED, "requirement", requirementDef.getName().toLowerCase(), parentResource.getName());
382 return Either.right(responseFormat);
385 if (moduleRequirements.size() > 0) {
386 resource.setRequirements(moduleRequirements);
394 private Either<RequirementDefinition, ResponseFormat> createRequirementFromImportFile(Object requirementJson) {
395 RequirementDefinition requirement = new RequirementDefinition();
396 Either<RequirementDefinition, ResponseFormat> result = Either.left(requirement);
399 if (requirementJson instanceof String) {
400 String requirementJsonString = (String) requirementJson;
401 requirement.setCapability(requirementJsonString);
402 } else if (requirementJson instanceof Map) {
403 Map<String, Object> requirementJsonMap = (Map<String, Object>) requirementJson;
404 if (requirementJsonMap.containsKey(ToscaTagNamesEnum.CAPABILITY.getElementName())) {
405 requirement.setCapability((String) requirementJsonMap.get(ToscaTagNamesEnum.CAPABILITY.getElementName()));
408 if (requirementJsonMap.containsKey(ToscaTagNamesEnum.NODE.getElementName())) {
409 requirement.setNode((String) requirementJsonMap.get(ToscaTagNamesEnum.NODE.getElementName()));
412 if (requirementJsonMap.containsKey(ToscaTagNamesEnum.RELATIONSHIP.getElementName())) {
413 requirement.setRelationship((String) requirementJsonMap.get(ToscaTagNamesEnum.RELATIONSHIP.getElementName()));
415 if (requirementJsonMap.containsKey(ToscaTagNamesEnum.OCCURRENCES.getElementName())) {
416 List<Object> occurrencesList = (List) requirementJsonMap.get(ToscaTagNamesEnum.OCCURRENCES.getElementName());
417 Either<Boolean, ResponseFormat> validateAndSetOccurrencesStatus = validateOccurrences(occurrencesList);
418 if (validateAndSetOccurrencesStatus.isRight()) {
419 result = Either.right(validateAndSetOccurrencesStatus.right().value());
422 if (validateAndSetOccurrencesStatus.left().value() == true) {
423 requirement.setMinOccurrences(occurrencesList.get(0).toString());
424 requirement.setMaxOccurrences(occurrencesList.get(1).toString());
429 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_YAML));
432 } catch (Exception e) {
433 BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "Import Resource - create Requirement");
434 BeEcompErrorManager.getInstance().logBeSystemError("Import Resource - create Requirement");
435 log.debug("error when creating requirement, message:{}", e.getMessage(), e);
436 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_YAML));
442 private ResultStatusEnum setProperties(Map<String, Object> toscaJson, Resource resource) {
443 Map<String, Object> reducedToscaJson = new HashMap<>(toscaJson);
444 ImportUtils.removeElementFromJsonMap(reducedToscaJson, "capabilities");
445 ResultStatusEnum result = ResultStatusEnum.OK;
446 Either<Map<String, PropertyDefinition>, ResultStatusEnum> properties = ImportUtils.getProperties(reducedToscaJson);
447 if (properties.isLeft()) {
448 List<PropertyDefinition> propertiesList = new ArrayList<>();
449 Map<String, PropertyDefinition> value = properties.left().value();
451 for (Entry<String, PropertyDefinition> entry : value.entrySet()) {
452 String name = entry.getKey();
453 PropertyDefinition propertyDefinition = entry.getValue();
454 propertyDefinition.setName(name);
455 propertiesList.add(propertyDefinition);
458 resource.setProperties(propertiesList);
460 result = properties.right().value();
465 private ResultStatusEnum setAttributes(Map<String, Object> toscaJson, Resource resource) {
466 ResultStatusEnum result = ResultStatusEnum.OK;
467 Either<Map<String, AttributeDefinition>, ResultStatusEnum> attributes = ImportUtils.getAttributes(toscaJson);
468 if (attributes.isLeft()) {
469 List<AttributeDefinition> attributeList = new ArrayList<>();
470 Map<String, AttributeDefinition> value = attributes.left().value();
472 for (Entry<String, AttributeDefinition> entry : value.entrySet()) {
473 String name = entry.getKey();
474 AttributeDefinition attributeDef = entry.getValue();
475 attributeDef.setName(name);
476 attributeList.add(attributeDef);
479 resource.setAttributes(attributeList);
481 result = attributes.right().value();
486 private Either<Resource, ResponseFormat> setDerivedFrom(Map<String, Object> toscaJson, Resource resource, boolean inTransaction) {
487 Either<String, ResultStatusEnum> toscaDerivedFromElement = ImportUtils.findFirstToscaStringElement(toscaJson, ToscaTagNamesEnum.DERIVED_FROM);
488 Resource derivedFromResource = null;
489 if (toscaDerivedFromElement.isLeft()) {
490 String derivedFrom = toscaDerivedFromElement.left().value();
491 log.debug("Derived from TOSCA name is {}", derivedFrom);
492 resource.setDerivedFrom(Arrays.asList(new String[] { derivedFrom }));
493 Either<Resource, StorageOperationStatus> latestByToscaResourceName = resourceOperation.getLatestByToscaResourceName(derivedFrom, inTransaction);
494 if (latestByToscaResourceName.isRight()) {
495 StorageOperationStatus operationStatus = latestByToscaResourceName.right().value();
496 if (operationStatus.equals(StorageOperationStatus.NOT_FOUND)) {
497 operationStatus = StorageOperationStatus.PARENT_RESOURCE_NOT_FOUND;
499 log.debug("Error when fetching parent resource {}, error: {}", derivedFrom, operationStatus);
500 ActionStatus convertFromStorageResponse = componentsUtils.convertFromStorageResponse(operationStatus);
501 BeEcompErrorManager.getInstance().logBeComponentMissingError("Import TOSCA YAML", "resource", derivedFrom);
502 return Either.right(componentsUtils.getResponseFormat(convertFromStorageResponse, derivedFrom));
504 derivedFromResource = latestByToscaResourceName.left().value();
506 return Either.left(derivedFromResource);
509 private Either<Boolean, ResponseFormat> setCapabilities(Map<String, Object> toscaJson, Resource resource, Resource parentResource) {// Note that parentResource can be null
510 Either<Boolean, ResponseFormat> eitherResult = Either.left(true);
511 Either<Map<String, Object>, ResultStatusEnum> toscaCapabilities = ImportUtils.findFirstToscaMapElement(toscaJson, ToscaTagNamesEnum.CAPABILITIES);
512 if (toscaCapabilities.isLeft()) {
513 Map<String, Object> jsonCapabilities = toscaCapabilities.left().value();
514 Map<String, List<CapabilityDefinition>> moduleCapabilities = new HashMap<String, List<CapabilityDefinition>>();
515 Iterator<Entry<String, Object>> capabilitiesNameValue = jsonCapabilities.entrySet().iterator();
516 Set<String> capNames = new HashSet<>();
517 // Getting flattened list of capabilities of parent node - cap name
519 Either<Map<String, String>, ResponseFormat> capName2Type = getCapName2Type(parentResource);
520 if (capName2Type.isRight()) {
521 ResponseFormat responseFormat = capName2Type.right().value();
522 log.debug("Error during setting capabilities of imported resource: {}", responseFormat);
523 return Either.right(responseFormat);
525 Map<String, String> capName2TypeMap = capName2Type.left().value();
526 while (capabilitiesNameValue.hasNext()) {
527 Entry<String, Object> capabilityNameValue = capabilitiesNameValue.next();
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 return Either.right(componentsUtils.getResponseFormat(ActionStatus.IMPORT_DUPLICATE_REQ_CAP_NAME, "capability", capNameLowerCase));
535 capNames.add(capNameLowerCase);
537 Either<CapabilityDefinition, ResponseFormat> eitherCapability = createCapabilityFromImportFile(capabilityNameValue.getValue());
538 if (eitherCapability.isRight()) {
539 log.debug("error when creating capability:{}, for resource:{}", capabilityNameValue.getKey(), resource.getName());
540 return Either.right(eitherCapability.right().value());
543 CapabilityDefinition capabilityDef = eitherCapability.left().value();
544 capabilityDef.setName(capabilityNameValue.getKey());
545 if (moduleCapabilities.containsKey(capabilityDef.getType())) {
546 moduleCapabilities.get(capabilityDef.getType()).add(capabilityDef);
548 List<CapabilityDefinition> list = new ArrayList<CapabilityDefinition>();
549 list.add(capabilityDef);
550 moduleCapabilities.put(capabilityDef.getType(), list);
553 // Validating against req/cap of "derived from" node
554 Either<Boolean, ResponseFormat> validateVsParentCap = validateCapNameVsDerived(capName2TypeMap, capabilityDef.getType(), capabilityDef.getName());
555 if (validateVsParentCap.isRight()) {
556 return Either.right(validateVsParentCap.right().value());
558 if (!validateVsParentCap.left().value()) {
559 // Here parentResource is for sure not null, so it's
561 log.debug("Capability with name {} already exists in parent {}", capabilityDef.getName(), parentResource.getName());
562 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.IMPORT_REQ_CAP_NAME_EXISTS_IN_DERIVED, "capability", capabilityDef.getName().toLowerCase(), parentResource.getName());
563 return Either.right(responseFormat);
566 if (moduleCapabilities.size() > 0) {
567 resource.setCapabilities(moduleCapabilities);
575 private Either<Map<String, String>, ResponseFormat> getCapName2Type(Resource parentResource) {
576 Map<String, String> capName2type = new HashMap<>();
577 if (parentResource != null) {
578 Map<String, List<CapabilityDefinition>> capabilities = parentResource.getCapabilities();
579 if (capabilities != null) {
580 for (List<CapabilityDefinition> capDefinitions : capabilities.values()) {
581 for (CapabilityDefinition capDefinition : capDefinitions) {
582 String nameLowerCase = capDefinition.getName().toLowerCase();
583 if (capName2type.get(nameLowerCase) != null) {
584 String parentResourceName = parentResource.getName();
585 log.debug("Resource with name {} has more than one capability with name {}, ignoring case", parentResourceName, nameLowerCase);
586 BeEcompErrorManager.getInstance().logInternalDataError("Import resource", "Parent resource " + parentResourceName + " of imported resource has one or more capabilities with name " + nameLowerCase, ErrorSeverity.ERROR);
587 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
589 capName2type.put(nameLowerCase, capDefinition.getType());
594 return Either.left(capName2type);
597 private Either<Map<String, String>, ResponseFormat> getReqName2Type(Resource parentResource) {
598 Map<String, String> reqName2type = new HashMap<>();
599 if (parentResource != null) {
600 Map<String, List<RequirementDefinition>> requirements = parentResource.getRequirements();
601 if (requirements != null) {
602 for (List<RequirementDefinition> reqDefinitions : requirements.values()) {
603 for (RequirementDefinition reqDefinition : reqDefinitions) {
604 String nameLowerCase = reqDefinition.getName().toLowerCase();
605 if (reqName2type.get(nameLowerCase) != null) {
606 String parentResourceName = parentResource.getName();
607 log.debug("Resource with name {} has more than one requirement with name {}, ignoring case", parentResourceName, nameLowerCase);
608 BeEcompErrorManager.getInstance().logInternalDataError("Import resource", "Parent resource " + parentResourceName + " of imported resource has one or more requirements with name " + nameLowerCase, ErrorSeverity.ERROR);
609 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
611 reqName2type.put(nameLowerCase, reqDefinition.getCapability());
616 return Either.left(reqName2type);
619 private Either<Boolean, ResponseFormat> validateCapNameVsDerived(Map<String, String> parentCapName2Type, String childCapabilityType, String reqCapName) {
620 String capNameLowerCase = reqCapName.toLowerCase();
621 log.trace("Validating capability {} vs parent resource", capNameLowerCase);
622 String parentCapType = parentCapName2Type.get(capNameLowerCase);
623 if (parentCapType != null) {
624 if (childCapabilityType.equals(parentCapType)) {
625 log.debug("Capability with name {} is of same type {} for imported resource and its parent - this is OK", capNameLowerCase, childCapabilityType);
626 return Either.left(true);
628 Either<Boolean, StorageOperationStatus> capabilityTypeDerivedFrom = capabilityTypeOperation.isCapabilityTypeDerivedFrom(childCapabilityType, parentCapType);
629 if (capabilityTypeDerivedFrom.isRight()) {
630 log.debug("Couldn't check whether imported resource capability derives from its parent's capability");
631 ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(capabilityTypeDerivedFrom.right().value()));
632 return Either.right(responseFormat);
634 return Either.left(capabilityTypeDerivedFrom.left().value());
636 return Either.left(true);
639 private Either<CapabilityDefinition, ResponseFormat> createCapabilityFromImportFile(Object capabilityJson) {
641 CapabilityDefinition capabilityDefinition = new CapabilityDefinition();
642 Either<CapabilityDefinition, ResponseFormat> result = Either.left(capabilityDefinition);
645 if (capabilityJson instanceof String) {
646 String capabilityJsonString = (String) capabilityJson;
647 capabilityDefinition.setType(capabilityJsonString);
648 } else if (capabilityJson instanceof Map) {
649 Map<String, Object> capabilityJsonMap = (Map<String, Object>) capabilityJson;
651 if (capabilityJsonMap.containsKey(ToscaTagNamesEnum.TYPE.getElementName())) {
652 capabilityDefinition.setType((String) capabilityJsonMap.get(ToscaTagNamesEnum.TYPE.getElementName()));
655 if (capabilityJsonMap.containsKey(ToscaTagNamesEnum.VALID_SOURCE_TYPES.getElementName())) {
656 capabilityDefinition.setValidSourceTypes((List<String>) capabilityJsonMap.get(ToscaTagNamesEnum.VALID_SOURCE_TYPES.getElementName()));
659 if (capabilityJsonMap.containsKey(ToscaTagNamesEnum.DESCRIPTION.getElementName())) {
660 capabilityDefinition.setDescription((String) capabilityJsonMap.get(ToscaTagNamesEnum.DESCRIPTION.getElementName()));
662 if (capabilityJsonMap.containsKey(ToscaTagNamesEnum.OCCURRENCES.getElementName())) {
663 List<Object> occurrencesList = (List) capabilityJsonMap.get(ToscaTagNamesEnum.OCCURRENCES.getElementName());
664 Either<Boolean, ResponseFormat> validateAndSetOccurrencesStatus = validateOccurrences(occurrencesList);
665 if (validateAndSetOccurrencesStatus.isRight()) {
666 result = Either.right(validateAndSetOccurrencesStatus.right().value());
669 if (validateAndSetOccurrencesStatus.left().value() == true) {
670 capabilityDefinition.setMinOccurrences(occurrencesList.get(0).toString());
671 capabilityDefinition.setMaxOccurrences(occurrencesList.get(1).toString());
674 if (capabilityJsonMap.containsKey(ToscaTagNamesEnum.PROPERTIES.getElementName())) {
676 Either<Map<String, PropertyDefinition>, ResultStatusEnum> propertiesRes = ImportUtils.getProperties(capabilityJsonMap);
677 if (propertiesRes.isRight()) {
678 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.PROPERTY_NOT_FOUND));
681 propertiesRes.left().value().entrySet().stream().forEach(e -> e.getValue().setName(e.getKey().toLowerCase()));
682 List<ComponentInstanceProperty> capabilityProperties = propertiesRes.left().value().values().stream().map(p -> new ComponentInstanceProperty(p, p.getDefaultValue(), null)).collect(Collectors.toList());
683 capabilityDefinition.setProperties(capabilityProperties);
688 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_YAML));
691 } catch (Exception e) {
692 BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "Import Resource - create capability");
693 BeEcompErrorManager.getInstance().logBeSystemError("Import Resource - create capability");
694 log.debug("error when creating capability, message:{}", e.getMessage(), e);
695 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_YAML));
701 private ResponseFormat handleImportResourceExecption(UploadResourceInfo resourceMetaData, User user, boolean isNormative, RuntimeException e) {
702 String payloadName = (resourceMetaData != null) ? resourceMetaData.getPayloadName() : "";
703 BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "Import Resource " + payloadName);
704 BeEcompErrorManager.getInstance().logBeSystemError("Import Resource " + payloadName);
706 log.debug("Error when importing resource from payload:{} Exception text: {}", payloadName, e.getMessage(), e);
707 ResponseFormat errorResponseWrapper = getResponseFormatManager().getResponseFormat(ActionStatus.GENERAL_ERROR);
708 auditErrorImport(resourceMetaData, user, errorResponseWrapper, isNormative);
709 return errorResponseWrapper;
712 private void auditErrorImport(UploadResourceInfo resourceMetaData, User user, ResponseFormat errorResponseWrapper, boolean isNormative) {
713 EnumMap<AuditingFieldsKeysEnum, Object> auditingFields = new EnumMap<>(AuditingFieldsKeysEnum.class);
714 auditingFields.put(AuditingFieldsKeysEnum.AUDIT_ACTION, AuditingActionEnum.IMPORT_RESOURCE.getName());
715 auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceMetaData.getName());
716 auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_TYPE, ComponentTypeEnum.RESOURCE.getValue());
717 auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_PREV_VERSION, "");
718 auditingFields.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_UID, user.getUserId());
719 auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_PREV_STATE, "");
720 auditingFields.put(AuditingFieldsKeysEnum.AUDIT_INVARIANT_UUID, "");
721 auditingFields.put(AuditingFieldsKeysEnum.AUDIT_STATUS, errorResponseWrapper.getStatus());
723 if (errorResponseWrapper.getMessageId() != null) {
724 message = errorResponseWrapper.getMessageId() + ": ";
726 message += errorResponseWrapper.getFormattedMessage();
727 auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DESC, message);
728 auditingFields.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_NAME, user.getFirstName() + " " + user.getLastName());
730 String version, lifeCycleState;
732 version = Constants.FIRST_CERTIFIED_VERSION_VERSION;
733 lifeCycleState = LifecycleStateEnum.CERTIFIED.name();
736 lifeCycleState = LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.name();
739 auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_VERSION, version);
740 auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_STATE, lifeCycleState);
741 auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_TOSCA_NODE_TYPE, "");
743 getAuditingManager().auditEvent(auditingFields);
746 private void setMetaDataFromJson(UploadResourceInfo resourceMetaData, Resource resource) {
747 resource.setTags(resourceMetaData.getTags());
748 List<CategoryDefinition> categories = resourceMetaData.getCategories();
749 resource.setCategories(categories);
750 resource.setDescription(resourceMetaData.getDescription());
751 resource.setIcon(resourceMetaData.getResourceIconPath());
752 resource.setName(resourceMetaData.getName());
753 if (categories != null && !categories.isEmpty()) {
754 CategoryDefinition categoryDef = categories.get(0);
755 resource.setAbstract(false);
756 if (categoryDef != null && categoryDef.getName() != null && categoryDef.getName().equals(Constants.ABSTRACT_CATEGORY_NAME)) {
757 SubCategoryDefinition subCategoryDef = categoryDef.getSubcategories().get(0);
758 if (subCategoryDef != null && subCategoryDef.getName().equals(Constants.ABSTRACT_SUBCATEGORY)) {
759 resource.setAbstract(true);
763 resource.setContactId(resourceMetaData.getContactId());
764 resource.setCreatorUserId(resourceMetaData.getContactId());
766 if (resourceMetaData.getVendorName() != null) {
767 resource.setVendorName(resourceMetaData.getVendorName());
770 if (resourceMetaData.getVendorRelease() != null) {
771 resource.setVendorRelease(resourceMetaData.getVendorRelease());
774 resource.setResourceType(ResourceTypeEnum.valueOf(resourceMetaData.getResourceType()));
778 private void setConstantMetaData(Resource resource) {
779 resource.setVersion(ImportUtils.Constants.FIRST_CERTIFIED_VERSION_VERSION);
781 resource.setLifecycleState(ImportUtils.Constants.NORMATIVE_TYPE_LIFE_CYCLE);
782 resource.setHighestVersion(ImportUtils.Constants.NORMATIVE_TYPE_HIGHEST_VERSION);
783 resource.setVendorName(ImportUtils.Constants.VENDOR_NAME);
784 resource.setVendorRelease(ImportUtils.Constants.VENDOR_RELEASE);
788 private Either<Boolean, ResponseFormat> validateOccurrences(List<Object> occurrensesList) {
790 if (!ValidationUtils.validateListNotEmpty(occurrensesList)) {
791 log.debug("Occurrenses list empty");
792 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_OCCURRENCES);
793 return Either.right(responseFormat);
796 if (occurrensesList.size() < 2) {
797 log.debug("Occurrenses list size not 2");
798 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_OCCURRENCES);
799 return Either.right(responseFormat);
801 Object minObj = occurrensesList.get(0);
802 Object maxObj = occurrensesList.get(1);
803 Integer minOccurrences = null;
804 Integer maxOccurrences = null;
805 if (minObj instanceof Integer)
806 minOccurrences = (Integer) minObj;
808 log.debug("Invalid occurrenses format. low_bound occurrense must be Integer {}", minObj);
809 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_OCCURRENCES);
810 return Either.right(responseFormat);
812 if (minOccurrences < 0) {
813 log.debug("Invalid occurrenses format.low_bound occurrense negative {}", minOccurrences);
814 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_OCCURRENCES);
815 return Either.right(responseFormat);
818 if (maxObj instanceof String) {
819 if (maxObj.equals("UNBOUNDED")) {
820 return Either.left(true);
822 log.debug("Invalid occurrenses format. Max occurrence is {}", maxObj);
823 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_OCCURRENCES);
824 return Either.right(responseFormat);
827 if (maxObj instanceof Integer)
828 maxOccurrences = (Integer) maxObj;
830 log.debug("Invalid occurrenses format. Max occurrence is {}", maxObj);
831 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_OCCURRENCES);
832 return Either.right(responseFormat);
835 if (maxOccurrences <= 0 || maxOccurrences < minOccurrences) {
836 log.debug("Invalid occurrenses format. min occurrence is {}. Max occurrence is {}", minOccurrences, maxOccurrences);
837 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_OCCURRENCES);
838 return Either.right(responseFormat);
842 return Either.left(true);
846 public void init(ServletContext servletContext) {
847 if (this.servletContext == null) {
848 synchronized (this) {
849 if (this.servletContext == null) {
850 this.servletContext = servletContext;
851 responseFormatManager = ResponseFormatManager.getInstance();
852 resourceBusinessLogic = getResourceBL(servletContext);
858 public boolean isResourceExist(String resourceName) {
859 return resourceBusinessLogic.isResourceExist(resourceName);
862 private ResourceBusinessLogic getResourceBL(ServletContext context) {
863 WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(org.openecomp.sdc.common.api.Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR);
864 WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context);
865 ResourceBusinessLogic resourceBl = webApplicationContext.getBean(ResourceBusinessLogic.class);
869 public ServletContext getServletContext() {
870 return servletContext;
873 public IAuditingManager getAuditingManager() {
874 return auditingManager;
877 public ResponseFormatManager getResponseFormatManager() {
878 return responseFormatManager;
881 public void setResponseFormatManager(ResponseFormatManager responseFormatManager) {
882 this.responseFormatManager = responseFormatManager;
885 public ResourceBusinessLogic getResourceBusinessLogic() {
886 return resourceBusinessLogic;
889 public void setResourceBusinessLogic(ResourceBusinessLogic resourceBusinessLogic) {
890 this.resourceBusinessLogic = resourceBusinessLogic;
893 public Logger getLog() {
897 public static void setLog(Logger log) {
898 ResourceImportManager.log = log;
901 public IGraphLockOperation getGraphLockOperation() {
902 return graphLockOperation;
905 public void setGraphLockOperation(IGraphLockOperation graphLockOperation) {
906 this.graphLockOperation = graphLockOperation;
909 public void setServletContext(ServletContext servletContext) {
910 this.servletContext = servletContext;
913 public void setAuditingManager(IAuditingManager auditingManager) {
914 this.auditingManager = auditingManager;
917 public void setResourceOperation(ResourceOperation resourceOperation) {
918 this.resourceOperation = resourceOperation;