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.ArtifactsBusinessLogic.ArtifactOperationEnum;
41 import org.openecomp.sdc.be.components.impl.ImportUtils.Constants;
42 import org.openecomp.sdc.be.components.impl.ImportUtils.ResultStatusEnum;
43 import org.openecomp.sdc.be.components.impl.ImportUtils.ToscaTagNamesEnum;
44 import org.openecomp.sdc.be.components.lifecycle.LifecycleChangeInfoWithAction;
45 import org.openecomp.sdc.be.config.BeEcompErrorManager;
46 import org.openecomp.sdc.be.config.BeEcompErrorManager.ErrorSeverity;
47 import org.openecomp.sdc.be.dao.api.ActionStatus;
48 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
49 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
50 import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
51 import org.openecomp.sdc.be.impl.ComponentsUtils;
52 import org.openecomp.sdc.be.impl.WebAppContextWrapper;
53 import org.openecomp.sdc.be.model.ArtifactDefinition;
54 import org.openecomp.sdc.be.model.AttributeDefinition;
55 import org.openecomp.sdc.be.model.CapabilityDefinition;
56 import org.openecomp.sdc.be.model.ComponentInstanceProperty;
57 import org.openecomp.sdc.be.model.InterfaceDefinition;
58 import org.openecomp.sdc.be.model.LifecycleStateEnum;
59 import org.openecomp.sdc.be.model.PropertyDefinition;
60 import org.openecomp.sdc.be.model.RequirementDefinition;
61 import org.openecomp.sdc.be.model.Resource;
62 import org.openecomp.sdc.be.model.UploadResourceInfo;
63 import org.openecomp.sdc.be.model.User;
64 import org.openecomp.sdc.be.model.category.CategoryDefinition;
65 import org.openecomp.sdc.be.model.category.SubCategoryDefinition;
66 import org.openecomp.sdc.be.model.jsontitan.operations.ToscaOperationFacade;
67 import org.openecomp.sdc.be.model.operations.api.IGraphLockOperation;
68 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
69 import org.openecomp.sdc.be.model.operations.impl.CapabilityTypeOperation;
70 import org.openecomp.sdc.be.model.operations.impl.ResourceOperation;
71 import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
72 import org.openecomp.sdc.common.config.EcompErrorName;
73 import org.openecomp.sdc.common.datastructure.AuditingFieldsKeysEnum;
74 import org.openecomp.sdc.common.util.ValidationUtils;
75 import org.openecomp.sdc.exception.ResponseFormat;
76 import org.slf4j.Logger;
77 import org.slf4j.LoggerFactory;
78 import org.springframework.beans.factory.annotation.Autowired;
79 import org.springframework.stereotype.Component;
80 import org.springframework.web.context.WebApplicationContext;
81 import org.yaml.snakeyaml.Yaml;
83 import fj.data.Either;
85 @Component("resourceImportManager")
86 public class ResourceImportManager {
88 private ServletContext servletContext;
91 private IAuditingManager auditingManager;
94 private ResourceBusinessLogic resourceBusinessLogic;
97 private IGraphLockOperation graphLockOperation;
100 protected ComponentsUtils componentsUtils;
103 protected ResourceOperation resourceOperation;
106 protected CapabilityTypeOperation capabilityTypeOperation;
108 protected ToscaOperationFacade toscaOperationFacade;
110 private ResponseFormatManager responseFormatManager;
112 private static Logger log = LoggerFactory.getLogger(ResourceImportManager.class.getName());
114 public void setToscaOperationFacade(ToscaOperationFacade toscaOperationFacade) {
115 this.toscaOperationFacade = toscaOperationFacade;
118 public Either<ImmutablePair<Resource, ActionStatus>, ResponseFormat> importNormativeResource(String resourceYml, UploadResourceInfo resourceMetaData, User creator, boolean createNewVersion, boolean needLock) {
120 LifecycleChangeInfoWithAction lifecycleChangeInfo = new LifecycleChangeInfoWithAction();
121 lifecycleChangeInfo.setUserRemarks("certification on import");
122 Function<Resource, Either<Boolean, ResponseFormat>> validator = (resource) -> resourceBusinessLogic.validatePropertiesDefaultValues(resource);
124 return importCertifiedResource(resourceYml, resourceMetaData, creator, validator, lifecycleChangeInfo, false, createNewVersion, needLock, null, null);
127 public Either<ImmutablePair<Resource, ActionStatus>, ResponseFormat> importNormativeResourceFromCsar(String resourceYml, UploadResourceInfo resourceMetaData, User creator, boolean createNewVersion, boolean needLock) {
129 LifecycleChangeInfoWithAction lifecycleChangeInfo = new LifecycleChangeInfoWithAction();
130 lifecycleChangeInfo.setUserRemarks("certification on import");
131 Function<Resource, Either<Boolean, ResponseFormat>> validator = (resource) -> resourceBusinessLogic.validatePropertiesDefaultValues(resource);
133 return importCertifiedResource(resourceYml, resourceMetaData, creator, validator, lifecycleChangeInfo, false, createNewVersion, needLock, null, null);
136 public Either<ImmutablePair<Resource, ActionStatus>, ResponseFormat> importCertifiedResource(String resourceYml, UploadResourceInfo resourceMetaData, User creator, Function<Resource, Either<Boolean, ResponseFormat>> validationFunction,
137 LifecycleChangeInfoWithAction lifecycleChangeInfo, boolean isInTransaction, boolean createNewVersion, boolean needLock, Map<ArtifactOperationEnum, List<ArtifactDefinition>> nodeTypeArtifactsToHandle, List<ArtifactDefinition> nodeTypesNewCreatedArtifacts) {
138 Resource resource = new Resource();
139 ImmutablePair<Resource, ActionStatus> responsePair = new ImmutablePair<>(resource, ActionStatus.CREATED);
140 Either<ImmutablePair<Resource, ActionStatus>, ResponseFormat> response = Either.left(responsePair);
142 String latestCertifiedResourceId = null;
144 boolean shouldBeCertified = nodeTypeArtifactsToHandle == null || nodeTypeArtifactsToHandle.isEmpty() ? true : false;
145 setConstantMetaData(resource, shouldBeCertified);
146 setMetaDataFromJson(resourceMetaData, resource);
148 Either<Boolean, ResponseFormat> validateResourceFromYaml = populateResourceFromYaml(resourceYml, resource, isInTransaction);
149 if (validateResourceFromYaml.isRight()) {
150 ResponseFormat validationErrorResponse = validateResourceFromYaml.right().value();
151 auditErrorImport(resourceMetaData, creator, validationErrorResponse, true);
152 return Either.right(validationErrorResponse);
156 Either<Boolean, ResponseFormat> isValidResource = validationFunction.apply(resource);
157 if (isValidResource.isLeft()) {
158 // The flag createNewVersion if false doesn't create new version
159 if (!createNewVersion) {
160 Either<Resource, StorageOperationStatus> latestByName = toscaOperationFacade.getLatestByName(resource.getName());
161 if (latestByName.isLeft()) {
162 return Either.right(componentsUtils.getResponseFormatByResource(ActionStatus.COMPONENT_NAME_ALREADY_EXIST, resource));
166 response = resourceBusinessLogic.createOrUpdateResourceByImport(resource, creator, true, isInTransaction, needLock);
167 Either<Resource, ResponseFormat> changeStateResponse;
168 if (response.isLeft()) {
169 resource = response.left().value().left;
171 if(nodeTypeArtifactsToHandle !=null && !nodeTypeArtifactsToHandle.isEmpty()){
172 Either<List<ArtifactDefinition>, ResponseFormat> handleNodeTypeArtifactsRes =
173 resourceBusinessLogic.handleNodeTypeArtifacts(resource, nodeTypeArtifactsToHandle, nodeTypesNewCreatedArtifacts, creator, isInTransaction);
174 if(handleNodeTypeArtifactsRes.isRight()){
175 return Either.right(handleNodeTypeArtifactsRes.right().value());
178 latestCertifiedResourceId = getLatestCertifiedResourceId(resource);
179 changeStateResponse = resourceBusinessLogic.propagateStateToCertified(creator, resource, lifecycleChangeInfo, isInTransaction, needLock);
180 if (changeStateResponse.isRight()) {
181 response = Either.right(changeStateResponse.right().value());
183 responsePair = new ImmutablePair<>(changeStateResponse.left().value(), response.left().value().right);
184 response = Either.left(responsePair);
188 ResponseFormat validationErrorResponse = isValidResource.right().value();
189 auditErrorImport(resourceMetaData, creator, validationErrorResponse, true);
190 response = Either.right(validationErrorResponse);
193 } catch (RuntimeException e) {
194 ResponseFormat exceptionResponse = handleImportResourceExecption(resourceMetaData, creator, true, e);
195 response = Either.right(exceptionResponse);
197 if (latestCertifiedResourceId != null && needLock) {
198 log.debug("unlock resource {}", latestCertifiedResourceId);
199 graphLockOperation.unlockComponent(latestCertifiedResourceId, NodeTypeEnum.Resource);
206 private String getLatestCertifiedResourceId(Resource resource) {
207 Map<String, String> allVersions = resource.getAllVersions();
208 Double latestCertifiedVersion = 0.0;
209 if (allVersions != null) {
210 for (String version : allVersions.keySet()) {
211 Double dVersion = Double.valueOf(version);
212 if ((dVersion > latestCertifiedVersion) && (version.endsWith(".0"))) {
213 latestCertifiedVersion = dVersion;
216 return allVersions.get(String.valueOf(latestCertifiedVersion));
222 public Either<ImmutablePair<Resource, ActionStatus>, ResponseFormat> importUserDefinedResource(String resourceYml, UploadResourceInfo resourceMetaData, User creator, boolean isReusable, boolean isInTransaction) {
224 Resource resource = new Resource();
225 ImmutablePair<Resource, ActionStatus> responsePair = new ImmutablePair<Resource, ActionStatus>(resource, ActionStatus.CREATED);
226 Either<ImmutablePair<Resource, ActionStatus>, ResponseFormat> response = Either.left(responsePair);
229 setMetaDataFromJson(resourceMetaData, resource);
231 Either<Boolean, ResponseFormat> validateResourceFromYaml = populateResourceFromYaml(resourceYml, resource, isInTransaction);
232 if (validateResourceFromYaml.isRight()) {
233 ResponseFormat validationErrorResponse = validateResourceFromYaml.right().value();
234 auditErrorImport(resourceMetaData, creator, validationErrorResponse, false);
235 return Either.right(validationErrorResponse);
239 // currently import VF isn't supported. In future will be supported
240 // import VF only with CSER file!!
241 if (ResourceTypeEnum.VF.equals(resource.getResourceType())) {
242 log.debug("Now import VF isn't supported. It will be supported in future with CSER file only");
243 return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
246 Either<Boolean, ResponseFormat> validateDerivedFromNotEmpty = resourceBusinessLogic.validateDerivedFromNotEmpty(creator, resource, AuditingActionEnum.CREATE_RESOURCE);
247 if (validateDerivedFromNotEmpty.isRight()) {
248 return Either.right(validateDerivedFromNotEmpty.right().value());
251 Either<Boolean, ResponseFormat> validatePropertiesTypes = resourceBusinessLogic.validatePropertiesDefaultValues(resource);
253 if (validatePropertiesTypes.isLeft()) {
254 response = resourceBusinessLogic.createOrUpdateResourceByImport(resource, creator, false, isInTransaction, true);
256 ResponseFormat validationErrorResponse = validatePropertiesTypes.right().value();
257 auditErrorImport(resourceMetaData, creator, validationErrorResponse, false);
258 response = Either.right(validationErrorResponse);
261 } catch (RuntimeException e) {
262 ResponseFormat exceptionResponse = handleImportResourceExecption(resourceMetaData, creator, false, e);
263 response = Either.right(exceptionResponse);
270 private Either<Boolean, ResponseFormat> populateResourceFromYaml(String resourceYml, Resource resource, boolean inTransaction) {
271 @SuppressWarnings("unchecked")
272 Either<Boolean, ResponseFormat> eitherResult = Either.left(true);
273 Map<String, Object> toscaJsonAll = (Map<String, Object>) new Yaml().load(resourceYml);
274 Map<String, Object> toscaJson = toscaJsonAll;
276 // Checks if exist and builds the node_types map
277 if (toscaJsonAll.containsKey(ToscaTagNamesEnum.NODE_TYPES.getElementName())) {
278 toscaJson = new HashMap<String, Object>();
279 toscaJson.put(ToscaTagNamesEnum.NODE_TYPES.getElementName(), toscaJsonAll.get(ToscaTagNamesEnum.NODE_TYPES.getElementName()));
282 Either<Resource, ResponseFormat> setDerivedFrom = setDerivedFrom(toscaJson, resource, inTransaction);
283 if (setDerivedFrom.isRight()) {
284 return Either.right(setDerivedFrom.right().value());
286 Resource parentResource = setDerivedFrom.left().value();
287 setToscaResourceName(toscaJson, resource);
288 setAttributes(toscaJson, resource);
289 eitherResult = setCapabilities(toscaJson, resource, parentResource);
290 if (eitherResult.isRight())
292 setProperties(toscaJson, resource);
293 eitherResult = setRequirements(toscaJson, resource, parentResource);
294 if (eitherResult.isRight())
296 setInterfaceLifecycle(toscaJson, resource);
301 private void setToscaResourceName(Map<String, Object> toscaJson, Resource resource) {
302 Either<Map<String, Object>, ResultStatusEnum> toscaElement = ImportUtils.findFirstToscaMapElement(toscaJson, ToscaTagNamesEnum.NODE_TYPES);
303 if (toscaElement.isLeft() || toscaElement.left().value().size() == 1) {
304 String toscaResourceName = toscaElement.left().value().keySet().iterator().next();
305 resource.setToscaResourceName(toscaResourceName);
309 private void setInterfaceLifecycle(Map<String, Object> toscaJson, Resource resource) {
310 Either<Map<String, Object>, ResultStatusEnum> toscaInterfaces = ImportUtils.findFirstToscaMapElement(toscaJson, ToscaTagNamesEnum.INTERFACES);
311 if (toscaInterfaces.isLeft()) {
312 Map<String, Object> jsonInterfaces = toscaInterfaces.left().value();
313 Map<String, InterfaceDefinition> moduleInterfaces = new HashMap<String, InterfaceDefinition>();
314 Iterator<Entry<String, Object>> interfacesNameValue = jsonInterfaces.entrySet().iterator();
315 while (interfacesNameValue.hasNext()) {
316 Entry<String, Object> interfaceNameValue = interfacesNameValue.next();
317 Either<InterfaceDefinition, ResultStatusEnum> eitherInterface = createModuleInterface(interfaceNameValue.getValue());
318 if (eitherInterface.isRight()) {
319 log.info("error when creating interface:{}, for resource:{}", interfaceNameValue.getKey(), resource.getName());
321 moduleInterfaces.put(interfaceNameValue.getKey(), eitherInterface.left().value());
325 if (moduleInterfaces.size() > 0) {
326 resource.setInterfaces(moduleInterfaces);
331 private Either<InterfaceDefinition, ResultStatusEnum> createModuleInterface(Object interfaceJson) {
332 InterfaceDefinition interf = new InterfaceDefinition();
333 Either<InterfaceDefinition, ResultStatusEnum> result = Either.left(interf);
336 if (interfaceJson instanceof String) {
337 String requirementJsonString = (String) interfaceJson;
338 interf.setType(requirementJsonString);
339 } else if (interfaceJson instanceof Map) {
340 Map<String, Object> requirementJsonMap = (Map<String, Object>) interfaceJson;
341 if (requirementJsonMap.containsKey(ToscaTagNamesEnum.TYPE.getElementName())) {
342 String type = (String) requirementJsonMap.get(ToscaTagNamesEnum.TYPE.getElementName());
343 interf.setType(type);
344 interf.setUniqueId(type.toLowerCase());
347 result = Either.right(ResultStatusEnum.GENERAL_ERROR);
350 } catch (Exception e) {
351 BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "Import Resource- create interface");
352 BeEcompErrorManager.getInstance().logBeSystemError("Import Resource- create interface");
353 log.debug("error when creating interface, message:{}", e.getMessage(), e);
354 result = Either.right(ResultStatusEnum.GENERAL_ERROR);
360 private Either<Boolean, ResponseFormat> setRequirements(Map<String, Object> toscaJson, Resource resource, Resource parentResource) {// Note that parentResource can be null
361 Either<Boolean, ResponseFormat> eitherResult = Either.left(true);
362 Either<List<Object>, ResultStatusEnum> toscaRequirements = ImportUtils.findFirstToscaListElement(toscaJson, ToscaTagNamesEnum.REQUIREMENTS);
363 if (toscaRequirements.isLeft()) {
364 List<Object> jsonRequirements = toscaRequirements.left().value();
365 Map<String, List<RequirementDefinition>> moduleRequirements = new HashMap<String, List<RequirementDefinition>>();
366 // Checking for name duplication
367 Set<String> reqNames = new HashSet<>();
368 // Getting flattened list of capabilities of parent node - cap name
370 Either<Map<String, String>, ResponseFormat> reqName2Type = getReqName2Type(parentResource);
371 if (reqName2Type.isRight()) {
372 ResponseFormat responseFormat = reqName2Type.right().value();
373 log.debug("Error during setting requirements of imported resource: {}", responseFormat);
374 return Either.right(responseFormat);
376 Map<String, String> reqName2TypeMap = reqName2Type.left().value();
377 for (Object jsonRequirementObj : jsonRequirements) {
379 Map<String, Object> requirementJsonWrapper = (Map<String, Object>) jsonRequirementObj;
380 String requirementName = requirementJsonWrapper.keySet().iterator().next();
381 String reqNameLowerCase = requirementName.toLowerCase();
382 if (reqNames.contains(reqNameLowerCase)) {
383 log.debug("More than one requirement with same name {} (case-insensitive) in imported TOSCA file is invalid", reqNameLowerCase);
384 return Either.right(componentsUtils.getResponseFormat(ActionStatus.IMPORT_DUPLICATE_REQ_CAP_NAME, "requirement", reqNameLowerCase));
386 reqNames.add(reqNameLowerCase);
387 Either<RequirementDefinition, ResponseFormat> eitherRequirement = createRequirementFromImportFile(requirementJsonWrapper.get(requirementName));
388 if (eitherRequirement.isRight()) {
389 log.info("error when creating Requirement:{}, for resource:{}", requirementName, resource.getName());
390 return Either.right(eitherRequirement.right().value());
392 RequirementDefinition requirementDef = eitherRequirement.left().value();
393 requirementDef.setName(requirementName);
394 if (moduleRequirements.containsKey(requirementDef.getCapability())) {
395 moduleRequirements.get(requirementDef.getCapability()).add(requirementDef);
397 List<RequirementDefinition> list = new ArrayList<RequirementDefinition>();
398 list.add(requirementDef);
399 moduleRequirements.put(requirementDef.getCapability(), list);
402 // Validating against req/cap of "derived from" node
403 Either<Boolean, ResponseFormat> validateVsParentCap = validateCapNameVsDerived(reqName2TypeMap, requirementDef.getCapability(), requirementDef.getName());
404 if (validateVsParentCap.isRight()) {
405 return Either.right(validateVsParentCap.right().value());
407 if (!validateVsParentCap.left().value()) {
408 log.debug("Requirement with name {} already exists in parent {}", requirementDef.getName(), parentResource.getName());
409 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.IMPORT_REQ_CAP_NAME_EXISTS_IN_DERIVED, "requirement", requirementDef.getName().toLowerCase(), parentResource.getName());
410 return Either.right(responseFormat);
413 if (moduleRequirements.size() > 0) {
414 resource.setRequirements(moduleRequirements);
422 private Either<RequirementDefinition, ResponseFormat> createRequirementFromImportFile(Object requirementJson) {
423 RequirementDefinition requirement = new RequirementDefinition();
424 Either<RequirementDefinition, ResponseFormat> result = Either.left(requirement);
427 if (requirementJson instanceof String) {
428 String requirementJsonString = (String) requirementJson;
429 requirement.setCapability(requirementJsonString);
430 } else if (requirementJson instanceof Map) {
431 Map<String, Object> requirementJsonMap = (Map<String, Object>) requirementJson;
432 if (requirementJsonMap.containsKey(ToscaTagNamesEnum.CAPABILITY.getElementName())) {
433 requirement.setCapability((String) requirementJsonMap.get(ToscaTagNamesEnum.CAPABILITY.getElementName()));
436 if (requirementJsonMap.containsKey(ToscaTagNamesEnum.NODE.getElementName())) {
437 requirement.setNode((String) requirementJsonMap.get(ToscaTagNamesEnum.NODE.getElementName()));
440 if (requirementJsonMap.containsKey(ToscaTagNamesEnum.RELATIONSHIP.getElementName())) {
441 requirement.setRelationship((String) requirementJsonMap.get(ToscaTagNamesEnum.RELATIONSHIP.getElementName()));
443 if (requirementJsonMap.containsKey(ToscaTagNamesEnum.OCCURRENCES.getElementName())) {
444 List<Object> occurrencesList = (List) requirementJsonMap.get(ToscaTagNamesEnum.OCCURRENCES.getElementName());
445 Either<Boolean, ResponseFormat> validateAndSetOccurrencesStatus = validateOccurrences(occurrencesList);
446 if (validateAndSetOccurrencesStatus.isRight()) {
447 result = Either.right(validateAndSetOccurrencesStatus.right().value());
450 if (validateAndSetOccurrencesStatus.left().value() == true) {
451 requirement.setMinOccurrences(occurrencesList.get(0).toString());
452 requirement.setMaxOccurrences(occurrencesList.get(1).toString());
457 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_YAML));
460 } catch (Exception e) {
461 BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "Import Resource - create Requirement");
462 BeEcompErrorManager.getInstance().logBeSystemError("Import Resource - create Requirement");
463 log.debug("error when creating requirement, message:{}", e.getMessage(), e);
464 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_YAML));
470 private ResultStatusEnum setProperties(Map<String, Object> toscaJson, Resource resource) {
471 Map<String, Object> reducedToscaJson = new HashMap<>(toscaJson);
472 ImportUtils.removeElementFromJsonMap(reducedToscaJson, "capabilities");
473 ResultStatusEnum result = ResultStatusEnum.OK;
474 Either<Map<String, PropertyDefinition>, ResultStatusEnum> properties = ImportUtils.getProperties(reducedToscaJson);
475 if (properties.isLeft()) {
476 List<PropertyDefinition> propertiesList = new ArrayList<>();
477 Map<String, PropertyDefinition> value = properties.left().value();
479 for (Entry<String, PropertyDefinition> entry : value.entrySet()) {
480 String name = entry.getKey();
481 PropertyDefinition propertyDefinition = entry.getValue();
482 propertyDefinition.setName(name);
483 propertiesList.add(propertyDefinition);
486 resource.setProperties(propertiesList);
488 result = properties.right().value();
493 private ResultStatusEnum setAttributes(Map<String, Object> toscaJson, Resource resource) {
494 ResultStatusEnum result = ResultStatusEnum.OK;
495 Either<Map<String, AttributeDefinition>, ResultStatusEnum> attributes = ImportUtils.getAttributes(toscaJson);
496 if (attributes.isLeft()) {
497 List<AttributeDefinition> attributeList = new ArrayList<>();
498 Map<String, AttributeDefinition> value = attributes.left().value();
500 for (Entry<String, AttributeDefinition> entry : value.entrySet()) {
501 String name = entry.getKey();
502 AttributeDefinition attributeDef = entry.getValue();
503 attributeDef.setName(name);
504 attributeList.add(attributeDef);
507 resource.setAttributes(attributeList);
509 result = attributes.right().value();
514 private Either<Resource, ResponseFormat> setDerivedFrom(Map<String, Object> toscaJson, Resource resource, boolean inTransaction) {
515 Either<String, ResultStatusEnum> toscaDerivedFromElement = ImportUtils.findFirstToscaStringElement(toscaJson, ToscaTagNamesEnum.DERIVED_FROM);
516 Resource derivedFromResource = null;
517 if (toscaDerivedFromElement.isLeft()) {
518 String derivedFrom = toscaDerivedFromElement.left().value();
519 log.debug("Derived from TOSCA name is {}", derivedFrom);
520 resource.setDerivedFrom(Arrays.asList(new String[] { derivedFrom }));
521 Either<Resource, StorageOperationStatus> latestByToscaResourceName = toscaOperationFacade.getLatestByToscaResourceName(derivedFrom);
523 if (latestByToscaResourceName.isRight()) {
524 StorageOperationStatus operationStatus = latestByToscaResourceName.right().value();
525 if (operationStatus.equals(StorageOperationStatus.NOT_FOUND)) {
526 operationStatus = StorageOperationStatus.PARENT_RESOURCE_NOT_FOUND;
528 log.debug("Error when fetching parent resource {}, error: {}", derivedFrom, operationStatus);
529 ActionStatus convertFromStorageResponse = componentsUtils.convertFromStorageResponse(operationStatus);
530 BeEcompErrorManager.getInstance().logBeComponentMissingError("Import TOSCA YAML", "resource", derivedFrom);
531 return Either.right(componentsUtils.getResponseFormat(convertFromStorageResponse, derivedFrom));
533 derivedFromResource = latestByToscaResourceName.left().value();
535 return Either.left(derivedFromResource);
538 private Either<Boolean, ResponseFormat> setCapabilities(Map<String, Object> toscaJson, Resource resource, Resource parentResource) {// Note that parentResource can be null
539 Either<Boolean, ResponseFormat> eitherResult = Either.left(true);
540 Either<Map<String, Object>, ResultStatusEnum> toscaCapabilities = ImportUtils.findFirstToscaMapElement(toscaJson, ToscaTagNamesEnum.CAPABILITIES);
541 if (toscaCapabilities.isLeft()) {
542 Map<String, Object> jsonCapabilities = toscaCapabilities.left().value();
543 Map<String, List<CapabilityDefinition>> moduleCapabilities = new HashMap<String, List<CapabilityDefinition>>();
544 Iterator<Entry<String, Object>> capabilitiesNameValue = jsonCapabilities.entrySet().iterator();
545 Set<String> capNames = new HashSet<>();
546 // Getting flattened list of capabilities of parent node - cap name
548 Either<Map<String, String>, ResponseFormat> capName2Type = getCapName2Type(parentResource);
549 if (capName2Type.isRight()) {
550 ResponseFormat responseFormat = capName2Type.right().value();
551 log.debug("Error during setting capabilities of imported resource: {}", responseFormat);
552 return Either.right(responseFormat);
554 Map<String, String> capName2TypeMap = capName2Type.left().value();
555 while (capabilitiesNameValue.hasNext()) {
556 Entry<String, Object> capabilityNameValue = capabilitiesNameValue.next();
558 // Validating that no req/cap duplicates exist in imported YAML
559 String capNameLowerCase = capabilityNameValue.getKey().toLowerCase();
560 if (capNames.contains(capNameLowerCase)) {
561 log.debug("More than one capability with same name {} (case-insensitive) in imported TOSCA file is invalid", capNameLowerCase);
562 return Either.right(componentsUtils.getResponseFormat(ActionStatus.IMPORT_DUPLICATE_REQ_CAP_NAME, "capability", capNameLowerCase));
564 capNames.add(capNameLowerCase);
566 Either<CapabilityDefinition, ResponseFormat> eitherCapability = createCapabilityFromImportFile(capabilityNameValue.getValue());
567 if (eitherCapability.isRight()) {
568 log.debug("error when creating capability:{}, for resource:{}", capabilityNameValue.getKey(), resource.getName());
569 return Either.right(eitherCapability.right().value());
572 CapabilityDefinition capabilityDef = eitherCapability.left().value();
573 capabilityDef.setName(capabilityNameValue.getKey());
574 if (moduleCapabilities.containsKey(capabilityDef.getType())) {
575 moduleCapabilities.get(capabilityDef.getType()).add(capabilityDef);
577 List<CapabilityDefinition> list = new ArrayList<CapabilityDefinition>();
578 list.add(capabilityDef);
579 moduleCapabilities.put(capabilityDef.getType(), list);
582 // Validating against req/cap of "derived from" node
583 Either<Boolean, ResponseFormat> validateVsParentCap = validateCapNameVsDerived(capName2TypeMap, capabilityDef.getType(), capabilityDef.getName());
584 if (validateVsParentCap.isRight()) {
585 return Either.right(validateVsParentCap.right().value());
587 if (!validateVsParentCap.left().value()) {
588 // Here parentResource is for sure not null, so it's
590 log.debug("Capability with name {} already exists in parent {}", capabilityDef.getName(), parentResource.getName());
591 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.IMPORT_REQ_CAP_NAME_EXISTS_IN_DERIVED, "capability", capabilityDef.getName().toLowerCase(), parentResource.getName());
592 return Either.right(responseFormat);
595 if (moduleCapabilities.size() > 0) {
596 resource.setCapabilities(moduleCapabilities);
604 private Either<Map<String, String>, ResponseFormat> getCapName2Type(Resource parentResource) {
605 Map<String, String> capName2type = new HashMap<>();
606 if (parentResource != null) {
607 Map<String, List<CapabilityDefinition>> capabilities = parentResource.getCapabilities();
608 if (capabilities != null) {
609 for (List<CapabilityDefinition> capDefinitions : capabilities.values()) {
610 for (CapabilityDefinition capDefinition : capDefinitions) {
611 String nameLowerCase = capDefinition.getName().toLowerCase();
612 if (capName2type.get(nameLowerCase) != null) {
613 String parentResourceName = parentResource.getName();
614 log.debug("Resource with name {} has more than one capability with name {}, ignoring case", parentResourceName, nameLowerCase);
615 BeEcompErrorManager.getInstance().logInternalDataError("Import resource", "Parent resource " + parentResourceName + " of imported resource has one or more capabilities with name " + nameLowerCase, ErrorSeverity.ERROR);
616 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
618 capName2type.put(nameLowerCase, capDefinition.getType());
623 return Either.left(capName2type);
626 private Either<Map<String, String>, ResponseFormat> getReqName2Type(Resource parentResource) {
627 Map<String, String> reqName2type = new HashMap<>();
628 if (parentResource != null) {
629 Map<String, List<RequirementDefinition>> requirements = parentResource.getRequirements();
630 if (requirements != null) {
631 for (List<RequirementDefinition> reqDefinitions : requirements.values()) {
632 for (RequirementDefinition reqDefinition : reqDefinitions) {
633 String nameLowerCase = reqDefinition.getName().toLowerCase();
634 if (reqName2type.get(nameLowerCase) != null) {
635 String parentResourceName = parentResource.getName();
636 log.debug("Resource with name {} has more than one requirement with name {}, ignoring case", parentResourceName, nameLowerCase);
637 BeEcompErrorManager.getInstance().logInternalDataError("Import resource", "Parent resource " + parentResourceName + " of imported resource has one or more requirements with name " + nameLowerCase, ErrorSeverity.ERROR);
638 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
640 reqName2type.put(nameLowerCase, reqDefinition.getCapability());
645 return Either.left(reqName2type);
648 private Either<Boolean, ResponseFormat> validateCapNameVsDerived(Map<String, String> parentCapName2Type, String childCapabilityType, String reqCapName) {
649 String capNameLowerCase = reqCapName.toLowerCase();
650 log.trace("Validating capability {} vs parent resource", capNameLowerCase);
651 String parentCapType = parentCapName2Type.get(capNameLowerCase);
652 if (parentCapType != null) {
653 if (childCapabilityType.equals(parentCapType)) {
654 log.debug("Capability with name {} is of same type {} for imported resource and its parent - this is OK", capNameLowerCase, childCapabilityType);
655 return Either.left(true);
657 Either<Boolean, StorageOperationStatus> capabilityTypeDerivedFrom = capabilityTypeOperation.isCapabilityTypeDerivedFrom(childCapabilityType, parentCapType);
658 if (capabilityTypeDerivedFrom.isRight()) {
659 log.debug("Couldn't check whether imported resource capability derives from its parent's capability");
660 ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(capabilityTypeDerivedFrom.right().value()));
661 return Either.right(responseFormat);
663 return Either.left(capabilityTypeDerivedFrom.left().value());
665 return Either.left(true);
668 private Either<CapabilityDefinition, ResponseFormat> createCapabilityFromImportFile(Object capabilityJson) {
670 CapabilityDefinition capabilityDefinition = new CapabilityDefinition();
671 Either<CapabilityDefinition, ResponseFormat> result = Either.left(capabilityDefinition);
674 if (capabilityJson instanceof String) {
675 String capabilityJsonString = (String) capabilityJson;
676 capabilityDefinition.setType(capabilityJsonString);
677 } else if (capabilityJson instanceof Map) {
678 Map<String, Object> capabilityJsonMap = (Map<String, Object>) capabilityJson;
680 if (capabilityJsonMap.containsKey(ToscaTagNamesEnum.TYPE.getElementName())) {
681 capabilityDefinition.setType((String) capabilityJsonMap.get(ToscaTagNamesEnum.TYPE.getElementName()));
684 if (capabilityJsonMap.containsKey(ToscaTagNamesEnum.VALID_SOURCE_TYPES.getElementName())) {
685 capabilityDefinition.setValidSourceTypes((List<String>) capabilityJsonMap.get(ToscaTagNamesEnum.VALID_SOURCE_TYPES.getElementName()));
688 if (capabilityJsonMap.containsKey(ToscaTagNamesEnum.DESCRIPTION.getElementName())) {
689 capabilityDefinition.setDescription((String) capabilityJsonMap.get(ToscaTagNamesEnum.DESCRIPTION.getElementName()));
691 if (capabilityJsonMap.containsKey(ToscaTagNamesEnum.OCCURRENCES.getElementName())) {
692 List<Object> occurrencesList = (List) capabilityJsonMap.get(ToscaTagNamesEnum.OCCURRENCES.getElementName());
693 Either<Boolean, ResponseFormat> validateAndSetOccurrencesStatus = validateOccurrences(occurrencesList);
694 if (validateAndSetOccurrencesStatus.isRight()) {
695 result = Either.right(validateAndSetOccurrencesStatus.right().value());
698 if (validateAndSetOccurrencesStatus.left().value() == true) {
699 capabilityDefinition.setMinOccurrences(occurrencesList.get(0).toString());
700 capabilityDefinition.setMaxOccurrences(occurrencesList.get(1).toString());
703 if (capabilityJsonMap.containsKey(ToscaTagNamesEnum.PROPERTIES.getElementName())) {
705 Either<Map<String, PropertyDefinition>, ResultStatusEnum> propertiesRes = ImportUtils.getProperties(capabilityJsonMap);
706 if (propertiesRes.isRight()) {
707 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.PROPERTY_NOT_FOUND));
710 propertiesRes.left().value().entrySet().stream().forEach(e -> e.getValue().setName(e.getKey().toLowerCase()));
711 List<ComponentInstanceProperty> capabilityProperties = propertiesRes.left().value().values().stream().map(p -> new ComponentInstanceProperty(p, p.getDefaultValue(), null)).collect(Collectors.toList());
712 capabilityDefinition.setProperties(capabilityProperties);
717 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_YAML));
720 } catch (Exception e) {
721 BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "Import Resource - create capability");
722 BeEcompErrorManager.getInstance().logBeSystemError("Import Resource - create capability");
723 log.debug("error when creating capability, message:{}", e.getMessage(), e);
724 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_YAML));
730 private ResponseFormat handleImportResourceExecption(UploadResourceInfo resourceMetaData, User user, boolean isNormative, RuntimeException e) {
731 String payloadName = (resourceMetaData != null) ? resourceMetaData.getPayloadName() : "";
732 BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeSystemError, "Import Resource " + payloadName);
733 BeEcompErrorManager.getInstance().logBeSystemError("Import Resource " + payloadName);
735 log.debug("Error when importing resource from payload:{} Exception text: {}", payloadName, e.getMessage(), e);
736 ResponseFormat errorResponseWrapper = getResponseFormatManager().getResponseFormat(ActionStatus.GENERAL_ERROR);
737 auditErrorImport(resourceMetaData, user, errorResponseWrapper, isNormative);
738 return errorResponseWrapper;
741 private void auditErrorImport(UploadResourceInfo resourceMetaData, User user, ResponseFormat errorResponseWrapper, boolean isNormative) {
742 EnumMap<AuditingFieldsKeysEnum, Object> auditingFields = new EnumMap<>(AuditingFieldsKeysEnum.class);
743 auditingFields.put(AuditingFieldsKeysEnum.AUDIT_ACTION, AuditingActionEnum.IMPORT_RESOURCE.getName());
744 auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceMetaData.getName());
745 auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_TYPE, ComponentTypeEnum.RESOURCE.getValue());
746 auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_PREV_VERSION, "");
747 auditingFields.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_UID, user.getUserId());
748 auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_PREV_STATE, "");
749 auditingFields.put(AuditingFieldsKeysEnum.AUDIT_INVARIANT_UUID, "");
750 auditingFields.put(AuditingFieldsKeysEnum.AUDIT_STATUS, errorResponseWrapper.getStatus());
752 if (errorResponseWrapper.getMessageId() != null) {
753 message = errorResponseWrapper.getMessageId() + ": ";
755 message += errorResponseWrapper.getFormattedMessage();
756 auditingFields.put(AuditingFieldsKeysEnum.AUDIT_DESC, message);
757 auditingFields.put(AuditingFieldsKeysEnum.AUDIT_MODIFIER_NAME, user.getFirstName() + " " + user.getLastName());
759 String version, lifeCycleState;
761 version = Constants.FIRST_CERTIFIED_VERSION_VERSION;
762 lifeCycleState = LifecycleStateEnum.CERTIFIED.name();
765 lifeCycleState = LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.name();
768 auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_VERSION, version);
769 auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_STATE, lifeCycleState);
770 auditingFields.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_TOSCA_NODE_TYPE, "");
772 getAuditingManager().auditEvent(auditingFields);
775 private void setMetaDataFromJson(UploadResourceInfo resourceMetaData, Resource resource) {
776 resource.setTags(resourceMetaData.getTags());
777 List<CategoryDefinition> categories = resourceMetaData.getCategories();
778 resource.setCategories(categories);
779 resource.setDescription(resourceMetaData.getDescription());
780 resource.setIcon(resourceMetaData.getResourceIconPath());
781 resource.setName(resourceMetaData.getName());
782 if (categories != null && !categories.isEmpty()) {
783 CategoryDefinition categoryDef = categories.get(0);
784 resource.setAbstract(false);
785 if (categoryDef != null && categoryDef.getName() != null && categoryDef.getName().equals(Constants.ABSTRACT_CATEGORY_NAME)) {
786 SubCategoryDefinition subCategoryDef = categoryDef.getSubcategories().get(0);
787 if (subCategoryDef != null && subCategoryDef.getName().equals(Constants.ABSTRACT_SUBCATEGORY)) {
788 resource.setAbstract(true);
792 resource.setContactId(resourceMetaData.getContactId());
793 resource.setCreatorUserId(resourceMetaData.getContactId());
795 if (resourceMetaData.getVendorName() != null) {
796 resource.setVendorName(resourceMetaData.getVendorName());
799 if (resourceMetaData.getVendorRelease() != null) {
800 resource.setVendorRelease(resourceMetaData.getVendorRelease());
803 resource.setResourceType(ResourceTypeEnum.valueOf(resourceMetaData.getResourceType()));
807 private void setConstantMetaData(Resource resource, boolean shouldBeCertified) {
809 LifecycleStateEnum state;
810 if(shouldBeCertified){
811 version = ImportUtils.Constants.FIRST_CERTIFIED_VERSION_VERSION;
812 state = ImportUtils.Constants.NORMATIVE_TYPE_LIFE_CYCLE;
814 version = ImportUtils.Constants.FIRST_NON_CERTIFIED_VERSION;
815 state = ImportUtils.Constants.NORMATIVE_TYPE_LIFE_CYCLE_NOT_CERTIFIED_CHECKOUT;
817 resource.setVersion(version);
818 resource.setLifecycleState(state);
819 resource.setHighestVersion(ImportUtils.Constants.NORMATIVE_TYPE_HIGHEST_VERSION);
820 resource.setVendorName(ImportUtils.Constants.VENDOR_NAME);
821 resource.setVendorRelease(ImportUtils.Constants.VENDOR_RELEASE);
825 private Either<Boolean, ResponseFormat> validateOccurrences(List<Object> occurrensesList) {
827 if (!ValidationUtils.validateListNotEmpty(occurrensesList)) {
828 log.debug("Occurrenses list empty");
829 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_OCCURRENCES);
830 return Either.right(responseFormat);
833 if (occurrensesList.size() < 2) {
834 log.debug("Occurrenses list size not 2");
835 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_OCCURRENCES);
836 return Either.right(responseFormat);
838 Object minObj = occurrensesList.get(0);
839 Object maxObj = occurrensesList.get(1);
840 Integer minOccurrences = null;
841 Integer maxOccurrences = null;
842 if (minObj instanceof Integer)
843 minOccurrences = (Integer) minObj;
845 log.debug("Invalid occurrenses format. low_bound occurrense must be Integer {}", minObj);
846 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_OCCURRENCES);
847 return Either.right(responseFormat);
849 if (minOccurrences < 0) {
850 log.debug("Invalid occurrenses format.low_bound occurrense negative {}", minOccurrences);
851 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_OCCURRENCES);
852 return Either.right(responseFormat);
855 if (maxObj instanceof String) {
856 if (maxObj.equals("UNBOUNDED")) {
857 return Either.left(true);
859 log.debug("Invalid occurrenses format. Max occurrence is {}", maxObj);
860 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_OCCURRENCES);
861 return Either.right(responseFormat);
864 if (maxObj instanceof Integer)
865 maxOccurrences = (Integer) maxObj;
867 log.debug("Invalid occurrenses format. Max occurrence is {}", maxObj);
868 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_OCCURRENCES);
869 return Either.right(responseFormat);
872 if (maxOccurrences <= 0 || maxOccurrences < minOccurrences) {
873 log.debug("Invalid occurrenses format. min occurrence is {}, Max occurrence is {}", minOccurrences, maxOccurrences);
874 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_OCCURRENCES);
875 return Either.right(responseFormat);
879 return Either.left(true);
883 public void init(ServletContext servletContext) {
884 if (this.servletContext == null) {
885 synchronized (this) {
886 if (this.servletContext == null) {
887 this.servletContext = servletContext;
888 responseFormatManager = ResponseFormatManager.getInstance();
889 resourceBusinessLogic = getResourceBL(servletContext);
895 public boolean isResourceExist(String resourceName) {
896 return resourceBusinessLogic.isResourceExist(resourceName);
899 private ResourceBusinessLogic getResourceBL(ServletContext context) {
900 WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(org.openecomp.sdc.common.api.Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR);
901 WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context);
902 ResourceBusinessLogic resourceBl = webApplicationContext.getBean(ResourceBusinessLogic.class);
906 public ServletContext getServletContext() {
907 return servletContext;
910 public IAuditingManager getAuditingManager() {
911 return auditingManager;
914 public ResponseFormatManager getResponseFormatManager() {
915 return responseFormatManager;
918 public void setResponseFormatManager(ResponseFormatManager responseFormatManager) {
919 this.responseFormatManager = responseFormatManager;
922 public ResourceBusinessLogic getResourceBusinessLogic() {
923 return resourceBusinessLogic;
926 public void setResourceBusinessLogic(ResourceBusinessLogic resourceBusinessLogic) {
927 this.resourceBusinessLogic = resourceBusinessLogic;
930 public Logger getLog() {
934 public static void setLog(Logger log) {
935 ResourceImportManager.log = log;
938 public IGraphLockOperation getGraphLockOperation() {
939 return graphLockOperation;
942 public void setGraphLockOperation(IGraphLockOperation graphLockOperation) {
943 this.graphLockOperation = graphLockOperation;
946 public void setServletContext(ServletContext servletContext) {
947 this.servletContext = servletContext;
950 public void setAuditingManager(IAuditingManager auditingManager) {
951 this.auditingManager = auditingManager;
954 public void setResourceOperation(ResourceOperation resourceOperation) {
955 this.resourceOperation = resourceOperation;