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