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