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