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.model.operations.impl;
23 import fj.data.Either;
24 import org.apache.commons.collections.MapUtils;
25 import org.apache.commons.lang3.StringUtils;
26 import org.apache.commons.lang3.tuple.ImmutablePair;
27 import org.openecomp.sdc.be.dao.graph.datatype.GraphEdge;
28 import org.openecomp.sdc.be.dao.graph.datatype.GraphRelation;
29 import org.openecomp.sdc.be.dao.neo4j.GraphEdgeLabels;
30 import org.openecomp.sdc.be.dao.titan.TitanGenericDao;
31 import org.openecomp.sdc.be.dao.titan.TitanOperationStatus;
32 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
33 import org.openecomp.sdc.be.model.CapabilityTypeDefinition;
34 import org.openecomp.sdc.be.model.PropertyDefinition;
35 import org.openecomp.sdc.be.model.operations.api.DerivedFromOperation;
36 import org.openecomp.sdc.be.model.operations.api.ICapabilityTypeOperation;
37 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
38 import org.openecomp.sdc.be.model.operations.api.TypeOperations;
39 import org.openecomp.sdc.be.resources.data.CapabilityTypeData;
40 import org.openecomp.sdc.be.resources.data.PropertyData;
41 import org.openecomp.sdc.common.log.wrappers.Logger;
42 import org.springframework.beans.factory.annotation.Autowired;
43 import org.springframework.stereotype.Component;
45 import java.util.List;
47 import java.util.stream.Collectors;
49 @Component("capability-type-operation")
50 public class CapabilityTypeOperation extends AbstractOperation implements ICapabilityTypeOperation {
52 private PropertyOperation propertyOperation;
54 private DerivedFromOperation derivedFromOperation;
56 public CapabilityTypeOperation() {
60 private static final Logger log = Logger.getLogger(CapabilityTypeOperation.class.getName());
65 * @param titanGenericDao
67 public void setTitanGenericDao(TitanGenericDao titanGenericDao) {
68 this.titanGenericDao = titanGenericDao;
72 public Either<CapabilityTypeDefinition, StorageOperationStatus> addCapabilityType(CapabilityTypeDefinition capabilityTypeDefinition, boolean inTransaction) {
74 Either<CapabilityTypeDefinition, StorageOperationStatus> result = null;
77 Either<CapabilityTypeDefinition, StorageOperationStatus> validationRes = validateUpdateProperties(capabilityTypeDefinition);
78 if (validationRes.isRight()) {
79 log.error("#addCapabilityType - One or all properties of capability type {} not valid. status is {}", capabilityTypeDefinition, validationRes.right().value());
83 Either<CapabilityTypeData, StorageOperationStatus> eitherStatus = addCapabilityTypeToGraph(capabilityTypeDefinition);
85 result = eitherStatus.left()
86 .map(CapabilityTypeData::getUniqueId)
88 .bind(uniqueId -> getCapabilityType(uniqueId, inTransaction));
91 log.debug("#addCapabilityType - The returned CapabilityTypeDefinition is {}", result.left().value());
99 if (result == null || result.isRight()) {
100 log.error("#addCapabilityType - Going to execute rollback on graph.");
101 titanGenericDao.rollback();
103 log.debug("#addCapabilityType - Going to execute commit on graph.");
104 titanGenericDao.commit();
111 public Either<Map<String, PropertyDefinition>, TitanOperationStatus> getAllCapabilityTypePropertiesFromAllDerivedFrom(String firstParentType) {
112 return propertyOperation.getAllTypePropertiesFromAllDerivedFrom(firstParentType, NodeTypeEnum.CapabilityType, CapabilityTypeData.class);
115 public Either<CapabilityTypeDefinition, StorageOperationStatus> validateUpdateProperties(CapabilityTypeDefinition capabilityTypeDefinition) {
116 TitanOperationStatus error = null;
117 if (MapUtils.isNotEmpty(capabilityTypeDefinition.getProperties()) && capabilityTypeDefinition.getDerivedFrom() != null) {
118 Either<Map<String, PropertyDefinition>, TitanOperationStatus> allPropertiesRes =
119 getAllCapabilityTypePropertiesFromAllDerivedFrom(capabilityTypeDefinition.getDerivedFrom());
120 if (allPropertiesRes.isRight() && !allPropertiesRes.right().value().equals(TitanOperationStatus.NOT_FOUND)) {
121 error = allPropertiesRes.right().value();
122 log.debug("Couldn't fetch derived from property nodes for capability type {}, error: {}", capabilityTypeDefinition.getType(), error);
124 if (error == null && !allPropertiesRes.left().value().isEmpty()) {
125 Map<String, PropertyDefinition> derivedFromProperties = allPropertiesRes.left().value();
126 capabilityTypeDefinition.getProperties().entrySet().stream().filter(e -> derivedFromProperties.containsKey(e.getKey()) && e.getValue().getType() == null)
127 .forEach(e -> e.getValue().setType(derivedFromProperties.get(e.getKey()).getType()));
129 List<PropertyDefinition> properties = capabilityTypeDefinition.getProperties().values().stream().collect(Collectors.toList());
130 Either<List<PropertyDefinition>, TitanOperationStatus> validatePropertiesRes = propertyOperation.validatePropertiesUniqueness(allPropertiesRes.left().value(),
132 if (validatePropertiesRes.isRight()) {
133 error = validatePropertiesRes.right().value();
138 return Either.left(capabilityTypeDefinition);
140 return Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(error));
146 * convert between graph Node object to Java object
148 * @param capabilityTypeData
151 protected CapabilityTypeDefinition convertCTDataToCTDefinition(CapabilityTypeData capabilityTypeData) {
152 log.debug("The object returned after create capability is {}", capabilityTypeData);
154 return new CapabilityTypeDefinition(capabilityTypeData.getCapabilityTypeDataDefinition());
159 * Add capability type to graph.
161 * 1. Add capability type node
163 * 2. Add edge between the former node to its parent(if exists)
165 * 3. Add property node and associate it to the node created at #1. (per property & if exists)
167 * @param capabilityTypeDefinition
170 private Either<CapabilityTypeData, StorageOperationStatus> addCapabilityTypeToGraph(CapabilityTypeDefinition capabilityTypeDefinition) {
172 log.debug("Got capability type {}", capabilityTypeDefinition);
174 String ctUniqueId = UniqueIdBuilder.buildCapabilityTypeUid(capabilityTypeDefinition.getType());
175 CapabilityTypeData capabilityTypeData = buildCapabilityTypeData(capabilityTypeDefinition, ctUniqueId);
177 log.debug("Before adding capability type to graph. capabilityTypeData = {}", capabilityTypeData);
178 Either<CapabilityTypeData, TitanOperationStatus> createCTResult = titanGenericDao.createNode(capabilityTypeData, CapabilityTypeData.class);
179 log.debug("After adding capability type to graph. status is = {}", createCTResult);
181 if (createCTResult.isRight()) {
182 TitanOperationStatus operationStatus = createCTResult.right().value();
183 log.error("Failed to capability type {} to graph. status is {}", capabilityTypeDefinition.getType(), operationStatus);
184 return Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(operationStatus));
187 CapabilityTypeData resultCTD = createCTResult.left().value();
188 Map<String, PropertyDefinition> propertiesMap = capabilityTypeDefinition.getProperties();
189 Either<Map<String, PropertyData>, TitanOperationStatus> addPropertiesToCapablityType = propertyOperation.addPropertiesToElementType(resultCTD.getUniqueId(), NodeTypeEnum.CapabilityType, propertiesMap);
190 if (addPropertiesToCapablityType.isRight()) {
191 log.error("Failed add properties {} to capability {}", propertiesMap, capabilityTypeDefinition.getType());
192 return Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(addPropertiesToCapablityType.right().value()));
195 return addDerivedFromRelation(capabilityTypeDefinition, ctUniqueId)
197 .map(updatedDerivedFrom -> createCTResult.left().value());
202 private CapabilityTypeData buildCapabilityTypeData(CapabilityTypeDefinition capabilityTypeDefinition, String ctUniqueId) {
204 CapabilityTypeData capabilityTypeData = new CapabilityTypeData(capabilityTypeDefinition);
206 capabilityTypeData.getCapabilityTypeDataDefinition().setUniqueId(ctUniqueId);
207 Long creationDate = capabilityTypeData.getCapabilityTypeDataDefinition().getCreationTime();
208 if (creationDate == null) {
209 creationDate = System.currentTimeMillis();
211 capabilityTypeData.getCapabilityTypeDataDefinition().setCreationTime(creationDate);
212 capabilityTypeData.getCapabilityTypeDataDefinition().setModificationTime(creationDate);
213 return capabilityTypeData;
217 public Either<CapabilityTypeDefinition, StorageOperationStatus> getCapabilityType(String uniqueId, boolean inTransaction) {
219 Either<CapabilityTypeDefinition, StorageOperationStatus> result = null;
222 Either<CapabilityTypeDefinition, TitanOperationStatus> ctResult = this.getCapabilityTypeByUid(uniqueId);
224 if (ctResult.isRight()) {
225 TitanOperationStatus status = ctResult.right().value();
226 if (status != TitanOperationStatus.NOT_FOUND) {
227 log.error("Failed to retrieve information on capability type {}. status is {}", uniqueId, status);
229 result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(ctResult.right().value()));
233 result = Either.left(ctResult.left().value());
237 if (!inTransaction) {
238 log.debug("Going to execute commit on graph.");
239 titanGenericDao.commit();
245 public Either<CapabilityTypeDefinition, TitanOperationStatus> getCapabilityTypeByType(String capabilityType) {
246 // Optimization: In case of Capability Type its unique ID is the same as type
247 return getCapabilityTypeByUid(capabilityType);
251 * Build Capability type object from graph by unique id
256 public Either<CapabilityTypeDefinition, TitanOperationStatus> getCapabilityTypeByUid(String uniqueId) {
258 Either<CapabilityTypeDefinition, TitanOperationStatus> result = null;
260 Either<CapabilityTypeData, TitanOperationStatus> capabilityTypesRes = titanGenericDao.getNode(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.CapabilityType), uniqueId, CapabilityTypeData.class);
262 if (capabilityTypesRes.isRight()) {
263 TitanOperationStatus status = capabilityTypesRes.right().value();
264 log.debug("Capability type {} cannot be found in graph. status is {}", uniqueId, status);
265 return Either.right(status);
268 CapabilityTypeData ctData = capabilityTypesRes.left().value();
269 CapabilityTypeDefinition capabilityTypeDefinition = new CapabilityTypeDefinition(ctData.getCapabilityTypeDataDefinition());
271 TitanOperationStatus propertiesStatus = fillProperties(uniqueId, capabilityTypeDefinition);
272 if (propertiesStatus != TitanOperationStatus.OK) {
273 log.error("Failed to fetch properties of capability type {}", uniqueId);
274 return Either.right(propertiesStatus);
277 Either<ImmutablePair<CapabilityTypeData, GraphEdge>, TitanOperationStatus> parentNode = titanGenericDao.getChild(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.CapabilityType), uniqueId, GraphEdgeLabels.DERIVED_FROM,
278 NodeTypeEnum.CapabilityType, CapabilityTypeData.class);
279 log.debug("After retrieving DERIVED_FROM node of {}. status is {}", uniqueId, parentNode);
280 if (parentNode.isRight()) {
281 TitanOperationStatus titanOperationStatus = parentNode.right().value();
282 if (titanOperationStatus != TitanOperationStatus.NOT_FOUND) {
283 log.error("Failed to find the parent capability of capability type {}. status is {}", uniqueId, titanOperationStatus);
284 result = Either.right(titanOperationStatus);
288 // derived from node was found
289 ImmutablePair<CapabilityTypeData, GraphEdge> immutablePair = parentNode.left().value();
290 CapabilityTypeData parentCT = immutablePair.getKey();
291 capabilityTypeDefinition.setDerivedFrom(parentCT.getCapabilityTypeDataDefinition().getType());
293 result = Either.left(capabilityTypeDefinition);
298 private TitanOperationStatus fillProperties(String uniqueId, CapabilityTypeDefinition capabilityTypeDefinition) {
300 Either<Map<String, PropertyDefinition>, TitanOperationStatus> findPropertiesOfNode = propertyOperation.findPropertiesOfNode(NodeTypeEnum.CapabilityType, uniqueId);
301 if (findPropertiesOfNode.isRight()) {
302 TitanOperationStatus titanOperationStatus = findPropertiesOfNode.right().value();
303 log.debug("After looking for properties of vertex {}. status is {}", uniqueId, titanOperationStatus);
304 if (TitanOperationStatus.NOT_FOUND.equals(titanOperationStatus)) {
305 return TitanOperationStatus.OK;
307 return titanOperationStatus;
310 Map<String, PropertyDefinition> properties = findPropertiesOfNode.left().value();
311 capabilityTypeDefinition.setProperties(properties);
312 return TitanOperationStatus.OK;
316 public Either<Boolean, StorageOperationStatus> isCapabilityTypeDerivedFrom(String childCandidateType, String parentCandidateType) {
317 return derivedFromOperation.isTypeDerivedFrom(childCandidateType, parentCandidateType, null, NodeTypeEnum.CapabilityType, CapabilityTypeData.class, t -> t.getCapabilityTypeDataDefinition().getType());
322 public Either<CapabilityTypeDefinition, StorageOperationStatus> updateCapabilityType(CapabilityTypeDefinition capabilityTypeDefNew,
323 CapabilityTypeDefinition capabilityTypeDefOld) {
324 log.debug("updating capability type {}", capabilityTypeDefNew.getType());
325 updateCapabilityTypeData(capabilityTypeDefNew, capabilityTypeDefOld);
326 return updateCapabilityTypeOnGraph(capabilityTypeDefNew, capabilityTypeDefOld);
330 private Either<CapabilityTypeDefinition, StorageOperationStatus> updateCapabilityTypeOnGraph(CapabilityTypeDefinition capabilityTypeDefinitionNew, CapabilityTypeDefinition capabilityTypeDefinitionOld) {
331 return titanGenericDao.updateNode(new CapabilityTypeData(capabilityTypeDefinitionNew), CapabilityTypeData.class)
333 .map(DaoStatusConverter::convertTitanStatusToStorageStatus)
335 .bind(updatedNode -> updateProperties(capabilityTypeDefinitionNew.getUniqueId(), capabilityTypeDefinitionNew.getProperties()))
337 .bind(updatedProperties -> updateDerivedFrom(capabilityTypeDefinitionNew, capabilityTypeDefinitionOld.getDerivedFrom()))
339 .bind(result -> TypeOperations.mapOkStatus(result, null))
341 .map(updatedDerivedFrom -> capabilityTypeDefinitionNew);
344 private Either<Map<String, PropertyData>, StorageOperationStatus> updateProperties(String capabilityTypeId, Map<String, PropertyDefinition> properties) {
345 log.debug("#updateCapabilityTypeProperties - updating properties for capability type with id {}", capabilityTypeId);
346 return propertyOperation.mergePropertiesAssociatedToNode(NodeTypeEnum.CapabilityType, capabilityTypeId, properties)
348 .map(DaoStatusConverter::convertTitanStatusToStorageStatus);
351 private Either<GraphRelation, StorageOperationStatus> updateDerivedFrom(CapabilityTypeDefinition updatedCapabilityType, String currDerivedFromCapabilityType) {
352 if( StringUtils.equals(updatedCapabilityType.getDerivedFrom(), currDerivedFromCapabilityType)) {
353 return Either.right(StorageOperationStatus.OK);
356 StorageOperationStatus status = isLegalToReplaceParent(currDerivedFromCapabilityType, updatedCapabilityType.getDerivedFrom(), updatedCapabilityType.getType());
357 if ( status != StorageOperationStatus.OK) {
358 return Either.right(status);
361 String capabilityTypeId = updatedCapabilityType.getUniqueId();
362 log.debug("#updateCapabilityTypeDerivedFrom - updating capability type derived from relation for capability type with id {}. old derived type {}. new derived type {}", capabilityTypeId, currDerivedFromCapabilityType, updatedCapabilityType.getDerivedFrom());
363 StorageOperationStatus deleteDerivedRelationStatus = deleteDerivedFromCapabilityType(capabilityTypeId, currDerivedFromCapabilityType);
364 if (deleteDerivedRelationStatus != StorageOperationStatus.OK) {
365 return Either.right(deleteDerivedRelationStatus);
367 return addDerivedFromRelation(updatedCapabilityType, capabilityTypeId);
370 private StorageOperationStatus isLegalToReplaceParent(String oldTypeParent, String newTypeParent, String childType) {
371 return derivedFromOperation.isUpdateParentAllowed(oldTypeParent, newTypeParent, childType, NodeTypeEnum.CapabilityType, CapabilityTypeData.class, t -> t.getCapabilityTypeDataDefinition().getType());
374 private Either<GraphRelation, StorageOperationStatus> addDerivedFromRelation(CapabilityTypeDefinition capabilityTypeDef, String ptUniqueId) {
375 String derivedFrom = capabilityTypeDef.getDerivedFrom();
376 if (derivedFrom == null) {
377 return Either.left(null);
379 log.debug("#addDerivedFromRelationBefore - adding derived from relation between capability type {} to its parent {}", capabilityTypeDef.getType(), derivedFrom);
380 return this.getCapabilityType(derivedFrom, true)
382 .bind(derivedFromCapabilityType -> derivedFromOperation.addDerivedFromRelation(ptUniqueId, derivedFromCapabilityType.getUniqueId(), NodeTypeEnum.CapabilityType));
385 private StorageOperationStatus deleteDerivedFromCapabilityType(String capabilityTypeId, String derivedFromType) {
386 if (derivedFromType == null) {
387 return StorageOperationStatus.OK;
389 log.debug("#deleteDerivedFromCapabilityType - deleting derivedFrom relation for capability type with id {} and its derived type {}", capabilityTypeId, derivedFromType);
390 return getCapabilityType(derivedFromType, true)
391 .either(derivedFromNode -> derivedFromOperation.removeDerivedFromRelation(capabilityTypeId, derivedFromNode.getUniqueId(), NodeTypeEnum.CapabilityType),
395 private void updateCapabilityTypeData(CapabilityTypeDefinition updatedTypeDefinition, CapabilityTypeDefinition currTypeDefinition) {
396 updatedTypeDefinition.setUniqueId(currTypeDefinition.getUniqueId());
397 updatedTypeDefinition.setCreationTime(currTypeDefinition.getCreationTime());
404 * @param propertyOperation
406 public void setPropertyOperation(PropertyOperation propertyOperation) {
407 this.propertyOperation = propertyOperation;
411 public Either<CapabilityTypeDefinition, StorageOperationStatus> addCapabilityType(CapabilityTypeDefinition capabilityTypeDefinition) {
413 return addCapabilityType(capabilityTypeDefinition, true);
417 public Either<CapabilityTypeDefinition, StorageOperationStatus> getCapabilityType(String uniqueId) {
418 return getCapabilityType(uniqueId, true);