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 java.util.Collection;
24 import java.util.HashMap;
25 import java.util.HashSet;
26 import java.util.List;
29 import java.util.stream.Collectors;
31 import org.apache.commons.lang3.tuple.ImmutablePair;
32 import org.openecomp.sdc.be.dao.graph.datatype.GraphEdge;
33 import org.openecomp.sdc.be.dao.graph.datatype.GraphRelation;
34 import org.openecomp.sdc.be.dao.neo4j.GraphEdgeLabels;
35 import org.openecomp.sdc.be.dao.titan.TitanGenericDao;
36 import org.openecomp.sdc.be.dao.titan.TitanOperationStatus;
37 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
38 import org.openecomp.sdc.be.model.CapabilityTypeDefinition;
39 import org.openecomp.sdc.be.model.PropertyDefinition;
40 import org.openecomp.sdc.be.model.operations.api.ICapabilityTypeOperation;
41 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
42 import org.openecomp.sdc.be.resources.data.CapabilityTypeData;
43 import org.openecomp.sdc.be.resources.data.PropertyData;
44 import org.openecomp.sdc.be.resources.data.UniqueIdData;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47 import org.springframework.beans.factory.annotation.Autowired;
48 import org.springframework.stereotype.Component;
50 import fj.data.Either;
52 @Component("capability-type-operation")
53 public class CapabilityTypeOperation extends AbstractOperation implements ICapabilityTypeOperation {
55 private PropertyOperation propertyOperation;
57 private CapabilityOperation capabilityOperation;
59 public CapabilityTypeOperation() {
63 private static Logger log = LoggerFactory.getLogger(CapabilityTypeOperation.class.getName());
68 * @param titanGenericDao
70 public void setTitanGenericDao(TitanGenericDao titanGenericDao) {
71 this.titanGenericDao = titanGenericDao;
75 public Either<CapabilityTypeDefinition, StorageOperationStatus> addCapabilityType(
76 CapabilityTypeDefinition capabilityTypeDefinition, boolean inTransaction) {
78 Either<CapabilityTypeDefinition, StorageOperationStatus> result = null;
81 Either<CapabilityTypeDefinition, TitanOperationStatus> validationRes = validateUpdateProperties(
82 capabilityTypeDefinition);
83 if (validationRes.isRight()) {
84 log.error("One or all properties of capability type {} not valid. status is {}",
85 capabilityTypeDefinition, validationRes.right().value().name());
87 .right(DaoStatusConverter.convertTitanStatusToStorageStatus(validationRes.right().value()));
90 Either<CapabilityTypeData, TitanOperationStatus> eitherStatus = addCapabilityTypeToGraph(
91 capabilityTypeDefinition);
93 if (eitherStatus.isRight()) {
94 log.error("Failed to add capability {} to Graph. status is {}", capabilityTypeDefinition,
95 eitherStatus.right().value().name());
97 .right(DaoStatusConverter.convertTitanStatusToStorageStatus(eitherStatus.right().value()));
100 CapabilityTypeData capabilityTypeData = eitherStatus.left().value();
102 CapabilityTypeDefinition capabilityTypeDefResult = convertCTDataToCTDefinition(capabilityTypeData);
103 log.debug("The returned CapabilityTypeDefinition is {}", capabilityTypeDefResult);
104 result = Either.left(capabilityTypeDefResult);
110 if (false == inTransaction) {
111 if (result == null || result.isRight()) {
112 log.error("Going to execute rollback on graph.");
113 titanGenericDao.rollback();
115 log.debug("Going to execute commit on graph.");
116 titanGenericDao.commit();
123 private Either<CapabilityTypeDefinition, TitanOperationStatus> validateUpdateProperties(
124 CapabilityTypeDefinition capabilityTypeDefinition) {
125 TitanOperationStatus error = null;
126 if (capabilityTypeDefinition.getProperties() != null && !capabilityTypeDefinition.getProperties().isEmpty()
127 && capabilityTypeDefinition.getDerivedFrom() != null) {
128 Either<Map<String, PropertyDefinition>, TitanOperationStatus> allPropertiesRes = capabilityOperation
129 .getAllCapabilityTypePropertiesFromAllDerivedFrom(capabilityTypeDefinition.getDerivedFrom());
130 if (allPropertiesRes.isRight()
131 && !allPropertiesRes.right().value().equals(TitanOperationStatus.NOT_FOUND)) {
132 error = allPropertiesRes.right().value();
133 log.debug("Couldn't fetch derived from property nodes for capability type {}, error: {}",
134 capabilityTypeDefinition.getType(), error);
136 if (error == null && !allPropertiesRes.left().value().isEmpty()) {
137 Map<String, PropertyDefinition> derivedFromProperties = allPropertiesRes.left().value();
138 capabilityTypeDefinition.getProperties().entrySet().stream()
139 .filter(e -> derivedFromProperties.containsKey(e.getKey()) && e.getValue().getType() == null)
140 .forEach(e -> e.getValue().setType(derivedFromProperties.get(e.getKey()).getType()));
142 Either<List<PropertyDefinition>, TitanOperationStatus> validatePropertiesRes = capabilityOperation
143 .validatePropertyUniqueness(allPropertiesRes.left().value(), capabilityTypeDefinition
144 .getProperties().values().stream().collect(Collectors.toList()));
145 if (validatePropertiesRes.isRight()) {
146 error = validatePropertiesRes.right().value();
151 return Either.left(capabilityTypeDefinition);
153 return Either.right(error);
158 * convert between graph Node object to Java object
160 * @param capabilityTypeData
163 protected CapabilityTypeDefinition convertCTDataToCTDefinition(CapabilityTypeData capabilityTypeData) {
164 log.debug("The object returned after create capability is {}", capabilityTypeData);
166 CapabilityTypeDefinition capabilityTypeDefResult = new CapabilityTypeDefinition(
167 capabilityTypeData.getCapabilityTypeDataDefinition());
169 return capabilityTypeDefResult;
174 * Add capability type to graph.
176 * 1. Add capability type node
178 * 2. Add edge between the former node to its parent(if exists)
180 * 3. Add property node and associate it to the node created at #1. (per
181 * property & if exists)
183 * @param capabilityTypeDefinition
186 private Either<CapabilityTypeData, TitanOperationStatus> addCapabilityTypeToGraph(
187 CapabilityTypeDefinition capabilityTypeDefinition) {
189 log.debug("Got capability type {}", capabilityTypeDefinition);
191 String ctUniqueId = UniqueIdBuilder.buildCapabilityTypeUid(capabilityTypeDefinition.getType());
192 // capabilityTypeDefinition.setUniqueId(ctUniqueId);
194 CapabilityTypeData capabilityTypeData = buildCapabilityTypeData(capabilityTypeDefinition, ctUniqueId);
196 log.debug("Before adding capability type to graph. capabilityTypeData = {}", capabilityTypeData);
197 Either<CapabilityTypeData, TitanOperationStatus> createCTResult = titanGenericDao.createNode(capabilityTypeData,
198 CapabilityTypeData.class);
199 log.debug("After adding capability type to graph. status is = {}", createCTResult);
201 if (createCTResult.isRight()) {
202 TitanOperationStatus operationStatus = createCTResult.right().value();
203 log.error("Failed to capability type " + capabilityTypeDefinition.getType() + " to graph. status is "
205 return Either.right(operationStatus);
208 CapabilityTypeData resultCTD = createCTResult.left().value();
209 Map<String, PropertyDefinition> propertiesMap = capabilityTypeDefinition.getProperties();
210 Collection<PropertyDefinition> properties = propertiesMap != null ? propertiesMap.values() : null;
211 Either<Map<String, PropertyData>, TitanOperationStatus> addPropertiesToCapablityType = propertyOperation
212 .addPropertiesToElementType(resultCTD.getUniqueId(), NodeTypeEnum.CapabilityType, propertiesMap);
213 if (addPropertiesToCapablityType.isRight()) {
215 "Failed add properties " + propertiesMap + " to capability " + capabilityTypeDefinition.getType());
216 return Either.right(addPropertiesToCapablityType.right().value());
219 String derivedFrom = capabilityTypeDefinition.getDerivedFrom();
220 if (derivedFrom != null) {
222 "Before creating relation between capability type " + ctUniqueId + " to its parent " + derivedFrom);
223 UniqueIdData from = new UniqueIdData(NodeTypeEnum.CapabilityType, ctUniqueId);
224 UniqueIdData to = new UniqueIdData(NodeTypeEnum.CapabilityType, derivedFrom);
225 Either<GraphRelation, TitanOperationStatus> createRelation = titanGenericDao.createRelation(from, to,
226 GraphEdgeLabels.DERIVED_FROM, null);
227 log.debug("After create relation between capability type {} to its parent {}. Status is {}", ctUniqueId, derivedFrom, createRelation);
228 if (createRelation.isRight()) {
229 return Either.right(createRelation.right().value());
233 return Either.left(createCTResult.left().value());
237 private CapabilityTypeData buildCapabilityTypeData(CapabilityTypeDefinition capabilityTypeDefinition,
240 CapabilityTypeData capabilityTypeData = new CapabilityTypeData(capabilityTypeDefinition);
242 capabilityTypeData.getCapabilityTypeDataDefinition().setUniqueId(ctUniqueId);
243 Long creationDate = capabilityTypeData.getCapabilityTypeDataDefinition().getCreationTime();
244 if (creationDate == null) {
245 creationDate = System.currentTimeMillis();
247 capabilityTypeData.getCapabilityTypeDataDefinition().setCreationTime(creationDate);
248 capabilityTypeData.getCapabilityTypeDataDefinition().setModificationTime(creationDate);
249 return capabilityTypeData;
253 public Either<CapabilityTypeDefinition, StorageOperationStatus> getCapabilityType(String uniqueId,
254 boolean inTransaction) {
256 Either<CapabilityTypeDefinition, StorageOperationStatus> result = null;
259 Either<CapabilityTypeDefinition, TitanOperationStatus> ctResult = this.getCapabilityTypeByUid(uniqueId);
261 if (ctResult.isRight()) {
262 TitanOperationStatus status = ctResult.right().value();
263 if (status != TitanOperationStatus.NOT_FOUND) {
264 log.error("Failed to retrieve information on capability type {}. Status is {}", uniqueId, status);
266 result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(ctResult.right().value()));
270 result = Either.left(ctResult.left().value());
274 if (false == inTransaction) {
275 log.debug("Going to execute commit on graph.");
276 titanGenericDao.commit();
282 * Build Capability type object from graph by unique id
287 public Either<CapabilityTypeDefinition, TitanOperationStatus> getCapabilityTypeByUid(String uniqueId) {
289 Either<CapabilityTypeDefinition, TitanOperationStatus> result = null;
291 Either<CapabilityTypeData, TitanOperationStatus> capabilityTypesRes = titanGenericDao.getNode(
292 UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.CapabilityType), uniqueId, CapabilityTypeData.class);
294 if (capabilityTypesRes.isRight()) {
295 TitanOperationStatus status = capabilityTypesRes.right().value();
296 log.debug("Capability type {} cannot be found in graph. Status is {}", uniqueId, status);
297 return Either.right(status);
300 CapabilityTypeData ctData = capabilityTypesRes.left().value();
301 CapabilityTypeDefinition capabilityTypeDefinition = new CapabilityTypeDefinition(
302 ctData.getCapabilityTypeDataDefinition());
304 TitanOperationStatus propertiesStatus = fillProperties(uniqueId, capabilityTypeDefinition);
305 if (propertiesStatus != TitanOperationStatus.OK) {
306 log.error("Failed to fetch properties of capability type " + uniqueId);
307 return Either.right(propertiesStatus);
310 Either<ImmutablePair<CapabilityTypeData, GraphEdge>, TitanOperationStatus> parentNode = titanGenericDao
311 .getChild(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.CapabilityType), uniqueId,
312 GraphEdgeLabels.DERIVED_FROM, NodeTypeEnum.CapabilityType, CapabilityTypeData.class);
313 log.debug("After retrieving DERIVED_FROM node of {}. Status is {}", uniqueId, parentNode);
314 if (parentNode.isRight()) {
315 TitanOperationStatus titanOperationStatus = parentNode.right().value();
316 if (titanOperationStatus != TitanOperationStatus.NOT_FOUND) {
317 log.error("Failed to find the parent capability of capability type {}. Status is {}", uniqueId, titanOperationStatus);
318 result = Either.right(titanOperationStatus);
322 // derived from node was found
323 ImmutablePair<CapabilityTypeData, GraphEdge> immutablePair = parentNode.left().value();
324 CapabilityTypeData parentCT = immutablePair.getKey();
325 capabilityTypeDefinition.setDerivedFrom(parentCT.getCapabilityTypeDataDefinition().getType());
327 result = Either.left(capabilityTypeDefinition);
332 private TitanOperationStatus fillProperties(String uniqueId, CapabilityTypeDefinition capabilityTypeDefinition) {
334 Either<Map<String, PropertyDefinition>, TitanOperationStatus> findPropertiesOfNode = propertyOperation
335 .findPropertiesOfNode(NodeTypeEnum.CapabilityType, uniqueId);
336 if (findPropertiesOfNode.isRight()) {
337 TitanOperationStatus titanOperationStatus = findPropertiesOfNode.right().value();
338 log.debug("After looking for properties of vertex {}. Status is {}", uniqueId, titanOperationStatus);
339 if (TitanOperationStatus.NOT_FOUND.equals(titanOperationStatus)) {
340 return TitanOperationStatus.OK;
342 return titanOperationStatus;
345 Map<String, PropertyDefinition> properties = findPropertiesOfNode.left().value();
346 capabilityTypeDefinition.setProperties(properties);
347 return TitanOperationStatus.OK;
351 public Either<Boolean, StorageOperationStatus> isCapabilityTypeDerivedFrom(String childCandidateType,
352 String parentCandidateType) {
353 Map<String, Object> propertiesToMatch = new HashMap<String, Object>();
354 propertiesToMatch.put(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.CapabilityType), childCandidateType);
355 Either<List<CapabilityTypeData>, TitanOperationStatus> getResponse = titanGenericDao
356 .getByCriteria(NodeTypeEnum.CapabilityType, propertiesToMatch, CapabilityTypeData.class);
357 if (getResponse.isRight()) {
358 TitanOperationStatus titanOperationStatus = getResponse.right().value();
359 log.debug("Couldn't fetch capability type {}, error: {}", childCandidateType, titanOperationStatus);
360 return Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(titanOperationStatus));
362 String childUniqueId = getResponse.left().value().get(0).getUniqueId();
363 Set<String> travelledTypes = new HashSet<>();
365 travelledTypes.add(childUniqueId);
366 Either<List<ImmutablePair<CapabilityTypeData, GraphEdge>>, TitanOperationStatus> childrenNodes = titanGenericDao
367 .getChildrenNodes(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.CapabilityType), childUniqueId,
368 GraphEdgeLabels.DERIVED_FROM, NodeTypeEnum.CapabilityType, CapabilityTypeData.class);
369 if (childrenNodes.isRight()) {
370 if (childrenNodes.right().value() != TitanOperationStatus.NOT_FOUND) {
371 TitanOperationStatus titanOperationStatus = getResponse.right().value();
372 log.debug("Couldn't fetch derived from node for capability type {}, error: {}", childCandidateType,
373 titanOperationStatus);
374 return Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(titanOperationStatus));
376 log.debug("Derived from node is not found for type {} - this is OK for root capability.");
377 return Either.left(false);
380 String derivedFromUniqueId = childrenNodes.left().value().get(0).getLeft().getUniqueId();
381 if (derivedFromUniqueId.equals(parentCandidateType)) {
382 log.debug("Verified that capability type {} derives from capability type {}", childCandidateType,
383 parentCandidateType);
384 return Either.left(true);
386 childUniqueId = derivedFromUniqueId;
387 } while (!travelledTypes.contains(childUniqueId));
388 // this stop condition should never be used, if we use it, we have an
389 // illegal cycle in graph - "derived from" hierarchy cannot be cycled.
390 // It's here just to avoid infinite loop in case we have such cycle.
391 log.error("Detected a cycle of \"derived from\" edges starting at capability type node {}", childUniqueId);
392 return Either.right(StorageOperationStatus.GENERAL_ERROR);
398 * @param propertyOperation
400 public void setPropertyOperation(PropertyOperation propertyOperation) {
401 this.propertyOperation = propertyOperation;
405 public Either<CapabilityTypeDefinition, StorageOperationStatus> addCapabilityType(
406 CapabilityTypeDefinition capabilityTypeDefinition) {
408 return addCapabilityType(capabilityTypeDefinition, false);
412 public Either<CapabilityTypeDefinition, StorageOperationStatus> getCapabilityType(String uniqueId) {
413 return getCapabilityType(uniqueId, false);