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(String userId) {
952 ActionStatus status = validateUserExistsActionStatus(userId);
953 if (ActionStatus.OK != status) {
954 return Either.right(status);
956 return elementOperation.getAllArtifactTypes();
959 public Either<Map<String, Object>, ActionStatus> getAllDeploymentArtifactTypes() {
960 return elementOperation.getAllDeploymentArtifactTypes();
963 public Either<Configuration.HeatDeploymentArtifactTimeout, ActionStatus> getDefaultHeatTimeout() {
964 return elementOperation.getDefaultHeatTimeout();
967 public Either<Map<String, List<CatalogComponent>>, ResponseFormat> getCatalogComponents(String userId, List<OriginTypeEnum> excludeTypes) {
969 return toscaOperationFacade.getCatalogOrArchiveComponents(true, excludeTypes)
970 .bimap(this::groupByComponentType,
971 err -> componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(err)));
973 janusGraphDao.commit();
977 private Map<String, List<CatalogComponent>> groupByComponentType(List<CatalogComponent> components) {
978 Map<String, List<CatalogComponent>> map = components.stream().collect(Collectors.groupingBy(cmpt -> cmptTypeToString(cmpt.getComponentType())));
980 // fixed response for UI!!! UI need to receive always map!
982 map = new HashMap<>();
984 map.computeIfAbsent(RESOURCES, k -> new ArrayList());
985 map.computeIfAbsent(SERVICES, k -> new ArrayList());
989 private String cmptTypeToString(ComponentTypeEnum componentTypeEnum) {
990 switch (componentTypeEnum) {
996 throw new IllegalStateException("resources or services only");
1000 public Either<List<? extends Component>, ResponseFormat> getFilteredCatalogComponents(String assetType, Map<FilterKeyEnum, String> filters, String query) {
1001 ComponentTypeEnum assetTypeEnum = AssetTypeEnum.convertToComponentTypeEnum(assetType);
1003 if (query != null) {
1004 Optional<NameValuePair> invalidFilter = findInvalidFilter(query, assetTypeEnum);
1005 if (invalidFilter.isPresent()) {
1006 log.debug("getFilteredAssetList: invalid filter key");
1007 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_FILTER_KEY, invalidFilter.get().getName(), FilterKeyEnum.getValidFiltersByAssetType(assetTypeEnum).toString()));
1011 if (filters == null || filters.isEmpty()) {
1012 Either<List<Component>, StorageOperationStatus> componentsList = toscaOperationFacade.getCatalogComponents(assetTypeEnum, null, false);
1013 if (componentsList.isRight()) {
1014 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(componentsList.right().value())));
1016 return Either.left(componentsList.left().value());
1019 Either<List<Component>, StorageOperationStatus> result = getFilteredComponents(filters, assetTypeEnum, false);
1021 // category hierarchy mismatch or category/subCategory/distributionStatus not found
1022 if (result.isRight()) {
1023 List<String> params = getErrorResponseParams(filters, assetTypeEnum);
1024 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(result.right().value()), params.get(0), params.get(1), params.get(2)));
1026 if (result.left().value().isEmpty()) {// no assets found for requested
1028 return Either.right(componentsUtils.getResponseFormat(ActionStatus.NO_ASSETS_FOUND, assetType, query));
1030 return Either.left(result.left().value());
1033 private Either<List<Component>, StorageOperationStatus> getFilteredComponents(Map<FilterKeyEnum, String> filters, ComponentTypeEnum assetType, boolean inTransaction) {
1034 Either<List<Component>, StorageOperationStatus> assetResult = Either.left(new LinkedList<>());
1035 if (assetType == ComponentTypeEnum.RESOURCE) {
1037 assetResult = getFilteredResources(filters, inTransaction);
1039 } else if (assetType == ComponentTypeEnum.SERVICE) {
1041 assetResult = getFilteredServices(filters, inTransaction);
1046 private <T extends Component> Either<List<T>, StorageOperationStatus> getFilteredServices(Map<FilterKeyEnum, String> filters, boolean inTransaction) {
1048 Either<List<T>, StorageOperationStatus> components = null;
1050 String categoryName = filters.get(FilterKeyEnum.CATEGORY);
1051 String distributionStatus = filters.get(FilterKeyEnum.DISTRIBUTION_STATUS);
1052 DistributionStatusEnum distEnum = DistributionStatusEnum.findState(distributionStatus);
1053 if (distributionStatus != null && distEnum == null) {
1054 filters.remove(FilterKeyEnum.CATEGORY);
1055 return Either.right(StorageOperationStatus.CATEGORY_NOT_FOUND);
1058 if (categoryName != null) { // primary filter
1059 components = fetchByCategoryOrSubCategoryName(categoryName, NodeTypeEnum.ServiceNewCategory, NodeTypeEnum.Service, inTransaction, null);
1060 if (components.isLeft() && distEnum != null) {// secondary filter
1061 Predicate<T> statusFilter = p -> ((Service) p).getDistributionStatus() == distEnum;
1062 return Either.left(components.left().value().stream().filter(statusFilter).collect(Collectors.toList()));
1064 filters.remove(FilterKeyEnum.DISTRIBUTION_STATUS);
1068 Set<DistributionStatusEnum> distStatusSet = new HashSet<>();
1069 distStatusSet.add(distEnum);
1070 Either<List<Service>, StorageOperationStatus> servicesWithDistStatus = toscaOperationFacade.getServicesWithDistStatus(distStatusSet, null);
1071 if (servicesWithDistStatus.isRight()) { // not found == empty list
1072 return Either.left(new ArrayList<>());
1075 return Either.left((List<T>) servicesWithDistStatus.left().value());
1078 public Either<List<? extends Component>, ResponseFormat> getCatalogComponentsByUuidAndAssetType(String assetType, String uuid) {
1080 if (assetType == null || uuid == null) {
1081 log.debug("getCatalogComponentsByUuidAndAssetType: One of the function parameteres is null");
1082 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
1085 ComponentTypeEnum assetTypeEnum = AssetTypeEnum.convertToComponentTypeEnum(assetType);
1087 if (assetTypeEnum == null) {
1088 log.debug("getCatalogComponentsByUuidAndAssetType: Corresponding ComponentTypeEnum not found");
1089 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
1092 Map<GraphPropertyEnum, Object> additionalPropertiesToMatch = new EnumMap<>(GraphPropertyEnum.class);
1094 switch (assetTypeEnum) {
1096 additionalPropertiesToMatch.put(GraphPropertyEnum.COMPONENT_TYPE, ComponentTypeEnum.RESOURCE.name());
1099 additionalPropertiesToMatch.put(GraphPropertyEnum.COMPONENT_TYPE, ComponentTypeEnum.SERVICE.name());
1102 log.debug("getCatalogComponentsByUuidAndAssetType: Corresponding ComponentTypeEnum not allowed for this API");
1103 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
1106 Either<List<Component>, StorageOperationStatus> componentsListByUuid = toscaOperationFacade.getComponentListByUuid(uuid, additionalPropertiesToMatch);
1107 if (componentsListByUuid.isRight()) {
1108 log.debug("getCatalogComponentsByUuidAndAssetType: " + assetTypeEnum.getValue() + " fetching failed");
1109 ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(componentsListByUuid.right().value(), assetTypeEnum);
1110 return Either.right(componentsUtils.getResponseFormat(actionStatus, uuid));
1113 log.debug("getCatalogComponentsByUuidAndAssetType: " + assetTypeEnum.getValue() + assetTypeEnum.getValue() + "fetching successful");
1114 return Either.left(componentsListByUuid.left().value());
1117 public List<String> getAllComponentTypesParamNames() {
1118 List<String> paramNames = new ArrayList<>();
1119 paramNames.add(ComponentTypeEnum.SERVICE_PARAM_NAME);
1120 paramNames.add(ComponentTypeEnum.RESOURCE_PARAM_NAME);
1121 paramNames.add(ComponentTypeEnum.PRODUCT_PARAM_NAME);
1125 public List<String> getAllSupportedRoles() {
1126 Role[] values = Role.values();
1127 List<String> roleNames = new ArrayList<>();
1128 for (Role role : values) {
1129 roleNames.add(role.name());
1134 public Either<Map<String, String>, ActionStatus> getResourceTypesMap() {
1135 return elementOperation.getResourceTypesMap();
1138 private Optional<NameValuePair> findInvalidFilter(String query, ComponentTypeEnum assetType) {
1139 List<NameValuePair> params = URLEncodedUtils.parse(query, StandardCharsets.UTF_8);
1140 List<String> validKeys = FilterKeyEnum.getValidFiltersByAssetType(assetType);
1141 Predicate<NameValuePair> noMatch = p -> !validKeys.contains(p.getName());
1142 return params.stream().filter(noMatch).findAny();
1145 private List<String> getErrorResponseParams(Map<FilterKeyEnum, String> filters, ComponentTypeEnum assetType) {
1146 List<String> params = new ArrayList<>();
1147 if (1 == filters.size()) {
1148 params.add(assetType.getValue().toLowerCase());
1149 params.add(filters.keySet().iterator().next().getName());
1150 params.add(filters.values().iterator().next());
1152 params.add(assetType.getValue());
1153 params.add(filters.get(FilterKeyEnum.SUB_CATEGORY));
1154 params.add(filters.get(FilterKeyEnum.CATEGORY));
1159 public Either<List<Component>, StorageOperationStatus> getFilteredResources(Map<FilterKeyEnum, String> filters, boolean inTransaction) {
1161 String subCategoryName = filters.get(FilterKeyEnum.SUB_CATEGORY);
1162 String categoryName = filters.get(FilterKeyEnum.CATEGORY);
1163 ResourceTypeEnum resourceType = ResourceTypeEnum.getType(filters.get(FilterKeyEnum.RESOURCE_TYPE));
1164 Either<List<ImmutablePair<SubCategoryData, GraphEdge>>, StorageOperationStatus> subcategories = null;
1165 Optional<ImmutablePair<SubCategoryData, GraphEdge>> subCategoryData;
1167 if (categoryName != null) {
1168 subcategories = getAllSubCategories(categoryName);
1169 if (subcategories.isRight()) {
1170 filters.remove(FilterKeyEnum.SUB_CATEGORY);
1171 return Either.right(subcategories.right().value());
1174 if (subCategoryName != null) { // primary filter
1175 if (categoryName != null) {
1176 subCategoryData = validateCategoryHierarcy(subcategories.left().value(), subCategoryName);
1177 if (!subCategoryData.isPresent()) {
1178 return Either.right(StorageOperationStatus.MATCH_NOT_FOUND);
1180 return fetchByCategoryOrSubCategoryUid(subCategoryData.get().getLeft().getUniqueId(), NodeTypeEnum.Resource, inTransaction, resourceType);
1183 return fetchByCategoryOrSubCategoryName(subCategoryName, NodeTypeEnum.ResourceSubcategory, NodeTypeEnum.Resource, inTransaction, resourceType);
1185 if (subcategories != null) {
1186 return fetchByMainCategory(subcategories.left().value(), inTransaction, resourceType);
1188 return fetchComponentMetaDataByResourceType(filters.get(FilterKeyEnum.RESOURCE_TYPE), inTransaction);
1191 private Either<List<ImmutablePair<SubCategoryData, GraphEdge>>, StorageOperationStatus> getAllSubCategories(String categoryName) {
1192 Either<CategoryData, StorageOperationStatus> categoryResult = elementOperation.getNewCategoryData(categoryName, NodeTypeEnum.ResourceNewCategory, CategoryData.class);
1193 if (categoryResult.isRight()) {
1194 return Either.right(categoryResult.right().value());
1196 CategoryData categoryData = categoryResult.left().value();
1198 Either<List<ImmutablePair<SubCategoryData, GraphEdge>>, JanusGraphOperationStatus> childrenNodes = janusGraphGenericDao
1199 .getChildrenNodes(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.ResourceNewCategory), (String) categoryData.getUniqueId(),
1200 GraphEdgeLabels.SUB_CATEGORY, NodeTypeEnum.ResourceSubcategory, SubCategoryData.class);
1201 if (childrenNodes.isRight()) {
1202 return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(childrenNodes.right().value()));
1204 return Either.left(childrenNodes.left().value());
1207 private Optional<ImmutablePair<SubCategoryData, GraphEdge>> validateCategoryHierarcy(List<ImmutablePair<SubCategoryData, GraphEdge>> childNodes, String subCategoryName) {
1208 Predicate<ImmutablePair<SubCategoryData, GraphEdge>> matchName = p -> p.getLeft().getSubCategoryDataDefinition().getName().equals(subCategoryName);
1209 return childNodes.stream().filter(matchName).findAny();
1212 protected <T extends Component> Either<List<T>, StorageOperationStatus> fetchByCategoryOrSubCategoryUid(String categoryUid, NodeTypeEnum categoryType, boolean inTransaction, ResourceTypeEnum resourceType) {
1214 return collectComponents(categoryType, categoryUid, resourceType);
1216 if (!inTransaction) {
1217 janusGraphDao.commit();
1222 protected <T extends Component> Either<List<T>, StorageOperationStatus> fetchByCategoryOrSubCategoryName(String categoryName, NodeTypeEnum categoryType, NodeTypeEnum neededType, boolean inTransaction, ResourceTypeEnum resourceType) {
1223 List<T> components = new ArrayList<>();
1225 Class categoryClazz = categoryType == NodeTypeEnum.ServiceNewCategory ? CategoryData.class : SubCategoryData.class;
1226 Map<String, Object> props = new HashMap<>();
1227 props.put(GraphPropertiesDictionary.NORMALIZED_NAME.getProperty(), ValidationUtils.normalizeCategoryName4Uniqueness(categoryName));
1228 Either<List<GraphNode>, JanusGraphOperationStatus> getCategory = janusGraphGenericDao.getByCriteria(categoryType, props, categoryClazz);
1229 if (getCategory.isRight()) {
1230 return Either.right(StorageOperationStatus.CATEGORY_NOT_FOUND);
1232 for (GraphNode category : getCategory.left().value()) {
1233 Either<List<T>, StorageOperationStatus> result = collectComponents(neededType, category.getUniqueId(), resourceType);
1234 if (result.isRight() && result.right().value() != StorageOperationStatus.NOT_FOUND) {
1236 } else if (result.isLeft()){
1237 components.addAll(result.left().value());
1240 if (components.isEmpty()){
1241 return Either.right(StorageOperationStatus.NOT_FOUND);
1243 return Either.left(components);
1245 if (!inTransaction) {
1246 janusGraphDao.commit();
1252 private <T extends Component> Either<List<T>, StorageOperationStatus> collectComponents(NodeTypeEnum neededType, String categoryUid, ResourceTypeEnum resourceType) {
1253 List<T> components = new ArrayList<>();
1254 Either<GraphVertex, JanusGraphOperationStatus> categoryVertexById = janusGraphDao.getVertexById(categoryUid, JsonParseFlagEnum.NoParse);
1255 if (categoryVertexById.isRight()){
1256 JanusGraphOperationStatus status = categoryVertexById.right().value();
1257 log.debug("#collectComponents Failed to get category vertex with uid {}, status is {}.", categoryUid, status);
1258 return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status));
1260 GraphVertex categoryVertex = categoryVertexById.left().value();
1261 Either<List<GraphVertex>, JanusGraphOperationStatus> componentsVertices = janusGraphDao.getParentVertices(categoryVertex, EdgeLabelEnum.CATEGORY, JsonParseFlagEnum.ParseMetadata);
1262 if (componentsVertices.isRight()){
1263 JanusGraphOperationStatus status = componentsVertices.right().value();
1264 log.debug("#collectComponents Failed to get components vertices of category {}, status is {}.", categoryVertex, status);
1265 return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status));
1267 List<ComponentMetadataDataDefinition> componentsMetadataDataDefinition = componentsVertices.left().value()
1269 .filter(Objects::nonNull)
1270 .filter(componentsVertex -> Objects.nonNull(componentsVertex.getType()))
1271 .map(ModelConverter::convertToComponentMetadataDataDefinition)
1272 .collect(Collectors.toList());
1273 for (ComponentMetadataDataDefinition component : componentsMetadataDataDefinition) {
1274 boolean isHighest = isTrue(component.isHighestVersion());
1275 boolean isMatchingResourceType = isMatchingByResourceType(neededType, resourceType, component);
1276 boolean isDeleted = isTrue(component.isDeleted());
1277 boolean isArchived = isTrue(component.isArchived());
1278 if (isHighest && isMatchingResourceType && !isDeleted && !isArchived) {
1279 Either<T, StorageOperationStatus> result = toscaOperationFacade.getToscaElement(component.getUniqueId(), JsonParseFlagEnum.ParseMetadata);
1280 if (result.isRight()) {
1281 return Either.right(result.right().value());
1283 components.add(result.left().value());
1286 return Either.left(components);
1289 private boolean isMatchingByResourceType(NodeTypeEnum componentType, ResourceTypeEnum resourceType, ComponentMetadataDataDefinition componentData) {
1292 if (componentType == NodeTypeEnum.Resource) {
1293 if (resourceType == null) {
1296 isMatching = resourceType == ((ResourceMetadataDataDefinition) componentData).getResourceType();
1304 private <T extends Component> Either<List<T>, StorageOperationStatus> fetchByMainCategory(List<ImmutablePair<SubCategoryData, GraphEdge>> subcategories, boolean inTransaction, ResourceTypeEnum resourceType) {
1305 List<T> components = new ArrayList<>();
1307 for (ImmutablePair<SubCategoryData, GraphEdge> subCategory : subcategories) {
1308 Either<List<T>, StorageOperationStatus> fetched = fetchByCategoryOrSubCategoryUid(subCategory.getLeft().getUniqueId(), NodeTypeEnum.Resource,
1309 inTransaction, resourceType);
1310 if (fetched.isRight()) {
1313 components.addAll(fetched.left().value());
1315 return Either.left(components);
1318 private Either<List<Component>, StorageOperationStatus> fetchComponentMetaDataByResourceType(String resourceType, boolean inTransaction) {
1319 List<Component> components = null;
1320 StorageOperationStatus status;
1321 Wrapper<StorageOperationStatus> statusWrapper = new Wrapper<>();
1322 Either<List<Component>, StorageOperationStatus> result;
1324 ComponentParametersView fetchUsersAndCategoriesFilter = new ComponentParametersView(Arrays.asList(ComponentFieldsEnum.USERS.getValue(), ComponentFieldsEnum.CATEGORIES.getValue()));
1325 Either<List<Component>, StorageOperationStatus> getResources = toscaOperationFacade.fetchMetaDataByResourceType(resourceType, fetchUsersAndCategoriesFilter);
1326 if (getResources.isRight()) {
1327 status = getResources.right().value();
1328 if (status != StorageOperationStatus.NOT_FOUND) {
1329 statusWrapper.setInnerElement(getResources.right().value());
1331 components = new ArrayList<>();
1334 components = getResources.left().value();
1336 if (!statusWrapper.isEmpty()) {
1337 result = Either.right(statusWrapper.getInnerElement());
1339 result = Either.left(components);
1343 if (!inTransaction) {
1344 janusGraphDao.commit();
1350 public CatalogUpdateTimestamp getCatalogUpdateTime(String userId) {
1353 return toscaOperationFacade.getCatalogTimes();
1356 janusGraphDao.commit();