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 * ================================================================================
23 package org.openecomp.sdc.be.components.impl;
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;
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;
107 import static org.apache.commons.lang.BooleanUtils.isTrue;
108 import static org.openecomp.sdc.be.components.impl.ImportUtils.Constants.DEFAULT_ICON;
110 @org.springframework.stereotype.Component("elementsBusinessLogic")
111 public class ElementBusinessLogic extends BaseBusinessLogic {
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 {}";
120 private final IElementOperation elementOperation;
121 private final UserBusinessLogic userAdminManager;
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;
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;
147 String role = user.getRole();
148 String userId = user.getUserId();
149 Role currentRole = Role.valueOf(role);
151 switch (currentRole) {
153 response = handleDesigner(userId);
156 case PRODUCT_STRATEGIST:
157 response = handleProductStrategist();
160 case PRODUCT_MANAGER:
161 response = handleProductManager(userId);
165 response = handleAdmin();
169 response = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
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);
177 private Either<Map<String, List<? extends Component>>, ResponseFormat> convertedToListResponse(Either<Map<String, Set<? extends Component>>, ResponseFormat> setResponse) {
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())));
184 return Either.left(arrayResponse);
186 return Either.right(setResponse.right().value());
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<>());
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);
206 lastStateStates.add(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN);
207 response = getFollowedResourcesAndServices(userId, lifecycleStates, lastStateStates);
211 private Either<Map<String, Set<? extends Component>>, ResponseFormat> handleGovernor() {
212 return handleFollowedCertifiedServices(null);
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);
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);
230 lastStateStates.add(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN);
231 response = getFollowedProducts(userId, lifecycleStates, lastStateStates);
235 private Either<Map<String, Set<? extends Component>>, ResponseFormat> handleFollowedCertifiedServices(Set<DistributionStatusEnum> distStatus) {
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);
245 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(services.right().value())));
249 private Either<Map<String, Set<? extends Component>>, ResponseFormat> getFollowedResourcesAndServices(String userId, Set<LifecycleStateEnum> lifecycleStates, Set<LifecycleStateEnum> lastStateStates) {
252 Either<Set<Resource>, StorageOperationStatus> resources = toscaOperationFacade.getFollowed(userId, lifecycleStates, lastStateStates, ComponentTypeEnum.RESOURCE);
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);
262 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(services.right().value())));
265 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(resources.right().value())));
268 janusGraphDao.commit();
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);
279 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(products.right().value())));
284 * New categories flow - start
286 public Either<List<CategoryDefinition>, ActionStatus> getAllResourceCategories() {
287 return elementOperation.getAllResourceCategories();
290 public Either<List<CategoryDefinition>, ActionStatus> getAllServiceCategories() {
291 return elementOperation.getAllServiceCategories();
294 public Either<CategoryDefinition, ResponseFormat> createCategory(CategoryDefinition category, String componentTypeParamName, String userId) {
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;
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);
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);
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);
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);
334 categoryName = ValidationUtils.normalizeCategoryName4Display(categoryName);
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);
343 category.setName(categoryName);
345 String normalizedName = ValidationUtils.normalizeCategoryName4Uniqueness(categoryName);
346 category.setNormalizedName(normalizedName);
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));
353 NodeTypeEnum nodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, categoryType);
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);
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);
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()));
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);
385 public Either<SubCategoryDefinition, ResponseFormat> createSubCategory(SubCategoryDefinition subCategory, String componentTypeParamName, String parentCategoryId, String userId) {
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;
392 String parentCategoryName = parentCategoryId;
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);
401 String subCategoryName = subCategory.getName();
402 // For auditing of failures we need the original non-normalized name
403 String origSubCategoryName = subCategoryName;
406 user = validateUserExists(userId);
407 } catch(ByActionStatusComponentException e){
408 ResponseFormat responseFormat = componentsUtils.getResponseFormat(e.getActionStatus(), e.getParams());
409 handleComponentException(userId, auditingAction, componentType, parentCategoryName, origSubCategoryName,
412 } catch(ByResponseFormatComponentException e){
413 ResponseFormat responseFormat = e.getResponseFormat();
414 handleComponentException(userId, auditingAction, componentType, parentCategoryName, origSubCategoryName,
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);
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);
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);
441 NodeTypeEnum parentNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.CATEGORY);
442 NodeTypeEnum childNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.SUBCATEGORY);
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);
453 categoryDefinition = validateCategoryExists.left().value();
454 parentCategoryName = categoryDefinition.getName();
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);
463 subCategoryName = ValidationUtils.normalizeCategoryName4Display(subCategoryName);
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);
472 String normalizedName = ValidationUtils.normalizeCategoryName4Uniqueness(subCategoryName);
473 subCategory.setNormalizedName(normalizedName);
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);
484 Boolean isSubUnique = subCategoryUniqueForCategory.left().value();
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);
492 // Setting name of subcategory to fit the similar subcategory name
494 // For example if Network-->kUKU exists for service category Network,
495 // and user is trying to create Router-->Kuku for service category
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);
505 SubCategoryDefinition subCategoryDefinition = subCategoryUniqueForType.left().value();
506 if (subCategoryDefinition != null) {
507 subCategoryName = subCategoryDefinition.getName();
510 subCategory.setName(subCategoryName);
511 ///////////////////////////////////////////// Validations end
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);
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);
528 private void handleComponentException(String userId, AuditingActionEnum auditingAction, String componentType,
529 String parentCategoryName, String origSubCategoryName, ResponseFormat responseFormat) {
531 log.debug(VALIDATION_OF_USER_FAILED_USER_ID, userId);
533 user.setUserId(userId);
534 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction,
538 private void handleComponentException(GroupingDefinition grouping, String userId, AuditingActionEnum auditingAction,
539 String componentType, String parentCategoryName, String parentSubCategoryName, ResponseFormat responseFormat) {
541 log.debug(VALIDATION_OF_USER_FAILED_USER_ID, userId);
543 user.setUserId(userId);
544 String groupingNameForAudit = grouping == null ? null : grouping.getName();
545 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, groupingNameForAudit,
546 auditingAction, componentType);
549 private void handleComponentException(String componentType, String userId, ResponseFormat responseFormat) {
552 user.setUserId(userId);
553 log.debug(VALIDATION_OF_USER_FAILED_USER_ID, userId);
554 componentsUtils.auditGetCategoryHierarchy(user, componentType, responseFormat);
557 public Either<GroupingDefinition, ResponseFormat> createGrouping(GroupingDefinition grouping, String componentTypeParamName, String grandParentCategoryId, String parentSubCategoryId, String userId) {
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;
564 String parentCategoryName = grandParentCategoryId;
565 String parentSubCategoryName = parentSubCategoryId;
569 user = validateUserExists(userId);
570 } catch(ByResponseFormatComponentException e){
571 ResponseFormat responseFormat = e.getResponseFormat();
572 handleComponentException(grouping, userId, auditingAction, componentType, parentCategoryName,
573 parentSubCategoryName,
576 } catch(ByActionStatusComponentException e){
577 ResponseFormat responseFormat = componentsUtils.getResponseFormat(e.getActionStatus(), e.getParams());
578 handleComponentException(grouping, userId, auditingAction, componentType, parentCategoryName,
579 parentSubCategoryName, responseFormat);
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);
590 String groupingName = grouping.getName();
591 // For auditing of failures we need the original non-normalized name
592 String origGroupingName = groupingName;
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);
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);
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);
617 NodeTypeEnum grandParentNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.CATEGORY);
618 NodeTypeEnum parentNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.SUBCATEGORY);
619 NodeTypeEnum childNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.GROUPING);
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);
631 categoryDefinition = validateCategoryExists.left().value();
632 parentCategoryName = categoryDefinition.getName();
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);
644 subCategoryDefinition = validateSubCategoryExists.left().value();
645 parentSubCategoryName = subCategoryDefinition.getName();
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);
654 groupingName = ValidationUtils.normalizeCategoryName4Display(groupingName);
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);
663 String normalizedName = ValidationUtils.normalizeCategoryName4Uniqueness(groupingName);
664 grouping.setNormalizedName(normalizedName);
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);
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);
683 // Setting name of grouping to fit the similar grouping name ignoring
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);
696 GroupingDefinition groupingDefinition = groupingUniqueForType.left().value();
697 if (groupingDefinition != null) {
698 groupingName = groupingDefinition.getName();
701 grouping.setName(groupingName);
702 ///////////////////////////////////////////// Validations end
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);
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);
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);
731 user = validateUserExists(userId);
732 } catch (ByActionStatusComponentException e){
733 responseFormat = componentsUtils.getResponseFormat(e.getActionStatus(), e.getParams());
734 handleComponentException(componentType, userId, responseFormat);
736 } catch (ByResponseFormatComponentException e){
737 responseFormat = e.getResponseFormat();
738 handleComponentException(componentType, userId, responseFormat);
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);
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);
756 List<CategoryDefinition> categories = getAllCategoriesByType.left().value();
757 responseFormat = componentsUtils.getResponseFormat(ActionStatus.OK);
758 componentsUtils.auditGetCategoryHierarchy(user, componentType, responseFormat);
759 return Either.left(categories);
764 public Either<UiCategories, ResponseFormat> getAllCategories(String userId) {
765 ResponseFormat responseFormat;
766 UiCategories categories = new UiCategories();
768 User user = validateUserExists(userId);
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);
777 categories.setResourceCategories(getResourceCategoriesByType.left().value());
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);
786 categories.setServiceCategories(getServiceCategoriesByType.left().value());
787 categories.setProductCategories(new ArrayList<>());
788 return Either.left(categories);
791 public Either<CategoryDefinition, ResponseFormat> deleteCategory(String categoryId, String componentTypeParamName, String userId) {
793 validateUserExists(userId);
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));
801 NodeTypeEnum nodeTypeEnum = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.CATEGORY);
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()));
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);
813 public Either<SubCategoryDefinition, ResponseFormat> deleteSubCategory(String parentSubCategoryId, String componentTypeParamName, String userId) {
815 validateUserExists(userId);
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));
823 NodeTypeEnum nodeTypeEnum = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.SUBCATEGORY);
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()));
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);
835 public Either<GroupingDefinition, ResponseFormat> deleteGrouping(String groupingId, String componentTypeParamName, String userId) {
837 validateUserExists(userId);
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));
845 NodeTypeEnum nodeTypeEnum = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.GROUPING);
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()));
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);
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);
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);
867 return Either.left(true);
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
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);
884 return Either.left(true);
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(), "");
896 responseFormat = componentsUtils.getResponseFormat(actionStatus);
898 return Either.right(responseFormat);
900 return Either.left(categoryByTypeAndId.left().value());
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(), "");
912 responseFormat = componentsUtils.getResponseFormat(actionStatus);
914 return Either.right(responseFormat);
916 return Either.left(subCategoryByTypeAndId.left().value());
919 private void handleCategoryAuditing(ResponseFormat responseFormat, User user, String category, AuditingActionEnum auditingAction, String componentType) {
920 componentsUtils.auditCategory(responseFormat, user, category, null, null, auditingAction, componentType);
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);
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);
932 * New categories flow - end
935 public Either<List<Tag>, ActionStatus> getAllTags(String userId) {
936 ActionStatus status = validateUserExistsActionStatus(userId);
937 if (ActionStatus.OK != status) {
938 return Either.right(status);
940 return elementOperation.getAllTags();
943 public Either<List<PropertyScope>, ActionStatus> getAllPropertyScopes(String userId) {
944 ActionStatus status = validateUserExistsActionStatus(userId);
945 if (ActionStatus.OK != status) {
946 return Either.right(status);
948 return elementOperation.getAllPropertyScopes();
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);
956 return Either.left(elementOperation.getAllArtifactTypes());
959 public Either<Configuration.HeatDeploymentArtifactTimeout, ActionStatus> getDefaultHeatTimeout() {
960 return elementOperation.getDefaultHeatTimeout();
963 public Either<Map<String, List<CatalogComponent>>, ResponseFormat> getCatalogComponents(String userId, List<OriginTypeEnum> excludeTypes) {
965 return toscaOperationFacade.getCatalogOrArchiveComponents(true, excludeTypes)
966 .bimap(this::groupByComponentType,
967 err -> componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(err)));
969 janusGraphDao.commit();
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())));
976 // fixed response for UI!!! UI need to receive always map!
978 map = new HashMap<>();
980 map.computeIfAbsent(RESOURCES, k -> new ArrayList());
981 map.computeIfAbsent(SERVICES, k -> new ArrayList());
985 private String cmptTypeToString(ComponentTypeEnum componentTypeEnum) {
986 switch (componentTypeEnum) {
992 throw new IllegalStateException("resources or services only");
996 public Either<List<? extends Component>, ResponseFormat> getFilteredCatalogComponents(String assetType, Map<FilterKeyEnum, String> filters, String query) {
997 ComponentTypeEnum assetTypeEnum = AssetTypeEnum.convertToComponentTypeEnum(assetType);
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()));
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())));
1012 return Either.left(componentsList.left().value());
1015 Either<List<Component>, StorageOperationStatus> result = getFilteredComponents(filters, assetTypeEnum, false);
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)));
1022 if (result.left().value().isEmpty()) {// no assets found for requested
1024 return Either.right(componentsUtils.getResponseFormat(ActionStatus.NO_ASSETS_FOUND, assetType, query));
1026 return Either.left(result.left().value());
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) {
1033 assetResult = getFilteredResources(filters, inTransaction);
1035 } else if (assetType == ComponentTypeEnum.SERVICE) {
1037 assetResult = getFilteredServices(filters, inTransaction);
1042 private <T extends Component> Either<List<T>, StorageOperationStatus> getFilteredServices(Map<FilterKeyEnum, String> filters, boolean inTransaction) {
1044 Either<List<T>, StorageOperationStatus> components = null;
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);
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()));
1060 filters.remove(FilterKeyEnum.DISTRIBUTION_STATUS);
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<>());
1071 return Either.left((List<T>) servicesWithDistStatus.left().value());
1074 public Either<List<? extends Component>, ResponseFormat> getCatalogComponentsByUuidAndAssetType(String assetType, String uuid) {
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));
1081 ComponentTypeEnum assetTypeEnum = AssetTypeEnum.convertToComponentTypeEnum(assetType);
1083 if (assetTypeEnum == null) {
1084 log.debug("getCatalogComponentsByUuidAndAssetType: Corresponding ComponentTypeEnum not found");
1085 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
1088 Map<GraphPropertyEnum, Object> additionalPropertiesToMatch = new EnumMap<>(GraphPropertyEnum.class);
1090 switch (assetTypeEnum) {
1092 additionalPropertiesToMatch.put(GraphPropertyEnum.COMPONENT_TYPE, ComponentTypeEnum.RESOURCE.name());
1095 additionalPropertiesToMatch.put(GraphPropertyEnum.COMPONENT_TYPE, ComponentTypeEnum.SERVICE.name());
1098 log.debug("getCatalogComponentsByUuidAndAssetType: Corresponding ComponentTypeEnum not allowed for this API");
1099 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
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));
1109 log.debug("getCatalogComponentsByUuidAndAssetType: " + assetTypeEnum.getValue() + assetTypeEnum.getValue() + "fetching successful");
1110 return Either.left(componentsListByUuid.left().value());
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);
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());
1130 public Either<Map<String, String>, ActionStatus> getResourceTypesMap() {
1131 return elementOperation.getResourceTypesMap();
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();
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());
1148 params.add(assetType.getValue());
1149 params.add(filters.get(FilterKeyEnum.SUB_CATEGORY));
1150 params.add(filters.get(FilterKeyEnum.CATEGORY));
1155 public Either<List<Component>, StorageOperationStatus> getFilteredResources(Map<FilterKeyEnum, String> filters, boolean inTransaction) {
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;
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());
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);
1176 return fetchByCategoryOrSubCategoryUid(subCategoryData.get().getLeft().getUniqueId(), NodeTypeEnum.Resource, inTransaction, resourceType);
1179 return fetchByCategoryOrSubCategoryName(subCategoryName, NodeTypeEnum.ResourceSubcategory, NodeTypeEnum.Resource, inTransaction, resourceType);
1181 if (subcategories != null) {
1182 return fetchByMainCategory(subcategories.left().value(), inTransaction, resourceType);
1184 return fetchComponentMetaDataByResourceType(filters.get(FilterKeyEnum.RESOURCE_TYPE), inTransaction);
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());
1192 CategoryData categoryData = categoryResult.left().value();
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()));
1200 return Either.left(childrenNodes.left().value());
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();
1208 protected <T extends Component> Either<List<T>, StorageOperationStatus> fetchByCategoryOrSubCategoryUid(String categoryUid, NodeTypeEnum categoryType, boolean inTransaction, ResourceTypeEnum resourceType) {
1210 return collectComponents(categoryType, categoryUid, resourceType);
1212 if (!inTransaction) {
1213 janusGraphDao.commit();
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<>();
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);
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) {
1232 } else if (result.isLeft()){
1233 components.addAll(result.left().value());
1236 if (components.isEmpty()){
1237 return Either.right(StorageOperationStatus.NOT_FOUND);
1239 return Either.left(components);
1241 if (!inTransaction) {
1242 janusGraphDao.commit();
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));
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));
1263 List<ComponentMetadataDataDefinition> componentsMetadataDataDefinition = componentsVertices.left().value()
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());
1279 components.add(result.left().value());
1282 return Either.left(components);
1285 private boolean isMatchingByResourceType(NodeTypeEnum componentType, ResourceTypeEnum resourceType, ComponentMetadataDataDefinition componentData) {
1288 if (componentType == NodeTypeEnum.Resource) {
1289 if (resourceType == null) {
1292 isMatching = resourceType == ((ResourceMetadataDataDefinition) componentData).getResourceType();
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<>();
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()) {
1309 components.addAll(fetched.left().value());
1311 return Either.left(components);
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;
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());
1327 components = new ArrayList<>();
1330 components = getResources.left().value();
1332 if (!statusWrapper.isEmpty()) {
1333 result = Either.right(statusWrapper.getInnerElement());
1335 result = Either.left(components);
1339 if (!inTransaction) {
1340 janusGraphDao.commit();
1346 public CatalogUpdateTimestamp getCatalogUpdateTime(String userId) {
1349 return toscaOperationFacade.getCatalogTimes();
1352 janusGraphDao.commit();