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