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