Sync Integ to Master
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / components / impl / ElementBusinessLogic.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.components.impl;
22
23 import fj.data.Either;
24 import org.apache.commons.lang3.tuple.ImmutablePair;
25 import org.apache.http.NameValuePair;
26 import org.apache.http.client.utils.URLEncodedUtils;
27 import org.openecomp.sdc.be.dao.api.ActionStatus;
28 import org.openecomp.sdc.be.dao.graph.datatype.GraphEdge;
29 import org.openecomp.sdc.be.dao.graph.datatype.GraphNode;
30 import org.openecomp.sdc.be.dao.jsongraph.types.JsonParseFlagEnum;
31 import org.openecomp.sdc.be.dao.neo4j.GraphEdgeLabels;
32 import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary;
33 import org.openecomp.sdc.be.dao.titan.TitanOperationStatus;
34 import org.openecomp.sdc.be.datamodel.api.CategoryTypeEnum;
35 import org.openecomp.sdc.be.datamodel.utils.NodeTypeConvertUtils;
36 import org.openecomp.sdc.be.datatypes.components.ComponentMetadataDataDefinition;
37 import org.openecomp.sdc.be.datatypes.components.ResourceMetadataDataDefinition;
38 import org.openecomp.sdc.be.datatypes.enums.AssetTypeEnum;
39 import org.openecomp.sdc.be.datatypes.enums.ComponentFieldsEnum;
40 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
41 import org.openecomp.sdc.be.datatypes.enums.FilterKeyEnum;
42 import org.openecomp.sdc.be.datatypes.enums.GraphPropertyEnum;
43 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
44 import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
45 import org.openecomp.sdc.be.impl.ComponentsUtils;
46 import org.openecomp.sdc.be.model.ArtifactType;
47 import org.openecomp.sdc.be.model.Component;
48 import org.openecomp.sdc.be.model.ComponentParametersView;
49 import org.openecomp.sdc.be.model.DistributionStatusEnum;
50 import org.openecomp.sdc.be.model.LifecycleStateEnum;
51 import org.openecomp.sdc.be.model.Product;
52 import org.openecomp.sdc.be.model.PropertyScope;
53 import org.openecomp.sdc.be.model.Resource;
54 import org.openecomp.sdc.be.model.Service;
55 import org.openecomp.sdc.be.model.Tag;
56 import org.openecomp.sdc.be.model.User;
57 import org.openecomp.sdc.be.model.catalog.CatalogComponent;
58 import org.openecomp.sdc.be.model.category.CategoryDefinition;
59 import org.openecomp.sdc.be.model.category.GroupingDefinition;
60 import org.openecomp.sdc.be.model.category.SubCategoryDefinition;
61 import org.openecomp.sdc.be.model.operations.api.IElementOperation;
62 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
63 import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter;
64 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
65 import org.openecomp.sdc.be.resources.data.ComponentMetadataData;
66 import org.openecomp.sdc.be.resources.data.ResourceMetadataData;
67 import org.openecomp.sdc.be.resources.data.ServiceMetadataData;
68 import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
69 import org.openecomp.sdc.be.resources.data.category.CategoryData;
70 import org.openecomp.sdc.be.resources.data.category.SubCategoryData;
71 import org.openecomp.sdc.be.ui.model.UiCategories;
72 import org.openecomp.sdc.be.user.Role;
73 import org.openecomp.sdc.be.user.UserBusinessLogic;
74 import org.openecomp.sdc.common.datastructure.Wrapper;
75 import org.openecomp.sdc.common.util.ValidationUtils;
76 import org.openecomp.sdc.exception.ResponseFormat;
77 import org.slf4j.Logger;
78 import org.slf4j.LoggerFactory;
79
80 import java.nio.charset.StandardCharsets;
81 import java.util.ArrayList;
82 import java.util.Arrays;
83 import java.util.EnumMap;
84 import java.util.HashMap;
85 import java.util.HashSet;
86 import java.util.LinkedList;
87 import java.util.List;
88 import java.util.Map;
89 import java.util.Optional;
90 import java.util.Set;
91 import java.util.function.Predicate;
92 import java.util.stream.Collectors;
93
94 @org.springframework.stereotype.Component("elementsBusinessLogic")
95 public class ElementBusinessLogic extends BaseBusinessLogic {
96
97     private static final Logger log = LoggerFactory.getLogger(ElementBusinessLogic.class);
98
99     @javax.annotation.Resource
100     private IElementOperation elementOperation;
101
102     @javax.annotation.Resource
103     private ComponentsUtils componentsUtils;
104
105     @javax.annotation.Resource
106     private UserBusinessLogic userAdminManager;
107
108     /**
109      *
110      * @param user
111      * @return
112      */
113     public Either<Map<String, List<? extends Component>>, ResponseFormat> getFollowed(User user) {
114         // Used for not getting duplicated followed. Cheaper than checking ArrayList.contains
115         Either<Map<String, Set<? extends Component>>, ResponseFormat> response = null;
116         // Getting the role
117         String role = user.getRole();
118         String userId = null;
119         Role currentRole = Role.valueOf(role);
120
121         switch (currentRole) {
122         case DESIGNER:
123             userId = user.getUserId();
124             response = handleDesigner(userId);
125             break;
126
127         case TESTER:
128             userId = user.getUserId();
129             response = handleTester(userId);
130             break;
131
132         case GOVERNOR:
133             userId = user.getUserId();
134             response = handleGovernor(userId);
135             break;
136
137         case OPS:
138             userId = user.getUserId();
139             response = handleOps(userId);
140             break;
141
142         case PRODUCT_STRATEGIST:
143             userId = user.getUserId();
144             response = handleProductStrategist(userId);
145             break;
146
147         case PRODUCT_MANAGER:
148             userId = user.getUserId();
149             response = handleProductManager(userId);
150             break;
151
152         case ADMIN:
153             response = handleAdmin();
154             break;
155
156         default:
157             response = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
158             break;
159         }
160         // converting the Set to List so the rest of the code will handle it normally (Was changed because the same element with the same uuid was returned twice)
161         return convertedToListResponse(response);
162
163     }
164
165     private Either<Map<String, List<? extends Component>>, ResponseFormat> convertedToListResponse(Either<Map<String, Set<? extends Component>>, ResponseFormat> setResponse) {
166
167         Map<String, List<? extends Component>> arrayResponse = new HashMap<>();
168         if (setResponse.isLeft()) {
169             for (Map.Entry<String, Set<? extends Component>> entry : setResponse.left().value().entrySet()) {
170                 arrayResponse.put(entry.getKey(), new ArrayList(new HashSet(entry.getValue())));
171             }
172             return Either.left(arrayResponse);
173         }
174         return Either.right(setResponse.right().value());
175     }
176
177     private Either<Map<String, Set<? extends Component>>, ResponseFormat> handleAdmin() {
178         Either<Map<String, Set<? extends Component>>, ResponseFormat> response;
179         // userId should stay null
180         Set<LifecycleStateEnum> lifecycleStates = new HashSet<LifecycleStateEnum>();
181         Set<LifecycleStateEnum> lastStateStates = new HashSet<LifecycleStateEnum>();
182         lifecycleStates.add(LifecycleStateEnum.CERTIFIED);
183         response = getFollowedResourcesAndServices(null, lifecycleStates, lastStateStates);
184         return response;
185     }
186
187     private Either<Map<String, Set<? extends Component>>, ResponseFormat> handleDesigner(String userId) {
188         Set<LifecycleStateEnum> lifecycleStates = new HashSet<LifecycleStateEnum>();
189         Set<LifecycleStateEnum> lastStateStates = new HashSet<LifecycleStateEnum>();
190         Either<Map<String, Set<? extends Component>>, ResponseFormat> response;
191         lifecycleStates.add(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN);
192         lifecycleStates.add(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT);
193         lifecycleStates.add(LifecycleStateEnum.READY_FOR_CERTIFICATION);
194         lifecycleStates.add(LifecycleStateEnum.CERTIFICATION_IN_PROGRESS);
195         lifecycleStates.add(LifecycleStateEnum.CERTIFIED);
196         // more states
197         lastStateStates.add(LifecycleStateEnum.READY_FOR_CERTIFICATION);
198         response = getFollowedResourcesAndServices(userId, lifecycleStates, lastStateStates);
199         return response;
200     }
201
202     private Either<Map<String, Set<? extends Component>>, ResponseFormat> handleGovernor(String userId) {
203         Either<Map<String, Set<? extends Component>>, ResponseFormat> result = handleFollowedCertifiedServices(null);
204         return result;
205     }
206
207     private Either<Map<String, Set<? extends Component>>, ResponseFormat> handleProductStrategist(String userId) {
208         // Should be empty list according to Ella, 13/03/16
209         Map<String, Set<? extends Component>> result = new HashMap<String, Set<? extends Component>>();
210         result.put("products", new HashSet<>());
211         return Either.left(result);
212     }
213
214     private Either<Map<String, Set<? extends Component>>, ResponseFormat> handleProductManager(String userId) {
215         Set<LifecycleStateEnum> lifecycleStates = new HashSet<LifecycleStateEnum>();
216         Set<LifecycleStateEnum> lastStateStates = new HashSet<LifecycleStateEnum>();
217         Either<Map<String, Set<? extends Component>>, ResponseFormat> response;
218         lifecycleStates.add(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN);
219         lifecycleStates.add(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT);
220         lifecycleStates.add(LifecycleStateEnum.READY_FOR_CERTIFICATION);
221         lifecycleStates.add(LifecycleStateEnum.CERTIFICATION_IN_PROGRESS);
222         lifecycleStates.add(LifecycleStateEnum.CERTIFIED);
223         // more states
224         lastStateStates.add(LifecycleStateEnum.READY_FOR_CERTIFICATION);
225         response = getFollowedProducts(userId, lifecycleStates, lastStateStates);
226         return response;
227     }
228
229     private Either<Map<String, Set<? extends Component>>, ResponseFormat> handleOps(String userId) {
230         Set<DistributionStatusEnum> distStatus = new HashSet<DistributionStatusEnum>();
231         distStatus.add(DistributionStatusEnum.DISTRIBUTION_APPROVED);
232         distStatus.add(DistributionStatusEnum.DISTRIBUTED);
233
234         Either<Map<String, Set<? extends Component>>, ResponseFormat> result = handleFollowedCertifiedServices(distStatus);
235         return result;
236     }
237
238     private Either<Map<String, Set<? extends Component>>, ResponseFormat> handleFollowedCertifiedServices(Set<DistributionStatusEnum> distStatus) {
239
240         Either<List<Service>, StorageOperationStatus> services = toscaOperationFacade.getCertifiedServicesWithDistStatus(distStatus);
241         if (services.isLeft()) {
242             Map<String, Set<? extends Component>> result = new HashMap<>();
243             Set<Service> set = new HashSet<>();
244             set.addAll(services.left().value());
245             result.put("services", set);
246             return Either.left(result);
247         } else {
248             return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(services.right().value())));
249         }
250     }
251
252     private Either<Map<String, Set<? extends Component>>, ResponseFormat> handleTester(String userId) {
253         Set<LifecycleStateEnum> lifecycleStates = new HashSet<LifecycleStateEnum>();
254         lifecycleStates.add(LifecycleStateEnum.CERTIFICATION_IN_PROGRESS);
255         lifecycleStates.add(LifecycleStateEnum.READY_FOR_CERTIFICATION);
256         Either<Map<String, Set<? extends Component>>, ResponseFormat> result = getFollowedResourcesAndServices(null, lifecycleStates, null);
257
258         return result;
259     }
260
261     private Either<Map<String, Set<? extends Component>>, ResponseFormat> getFollowedResourcesAndServices(String userId, Set<LifecycleStateEnum> lifecycleStates, Set<LifecycleStateEnum> lastStateStates) {
262
263         try {
264             Either<Set<Resource>, StorageOperationStatus> resources = toscaOperationFacade.getFollowed(userId, lifecycleStates, lastStateStates, ComponentTypeEnum.RESOURCE);
265
266             if (resources.isLeft()) {
267                 Either<Set<Service>, StorageOperationStatus> services = toscaOperationFacade.getFollowed(userId, lifecycleStates, lastStateStates, ComponentTypeEnum.SERVICE);
268                 if (services.isLeft()) {
269                     Map<String, Set<? extends Component>> result = new HashMap<String, Set<? extends Component>>();
270                     result.put("services", services.left().value());
271                     result.put("resources", resources.left().value());
272                     return Either.left(result);
273                 } else {
274                     return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(services.right().value())));
275                 }
276             } else {
277                 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(resources.right().value())));
278             }
279         } finally {
280             titanDao.commit();
281         }
282     }
283
284     private Either<Map<String, Set<? extends Component>>, ResponseFormat> getFollowedProducts(String userId, Set<LifecycleStateEnum> lifecycleStates, Set<LifecycleStateEnum> lastStateStates) {
285         Either<Set<Product>, StorageOperationStatus> products = toscaOperationFacade.getFollowed(userId, lifecycleStates, lastStateStates, ComponentTypeEnum.PRODUCT);
286         if (products.isLeft()) {
287             Map<String, Set<? extends Component>> result = new HashMap<>();
288             result.put("products", products.left().value());
289             return Either.left(result);
290         } else {
291             return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(products.right().value())));
292         }
293     }
294
295     /*
296      * New categories flow - start
297      */
298     public Either<List<CategoryDefinition>, ActionStatus> getAllResourceCategories() {
299         return elementOperation.getAllResourceCategories();
300     }
301
302     public Either<List<CategoryDefinition>, ActionStatus> getAllServiceCategories() {
303         return elementOperation.getAllServiceCategories();
304     }
305
306     public Either<CategoryDefinition, ResponseFormat> createCategory(CategoryDefinition category, String componentTypeParamName, String userId) {
307
308         AuditingActionEnum auditingAction = AuditingActionEnum.ADD_CATEGORY;
309         ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName);
310         String componentType = componentTypeEnum == null ? componentTypeParamName : componentTypeEnum.getValue();
311         CategoryTypeEnum categoryType = CategoryTypeEnum.CATEGORY;
312
313         User user = new User();
314         Either<User, ResponseFormat> validateUser = validateUser(userId);
315         if (validateUser.isRight()) {
316             log.debug("Validation of user failed, userId {}", userId);
317             ResponseFormat responseFormat = validateUser.right().value();
318             user = new User();
319             user.setUserId(userId);
320             String currCategoryName = (category == null ? null : category.getName());
321             handleCategoryAuditing(responseFormat, user, currCategoryName, auditingAction, componentType);
322             return Either.right(responseFormat);
323         }
324
325         user = validateUser.left().value();
326
327         if (category == null) {
328             log.debug("Category json is invalid");
329             ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
330             handleCategoryAuditing(responseFormat, user, null, auditingAction, componentType);
331             return Either.right(responseFormat);
332         }
333
334         String categoryName = category.getName();
335         // For auditing of failures we need the original non-normalized name
336         String origCategoryName = categoryName;
337         if (componentTypeEnum == null) {
338             log.debug("Component type {} is invalid", componentTypeParamName);
339             ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
340             handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
341             return Either.right(responseFormat);
342         }
343
344         Either<Boolean, ResponseFormat> validateUserRole = validateUserRole(user, componentTypeEnum);
345         if (validateUserRole.isRight()) {
346             log.debug("Validation of user role failed, userId {}", userId);
347             ResponseFormat responseFormat = validateUserRole.right().value();
348             handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
349             return Either.right(responseFormat);
350         }
351
352         if (!ValidationUtils.validateCategoryDisplayNameFormat(categoryName)) {
353             log.debug("Category display name format is invalid, name {}, componentType {}", categoryName, componentType);
354             ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, componentType, categoryType.getValue());
355             handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
356             return Either.right(responseFormat);
357         }
358
359         categoryName = ValidationUtils.normalizeCategoryName4Display(categoryName);
360
361         if (!ValidationUtils.validateCategoryDisplayNameLength(categoryName)) {
362             log.debug("Category display name length is invalid, should be from 4 to 25 chars, name {}, componentType {}", categoryName, componentType);
363             ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, componentType, categoryType.getValue());
364             handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
365             return Either.right(responseFormat);
366         }
367
368         category.setName(categoryName);
369
370         String normalizedName = ValidationUtils.normalizeCategoryName4Uniqueness(categoryName);
371         category.setNormalizedName(normalizedName);
372
373         NodeTypeEnum nodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, categoryType);
374
375         Either<Boolean, ActionStatus> categoryUniqueEither = elementOperation.isCategoryUniqueForType(nodeType, normalizedName);
376         if (categoryUniqueEither.isRight()) {
377             log.debug("Failed to check category uniqueness, name {}, componentType {}", categoryName, componentType);
378             ResponseFormat responseFormat = componentsUtils.getResponseFormat(categoryUniqueEither.right().value());
379             handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
380             return Either.right(responseFormat);
381         }
382
383         Boolean isCategoryUnique = categoryUniqueEither.left().value();
384         if (!isCategoryUnique) {
385             log.debug("Category is not unique, name {}, componentType {}", categoryName, componentType);
386             ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_CATEGORY_ALREADY_EXISTS, componentType, categoryName);
387             handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
388             return Either.right(responseFormat);
389         }
390
391         Either<CategoryDefinition, ActionStatus> createCategoryByType = elementOperation.createCategory(category, nodeType);
392         if (createCategoryByType.isRight()) {
393             log.debug("Failed to create category, name {}, componentType {}", categoryName, componentType);
394             ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_CATEGORY_ALREADY_EXISTS, componentType, categoryName);
395             handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
396             return Either.right(componentsUtils.getResponseFormat(createCategoryByType.right().value()));
397         }
398         category = createCategoryByType.left().value();
399         log.debug("Created category for component {}, name {}, uniqueId {}", componentType, categoryName, category.getUniqueId());
400         ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.CREATED);
401         handleCategoryAuditing(responseFormat, user, category.getName(), auditingAction, componentType);
402         return Either.left(category);
403     }
404
405     public Either<SubCategoryDefinition, ResponseFormat> createSubCategory(SubCategoryDefinition subCategory, String componentTypeParamName, String parentCategoryId, String userId) {
406
407         AuditingActionEnum auditingAction = AuditingActionEnum.ADD_SUB_CATEGORY;
408         ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName);
409         String componentType = componentTypeEnum == null ? componentTypeParamName : componentTypeEnum.getValue();
410         CategoryTypeEnum categoryType = CategoryTypeEnum.SUBCATEGORY;
411         // For auditing
412         String parentCategoryName = parentCategoryId;
413
414         if (subCategory == null) {
415             log.debug("Sub-category json is invalid");
416             ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
417             handleCategoryAuditing(responseFormat, null, parentCategoryName, null, auditingAction, componentType);
418             return Either.right(responseFormat);
419         }
420
421         String subCategoryName = subCategory.getName();
422         // For auditing of failures we need the original non-normalized name
423         String origSubCategoryName = subCategoryName;
424
425         User user = new User();
426         Either<User, ResponseFormat> validateUser = validateUserExists(userId, "createSubCategory", false);
427         if (validateUser.isRight()) {
428             log.debug("Validation of user failed, userId {}", userId);
429             ResponseFormat responseFormat = validateUser.right().value();
430             user = new User();
431             user.setUserId(userId);
432             handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
433             return Either.right(responseFormat);
434         }
435
436         user = validateUser.left().value();
437
438         if (componentTypeEnum == null) {
439             log.debug("Component type {} is invalid", componentTypeParamName);
440             ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
441             handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
442             return Either.right(responseFormat);
443         }
444
445         Either<Boolean, ResponseFormat> validateComponentType = validateComponentTypeForCategory(componentTypeEnum, categoryType);
446         if (validateComponentType.isRight()) {
447             log.debug("Validation of component type for sub-category failed");
448             ResponseFormat responseFormat = validateComponentType.right().value();
449             handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
450             return Either.right(responseFormat);
451         }
452
453         Either<Boolean, ResponseFormat> validateUserRole = validateUserRole(user, componentTypeEnum);
454         if (validateUserRole.isRight()) {
455             log.debug("Validation of user role failed, userId {}", userId);
456             ResponseFormat responseFormat = validateUserRole.right().value();
457             handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
458             return Either.right(responseFormat);
459         }
460
461         NodeTypeEnum parentNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.CATEGORY);
462         NodeTypeEnum childNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.SUBCATEGORY);
463
464         CategoryDefinition categoryDefinition;
465         Either<CategoryDefinition, ResponseFormat> validateCategoryExists = validateCategoryExists(parentNodeType, parentCategoryId, componentTypeEnum);
466         if (validateCategoryExists.isRight()) {
467             log.debug("Validation of parent category exists failed, parent categoryId {}", parentCategoryId);
468             ResponseFormat responseFormat = validateCategoryExists.right().value();
469             handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
470             return Either.right(responseFormat);
471         }
472
473         categoryDefinition = validateCategoryExists.left().value();
474         parentCategoryName = categoryDefinition.getName();
475
476         if (!ValidationUtils.validateCategoryDisplayNameFormat(subCategoryName)) {
477             log.debug("Sub-category display name format is invalid, name {}, componentType {}", subCategoryName, componentType);
478             ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, componentType, categoryType.getValue());
479             handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
480             return Either.right(responseFormat);
481         }
482
483         subCategoryName = ValidationUtils.normalizeCategoryName4Display(subCategoryName);
484
485         if (!ValidationUtils.validateCategoryDisplayNameLength(subCategoryName)) {
486             log.debug("Sub-category display name length is invalid, should be from 4 to 25 chars, name {}, componentType {}", subCategoryName, componentType);
487             ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, componentType, categoryType.getValue());
488             handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
489             return Either.right(responseFormat);
490         }
491
492         String normalizedName = ValidationUtils.normalizeCategoryName4Uniqueness(subCategoryName);
493         subCategory.setNormalizedName(normalizedName);
494
495         // Uniqueness under this category
496         Either<Boolean, ActionStatus> subCategoryUniqueForCategory = elementOperation.isSubCategoryUniqueForCategory(childNodeType, normalizedName, parentCategoryId);
497         if (subCategoryUniqueForCategory.isRight()) {
498             log.debug("Failed to check sub-category uniqueness, parent name {}, subcategory norm name {}, componentType {}", parentCategoryName, normalizedName, componentType);
499             ResponseFormat responseFormat = componentsUtils.getResponseFormat(subCategoryUniqueForCategory.right().value());
500             handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
501             return Either.right(responseFormat);
502         }
503
504         Boolean isSubUnique = subCategoryUniqueForCategory.left().value();
505         if (!isSubUnique) {
506             log.debug("Sub-category is not unique for category, parent name {}, subcategory norm name {}, componentType {}", parentCategoryName, normalizedName, componentType);
507             ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_SUB_CATEGORY_EXISTS_FOR_CATEGORY, componentType, subCategoryName, parentCategoryName);
508             handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
509             return Either.right(responseFormat);
510         }
511
512         // Setting name of subcategory to fit the similar subcategory name
513         // ignoring cases.
514         // For example if Network-->kUKU exists for service category Network,
515         // and user is trying to create Router-->Kuku for service category
516         // Router,
517         // his subcategory name will be Router-->kUKU.
518         Either<SubCategoryDefinition, ActionStatus> subCategoryUniqueForType = elementOperation.getSubCategoryUniqueForType(childNodeType, normalizedName);
519         if (subCategoryUniqueForType.isRight()) {
520             log.debug("Failed validation of whether similar sub-category exists, normalizedName {} componentType {}", normalizedName, componentType);
521             ResponseFormat responseFormat = componentsUtils.getResponseFormat(subCategoryUniqueForType.right().value());
522             handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
523             return Either.right(responseFormat);
524         }
525         SubCategoryDefinition subCategoryDefinition = subCategoryUniqueForType.left().value();
526         if (subCategoryDefinition != null) {
527             subCategoryName = subCategoryDefinition.getName();
528         }
529
530         subCategory.setName(subCategoryName);
531         ///////////////////////////////////////////// Validations end
532
533         Either<SubCategoryDefinition, ActionStatus> createSubCategory = elementOperation.createSubCategory(parentCategoryId, subCategory, childNodeType);
534         if (createSubCategory.isRight()) {
535             log.debug("Failed to create sub-category, name {}, componentType {}", subCategoryName, componentType);
536             ResponseFormat responseFormat = componentsUtils.getResponseFormat(subCategoryUniqueForType.right().value());
537             handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
538             return Either.right(responseFormat);
539         }
540
541         SubCategoryDefinition subCategoryCreated = createSubCategory.left().value();
542         log.debug("Created sub-category for component {}, name {}, uniqueId {}", componentType, subCategoryName, subCategoryCreated.getUniqueId());
543         ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.CREATED);
544         handleCategoryAuditing(responseFormat, user, parentCategoryName, subCategoryCreated.getName(), auditingAction, componentType);
545         return Either.left(subCategoryCreated);
546     }
547
548     public Either<GroupingDefinition, ResponseFormat> createGrouping(GroupingDefinition grouping, String componentTypeParamName, String grandParentCategoryId, String parentSubCategoryId, String userId) {
549
550         AuditingActionEnum auditingAction = AuditingActionEnum.ADD_GROUPING;
551         ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName);
552         String componentType = componentTypeEnum == null ? componentTypeParamName : componentTypeEnum.getValue();
553         CategoryTypeEnum categoryType = CategoryTypeEnum.GROUPING;
554         // For auditing
555         String parentCategoryName = grandParentCategoryId;
556         String parentSubCategoryName = parentSubCategoryId;
557
558         User user;
559         Either<User, ResponseFormat> validateUser = validateUserExists(userId, "create Grouping", false);
560         if (validateUser.isRight()) {
561             log.debug("Validation of user failed, userId {}", userId);
562             ResponseFormat responseFormat = validateUser.right().value();
563             user = new User();
564             user.setUserId(userId);
565             String groupingNameForAudit = grouping == null ? null : grouping.getName();
566             handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, groupingNameForAudit, auditingAction, componentType);
567             return Either.right(responseFormat);
568         }
569
570         user = validateUser.left().value();
571
572         if (grouping == null) {
573             log.debug("Grouping json is invalid");
574             ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
575             handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, null, auditingAction, componentType);
576             return Either.right(responseFormat);
577         }
578
579         String groupingName = grouping.getName();
580         // For auditing of failures we need the original non-normalized name
581         String origGroupingName = groupingName;
582
583         if (componentTypeEnum == null) {
584             log.debug("Component type {} is invalid", componentTypeParamName);
585             ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
586             handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
587             return Either.right(responseFormat);
588         }
589
590         Either<Boolean, ResponseFormat> validateComponentType = validateComponentTypeForCategory(componentTypeEnum, categoryType);
591         if (validateComponentType.isRight()) {
592             log.debug("Validation of component type for grouping failed");
593             ResponseFormat responseFormat = validateComponentType.right().value();
594             handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
595             return Either.right(responseFormat);
596         }
597
598         Either<Boolean, ResponseFormat> validateUserRole = validateUserRole(user, componentTypeEnum);
599         if (validateUserRole.isRight()) {
600             log.debug("Validation of user role failed, userId {}", userId);
601             ResponseFormat responseFormat = validateUserRole.right().value();
602             handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
603             return Either.right(responseFormat);
604         }
605
606         NodeTypeEnum grandParentNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.CATEGORY);
607         NodeTypeEnum parentNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.SUBCATEGORY);
608         NodeTypeEnum childNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.GROUPING);
609
610         // Validate category
611         CategoryDefinition categoryDefinition;
612         Either<CategoryDefinition, ResponseFormat> validateCategoryExists = validateCategoryExists(grandParentNodeType, grandParentCategoryId, componentTypeEnum);
613         if (validateCategoryExists.isRight()) {
614             log.debug("Validation of parent category exists failed, parent categoryId {}", grandParentCategoryId);
615             ResponseFormat responseFormat = validateCategoryExists.right().value();
616             handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
617             return Either.right(responseFormat);
618         }
619
620         categoryDefinition = validateCategoryExists.left().value();
621         parentCategoryName = categoryDefinition.getName();
622
623         // Validate subcategory
624         SubCategoryDefinition subCategoryDefinition;
625         Either<SubCategoryDefinition, ResponseFormat> validateSubCategoryExists = validateSubCategoryExists(parentNodeType, parentSubCategoryId, componentTypeEnum);
626         if (validateSubCategoryExists.isRight()) {
627             log.debug("Validation of parent sub-category exists failed, parent sub-category id {}", parentSubCategoryId);
628             ResponseFormat responseFormat = validateSubCategoryExists.right().value();
629             handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
630             return Either.right(responseFormat);
631         }
632
633         subCategoryDefinition = validateSubCategoryExists.left().value();
634         parentSubCategoryName = subCategoryDefinition.getName();
635
636         if (!ValidationUtils.validateCategoryDisplayNameFormat(groupingName)) {
637             log.debug("Sub-category display name format is invalid, name {}, componentType {}", groupingName, componentType);
638             ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, componentType, categoryType.getValue());
639             handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
640             return Either.right(responseFormat);
641         }
642
643         groupingName = ValidationUtils.normalizeCategoryName4Display(groupingName);
644
645         if (!ValidationUtils.validateCategoryDisplayNameLength(groupingName)) {
646             log.debug("Grouping display name length is invalid, should be from 4 to 25 chars, name {}, componentType {}", groupingName, componentType);
647             ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, componentType, categoryType.getValue());
648             handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
649             return Either.right(responseFormat);
650         }
651
652         String normalizedName = ValidationUtils.normalizeCategoryName4Uniqueness(groupingName);
653         grouping.setNormalizedName(normalizedName);
654
655         // Uniqueness under this category
656         Either<Boolean, ActionStatus> groupingUniqueForSubCategory = elementOperation.isGroupingUniqueForSubCategory(childNodeType, normalizedName, parentSubCategoryId);
657         if (groupingUniqueForSubCategory.isRight()) {
658             log.debug("Failed to check grouping uniqueness, parent name {}, grouping norm name {}, componentType {}", parentSubCategoryName, normalizedName, componentType);
659             ResponseFormat responseFormat = componentsUtils.getResponseFormat(groupingUniqueForSubCategory.right().value());
660             handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
661             return Either.right(responseFormat);
662         }
663
664         Boolean isGroupingUnique = groupingUniqueForSubCategory.left().value();
665         if (!isGroupingUnique) {
666             log.debug("Grouping is not unique for sub-category, parent name {}, grouping norm name {}, componentType {}", parentSubCategoryName, normalizedName, componentType);
667             ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_GROUPING_EXISTS_FOR_SUB_CATEGORY, componentType, groupingName, parentSubCategoryName);
668             handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
669             return Either.right(responseFormat);
670         }
671
672         // Setting name of grouping to fit the similar grouping name ignoring
673         // cases.
674         // For example if Network-->kUKU exists for service sub-category
675         // Network, and user is trying to create grouping Router-->Kuku for
676         // service sub-category Router,
677         // his grouping name will be Router-->kUKU.
678         Either<GroupingDefinition, ActionStatus> groupingUniqueForType = elementOperation.getGroupingUniqueForType(childNodeType, normalizedName);
679         if (groupingUniqueForType.isRight()) {
680             log.debug("Failed validation of whether similar grouping exists, normalizedName {} componentType {}", normalizedName, componentType);
681             ResponseFormat responseFormat = componentsUtils.getResponseFormat(groupingUniqueForType.right().value());
682             handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
683             return Either.right(responseFormat);
684         }
685         GroupingDefinition groupingDefinition = groupingUniqueForType.left().value();
686         if (groupingDefinition != null) {
687             groupingName = groupingDefinition.getName();
688         }
689
690         grouping.setName(groupingName);
691         ///////////////////////////////////////////// Validations end
692
693         Either<GroupingDefinition, ActionStatus> createGrouping = elementOperation.createGrouping(parentSubCategoryId, grouping, childNodeType);
694         if (createGrouping.isRight()) {
695             log.debug("Failed to create grouping, name {}, componentType {}", groupingName, componentType);
696             ResponseFormat responseFormat = componentsUtils.getResponseFormat(createGrouping.right().value());
697             handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
698             return Either.right(responseFormat);
699         }
700
701         GroupingDefinition groupingCreated = createGrouping.left().value();
702         log.debug("Created grouping for component {}, name {}, uniqueId {}", componentType, groupingName, groupingCreated.getUniqueId());
703         ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.CREATED);
704         handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, groupingCreated.getName(), auditingAction, componentType);
705         return Either.left(groupingCreated);
706     }
707
708     public Either<List<CategoryDefinition>, ResponseFormat> getAllCategories(String componentType, String userId) {
709         AuditingActionEnum auditingAction = AuditingActionEnum.GET_CATEGORY_HIERARCHY;
710         ResponseFormat responseFormat;
711         User user = new User();
712         if (userId == null) {
713             user.setUserId("UNKNOWN");
714             responseFormat = componentsUtils.getResponseFormat(ActionStatus.MISSING_INFORMATION);
715             componentsUtils.auditGetCategoryHierarchy(auditingAction, user, componentType, responseFormat);
716             return Either.right(responseFormat);
717         }
718
719         Either<User, ResponseFormat> validateUser = validateUserExists(userId, "get All Categories", false);
720         if (validateUser.isRight()) {
721             user.setUserId(userId);
722             log.debug("Validation of user failed, userId {}", userId);
723             responseFormat = validateUser.right().value();
724             componentsUtils.auditGetCategoryHierarchy(auditingAction, user, componentType, responseFormat);
725             return Either.right(responseFormat);
726         }
727         user = validateUser.left().value();
728
729         ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentType);
730         if (componentTypeEnum == null) {
731             log.debug("Cannot create category for component type {}", componentType);
732             responseFormat = componentsUtils.getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, "component type");
733             componentsUtils.auditGetCategoryHierarchy(auditingAction, user, componentType, responseFormat);
734             return Either.right(responseFormat);
735         }
736
737         NodeTypeEnum nodeTypeEnum = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.CATEGORY);
738         Either<List<CategoryDefinition>, ActionStatus> getAllCategoriesByType = elementOperation.getAllCategories(nodeTypeEnum, false);
739         if (getAllCategoriesByType.isRight()) {
740             responseFormat = componentsUtils.getResponseFormat(getAllCategoriesByType.right().value());
741             componentsUtils.auditGetCategoryHierarchy(auditingAction, user, componentType, responseFormat);
742             return Either.right(responseFormat);
743         }
744         List<CategoryDefinition> categories = getAllCategoriesByType.left().value();
745         responseFormat = componentsUtils.getResponseFormat(ActionStatus.OK);
746         componentsUtils.auditGetCategoryHierarchy(auditingAction, user, componentType, responseFormat);
747         return Either.left(categories);
748     }
749
750     public Either<UiCategories, ResponseFormat> getAllCategories(String userId) {
751         AuditingActionEnum auditingAction = AuditingActionEnum.GET_CATEGORY_HIERARCHY;
752         ResponseFormat responseFormat;
753         UiCategories categories = new UiCategories();
754
755         Either<User, ResponseFormat> userResponse = validateUserExists(userId, "get all categories", false);
756
757         if (userResponse.isRight()) {
758             return Either.right(userResponse.right().value());
759         }
760         User user = userResponse.left().value();
761
762         // GET resource categories
763         Either<List<CategoryDefinition>, ActionStatus> getResourceCategoriesByType = elementOperation.getAllCategories(NodeTypeEnum.ResourceNewCategory, false);
764         if (getResourceCategoriesByType.isRight()) {
765             responseFormat = componentsUtils.getResponseFormat(getResourceCategoriesByType.right().value());
766             componentsUtils.auditGetCategoryHierarchy(auditingAction, user, ComponentTypeEnum.RESOURCE.getValue(), responseFormat);
767             return Either.right(responseFormat);
768         }
769         categories.setResourceCategories(getResourceCategoriesByType.left().value());
770
771         // GET service categories
772         Either<List<CategoryDefinition>, ActionStatus> getServiceCategoriesByType = elementOperation.getAllCategories(NodeTypeEnum.ServiceNewCategory, false);
773         if (getServiceCategoriesByType.isRight()) {
774             responseFormat = componentsUtils.getResponseFormat(getServiceCategoriesByType.right().value());
775             componentsUtils.auditGetCategoryHierarchy(auditingAction, user, ComponentTypeEnum.SERVICE.getValue(), responseFormat);
776             return Either.right(responseFormat);
777         }
778         categories.setServiceCategories(getServiceCategoriesByType.left().value());
779
780         // GET product categories
781         Either<List<CategoryDefinition>, ActionStatus> getProductCategoriesByType = elementOperation.getAllCategories(NodeTypeEnum.ProductCategory, false);
782         if (getProductCategoriesByType.isRight()) {
783             responseFormat = componentsUtils.getResponseFormat(getProductCategoriesByType.right().value());
784             componentsUtils.auditGetCategoryHierarchy(auditingAction, user, ComponentTypeEnum.PRODUCT.getValue(), responseFormat);
785             return Either.right(responseFormat);
786         }
787
788         categories.setProductCategories(getProductCategoriesByType.left().value());
789         return Either.left(categories);
790
791     }
792
793     public Either<CategoryDefinition, ResponseFormat> deleteCategory(String categoryId, String componentTypeParamName, String userId) {
794
795         Either<User, ResponseFormat> resp = validateUserExists(userId, "delete Category", false);
796         if (resp.isRight()) {
797             return Either.right(resp.right().value());
798         }
799
800         ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName);
801         if (componentTypeEnum == null) {
802             log.debug("Cannot create category for component type {}", componentTypeParamName);
803             return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
804         }
805
806         NodeTypeEnum nodeTypeEnum = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.CATEGORY);
807
808         Either<CategoryDefinition, ActionStatus> deleteCategoryByType = elementOperation.deleteCategory(nodeTypeEnum, categoryId);
809         if (deleteCategoryByType.isRight()) {
810             // auditing, logging here...
811             return Either.right(componentsUtils.getResponseFormat(deleteCategoryByType.right().value()));
812         }
813         CategoryDefinition category = deleteCategoryByType.left().value();
814         log.debug("Delete category for component {}, name {}, uniqueId {}", nodeTypeEnum, category.getName(), category.getUniqueId());
815         return Either.left(category);
816     }
817
818     public Either<SubCategoryDefinition, ResponseFormat> deleteSubCategory(String grandParentCategoryId, String parentSubCategoryId, String componentTypeParamName, String userId) {
819
820         Either<User, ResponseFormat> resp = validateUserExists(userId, "delete Sub Category", false);
821         if (resp.isRight()) {
822             return Either.right(resp.right().value());
823         }
824
825         ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName);
826         if (componentTypeEnum == null) {
827             log.debug("Cannot delete sub-category for component type {}", componentTypeParamName);
828             return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
829         }
830
831         NodeTypeEnum nodeTypeEnum = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.SUBCATEGORY);
832
833         Either<SubCategoryDefinition, ActionStatus> deleteSubCategoryByType = elementOperation.deleteSubCategory(nodeTypeEnum, parentSubCategoryId);
834         if (deleteSubCategoryByType.isRight()) {
835             // auditing, logging here...
836             return Either.right(componentsUtils.getResponseFormat(deleteSubCategoryByType.right().value()));
837         }
838         SubCategoryDefinition subCategory = deleteSubCategoryByType.left().value();
839         log.debug("Deleted sub-category for component {}, name {}, uniqueId {}", nodeTypeEnum, subCategory.getName(), subCategory.getUniqueId());
840         return Either.left(subCategory);
841     }
842
843     public Either<GroupingDefinition, ResponseFormat> deleteGrouping(String grandParentCategoryId, String parentSubCategoryId, String groupingId, String componentTypeParamName, String userId) {
844
845         Either<User, ResponseFormat> resp = validateUserExists(userId, "delete Grouping", false);
846         if (resp.isRight()) {
847             return Either.right(resp.right().value());
848         }
849
850         ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName);
851         if (componentTypeEnum == null) {
852             log.debug("Cannot delete grouping for component type {}", componentTypeParamName);
853             return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
854         }
855
856         NodeTypeEnum nodeTypeEnum = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.GROUPING);
857
858         Either<GroupingDefinition, ActionStatus> deleteGroupingByType = elementOperation.deleteGrouping(nodeTypeEnum, groupingId);
859         if (deleteGroupingByType.isRight()) {
860             // auditing, logging here...
861             return Either.right(componentsUtils.getResponseFormat(deleteGroupingByType.right().value()));
862         }
863         GroupingDefinition deletedGrouping = deleteGroupingByType.left().value();
864         log.debug("Deleted grouping for component {}, name {}, uniqueId {}", nodeTypeEnum, deletedGrouping.getName(), deletedGrouping.getUniqueId());
865         return Either.left(deletedGrouping);
866     }
867
868     private Either<User, ResponseFormat> validateUser(String userId) {
869
870         // validate user exists
871         if (userId == null) {
872             log.debug("UserId is null");
873             return Either.right(componentsUtils.getResponseFormat(ActionStatus.MISSING_INFORMATION));
874         }
875
876         Either<User, ActionStatus> userResult = userAdminManager.getUser(userId, false);
877         if (userResult.isRight()) {
878             ResponseFormat responseFormat;
879             if (userResult.right().value().equals(ActionStatus.USER_NOT_FOUND)) {
880                 log.debug("Not authorized user, userId = {}", userId);
881                 responseFormat = componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION);
882             } else {
883                 log.debug("Failed to authorize user, userId = {}", userId);
884                 responseFormat = componentsUtils.getResponseFormat(userResult.right().value());
885             }
886
887             return Either.right(responseFormat);
888         }
889         return Either.left(userResult.left().value());
890         // ========================================-
891     }
892
893     private Either<Boolean, ResponseFormat> validateUserRole(User user, ComponentTypeEnum componentTypeEnum) {
894         String role = user.getRole();
895         boolean validAdminAction = role.equals(Role.ADMIN.name()) && (componentTypeEnum == ComponentTypeEnum.SERVICE || componentTypeEnum == ComponentTypeEnum.RESOURCE);
896         boolean validProductAction = role.equals(Role.PRODUCT_STRATEGIST.name()) && (componentTypeEnum == ComponentTypeEnum.PRODUCT);
897
898         if (!(validAdminAction || validProductAction)) {
899             ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION);
900             log.debug("User not permitted to perform operation on category, userId = {}, role = {}, componentType = {}", user.getUserId(), role, componentTypeEnum);
901             return Either.right(responseFormat);
902         }
903         return Either.left(true);
904     }
905
906     private Either<Boolean, ResponseFormat> validateComponentTypeForCategory(ComponentTypeEnum componentType, CategoryTypeEnum categoryType) {
907         boolean validResourceAction = componentType == ComponentTypeEnum.RESOURCE && (categoryType == CategoryTypeEnum.CATEGORY || categoryType == CategoryTypeEnum.SUBCATEGORY);
908         boolean validServiceAction = componentType == ComponentTypeEnum.SERVICE && categoryType == CategoryTypeEnum.CATEGORY;
909         boolean validProductAction = componentType == ComponentTypeEnum.PRODUCT; // can
910                                                                                  // be
911                                                                                  // any
912                                                                                  // category
913                                                                                  // type
914
915         if (!(validResourceAction || validServiceAction || validProductAction)) {
916             ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
917             log.debug("It's not allowed to create category type {} for component type {}", categoryType, componentType);
918             return Either.right(responseFormat);
919         }
920         return Either.left(true);
921     }
922
923     private Either<CategoryDefinition, ResponseFormat> validateCategoryExists(NodeTypeEnum nodeType, String categoryId, ComponentTypeEnum componentType) {
924         Either<CategoryDefinition, ActionStatus> categoryByTypeAndId = elementOperation.getCategory(nodeType, categoryId);
925         if (categoryByTypeAndId.isRight()) {
926             log.debug("Failed to fetch parent category, parent categoryId {}", categoryId);
927             ActionStatus actionStatus = categoryByTypeAndId.right().value();
928             ResponseFormat responseFormat;
929             if (actionStatus == ActionStatus.COMPONENT_CATEGORY_NOT_FOUND) {
930                 responseFormat = componentsUtils.getResponseFormat(actionStatus, componentType.getValue().toLowerCase(), CategoryTypeEnum.CATEGORY.getValue(), "");
931             } else {
932                 responseFormat = componentsUtils.getResponseFormat(actionStatus);
933             }
934             return Either.right(responseFormat);
935         }
936         return Either.left(categoryByTypeAndId.left().value());
937     }
938
939     private Either<SubCategoryDefinition, ResponseFormat> validateSubCategoryExists(NodeTypeEnum nodeType, String subCategoryId, ComponentTypeEnum componentType) {
940         Either<SubCategoryDefinition, ActionStatus> subCategoryByTypeAndId = elementOperation.getSubCategory(nodeType, subCategoryId);
941         if (subCategoryByTypeAndId.isRight()) {
942             log.debug("Failed to fetch parent category, parent categoryId {}", subCategoryId);
943             ActionStatus actionStatus = subCategoryByTypeAndId.right().value();
944             ResponseFormat responseFormat;
945             if (actionStatus == ActionStatus.COMPONENT_CATEGORY_NOT_FOUND) {
946                 responseFormat = componentsUtils.getResponseFormat(actionStatus, componentType.getValue().toLowerCase(), CategoryTypeEnum.SUBCATEGORY.getValue(), "");
947             } else {
948                 responseFormat = componentsUtils.getResponseFormat(actionStatus);
949             }
950             return Either.right(responseFormat);
951         }
952         return Either.left(subCategoryByTypeAndId.left().value());
953     }
954
955     private void handleCategoryAuditing(ResponseFormat responseFormat, User user, String category, AuditingActionEnum auditingAction, String componentType) {
956         componentsUtils.auditCategory(responseFormat, user, category, null, null, auditingAction, componentType);
957     }
958
959     private void handleCategoryAuditing(ResponseFormat responseFormat, User user, String category, String subCategory, AuditingActionEnum auditingAction, String componentType) {
960         componentsUtils.auditCategory(responseFormat, user, category, subCategory, null, auditingAction, componentType);
961     }
962
963     private void handleCategoryAuditing(ResponseFormat responseFormat, User user, String category, String subCategory, String grouping, AuditingActionEnum auditingAction, String componentType) {
964         componentsUtils.auditCategory(responseFormat, user, category, subCategory, grouping, auditingAction, componentType);
965     }
966
967     /*
968      * New categories flow - end
969      */
970
971     public Either<List<Tag>, ActionStatus> getAllTags(String userId) {
972         Either<User, ActionStatus> resp = validateUserExistsActionStatus(userId, "get All Tags");
973         if (resp.isRight()) {
974             return Either.right(resp.right().value());
975         }
976         return elementOperation.getAllTags();
977     }
978
979     public Either<List<PropertyScope>, ActionStatus> getAllPropertyScopes(String userId) {
980         Either<User, ActionStatus> resp = validateUserExistsActionStatus(userId, "get All Property Scopes");
981         if (resp.isRight()) {
982             return Either.right(resp.right().value());
983         }
984         return elementOperation.getAllPropertyScopes();
985     }
986
987     public Either<List<ArtifactType>, ActionStatus> getAllArtifactTypes(String userId) {
988         Either<User, ActionStatus> resp = validateUserExistsActionStatus(userId, "get All Artifact Types");
989         if (resp.isRight()) {
990             return Either.right(resp.right().value());
991         }
992         return elementOperation.getAllArtifactTypes();
993     }
994
995     public Either<Map<String, Object>, ActionStatus> getAllDeploymentArtifactTypes() {
996         return elementOperation.getAllDeploymentArtifactTypes();
997     }
998
999     public Either<Integer, ActionStatus> getDefaultHeatTimeout() {
1000         return elementOperation.getDefaultHeatTimeout();
1001     }
1002
1003     public Either<Map<String, List<CatalogComponent>>, ResponseFormat> getCatalogComponents(String userId) {
1004         try {
1005             Either<User, ResponseFormat> resp = validateUserExists(userId, "get Catalog Components", true);
1006             if (resp.isRight()) {
1007                 return Either.right(resp.right().value());
1008             }
1009             return toscaOperationFacade.getCatalogComponents().bimap(this::groupByComponentType, err -> componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(err)));
1010         } finally {
1011             titanDao.commit();
1012         }
1013     }
1014
1015     private Map<String, List<CatalogComponent>> groupByComponentType(List<CatalogComponent> components) {
1016         Map<String, List<CatalogComponent>> map = components.stream().collect(Collectors.groupingBy(cmpt -> cmptTypeToString(cmpt.getComponentType())));
1017
1018         // fixed response for UI!!! UI need to receive always map!
1019         if (map == null) {
1020             map = new HashMap<>();
1021         }
1022         if (map.get("resources") == null) {
1023             map.put("resources", new ArrayList());
1024         }
1025         if (map.get("services") == null) {
1026             map.put("services", new ArrayList());
1027         }
1028         return map;
1029     }
1030
1031     private String cmptTypeToString(ComponentTypeEnum componentTypeEnum) {
1032         switch (componentTypeEnum) {
1033         case RESOURCE:
1034             return "resources";
1035         case SERVICE:
1036             return "services";
1037         default:
1038             throw new IllegalStateException("resources or services only");
1039         }
1040     }
1041
1042     public Either<List<? extends Component>, ResponseFormat> getFilteredCatalogComponents(String assetType, Map<FilterKeyEnum, String> filters, String query) {
1043         ComponentTypeEnum assetTypeEnum = AssetTypeEnum.convertToComponentTypeEnum(assetType);
1044
1045         if (query != null) {
1046             Optional<NameValuePair> invalidFilter = findInvalidFilter(query, assetTypeEnum);
1047             if (invalidFilter.isPresent()) {
1048                 log.debug("getFilteredAssetList: invalid filter key");
1049                 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_FILTER_KEY, invalidFilter.get().getName(), FilterKeyEnum.getValidFiltersByAssetType(assetTypeEnum).toString()));
1050             }
1051         }
1052
1053         if (filters == null || filters.isEmpty()) {
1054             Either<List<Component>, StorageOperationStatus> componentsList = toscaOperationFacade.getCatalogComponents(assetTypeEnum, null, false);
1055             if (componentsList.isRight()) {
1056                 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(componentsList.right().value())));
1057             }
1058             return Either.left(componentsList.left().value());
1059         }
1060
1061         Either<List<Component>, StorageOperationStatus> result = getFilteredComponents(filters, assetTypeEnum, false);
1062
1063         // category hierarchy mismatch or category/subCategory/distributionStatus not found
1064         if (result.isRight()) {
1065             List<String> params = getErrorResponseParams(filters, assetTypeEnum);
1066             return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(result.right().value()), params.get(0), params.get(1), params.get(2)));
1067         }
1068         if (result.left().value().isEmpty()) {// no assets found for requested
1069                                               // criteria
1070             return Either.right(componentsUtils.getResponseFormat(ActionStatus.NO_ASSETS_FOUND, assetType, query));
1071         }
1072         return Either.left(result.left().value());
1073     }
1074
1075     private Either<List<Component>, StorageOperationStatus> getFilteredComponents(Map<FilterKeyEnum, String> filters, ComponentTypeEnum assetType, boolean inTransaction) {
1076         Either<List<Component>, StorageOperationStatus> assetResult = Either.left(new LinkedList<>());
1077         if (assetType == ComponentTypeEnum.RESOURCE) {
1078
1079             assetResult = getFilteredResouces(filters, inTransaction);
1080
1081         } else if (assetType == ComponentTypeEnum.SERVICE) {
1082
1083             assetResult = getFilteredServices(filters, inTransaction);
1084         }
1085         return assetResult;
1086     }
1087
1088     private <T> Either<List<T>, StorageOperationStatus> getFilteredServices(Map<FilterKeyEnum, String> filters, boolean inTransaction) {
1089
1090         Either<List<T>, StorageOperationStatus> components = null;
1091
1092         String categoryName = filters.get(FilterKeyEnum.CATEGORY);
1093         String distributionStatus = filters.get(FilterKeyEnum.DISTRIBUTION_STATUS);
1094         DistributionStatusEnum distEnum = DistributionStatusEnum.findState(distributionStatus);
1095         if (distributionStatus != null && distEnum == null) {
1096             filters.remove(FilterKeyEnum.CATEGORY);
1097             return Either.right(StorageOperationStatus.CATEGORY_NOT_FOUND);
1098         }
1099
1100         if (categoryName != null) { // primary filter
1101             components = fetchByCategoryOrSubCategoryName(categoryName, NodeTypeEnum.ServiceNewCategory, GraphEdgeLabels.CATEGORY.getProperty(), NodeTypeEnum.Service, inTransaction, ServiceMetadataData.class, null);
1102             if (components.isLeft() && distEnum != null) {// secondary filter
1103                 Predicate<T> statusFilter = p -> ((Service) p).getDistributionStatus().equals(distEnum);
1104                 return Either.left(components.left().value().stream().filter(statusFilter).collect(Collectors.toList()));
1105             }
1106             filters.remove(FilterKeyEnum.DISTRIBUTION_STATUS);
1107             return components;
1108         }
1109
1110         Set<DistributionStatusEnum> distStatusSet = new HashSet<>();
1111         distStatusSet.add(distEnum);
1112         Either<List<Service>, StorageOperationStatus> servicesWithDistStatus = toscaOperationFacade.getServicesWithDistStatus(distStatusSet, null);
1113         if (servicesWithDistStatus.isRight()) { // not found == empty list
1114             return Either.left(new ArrayList<>());
1115         }
1116
1117         return Either.left((List<T>) servicesWithDistStatus.left().value());
1118     }
1119
1120     public Either<List<? extends Component>, ResponseFormat> getCatalogComponentsByUuidAndAssetType(String assetType, String uuid) {
1121
1122         if (assetType == null || uuid == null) {
1123             log.debug("getCatalogComponentsByUuidAndAssetType: One of the function parameteres is null");
1124             return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
1125         }
1126
1127         ComponentTypeEnum assetTypeEnum = AssetTypeEnum.convertToComponentTypeEnum(assetType);
1128
1129         if (assetTypeEnum == null) {
1130             log.debug("getCatalogComponentsByUuidAndAssetType: Corresponding ComponentTypeEnum not found");
1131             return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
1132         }
1133
1134         Map<GraphPropertyEnum, Object> additionalPropertiesToMatch = new EnumMap<>(GraphPropertyEnum.class);
1135
1136         switch (assetTypeEnum) {
1137         case RESOURCE:
1138             additionalPropertiesToMatch.put(GraphPropertyEnum.COMPONENT_TYPE, ComponentTypeEnum.RESOURCE.name());
1139             break;
1140         case SERVICE:
1141             additionalPropertiesToMatch.put(GraphPropertyEnum.COMPONENT_TYPE, ComponentTypeEnum.SERVICE.name());
1142             break;
1143         default:
1144             log.debug("getCatalogComponentsByUuidAndAssetType: Corresponding ComponentTypeEnum not allowed for this API");
1145             return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
1146         }
1147
1148         Either<List<Component>, StorageOperationStatus> componentsListByUuid = toscaOperationFacade.getComponentListByUuid(uuid, additionalPropertiesToMatch);
1149         if (componentsListByUuid.isRight()) {
1150             log.debug("getCatalogComponentsByUuidAndAssetType: " + assetTypeEnum.getValue() + " fetching failed");
1151             ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(componentsListByUuid.right().value(), assetTypeEnum);
1152             return Either.right(componentsUtils.getResponseFormat(actionStatus, uuid));
1153         }
1154
1155         log.debug("getCatalogComponentsByUuidAndAssetType: " + assetTypeEnum.getValue() + assetTypeEnum.getValue() + "fetching successful");
1156         return Either.left(componentsListByUuid.left().value());
1157     }
1158
1159     public List<String> getAllComponentTypesParamNames() {
1160         List<String> paramNames = new ArrayList<>();
1161         paramNames.add(ComponentTypeEnum.SERVICE_PARAM_NAME);
1162         paramNames.add(ComponentTypeEnum.RESOURCE_PARAM_NAME);
1163         paramNames.add(ComponentTypeEnum.PRODUCT_PARAM_NAME);
1164         return paramNames;
1165     }
1166
1167     public List<String> getAllSupportedRoles() {
1168         Role[] values = Role.values();
1169         List<String> roleNames = new ArrayList<>();
1170         for (Role role : values) {
1171             roleNames.add(role.name());
1172         }
1173         return roleNames;
1174     }
1175
1176     public Either<Map<String, String>, ActionStatus> getResourceTypesMap() {
1177         return elementOperation.getResourceTypesMap();
1178     }
1179
1180     private Optional<NameValuePair> findInvalidFilter(String query, ComponentTypeEnum assetType) {
1181         List<NameValuePair> params = URLEncodedUtils.parse(query, StandardCharsets.UTF_8);
1182         List<String> validKeys = FilterKeyEnum.getValidFiltersByAssetType(assetType);
1183         Predicate<NameValuePair> noMatch = p -> !validKeys.contains(p.getName());
1184         return params.stream().filter(noMatch).findAny();
1185     }
1186
1187     private List<String> getErrorResponseParams(Map<FilterKeyEnum, String> filters, ComponentTypeEnum assetType) {
1188         List<String> params = new ArrayList<String>();
1189         if (1 == filters.size()) {
1190             params.add(assetType.getValue().toLowerCase());
1191             params.add(filters.keySet().iterator().next().getName());
1192             params.add(filters.values().iterator().next());
1193         } else {
1194             params.add(assetType.getValue());
1195             params.add(filters.get(FilterKeyEnum.SUB_CATEGORY));
1196             params.add(filters.get(FilterKeyEnum.CATEGORY));
1197         }
1198         return params;
1199     }
1200
1201     public Either<List<Component>, StorageOperationStatus> getFilteredResouces(Map<FilterKeyEnum, String> filters, boolean inTransaction) {
1202
1203         String subCategoryName = filters.get(FilterKeyEnum.SUB_CATEGORY);
1204         String categoryName = filters.get(FilterKeyEnum.CATEGORY);
1205         ResourceTypeEnum resourceType = ResourceTypeEnum.getType(filters.get(FilterKeyEnum.RESOURCE_TYPE));
1206         Either<List<ImmutablePair<SubCategoryData, GraphEdge>>, StorageOperationStatus> subcategories = null;
1207         Optional<ImmutablePair<SubCategoryData, GraphEdge>> subCategoryData;
1208
1209         if (categoryName != null) {
1210             subcategories = getAllSubCategories(categoryName);
1211             if (subcategories.isRight()) {
1212                 filters.remove(FilterKeyEnum.SUB_CATEGORY);
1213                 return Either.right(subcategories.right().value());
1214             }
1215         }
1216         if (subCategoryName != null) { // primary filter
1217             if (categoryName != null) {
1218                 subCategoryData = validateCategoryHierarcy(subcategories.left().value(), subCategoryName);
1219                 if (!subCategoryData.isPresent()) {
1220                     return Either.right(StorageOperationStatus.MATCH_NOT_FOUND);
1221                 }
1222                 return fetchByCategoryOrSubCategoryUid((String) subCategoryData.get().getLeft().getUniqueId(), NodeTypeEnum.ResourceSubcategory, GraphEdgeLabels.SUB_CATEGORY.getProperty(), NodeTypeEnum.Resource, inTransaction,
1223                         ResourceMetadataData.class, resourceType);
1224             }
1225
1226             return fetchByCategoryOrSubCategoryName(subCategoryName, NodeTypeEnum.ResourceSubcategory, GraphEdgeLabels.SUB_CATEGORY.getProperty(), NodeTypeEnum.Resource, inTransaction, ResourceMetadataData.class, resourceType);
1227         }
1228         if (subcategories != null) {
1229             return fetchByMainCategory(subcategories.left().value(), inTransaction, resourceType);
1230         }
1231         return fetchComponentMetaDataByResourceType(filters.get(FilterKeyEnum.RESOURCE_TYPE), inTransaction);
1232     }
1233
1234     private Either<List<ImmutablePair<SubCategoryData, GraphEdge>>, StorageOperationStatus> getAllSubCategories(String categoryName) {
1235         Either<CategoryData, StorageOperationStatus> categoryResult = elementOperation.getNewCategoryData(categoryName, NodeTypeEnum.ResourceNewCategory, CategoryData.class);
1236         if (categoryResult.isRight()) {
1237             return Either.right(categoryResult.right().value());
1238         }
1239         CategoryData categoryData = categoryResult.left().value();
1240
1241         Either<List<ImmutablePair<SubCategoryData, GraphEdge>>, TitanOperationStatus> childrenNodes = titanGenericDao.getChildrenNodes(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.ResourceNewCategory), (String) categoryData.getUniqueId(),
1242                 GraphEdgeLabels.SUB_CATEGORY, NodeTypeEnum.ResourceSubcategory, SubCategoryData.class);
1243         if (childrenNodes.isRight()) {
1244             return Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(childrenNodes.right().value()));
1245         }
1246         return Either.left(childrenNodes.left().value());
1247     }
1248
1249     private Optional<ImmutablePair<SubCategoryData, GraphEdge>> validateCategoryHierarcy(List<ImmutablePair<SubCategoryData, GraphEdge>> childNodes, String subCategoryName) {
1250         Predicate<ImmutablePair<SubCategoryData, GraphEdge>> matchName = p -> p.getLeft().getSubCategoryDataDefinition().getName().equals(subCategoryName);
1251         return childNodes.stream().filter(matchName).findAny();
1252     }
1253
1254     protected <T, S extends ComponentMetadataData> Either<List<T>, StorageOperationStatus> fetchByCategoryOrSubCategoryUid(String categoryUid, NodeTypeEnum categoryType, String categoryLabel, NodeTypeEnum neededType, boolean inTransaction,
1255             Class<S> clazz, ResourceTypeEnum resourceType) {
1256         try {
1257             return collectComponents(neededType, categoryUid, categoryType, clazz, resourceType);
1258         } finally {
1259             if (false == inTransaction) {
1260                 titanDao.commit();
1261             }
1262         }
1263     }
1264
1265     protected <T, S extends ComponentMetadataData> Either<List<T>, StorageOperationStatus> fetchByCategoryOrSubCategoryName(String categoryName, NodeTypeEnum categoryType, String categoryLabel, NodeTypeEnum neededType, boolean inTransaction,
1266             Class<S> clazz, ResourceTypeEnum resourceType) {
1267         List<T> components = new ArrayList<>();
1268         try {
1269             Class categoryClazz = categoryType == NodeTypeEnum.ServiceNewCategory ? CategoryData.class : SubCategoryData.class;
1270             Map<String, Object> props = new HashMap<String, Object>();
1271             props.put(GraphPropertiesDictionary.NORMALIZED_NAME.getProperty(), ValidationUtils.normalizeCategoryName4Uniqueness(categoryName));
1272             Either<List<GraphNode>, TitanOperationStatus> getCategory = titanGenericDao.getByCriteria(categoryType, props, categoryClazz);
1273             if (getCategory.isRight()) {
1274                 return Either.right(StorageOperationStatus.CATEGORY_NOT_FOUND);
1275             }
1276             for (GraphNode category : getCategory.left().value()) {
1277                 Either<List<T>, StorageOperationStatus> result = collectComponents(neededType, (String) category.getUniqueId(), categoryType, clazz, resourceType);
1278                 if (result.isRight()) {
1279                     return result;
1280                 }
1281                 components.addAll(result.left().value());
1282             }
1283
1284             return Either.left(components);
1285         } finally {
1286             if (false == inTransaction) {
1287                 titanDao.commit();
1288             }
1289         }
1290     }
1291
1292     private <T, S extends ComponentMetadataData> Either<List<T>, StorageOperationStatus> collectComponents(NodeTypeEnum neededType, String categoryUid, NodeTypeEnum categoryType, Class<S> clazz, ResourceTypeEnum resourceType) {
1293         List<T> components = new ArrayList<>();
1294         Either<List<ImmutablePair<S, GraphEdge>>, TitanOperationStatus> parentNodes = titanGenericDao.getParentNodes(UniqueIdBuilder.getKeyByNodeType(categoryType), categoryUid, GraphEdgeLabels.CATEGORY, neededType, clazz);
1295         if (parentNodes.isLeft()) {
1296             for (ImmutablePair<S, GraphEdge> component : parentNodes.left().value()) {
1297                 ComponentMetadataDataDefinition componentData = component.getLeft().getMetadataDataDefinition();
1298                 Boolean isHighest = componentData.isHighestVersion();
1299                 boolean isMatchingResourceType = isMatchingByResourceType(neededType, resourceType, componentData);
1300                 boolean isDeleted = componentData.isDeleted() != null && componentData.isDeleted();
1301
1302                 if (isHighest && isMatchingResourceType && !isDeleted) {
1303                     Either<T, StorageOperationStatus> result = (Either<T, StorageOperationStatus>) toscaOperationFacade.getToscaElement(componentData.getUniqueId(), JsonParseFlagEnum.ParseMetadata);
1304                     if (result.isRight()) {
1305                         return Either.right(result.right().value());
1306                     }
1307                     components.add(result.left().value());
1308                 }
1309             }
1310         }
1311         return Either.left(components);
1312     }
1313
1314     private boolean isMatchingByResourceType(NodeTypeEnum componentType, ResourceTypeEnum resourceType, ComponentMetadataDataDefinition componentData) {
1315
1316         boolean isMatching;
1317         if (componentType == NodeTypeEnum.Resource) {
1318             if (resourceType == null) {
1319                 isMatching = true;
1320             } else {
1321                 isMatching = resourceType == ((ResourceMetadataDataDefinition) componentData).getResourceType();
1322             }
1323         } else {
1324             isMatching = true;
1325         }
1326         return isMatching;
1327     }
1328
1329     private <T> Either<List<T>, StorageOperationStatus> fetchByMainCategory(List<ImmutablePair<SubCategoryData, GraphEdge>> subcategories, boolean inTransaction, ResourceTypeEnum resourceType) {
1330         List<T> components = new ArrayList<>();
1331
1332         for (ImmutablePair<SubCategoryData, GraphEdge> subCategory : subcategories) {
1333             Either<List<T>, StorageOperationStatus> fetched = fetchByCategoryOrSubCategoryUid((String) subCategory.getLeft().getUniqueId(), NodeTypeEnum.ResourceSubcategory, GraphEdgeLabels.SUB_CATEGORY.getProperty(), NodeTypeEnum.Resource,
1334                     inTransaction, ResourceMetadataData.class, resourceType);
1335             if (fetched.isRight()) {
1336                 continue;
1337             }
1338             components.addAll(fetched.left().value());
1339         }
1340         return Either.left(components);
1341     }
1342
1343     private Either<List<Component>, StorageOperationStatus> fetchComponentMetaDataByResourceType(String resourceType, boolean inTransaction) {
1344         List<Component> components = null;
1345         StorageOperationStatus status;
1346         Wrapper<StorageOperationStatus> statusWrapper = new Wrapper<>();
1347         Either<List<Component>, StorageOperationStatus> result;
1348         try {
1349             ComponentParametersView fetchUsersAndCategoriesFilter = new ComponentParametersView(Arrays.asList(ComponentFieldsEnum.USERS.getValue(), ComponentFieldsEnum.CATEGORIES.getValue()));
1350             Either<List<Component>, StorageOperationStatus> getResources = toscaOperationFacade.fetchMetaDataByResourceType(resourceType, fetchUsersAndCategoriesFilter);
1351             if (getResources.isRight()) {
1352                 status = getResources.right().value();
1353                 if (status != StorageOperationStatus.NOT_FOUND) {
1354                     statusWrapper.setInnerElement(getResources.right().value());
1355                 } else {
1356                     components = new ArrayList<>();
1357                 }
1358             } else {
1359                 components = getResources.left().value();
1360             }
1361             if (!statusWrapper.isEmpty()) {
1362                 result = Either.right(statusWrapper.getInnerElement());
1363             } else {
1364                 result = Either.left(components);
1365             }
1366             return result;
1367         } finally {
1368             if (!inTransaction) {
1369                 titanDao.commit();
1370             }
1371         }
1372     }
1373 }