363b8d64df18a4eb51236a47feb121ce82edb916
[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     public Either<List<CategoryDefinition>, ActionStatus> getAllServiceCategories() {
269         return elementOperation.getAllServiceCategories();
270     }
271
272     public Either<CategoryDefinition, ResponseFormat> createCategory(CategoryDefinition category, String componentTypeParamName, String userId) {
273         AuditingActionEnum auditingAction = AuditingActionEnum.ADD_CATEGORY;
274         ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName);
275         String componentType = componentTypeEnum == null ? componentTypeParamName : componentTypeEnum.getValue();
276         CategoryTypeEnum categoryType = CategoryTypeEnum.CATEGORY;
277         User user = validateUserExists(userId);
278         if (category == null) {
279             log.debug("Category json is invalid");
280             ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
281             handleCategoryAuditing(responseFormat, user, null, auditingAction, componentType);
282             return Either.right(responseFormat);
283         }
284         String categoryName = category.getName();
285         // For auditing of failures we need the original non-normalized name
286         String origCategoryName = categoryName;
287         if (componentTypeEnum == null) {
288             log.debug(COMPONENT_TYPE_IS_INVALID, componentTypeParamName);
289             ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
290             handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
291             return Either.right(responseFormat);
292         }
293         Either<Boolean, ResponseFormat> validateUserRole = validateUserRole(user, componentTypeEnum);
294         if (validateUserRole.isRight()) {
295             log.debug(VALIDATION_OF_USER_ROLE_FAILED_USER_ID, userId);
296             ResponseFormat responseFormat = validateUserRole.right().value();
297             handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
298             return Either.right(responseFormat);
299         }
300         if (!ValidationUtils.validateCategoryDisplayNameFormat(categoryName)) {
301             log.debug("Category display name format is invalid, name {}, componentType {}", categoryName, componentType);
302             ResponseFormat responseFormat = componentsUtils
303                     .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, componentType, categoryType.getValue());
304             handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
305             return Either.right(responseFormat);
306         }
307         categoryName = ValidationUtils.normalizeCategoryName4Display(categoryName);
308         if (!ValidationUtils.validateCategoryDisplayNameLength(categoryName)) {
309             log.debug("Category display name length is invalid, should be from 4 to 25 chars, name {}, componentType {}", categoryName,
310                     componentType);
311             ResponseFormat responseFormat = componentsUtils
312                     .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, componentType, categoryType.getValue());
313             handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
314             return Either.right(responseFormat);
315         }
316         category.setName(categoryName);
317         String normalizedName = ValidationUtils.normalizeCategoryName4Uniqueness(categoryName);
318         category.setNormalizedName(normalizedName);
319         if (ValidationUtils.validateCategoryIconNotEmpty(category.getIcons())) {
320             log.debug("createCategory: setting category icon to default icon since service category was created without an icon ");
321             category.setIcons(Arrays.asList(DEFAULT_ICON));
322         }
323         NodeTypeEnum nodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, categoryType);
324         Either<Boolean, ActionStatus> categoryUniqueEither = elementOperation.isCategoryUniqueForType(nodeType, normalizedName);
325         if (categoryUniqueEither.isRight()) {
326             log.debug("Failed to check category uniqueness, name {}, componentType {}", categoryName, componentType);
327             ResponseFormat responseFormat = componentsUtils.getResponseFormat(categoryUniqueEither.right().value());
328             handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
329             return Either.right(responseFormat);
330         }
331         Boolean isCategoryUnique = categoryUniqueEither.left().value();
332         if (Boolean.FALSE.equals(isCategoryUnique)) {
333             log.debug("Category is not unique, name {}, componentType {}", categoryName, componentType);
334             ResponseFormat responseFormat = componentsUtils
335                     .getResponseFormat(ActionStatus.COMPONENT_CATEGORY_ALREADY_EXISTS, componentType, categoryName);
336             handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
337             return Either.right(responseFormat);
338         }
339         Either<CategoryDefinition, ActionStatus> createCategoryByType = elementOperation.createCategory(category, nodeType);
340         if (createCategoryByType.isRight()) {
341             log.debug("Failed to create category, name {}, componentType {}", categoryName, componentType);
342             ResponseFormat responseFormat = componentsUtils
343                     .getResponseFormat(ActionStatus.COMPONENT_CATEGORY_ALREADY_EXISTS, componentType, categoryName);
344             handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
345             return Either.right(componentsUtils.getResponseFormat(createCategoryByType.right().value()));
346         }
347         category = createCategoryByType.left().value();
348         log.debug("Created category for component {}, name {}, uniqueId {}", componentType, categoryName, category.getUniqueId());
349         ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.CREATED);
350         handleCategoryAuditing(responseFormat, user, category.getName(), auditingAction, componentType);
351         return Either.left(category);
352     }
353
354     public Either<SubCategoryDefinition, ResponseFormat> createSubCategory(SubCategoryDefinition subCategory, String componentTypeParamName,
355                                                                            String parentCategoryId, String userId) {
356         AuditingActionEnum auditingAction = AuditingActionEnum.ADD_SUB_CATEGORY;
357         ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName);
358         String componentType = componentTypeEnum == null ? componentTypeParamName : componentTypeEnum.getValue();
359         CategoryTypeEnum categoryType = CategoryTypeEnum.SUBCATEGORY;
360         // For auditing
361         String parentCategoryName = parentCategoryId;
362         if (subCategory == null) {
363             log.debug("Sub-category json is invalid");
364             ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
365             handleCategoryAuditing(responseFormat, null, parentCategoryName, null, auditingAction, componentType);
366             return Either.right(responseFormat);
367         }
368         String subCategoryName = subCategory.getName();
369         // For auditing of failures we need the original non-normalized name
370         String origSubCategoryName = subCategoryName;
371         User user;
372         try {
373             user = validateUserExists(userId);
374         } catch (ByActionStatusComponentException e) {
375             ResponseFormat responseFormat = componentsUtils.getResponseFormat(e.getActionStatus(), e.getParams());
376             handleComponentException(userId, auditingAction, componentType, parentCategoryName, origSubCategoryName, responseFormat);
377             throw e;
378         } catch (ByResponseFormatComponentException e) {
379             ResponseFormat responseFormat = e.getResponseFormat();
380             handleComponentException(userId, auditingAction, componentType, parentCategoryName, origSubCategoryName, responseFormat);
381             throw e;
382         }
383         if (componentTypeEnum == null) {
384             log.debug(COMPONENT_TYPE_IS_INVALID, componentTypeParamName);
385             ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
386             handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
387             return Either.right(responseFormat);
388         }
389         Either<Boolean, ResponseFormat> validateComponentType = validateComponentTypeForCategory(componentTypeEnum, categoryType);
390         if (validateComponentType.isRight()) {
391             log.debug("Validation of component type for sub-category failed");
392             ResponseFormat responseFormat = validateComponentType.right().value();
393             handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
394             return Either.right(responseFormat);
395         }
396         Either<Boolean, ResponseFormat> validateUserRole = validateUserRole(user, componentTypeEnum);
397         if (validateUserRole.isRight()) {
398             log.debug(VALIDATION_OF_USER_ROLE_FAILED_USER_ID, userId);
399             ResponseFormat responseFormat = validateUserRole.right().value();
400             handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
401             return Either.right(responseFormat);
402         }
403         NodeTypeEnum parentNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.CATEGORY);
404         NodeTypeEnum childNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.SUBCATEGORY);
405         CategoryDefinition categoryDefinition;
406         Either<CategoryDefinition, ResponseFormat> validateCategoryExists = validateCategoryExists(parentNodeType, parentCategoryId,
407                 componentTypeEnum);
408         if (validateCategoryExists.isRight()) {
409             log.debug("Validation of parent category exists failed, parent categoryId {}", parentCategoryId);
410             ResponseFormat responseFormat = validateCategoryExists.right().value();
411             handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
412             return Either.right(responseFormat);
413         }
414         categoryDefinition = validateCategoryExists.left().value();
415         parentCategoryName = categoryDefinition.getName();
416         if (!ValidationUtils.validateCategoryDisplayNameFormat(subCategoryName)) {
417             log.debug("Sub-category display name format is invalid, name {}, componentType {}", subCategoryName, componentType);
418             ResponseFormat responseFormat = componentsUtils
419                     .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, componentType, categoryType.getValue());
420             handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
421             return Either.right(responseFormat);
422         }
423         subCategoryName = ValidationUtils.normalizeCategoryName4Display(subCategoryName);
424         if (!ValidationUtils.validateCategoryDisplayNameLength(subCategoryName)) {
425             log.debug("Sub-category display name length is invalid, should be from 4 to 25 chars, name {}, componentType {}", subCategoryName,
426                     componentType);
427             ResponseFormat responseFormat = componentsUtils
428                     .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, componentType, categoryType.getValue());
429             handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
430             return Either.right(responseFormat);
431         }
432         String normalizedName = ValidationUtils.normalizeCategoryName4Uniqueness(subCategoryName);
433         subCategory.setNormalizedName(normalizedName);
434         // Uniqueness under this category
435         Either<Boolean, ActionStatus> subCategoryUniqueForCategory = elementOperation
436                 .isSubCategoryUniqueForCategory(childNodeType, normalizedName, parentCategoryId);
437         if (subCategoryUniqueForCategory.isRight()) {
438             log.debug("Failed to check sub-category uniqueness, parent name {}, subcategory norm name {}, componentType {}", parentCategoryName,
439                     normalizedName, componentType);
440             ResponseFormat responseFormat = componentsUtils.getResponseFormat(subCategoryUniqueForCategory.right().value());
441             handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
442             return Either.right(responseFormat);
443         }
444         Boolean isSubUnique = subCategoryUniqueForCategory.left().value();
445         if (Boolean.FALSE.equals(isSubUnique)) {
446             log.debug("Sub-category is not unique for category, parent name {}, subcategory norm name {}, componentType {}", parentCategoryName,
447                     normalizedName, componentType);
448             ResponseFormat responseFormat = componentsUtils
449                     .getResponseFormat(ActionStatus.COMPONENT_SUB_CATEGORY_EXISTS_FOR_CATEGORY, componentType, subCategoryName, parentCategoryName);
450             handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
451             return Either.right(responseFormat);
452         }
453         // Setting name of subcategory to fit the similar subcategory name
454
455         // ignoring cases.
456
457         // For example if Network-->kUKU exists for service category Network,
458
459         // and user is trying to create Router-->Kuku for service category
460
461         // Router,
462
463         // his subcategory name will be Router-->kUKU.
464         Either<SubCategoryDefinition, ActionStatus> subCategoryUniqueForType = elementOperation
465                 .getSubCategoryUniqueForType(childNodeType, normalizedName);
466         if (subCategoryUniqueForType.isRight()) {
467             log.debug("Failed validation of whether similar sub-category exists, normalizedName {} componentType {}", normalizedName, componentType);
468             ResponseFormat responseFormat = componentsUtils.getResponseFormat(subCategoryUniqueForType.right().value());
469             handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
470             return Either.right(responseFormat);
471         }
472         SubCategoryDefinition subCategoryDefinition = subCategoryUniqueForType.left().value();
473         if (subCategoryDefinition != null) {
474             subCategoryName = subCategoryDefinition.getName();
475         }
476         subCategory.setName(subCategoryName);
477         ///////////////////////////////////////////// Validations end
478         Either<SubCategoryDefinition, ActionStatus> createSubCategory = elementOperation
479                 .createSubCategory(parentCategoryId, subCategory, childNodeType);
480         if (createSubCategory.isRight()) {
481             log.debug("Failed to create sub-category, name {}, componentType {}", subCategoryName, componentType);
482             ResponseFormat responseFormat = componentsUtils.getResponseFormat(subCategoryUniqueForType.right().value());
483             handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
484             return Either.right(responseFormat);
485         }
486         SubCategoryDefinition subCategoryCreated = createSubCategory.left().value();
487         log.debug("Created sub-category for component {}, name {}, uniqueId {}", componentType, subCategoryName, subCategoryCreated.getUniqueId());
488         ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.CREATED);
489         handleCategoryAuditing(responseFormat, user, parentCategoryName, subCategoryCreated.getName(), auditingAction, componentType);
490         return Either.left(subCategoryCreated);
491     }
492
493     private void handleComponentException(String userId, AuditingActionEnum auditingAction, String componentType, String parentCategoryName,
494                                           String origSubCategoryName, ResponseFormat responseFormat) {
495         User user;
496         log.debug(VALIDATION_OF_USER_FAILED_USER_ID, userId);
497         user = new User();
498         user.setUserId(userId);
499         handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
500     }
501
502     private void handleComponentException(GroupingDefinition grouping, String userId, AuditingActionEnum auditingAction, String componentType,
503                                           String parentCategoryName, String parentSubCategoryName, ResponseFormat responseFormat) {
504         User user;
505         log.debug(VALIDATION_OF_USER_FAILED_USER_ID, userId);
506         user = new User();
507         user.setUserId(userId);
508         String groupingNameForAudit = grouping == null ? null : grouping.getName();
509         handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, groupingNameForAudit, auditingAction, componentType);
510     }
511
512     private void handleComponentException(String componentType, String userId, ResponseFormat responseFormat) {
513         User user;
514         user = new User();
515         user.setUserId(userId);
516         log.debug(VALIDATION_OF_USER_FAILED_USER_ID, userId);
517         componentsUtils.auditGetCategoryHierarchy(user, componentType, responseFormat);
518     }
519
520     public Either<GroupingDefinition, ResponseFormat> createGrouping(GroupingDefinition grouping, String componentTypeParamName,
521                                                                      String grandParentCategoryId, String parentSubCategoryId, String userId) {
522         AuditingActionEnum auditingAction = AuditingActionEnum.ADD_GROUPING;
523         ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName);
524         String componentType = componentTypeEnum == null ? componentTypeParamName : componentTypeEnum.getValue();
525         CategoryTypeEnum categoryType = CategoryTypeEnum.GROUPING;
526         // For auditing
527         String parentCategoryName = grandParentCategoryId;
528         String parentSubCategoryName = parentSubCategoryId;
529         User user;
530         try {
531             user = validateUserExists(userId);
532         } catch (ByResponseFormatComponentException e) {
533             ResponseFormat responseFormat = e.getResponseFormat();
534             handleComponentException(grouping, userId, auditingAction, componentType, parentCategoryName, parentSubCategoryName, responseFormat);
535             throw e;
536         } catch (ByActionStatusComponentException e) {
537             ResponseFormat responseFormat = componentsUtils.getResponseFormat(e.getActionStatus(), e.getParams());
538             handleComponentException(grouping, userId, auditingAction, componentType, parentCategoryName, parentSubCategoryName, responseFormat);
539             throw e;
540         }
541         if (grouping == null) {
542             log.debug("Grouping json is invalid");
543             ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
544             handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, null, auditingAction, componentType);
545             return Either.right(responseFormat);
546         }
547         String groupingName = grouping.getName();
548         // For auditing of failures we need the original non-normalized name
549         String origGroupingName = groupingName;
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         Either<Boolean, ResponseFormat> validateComponentType = validateComponentTypeForCategory(componentTypeEnum, categoryType);
557         if (validateComponentType.isRight()) {
558             log.debug("Validation of component type for grouping failed");
559             ResponseFormat responseFormat = validateComponentType.right().value();
560             handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
561             return Either.right(responseFormat);
562         }
563         Either<Boolean, ResponseFormat> validateUserRole = validateUserRole(user, componentTypeEnum);
564         if (validateUserRole.isRight()) {
565             log.debug(VALIDATION_OF_USER_ROLE_FAILED_USER_ID, userId);
566             ResponseFormat responseFormat = validateUserRole.right().value();
567             handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
568             return Either.right(responseFormat);
569         }
570         NodeTypeEnum grandParentNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.CATEGORY);
571         NodeTypeEnum parentNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.SUBCATEGORY);
572         NodeTypeEnum childNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.GROUPING);
573         // Validate category
574         CategoryDefinition categoryDefinition;
575         Either<CategoryDefinition, ResponseFormat> validateCategoryExists = validateCategoryExists(grandParentNodeType, grandParentCategoryId,
576                 componentTypeEnum);
577         if (validateCategoryExists.isRight()) {
578             log.debug("Validation of parent category exists failed, parent categoryId {}", grandParentCategoryId);
579             ResponseFormat responseFormat = validateCategoryExists.right().value();
580             handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
581             return Either.right(responseFormat);
582         }
583         categoryDefinition = validateCategoryExists.left().value();
584         parentCategoryName = categoryDefinition.getName();
585         // Validate subcategory
586         SubCategoryDefinition subCategoryDefinition;
587         Either<SubCategoryDefinition, ResponseFormat> validateSubCategoryExists = validateSubCategoryExists(parentNodeType, parentSubCategoryId,
588                 componentTypeEnum);
589         if (validateSubCategoryExists.isRight()) {
590             log.debug("Validation of parent sub-category exists failed, parent sub-category id {}", parentSubCategoryId);
591             ResponseFormat responseFormat = validateSubCategoryExists.right().value();
592             handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
593             return Either.right(responseFormat);
594         }
595         subCategoryDefinition = validateSubCategoryExists.left().value();
596         parentSubCategoryName = subCategoryDefinition.getName();
597         if (!ValidationUtils.validateCategoryDisplayNameFormat(groupingName)) {
598             log.debug("Sub-category display name format is invalid, name {}, componentType {}", groupingName, componentType);
599             ResponseFormat responseFormat = componentsUtils
600                     .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, componentType, categoryType.getValue());
601             handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
602             return Either.right(responseFormat);
603         }
604         groupingName = ValidationUtils.normalizeCategoryName4Display(groupingName);
605         if (!ValidationUtils.validateCategoryDisplayNameLength(groupingName)) {
606             log.debug("Grouping display name length is invalid, should be from 4 to 25 chars, name {}, componentType {}", groupingName,
607                     componentType);
608             ResponseFormat responseFormat = componentsUtils
609                     .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, componentType, categoryType.getValue());
610             handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
611             return Either.right(responseFormat);
612         }
613         String normalizedName = ValidationUtils.normalizeCategoryName4Uniqueness(groupingName);
614         grouping.setNormalizedName(normalizedName);
615         // Uniqueness under this category
616         Either<Boolean, ActionStatus> groupingUniqueForSubCategory = elementOperation
617                 .isGroupingUniqueForSubCategory(childNodeType, normalizedName, parentSubCategoryId);
618         if (groupingUniqueForSubCategory.isRight()) {
619             log.debug("Failed to check grouping uniqueness, parent name {}, grouping norm name {}, componentType {}", parentSubCategoryName,
620                     normalizedName, componentType);
621             ResponseFormat responseFormat = componentsUtils.getResponseFormat(groupingUniqueForSubCategory.right().value());
622             handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
623             return Either.right(responseFormat);
624         }
625         Boolean isGroupingUnique = groupingUniqueForSubCategory.left().value();
626         if (Boolean.FALSE.equals(isGroupingUnique)) {
627             log.debug("Grouping is not unique for sub-category, parent name {}, grouping norm name {}, componentType {}", parentSubCategoryName,
628                     normalizedName, componentType);
629             ResponseFormat responseFormat = componentsUtils
630                     .getResponseFormat(ActionStatus.COMPONENT_GROUPING_EXISTS_FOR_SUB_CATEGORY, componentType, groupingName, parentSubCategoryName);
631             handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
632             return Either.right(responseFormat);
633         }
634         // Setting name of grouping to fit the similar grouping name ignoring
635
636         // cases.
637
638         // For example if Network-->kUKU exists for service sub-category
639
640         // Network, and user is trying to create grouping Router-->Kuku for
641
642         // service sub-category Router,
643
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         grouping.setName(groupingName);
657         ///////////////////////////////////////////// Validations end
658         Either<GroupingDefinition, ActionStatus> createGrouping = elementOperation.createGrouping(parentSubCategoryId, grouping, childNodeType);
659         if (createGrouping.isRight()) {
660             log.debug("Failed to create grouping, name {}, componentType {}", groupingName, componentType);
661             ResponseFormat responseFormat = componentsUtils.getResponseFormat(createGrouping.right().value());
662             handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
663             return Either.right(responseFormat);
664         }
665         GroupingDefinition groupingCreated = createGrouping.left().value();
666         log.debug("Created grouping for component {}, name {}, uniqueId {}", componentType, groupingName, groupingCreated.getUniqueId());
667         ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.CREATED);
668         handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, groupingCreated.getName(), auditingAction,
669                 componentType);
670         return Either.left(groupingCreated);
671     }
672
673     public Either<List<CategoryDefinition>, ResponseFormat> getAllCategories(String componentType, String userId) {
674         ResponseFormat responseFormat;
675         User user = new User();
676         if (userId == null) {
677             user.setUserId("UNKNOWN");
678             responseFormat = componentsUtils.getResponseFormat(ActionStatus.MISSING_INFORMATION);
679             componentsUtils.auditGetCategoryHierarchy(user, componentType, responseFormat);
680             return Either.right(responseFormat);
681         }
682         try {
683             user = validateUserExists(userId);
684         } catch (ByActionStatusComponentException e) {
685             responseFormat = componentsUtils.getResponseFormat(e.getActionStatus(), e.getParams());
686             handleComponentException(componentType, userId, responseFormat);
687             throw e;
688         } catch (ByResponseFormatComponentException e) {
689             responseFormat = e.getResponseFormat();
690             handleComponentException(componentType, userId, responseFormat);
691             throw e;
692         }
693         ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentType);
694         if (componentTypeEnum == null) {
695             log.debug("Cannot create category for component type {}", componentType);
696             responseFormat = componentsUtils.getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, "component type");
697             componentsUtils.auditGetCategoryHierarchy(user, componentType, responseFormat);
698             return Either.right(responseFormat);
699         }
700         NodeTypeEnum nodeTypeEnum = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.CATEGORY);
701         Either<List<CategoryDefinition>, ActionStatus> getAllCategoriesByType = elementOperation.getAllCategories(nodeTypeEnum, false);
702         if (getAllCategoriesByType.isRight()) {
703             responseFormat = componentsUtils.getResponseFormat(getAllCategoriesByType.right().value());
704             componentsUtils.auditGetCategoryHierarchy(user, componentType, responseFormat);
705             return Either.right(responseFormat);
706         }
707         List<CategoryDefinition> categories = getAllCategoriesByType.left().value();
708         responseFormat = componentsUtils.getResponseFormat(ActionStatus.OK);
709         componentsUtils.auditGetCategoryHierarchy(user, componentType, responseFormat);
710         return Either.left(categories);
711     }
712
713     public Either<UiCategories, ResponseFormat> getAllCategories(String userId) {
714         ResponseFormat responseFormat;
715         UiCategories categories = new UiCategories();
716         User user = validateUserExists(userId);
717         // GET resource categories
718         Either<List<CategoryDefinition>, ActionStatus> getResourceCategoriesByType = elementOperation
719                 .getAllCategories(NodeTypeEnum.ResourceNewCategory, false);
720         if (getResourceCategoriesByType.isRight()) {
721             responseFormat = componentsUtils.getResponseFormat(getResourceCategoriesByType.right().value());
722             componentsUtils.auditGetCategoryHierarchy(user, ComponentTypeEnum.RESOURCE.getValue(), responseFormat);
723             return Either.right(responseFormat);
724         }
725         categories.setResourceCategories(getResourceCategoriesByType.left().value());
726         // GET service categories
727         Either<List<CategoryDefinition>, ActionStatus> getServiceCategoriesByType = elementOperation
728                 .getAllCategories(NodeTypeEnum.ServiceNewCategory, false);
729         if (getServiceCategoriesByType.isRight()) {
730             responseFormat = componentsUtils.getResponseFormat(getServiceCategoriesByType.right().value());
731             componentsUtils.auditGetCategoryHierarchy(user, ComponentTypeEnum.SERVICE.getValue(), responseFormat);
732             return Either.right(responseFormat);
733         }
734         categories.setServiceCategories(getServiceCategoriesByType.left().value());
735         categories.setProductCategories(new ArrayList<>());
736         return Either.left(categories);
737     }
738
739     public Either<CategoryDefinition, ResponseFormat> deleteCategory(String categoryId, String componentTypeParamName, String userId) {
740         validateUserExists(userId);
741         ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName);
742         if (componentTypeEnum == null) {
743             log.debug("Cannot create category for component type {}", componentTypeParamName);
744             return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
745         }
746         NodeTypeEnum nodeTypeEnum = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.CATEGORY);
747         Either<CategoryDefinition, ActionStatus> deleteCategoryByType = elementOperation.deleteCategory(nodeTypeEnum, categoryId);
748         if (deleteCategoryByType.isRight()) {
749             // auditing, logging here...
750             return Either.right(componentsUtils.getResponseFormat(deleteCategoryByType.right().value()));
751         }
752         CategoryDefinition category = deleteCategoryByType.left().value();
753         log.debug("Delete category for component {}, name {}, uniqueId {}", nodeTypeEnum, category.getName(), category.getUniqueId());
754         return Either.left(category);
755     }
756
757     public Either<SubCategoryDefinition, ResponseFormat> deleteSubCategory(String parentSubCategoryId, String componentTypeParamName, String userId) {
758         validateUserExists(userId);
759         ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName);
760         if (componentTypeEnum == null) {
761             log.debug("Cannot delete sub-category for component type {}", componentTypeParamName);
762             return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
763         }
764         NodeTypeEnum nodeTypeEnum = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.SUBCATEGORY);
765         Either<SubCategoryDefinition, ActionStatus> deleteSubCategoryByType = elementOperation.deleteSubCategory(nodeTypeEnum, parentSubCategoryId);
766         if (deleteSubCategoryByType.isRight()) {
767             // auditing, logging here...
768             return Either.right(componentsUtils.getResponseFormat(deleteSubCategoryByType.right().value()));
769         }
770         SubCategoryDefinition subCategory = deleteSubCategoryByType.left().value();
771         log.debug("Deleted sub-category for component {}, name {}, uniqueId {}", nodeTypeEnum, subCategory.getName(), subCategory.getUniqueId());
772         return Either.left(subCategory);
773     }
774
775     public Either<GroupingDefinition, ResponseFormat> deleteGrouping(String groupingId, String componentTypeParamName, String userId) {
776         validateUserExists(userId);
777         ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName);
778         if (componentTypeEnum == null) {
779             log.debug("Cannot delete grouping for component type {}", componentTypeParamName);
780             return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
781         }
782         NodeTypeEnum nodeTypeEnum = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.GROUPING);
783         Either<GroupingDefinition, ActionStatus> deleteGroupingByType = elementOperation.deleteGrouping(nodeTypeEnum, groupingId);
784         if (deleteGroupingByType.isRight()) {
785             // auditing, logging here...
786             return Either.right(componentsUtils.getResponseFormat(deleteGroupingByType.right().value()));
787         }
788         GroupingDefinition deletedGrouping = deleteGroupingByType.left().value();
789         log.debug("Deleted grouping for component {}, name {}, uniqueId {}", nodeTypeEnum, deletedGrouping.getName(), deletedGrouping.getUniqueId());
790         return Either.left(deletedGrouping);
791     }
792
793     private Either<Boolean, ResponseFormat> validateUserRole(User user, ComponentTypeEnum componentTypeEnum) {
794         String role = user.getRole();
795         boolean validAdminAction =
796                 role.equals(Role.ADMIN.name()) && (componentTypeEnum == ComponentTypeEnum.SERVICE || componentTypeEnum == ComponentTypeEnum.RESOURCE);
797         boolean validProductAction = role.equals(Role.PRODUCT_STRATEGIST.name()) && (componentTypeEnum == ComponentTypeEnum.PRODUCT);
798         if (!(validAdminAction || validProductAction)) {
799             ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION);
800             log.debug("User not permitted to perform operation on category, userId = {}, role = {}, componentType = {}", user.getUserId(), role,
801                     componentTypeEnum);
802             return Either.right(responseFormat);
803         }
804         return Either.left(true);
805     }
806
807     private Either<Boolean, ResponseFormat> validateComponentTypeForCategory(ComponentTypeEnum componentType, CategoryTypeEnum categoryType) {
808         boolean validResourceAction = componentType == ComponentTypeEnum.RESOURCE && (categoryType == CategoryTypeEnum.CATEGORY
809                 || categoryType == CategoryTypeEnum.SUBCATEGORY);
810         boolean validServiceAction = componentType == ComponentTypeEnum.SERVICE && categoryType == CategoryTypeEnum.CATEGORY;
811         boolean validProductAction = componentType == ComponentTypeEnum.PRODUCT; // can
812
813         // be
814
815         // any
816
817         // category
818
819         // type
820         if (!(validResourceAction || validServiceAction || validProductAction)) {
821             ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
822             log.debug("It's not allowed to create category type {} for component type {}", categoryType, componentType);
823             return Either.right(responseFormat);
824         }
825         return Either.left(true);
826     }
827
828     private Either<CategoryDefinition, ResponseFormat> validateCategoryExists(NodeTypeEnum nodeType, String categoryId,
829                                                                               ComponentTypeEnum componentType) {
830         Either<CategoryDefinition, ActionStatus> categoryByTypeAndId = elementOperation.getCategory(nodeType, categoryId);
831         if (categoryByTypeAndId.isRight()) {
832             log.debug("Failed to fetch parent category, parent categoryId {}", categoryId);
833             ActionStatus actionStatus = categoryByTypeAndId.right().value();
834             ResponseFormat responseFormat;
835             if (actionStatus == ActionStatus.COMPONENT_CATEGORY_NOT_FOUND) {
836                 responseFormat = componentsUtils
837                         .getResponseFormat(actionStatus, componentType.getValue().toLowerCase(), CategoryTypeEnum.CATEGORY.getValue(), "");
838             } else {
839                 responseFormat = componentsUtils.getResponseFormat(actionStatus);
840             }
841             return Either.right(responseFormat);
842         }
843         return Either.left(categoryByTypeAndId.left().value());
844     }
845
846     private Either<SubCategoryDefinition, ResponseFormat> validateSubCategoryExists(NodeTypeEnum nodeType, String subCategoryId,
847                                                                                     ComponentTypeEnum componentType) {
848         Either<SubCategoryDefinition, ActionStatus> subCategoryByTypeAndId = elementOperation.getSubCategory(nodeType, subCategoryId);
849         if (subCategoryByTypeAndId.isRight()) {
850             log.debug("Failed to fetch parent category, parent categoryId {}", subCategoryId);
851             ActionStatus actionStatus = subCategoryByTypeAndId.right().value();
852             ResponseFormat responseFormat;
853             if (actionStatus == ActionStatus.COMPONENT_CATEGORY_NOT_FOUND) {
854                 responseFormat = componentsUtils
855                         .getResponseFormat(actionStatus, componentType.getValue().toLowerCase(), CategoryTypeEnum.SUBCATEGORY.getValue(), "");
856             } else {
857                 responseFormat = componentsUtils.getResponseFormat(actionStatus);
858             }
859             return Either.right(responseFormat);
860         }
861         return Either.left(subCategoryByTypeAndId.left().value());
862     }
863
864     private void handleCategoryAuditing(ResponseFormat responseFormat, User user, String category, AuditingActionEnum auditingAction,
865                                         String componentType) {
866         componentsUtils.auditCategory(responseFormat, user, category, null, null, auditingAction, componentType);
867     }
868
869     private void handleCategoryAuditing(ResponseFormat responseFormat, User user, String category, String subCategory,
870                                         AuditingActionEnum auditingAction, String componentType) {
871         componentsUtils.auditCategory(responseFormat, user, category, subCategory, null, auditingAction, componentType);
872     }
873
874     private void handleCategoryAuditing(ResponseFormat responseFormat, User user, String category, String subCategory, String grouping,
875                                         AuditingActionEnum auditingAction, String componentType) {
876         componentsUtils.auditCategory(responseFormat, user, category, subCategory, grouping, auditingAction, componentType);
877     }
878
879     /*
880      * New categories flow - end
881      */
882     public Either<List<Tag>, ActionStatus> getAllTags(String userId) {
883         ActionStatus status = validateUserExistsActionStatus(userId);
884         if (ActionStatus.OK != status) {
885             return Either.right(status);
886         }
887         return elementOperation.getAllTags();
888     }
889
890     public Either<List<PropertyScope>, ActionStatus> getAllPropertyScopes(String userId) {
891         ActionStatus status = validateUserExistsActionStatus(userId);
892         if (ActionStatus.OK != status) {
893             return Either.right(status);
894         }
895         return elementOperation.getAllPropertyScopes();
896     }
897
898     public Either<List<ArtifactType>, ActionStatus> getAllArtifactTypes(final String userId) {
899         ActionStatus status = validateUserExistsActionStatus(userId);
900         if (ActionStatus.OK != status) {
901             return Either.right(status);
902         }
903         return Either.left(elementOperation.getAllArtifactTypes());
904     }
905
906     public Either<Configuration.HeatDeploymentArtifactTimeout, ActionStatus> getDefaultHeatTimeout() {
907         return elementOperation.getDefaultHeatTimeout();
908     }
909
910     public Either<Map<String, List<CatalogComponent>>, ResponseFormat> getCatalogComponents(List<OriginTypeEnum> excludeTypes) {
911         try {
912             return toscaOperationFacade.getCatalogOrArchiveComponents(true, excludeTypes)
913                     .bimap(this::groupByComponentType, err -> componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(err)));
914         } finally {
915             janusGraphDao.commit();
916         }
917     }
918
919     private Map<String, List<CatalogComponent>> groupByComponentType(List<CatalogComponent> components) {
920         Map<String, List<CatalogComponent>> map = components.stream()
921                 .collect(Collectors.groupingBy(cmpt -> cmptTypeToString(cmpt.getComponentType())));
922         // fixed response for UI!!! UI need to receive always map!
923         if (map == null) {
924             map = new HashMap<>();
925         }
926         map.computeIfAbsent(RESOURCES, k -> new ArrayList());
927         map.computeIfAbsent(SERVICES, k -> new ArrayList());
928         return map;
929     }
930
931     private String cmptTypeToString(ComponentTypeEnum componentTypeEnum) {
932         switch (componentTypeEnum) {
933             case RESOURCE:
934                 return RESOURCES;
935             case SERVICE:
936                 return SERVICES;
937             default:
938                 throw new IllegalStateException("resources or services only");
939         }
940     }
941
942     public Either<List<? extends Component>, ResponseFormat> getFilteredCatalogComponents(String assetType, Map<FilterKeyEnum, Object> filters,
943                                                                                           String query) {
944         ComponentTypeEnum assetTypeEnum = AssetTypeEnum.convertToComponentTypeEnum(assetType);
945         if (query != null) {
946             Optional<NameValuePair> invalidFilter = findInvalidFilter(query, assetTypeEnum);
947             if (invalidFilter.isPresent()) {
948                 log.debug("getFilteredAssetList: invalid filter key");
949                 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_FILTER_KEY, invalidFilter.get().getName(),
950                         FilterKeyEnum.getValidFiltersByAssetType(assetTypeEnum).toString()));
951             }
952         }
953         if (MapUtils.isEmpty(filters)) {
954             Either<List<Component>, StorageOperationStatus> componentsList = toscaOperationFacade.getCatalogComponents(assetTypeEnum, null, false);
955             if (componentsList.isRight()) {
956                 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(componentsList.right().value())));
957             }
958             return Either.left(componentsList.left().value());
959         }
960         Either<List<Component>, StorageOperationStatus> result = getFilteredComponents(filters, assetTypeEnum, false);
961         // category hierarchy mismatch or category/subCategory/distributionStatus not found
962         if (result.isRight()) {
963             List<String> params = getErrorResponseParams(filters, assetTypeEnum);
964             return Either.right(componentsUtils
965                     .getResponseFormat(componentsUtils.convertFromStorageResponse(result.right().value()), params.get(0), params.get(1), params.get(2)));
966         }
967         if (result.left().value().isEmpty()) { // no assets found for requested criteria
968             return Either.right(componentsUtils.getResponseFormat(ActionStatus.NO_ASSETS_FOUND, assetType, query));
969         }
970         return Either.left(result.left().value());
971     }
972
973     private Either<List<Component>, StorageOperationStatus> getFilteredComponents(Map<FilterKeyEnum, Object> filters, ComponentTypeEnum assetType,
974                                                                                   boolean inTransaction) {
975         Either<List<Component>, StorageOperationStatus> assetResult = Either.left(new LinkedList<>());
976         if (assetType == ComponentTypeEnum.RESOURCE) {
977             assetResult = getFilteredResources(filters, inTransaction);
978         } else if (assetType == ComponentTypeEnum.SERVICE) {
979             assetResult = getFilteredServices(filters);
980         }
981         return assetResult;
982     }
983
984     private <T extends Component> Either<List<T>, StorageOperationStatus> getFilteredServices(Map<FilterKeyEnum, Object> filters) {
985         final String distributionStatus = (String) filters.get(FilterKeyEnum.DISTRIBUTION_STATUS);
986         final DistributionStatusEnum distEnum;
987         if (StringUtils.isNotBlank(distributionStatus)) {
988             distEnum = DistributionStatusEnum.findState(distributionStatus);
989             if (distEnum == null) {
990                 return Either.right(StorageOperationStatus.CATEGORY_NOT_FOUND);
991             }
992         } else {
993             distEnum = null;
994         }
995         Either<List<Service>, StorageOperationStatus> components = toscaOperationFacade.getCatalogComponents(ComponentTypeEnum.SERVICE, null, false);
996         if (components.isRight()) { // not found == empty list
997             return Either.left(new ArrayList<>());
998         }
999         final String categoryName = (String) filters.get(FilterKeyEnum.CATEGORY);
1000         Predicate<Service> servPredicate = Component::isService;
1001         if (StringUtils.isNotBlank(categoryName)) { // primary filter
1002             servPredicate = servPredicate.and(
1003                     p -> p.getCategories().parallelStream().map(CategoryDataDefinition::getName).collect(Collectors.toList()).contains(categoryName));
1004         }
1005         if (distEnum != null) {// secondary filter
1006             servPredicate = servPredicate.and(p -> p.getDistributionStatus() == distEnum);
1007         }
1008         List<Service> serviceList = components.left().value().parallelStream().filter(servPredicate).collect(Collectors.toList());
1009
1010         final String version = (String) filters.get(FilterKeyEnum.VERSION);
1011         if (StringUtils.isNotBlank(version)) {
1012             serviceList = filterServicesWithVersion(serviceList, version);
1013         }
1014         final List<String> metadata = (List<String>) filters.get(FilterKeyEnum.METADATA);
1015         if (CollectionUtils.isNotEmpty(metadata)) {
1016             serviceList = filterServicesWithMetadata(serviceList, metadata);
1017         }
1018         return Either.left((List<T>) serviceList);
1019     }
1020
1021     private List<Service> filterServicesWithMetadata(final List<Service> serviceList, final List<String> metadata) {
1022         Predicate<Service> predicate = Component::isService;
1023         final String regex = "[\\w\\.\\- ]";
1024         for (final String keyValuePair : metadata) {
1025             final Matcher matcher = Pattern.compile("(" + regex + "+)[:=](" + regex + "+)").matcher(keyValuePair);
1026             if (matcher.find()) {
1027                 predicate = predicate.and(service -> matcher.group(2).equals(service.getCategorySpecificMetadata().get(matcher.group(1))));
1028             }
1029         }
1030         return serviceList.stream().filter(predicate).collect(Collectors.toList());
1031     }
1032
1033     private List<Service> filterServicesWithVersion(final List<Service> serviceList, final String version) {
1034         String trim = version.trim();
1035         final Optional<VersionFilterEnum> versionFilter = VersionFilterEnum.getFilter(trim);
1036         if (versionFilter.isPresent()) {
1037             return versionFilter.get().filter(serviceList, trim);
1038         }
1039         return serviceList;
1040     }
1041
1042     public Either<List<? extends Component>, ResponseFormat> getCatalogComponentsByUuidAndAssetType(String assetType, String uuid) {
1043         if (assetType == null || uuid == null) {
1044             log.debug("getCatalogComponentsByUuidAndAssetType: One of the function parameteres is null");
1045             return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
1046         }
1047         ComponentTypeEnum assetTypeEnum = AssetTypeEnum.convertToComponentTypeEnum(assetType);
1048         if (assetTypeEnum == null) {
1049             log.debug("getCatalogComponentsByUuidAndAssetType: Corresponding ComponentTypeEnum not found");
1050             return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
1051         }
1052         Map<GraphPropertyEnum, Object> additionalPropertiesToMatch = new EnumMap<>(GraphPropertyEnum.class);
1053         switch (assetTypeEnum) {
1054             case RESOURCE:
1055                 additionalPropertiesToMatch.put(GraphPropertyEnum.COMPONENT_TYPE, ComponentTypeEnum.RESOURCE.name());
1056                 break;
1057             case SERVICE:
1058                 additionalPropertiesToMatch.put(GraphPropertyEnum.COMPONENT_TYPE, ComponentTypeEnum.SERVICE.name());
1059                 break;
1060             default:
1061                 log.debug("getCatalogComponentsByUuidAndAssetType: Corresponding ComponentTypeEnum not allowed for this API");
1062                 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
1063         }
1064         Either<List<Component>, StorageOperationStatus> componentsListByUuid = toscaOperationFacade
1065                 .getComponentListByUuid(uuid, additionalPropertiesToMatch);
1066         if (componentsListByUuid.isRight()) {
1067             log.debug("getCatalogComponentsByUuidAndAssetType: " + assetTypeEnum.getValue() + " fetching failed");
1068             ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(componentsListByUuid.right().value(), assetTypeEnum);
1069             return Either.right(componentsUtils.getResponseFormat(actionStatus, uuid));
1070         }
1071         log.debug("getCatalogComponentsByUuidAndAssetType: " + assetTypeEnum.getValue() + assetTypeEnum.getValue() + "fetching successful");
1072         return Either.left(componentsListByUuid.left().value());
1073     }
1074
1075     public List<String> getAllComponentTypesParamNames() {
1076         List<String> paramNames = new ArrayList<>();
1077         paramNames.add(ComponentTypeEnum.SERVICE_PARAM_NAME);
1078         paramNames.add(ComponentTypeEnum.RESOURCE_PARAM_NAME);
1079         paramNames.add(ComponentTypeEnum.PRODUCT_PARAM_NAME);
1080         return paramNames;
1081     }
1082
1083     public List<String> getAllSupportedRoles() {
1084         Role[] values = Role.values();
1085         List<String> roleNames = new ArrayList<>();
1086         for (Role role : values) {
1087             roleNames.add(role.name());
1088         }
1089         return roleNames;
1090     }
1091
1092     public Either<Map<String, String>, ActionStatus> getResourceTypesMap() {
1093         return elementOperation.getResourceTypesMap();
1094     }
1095
1096     private Optional<NameValuePair> findInvalidFilter(String query, ComponentTypeEnum assetType) {
1097         return URLEncodedUtils.parse(query, StandardCharsets.UTF_8)
1098                 .stream().filter(p -> !FilterKeyEnum.getValidFiltersByAssetType(assetType).contains(p.getName())).findAny();
1099     }
1100
1101     private List<String> getErrorResponseParams(Map<FilterKeyEnum, Object> filters, ComponentTypeEnum assetType) {
1102         List<String> params = new ArrayList<>();
1103         if (1 == filters.size()) {
1104             params.add(assetType.getValue().toLowerCase());
1105             params.add(filters.keySet().iterator().next().getName());
1106             params.add((String) filters.values().iterator().next());
1107         } else {
1108             params.add(assetType.getValue());
1109             params.add((String) filters.get(FilterKeyEnum.SUB_CATEGORY));
1110             params.add((String) filters.get(FilterKeyEnum.CATEGORY));
1111         }
1112         return params;
1113     }
1114
1115     public Either<List<Component>, StorageOperationStatus> getFilteredResources(Map<FilterKeyEnum, Object> filters, boolean inTransaction) {
1116         String subCategoryName = (String) filters.get(FilterKeyEnum.SUB_CATEGORY);
1117         String categoryName = (String) filters.get(FilterKeyEnum.CATEGORY);
1118         ResourceTypeEnum resourceType = ResourceTypeEnum.getType((String) filters.get(FilterKeyEnum.RESOURCE_TYPE));
1119         Either<List<ImmutablePair<SubCategoryData, GraphEdge>>, StorageOperationStatus> subcategories = null;
1120         Optional<ImmutablePair<SubCategoryData, GraphEdge>> subCategoryData;
1121         if (categoryName != null) {
1122             subcategories = getAllSubCategories(categoryName);
1123             if (subcategories.isRight()) {
1124                 filters.remove(FilterKeyEnum.SUB_CATEGORY);
1125                 return Either.right(subcategories.right().value());
1126             }
1127         }
1128         if (subCategoryName != null) { // primary filter
1129             if (categoryName != null) {
1130                 subCategoryData = validateCategoryHierarcy(subcategories.left().value(), subCategoryName);
1131                 if (subCategoryData.isEmpty()) {
1132                     return Either.right(StorageOperationStatus.MATCH_NOT_FOUND);
1133                 }
1134                 return fetchByCategoryOrSubCategoryUid(subCategoryData.get().getLeft().getUniqueId(), NodeTypeEnum.Resource, inTransaction,
1135                         resourceType);
1136             }
1137             return fetchByCategoryOrSubCategoryName(subCategoryName, NodeTypeEnum.ResourceSubcategory, NodeTypeEnum.Resource, inTransaction,
1138                     resourceType);
1139         }
1140         if (subcategories != null) {
1141             return fetchByMainCategory(subcategories.left().value(), inTransaction, resourceType);
1142         }
1143         return fetchComponentMetaDataByResourceType((String) filters.get(FilterKeyEnum.RESOURCE_TYPE), inTransaction);
1144     }
1145
1146     private Either<List<ImmutablePair<SubCategoryData, GraphEdge>>, StorageOperationStatus> getAllSubCategories(String categoryName) {
1147         Either<CategoryData, StorageOperationStatus> categoryResult = elementOperation
1148                 .getNewCategoryData(categoryName, NodeTypeEnum.ResourceNewCategory, CategoryData.class);
1149         if (categoryResult.isRight()) {
1150             return Either.right(categoryResult.right().value());
1151         }
1152         CategoryData categoryData = categoryResult.left().value();
1153         Either<List<ImmutablePair<SubCategoryData, GraphEdge>>, JanusGraphOperationStatus> childrenNodes = janusGraphGenericDao
1154                 .getChildrenNodes(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.ResourceNewCategory), categoryData.getUniqueId(),
1155                         GraphEdgeLabels.SUB_CATEGORY, NodeTypeEnum.ResourceSubcategory, SubCategoryData.class);
1156         if (childrenNodes.isRight()) {
1157             return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(childrenNodes.right().value()));
1158         }
1159         return Either.left(childrenNodes.left().value());
1160     }
1161
1162     private Optional<ImmutablePair<SubCategoryData, GraphEdge>> validateCategoryHierarcy(List<ImmutablePair<SubCategoryData, GraphEdge>> childNodes,
1163                                                                                          String subCategoryName) {
1164         Predicate<ImmutablePair<SubCategoryData, GraphEdge>> matchName = p -> p.getLeft().getSubCategoryDataDefinition().getName()
1165                 .equals(subCategoryName);
1166         return childNodes.stream().filter(matchName).findAny();
1167     }
1168
1169     protected <T extends Component> Either<List<T>, StorageOperationStatus> fetchByCategoryOrSubCategoryUid(String categoryUid,
1170                                                                                                             NodeTypeEnum categoryType,
1171                                                                                                             boolean inTransaction,
1172                                                                                                             ResourceTypeEnum resourceType) {
1173         try {
1174             return collectComponents(categoryType, categoryUid, resourceType);
1175         } finally {
1176             if (!inTransaction) {
1177                 janusGraphDao.commit();
1178             }
1179         }
1180     }
1181
1182     protected <T extends Component> Either<List<T>, StorageOperationStatus> fetchByCategoryOrSubCategoryName(String categoryName,
1183                                                                                                              NodeTypeEnum categoryType,
1184                                                                                                              NodeTypeEnum neededType,
1185                                                                                                              boolean inTransaction,
1186                                                                                                              ResourceTypeEnum resourceType) {
1187         List<T> components = new ArrayList<>();
1188         try {
1189             Class<? extends GraphNode> categoryClazz = categoryType == NodeTypeEnum.ServiceNewCategory ? CategoryData.class : SubCategoryData.class;
1190             Map<String, Object> props = new HashMap<>();
1191             props.put(GraphPropertiesDictionary.NORMALIZED_NAME.getProperty(), ValidationUtils.normalizeCategoryName4Uniqueness(categoryName));
1192             Either<List<GraphNode>, JanusGraphOperationStatus> getCategory = janusGraphGenericDao.getByCriteria(categoryType, props,
1193                     (Class<GraphNode>) categoryClazz);
1194             if (getCategory.isRight()) {
1195                 return Either.right(StorageOperationStatus.CATEGORY_NOT_FOUND);
1196             }
1197             for (GraphNode category : getCategory.left().value()) {
1198                 Either<List<T>, StorageOperationStatus> result = collectComponents(neededType, category.getUniqueId(), resourceType);
1199                 if (result.isRight() && result.right().value() != StorageOperationStatus.NOT_FOUND) {
1200                     return result;
1201                 } else if (result.isLeft()) {
1202                     components.addAll(result.left().value());
1203                 }
1204             }
1205             if (components.isEmpty()) {
1206                 return Either.right(StorageOperationStatus.NOT_FOUND);
1207             }
1208             return Either.left(components);
1209         } finally {
1210             if (!inTransaction) {
1211                 janusGraphDao.commit();
1212             }
1213         }
1214     }
1215
1216     private <T extends Component> Either<List<T>, StorageOperationStatus> collectComponents(NodeTypeEnum neededType, String categoryUid,
1217                                                                                             ResourceTypeEnum resourceType) {
1218         List<T> components = new ArrayList<>();
1219         Either<GraphVertex, JanusGraphOperationStatus> categoryVertexById = janusGraphDao.getVertexById(categoryUid, JsonParseFlagEnum.NoParse);
1220         if (categoryVertexById.isRight()) {
1221             JanusGraphOperationStatus status = categoryVertexById.right().value();
1222             log.debug("#collectComponents Failed to get category vertex with uid {}, status is {}.", categoryUid, status);
1223             return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status));
1224         }
1225         GraphVertex categoryVertex = categoryVertexById.left().value();
1226         Either<List<GraphVertex>, JanusGraphOperationStatus> componentsVertices = janusGraphDao
1227                 .getParentVertices(categoryVertex, EdgeLabelEnum.CATEGORY, JsonParseFlagEnum.ParseMetadata);
1228         if (componentsVertices.isRight()) {
1229             JanusGraphOperationStatus status = componentsVertices.right().value();
1230             log.debug("#collectComponents Failed to get components vertices of category {}, status is {}.", categoryVertex, status);
1231             return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status));
1232         }
1233         List<ComponentMetadataDataDefinition> componentsMetadataDataDefinition = componentsVertices.left().value().stream().filter(Objects::nonNull)
1234                 .filter(componentsVertex -> Objects.nonNull(componentsVertex.getType())).map(ModelConverter::convertToComponentMetadataDataDefinition)
1235                 .collect(Collectors.toList());
1236         for (ComponentMetadataDataDefinition component : componentsMetadataDataDefinition) {
1237             boolean isHighest = isTrue(component.isHighestVersion());
1238             boolean isMatchingResourceType = isMatchingByResourceType(neededType, resourceType, component);
1239             boolean isDeleted = isTrue(component.isDeleted());
1240             boolean isArchived = isTrue(component.isArchived());
1241             if (isHighest && isMatchingResourceType && !isDeleted && !isArchived) {
1242                 Either<T, StorageOperationStatus> result = toscaOperationFacade
1243                         .getToscaElement(component.getUniqueId(), JsonParseFlagEnum.ParseMetadata);
1244                 if (result.isRight()) {
1245                     return Either.right(result.right().value());
1246                 }
1247                 components.add(result.left().value());
1248             }
1249         }
1250         return Either.left(components);
1251     }
1252
1253     private boolean isMatchingByResourceType(NodeTypeEnum componentType, ResourceTypeEnum resourceType,
1254                                              ComponentMetadataDataDefinition componentData) {
1255         boolean isMatching;
1256         if (componentType == NodeTypeEnum.Resource) {
1257             if (resourceType == null) {
1258                 isMatching = true;
1259             } else {
1260                 isMatching = resourceType == ((ResourceMetadataDataDefinition) componentData).getResourceType();
1261             }
1262         } else {
1263             isMatching = true;
1264         }
1265         return isMatching;
1266     }
1267
1268     private <T extends Component> Either<List<T>, StorageOperationStatus> fetchByMainCategory(
1269             List<ImmutablePair<SubCategoryData, GraphEdge>> subcategories, boolean inTransaction, ResourceTypeEnum resourceType) {
1270         List<T> components = new ArrayList<>();
1271         for (ImmutablePair<SubCategoryData, GraphEdge> subCategory : subcategories) {
1272             Either<List<T>, StorageOperationStatus> fetched = fetchByCategoryOrSubCategoryUid(subCategory.getLeft().getUniqueId(),
1273                     NodeTypeEnum.Resource, inTransaction, resourceType);
1274             if (fetched.isRight()) {
1275                 continue;
1276             }
1277             components.addAll(fetched.left().value());
1278         }
1279         return Either.left(components);
1280     }
1281
1282     private Either<List<Component>, StorageOperationStatus> fetchComponentMetaDataByResourceType(String resourceType, boolean inTransaction) {
1283         List<Component> components = null;
1284         StorageOperationStatus status;
1285         Wrapper<StorageOperationStatus> statusWrapper = new Wrapper<>();
1286         try {
1287             ComponentParametersView fetchUsersAndCategoriesFilter = new ComponentParametersView(
1288                     Arrays.asList(ComponentFieldsEnum.USERS.getValue(), ComponentFieldsEnum.CATEGORIES.getValue()));
1289             Either<List<Component>, StorageOperationStatus> getResources = toscaOperationFacade
1290                     .fetchMetaDataByResourceType(resourceType, fetchUsersAndCategoriesFilter);
1291             if (getResources.isRight()) {
1292                 status = getResources.right().value();
1293                 if (status != StorageOperationStatus.NOT_FOUND) {
1294                     statusWrapper.setInnerElement(getResources.right().value());
1295                 } else {
1296                     components = new ArrayList<>();
1297                 }
1298             } else {
1299                 components = getResources.left().value();
1300             }
1301             if (statusWrapper.isEmpty()) {
1302                 return Either.left(components);
1303             } else {
1304                 return Either.right(statusWrapper.getInnerElement());
1305             }
1306         } finally {
1307             if (!inTransaction) {
1308                 janusGraphDao.commit();
1309             }
1310         }
1311     }
1312
1313     public CatalogUpdateTimestamp getCatalogUpdateTime() {
1314         try {
1315             return toscaOperationFacade.getCatalogTimes();
1316         } finally {
1317             janusGraphDao.commit();
1318         }
1319     }
1320
1321     public Either<List<BaseType>, ActionStatus> getBaseTypes(final String categoryName, final String userId, final String modelName) {
1322         final ActionStatus status = validateUserExistsActionStatus(userId);
1323         if (ActionStatus.OK != status) {
1324             return Either.right(status);
1325         }
1326         return Either.left(elementOperation.getServiceBaseTypes(categoryName, modelName));
1327     }
1328
1329     /**
1330      * Checks if a category requires a base type.
1331      *
1332      * @param categoryName the category name
1333      * @return {@code true} if a base type is required, {@code false} otherwise.
1334      */
1335     public boolean isBaseTypeRequired(final String categoryName) {
1336         return elementOperation.isBaseTypeRequired(categoryName);
1337     }
1338
1339     /**
1340      * Fetches default baseType from the template.
1341      *
1342      * @param categoryName the category name
1343      * @return defaultBaseType mapped to the corresponding category name.
1344      */
1345     public String getDefaultBaseType(final String categoryName) {
1346         return elementOperation.getDefaultBaseType(categoryName);
1347     }
1348
1349     public boolean isDoNotExtendBaseType(final String categoryName) {
1350         return elementOperation.isDoNotExtendBaseType(categoryName);
1351     }
1352 }