2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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 * ================================================================================
22 package org.openecomp.sdc.be.components.impl;
24 import static org.apache.commons.lang.BooleanUtils.isTrue;
25 import static org.openecomp.sdc.be.components.impl.ImportUtils.Constants.DEFAULT_ICON;
27 import fj.data.Either;
28 import java.nio.charset.StandardCharsets;
29 import java.util.ArrayList;
30 import java.util.Arrays;
31 import java.util.EnumMap;
32 import java.util.HashMap;
33 import java.util.HashSet;
34 import java.util.LinkedList;
35 import java.util.List;
37 import java.util.Objects;
38 import java.util.Optional;
40 import java.util.function.Predicate;
41 import java.util.stream.Collectors;
42 import org.apache.commons.lang3.tuple.ImmutablePair;
43 import org.apache.http.NameValuePair;
44 import org.apache.http.client.utils.URLEncodedUtils;
45 import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
46 import org.openecomp.sdc.be.components.impl.exceptions.ByResponseFormatComponentException;
47 import org.openecomp.sdc.be.config.Configuration;
48 import org.openecomp.sdc.be.dao.api.ActionStatus;
49 import org.openecomp.sdc.be.dao.graph.datatype.GraphEdge;
50 import org.openecomp.sdc.be.dao.graph.datatype.GraphNode;
51 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
52 import org.openecomp.sdc.be.dao.jsongraph.GraphVertex;
53 import org.openecomp.sdc.be.dao.jsongraph.types.EdgeLabelEnum;
54 import org.openecomp.sdc.be.dao.jsongraph.types.JsonParseFlagEnum;
55 import org.openecomp.sdc.be.dao.neo4j.GraphEdgeLabels;
56 import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary;
57 import org.openecomp.sdc.be.datamodel.api.CategoryTypeEnum;
58 import org.openecomp.sdc.be.datamodel.utils.NodeTypeConvertUtils;
59 import org.openecomp.sdc.be.datatypes.components.ComponentMetadataDataDefinition;
60 import org.openecomp.sdc.be.datatypes.components.ResourceMetadataDataDefinition;
61 import org.openecomp.sdc.be.datatypes.enums.AssetTypeEnum;
62 import org.openecomp.sdc.be.datatypes.enums.ComponentFieldsEnum;
63 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
64 import org.openecomp.sdc.be.datatypes.enums.FilterKeyEnum;
65 import org.openecomp.sdc.be.datatypes.enums.GraphPropertyEnum;
66 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
67 import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum;
68 import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
69 import org.openecomp.sdc.be.model.ArtifactType;
70 import org.openecomp.sdc.be.model.BaseType;
71 import org.openecomp.sdc.be.model.CatalogUpdateTimestamp;
72 import org.openecomp.sdc.be.model.Component;
73 import org.openecomp.sdc.be.model.ComponentParametersView;
74 import org.openecomp.sdc.be.model.DistributionStatusEnum;
75 import org.openecomp.sdc.be.model.LifecycleStateEnum;
76 import org.openecomp.sdc.be.model.Product;
77 import org.openecomp.sdc.be.model.PropertyScope;
78 import org.openecomp.sdc.be.model.Resource;
79 import org.openecomp.sdc.be.model.Service;
80 import org.openecomp.sdc.be.model.Tag;
81 import org.openecomp.sdc.be.model.User;
82 import org.openecomp.sdc.be.model.catalog.CatalogComponent;
83 import org.openecomp.sdc.be.model.category.CategoryDefinition;
84 import org.openecomp.sdc.be.model.category.GroupingDefinition;
85 import org.openecomp.sdc.be.model.category.SubCategoryDefinition;
86 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ArtifactsOperations;
87 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.InterfaceOperation;
88 import org.openecomp.sdc.be.model.jsonjanusgraph.utils.ModelConverter;
89 import org.openecomp.sdc.be.model.operations.api.IElementOperation;
90 import org.openecomp.sdc.be.model.operations.api.IGroupInstanceOperation;
91 import org.openecomp.sdc.be.model.operations.api.IGroupOperation;
92 import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation;
93 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
94 import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter;
95 import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation;
96 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
97 import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
98 import org.openecomp.sdc.be.resources.data.category.CategoryData;
99 import org.openecomp.sdc.be.resources.data.category.SubCategoryData;
100 import org.openecomp.sdc.be.ui.model.UiCategories;
101 import org.openecomp.sdc.be.user.Role;
102 import org.openecomp.sdc.be.user.UserBusinessLogic;
103 import org.openecomp.sdc.common.datastructure.Wrapper;
104 import org.openecomp.sdc.common.log.wrappers.Logger;
105 import org.openecomp.sdc.common.util.ValidationUtils;
106 import org.openecomp.sdc.exception.ResponseFormat;
107 import org.springframework.beans.factory.annotation.Autowired;
109 @org.springframework.stereotype.Component("elementsBusinessLogic")
110 public class ElementBusinessLogic extends BaseBusinessLogic {
112 private static final Logger log = Logger.getLogger(ElementBusinessLogic.class);
113 private static final String SERVICES = "services";
114 private static final String RESOURCES = "resources";
115 private static final String VALIDATION_OF_USER_FAILED_USER_ID = "Validation of user failed, userId {}";
116 private static final String COMPONENT_TYPE_IS_INVALID = "Component type {} is invalid";
117 private static final String VALIDATION_OF_USER_ROLE_FAILED_USER_ID = "Validation of user role failed, userId {}";
118 private final IElementOperation elementOperation;
121 public ElementBusinessLogic(IElementOperation elementDao, IGroupOperation groupOperation, IGroupInstanceOperation groupInstanceOperation,
122 IGroupTypeOperation groupTypeOperation, GroupBusinessLogic groupBusinessLogic, InterfaceOperation interfaceOperation,
123 InterfaceLifecycleOperation interfaceLifecycleTypeOperation, ArtifactsOperations artifactToscaOperation,
124 IElementOperation elementOperation, UserBusinessLogic userAdminManager) {
125 super(elementDao, groupOperation, groupInstanceOperation, groupTypeOperation, interfaceOperation, interfaceLifecycleTypeOperation,
126 artifactToscaOperation);
127 this.elementOperation = elementOperation;
134 public Either<Map<String, List<? extends Component>>, ResponseFormat> getFollowed(User user) {
135 // Used for not getting duplicated followed. Cheaper than checking ArrayList.contains
136 Either<Map<String, Set<? extends Component>>, ResponseFormat> response = null;
138 String role = user.getRole();
139 String userId = user.getUserId();
140 Role currentRole = Role.valueOf(role);
141 switch (currentRole) {
143 response = handleDesigner(userId);
145 case PRODUCT_STRATEGIST:
146 response = handleProductStrategist();
148 case PRODUCT_MANAGER:
149 response = handleProductManager(userId);
152 response = handleAdmin();
155 response = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
158 // converting the Set to List so the rest of the code will handle it normally (Was changed because the same element with the same uuid was returned twice)
159 return convertedToListResponse(response);
162 private Either<Map<String, List<? extends Component>>, ResponseFormat> convertedToListResponse(
163 Either<Map<String, Set<? extends Component>>, ResponseFormat> setResponse) {
164 Map<String, List<? extends Component>> arrayResponse = new HashMap<>();
165 if (setResponse.isLeft()) {
166 for (Map.Entry<String, Set<? extends Component>> entry : setResponse.left().value().entrySet()) {
167 arrayResponse.put(entry.getKey(), new ArrayList(new HashSet(entry.getValue())));
169 return Either.left(arrayResponse);
171 return Either.right(setResponse.right().value());
174 private Either<Map<String, Set<? extends Component>>, ResponseFormat> handleAdmin() {
175 Either<Map<String, Set<? extends Component>>, ResponseFormat> response;
176 // userId should stay null
177 Set<LifecycleStateEnum> lifecycleStates = new HashSet<>();
178 lifecycleStates.add(LifecycleStateEnum.CERTIFIED);
179 response = getFollowedResourcesAndServices(null, lifecycleStates, new HashSet<>());
183 private Either<Map<String, Set<? extends Component>>, ResponseFormat> handleDesigner(String userId) {
184 Set<LifecycleStateEnum> lifecycleStates = new HashSet<>();
185 Set<LifecycleStateEnum> lastStateStates = new HashSet<>();
186 Either<Map<String, Set<? extends Component>>, ResponseFormat> response;
187 lifecycleStates.add(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN);
188 lifecycleStates.add(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT);
189 lifecycleStates.add(LifecycleStateEnum.CERTIFIED);
191 lastStateStates.add(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN);
192 response = getFollowedResourcesAndServices(userId, lifecycleStates, lastStateStates);
196 private Either<Map<String, Set<? extends Component>>, ResponseFormat> handleProductStrategist() {
197 // Should be empty list according to Ella, 13/03/16
198 Map<String, Set<? extends Component>> result = new HashMap<>();
199 result.put("products", new HashSet<>());
200 return Either.left(result);
203 private Either<Map<String, Set<? extends Component>>, ResponseFormat> handleProductManager(String userId) {
204 Set<LifecycleStateEnum> lifecycleStates = new HashSet<>();
205 Set<LifecycleStateEnum> lastStateStates = new HashSet<>();
206 Either<Map<String, Set<? extends Component>>, ResponseFormat> response;
207 lifecycleStates.add(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN);
208 lifecycleStates.add(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT);
209 lifecycleStates.add(LifecycleStateEnum.CERTIFIED);
211 lastStateStates.add(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN);
212 response = getFollowedProducts(userId, lifecycleStates, lastStateStates);
216 private Either<Map<String, Set<? extends Component>>, ResponseFormat> getFollowedResourcesAndServices(String userId,
217 Set<LifecycleStateEnum> lifecycleStates,
218 Set<LifecycleStateEnum> lastStateStates) {
220 Either<Set<Resource>, StorageOperationStatus> resources = toscaOperationFacade
221 .getFollowed(userId, lifecycleStates, lastStateStates, ComponentTypeEnum.RESOURCE);
222 if (resources.isLeft()) {
223 Either<Set<Service>, StorageOperationStatus> services = toscaOperationFacade
224 .getFollowed(userId, lifecycleStates, lastStateStates, ComponentTypeEnum.SERVICE);
225 if (services.isLeft()) {
226 Map<String, Set<? extends Component>> result = new HashMap<>();
227 result.put(SERVICES, services.left().value());
228 result.put(RESOURCES, resources.left().value());
229 return Either.left(result);
231 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(services.right().value())));
234 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(resources.right().value())));
237 janusGraphDao.commit();
241 private Either<Map<String, Set<? extends Component>>, ResponseFormat> getFollowedProducts(String userId, Set<LifecycleStateEnum> lifecycleStates,
242 Set<LifecycleStateEnum> lastStateStates) {
243 Either<Set<Product>, StorageOperationStatus> products = toscaOperationFacade
244 .getFollowed(userId, lifecycleStates, lastStateStates, ComponentTypeEnum.PRODUCT);
245 if (products.isLeft()) {
246 Map<String, Set<? extends Component>> result = new HashMap<>();
247 result.put("products", products.left().value());
248 return Either.left(result);
250 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(products.right().value())));
255 * New categories flow - start
257 public Either<List<CategoryDefinition>, ActionStatus> getAllResourceCategories() {
258 return elementOperation.getAllResourceCategories();
261 public Either<List<CategoryDefinition>, ActionStatus> getAllServiceCategories() {
262 return elementOperation.getAllServiceCategories();
265 public Either<CategoryDefinition, ResponseFormat> createCategory(CategoryDefinition category, String componentTypeParamName, String userId) {
266 AuditingActionEnum auditingAction = AuditingActionEnum.ADD_CATEGORY;
267 ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName);
268 String componentType = componentTypeEnum == null ? componentTypeParamName : componentTypeEnum.getValue();
269 CategoryTypeEnum categoryType = CategoryTypeEnum.CATEGORY;
270 User user = validateUserExists(userId);
271 if (category == null) {
272 log.debug("Category json is invalid");
273 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
274 handleCategoryAuditing(responseFormat, user, null, auditingAction, componentType);
275 return Either.right(responseFormat);
277 String categoryName = category.getName();
278 // For auditing of failures we need the original non-normalized name
279 String origCategoryName = categoryName;
280 if (componentTypeEnum == null) {
281 log.debug(COMPONENT_TYPE_IS_INVALID, componentTypeParamName);
282 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
283 handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
284 return Either.right(responseFormat);
286 Either<Boolean, ResponseFormat> validateUserRole = validateUserRole(user, componentTypeEnum);
287 if (validateUserRole.isRight()) {
288 log.debug(VALIDATION_OF_USER_ROLE_FAILED_USER_ID, userId);
289 ResponseFormat responseFormat = validateUserRole.right().value();
290 handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
291 return Either.right(responseFormat);
293 if (!ValidationUtils.validateCategoryDisplayNameFormat(categoryName)) {
294 log.debug("Category display name format is invalid, name {}, componentType {}", categoryName, componentType);
295 ResponseFormat responseFormat = componentsUtils
296 .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, componentType, categoryType.getValue());
297 handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
298 return Either.right(responseFormat);
300 categoryName = ValidationUtils.normalizeCategoryName4Display(categoryName);
301 if (!ValidationUtils.validateCategoryDisplayNameLength(categoryName)) {
302 log.debug("Category display name length is invalid, should be from 4 to 25 chars, name {}, componentType {}", categoryName,
304 ResponseFormat responseFormat = componentsUtils
305 .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, componentType, categoryType.getValue());
306 handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
307 return Either.right(responseFormat);
309 category.setName(categoryName);
310 String normalizedName = ValidationUtils.normalizeCategoryName4Uniqueness(categoryName);
311 category.setNormalizedName(normalizedName);
312 if (ValidationUtils.validateCategoryIconNotEmpty(category.getIcons())) {
313 log.debug("createCategory: setting category icon to default icon since service category was created without an icon ");
314 category.setIcons(Arrays.asList(DEFAULT_ICON));
316 NodeTypeEnum nodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, categoryType);
317 Either<Boolean, ActionStatus> categoryUniqueEither = elementOperation.isCategoryUniqueForType(nodeType, normalizedName);
318 if (categoryUniqueEither.isRight()) {
319 log.debug("Failed to check category uniqueness, name {}, componentType {}", categoryName, componentType);
320 ResponseFormat responseFormat = componentsUtils.getResponseFormat(categoryUniqueEither.right().value());
321 handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
322 return Either.right(responseFormat);
324 Boolean isCategoryUnique = categoryUniqueEither.left().value();
325 if (Boolean.FALSE.equals(isCategoryUnique)) {
326 log.debug("Category is not unique, name {}, componentType {}", categoryName, componentType);
327 ResponseFormat responseFormat = componentsUtils
328 .getResponseFormat(ActionStatus.COMPONENT_CATEGORY_ALREADY_EXISTS, componentType, categoryName);
329 handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
330 return Either.right(responseFormat);
332 Either<CategoryDefinition, ActionStatus> createCategoryByType = elementOperation.createCategory(category, nodeType);
333 if (createCategoryByType.isRight()) {
334 log.debug("Failed to create category, name {}, componentType {}", categoryName, componentType);
335 ResponseFormat responseFormat = componentsUtils
336 .getResponseFormat(ActionStatus.COMPONENT_CATEGORY_ALREADY_EXISTS, componentType, categoryName);
337 handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
338 return Either.right(componentsUtils.getResponseFormat(createCategoryByType.right().value()));
340 category = createCategoryByType.left().value();
341 log.debug("Created category for component {}, name {}, uniqueId {}", componentType, categoryName, category.getUniqueId());
342 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.CREATED);
343 handleCategoryAuditing(responseFormat, user, category.getName(), auditingAction, componentType);
344 return Either.left(category);
347 public Either<SubCategoryDefinition, ResponseFormat> createSubCategory(SubCategoryDefinition subCategory, String componentTypeParamName,
348 String parentCategoryId, String userId) {
349 AuditingActionEnum auditingAction = AuditingActionEnum.ADD_SUB_CATEGORY;
350 ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName);
351 String componentType = componentTypeEnum == null ? componentTypeParamName : componentTypeEnum.getValue();
352 CategoryTypeEnum categoryType = CategoryTypeEnum.SUBCATEGORY;
354 String parentCategoryName = parentCategoryId;
355 if (subCategory == null) {
356 log.debug("Sub-category json is invalid");
357 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
358 handleCategoryAuditing(responseFormat, null, parentCategoryName, null, auditingAction, componentType);
359 return Either.right(responseFormat);
361 String subCategoryName = subCategory.getName();
362 // For auditing of failures we need the original non-normalized name
363 String origSubCategoryName = subCategoryName;
366 user = validateUserExists(userId);
367 } catch (ByActionStatusComponentException e) {
368 ResponseFormat responseFormat = componentsUtils.getResponseFormat(e.getActionStatus(), e.getParams());
369 handleComponentException(userId, auditingAction, componentType, parentCategoryName, origSubCategoryName, responseFormat);
371 } catch (ByResponseFormatComponentException e) {
372 ResponseFormat responseFormat = e.getResponseFormat();
373 handleComponentException(userId, auditingAction, componentType, parentCategoryName, origSubCategoryName, responseFormat);
376 if (componentTypeEnum == null) {
377 log.debug(COMPONENT_TYPE_IS_INVALID, componentTypeParamName);
378 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
379 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
380 return Either.right(responseFormat);
382 Either<Boolean, ResponseFormat> validateComponentType = validateComponentTypeForCategory(componentTypeEnum, categoryType);
383 if (validateComponentType.isRight()) {
384 log.debug("Validation of component type for sub-category failed");
385 ResponseFormat responseFormat = validateComponentType.right().value();
386 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
387 return Either.right(responseFormat);
389 Either<Boolean, ResponseFormat> validateUserRole = validateUserRole(user, componentTypeEnum);
390 if (validateUserRole.isRight()) {
391 log.debug(VALIDATION_OF_USER_ROLE_FAILED_USER_ID, userId);
392 ResponseFormat responseFormat = validateUserRole.right().value();
393 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
394 return Either.right(responseFormat);
396 NodeTypeEnum parentNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.CATEGORY);
397 NodeTypeEnum childNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.SUBCATEGORY);
398 CategoryDefinition categoryDefinition;
399 Either<CategoryDefinition, ResponseFormat> validateCategoryExists = validateCategoryExists(parentNodeType, parentCategoryId,
401 if (validateCategoryExists.isRight()) {
402 log.debug("Validation of parent category exists failed, parent categoryId {}", parentCategoryId);
403 ResponseFormat responseFormat = validateCategoryExists.right().value();
404 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
405 return Either.right(responseFormat);
407 categoryDefinition = validateCategoryExists.left().value();
408 parentCategoryName = categoryDefinition.getName();
409 if (!ValidationUtils.validateCategoryDisplayNameFormat(subCategoryName)) {
410 log.debug("Sub-category display name format is invalid, name {}, componentType {}", subCategoryName, componentType);
411 ResponseFormat responseFormat = componentsUtils
412 .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, componentType, categoryType.getValue());
413 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
414 return Either.right(responseFormat);
416 subCategoryName = ValidationUtils.normalizeCategoryName4Display(subCategoryName);
417 if (!ValidationUtils.validateCategoryDisplayNameLength(subCategoryName)) {
418 log.debug("Sub-category display name length is invalid, should be from 4 to 25 chars, name {}, componentType {}", subCategoryName,
420 ResponseFormat responseFormat = componentsUtils
421 .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, componentType, categoryType.getValue());
422 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
423 return Either.right(responseFormat);
425 String normalizedName = ValidationUtils.normalizeCategoryName4Uniqueness(subCategoryName);
426 subCategory.setNormalizedName(normalizedName);
427 // Uniqueness under this category
428 Either<Boolean, ActionStatus> subCategoryUniqueForCategory = elementOperation
429 .isSubCategoryUniqueForCategory(childNodeType, normalizedName, parentCategoryId);
430 if (subCategoryUniqueForCategory.isRight()) {
431 log.debug("Failed to check sub-category uniqueness, parent name {}, subcategory norm name {}, componentType {}", parentCategoryName,
432 normalizedName, componentType);
433 ResponseFormat responseFormat = componentsUtils.getResponseFormat(subCategoryUniqueForCategory.right().value());
434 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
435 return Either.right(responseFormat);
437 Boolean isSubUnique = subCategoryUniqueForCategory.left().value();
438 if (Boolean.FALSE.equals(isSubUnique)) {
439 log.debug("Sub-category is not unique for category, parent name {}, subcategory norm name {}, componentType {}", parentCategoryName,
440 normalizedName, componentType);
441 ResponseFormat responseFormat = componentsUtils
442 .getResponseFormat(ActionStatus.COMPONENT_SUB_CATEGORY_EXISTS_FOR_CATEGORY, componentType, subCategoryName, parentCategoryName);
443 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
444 return Either.right(responseFormat);
446 // Setting name of subcategory to fit the similar subcategory name
450 // For example if Network-->kUKU exists for service category Network,
452 // and user is trying to create Router-->Kuku for service category
456 // his subcategory name will be Router-->kUKU.
457 Either<SubCategoryDefinition, ActionStatus> subCategoryUniqueForType = elementOperation
458 .getSubCategoryUniqueForType(childNodeType, normalizedName);
459 if (subCategoryUniqueForType.isRight()) {
460 log.debug("Failed validation of whether similar sub-category exists, normalizedName {} componentType {}", normalizedName, componentType);
461 ResponseFormat responseFormat = componentsUtils.getResponseFormat(subCategoryUniqueForType.right().value());
462 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
463 return Either.right(responseFormat);
465 SubCategoryDefinition subCategoryDefinition = subCategoryUniqueForType.left().value();
466 if (subCategoryDefinition != null) {
467 subCategoryName = subCategoryDefinition.getName();
469 subCategory.setName(subCategoryName);
470 ///////////////////////////////////////////// Validations end
471 Either<SubCategoryDefinition, ActionStatus> createSubCategory = elementOperation
472 .createSubCategory(parentCategoryId, subCategory, childNodeType);
473 if (createSubCategory.isRight()) {
474 log.debug("Failed to create sub-category, name {}, componentType {}", subCategoryName, componentType);
475 ResponseFormat responseFormat = componentsUtils.getResponseFormat(subCategoryUniqueForType.right().value());
476 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
477 return Either.right(responseFormat);
479 SubCategoryDefinition subCategoryCreated = createSubCategory.left().value();
480 log.debug("Created sub-category for component {}, name {}, uniqueId {}", componentType, subCategoryName, subCategoryCreated.getUniqueId());
481 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.CREATED);
482 handleCategoryAuditing(responseFormat, user, parentCategoryName, subCategoryCreated.getName(), auditingAction, componentType);
483 return Either.left(subCategoryCreated);
486 private void handleComponentException(String userId, AuditingActionEnum auditingAction, String componentType, String parentCategoryName,
487 String origSubCategoryName, ResponseFormat responseFormat) {
489 log.debug(VALIDATION_OF_USER_FAILED_USER_ID, userId);
491 user.setUserId(userId);
492 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
495 private void handleComponentException(GroupingDefinition grouping, String userId, AuditingActionEnum auditingAction, String componentType,
496 String parentCategoryName, String parentSubCategoryName, ResponseFormat responseFormat) {
498 log.debug(VALIDATION_OF_USER_FAILED_USER_ID, userId);
500 user.setUserId(userId);
501 String groupingNameForAudit = grouping == null ? null : grouping.getName();
502 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, groupingNameForAudit, auditingAction, componentType);
505 private void handleComponentException(String componentType, String userId, ResponseFormat responseFormat) {
508 user.setUserId(userId);
509 log.debug(VALIDATION_OF_USER_FAILED_USER_ID, userId);
510 componentsUtils.auditGetCategoryHierarchy(user, componentType, responseFormat);
513 public Either<GroupingDefinition, ResponseFormat> createGrouping(GroupingDefinition grouping, String componentTypeParamName,
514 String grandParentCategoryId, String parentSubCategoryId, String userId) {
515 AuditingActionEnum auditingAction = AuditingActionEnum.ADD_GROUPING;
516 ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName);
517 String componentType = componentTypeEnum == null ? componentTypeParamName : componentTypeEnum.getValue();
518 CategoryTypeEnum categoryType = CategoryTypeEnum.GROUPING;
520 String parentCategoryName = grandParentCategoryId;
521 String parentSubCategoryName = parentSubCategoryId;
524 user = validateUserExists(userId);
525 } catch (ByResponseFormatComponentException e) {
526 ResponseFormat responseFormat = e.getResponseFormat();
527 handleComponentException(grouping, userId, auditingAction, componentType, parentCategoryName, parentSubCategoryName, responseFormat);
529 } catch (ByActionStatusComponentException e) {
530 ResponseFormat responseFormat = componentsUtils.getResponseFormat(e.getActionStatus(), e.getParams());
531 handleComponentException(grouping, userId, auditingAction, componentType, parentCategoryName, parentSubCategoryName, responseFormat);
534 if (grouping == null) {
535 log.debug("Grouping json is invalid");
536 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
537 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, null, auditingAction, componentType);
538 return Either.right(responseFormat);
540 String groupingName = grouping.getName();
541 // For auditing of failures we need the original non-normalized name
542 String origGroupingName = groupingName;
543 if (componentTypeEnum == null) {
544 log.debug(COMPONENT_TYPE_IS_INVALID, componentTypeParamName);
545 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
546 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
547 return Either.right(responseFormat);
549 Either<Boolean, ResponseFormat> validateComponentType = validateComponentTypeForCategory(componentTypeEnum, categoryType);
550 if (validateComponentType.isRight()) {
551 log.debug("Validation of component type for grouping failed");
552 ResponseFormat responseFormat = validateComponentType.right().value();
553 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
554 return Either.right(responseFormat);
556 Either<Boolean, ResponseFormat> validateUserRole = validateUserRole(user, componentTypeEnum);
557 if (validateUserRole.isRight()) {
558 log.debug(VALIDATION_OF_USER_ROLE_FAILED_USER_ID, userId);
559 ResponseFormat responseFormat = validateUserRole.right().value();
560 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
561 return Either.right(responseFormat);
563 NodeTypeEnum grandParentNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.CATEGORY);
564 NodeTypeEnum parentNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.SUBCATEGORY);
565 NodeTypeEnum childNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.GROUPING);
567 CategoryDefinition categoryDefinition;
568 Either<CategoryDefinition, ResponseFormat> validateCategoryExists = validateCategoryExists(grandParentNodeType, grandParentCategoryId,
570 if (validateCategoryExists.isRight()) {
571 log.debug("Validation of parent category exists failed, parent categoryId {}", grandParentCategoryId);
572 ResponseFormat responseFormat = validateCategoryExists.right().value();
573 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
574 return Either.right(responseFormat);
576 categoryDefinition = validateCategoryExists.left().value();
577 parentCategoryName = categoryDefinition.getName();
578 // Validate subcategory
579 SubCategoryDefinition subCategoryDefinition;
580 Either<SubCategoryDefinition, ResponseFormat> validateSubCategoryExists = validateSubCategoryExists(parentNodeType, parentSubCategoryId,
582 if (validateSubCategoryExists.isRight()) {
583 log.debug("Validation of parent sub-category exists failed, parent sub-category id {}", parentSubCategoryId);
584 ResponseFormat responseFormat = validateSubCategoryExists.right().value();
585 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
586 return Either.right(responseFormat);
588 subCategoryDefinition = validateSubCategoryExists.left().value();
589 parentSubCategoryName = subCategoryDefinition.getName();
590 if (!ValidationUtils.validateCategoryDisplayNameFormat(groupingName)) {
591 log.debug("Sub-category display name format is invalid, name {}, componentType {}", groupingName, componentType);
592 ResponseFormat responseFormat = componentsUtils
593 .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, componentType, categoryType.getValue());
594 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
595 return Either.right(responseFormat);
597 groupingName = ValidationUtils.normalizeCategoryName4Display(groupingName);
598 if (!ValidationUtils.validateCategoryDisplayNameLength(groupingName)) {
599 log.debug("Grouping display name length is invalid, should be from 4 to 25 chars, name {}, componentType {}", groupingName,
601 ResponseFormat responseFormat = componentsUtils
602 .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, componentType, categoryType.getValue());
603 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
604 return Either.right(responseFormat);
606 String normalizedName = ValidationUtils.normalizeCategoryName4Uniqueness(groupingName);
607 grouping.setNormalizedName(normalizedName);
608 // Uniqueness under this category
609 Either<Boolean, ActionStatus> groupingUniqueForSubCategory = elementOperation
610 .isGroupingUniqueForSubCategory(childNodeType, normalizedName, parentSubCategoryId);
611 if (groupingUniqueForSubCategory.isRight()) {
612 log.debug("Failed to check grouping uniqueness, parent name {}, grouping norm name {}, componentType {}", parentSubCategoryName,
613 normalizedName, componentType);
614 ResponseFormat responseFormat = componentsUtils.getResponseFormat(groupingUniqueForSubCategory.right().value());
615 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
616 return Either.right(responseFormat);
618 Boolean isGroupingUnique = groupingUniqueForSubCategory.left().value();
619 if (Boolean.FALSE.equals(isGroupingUnique)) {
620 log.debug("Grouping is not unique for sub-category, parent name {}, grouping norm name {}, componentType {}", parentSubCategoryName,
621 normalizedName, componentType);
622 ResponseFormat responseFormat = componentsUtils
623 .getResponseFormat(ActionStatus.COMPONENT_GROUPING_EXISTS_FOR_SUB_CATEGORY, componentType, groupingName, parentSubCategoryName);
624 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
625 return Either.right(responseFormat);
627 // Setting name of grouping to fit the similar grouping name ignoring
631 // For example if Network-->kUKU exists for service sub-category
633 // Network, and user is trying to create grouping Router-->Kuku for
635 // service sub-category Router,
637 // his grouping name will be Router-->kUKU.
638 Either<GroupingDefinition, ActionStatus> groupingUniqueForType = elementOperation.getGroupingUniqueForType(childNodeType, normalizedName);
639 if (groupingUniqueForType.isRight()) {
640 log.debug("Failed validation of whether similar grouping exists, normalizedName {} componentType {}", normalizedName, componentType);
641 ResponseFormat responseFormat = componentsUtils.getResponseFormat(groupingUniqueForType.right().value());
642 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
643 return Either.right(responseFormat);
645 GroupingDefinition groupingDefinition = groupingUniqueForType.left().value();
646 if (groupingDefinition != null) {
647 groupingName = groupingDefinition.getName();
649 grouping.setName(groupingName);
650 ///////////////////////////////////////////// Validations end
651 Either<GroupingDefinition, ActionStatus> createGrouping = elementOperation.createGrouping(parentSubCategoryId, grouping, childNodeType);
652 if (createGrouping.isRight()) {
653 log.debug("Failed to create grouping, name {}, componentType {}", groupingName, componentType);
654 ResponseFormat responseFormat = componentsUtils.getResponseFormat(createGrouping.right().value());
655 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
656 return Either.right(responseFormat);
658 GroupingDefinition groupingCreated = createGrouping.left().value();
659 log.debug("Created grouping for component {}, name {}, uniqueId {}", componentType, groupingName, groupingCreated.getUniqueId());
660 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.CREATED);
661 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, groupingCreated.getName(), auditingAction,
663 return Either.left(groupingCreated);
666 public Either<List<CategoryDefinition>, ResponseFormat> getAllCategories(String componentType, String userId) {
667 ResponseFormat responseFormat;
668 User user = new User();
669 if (userId == null) {
670 user.setUserId("UNKNOWN");
671 responseFormat = componentsUtils.getResponseFormat(ActionStatus.MISSING_INFORMATION);
672 componentsUtils.auditGetCategoryHierarchy(user, componentType, responseFormat);
673 return Either.right(responseFormat);
676 user = validateUserExists(userId);
677 } catch (ByActionStatusComponentException e) {
678 responseFormat = componentsUtils.getResponseFormat(e.getActionStatus(), e.getParams());
679 handleComponentException(componentType, userId, responseFormat);
681 } catch (ByResponseFormatComponentException e) {
682 responseFormat = e.getResponseFormat();
683 handleComponentException(componentType, userId, responseFormat);
686 ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentType);
687 if (componentTypeEnum == null) {
688 log.debug("Cannot create category for component type {}", componentType);
689 responseFormat = componentsUtils.getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, "component type");
690 componentsUtils.auditGetCategoryHierarchy(user, componentType, responseFormat);
691 return Either.right(responseFormat);
693 NodeTypeEnum nodeTypeEnum = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.CATEGORY);
694 Either<List<CategoryDefinition>, ActionStatus> getAllCategoriesByType = elementOperation.getAllCategories(nodeTypeEnum, false);
695 if (getAllCategoriesByType.isRight()) {
696 responseFormat = componentsUtils.getResponseFormat(getAllCategoriesByType.right().value());
697 componentsUtils.auditGetCategoryHierarchy(user, componentType, responseFormat);
698 return Either.right(responseFormat);
700 List<CategoryDefinition> categories = getAllCategoriesByType.left().value();
701 responseFormat = componentsUtils.getResponseFormat(ActionStatus.OK);
702 componentsUtils.auditGetCategoryHierarchy(user, componentType, responseFormat);
703 return Either.left(categories);
706 public Either<UiCategories, ResponseFormat> getAllCategories(String userId) {
707 ResponseFormat responseFormat;
708 UiCategories categories = new UiCategories();
709 User user = validateUserExists(userId);
710 // GET resource categories
711 Either<List<CategoryDefinition>, ActionStatus> getResourceCategoriesByType = elementOperation
712 .getAllCategories(NodeTypeEnum.ResourceNewCategory, false);
713 if (getResourceCategoriesByType.isRight()) {
714 responseFormat = componentsUtils.getResponseFormat(getResourceCategoriesByType.right().value());
715 componentsUtils.auditGetCategoryHierarchy(user, ComponentTypeEnum.RESOURCE.getValue(), responseFormat);
716 return Either.right(responseFormat);
718 categories.setResourceCategories(getResourceCategoriesByType.left().value());
719 // GET service categories
720 Either<List<CategoryDefinition>, ActionStatus> getServiceCategoriesByType = elementOperation
721 .getAllCategories(NodeTypeEnum.ServiceNewCategory, false);
722 if (getServiceCategoriesByType.isRight()) {
723 responseFormat = componentsUtils.getResponseFormat(getServiceCategoriesByType.right().value());
724 componentsUtils.auditGetCategoryHierarchy(user, ComponentTypeEnum.SERVICE.getValue(), responseFormat);
725 return Either.right(responseFormat);
727 categories.setServiceCategories(getServiceCategoriesByType.left().value());
728 categories.setProductCategories(new ArrayList<>());
729 return Either.left(categories);
732 public Either<CategoryDefinition, ResponseFormat> deleteCategory(String categoryId, String componentTypeParamName, String userId) {
733 validateUserExists(userId);
734 ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName);
735 if (componentTypeEnum == null) {
736 log.debug("Cannot create category for component type {}", componentTypeParamName);
737 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
739 NodeTypeEnum nodeTypeEnum = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.CATEGORY);
740 Either<CategoryDefinition, ActionStatus> deleteCategoryByType = elementOperation.deleteCategory(nodeTypeEnum, categoryId);
741 if (deleteCategoryByType.isRight()) {
742 // auditing, logging here...
743 return Either.right(componentsUtils.getResponseFormat(deleteCategoryByType.right().value()));
745 CategoryDefinition category = deleteCategoryByType.left().value();
746 log.debug("Delete category for component {}, name {}, uniqueId {}", nodeTypeEnum, category.getName(), category.getUniqueId());
747 return Either.left(category);
750 public Either<SubCategoryDefinition, ResponseFormat> deleteSubCategory(String parentSubCategoryId, String componentTypeParamName, String userId) {
751 validateUserExists(userId);
752 ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName);
753 if (componentTypeEnum == null) {
754 log.debug("Cannot delete sub-category for component type {}", componentTypeParamName);
755 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
757 NodeTypeEnum nodeTypeEnum = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.SUBCATEGORY);
758 Either<SubCategoryDefinition, ActionStatus> deleteSubCategoryByType = elementOperation.deleteSubCategory(nodeTypeEnum, parentSubCategoryId);
759 if (deleteSubCategoryByType.isRight()) {
760 // auditing, logging here...
761 return Either.right(componentsUtils.getResponseFormat(deleteSubCategoryByType.right().value()));
763 SubCategoryDefinition subCategory = deleteSubCategoryByType.left().value();
764 log.debug("Deleted sub-category for component {}, name {}, uniqueId {}", nodeTypeEnum, subCategory.getName(), subCategory.getUniqueId());
765 return Either.left(subCategory);
768 public Either<GroupingDefinition, ResponseFormat> deleteGrouping(String groupingId, String componentTypeParamName, String userId) {
769 validateUserExists(userId);
770 ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName);
771 if (componentTypeEnum == null) {
772 log.debug("Cannot delete grouping for component type {}", componentTypeParamName);
773 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
775 NodeTypeEnum nodeTypeEnum = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.GROUPING);
776 Either<GroupingDefinition, ActionStatus> deleteGroupingByType = elementOperation.deleteGrouping(nodeTypeEnum, groupingId);
777 if (deleteGroupingByType.isRight()) {
778 // auditing, logging here...
779 return Either.right(componentsUtils.getResponseFormat(deleteGroupingByType.right().value()));
781 GroupingDefinition deletedGrouping = deleteGroupingByType.left().value();
782 log.debug("Deleted grouping for component {}, name {}, uniqueId {}", nodeTypeEnum, deletedGrouping.getName(), deletedGrouping.getUniqueId());
783 return Either.left(deletedGrouping);
786 private Either<Boolean, ResponseFormat> validateUserRole(User user, ComponentTypeEnum componentTypeEnum) {
787 String role = user.getRole();
788 boolean validAdminAction =
789 role.equals(Role.ADMIN.name()) && (componentTypeEnum == ComponentTypeEnum.SERVICE || componentTypeEnum == ComponentTypeEnum.RESOURCE);
790 boolean validProductAction = role.equals(Role.PRODUCT_STRATEGIST.name()) && (componentTypeEnum == ComponentTypeEnum.PRODUCT);
791 if (!(validAdminAction || validProductAction)) {
792 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION);
793 log.debug("User not permitted to perform operation on category, userId = {}, role = {}, componentType = {}", user.getUserId(), role,
795 return Either.right(responseFormat);
797 return Either.left(true);
800 private Either<Boolean, ResponseFormat> validateComponentTypeForCategory(ComponentTypeEnum componentType, CategoryTypeEnum categoryType) {
801 boolean validResourceAction = componentType == ComponentTypeEnum.RESOURCE && (categoryType == CategoryTypeEnum.CATEGORY
802 || categoryType == CategoryTypeEnum.SUBCATEGORY);
803 boolean validServiceAction = componentType == ComponentTypeEnum.SERVICE && categoryType == CategoryTypeEnum.CATEGORY;
804 boolean validProductAction = componentType == ComponentTypeEnum.PRODUCT; // can
813 if (!(validResourceAction || validServiceAction || validProductAction)) {
814 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
815 log.debug("It's not allowed to create category type {} for component type {}", categoryType, componentType);
816 return Either.right(responseFormat);
818 return Either.left(true);
821 private Either<CategoryDefinition, ResponseFormat> validateCategoryExists(NodeTypeEnum nodeType, String categoryId,
822 ComponentTypeEnum componentType) {
823 Either<CategoryDefinition, ActionStatus> categoryByTypeAndId = elementOperation.getCategory(nodeType, categoryId);
824 if (categoryByTypeAndId.isRight()) {
825 log.debug("Failed to fetch parent category, parent categoryId {}", categoryId);
826 ActionStatus actionStatus = categoryByTypeAndId.right().value();
827 ResponseFormat responseFormat;
828 if (actionStatus == ActionStatus.COMPONENT_CATEGORY_NOT_FOUND) {
829 responseFormat = componentsUtils
830 .getResponseFormat(actionStatus, componentType.getValue().toLowerCase(), CategoryTypeEnum.CATEGORY.getValue(), "");
832 responseFormat = componentsUtils.getResponseFormat(actionStatus);
834 return Either.right(responseFormat);
836 return Either.left(categoryByTypeAndId.left().value());
839 private Either<SubCategoryDefinition, ResponseFormat> validateSubCategoryExists(NodeTypeEnum nodeType, String subCategoryId,
840 ComponentTypeEnum componentType) {
841 Either<SubCategoryDefinition, ActionStatus> subCategoryByTypeAndId = elementOperation.getSubCategory(nodeType, subCategoryId);
842 if (subCategoryByTypeAndId.isRight()) {
843 log.debug("Failed to fetch parent category, parent categoryId {}", subCategoryId);
844 ActionStatus actionStatus = subCategoryByTypeAndId.right().value();
845 ResponseFormat responseFormat;
846 if (actionStatus == ActionStatus.COMPONENT_CATEGORY_NOT_FOUND) {
847 responseFormat = componentsUtils
848 .getResponseFormat(actionStatus, componentType.getValue().toLowerCase(), CategoryTypeEnum.SUBCATEGORY.getValue(), "");
850 responseFormat = componentsUtils.getResponseFormat(actionStatus);
852 return Either.right(responseFormat);
854 return Either.left(subCategoryByTypeAndId.left().value());
857 private void handleCategoryAuditing(ResponseFormat responseFormat, User user, String category, AuditingActionEnum auditingAction,
858 String componentType) {
859 componentsUtils.auditCategory(responseFormat, user, category, null, null, auditingAction, componentType);
862 private void handleCategoryAuditing(ResponseFormat responseFormat, User user, String category, String subCategory,
863 AuditingActionEnum auditingAction, String componentType) {
864 componentsUtils.auditCategory(responseFormat, user, category, subCategory, null, auditingAction, componentType);
867 private void handleCategoryAuditing(ResponseFormat responseFormat, User user, String category, String subCategory, String grouping,
868 AuditingActionEnum auditingAction, String componentType) {
869 componentsUtils.auditCategory(responseFormat, user, category, subCategory, grouping, auditingAction, componentType);
873 * New categories flow - end
875 public Either<List<Tag>, ActionStatus> getAllTags(String userId) {
876 ActionStatus status = validateUserExistsActionStatus(userId);
877 if (ActionStatus.OK != status) {
878 return Either.right(status);
880 return elementOperation.getAllTags();
883 public Either<List<PropertyScope>, ActionStatus> getAllPropertyScopes(String userId) {
884 ActionStatus status = validateUserExistsActionStatus(userId);
885 if (ActionStatus.OK != status) {
886 return Either.right(status);
888 return elementOperation.getAllPropertyScopes();
891 public Either<List<ArtifactType>, ActionStatus> getAllArtifactTypes(final String userId) {
892 ActionStatus status = validateUserExistsActionStatus(userId);
893 if (ActionStatus.OK != status) {
894 return Either.right(status);
896 return Either.left(elementOperation.getAllArtifactTypes());
899 public Either<Configuration.HeatDeploymentArtifactTimeout, ActionStatus> getDefaultHeatTimeout() {
900 return elementOperation.getDefaultHeatTimeout();
903 public Either<Map<String, List<CatalogComponent>>, ResponseFormat> getCatalogComponents(List<OriginTypeEnum> excludeTypes) {
905 return toscaOperationFacade.getCatalogOrArchiveComponents(true, excludeTypes)
906 .bimap(this::groupByComponentType, err -> componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(err)));
908 janusGraphDao.commit();
912 private Map<String, List<CatalogComponent>> groupByComponentType(List<CatalogComponent> components) {
913 Map<String, List<CatalogComponent>> map = components.stream()
914 .collect(Collectors.groupingBy(cmpt -> cmptTypeToString(cmpt.getComponentType())));
915 // fixed response for UI!!! UI need to receive always map!
917 map = new HashMap<>();
919 map.computeIfAbsent(RESOURCES, k -> new ArrayList());
920 map.computeIfAbsent(SERVICES, k -> new ArrayList());
924 private String cmptTypeToString(ComponentTypeEnum componentTypeEnum) {
925 switch (componentTypeEnum) {
931 throw new IllegalStateException("resources or services only");
935 public Either<List<? extends Component>, ResponseFormat> getFilteredCatalogComponents(String assetType, Map<FilterKeyEnum, String> filters,
937 ComponentTypeEnum assetTypeEnum = AssetTypeEnum.convertToComponentTypeEnum(assetType);
939 Optional<NameValuePair> invalidFilter = findInvalidFilter(query, assetTypeEnum);
940 if (invalidFilter.isPresent()) {
941 log.debug("getFilteredAssetList: invalid filter key");
942 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_FILTER_KEY, invalidFilter.get().getName(),
943 FilterKeyEnum.getValidFiltersByAssetType(assetTypeEnum).toString()));
946 if (filters == null || filters.isEmpty()) {
947 Either<List<Component>, StorageOperationStatus> componentsList = toscaOperationFacade.getCatalogComponents(assetTypeEnum, null, false);
948 if (componentsList.isRight()) {
949 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(componentsList.right().value())));
951 return Either.left(componentsList.left().value());
953 Either<List<Component>, StorageOperationStatus> result = getFilteredComponents(filters, assetTypeEnum, false);
954 // category hierarchy mismatch or category/subCategory/distributionStatus not found
955 if (result.isRight()) {
956 List<String> params = getErrorResponseParams(filters, assetTypeEnum);
957 return Either.right(componentsUtils
958 .getResponseFormat(componentsUtils.convertFromStorageResponse(result.right().value()), params.get(0), params.get(1), params.get(2)));
960 if (result.left().value().isEmpty()) {// no assets found for requested
963 return Either.right(componentsUtils.getResponseFormat(ActionStatus.NO_ASSETS_FOUND, assetType, query));
965 return Either.left(result.left().value());
968 private Either<List<Component>, StorageOperationStatus> getFilteredComponents(Map<FilterKeyEnum, String> filters, ComponentTypeEnum assetType,
969 boolean inTransaction) {
970 Either<List<Component>, StorageOperationStatus> assetResult = Either.left(new LinkedList<>());
971 if (assetType == ComponentTypeEnum.RESOURCE) {
972 assetResult = getFilteredResources(filters, inTransaction);
973 } else if (assetType == ComponentTypeEnum.SERVICE) {
974 assetResult = getFilteredServices(filters, inTransaction);
979 private <T extends Component> Either<List<T>, StorageOperationStatus> getFilteredServices(Map<FilterKeyEnum, String> filters,
980 boolean inTransaction) {
981 Either<List<T>, StorageOperationStatus> components = null;
982 String categoryName = filters.get(FilterKeyEnum.CATEGORY);
983 String distributionStatus = filters.get(FilterKeyEnum.DISTRIBUTION_STATUS);
984 DistributionStatusEnum distEnum = DistributionStatusEnum.findState(distributionStatus);
985 if (distributionStatus != null && distEnum == null) {
986 filters.remove(FilterKeyEnum.CATEGORY);
987 return Either.right(StorageOperationStatus.CATEGORY_NOT_FOUND);
989 if (categoryName != null) { // primary filter
990 components = fetchByCategoryOrSubCategoryName(categoryName, NodeTypeEnum.ServiceNewCategory, NodeTypeEnum.Service, inTransaction, null);
991 if (components.isLeft() && distEnum != null) {// secondary filter
992 Predicate<T> statusFilter = p -> ((Service) p).getDistributionStatus() == distEnum;
993 return Either.left(components.left().value().stream().filter(statusFilter).collect(Collectors.toList()));
995 filters.remove(FilterKeyEnum.DISTRIBUTION_STATUS);
998 Set<DistributionStatusEnum> distStatusSet = new HashSet<>();
999 distStatusSet.add(distEnum);
1000 Either<List<Service>, StorageOperationStatus> servicesWithDistStatus = toscaOperationFacade.getServicesWithDistStatus(distStatusSet, null);
1001 if (servicesWithDistStatus.isRight()) { // not found == empty list
1002 return Either.left(new ArrayList<>());
1004 return Either.left((List<T>) servicesWithDistStatus.left().value());
1007 public Either<List<? extends Component>, ResponseFormat> getCatalogComponentsByUuidAndAssetType(String assetType, String uuid) {
1008 if (assetType == null || uuid == null) {
1009 log.debug("getCatalogComponentsByUuidAndAssetType: One of the function parameteres is null");
1010 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
1012 ComponentTypeEnum assetTypeEnum = AssetTypeEnum.convertToComponentTypeEnum(assetType);
1013 if (assetTypeEnum == null) {
1014 log.debug("getCatalogComponentsByUuidAndAssetType: Corresponding ComponentTypeEnum not found");
1015 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
1017 Map<GraphPropertyEnum, Object> additionalPropertiesToMatch = new EnumMap<>(GraphPropertyEnum.class);
1018 switch (assetTypeEnum) {
1020 additionalPropertiesToMatch.put(GraphPropertyEnum.COMPONENT_TYPE, ComponentTypeEnum.RESOURCE.name());
1023 additionalPropertiesToMatch.put(GraphPropertyEnum.COMPONENT_TYPE, ComponentTypeEnum.SERVICE.name());
1026 log.debug("getCatalogComponentsByUuidAndAssetType: Corresponding ComponentTypeEnum not allowed for this API");
1027 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
1029 Either<List<Component>, StorageOperationStatus> componentsListByUuid = toscaOperationFacade
1030 .getComponentListByUuid(uuid, additionalPropertiesToMatch);
1031 if (componentsListByUuid.isRight()) {
1032 log.debug("getCatalogComponentsByUuidAndAssetType: " + assetTypeEnum.getValue() + " fetching failed");
1033 ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(componentsListByUuid.right().value(), assetTypeEnum);
1034 return Either.right(componentsUtils.getResponseFormat(actionStatus, uuid));
1036 log.debug("getCatalogComponentsByUuidAndAssetType: " + assetTypeEnum.getValue() + assetTypeEnum.getValue() + "fetching successful");
1037 return Either.left(componentsListByUuid.left().value());
1040 public List<String> getAllComponentTypesParamNames() {
1041 List<String> paramNames = new ArrayList<>();
1042 paramNames.add(ComponentTypeEnum.SERVICE_PARAM_NAME);
1043 paramNames.add(ComponentTypeEnum.RESOURCE_PARAM_NAME);
1044 paramNames.add(ComponentTypeEnum.PRODUCT_PARAM_NAME);
1048 public List<String> getAllSupportedRoles() {
1049 Role[] values = Role.values();
1050 List<String> roleNames = new ArrayList<>();
1051 for (Role role : values) {
1052 roleNames.add(role.name());
1057 public Either<Map<String, String>, ActionStatus> getResourceTypesMap() {
1058 return elementOperation.getResourceTypesMap();
1061 private Optional<NameValuePair> findInvalidFilter(String query, ComponentTypeEnum assetType) {
1062 List<NameValuePair> params = URLEncodedUtils.parse(query, StandardCharsets.UTF_8);
1063 List<String> validKeys = FilterKeyEnum.getValidFiltersByAssetType(assetType);
1064 Predicate<NameValuePair> noMatch = p -> !validKeys.contains(p.getName());
1065 return params.stream().filter(noMatch).findAny();
1068 private List<String> getErrorResponseParams(Map<FilterKeyEnum, String> filters, ComponentTypeEnum assetType) {
1069 List<String> params = new ArrayList<>();
1070 if (1 == filters.size()) {
1071 params.add(assetType.getValue().toLowerCase());
1072 params.add(filters.keySet().iterator().next().getName());
1073 params.add(filters.values().iterator().next());
1075 params.add(assetType.getValue());
1076 params.add(filters.get(FilterKeyEnum.SUB_CATEGORY));
1077 params.add(filters.get(FilterKeyEnum.CATEGORY));
1082 public Either<List<Component>, StorageOperationStatus> getFilteredResources(Map<FilterKeyEnum, String> filters, boolean inTransaction) {
1083 String subCategoryName = filters.get(FilterKeyEnum.SUB_CATEGORY);
1084 String categoryName = filters.get(FilterKeyEnum.CATEGORY);
1085 ResourceTypeEnum resourceType = ResourceTypeEnum.getType(filters.get(FilterKeyEnum.RESOURCE_TYPE));
1086 Either<List<ImmutablePair<SubCategoryData, GraphEdge>>, StorageOperationStatus> subcategories = null;
1087 Optional<ImmutablePair<SubCategoryData, GraphEdge>> subCategoryData;
1088 if (categoryName != null) {
1089 subcategories = getAllSubCategories(categoryName);
1090 if (subcategories.isRight()) {
1091 filters.remove(FilterKeyEnum.SUB_CATEGORY);
1092 return Either.right(subcategories.right().value());
1095 if (subCategoryName != null) { // primary filter
1096 if (categoryName != null) {
1097 subCategoryData = validateCategoryHierarcy(subcategories.left().value(), subCategoryName);
1098 if (!subCategoryData.isPresent()) {
1099 return Either.right(StorageOperationStatus.MATCH_NOT_FOUND);
1101 return fetchByCategoryOrSubCategoryUid(subCategoryData.get().getLeft().getUniqueId(), NodeTypeEnum.Resource, inTransaction,
1104 return fetchByCategoryOrSubCategoryName(subCategoryName, NodeTypeEnum.ResourceSubcategory, NodeTypeEnum.Resource, inTransaction,
1107 if (subcategories != null) {
1108 return fetchByMainCategory(subcategories.left().value(), inTransaction, resourceType);
1110 return fetchComponentMetaDataByResourceType(filters.get(FilterKeyEnum.RESOURCE_TYPE), inTransaction);
1113 private Either<List<ImmutablePair<SubCategoryData, GraphEdge>>, StorageOperationStatus> getAllSubCategories(String categoryName) {
1114 Either<CategoryData, StorageOperationStatus> categoryResult = elementOperation
1115 .getNewCategoryData(categoryName, NodeTypeEnum.ResourceNewCategory, CategoryData.class);
1116 if (categoryResult.isRight()) {
1117 return Either.right(categoryResult.right().value());
1119 CategoryData categoryData = categoryResult.left().value();
1120 Either<List<ImmutablePair<SubCategoryData, GraphEdge>>, JanusGraphOperationStatus> childrenNodes = janusGraphGenericDao
1121 .getChildrenNodes(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.ResourceNewCategory), categoryData.getUniqueId(),
1122 GraphEdgeLabels.SUB_CATEGORY, NodeTypeEnum.ResourceSubcategory, SubCategoryData.class);
1123 if (childrenNodes.isRight()) {
1124 return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(childrenNodes.right().value()));
1126 return Either.left(childrenNodes.left().value());
1129 private Optional<ImmutablePair<SubCategoryData, GraphEdge>> validateCategoryHierarcy(List<ImmutablePair<SubCategoryData, GraphEdge>> childNodes,
1130 String subCategoryName) {
1131 Predicate<ImmutablePair<SubCategoryData, GraphEdge>> matchName = p -> p.getLeft().getSubCategoryDataDefinition().getName()
1132 .equals(subCategoryName);
1133 return childNodes.stream().filter(matchName).findAny();
1136 protected <T extends Component> Either<List<T>, StorageOperationStatus> fetchByCategoryOrSubCategoryUid(String categoryUid,
1137 NodeTypeEnum categoryType,
1138 boolean inTransaction,
1139 ResourceTypeEnum resourceType) {
1141 return collectComponents(categoryType, categoryUid, resourceType);
1143 if (!inTransaction) {
1144 janusGraphDao.commit();
1149 protected <T extends Component> Either<List<T>, StorageOperationStatus> fetchByCategoryOrSubCategoryName(String categoryName,
1150 NodeTypeEnum categoryType,
1151 NodeTypeEnum neededType,
1152 boolean inTransaction,
1153 ResourceTypeEnum resourceType) {
1154 List<T> components = new ArrayList<>();
1156 Class categoryClazz = categoryType == NodeTypeEnum.ServiceNewCategory ? CategoryData.class : SubCategoryData.class;
1157 Map<String, Object> props = new HashMap<>();
1158 props.put(GraphPropertiesDictionary.NORMALIZED_NAME.getProperty(), ValidationUtils.normalizeCategoryName4Uniqueness(categoryName));
1159 Either<List<GraphNode>, JanusGraphOperationStatus> getCategory = janusGraphGenericDao.getByCriteria(categoryType, props, categoryClazz);
1160 if (getCategory.isRight()) {
1161 return Either.right(StorageOperationStatus.CATEGORY_NOT_FOUND);
1163 for (GraphNode category : getCategory.left().value()) {
1164 Either<List<T>, StorageOperationStatus> result = collectComponents(neededType, category.getUniqueId(), resourceType);
1165 if (result.isRight() && result.right().value() != StorageOperationStatus.NOT_FOUND) {
1167 } else if (result.isLeft()) {
1168 components.addAll(result.left().value());
1171 if (components.isEmpty()) {
1172 return Either.right(StorageOperationStatus.NOT_FOUND);
1174 return Either.left(components);
1176 if (!inTransaction) {
1177 janusGraphDao.commit();
1182 private <T extends Component> Either<List<T>, StorageOperationStatus> collectComponents(NodeTypeEnum neededType, String categoryUid,
1183 ResourceTypeEnum resourceType) {
1184 List<T> components = new ArrayList<>();
1185 Either<GraphVertex, JanusGraphOperationStatus> categoryVertexById = janusGraphDao.getVertexById(categoryUid, JsonParseFlagEnum.NoParse);
1186 if (categoryVertexById.isRight()) {
1187 JanusGraphOperationStatus status = categoryVertexById.right().value();
1188 log.debug("#collectComponents Failed to get category vertex with uid {}, status is {}.", categoryUid, status);
1189 return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status));
1191 GraphVertex categoryVertex = categoryVertexById.left().value();
1192 Either<List<GraphVertex>, JanusGraphOperationStatus> componentsVertices = janusGraphDao
1193 .getParentVertices(categoryVertex, EdgeLabelEnum.CATEGORY, JsonParseFlagEnum.ParseMetadata);
1194 if (componentsVertices.isRight()) {
1195 JanusGraphOperationStatus status = componentsVertices.right().value();
1196 log.debug("#collectComponents Failed to get components vertices of category {}, status is {}.", categoryVertex, status);
1197 return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status));
1199 List<ComponentMetadataDataDefinition> componentsMetadataDataDefinition = componentsVertices.left().value().stream().filter(Objects::nonNull)
1200 .filter(componentsVertex -> Objects.nonNull(componentsVertex.getType())).map(ModelConverter::convertToComponentMetadataDataDefinition)
1201 .collect(Collectors.toList());
1202 for (ComponentMetadataDataDefinition component : componentsMetadataDataDefinition) {
1203 boolean isHighest = isTrue(component.isHighestVersion());
1204 boolean isMatchingResourceType = isMatchingByResourceType(neededType, resourceType, component);
1205 boolean isDeleted = isTrue(component.isDeleted());
1206 boolean isArchived = isTrue(component.isArchived());
1207 if (isHighest && isMatchingResourceType && !isDeleted && !isArchived) {
1208 Either<T, StorageOperationStatus> result = toscaOperationFacade
1209 .getToscaElement(component.getUniqueId(), JsonParseFlagEnum.ParseMetadata);
1210 if (result.isRight()) {
1211 return Either.right(result.right().value());
1213 components.add(result.left().value());
1216 return Either.left(components);
1219 private boolean isMatchingByResourceType(NodeTypeEnum componentType, ResourceTypeEnum resourceType,
1220 ComponentMetadataDataDefinition componentData) {
1222 if (componentType == NodeTypeEnum.Resource) {
1223 if (resourceType == null) {
1226 isMatching = resourceType == ((ResourceMetadataDataDefinition) componentData).getResourceType();
1234 private <T extends Component> Either<List<T>, StorageOperationStatus> fetchByMainCategory(
1235 List<ImmutablePair<SubCategoryData, GraphEdge>> subcategories, boolean inTransaction, ResourceTypeEnum resourceType) {
1236 List<T> components = new ArrayList<>();
1237 for (ImmutablePair<SubCategoryData, GraphEdge> subCategory : subcategories) {
1238 Either<List<T>, StorageOperationStatus> fetched = fetchByCategoryOrSubCategoryUid(subCategory.getLeft().getUniqueId(),
1239 NodeTypeEnum.Resource, inTransaction, resourceType);
1240 if (fetched.isRight()) {
1243 components.addAll(fetched.left().value());
1245 return Either.left(components);
1248 private Either<List<Component>, StorageOperationStatus> fetchComponentMetaDataByResourceType(String resourceType, boolean inTransaction) {
1249 List<Component> components = null;
1250 StorageOperationStatus status;
1251 Wrapper<StorageOperationStatus> statusWrapper = new Wrapper<>();
1252 Either<List<Component>, StorageOperationStatus> result;
1254 ComponentParametersView fetchUsersAndCategoriesFilter = new ComponentParametersView(
1255 Arrays.asList(ComponentFieldsEnum.USERS.getValue(), ComponentFieldsEnum.CATEGORIES.getValue()));
1256 Either<List<Component>, StorageOperationStatus> getResources = toscaOperationFacade
1257 .fetchMetaDataByResourceType(resourceType, fetchUsersAndCategoriesFilter);
1258 if (getResources.isRight()) {
1259 status = getResources.right().value();
1260 if (status != StorageOperationStatus.NOT_FOUND) {
1261 statusWrapper.setInnerElement(getResources.right().value());
1263 components = new ArrayList<>();
1266 components = getResources.left().value();
1268 if (!statusWrapper.isEmpty()) {
1269 result = Either.right(statusWrapper.getInnerElement());
1271 result = Either.left(components);
1275 if (!inTransaction) {
1276 janusGraphDao.commit();
1281 public CatalogUpdateTimestamp getCatalogUpdateTime() {
1283 return toscaOperationFacade.getCatalogTimes();
1285 janusGraphDao.commit();
1289 public Either<List<BaseType>, ActionStatus> getBaseTypes(final String categoryName, final String userId, final String modelName) {
1290 final ActionStatus status = validateUserExistsActionStatus(userId);
1291 if (ActionStatus.OK != status) {
1292 return Either.right(status);
1294 return Either.left(elementOperation.getServiceBaseTypes(categoryName, modelName));
1298 * Checks if a category requires a base type.
1300 * @param categoryName the category name
1301 * @return {@code true} if a base type is required, {@code false} otherwise.
1303 public boolean isBaseTypeRequired(final String categoryName) {
1304 return elementOperation.isBaseTypeRequired(categoryName);