[SDC] rebase 1710 code
[sdc.git] / catalog-model / src / main / java / org / openecomp / sdc / be / model / operations / impl / GroupTypeOperation.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
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
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
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=========================================================
19  */
20
21 package org.openecomp.sdc.be.model.operations.impl;
22
23 import java.util.HashMap;
24 import java.util.HashSet;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Set;
28
29 import org.apache.commons.lang3.tuple.ImmutablePair;
30 import org.openecomp.sdc.be.config.BeEcompErrorManager;
31 import org.openecomp.sdc.be.dao.graph.datatype.GraphEdge;
32 import org.openecomp.sdc.be.dao.neo4j.GraphEdgeLabels;
33 import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary;
34 import org.openecomp.sdc.be.dao.titan.TitanGenericDao;
35 import org.openecomp.sdc.be.dao.titan.TitanOperationStatus;
36 import org.openecomp.sdc.be.datatypes.elements.GroupTypeDataDefinition;
37 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
38 import org.openecomp.sdc.be.model.CapabilityTypeDefinition;
39 import org.openecomp.sdc.be.model.GroupTypeDefinition;
40 import org.openecomp.sdc.be.model.PropertyDefinition;
41 import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation;
42 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
43 import org.openecomp.sdc.be.resources.data.CapabilityTypeData;
44 import org.openecomp.sdc.be.resources.data.GroupTypeData;
45 import org.openecomp.sdc.be.resources.data.PropertyData;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48 import org.springframework.beans.factory.annotation.Qualifier;
49 import org.springframework.stereotype.Component;
50
51 import fj.data.Either;
52
53 @Component("group-type-operation")
54 public class GroupTypeOperation extends AbstractOperation implements IGroupTypeOperation {
55
56         String CREATE_FLOW_CONTEXT = "CreateGroupType";
57         String GET_FLOW_CONTEXT = "GetGroupType";
58
59         private PropertyOperation propertyOperation;
60         
61         private TitanGenericDao titanGenericDao;
62
63         public GroupTypeOperation(@Qualifier("titan-generic-dao") TitanGenericDao titanGenericDao, @Qualifier("property-operation")PropertyOperation propertyOperation) {
64                 super();
65                 this.propertyOperation = propertyOperation;
66                 this.titanGenericDao = titanGenericDao;
67         }
68
69         private static Logger log = LoggerFactory.getLogger(GroupTypeOperation.class.getName());
70
71         /**
72          * FOR TEST ONLY
73          * 
74          * @param titanGenericDao
75          */
76         public void setTitanGenericDao(TitanGenericDao titanGenericDao) {
77                 this.titanGenericDao = titanGenericDao;
78         }
79
80         @Override
81         public Either<GroupTypeDefinition, StorageOperationStatus> addGroupType(GroupTypeDefinition groupTypeDefinition) {
82
83                 return addGroupType(groupTypeDefinition, false);
84         }
85
86         @Override
87         public Either<GroupTypeDefinition, StorageOperationStatus> addGroupType(GroupTypeDefinition groupTypeDefinition, boolean inTransaction) {
88
89                 Either<GroupTypeDefinition, StorageOperationStatus> result = null;
90
91                 try {
92
93                         Either<GroupTypeData, TitanOperationStatus> eitherStatus = addGroupTypeToGraph(groupTypeDefinition);
94
95                         if (eitherStatus.isRight()) {
96                                 BeEcompErrorManager.getInstance().logBeFailedCreateNodeError(CREATE_FLOW_CONTEXT, groupTypeDefinition.getType(), eitherStatus.right().value().name());
97                                 result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(eitherStatus.right().value()));
98
99                         } else {
100                                 GroupTypeData groupTypeData = eitherStatus.left().value();
101
102                                 String uniqueId = groupTypeData.getUniqueId();
103                                 Either<GroupTypeDefinition, StorageOperationStatus> groupTypeRes = this.getGroupType(uniqueId, true);
104
105                                 if (groupTypeRes.isRight()) {
106                                         BeEcompErrorManager.getInstance().logBeFailedRetrieveNodeError(GET_FLOW_CONTEXT, groupTypeDefinition.getType(), eitherStatus.right().value().name());
107                                 }
108
109                                 result = groupTypeRes;
110
111                         }
112
113                         return result;
114
115                 } finally {
116                         handleTransactionCommitRollback(inTransaction, result);
117                 }
118
119         }
120
121         public Either<GroupTypeDefinition, TitanOperationStatus> getGroupTypeByUid(String uniqueId) {
122
123                 Either<GroupTypeDefinition, TitanOperationStatus> result = null;
124
125                 Either<GroupTypeData, TitanOperationStatus> groupTypesRes = titanGenericDao.getNode(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.GroupType), uniqueId, GroupTypeData.class);
126
127                 if (groupTypesRes.isRight()) {
128                         TitanOperationStatus status = groupTypesRes.right().value();
129                         log.debug("Group type {} cannot be found in graph. status is {}", uniqueId, status);
130                         return Either.right(status);
131                 }
132
133                 GroupTypeData gtData = groupTypesRes.left().value();
134                 GroupTypeDefinition groupTypeDefinition = new GroupTypeDefinition(gtData.getGroupTypeDataDefinition());
135
136                 TitanOperationStatus propertiesStatus = propertyOperation.fillProperties(uniqueId, properList -> groupTypeDefinition.setProperties(properList));
137
138                 if (propertiesStatus != TitanOperationStatus.OK) {
139                         log.error("Failed to fetch properties of capability type {}", uniqueId);
140                         return Either.right(propertiesStatus);
141                 }
142
143                 result = Either.left(groupTypeDefinition);
144
145                 return result;
146         }
147
148         @Override
149         public Either<GroupTypeDefinition, StorageOperationStatus> getGroupType(String uniqueId) {
150
151                 return getGroupType(uniqueId, false);
152
153         }
154
155         @Override
156         public Either<GroupTypeDefinition, StorageOperationStatus> getGroupType(String uniqueId, boolean inTransaction) {
157                 return getElementType(this::getGroupTypeByUid, uniqueId, inTransaction);
158         }
159
160         @Override
161         public Either<GroupTypeDefinition, StorageOperationStatus> getLatestGroupTypeByType(String type) {
162                 return getLatestGroupTypeByType(type, false);
163         }
164
165         @Override
166         public Either<GroupTypeDefinition, StorageOperationStatus> getLatestGroupTypeByType(String type, boolean inTransaction) {
167                 Map<String, Object> mapCriteria = new HashMap<>();
168                 mapCriteria.put(GraphPropertiesDictionary.TYPE.getProperty(), type);
169                 mapCriteria.put(GraphPropertiesDictionary.IS_HIGHEST_VERSION.getProperty(), true);
170
171                 return getGroupTypeByCriteria(type, mapCriteria, inTransaction);
172
173         }
174
175         public Either<GroupTypeDefinition, StorageOperationStatus> getGroupTypeByCriteria(String type, Map<String, Object> properties, boolean inTransaction) {
176                 Either<GroupTypeDefinition, StorageOperationStatus> result = null;
177                 try {
178                         if (type == null || type.isEmpty()) {
179                                 log.error("type is empty");
180                                 result = Either.right(StorageOperationStatus.INVALID_ID);
181                                 return result;
182                         }
183
184                         Either<List<GroupTypeData>, TitanOperationStatus> groupTypeEither = titanGenericDao.getByCriteria(NodeTypeEnum.GroupType, properties, GroupTypeData.class);
185                         if (groupTypeEither.isRight()) {
186                                 result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(groupTypeEither.right().value()));
187                         } else {
188                                 GroupTypeDataDefinition dataDefinition = groupTypeEither.left().value().stream().map(e -> e.getGroupTypeDataDefinition()).findFirst().get();
189                                 result = getGroupType(dataDefinition.getUniqueId(), inTransaction);
190                         }
191
192                         return result;
193
194                 } finally {
195                         handleTransactionCommitRollback(inTransaction, result);
196                 }
197         }
198
199         @Override
200         public Either<GroupTypeDefinition, StorageOperationStatus> getGroupTypeByTypeAndVersion(String type, String version) {
201                 return getGroupTypeByTypeAndVersion(type, version, false);
202         }
203
204         @Override
205         public Either<GroupTypeDefinition, StorageOperationStatus> getGroupTypeByTypeAndVersion(String type, String version, boolean inTransaction) {
206                 Map<String, Object> mapCriteria = new HashMap<>();
207                 mapCriteria.put(GraphPropertiesDictionary.TYPE.getProperty(), type);
208                 mapCriteria.put(GraphPropertiesDictionary.VERSION.getProperty(), version);
209
210                 return getGroupTypeByCriteria(type, mapCriteria, inTransaction);
211         }
212
213         /**
214          * 
215          * Add group type to graph.
216          * 
217          * 1. Add group type node
218          * 
219          * 2. Add edge between the former node to its parent(if exists)
220          * 
221          * 3. Add property node and associate it to the node created at #1. (per property & if exists)
222          * 
223          * @param groupTypeDefinition
224          * @return
225          */
226         private Either<GroupTypeData, TitanOperationStatus> addGroupTypeToGraph(GroupTypeDefinition groupTypeDefinition) {
227
228                 log.debug("Got group type {}", groupTypeDefinition);
229
230                 String ctUniqueId = UniqueIdBuilder.buildGroupTypeUid(groupTypeDefinition.getType(), groupTypeDefinition.getVersion());
231                 // capabilityTypeDefinition.setUniqueId(ctUniqueId);
232
233                 GroupTypeData groupTypeData = buildGroupTypeData(groupTypeDefinition, ctUniqueId);
234
235                 log.debug("Before adding group type to graph. groupTypeData = {}", groupTypeData);
236
237                 Either<GroupTypeData, TitanOperationStatus> createGTResult = titanGenericDao.createNode(groupTypeData, GroupTypeData.class);
238                 log.debug("After adding group type to graph. status is = {}", createGTResult);
239
240                 if (createGTResult.isRight()) {
241                         TitanOperationStatus operationStatus = createGTResult.right().value();
242                         log.error("Failed to add group type {} to graph. status is {}", groupTypeDefinition.getType(), operationStatus);
243                         return Either.right(operationStatus);
244                 }
245
246                 GroupTypeData resultCTD = createGTResult.left().value();
247                 List<PropertyDefinition> properties = groupTypeDefinition.getProperties();
248                 Either<Map<String, PropertyData>, TitanOperationStatus> addPropertiesToCapablityType = propertyOperation.addPropertiesToElementType(resultCTD.getUniqueId(), NodeTypeEnum.GroupType, properties);
249                 if (addPropertiesToCapablityType.isRight()) {
250                         log.error("Failed add properties {} to capability {}", properties, groupTypeDefinition.getType());
251                         return Either.right(addPropertiesToCapablityType.right().value());
252                 }
253
254                 String derivedFrom = groupTypeDefinition.getDerivedFrom();
255                 if (derivedFrom != null) {
256
257                         // TODO: Need to find the parent. need to take the latest one since
258                         // we may have many versions of the same type
259                         /*
260                          * log.debug("Before creating relation between group type {} to its parent {}", ctUniqueId, derivedFrom); UniqueIdData from = new UniqueIdData(NodeTypeEnum.CapabilityType, ctUniqueId); UniqueIdData to = new
261                          * UniqueIdData(NodeTypeEnum.CapabilityType, derivedFrom); Either<GraphRelation, TitanOperationStatus> createRelation = titanGenericDao .createRelation(from, to, GraphEdgeLabels.DERIVED_FROM, null);
262                          * log.debug("After create relation between capability type {} to its parent {}. status is {}", ctUniqueId, derivedFrom, createRelation); if (createRelation.isRight()) { return Either.right(createRelation.right().value()); }
263                          * 
264                          */
265                 }
266
267                 return Either.left(createGTResult.left().value());
268
269         }
270
271         /**
272          * 
273          * convert between graph Node object to Java object
274          * 
275          * @param capabilityTypeData
276          * @return
277          */
278         protected CapabilityTypeDefinition convertCTDataToCTDefinition(CapabilityTypeData capabilityTypeData) {
279                 log.debug("The object returned after create capability is {}", capabilityTypeData);
280
281                 CapabilityTypeDefinition capabilityTypeDefResult = new CapabilityTypeDefinition(capabilityTypeData.getCapabilityTypeDataDefinition());
282
283                 return capabilityTypeDefResult;
284         }
285
286         private GroupTypeData buildGroupTypeData(GroupTypeDefinition groupTypeDefinition, String ctUniqueId) {
287
288                 GroupTypeData groupTypeData = new GroupTypeData(groupTypeDefinition);
289
290                 groupTypeData.getGroupTypeDataDefinition().setUniqueId(ctUniqueId);
291                 Long creationDate = groupTypeData.getGroupTypeDataDefinition().getCreationTime();
292                 if (creationDate == null) {
293                         creationDate = System.currentTimeMillis();
294                 }
295                 groupTypeData.getGroupTypeDataDefinition().setCreationTime(creationDate);
296                 groupTypeData.getGroupTypeDataDefinition().setModificationTime(creationDate);
297
298                 return groupTypeData;
299         }
300
301         public Either<Boolean, StorageOperationStatus> isCapabilityTypeDerivedFrom(String childCandidateType, String parentCandidateType) {
302                 Map<String, Object> propertiesToMatch = new HashMap<String, Object>();
303                 propertiesToMatch.put(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.CapabilityType), childCandidateType);
304                 Either<List<CapabilityTypeData>, TitanOperationStatus> getResponse = titanGenericDao.getByCriteria(NodeTypeEnum.CapabilityType, propertiesToMatch, CapabilityTypeData.class);
305                 if (getResponse.isRight()) {
306                         TitanOperationStatus titanOperationStatus = getResponse.right().value();
307                         log.debug("Couldn't fetch capability type {}, error: {}", childCandidateType, titanOperationStatus);
308                         return Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(titanOperationStatus));
309                 }
310                 String childUniqueId = getResponse.left().value().get(0).getUniqueId();
311                 Set<String> travelledTypes = new HashSet<>();
312                 do {
313                         travelledTypes.add(childUniqueId);
314                         Either<List<ImmutablePair<CapabilityTypeData, GraphEdge>>, TitanOperationStatus> childrenNodes = titanGenericDao.getChildrenNodes(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.CapabilityType), childUniqueId, GraphEdgeLabels.DERIVED_FROM,
315                                         NodeTypeEnum.CapabilityType, CapabilityTypeData.class);
316                         if (childrenNodes.isRight()) {
317                                 if (childrenNodes.right().value() != TitanOperationStatus.NOT_FOUND) {
318                                         TitanOperationStatus titanOperationStatus = getResponse.right().value();
319                                         log.debug("Couldn't fetch derived from node for capability type {}, error: {}", childCandidateType, titanOperationStatus);
320                                         return Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(titanOperationStatus));
321                                 } else {
322                                         log.debug("Derived from node is not found for type {} - this is OK for root capability.");
323                                         return Either.left(false);
324                                 }
325                         }
326                         String derivedFromUniqueId = childrenNodes.left().value().get(0).getLeft().getUniqueId();
327                         if (derivedFromUniqueId.equals(parentCandidateType)) {
328                                 log.debug("Verified that capability type {} derives from capability type {}", childCandidateType, parentCandidateType);
329                                 return Either.left(true);
330                         }
331                         childUniqueId = derivedFromUniqueId;
332                 } while (!travelledTypes.contains(childUniqueId));
333                 // this stop condition should never be used, if we use it, we have an
334                 // illegal cycle in graph - "derived from" hierarchy cannot be cycled.
335                 // It's here just to avoid infinite loop in case we have such cycle.
336                 log.error("Detected a cycle of \"derived from\" edges starting at capability type node {}", childUniqueId);
337                 return Either.right(StorageOperationStatus.GENERAL_ERROR);
338         }
339
340         /**
341          * FOR TEST ONLY
342          * 
343          * @param propertyOperation
344          */
345         public void setPropertyOperation(PropertyOperation propertyOperation) {
346                 this.propertyOperation = propertyOperation;
347         }
348
349         @Override
350         public Either<GroupTypeData, TitanOperationStatus> getLatestGroupTypeByNameFromGraph(String name) {
351
352                 return null;
353         }
354
355 }