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=========================================================
20 package org.openecomp.sdc.be.model.operations.impl;
22 import fj.data.Either;
23 import java.util.HashMap;
24 import java.util.List;
26 import java.util.stream.Collectors;
27 import org.apache.commons.collections.MapUtils;
28 import org.apache.commons.lang3.StringUtils;
29 import org.apache.commons.lang3.tuple.ImmutablePair;
30 import org.openecomp.sdc.be.dao.graph.datatype.GraphEdge;
31 import org.openecomp.sdc.be.dao.graph.datatype.GraphRelation;
32 import org.openecomp.sdc.be.dao.janusgraph.HealingJanusGraphGenericDao;
33 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
34 import org.openecomp.sdc.be.dao.neo4j.GraphEdgeLabels;
35 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
36 import org.openecomp.sdc.be.model.CapabilityTypeDefinition;
37 import org.openecomp.sdc.be.model.PropertyDefinition;
38 import org.openecomp.sdc.be.model.operations.api.DerivedFromOperation;
39 import org.openecomp.sdc.be.model.operations.api.ICapabilityTypeOperation;
40 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
41 import org.openecomp.sdc.be.model.operations.api.TypeOperations;
42 import org.openecomp.sdc.be.resources.data.CapabilityTypeData;
43 import org.openecomp.sdc.be.resources.data.PropertyData;
44 import org.openecomp.sdc.common.log.wrappers.Logger;
45 import org.springframework.beans.factory.annotation.Autowired;
46 import org.springframework.stereotype.Component;
48 @Component("capability-type-operation")
49 public class CapabilityTypeOperation extends AbstractOperation implements ICapabilityTypeOperation {
51 private static final Logger log = Logger.getLogger(CapabilityTypeOperation.class.getName());
52 private static final String DATA_TYPE_CANNOT_BE_FOUND_IN_GRAPH_STATUS_IS = "Data type {} cannot be found in graph." + " status is {}";
53 private static final String FAILED_TO_FETCH_PROPERTIES_OF_DATA_TYPE = "Failed to fetch properties of data type {}";
55 private PropertyOperation propertyOperation;
57 private DerivedFromOperation derivedFromOperation;
59 public CapabilityTypeOperation() {
66 * @param janusGraphGenericDao
68 public void setJanusGraphGenericDao(HealingJanusGraphGenericDao janusGraphGenericDao) {
69 this.janusGraphGenericDao = janusGraphGenericDao;
73 public Either<CapabilityTypeDefinition, StorageOperationStatus> addCapabilityType(CapabilityTypeDefinition capabilityTypeDefinition,
74 boolean inTransaction) {
75 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,
80 validationRes.right().value());
83 Either<CapabilityTypeData, StorageOperationStatus> eitherStatus = addCapabilityTypeToGraph(capabilityTypeDefinition);
84 result = eitherStatus.left().map(CapabilityTypeData::getUniqueId).left().bind(uniqueId -> getCapabilityType(uniqueId, inTransaction));
85 if (result.isLeft()) {
86 log.debug("#addCapabilityType - The returned CapabilityTypeDefinition is {}", result.left().value());
91 if (result == null || result.isRight()) {
92 log.error("#addCapabilityType - Going to execute rollback on graph.");
93 janusGraphGenericDao.rollback();
95 log.debug("#addCapabilityType - Going to execute commit on graph.");
96 janusGraphGenericDao.commit();
102 public Either<Map<String, PropertyDefinition>, JanusGraphOperationStatus> getAllCapabilityTypePropertiesFromAllDerivedFrom(
103 String firstParentType) {
104 return propertyOperation.getAllTypePropertiesFromAllDerivedFrom(firstParentType, NodeTypeEnum.CapabilityType, CapabilityTypeData.class);
107 public Either<CapabilityTypeDefinition, StorageOperationStatus> validateUpdateProperties(CapabilityTypeDefinition capabilityTypeDefinition) {
108 JanusGraphOperationStatus error = null;
109 if (MapUtils.isNotEmpty(capabilityTypeDefinition.getProperties()) && capabilityTypeDefinition.getDerivedFrom() != null) {
110 Either<Map<String, PropertyDefinition>, JanusGraphOperationStatus> allPropertiesRes = getAllCapabilityTypePropertiesFromAllDerivedFrom(
111 capabilityTypeDefinition.getDerivedFrom());
112 if (allPropertiesRes.isRight() && !allPropertiesRes.right().value().equals(JanusGraphOperationStatus.NOT_FOUND)) {
113 error = allPropertiesRes.right().value();
114 log.debug("Couldn't fetch derived from property nodes for capability type {}, error: {}", capabilityTypeDefinition.getType(), error);
116 if (error == null && !allPropertiesRes.left().value().isEmpty()) {
117 Map<String, PropertyDefinition> derivedFromProperties = allPropertiesRes.left().value();
118 capabilityTypeDefinition.getProperties().entrySet().stream()
119 .filter(e -> derivedFromProperties.containsKey(e.getKey()) && e.getValue().getType() == null)
120 .forEach(e -> e.getValue().setType(derivedFromProperties.get(e.getKey()).getType()));
121 List<PropertyDefinition> properties = capabilityTypeDefinition.getProperties().values().stream().collect(Collectors.toList());
122 Either<List<PropertyDefinition>, JanusGraphOperationStatus> validatePropertiesRes = propertyOperation
123 .validatePropertiesUniqueness(allPropertiesRes.left().value(), properties);
124 if (validatePropertiesRes.isRight()) {
125 error = validatePropertiesRes.right().value();
130 return Either.left(capabilityTypeDefinition);
132 return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(error));
136 * Add capability type to graph.
138 * 1. Add capability type node
140 * 2. Add edge between the former node to its parent(if exists)
142 * 3. Add property node and associate it to the node created at #1. (per property & if exists)
144 * @param capabilityTypeDefinition
147 private Either<CapabilityTypeData, StorageOperationStatus> addCapabilityTypeToGraph(CapabilityTypeDefinition capabilityTypeDefinition) {
148 log.debug("Got capability type {}", capabilityTypeDefinition);
149 String ctUniqueId = UniqueIdBuilder.buildCapabilityTypeUid(capabilityTypeDefinition.getType());
150 CapabilityTypeData capabilityTypeData = buildCapabilityTypeData(capabilityTypeDefinition, ctUniqueId);
151 log.debug("Before adding capability type to graph. capabilityTypeData = {}", capabilityTypeData);
152 Either<CapabilityTypeData, JanusGraphOperationStatus> createCTResult = janusGraphGenericDao
153 .createNode(capabilityTypeData, CapabilityTypeData.class);
154 log.debug("After adding capability type to graph. status is = {}", createCTResult);
155 if (createCTResult.isRight()) {
156 JanusGraphOperationStatus operationStatus = createCTResult.right().value();
157 log.error("Failed to capability type {} to graph. status is {}", capabilityTypeDefinition.getType(), operationStatus);
158 return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(operationStatus));
160 CapabilityTypeData resultCTD = createCTResult.left().value();
161 Map<String, PropertyDefinition> propertiesMap = capabilityTypeDefinition.getProperties();
162 Either<Map<String, PropertyData>, JanusGraphOperationStatus> addPropertiesToCapablityType = propertyOperation
163 .addPropertiesToElementType(resultCTD.getUniqueId(), NodeTypeEnum.CapabilityType, propertiesMap);
164 if (addPropertiesToCapablityType.isRight()) {
165 log.error("Failed add properties {} to capability {}", propertiesMap, capabilityTypeDefinition.getType());
166 return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(addPropertiesToCapablityType.right().value()));
168 return addDerivedFromRelation(capabilityTypeDefinition, ctUniqueId).left().map(updatedDerivedFrom -> createCTResult.left().value());
171 private CapabilityTypeData buildCapabilityTypeData(CapabilityTypeDefinition capabilityTypeDefinition, String ctUniqueId) {
172 CapabilityTypeData capabilityTypeData = new CapabilityTypeData(capabilityTypeDefinition);
173 capabilityTypeData.getCapabilityTypeDataDefinition().setUniqueId(ctUniqueId);
174 Long creationDate = capabilityTypeData.getCapabilityTypeDataDefinition().getCreationTime();
175 if (creationDate == null) {
176 creationDate = System.currentTimeMillis();
178 capabilityTypeData.getCapabilityTypeDataDefinition().setCreationTime(creationDate);
179 capabilityTypeData.getCapabilityTypeDataDefinition().setModificationTime(creationDate);
180 return capabilityTypeData;
184 public Either<CapabilityTypeDefinition, StorageOperationStatus> getCapabilityType(String uniqueId, boolean inTransaction) {
185 Either<CapabilityTypeDefinition, StorageOperationStatus> result = null;
187 Either<CapabilityTypeDefinition, JanusGraphOperationStatus> ctResult = this.getCapabilityTypeByUid(uniqueId);
188 if (ctResult.isRight()) {
189 JanusGraphOperationStatus status = ctResult.right().value();
190 if (status != JanusGraphOperationStatus.NOT_FOUND) {
191 log.error("Failed to retrieve information on capability type {}. status is {}", uniqueId, status);
193 result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(ctResult.right().value()));
196 result = Either.left(ctResult.left().value());
199 if (!inTransaction) {
200 log.debug("Going to execute commit on graph.");
201 janusGraphGenericDao.commit();
206 public Either<CapabilityTypeDefinition, JanusGraphOperationStatus> getCapabilityTypeByType(String capabilityType) {
207 // Optimization: In case of Capability Type its unique ID is the same as type
208 return getCapabilityTypeByUid(capabilityType);
212 * Build Capability type object from graph by unique id
217 public Either<CapabilityTypeDefinition, JanusGraphOperationStatus> getCapabilityTypeByUid(String uniqueId) {
218 Either<CapabilityTypeDefinition, JanusGraphOperationStatus> result = null;
219 Either<CapabilityTypeData, JanusGraphOperationStatus> capabilityTypesRes = janusGraphGenericDao
220 .getNode(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.CapabilityType), uniqueId, CapabilityTypeData.class);
221 if (capabilityTypesRes.isRight()) {
222 JanusGraphOperationStatus status = capabilityTypesRes.right().value();
223 log.debug("Capability type {} cannot be found in graph. status is {}", uniqueId, status);
224 return Either.right(status);
226 CapabilityTypeData ctData = capabilityTypesRes.left().value();
227 CapabilityTypeDefinition capabilityTypeDefinition = new CapabilityTypeDefinition(ctData.getCapabilityTypeDataDefinition());
228 Either<Map<String, PropertyDefinition>, JanusGraphOperationStatus> propertiesStatus = OperationUtils
229 .fillProperties(uniqueId, propertyOperation, NodeTypeEnum.CapabilityType);
230 if (propertiesStatus.isRight() && propertiesStatus.right().value() != JanusGraphOperationStatus.OK) {
231 log.error("Failed to fetch properties of capability type {}", uniqueId);
232 return Either.right(propertiesStatus.right().value());
234 if (propertiesStatus.isLeft()) {
235 capabilityTypeDefinition.setProperties(propertiesStatus.left().value());
237 Either<ImmutablePair<CapabilityTypeData, GraphEdge>, JanusGraphOperationStatus> parentNode = janusGraphGenericDao
238 .getChild(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.CapabilityType), uniqueId, GraphEdgeLabels.DERIVED_FROM,
239 NodeTypeEnum.CapabilityType, CapabilityTypeData.class);
240 log.debug("After retrieving DERIVED_FROM node of {}. status is {}", uniqueId, parentNode);
241 if (parentNode.isRight()) {
242 JanusGraphOperationStatus janusGraphOperationStatus = parentNode.right().value();
243 if (janusGraphOperationStatus != JanusGraphOperationStatus.NOT_FOUND) {
244 log.error("Failed to find the parent capability of capability type {}. status is {}", uniqueId, janusGraphOperationStatus);
245 result = Either.right(janusGraphOperationStatus);
249 // derived from node was found
250 ImmutablePair<CapabilityTypeData, GraphEdge> immutablePair = parentNode.left().value();
251 CapabilityTypeData parentCT = immutablePair.getKey();
252 capabilityTypeDefinition.setDerivedFrom(parentCT.getCapabilityTypeDataDefinition().getType());
254 result = Either.left(capabilityTypeDefinition);
258 public Either<Boolean, StorageOperationStatus> isCapabilityTypeDerivedFrom(String childCandidateType, String parentCandidateType) {
259 return derivedFromOperation
260 .isTypeDerivedFrom(childCandidateType, parentCandidateType, null, NodeTypeEnum.CapabilityType, CapabilityTypeData.class,
261 t -> t.getCapabilityTypeDataDefinition().getType());
265 public Either<CapabilityTypeDefinition, StorageOperationStatus> updateCapabilityType(CapabilityTypeDefinition capabilityTypeDefNew,
266 CapabilityTypeDefinition capabilityTypeDefOld) {
267 log.debug("updating capability type {}", capabilityTypeDefNew.getType());
268 updateCapabilityTypeData(capabilityTypeDefNew, capabilityTypeDefOld);
269 return updateCapabilityTypeOnGraph(capabilityTypeDefNew, capabilityTypeDefOld);
272 private Either<CapabilityTypeDefinition, StorageOperationStatus> updateCapabilityTypeOnGraph(CapabilityTypeDefinition capabilityTypeDefinitionNew,
273 CapabilityTypeDefinition capabilityTypeDefinitionOld) {
274 return janusGraphGenericDao.updateNode(new CapabilityTypeData(capabilityTypeDefinitionNew), CapabilityTypeData.class).right()
275 .map(DaoStatusConverter::convertJanusGraphStatusToStorageStatus).left()
276 .bind(updatedNode -> updateProperties(capabilityTypeDefinitionNew.getUniqueId(), capabilityTypeDefinitionNew.getProperties())).left()
277 .bind(updatedProperties -> updateDerivedFrom(capabilityTypeDefinitionNew, capabilityTypeDefinitionOld.getDerivedFrom())).right()
278 .bind(result -> TypeOperations.mapOkStatus(result, null)).left().map(updatedDerivedFrom -> capabilityTypeDefinitionNew);
281 private Either<Map<String, PropertyData>, StorageOperationStatus> updateProperties(String capabilityTypeId,
282 Map<String, PropertyDefinition> properties) {
283 log.debug("#updateCapabilityTypeProperties - updating properties for capability type with id {}", capabilityTypeId);
284 return propertyOperation.mergePropertiesAssociatedToNode(NodeTypeEnum.CapabilityType, capabilityTypeId, properties).right()
285 .map(DaoStatusConverter::convertJanusGraphStatusToStorageStatus);
288 private Either<GraphRelation, StorageOperationStatus> updateDerivedFrom(CapabilityTypeDefinition updatedCapabilityType,
289 String currDerivedFromCapabilityType) {
290 if (StringUtils.equals(updatedCapabilityType.getDerivedFrom(), currDerivedFromCapabilityType)) {
291 return Either.right(StorageOperationStatus.OK);
293 StorageOperationStatus status = isLegalToReplaceParent(currDerivedFromCapabilityType, updatedCapabilityType.getDerivedFrom(),
294 updatedCapabilityType.getType());
295 if (status != StorageOperationStatus.OK) {
296 return Either.right(status);
298 String capabilityTypeId = updatedCapabilityType.getUniqueId();
300 "#updateCapabilityTypeDerivedFrom - updating capability type derived from relation for capability type with id {}. old derived type {}. new derived type {}",
301 capabilityTypeId, currDerivedFromCapabilityType, updatedCapabilityType.getDerivedFrom());
302 StorageOperationStatus deleteDerivedRelationStatus = deleteDerivedFromCapabilityType(capabilityTypeId, currDerivedFromCapabilityType);
303 if (deleteDerivedRelationStatus != StorageOperationStatus.OK) {
304 return Either.right(deleteDerivedRelationStatus);
306 return addDerivedFromRelation(updatedCapabilityType, capabilityTypeId);
309 private StorageOperationStatus isLegalToReplaceParent(String oldTypeParent, String newTypeParent, String childType) {
310 return derivedFromOperation
311 .isUpdateParentAllowed(oldTypeParent, newTypeParent, childType, NodeTypeEnum.CapabilityType, CapabilityTypeData.class,
312 t -> t.getCapabilityTypeDataDefinition().getType());
315 private Either<GraphRelation, StorageOperationStatus> addDerivedFromRelation(CapabilityTypeDefinition capabilityTypeDef, String ptUniqueId) {
316 String derivedFrom = capabilityTypeDef.getDerivedFrom();
317 if (derivedFrom == null) {
318 return Either.left(null);
320 log.debug("#addDerivedFromRelationBefore - adding derived from relation between capability type {} to its parent {}",
321 capabilityTypeDef.getType(), derivedFrom);
322 return this.getCapabilityType(derivedFrom, true).left().bind(derivedFromCapabilityType -> derivedFromOperation
323 .addDerivedFromRelation(ptUniqueId, derivedFromCapabilityType.getUniqueId(), NodeTypeEnum.CapabilityType));
326 private StorageOperationStatus deleteDerivedFromCapabilityType(String capabilityTypeId, String derivedFromType) {
327 if (derivedFromType == null) {
328 return StorageOperationStatus.OK;
330 log.debug("#deleteDerivedFromCapabilityType - deleting derivedFrom relation for capability type with id {} and its derived type {}",
331 capabilityTypeId, derivedFromType);
332 return getCapabilityType(derivedFromType, true).either(derivedFromNode -> derivedFromOperation
333 .removeDerivedFromRelation(capabilityTypeId, derivedFromNode.getUniqueId(), NodeTypeEnum.CapabilityType), err -> err);
336 private void updateCapabilityTypeData(CapabilityTypeDefinition updatedTypeDefinition, CapabilityTypeDefinition currTypeDefinition) {
337 updatedTypeDefinition.setUniqueId(currTypeDefinition.getUniqueId());
338 updatedTypeDefinition.setCreationTime(currTypeDefinition.getCreationTime());
344 * @param propertyOperation
346 public void setPropertyOperation(PropertyOperation propertyOperation) {
347 this.propertyOperation = propertyOperation;
351 public Either<CapabilityTypeDefinition, StorageOperationStatus> addCapabilityType(CapabilityTypeDefinition capabilityTypeDefinition) {
352 return addCapabilityType(capabilityTypeDefinition, true);
356 public Either<CapabilityTypeDefinition, StorageOperationStatus> getCapabilityType(String uniqueId) {
357 return getCapabilityType(uniqueId, true);
360 public Either<Map<String, CapabilityTypeDefinition>, JanusGraphOperationStatus> getAllCapabilityTypes() {
361 Map<String, CapabilityTypeDefinition> capabilityTypes = new HashMap<>();
362 Either<Map<String, CapabilityTypeDefinition>, JanusGraphOperationStatus> result = Either.left(capabilityTypes);
363 Either<List<CapabilityTypeData>, JanusGraphOperationStatus> getAllCapabilityTypes = janusGraphGenericDao
364 .getByCriteria(NodeTypeEnum.CapabilityType, null, CapabilityTypeData.class);
365 if (getAllCapabilityTypes.isRight()) {
366 JanusGraphOperationStatus status = getAllCapabilityTypes.right().value();
367 if (status != JanusGraphOperationStatus.NOT_FOUND) {
368 return Either.right(status);
373 List<CapabilityTypeData> list = getAllCapabilityTypes.left().value();
375 log.trace("Number of data types to load is {}", list.size());
377 for (CapabilityTypeData capabilityTypeData : list) {
378 log.trace("Going to fetch data type {}. uid is {}", capabilityTypeData.getCapabilityTypeDataDefinition().getType(),
379 capabilityTypeData.getUniqueId());
380 Either<CapabilityTypeDefinition, JanusGraphOperationStatus> capabilityTypesByUid = getAndAddPropertiesANdDerivedFrom(
381 capabilityTypeData.getUniqueId(), capabilityTypes);
382 if (capabilityTypesByUid.isRight()) {
383 JanusGraphOperationStatus status = capabilityTypesByUid.right().value();
384 if (status == JanusGraphOperationStatus.NOT_FOUND) {
385 status = JanusGraphOperationStatus.INVALID_ID;
387 return Either.right(status);
394 private void fillDerivedFrom(String uniqueId, CapabilityTypeDefinition capabilityType) {
395 log.debug("#fillDerivedFrom - fetching capability type {} derived node", capabilityType.getType());
396 derivedFromOperation.getDerivedFromChild(uniqueId, NodeTypeEnum.CapabilityType, CapabilityTypeData.class).right()
397 .bind(this::handleDerivedFromNotExist).left().map(derivedFrom -> setDerivedFrom(capabilityType, derivedFrom));
400 private Either<CapabilityTypeData, StorageOperationStatus> handleDerivedFromNotExist(StorageOperationStatus err) {
401 if (err == StorageOperationStatus.NOT_FOUND) {
402 return Either.left(null);
404 return Either.right(err);
407 private CapabilityTypeData setDerivedFrom(CapabilityTypeDefinition capabilityTypeDefinition, CapabilityTypeData derivedFrom) {
408 if (derivedFrom != null) {
409 capabilityTypeDefinition.setDerivedFrom(derivedFrom.getCapabilityTypeDataDefinition().getType());
414 private Either<CapabilityTypeDefinition, JanusGraphOperationStatus> getAndAddPropertiesANdDerivedFrom(String uniqueId,
415 Map<String, CapabilityTypeDefinition> capabilityTypeDefinitionMap) {
416 if (capabilityTypeDefinitionMap.containsKey(uniqueId)) {
417 return Either.left(capabilityTypeDefinitionMap.get(uniqueId));
419 Either<CapabilityTypeData, JanusGraphOperationStatus> capabilityTypesRes = janusGraphGenericDao
420 .getNode(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.CapabilityType), uniqueId, CapabilityTypeData.class);
421 if (capabilityTypesRes.isRight()) {
422 JanusGraphOperationStatus status = capabilityTypesRes.right().value();
423 log.debug(DATA_TYPE_CANNOT_BE_FOUND_IN_GRAPH_STATUS_IS, uniqueId, status);
424 return Either.right(status);
426 CapabilityTypeData ctData = capabilityTypesRes.left().value();
427 CapabilityTypeDefinition capabilityTypeDefinition = new CapabilityTypeDefinition(ctData.getCapabilityTypeDataDefinition());
428 Either<Map<String, PropertyDefinition>, JanusGraphOperationStatus> propertiesStatus = OperationUtils
429 .fillProperties(uniqueId, propertyOperation, NodeTypeEnum.CapabilityType);
430 if (propertiesStatus.isRight() && propertiesStatus.right().value() != JanusGraphOperationStatus.OK) {
431 log.error(FAILED_TO_FETCH_PROPERTIES_OF_DATA_TYPE, uniqueId);
432 return Either.right(propertiesStatus.right().value());
434 if (propertiesStatus.isLeft()) {
435 capabilityTypeDefinition.setProperties(propertiesStatus.left().value());
437 fillDerivedFrom(uniqueId, capabilityTypeDefinition);
438 capabilityTypeDefinitionMap.put(capabilityTypeDefinition.getType(), capabilityTypeDefinition);
439 return Either.left(capabilityTypeDefinition);