Configure a new Artifact Type
[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(final String userId) {
952         ActionStatus status = validateUserExistsActionStatus(userId);
953         if (ActionStatus.OK != status) {
954             return Either.right(status);
955         }
956         return Either.left(elementOperation.getAllArtifactTypes());
957     }
958
959     public Either<Configuration.HeatDeploymentArtifactTimeout, ActionStatus> getDefaultHeatTimeout() {
960         return elementOperation.getDefaultHeatTimeout();
961     }
962
963         public Either<Map<String, List<CatalogComponent>>, ResponseFormat> getCatalogComponents(String userId, List<OriginTypeEnum> excludeTypes) {
964         try {
965             return toscaOperationFacade.getCatalogOrArchiveComponents(true, excludeTypes)
966                     .bimap(this::groupByComponentType,
967                             err -> componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(err)));
968         } finally {
969             janusGraphDao.commit();
970         }
971     }
972
973     private Map<String, List<CatalogComponent>> groupByComponentType(List<CatalogComponent> components) {
974         Map<String, List<CatalogComponent>> map = components.stream().collect(Collectors.groupingBy(cmpt -> cmptTypeToString(cmpt.getComponentType())));
975
976         // fixed response for UI!!! UI need to receive always map!
977         if (map == null) {
978             map = new HashMap<>();
979         }
980         map.computeIfAbsent(RESOURCES, k -> new ArrayList());
981         map.computeIfAbsent(SERVICES, k -> new ArrayList());
982         return map;
983     }
984
985     private String cmptTypeToString(ComponentTypeEnum componentTypeEnum) {
986         switch (componentTypeEnum) {
987         case RESOURCE:
988             return RESOURCES;
989         case SERVICE:
990             return SERVICES;
991         default:
992             throw new IllegalStateException("resources or services only");
993         }
994     }
995
996     public Either<List<? extends Component>, ResponseFormat> getFilteredCatalogComponents(String assetType, Map<FilterKeyEnum, String> filters, String query) {
997         ComponentTypeEnum assetTypeEnum = AssetTypeEnum.convertToComponentTypeEnum(assetType);
998
999         if (query != null) {
1000             Optional<NameValuePair> invalidFilter = findInvalidFilter(query, assetTypeEnum);
1001             if (invalidFilter.isPresent()) {
1002                 log.debug("getFilteredAssetList: invalid filter key");
1003                 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_FILTER_KEY, invalidFilter.get().getName(), FilterKeyEnum.getValidFiltersByAssetType(assetTypeEnum).toString()));
1004             }
1005         }
1006
1007         if (filters == null || filters.isEmpty()) {
1008             Either<List<Component>, StorageOperationStatus> componentsList = toscaOperationFacade.getCatalogComponents(assetTypeEnum, null, false);
1009             if (componentsList.isRight()) {
1010                 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(componentsList.right().value())));
1011             }
1012             return Either.left(componentsList.left().value());
1013         }
1014
1015         Either<List<Component>, StorageOperationStatus> result = getFilteredComponents(filters, assetTypeEnum, false);
1016
1017         // category hierarchy mismatch or category/subCategory/distributionStatus not found
1018         if (result.isRight()) {
1019             List<String> params = getErrorResponseParams(filters, assetTypeEnum);
1020             return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(result.right().value()), params.get(0), params.get(1), params.get(2)));
1021         }
1022         if (result.left().value().isEmpty()) {// no assets found for requested
1023                                               // criteria
1024             return Either.right(componentsUtils.getResponseFormat(ActionStatus.NO_ASSETS_FOUND, assetType, query));
1025         }
1026         return Either.left(result.left().value());
1027     }
1028
1029     private Either<List<Component>, StorageOperationStatus> getFilteredComponents(Map<FilterKeyEnum, String> filters, ComponentTypeEnum assetType, boolean inTransaction) {
1030         Either<List<Component>, StorageOperationStatus> assetResult = Either.left(new LinkedList<>());
1031         if (assetType == ComponentTypeEnum.RESOURCE) {
1032
1033             assetResult = getFilteredResources(filters, inTransaction);
1034
1035         } else if (assetType == ComponentTypeEnum.SERVICE) {
1036
1037             assetResult = getFilteredServices(filters, inTransaction);
1038         }
1039         return assetResult;
1040     }
1041
1042     private <T extends Component> Either<List<T>, StorageOperationStatus> getFilteredServices(Map<FilterKeyEnum, String> filters, boolean inTransaction) {
1043
1044         Either<List<T>, StorageOperationStatus> components = null;
1045
1046         String categoryName = filters.get(FilterKeyEnum.CATEGORY);
1047         String distributionStatus = filters.get(FilterKeyEnum.DISTRIBUTION_STATUS);
1048         DistributionStatusEnum distEnum = DistributionStatusEnum.findState(distributionStatus);
1049         if (distributionStatus != null && distEnum == null) {
1050             filters.remove(FilterKeyEnum.CATEGORY);
1051             return Either.right(StorageOperationStatus.CATEGORY_NOT_FOUND);
1052         }
1053
1054         if (categoryName != null) { // primary filter
1055             components = fetchByCategoryOrSubCategoryName(categoryName, NodeTypeEnum.ServiceNewCategory, NodeTypeEnum.Service, inTransaction, null);
1056             if (components.isLeft() && distEnum != null) {// secondary filter
1057                 Predicate<T> statusFilter = p -> ((Service) p).getDistributionStatus() == distEnum;
1058                 return Either.left(components.left().value().stream().filter(statusFilter).collect(Collectors.toList()));
1059             }
1060             filters.remove(FilterKeyEnum.DISTRIBUTION_STATUS);
1061             return components;
1062         }
1063
1064         Set<DistributionStatusEnum> distStatusSet = new HashSet<>();
1065         distStatusSet.add(distEnum);
1066         Either<List<Service>, StorageOperationStatus> servicesWithDistStatus = toscaOperationFacade.getServicesWithDistStatus(distStatusSet, null);
1067         if (servicesWithDistStatus.isRight()) { // not found == empty list
1068             return Either.left(new ArrayList<>());
1069         }
1070
1071         return Either.left((List<T>) servicesWithDistStatus.left().value());
1072     }
1073
1074     public Either<List<? extends Component>, ResponseFormat> getCatalogComponentsByUuidAndAssetType(String assetType, String uuid) {
1075
1076         if (assetType == null || uuid == null) {
1077             log.debug("getCatalogComponentsByUuidAndAssetType: One of the function parameteres is null");
1078             return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
1079         }
1080
1081         ComponentTypeEnum assetTypeEnum = AssetTypeEnum.convertToComponentTypeEnum(assetType);
1082
1083         if (assetTypeEnum == null) {
1084             log.debug("getCatalogComponentsByUuidAndAssetType: Corresponding ComponentTypeEnum not found");
1085             return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
1086         }
1087
1088         Map<GraphPropertyEnum, Object> additionalPropertiesToMatch = new EnumMap<>(GraphPropertyEnum.class);
1089
1090         switch (assetTypeEnum) {
1091         case RESOURCE:
1092             additionalPropertiesToMatch.put(GraphPropertyEnum.COMPONENT_TYPE, ComponentTypeEnum.RESOURCE.name());
1093             break;
1094         case SERVICE:
1095             additionalPropertiesToMatch.put(GraphPropertyEnum.COMPONENT_TYPE, ComponentTypeEnum.SERVICE.name());
1096             break;
1097         default:
1098             log.debug("getCatalogComponentsByUuidAndAssetType: Corresponding ComponentTypeEnum not allowed for this API");
1099             return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
1100         }
1101
1102         Either<List<Component>, StorageOperationStatus> componentsListByUuid = toscaOperationFacade.getComponentListByUuid(uuid, additionalPropertiesToMatch);
1103         if (componentsListByUuid.isRight()) {
1104             log.debug("getCatalogComponentsByUuidAndAssetType: " + assetTypeEnum.getValue() + " fetching failed");
1105             ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(componentsListByUuid.right().value(), assetTypeEnum);
1106             return Either.right(componentsUtils.getResponseFormat(actionStatus, uuid));
1107         }
1108
1109         log.debug("getCatalogComponentsByUuidAndAssetType: " + assetTypeEnum.getValue() + assetTypeEnum.getValue() + "fetching successful");
1110         return Either.left(componentsListByUuid.left().value());
1111     }
1112
1113     public List<String> getAllComponentTypesParamNames() {
1114         List<String> paramNames = new ArrayList<>();
1115         paramNames.add(ComponentTypeEnum.SERVICE_PARAM_NAME);
1116         paramNames.add(ComponentTypeEnum.RESOURCE_PARAM_NAME);
1117         paramNames.add(ComponentTypeEnum.PRODUCT_PARAM_NAME);
1118         return paramNames;
1119     }
1120
1121     public List<String> getAllSupportedRoles() {
1122         Role[] values = Role.values();
1123         List<String> roleNames = new ArrayList<>();
1124         for (Role role : values) {
1125             roleNames.add(role.name());
1126         }
1127         return roleNames;
1128     }
1129
1130     public Either<Map<String, String>, ActionStatus> getResourceTypesMap() {
1131         return elementOperation.getResourceTypesMap();
1132     }
1133
1134     private Optional<NameValuePair> findInvalidFilter(String query, ComponentTypeEnum assetType) {
1135         List<NameValuePair> params = URLEncodedUtils.parse(query, StandardCharsets.UTF_8);
1136         List<String> validKeys = FilterKeyEnum.getValidFiltersByAssetType(assetType);
1137         Predicate<NameValuePair> noMatch = p -> !validKeys.contains(p.getName());
1138         return params.stream().filter(noMatch).findAny();
1139     }
1140
1141     private List<String> getErrorResponseParams(Map<FilterKeyEnum, String> filters, ComponentTypeEnum assetType) {
1142         List<String> params = new ArrayList<>();
1143         if (1 == filters.size()) {
1144             params.add(assetType.getValue().toLowerCase());
1145             params.add(filters.keySet().iterator().next().getName());
1146             params.add(filters.values().iterator().next());
1147         } else {
1148             params.add(assetType.getValue());
1149             params.add(filters.get(FilterKeyEnum.SUB_CATEGORY));
1150             params.add(filters.get(FilterKeyEnum.CATEGORY));
1151         }
1152         return params;
1153     }
1154
1155     public Either<List<Component>, StorageOperationStatus> getFilteredResources(Map<FilterKeyEnum, String> filters, boolean inTransaction) {
1156
1157         String subCategoryName = filters.get(FilterKeyEnum.SUB_CATEGORY);
1158         String categoryName = filters.get(FilterKeyEnum.CATEGORY);
1159         ResourceTypeEnum resourceType = ResourceTypeEnum.getType(filters.get(FilterKeyEnum.RESOURCE_TYPE));
1160         Either<List<ImmutablePair<SubCategoryData, GraphEdge>>, StorageOperationStatus> subcategories = null;
1161         Optional<ImmutablePair<SubCategoryData, GraphEdge>> subCategoryData;
1162
1163         if (categoryName != null) {
1164             subcategories = getAllSubCategories(categoryName);
1165             if (subcategories.isRight()) {
1166                 filters.remove(FilterKeyEnum.SUB_CATEGORY);
1167                 return Either.right(subcategories.right().value());
1168             }
1169         }
1170         if (subCategoryName != null) { // primary filter
1171             if (categoryName != null) {
1172                 subCategoryData = validateCategoryHierarcy(subcategories.left().value(), subCategoryName);
1173                 if (!subCategoryData.isPresent()) {
1174                     return Either.right(StorageOperationStatus.MATCH_NOT_FOUND);
1175                 }
1176                 return fetchByCategoryOrSubCategoryUid(subCategoryData.get().getLeft().getUniqueId(), NodeTypeEnum.Resource, inTransaction, resourceType);
1177             }
1178
1179             return fetchByCategoryOrSubCategoryName(subCategoryName, NodeTypeEnum.ResourceSubcategory, NodeTypeEnum.Resource, inTransaction, resourceType);
1180         }
1181         if (subcategories != null) {
1182             return fetchByMainCategory(subcategories.left().value(), inTransaction, resourceType);
1183         }
1184         return fetchComponentMetaDataByResourceType(filters.get(FilterKeyEnum.RESOURCE_TYPE), inTransaction);
1185     }
1186
1187     private Either<List<ImmutablePair<SubCategoryData, GraphEdge>>, StorageOperationStatus> getAllSubCategories(String categoryName) {
1188         Either<CategoryData, StorageOperationStatus> categoryResult = elementOperation.getNewCategoryData(categoryName, NodeTypeEnum.ResourceNewCategory, CategoryData.class);
1189         if (categoryResult.isRight()) {
1190             return Either.right(categoryResult.right().value());
1191         }
1192         CategoryData categoryData = categoryResult.left().value();
1193
1194         Either<List<ImmutablePair<SubCategoryData, GraphEdge>>, JanusGraphOperationStatus> childrenNodes = janusGraphGenericDao
1195             .getChildrenNodes(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.ResourceNewCategory), (String) categoryData.getUniqueId(),
1196                 GraphEdgeLabels.SUB_CATEGORY, NodeTypeEnum.ResourceSubcategory, SubCategoryData.class);
1197         if (childrenNodes.isRight()) {
1198             return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(childrenNodes.right().value()));
1199         }
1200         return Either.left(childrenNodes.left().value());
1201     }
1202
1203     private Optional<ImmutablePair<SubCategoryData, GraphEdge>> validateCategoryHierarcy(List<ImmutablePair<SubCategoryData, GraphEdge>> childNodes, String subCategoryName) {
1204         Predicate<ImmutablePair<SubCategoryData, GraphEdge>> matchName = p -> p.getLeft().getSubCategoryDataDefinition().getName().equals(subCategoryName);
1205         return childNodes.stream().filter(matchName).findAny();
1206     }
1207
1208     protected <T extends Component> Either<List<T>, StorageOperationStatus> fetchByCategoryOrSubCategoryUid(String categoryUid, NodeTypeEnum categoryType, boolean inTransaction, ResourceTypeEnum resourceType) {
1209         try {
1210             return collectComponents(categoryType, categoryUid, resourceType);
1211         } finally {
1212             if (!inTransaction) {
1213                 janusGraphDao.commit();
1214             }
1215         }
1216     }
1217
1218     protected <T extends Component> Either<List<T>, StorageOperationStatus> fetchByCategoryOrSubCategoryName(String categoryName, NodeTypeEnum categoryType, NodeTypeEnum neededType, boolean inTransaction, ResourceTypeEnum resourceType) {
1219         List<T> components = new ArrayList<>();
1220         try {
1221             Class categoryClazz = categoryType == NodeTypeEnum.ServiceNewCategory ? CategoryData.class : SubCategoryData.class;
1222             Map<String, Object> props = new HashMap<>();
1223             props.put(GraphPropertiesDictionary.NORMALIZED_NAME.getProperty(), ValidationUtils.normalizeCategoryName4Uniqueness(categoryName));
1224             Either<List<GraphNode>, JanusGraphOperationStatus> getCategory = janusGraphGenericDao.getByCriteria(categoryType, props, categoryClazz);
1225             if (getCategory.isRight()) {
1226                 return Either.right(StorageOperationStatus.CATEGORY_NOT_FOUND);
1227             }
1228             for (GraphNode category : getCategory.left().value()) {
1229                 Either<List<T>, StorageOperationStatus> result = collectComponents(neededType, category.getUniqueId(), resourceType);
1230                 if (result.isRight() && result.right().value() != StorageOperationStatus.NOT_FOUND) {
1231                     return result;
1232                 } else if (result.isLeft()){
1233                     components.addAll(result.left().value());
1234                 }
1235             }
1236             if (components.isEmpty()){
1237                 return Either.right(StorageOperationStatus.NOT_FOUND);
1238             }
1239             return Either.left(components);
1240         } finally {
1241             if (!inTransaction) {
1242                 janusGraphDao.commit();
1243             }
1244         }
1245     }
1246
1247
1248     private <T extends Component> Either<List<T>, StorageOperationStatus> collectComponents(NodeTypeEnum neededType, String categoryUid, ResourceTypeEnum resourceType) {
1249         List<T> components = new ArrayList<>();
1250         Either<GraphVertex, JanusGraphOperationStatus> categoryVertexById = janusGraphDao.getVertexById(categoryUid, JsonParseFlagEnum.NoParse);
1251         if (categoryVertexById.isRight()){
1252             JanusGraphOperationStatus status = categoryVertexById.right().value();
1253             log.debug("#collectComponents Failed to get category vertex with uid {}, status is {}.", categoryUid, status);
1254             return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status));
1255         }
1256         GraphVertex categoryVertex = categoryVertexById.left().value();
1257         Either<List<GraphVertex>, JanusGraphOperationStatus> componentsVertices = janusGraphDao.getParentVertices(categoryVertex, EdgeLabelEnum.CATEGORY, JsonParseFlagEnum.ParseMetadata);
1258         if (componentsVertices.isRight()){
1259             JanusGraphOperationStatus status = componentsVertices.right().value();
1260             log.debug("#collectComponents Failed to get components vertices of category {}, status is {}.", categoryVertex, status);
1261             return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status));
1262         }
1263         List<ComponentMetadataDataDefinition> componentsMetadataDataDefinition = componentsVertices.left().value()
1264                 .stream()
1265                 .filter(Objects::nonNull)
1266                 .filter(componentsVertex -> Objects.nonNull(componentsVertex.getType()))
1267                 .map(ModelConverter::convertToComponentMetadataDataDefinition)
1268                 .collect(Collectors.toList());
1269         for (ComponentMetadataDataDefinition component : componentsMetadataDataDefinition) {
1270             boolean isHighest = isTrue(component.isHighestVersion());
1271             boolean isMatchingResourceType = isMatchingByResourceType(neededType, resourceType, component);
1272             boolean isDeleted = isTrue(component.isDeleted());
1273             boolean isArchived = isTrue(component.isArchived());
1274             if (isHighest && isMatchingResourceType && !isDeleted && !isArchived) {
1275                 Either<T, StorageOperationStatus> result = toscaOperationFacade.getToscaElement(component.getUniqueId(), JsonParseFlagEnum.ParseMetadata);
1276                  if (result.isRight()) {
1277                     return Either.right(result.right().value());
1278                 }
1279                 components.add(result.left().value());
1280             }
1281         }
1282         return Either.left(components);
1283     }
1284
1285     private boolean isMatchingByResourceType(NodeTypeEnum componentType, ResourceTypeEnum resourceType, ComponentMetadataDataDefinition componentData) {
1286
1287         boolean isMatching;
1288         if (componentType == NodeTypeEnum.Resource) {
1289             if (resourceType == null) {
1290                 isMatching = true;
1291             } else {
1292                 isMatching = resourceType == ((ResourceMetadataDataDefinition) componentData).getResourceType();
1293             }
1294         } else {
1295             isMatching = true;
1296         }
1297         return isMatching;
1298     }
1299
1300     private <T extends Component> Either<List<T>, StorageOperationStatus> fetchByMainCategory(List<ImmutablePair<SubCategoryData, GraphEdge>> subcategories, boolean inTransaction, ResourceTypeEnum resourceType) {
1301         List<T> components = new ArrayList<>();
1302
1303         for (ImmutablePair<SubCategoryData, GraphEdge> subCategory : subcategories) {
1304             Either<List<T>, StorageOperationStatus> fetched = fetchByCategoryOrSubCategoryUid(subCategory.getLeft().getUniqueId(), NodeTypeEnum.Resource,
1305                     inTransaction, resourceType);
1306             if (fetched.isRight()) {
1307                 continue;
1308             }
1309             components.addAll(fetched.left().value());
1310         }
1311         return Either.left(components);
1312     }
1313
1314     private Either<List<Component>, StorageOperationStatus> fetchComponentMetaDataByResourceType(String resourceType, boolean inTransaction) {
1315         List<Component> components = null;
1316         StorageOperationStatus status;
1317         Wrapper<StorageOperationStatus> statusWrapper = new Wrapper<>();
1318         Either<List<Component>, StorageOperationStatus> result;
1319         try {
1320             ComponentParametersView fetchUsersAndCategoriesFilter = new ComponentParametersView(Arrays.asList(ComponentFieldsEnum.USERS.getValue(), ComponentFieldsEnum.CATEGORIES.getValue()));
1321             Either<List<Component>, StorageOperationStatus> getResources = toscaOperationFacade.fetchMetaDataByResourceType(resourceType, fetchUsersAndCategoriesFilter);
1322             if (getResources.isRight()) {
1323                 status = getResources.right().value();
1324                 if (status != StorageOperationStatus.NOT_FOUND) {
1325                     statusWrapper.setInnerElement(getResources.right().value());
1326                 } else {
1327                     components = new ArrayList<>();
1328                 }
1329             } else {
1330                 components = getResources.left().value();
1331             }
1332             if (!statusWrapper.isEmpty()) {
1333                 result = Either.right(statusWrapper.getInnerElement());
1334             } else {
1335                 result = Either.left(components);
1336             }
1337             return result;
1338         } finally {
1339             if (!inTransaction) {
1340                 janusGraphDao.commit();
1341             }
1342         }
1343     }
1344
1345
1346     public CatalogUpdateTimestamp getCatalogUpdateTime(String userId) {
1347
1348         try{
1349             return toscaOperationFacade.getCatalogTimes();
1350
1351         } finally {
1352             janusGraphDao.commit();
1353         }
1354
1355     }
1356 }