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