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