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