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