2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
19 * Modifications copyright (c) 2019 Nokia
20 * ================================================================================
22 package org.openecomp.sdc.be.components.impl;
24 import static org.apache.commons.lang.BooleanUtils.isTrue;
25 import static org.openecomp.sdc.be.components.impl.ImportUtils.Constants.DEFAULT_ICON;
27 import fj.data.Either;
28 import java.nio.charset.StandardCharsets;
29 import java.util.ArrayList;
30 import java.util.Arrays;
31 import java.util.EnumMap;
32 import java.util.HashMap;
33 import java.util.HashSet;
34 import java.util.LinkedList;
35 import java.util.List;
37 import java.util.Objects;
38 import java.util.Optional;
40 import java.util.function.Predicate;
41 import java.util.stream.Collectors;
42 import org.apache.commons.lang3.tuple.ImmutablePair;
43 import org.apache.http.NameValuePair;
44 import org.apache.http.client.utils.URLEncodedUtils;
45 import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
46 import org.openecomp.sdc.be.components.impl.exceptions.ByResponseFormatComponentException;
47 import org.openecomp.sdc.be.config.Configuration;
48 import org.openecomp.sdc.be.dao.api.ActionStatus;
49 import org.openecomp.sdc.be.dao.graph.datatype.GraphEdge;
50 import org.openecomp.sdc.be.dao.graph.datatype.GraphNode;
51 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
52 import org.openecomp.sdc.be.dao.jsongraph.GraphVertex;
53 import org.openecomp.sdc.be.dao.jsongraph.types.EdgeLabelEnum;
54 import org.openecomp.sdc.be.dao.jsongraph.types.JsonParseFlagEnum;
55 import org.openecomp.sdc.be.dao.neo4j.GraphEdgeLabels;
56 import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary;
57 import org.openecomp.sdc.be.datamodel.api.CategoryTypeEnum;
58 import org.openecomp.sdc.be.datamodel.utils.NodeTypeConvertUtils;
59 import org.openecomp.sdc.be.datatypes.components.ComponentMetadataDataDefinition;
60 import org.openecomp.sdc.be.datatypes.components.ResourceMetadataDataDefinition;
61 import org.openecomp.sdc.be.datatypes.enums.AssetTypeEnum;
62 import org.openecomp.sdc.be.datatypes.enums.ComponentFieldsEnum;
63 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
64 import org.openecomp.sdc.be.datatypes.enums.FilterKeyEnum;
65 import org.openecomp.sdc.be.datatypes.enums.GraphPropertyEnum;
66 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
67 import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum;
68 import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
69 import org.openecomp.sdc.be.model.ArtifactType;
70 import org.openecomp.sdc.be.model.BaseType;
71 import org.openecomp.sdc.be.model.CatalogUpdateTimestamp;
72 import org.openecomp.sdc.be.model.Component;
73 import org.openecomp.sdc.be.model.ComponentParametersView;
74 import org.openecomp.sdc.be.model.DistributionStatusEnum;
75 import org.openecomp.sdc.be.model.LifecycleStateEnum;
76 import org.openecomp.sdc.be.model.Product;
77 import org.openecomp.sdc.be.model.PropertyScope;
78 import org.openecomp.sdc.be.model.Resource;
79 import org.openecomp.sdc.be.model.Service;
80 import org.openecomp.sdc.be.model.Tag;
81 import org.openecomp.sdc.be.model.User;
82 import org.openecomp.sdc.be.model.catalog.CatalogComponent;
83 import org.openecomp.sdc.be.model.category.CategoryDefinition;
84 import org.openecomp.sdc.be.model.category.GroupingDefinition;
85 import org.openecomp.sdc.be.model.category.SubCategoryDefinition;
86 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ArtifactsOperations;
87 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.InterfaceOperation;
88 import org.openecomp.sdc.be.model.jsonjanusgraph.utils.ModelConverter;
89 import org.openecomp.sdc.be.model.operations.api.IElementOperation;
90 import org.openecomp.sdc.be.model.operations.api.IGroupInstanceOperation;
91 import org.openecomp.sdc.be.model.operations.api.IGroupOperation;
92 import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation;
93 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
94 import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter;
95 import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation;
96 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
97 import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
98 import org.openecomp.sdc.be.resources.data.category.CategoryData;
99 import org.openecomp.sdc.be.resources.data.category.SubCategoryData;
100 import org.openecomp.sdc.be.ui.model.UiCategories;
101 import org.openecomp.sdc.be.user.Role;
102 import org.openecomp.sdc.be.user.UserBusinessLogic;
103 import org.openecomp.sdc.common.datastructure.Wrapper;
104 import org.openecomp.sdc.common.log.wrappers.Logger;
105 import org.openecomp.sdc.common.util.ValidationUtils;
106 import org.openecomp.sdc.exception.ResponseFormat;
107 import org.springframework.beans.factory.annotation.Autowired;
109 @org.springframework.stereotype.Component("elementsBusinessLogic")
110 public class ElementBusinessLogic extends BaseBusinessLogic {
112 private static final Logger log = Logger.getLogger(ElementBusinessLogic.class);
113 private static final String SERVICES = "services";
114 private static final String RESOURCES = "resources";
115 private static final String VALIDATION_OF_USER_FAILED_USER_ID = "Validation of user failed, userId {}";
116 private static final String COMPONENT_TYPE_IS_INVALID = "Component type {} is invalid";
117 private static final String VALIDATION_OF_USER_ROLE_FAILED_USER_ID = "Validation of user role failed, userId {}";
118 private final IElementOperation elementOperation;
119 private final UserBusinessLogic userAdminManager;
122 public ElementBusinessLogic(IElementOperation elementDao, IGroupOperation groupOperation, IGroupInstanceOperation groupInstanceOperation,
123 IGroupTypeOperation groupTypeOperation, GroupBusinessLogic groupBusinessLogic, InterfaceOperation interfaceOperation,
124 InterfaceLifecycleOperation interfaceLifecycleTypeOperation, ArtifactsOperations artifactToscaOperation,
125 IElementOperation elementOperation, UserBusinessLogic userAdminManager) {
126 super(elementDao, groupOperation, groupInstanceOperation, groupTypeOperation, interfaceOperation, interfaceLifecycleTypeOperation,
127 artifactToscaOperation);
128 this.elementOperation = elementOperation;
129 this.userAdminManager = userAdminManager;
136 public Either<Map<String, List<? extends Component>>, ResponseFormat> getFollowed(User user) {
137 // Used for not getting duplicated followed. Cheaper than checking ArrayList.contains
138 Either<Map<String, Set<? extends Component>>, ResponseFormat> response = null;
140 String role = user.getRole();
141 String userId = user.getUserId();
142 Role currentRole = Role.valueOf(role);
143 switch (currentRole) {
145 response = handleDesigner(userId);
147 case PRODUCT_STRATEGIST:
148 response = handleProductStrategist();
150 case PRODUCT_MANAGER:
151 response = handleProductManager(userId);
154 response = handleAdmin();
157 response = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
160 // 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)
161 return convertedToListResponse(response);
164 private Either<Map<String, List<? extends Component>>, ResponseFormat> convertedToListResponse(
165 Either<Map<String, Set<? extends Component>>, ResponseFormat> setResponse) {
166 Map<String, List<? extends Component>> arrayResponse = new HashMap<>();
167 if (setResponse.isLeft()) {
168 for (Map.Entry<String, Set<? extends Component>> entry : setResponse.left().value().entrySet()) {
169 arrayResponse.put(entry.getKey(), new ArrayList(new HashSet(entry.getValue())));
171 return Either.left(arrayResponse);
173 return Either.right(setResponse.right().value());
176 private Either<Map<String, Set<? extends Component>>, ResponseFormat> handleAdmin() {
177 Either<Map<String, Set<? extends Component>>, ResponseFormat> response;
178 // userId should stay null
179 Set<LifecycleStateEnum> lifecycleStates = new HashSet<>();
180 lifecycleStates.add(LifecycleStateEnum.CERTIFIED);
181 response = getFollowedResourcesAndServices(null, lifecycleStates, new HashSet<>());
185 private Either<Map<String, Set<? extends Component>>, ResponseFormat> handleDesigner(String userId) {
186 Set<LifecycleStateEnum> lifecycleStates = new HashSet<>();
187 Set<LifecycleStateEnum> lastStateStates = new HashSet<>();
188 Either<Map<String, Set<? extends Component>>, ResponseFormat> response;
189 lifecycleStates.add(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN);
190 lifecycleStates.add(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT);
191 lifecycleStates.add(LifecycleStateEnum.CERTIFIED);
193 lastStateStates.add(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN);
194 response = getFollowedResourcesAndServices(userId, lifecycleStates, lastStateStates);
198 private Either<Map<String, Set<? extends Component>>, ResponseFormat> handleProductStrategist() {
199 // Should be empty list according to Ella, 13/03/16
200 Map<String, Set<? extends Component>> result = new HashMap<>();
201 result.put("products", new HashSet<>());
202 return Either.left(result);
205 private Either<Map<String, Set<? extends Component>>, ResponseFormat> handleProductManager(String userId) {
206 Set<LifecycleStateEnum> lifecycleStates = new HashSet<>();
207 Set<LifecycleStateEnum> lastStateStates = new HashSet<>();
208 Either<Map<String, Set<? extends Component>>, ResponseFormat> response;
209 lifecycleStates.add(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN);
210 lifecycleStates.add(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT);
211 lifecycleStates.add(LifecycleStateEnum.CERTIFIED);
213 lastStateStates.add(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN);
214 response = getFollowedProducts(userId, lifecycleStates, lastStateStates);
218 private Either<Map<String, Set<? extends Component>>, ResponseFormat> getFollowedResourcesAndServices(String userId,
219 Set<LifecycleStateEnum> lifecycleStates,
220 Set<LifecycleStateEnum> lastStateStates) {
222 Either<Set<Resource>, StorageOperationStatus> resources = toscaOperationFacade
223 .getFollowed(userId, lifecycleStates, lastStateStates, ComponentTypeEnum.RESOURCE);
224 if (resources.isLeft()) {
225 Either<Set<Service>, StorageOperationStatus> services = toscaOperationFacade
226 .getFollowed(userId, lifecycleStates, lastStateStates, ComponentTypeEnum.SERVICE);
227 if (services.isLeft()) {
228 Map<String, Set<? extends Component>> result = new HashMap<>();
229 result.put(SERVICES, services.left().value());
230 result.put(RESOURCES, resources.left().value());
231 return Either.left(result);
233 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(services.right().value())));
236 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(resources.right().value())));
239 janusGraphDao.commit();
243 private Either<Map<String, Set<? extends Component>>, ResponseFormat> getFollowedProducts(String userId, Set<LifecycleStateEnum> lifecycleStates,
244 Set<LifecycleStateEnum> lastStateStates) {
245 Either<Set<Product>, StorageOperationStatus> products = toscaOperationFacade
246 .getFollowed(userId, lifecycleStates, lastStateStates, ComponentTypeEnum.PRODUCT);
247 if (products.isLeft()) {
248 Map<String, Set<? extends Component>> result = new HashMap<>();
249 result.put("products", products.left().value());
250 return Either.left(result);
252 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(products.right().value())));
257 * New categories flow - start
259 public Either<List<CategoryDefinition>, ActionStatus> getAllResourceCategories() {
260 return elementOperation.getAllResourceCategories();
263 public Either<List<CategoryDefinition>, ActionStatus> getAllServiceCategories() {
264 return elementOperation.getAllServiceCategories();
267 public Either<CategoryDefinition, ResponseFormat> createCategory(CategoryDefinition category, String componentTypeParamName, String userId) {
268 AuditingActionEnum auditingAction = AuditingActionEnum.ADD_CATEGORY;
269 ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName);
270 String componentType = componentTypeEnum == null ? componentTypeParamName : componentTypeEnum.getValue();
271 CategoryTypeEnum categoryType = CategoryTypeEnum.CATEGORY;
272 User user = validateUserExists(userId);
273 if (category == null) {
274 log.debug("Category json is invalid");
275 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
276 handleCategoryAuditing(responseFormat, user, null, auditingAction, componentType);
277 return Either.right(responseFormat);
279 String categoryName = category.getName();
280 // For auditing of failures we need the original non-normalized name
281 String origCategoryName = categoryName;
282 if (componentTypeEnum == null) {
283 log.debug(COMPONENT_TYPE_IS_INVALID, componentTypeParamName);
284 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
285 handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
286 return Either.right(responseFormat);
288 Either<Boolean, ResponseFormat> validateUserRole = validateUserRole(user, componentTypeEnum);
289 if (validateUserRole.isRight()) {
290 log.debug(VALIDATION_OF_USER_ROLE_FAILED_USER_ID, userId);
291 ResponseFormat responseFormat = validateUserRole.right().value();
292 handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
293 return Either.right(responseFormat);
295 if (!ValidationUtils.validateCategoryDisplayNameFormat(categoryName)) {
296 log.debug("Category display name format is invalid, name {}, componentType {}", categoryName, componentType);
297 ResponseFormat responseFormat = componentsUtils
298 .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, componentType, categoryType.getValue());
299 handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
300 return Either.right(responseFormat);
302 categoryName = ValidationUtils.normalizeCategoryName4Display(categoryName);
303 if (!ValidationUtils.validateCategoryDisplayNameLength(categoryName)) {
304 log.debug("Category display name length is invalid, should be from 4 to 25 chars, name {}, componentType {}", categoryName,
306 ResponseFormat responseFormat = componentsUtils
307 .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, componentType, categoryType.getValue());
308 handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
309 return Either.right(responseFormat);
311 category.setName(categoryName);
312 String normalizedName = ValidationUtils.normalizeCategoryName4Uniqueness(categoryName);
313 category.setNormalizedName(normalizedName);
314 if (ValidationUtils.validateCategoryIconNotEmpty(category.getIcons())) {
315 log.debug("createCategory: setting category icon to default icon since service category was created without an icon ");
316 category.setIcons(Arrays.asList(DEFAULT_ICON));
318 NodeTypeEnum nodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, categoryType);
319 Either<Boolean, ActionStatus> categoryUniqueEither = elementOperation.isCategoryUniqueForType(nodeType, normalizedName);
320 if (categoryUniqueEither.isRight()) {
321 log.debug("Failed to check category uniqueness, name {}, componentType {}", categoryName, componentType);
322 ResponseFormat responseFormat = componentsUtils.getResponseFormat(categoryUniqueEither.right().value());
323 handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
324 return Either.right(responseFormat);
326 Boolean isCategoryUnique = categoryUniqueEither.left().value();
327 if (!isCategoryUnique) {
328 log.debug("Category is not unique, name {}, componentType {}", categoryName, componentType);
329 ResponseFormat responseFormat = componentsUtils
330 .getResponseFormat(ActionStatus.COMPONENT_CATEGORY_ALREADY_EXISTS, componentType, categoryName);
331 handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
332 return Either.right(responseFormat);
334 Either<CategoryDefinition, ActionStatus> createCategoryByType = elementOperation.createCategory(category, nodeType);
335 if (createCategoryByType.isRight()) {
336 log.debug("Failed to create category, name {}, componentType {}", categoryName, componentType);
337 ResponseFormat responseFormat = componentsUtils
338 .getResponseFormat(ActionStatus.COMPONENT_CATEGORY_ALREADY_EXISTS, componentType, categoryName);
339 handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
340 return Either.right(componentsUtils.getResponseFormat(createCategoryByType.right().value()));
342 category = createCategoryByType.left().value();
343 log.debug("Created category for component {}, name {}, uniqueId {}", componentType, categoryName, category.getUniqueId());
344 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.CREATED);
345 handleCategoryAuditing(responseFormat, user, category.getName(), auditingAction, componentType);
346 return Either.left(category);
349 public Either<SubCategoryDefinition, ResponseFormat> createSubCategory(SubCategoryDefinition subCategory, String componentTypeParamName,
350 String parentCategoryId, String userId) {
351 AuditingActionEnum auditingAction = AuditingActionEnum.ADD_SUB_CATEGORY;
352 ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName);
353 String componentType = componentTypeEnum == null ? componentTypeParamName : componentTypeEnum.getValue();
354 CategoryTypeEnum categoryType = CategoryTypeEnum.SUBCATEGORY;
356 String parentCategoryName = parentCategoryId;
357 if (subCategory == null) {
358 log.debug("Sub-category json is invalid");
359 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
360 handleCategoryAuditing(responseFormat, null, parentCategoryName, null, auditingAction, componentType);
361 return Either.right(responseFormat);
363 String subCategoryName = subCategory.getName();
364 // For auditing of failures we need the original non-normalized name
365 String origSubCategoryName = subCategoryName;
368 user = validateUserExists(userId);
369 } catch (ByActionStatusComponentException e) {
370 ResponseFormat responseFormat = componentsUtils.getResponseFormat(e.getActionStatus(), e.getParams());
371 handleComponentException(userId, auditingAction, componentType, parentCategoryName, origSubCategoryName, responseFormat);
373 } catch (ByResponseFormatComponentException e) {
374 ResponseFormat responseFormat = e.getResponseFormat();
375 handleComponentException(userId, auditingAction, componentType, parentCategoryName, origSubCategoryName, responseFormat);
378 if (componentTypeEnum == null) {
379 log.debug(COMPONENT_TYPE_IS_INVALID, componentTypeParamName);
380 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
381 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
382 return Either.right(responseFormat);
384 Either<Boolean, ResponseFormat> validateComponentType = validateComponentTypeForCategory(componentTypeEnum, categoryType);
385 if (validateComponentType.isRight()) {
386 log.debug("Validation of component type for sub-category failed");
387 ResponseFormat responseFormat = validateComponentType.right().value();
388 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
389 return Either.right(responseFormat);
391 Either<Boolean, ResponseFormat> validateUserRole = validateUserRole(user, componentTypeEnum);
392 if (validateUserRole.isRight()) {
393 log.debug(VALIDATION_OF_USER_ROLE_FAILED_USER_ID, userId);
394 ResponseFormat responseFormat = validateUserRole.right().value();
395 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
396 return Either.right(responseFormat);
398 NodeTypeEnum parentNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.CATEGORY);
399 NodeTypeEnum childNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.SUBCATEGORY);
400 CategoryDefinition categoryDefinition;
401 Either<CategoryDefinition, ResponseFormat> validateCategoryExists = validateCategoryExists(parentNodeType, parentCategoryId,
403 if (validateCategoryExists.isRight()) {
404 log.debug("Validation of parent category exists failed, parent categoryId {}", parentCategoryId);
405 ResponseFormat responseFormat = validateCategoryExists.right().value();
406 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
407 return Either.right(responseFormat);
409 categoryDefinition = validateCategoryExists.left().value();
410 parentCategoryName = categoryDefinition.getName();
411 if (!ValidationUtils.validateCategoryDisplayNameFormat(subCategoryName)) {
412 log.debug("Sub-category display name format is invalid, name {}, componentType {}", subCategoryName, componentType);
413 ResponseFormat responseFormat = componentsUtils
414 .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, componentType, categoryType.getValue());
415 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
416 return Either.right(responseFormat);
418 subCategoryName = ValidationUtils.normalizeCategoryName4Display(subCategoryName);
419 if (!ValidationUtils.validateCategoryDisplayNameLength(subCategoryName)) {
420 log.debug("Sub-category display name length is invalid, should be from 4 to 25 chars, name {}, componentType {}", subCategoryName,
422 ResponseFormat responseFormat = componentsUtils
423 .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, componentType, categoryType.getValue());
424 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
425 return Either.right(responseFormat);
427 String normalizedName = ValidationUtils.normalizeCategoryName4Uniqueness(subCategoryName);
428 subCategory.setNormalizedName(normalizedName);
429 // Uniqueness under this category
430 Either<Boolean, ActionStatus> subCategoryUniqueForCategory = elementOperation
431 .isSubCategoryUniqueForCategory(childNodeType, normalizedName, parentCategoryId);
432 if (subCategoryUniqueForCategory.isRight()) {
433 log.debug("Failed to check sub-category uniqueness, parent name {}, subcategory norm name {}, componentType {}", parentCategoryName,
434 normalizedName, componentType);
435 ResponseFormat responseFormat = componentsUtils.getResponseFormat(subCategoryUniqueForCategory.right().value());
436 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
437 return Either.right(responseFormat);
439 Boolean isSubUnique = subCategoryUniqueForCategory.left().value();
441 log.debug("Sub-category is not unique for category, parent name {}, subcategory norm name {}, componentType {}", parentCategoryName,
442 normalizedName, componentType);
443 ResponseFormat responseFormat = componentsUtils
444 .getResponseFormat(ActionStatus.COMPONENT_SUB_CATEGORY_EXISTS_FOR_CATEGORY, componentType, subCategoryName, parentCategoryName);
445 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
446 return Either.right(responseFormat);
448 // Setting name of subcategory to fit the similar subcategory name
452 // For example if Network-->kUKU exists for service category Network,
454 // and user is trying to create Router-->Kuku for service category
458 // his subcategory name will be Router-->kUKU.
459 Either<SubCategoryDefinition, ActionStatus> subCategoryUniqueForType = elementOperation
460 .getSubCategoryUniqueForType(childNodeType, normalizedName);
461 if (subCategoryUniqueForType.isRight()) {
462 log.debug("Failed validation of whether similar sub-category exists, normalizedName {} componentType {}", normalizedName, componentType);
463 ResponseFormat responseFormat = componentsUtils.getResponseFormat(subCategoryUniqueForType.right().value());
464 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
465 return Either.right(responseFormat);
467 SubCategoryDefinition subCategoryDefinition = subCategoryUniqueForType.left().value();
468 if (subCategoryDefinition != null) {
469 subCategoryName = subCategoryDefinition.getName();
471 subCategory.setName(subCategoryName);
472 ///////////////////////////////////////////// Validations end
473 Either<SubCategoryDefinition, ActionStatus> createSubCategory = elementOperation
474 .createSubCategory(parentCategoryId, subCategory, childNodeType);
475 if (createSubCategory.isRight()) {
476 log.debug("Failed to create sub-category, name {}, componentType {}", subCategoryName, componentType);
477 ResponseFormat responseFormat = componentsUtils.getResponseFormat(subCategoryUniqueForType.right().value());
478 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
479 return Either.right(responseFormat);
481 SubCategoryDefinition subCategoryCreated = createSubCategory.left().value();
482 log.debug("Created sub-category for component {}, name {}, uniqueId {}", componentType, subCategoryName, subCategoryCreated.getUniqueId());
483 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.CREATED);
484 handleCategoryAuditing(responseFormat, user, parentCategoryName, subCategoryCreated.getName(), auditingAction, componentType);
485 return Either.left(subCategoryCreated);
488 private void handleComponentException(String userId, AuditingActionEnum auditingAction, String componentType, String parentCategoryName,
489 String origSubCategoryName, ResponseFormat responseFormat) {
491 log.debug(VALIDATION_OF_USER_FAILED_USER_ID, userId);
493 user.setUserId(userId);
494 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
497 private void handleComponentException(GroupingDefinition grouping, String userId, AuditingActionEnum auditingAction, String componentType,
498 String parentCategoryName, String parentSubCategoryName, ResponseFormat responseFormat) {
500 log.debug(VALIDATION_OF_USER_FAILED_USER_ID, userId);
502 user.setUserId(userId);
503 String groupingNameForAudit = grouping == null ? null : grouping.getName();
504 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, groupingNameForAudit, auditingAction, componentType);
507 private void handleComponentException(String componentType, String userId, ResponseFormat responseFormat) {
510 user.setUserId(userId);
511 log.debug(VALIDATION_OF_USER_FAILED_USER_ID, userId);
512 componentsUtils.auditGetCategoryHierarchy(user, componentType, responseFormat);
515 public Either<GroupingDefinition, ResponseFormat> createGrouping(GroupingDefinition grouping, String componentTypeParamName,
516 String grandParentCategoryId, String parentSubCategoryId, String userId) {
517 AuditingActionEnum auditingAction = AuditingActionEnum.ADD_GROUPING;
518 ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName);
519 String componentType = componentTypeEnum == null ? componentTypeParamName : componentTypeEnum.getValue();
520 CategoryTypeEnum categoryType = CategoryTypeEnum.GROUPING;
522 String parentCategoryName = grandParentCategoryId;
523 String parentSubCategoryName = parentSubCategoryId;
526 user = validateUserExists(userId);
527 } catch (ByResponseFormatComponentException e) {
528 ResponseFormat responseFormat = e.getResponseFormat();
529 handleComponentException(grouping, userId, auditingAction, componentType, parentCategoryName, parentSubCategoryName, responseFormat);
531 } catch (ByActionStatusComponentException e) {
532 ResponseFormat responseFormat = componentsUtils.getResponseFormat(e.getActionStatus(), e.getParams());
533 handleComponentException(grouping, userId, auditingAction, componentType, parentCategoryName, parentSubCategoryName, responseFormat);
536 if (grouping == null) {
537 log.debug("Grouping json is invalid");
538 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
539 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, null, auditingAction, componentType);
540 return Either.right(responseFormat);
542 String groupingName = grouping.getName();
543 // For auditing of failures we need the original non-normalized name
544 String origGroupingName = groupingName;
545 if (componentTypeEnum == null) {
546 log.debug(COMPONENT_TYPE_IS_INVALID, componentTypeParamName);
547 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
548 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
549 return Either.right(responseFormat);
551 Either<Boolean, ResponseFormat> validateComponentType = validateComponentTypeForCategory(componentTypeEnum, categoryType);
552 if (validateComponentType.isRight()) {
553 log.debug("Validation of component type for grouping failed");
554 ResponseFormat responseFormat = validateComponentType.right().value();
555 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
556 return Either.right(responseFormat);
558 Either<Boolean, ResponseFormat> validateUserRole = validateUserRole(user, componentTypeEnum);
559 if (validateUserRole.isRight()) {
560 log.debug(VALIDATION_OF_USER_ROLE_FAILED_USER_ID, userId);
561 ResponseFormat responseFormat = validateUserRole.right().value();
562 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
563 return Either.right(responseFormat);
565 NodeTypeEnum grandParentNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.CATEGORY);
566 NodeTypeEnum parentNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.SUBCATEGORY);
567 NodeTypeEnum childNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.GROUPING);
569 CategoryDefinition categoryDefinition;
570 Either<CategoryDefinition, ResponseFormat> validateCategoryExists = validateCategoryExists(grandParentNodeType, grandParentCategoryId,
572 if (validateCategoryExists.isRight()) {
573 log.debug("Validation of parent category exists failed, parent categoryId {}", grandParentCategoryId);
574 ResponseFormat responseFormat = validateCategoryExists.right().value();
575 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
576 return Either.right(responseFormat);
578 categoryDefinition = validateCategoryExists.left().value();
579 parentCategoryName = categoryDefinition.getName();
580 // Validate subcategory
581 SubCategoryDefinition subCategoryDefinition;
582 Either<SubCategoryDefinition, ResponseFormat> validateSubCategoryExists = validateSubCategoryExists(parentNodeType, parentSubCategoryId,
584 if (validateSubCategoryExists.isRight()) {
585 log.debug("Validation of parent sub-category exists failed, parent sub-category id {}", parentSubCategoryId);
586 ResponseFormat responseFormat = validateSubCategoryExists.right().value();
587 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
588 return Either.right(responseFormat);
590 subCategoryDefinition = validateSubCategoryExists.left().value();
591 parentSubCategoryName = subCategoryDefinition.getName();
592 if (!ValidationUtils.validateCategoryDisplayNameFormat(groupingName)) {
593 log.debug("Sub-category display name format is invalid, name {}, componentType {}", groupingName, componentType);
594 ResponseFormat responseFormat = componentsUtils
595 .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, componentType, categoryType.getValue());
596 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
597 return Either.right(responseFormat);
599 groupingName = ValidationUtils.normalizeCategoryName4Display(groupingName);
600 if (!ValidationUtils.validateCategoryDisplayNameLength(groupingName)) {
601 log.debug("Grouping display name length is invalid, should be from 4 to 25 chars, name {}, componentType {}", groupingName,
603 ResponseFormat responseFormat = componentsUtils
604 .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, componentType, categoryType.getValue());
605 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
606 return Either.right(responseFormat);
608 String normalizedName = ValidationUtils.normalizeCategoryName4Uniqueness(groupingName);
609 grouping.setNormalizedName(normalizedName);
610 // Uniqueness under this category
611 Either<Boolean, ActionStatus> groupingUniqueForSubCategory = elementOperation
612 .isGroupingUniqueForSubCategory(childNodeType, normalizedName, parentSubCategoryId);
613 if (groupingUniqueForSubCategory.isRight()) {
614 log.debug("Failed to check grouping uniqueness, parent name {}, grouping norm name {}, componentType {}", parentSubCategoryName,
615 normalizedName, componentType);
616 ResponseFormat responseFormat = componentsUtils.getResponseFormat(groupingUniqueForSubCategory.right().value());
617 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
618 return Either.right(responseFormat);
620 Boolean isGroupingUnique = groupingUniqueForSubCategory.left().value();
621 if (!isGroupingUnique) {
622 log.debug("Grouping is not unique for sub-category, parent name {}, grouping norm name {}, componentType {}", parentSubCategoryName,
623 normalizedName, componentType);
624 ResponseFormat responseFormat = componentsUtils
625 .getResponseFormat(ActionStatus.COMPONENT_GROUPING_EXISTS_FOR_SUB_CATEGORY, componentType, groupingName, parentSubCategoryName);
626 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
627 return Either.right(responseFormat);
629 // Setting name of grouping to fit the similar grouping name ignoring
633 // For example if Network-->kUKU exists for service sub-category
635 // Network, and user is trying to create grouping Router-->Kuku for
637 // service sub-category Router,
639 // his grouping name will be Router-->kUKU.
640 Either<GroupingDefinition, ActionStatus> groupingUniqueForType = elementOperation.getGroupingUniqueForType(childNodeType, normalizedName);
641 if (groupingUniqueForType.isRight()) {
642 log.debug("Failed validation of whether similar grouping exists, normalizedName {} componentType {}", normalizedName, componentType);
643 ResponseFormat responseFormat = componentsUtils.getResponseFormat(groupingUniqueForType.right().value());
644 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
645 return Either.right(responseFormat);
647 GroupingDefinition groupingDefinition = groupingUniqueForType.left().value();
648 if (groupingDefinition != null) {
649 groupingName = groupingDefinition.getName();
651 grouping.setName(groupingName);
652 ///////////////////////////////////////////// Validations end
653 Either<GroupingDefinition, ActionStatus> createGrouping = elementOperation.createGrouping(parentSubCategoryId, grouping, childNodeType);
654 if (createGrouping.isRight()) {
655 log.debug("Failed to create grouping, name {}, componentType {}", groupingName, componentType);
656 ResponseFormat responseFormat = componentsUtils.getResponseFormat(createGrouping.right().value());
657 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
658 return Either.right(responseFormat);
660 GroupingDefinition groupingCreated = createGrouping.left().value();
661 log.debug("Created grouping for component {}, name {}, uniqueId {}", componentType, groupingName, groupingCreated.getUniqueId());
662 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.CREATED);
663 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, groupingCreated.getName(), auditingAction,
665 return Either.left(groupingCreated);
668 public Either<List<CategoryDefinition>, ResponseFormat> getAllCategories(String componentType, String userId) {
669 ResponseFormat responseFormat;
670 User user = new User();
671 if (userId == null) {
672 user.setUserId("UNKNOWN");
673 responseFormat = componentsUtils.getResponseFormat(ActionStatus.MISSING_INFORMATION);
674 componentsUtils.auditGetCategoryHierarchy(user, componentType, responseFormat);
675 return Either.right(responseFormat);
678 user = validateUserExists(userId);
679 } catch (ByActionStatusComponentException e) {
680 responseFormat = componentsUtils.getResponseFormat(e.getActionStatus(), e.getParams());
681 handleComponentException(componentType, userId, responseFormat);
683 } catch (ByResponseFormatComponentException e) {
684 responseFormat = e.getResponseFormat();
685 handleComponentException(componentType, userId, responseFormat);
688 ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentType);
689 if (componentTypeEnum == null) {
690 log.debug("Cannot create category for component type {}", componentType);
691 responseFormat = componentsUtils.getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, "component type");
692 componentsUtils.auditGetCategoryHierarchy(user, componentType, responseFormat);
693 return Either.right(responseFormat);
695 NodeTypeEnum nodeTypeEnum = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.CATEGORY);
696 Either<List<CategoryDefinition>, ActionStatus> getAllCategoriesByType = elementOperation.getAllCategories(nodeTypeEnum, false);
697 if (getAllCategoriesByType.isRight()) {
698 responseFormat = componentsUtils.getResponseFormat(getAllCategoriesByType.right().value());
699 componentsUtils.auditGetCategoryHierarchy(user, componentType, responseFormat);
700 return Either.right(responseFormat);
702 List<CategoryDefinition> categories = getAllCategoriesByType.left().value();
703 responseFormat = componentsUtils.getResponseFormat(ActionStatus.OK);
704 componentsUtils.auditGetCategoryHierarchy(user, componentType, responseFormat);
705 return Either.left(categories);
708 public Either<UiCategories, ResponseFormat> getAllCategories(String userId) {
709 ResponseFormat responseFormat;
710 UiCategories categories = new UiCategories();
711 User user = validateUserExists(userId);
712 // GET resource categories
713 Either<List<CategoryDefinition>, ActionStatus> getResourceCategoriesByType = elementOperation
714 .getAllCategories(NodeTypeEnum.ResourceNewCategory, false);
715 if (getResourceCategoriesByType.isRight()) {
716 responseFormat = componentsUtils.getResponseFormat(getResourceCategoriesByType.right().value());
717 componentsUtils.auditGetCategoryHierarchy(user, ComponentTypeEnum.RESOURCE.getValue(), responseFormat);
718 return Either.right(responseFormat);
720 categories.setResourceCategories(getResourceCategoriesByType.left().value());
721 // GET service categories
722 Either<List<CategoryDefinition>, ActionStatus> getServiceCategoriesByType = elementOperation
723 .getAllCategories(NodeTypeEnum.ServiceNewCategory, false);
724 if (getServiceCategoriesByType.isRight()) {
725 responseFormat = componentsUtils.getResponseFormat(getServiceCategoriesByType.right().value());
726 componentsUtils.auditGetCategoryHierarchy(user, ComponentTypeEnum.SERVICE.getValue(), responseFormat);
727 return Either.right(responseFormat);
729 categories.setServiceCategories(getServiceCategoriesByType.left().value());
730 categories.setProductCategories(new ArrayList<>());
731 return Either.left(categories);
734 public Either<CategoryDefinition, ResponseFormat> deleteCategory(String categoryId, String componentTypeParamName, String userId) {
735 validateUserExists(userId);
736 ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName);
737 if (componentTypeEnum == null) {
738 log.debug("Cannot create category for component type {}", componentTypeParamName);
739 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
741 NodeTypeEnum nodeTypeEnum = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.CATEGORY);
742 Either<CategoryDefinition, ActionStatus> deleteCategoryByType = elementOperation.deleteCategory(nodeTypeEnum, categoryId);
743 if (deleteCategoryByType.isRight()) {
744 // auditing, logging here...
745 return Either.right(componentsUtils.getResponseFormat(deleteCategoryByType.right().value()));
747 CategoryDefinition category = deleteCategoryByType.left().value();
748 log.debug("Delete category for component {}, name {}, uniqueId {}", nodeTypeEnum, category.getName(), category.getUniqueId());
749 return Either.left(category);
752 public Either<SubCategoryDefinition, ResponseFormat> deleteSubCategory(String parentSubCategoryId, String componentTypeParamName, String userId) {
753 validateUserExists(userId);
754 ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName);
755 if (componentTypeEnum == null) {
756 log.debug("Cannot delete sub-category for component type {}", componentTypeParamName);
757 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
759 NodeTypeEnum nodeTypeEnum = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.SUBCATEGORY);
760 Either<SubCategoryDefinition, ActionStatus> deleteSubCategoryByType = elementOperation.deleteSubCategory(nodeTypeEnum, parentSubCategoryId);
761 if (deleteSubCategoryByType.isRight()) {
762 // auditing, logging here...
763 return Either.right(componentsUtils.getResponseFormat(deleteSubCategoryByType.right().value()));
765 SubCategoryDefinition subCategory = deleteSubCategoryByType.left().value();
766 log.debug("Deleted sub-category for component {}, name {}, uniqueId {}", nodeTypeEnum, subCategory.getName(), subCategory.getUniqueId());
767 return Either.left(subCategory);
770 public Either<GroupingDefinition, ResponseFormat> deleteGrouping(String groupingId, String componentTypeParamName, String userId) {
771 validateUserExists(userId);
772 ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName);
773 if (componentTypeEnum == null) {
774 log.debug("Cannot delete grouping for component type {}", componentTypeParamName);
775 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
777 NodeTypeEnum nodeTypeEnum = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.GROUPING);
778 Either<GroupingDefinition, ActionStatus> deleteGroupingByType = elementOperation.deleteGrouping(nodeTypeEnum, groupingId);
779 if (deleteGroupingByType.isRight()) {
780 // auditing, logging here...
781 return Either.right(componentsUtils.getResponseFormat(deleteGroupingByType.right().value()));
783 GroupingDefinition deletedGrouping = deleteGroupingByType.left().value();
784 log.debug("Deleted grouping for component {}, name {}, uniqueId {}", nodeTypeEnum, deletedGrouping.getName(), deletedGrouping.getUniqueId());
785 return Either.left(deletedGrouping);
788 private Either<Boolean, ResponseFormat> validateUserRole(User user, ComponentTypeEnum componentTypeEnum) {
789 String role = user.getRole();
790 boolean validAdminAction =
791 role.equals(Role.ADMIN.name()) && (componentTypeEnum == ComponentTypeEnum.SERVICE || componentTypeEnum == ComponentTypeEnum.RESOURCE);
792 boolean validProductAction = role.equals(Role.PRODUCT_STRATEGIST.name()) && (componentTypeEnum == ComponentTypeEnum.PRODUCT);
793 if (!(validAdminAction || validProductAction)) {
794 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION);
795 log.debug("User not permitted to perform operation on category, userId = {}, role = {}, componentType = {}", user.getUserId(), role,
797 return Either.right(responseFormat);
799 return Either.left(true);
802 private Either<Boolean, ResponseFormat> validateComponentTypeForCategory(ComponentTypeEnum componentType, CategoryTypeEnum categoryType) {
803 boolean validResourceAction = componentType == ComponentTypeEnum.RESOURCE && (categoryType == CategoryTypeEnum.CATEGORY
804 || categoryType == CategoryTypeEnum.SUBCATEGORY);
805 boolean validServiceAction = componentType == ComponentTypeEnum.SERVICE && categoryType == CategoryTypeEnum.CATEGORY;
806 boolean validProductAction = componentType == ComponentTypeEnum.PRODUCT; // can
815 if (!(validResourceAction || validServiceAction || validProductAction)) {
816 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
817 log.debug("It's not allowed to create category type {} for component type {}", categoryType, componentType);
818 return Either.right(responseFormat);
820 return Either.left(true);
823 private Either<CategoryDefinition, ResponseFormat> validateCategoryExists(NodeTypeEnum nodeType, String categoryId,
824 ComponentTypeEnum componentType) {
825 Either<CategoryDefinition, ActionStatus> categoryByTypeAndId = elementOperation.getCategory(nodeType, categoryId);
826 if (categoryByTypeAndId.isRight()) {
827 log.debug("Failed to fetch parent category, parent categoryId {}", categoryId);
828 ActionStatus actionStatus = categoryByTypeAndId.right().value();
829 ResponseFormat responseFormat;
830 if (actionStatus == ActionStatus.COMPONENT_CATEGORY_NOT_FOUND) {
831 responseFormat = componentsUtils
832 .getResponseFormat(actionStatus, componentType.getValue().toLowerCase(), CategoryTypeEnum.CATEGORY.getValue(), "");
834 responseFormat = componentsUtils.getResponseFormat(actionStatus);
836 return Either.right(responseFormat);
838 return Either.left(categoryByTypeAndId.left().value());
841 private Either<SubCategoryDefinition, ResponseFormat> validateSubCategoryExists(NodeTypeEnum nodeType, String subCategoryId,
842 ComponentTypeEnum componentType) {
843 Either<SubCategoryDefinition, ActionStatus> subCategoryByTypeAndId = elementOperation.getSubCategory(nodeType, subCategoryId);
844 if (subCategoryByTypeAndId.isRight()) {
845 log.debug("Failed to fetch parent category, parent categoryId {}", subCategoryId);
846 ActionStatus actionStatus = subCategoryByTypeAndId.right().value();
847 ResponseFormat responseFormat;
848 if (actionStatus == ActionStatus.COMPONENT_CATEGORY_NOT_FOUND) {
849 responseFormat = componentsUtils
850 .getResponseFormat(actionStatus, componentType.getValue().toLowerCase(), CategoryTypeEnum.SUBCATEGORY.getValue(), "");
852 responseFormat = componentsUtils.getResponseFormat(actionStatus);
854 return Either.right(responseFormat);
856 return Either.left(subCategoryByTypeAndId.left().value());
859 private void handleCategoryAuditing(ResponseFormat responseFormat, User user, String category, AuditingActionEnum auditingAction,
860 String componentType) {
861 componentsUtils.auditCategory(responseFormat, user, category, null, null, auditingAction, componentType);
864 private void handleCategoryAuditing(ResponseFormat responseFormat, User user, String category, String subCategory,
865 AuditingActionEnum auditingAction, String componentType) {
866 componentsUtils.auditCategory(responseFormat, user, category, subCategory, null, auditingAction, componentType);
869 private void handleCategoryAuditing(ResponseFormat responseFormat, User user, String category, String subCategory, String grouping,
870 AuditingActionEnum auditingAction, String componentType) {
871 componentsUtils.auditCategory(responseFormat, user, category, subCategory, grouping, auditingAction, componentType);
875 * New categories flow - end
877 public Either<List<Tag>, ActionStatus> getAllTags(String userId) {
878 ActionStatus status = validateUserExistsActionStatus(userId);
879 if (ActionStatus.OK != status) {
880 return Either.right(status);
882 return elementOperation.getAllTags();
885 public Either<List<PropertyScope>, ActionStatus> getAllPropertyScopes(String userId) {
886 ActionStatus status = validateUserExistsActionStatus(userId);
887 if (ActionStatus.OK != status) {
888 return Either.right(status);
890 return elementOperation.getAllPropertyScopes();
893 public Either<List<ArtifactType>, ActionStatus> getAllArtifactTypes(final String userId) {
894 ActionStatus status = validateUserExistsActionStatus(userId);
895 if (ActionStatus.OK != status) {
896 return Either.right(status);
898 return Either.left(elementOperation.getAllArtifactTypes());
901 public Either<Configuration.HeatDeploymentArtifactTimeout, ActionStatus> getDefaultHeatTimeout() {
902 return elementOperation.getDefaultHeatTimeout();
905 public Either<Map<String, List<CatalogComponent>>, ResponseFormat> getCatalogComponents(String userId, List<OriginTypeEnum> excludeTypes) {
907 return toscaOperationFacade.getCatalogOrArchiveComponents(true, excludeTypes)
908 .bimap(this::groupByComponentType, err -> componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(err)));
910 janusGraphDao.commit();
914 private Map<String, List<CatalogComponent>> groupByComponentType(List<CatalogComponent> components) {
915 Map<String, List<CatalogComponent>> map = components.stream()
916 .collect(Collectors.groupingBy(cmpt -> cmptTypeToString(cmpt.getComponentType())));
917 // fixed response for UI!!! UI need to receive always map!
919 map = new HashMap<>();
921 map.computeIfAbsent(RESOURCES, k -> new ArrayList());
922 map.computeIfAbsent(SERVICES, k -> new ArrayList());
926 private String cmptTypeToString(ComponentTypeEnum componentTypeEnum) {
927 switch (componentTypeEnum) {
933 throw new IllegalStateException("resources or services only");
937 public Either<List<? extends Component>, ResponseFormat> getFilteredCatalogComponents(String assetType, Map<FilterKeyEnum, String> filters,
939 ComponentTypeEnum assetTypeEnum = AssetTypeEnum.convertToComponentTypeEnum(assetType);
941 Optional<NameValuePair> invalidFilter = findInvalidFilter(query, assetTypeEnum);
942 if (invalidFilter.isPresent()) {
943 log.debug("getFilteredAssetList: invalid filter key");
944 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_FILTER_KEY, invalidFilter.get().getName(),
945 FilterKeyEnum.getValidFiltersByAssetType(assetTypeEnum).toString()));
948 if (filters == null || filters.isEmpty()) {
949 Either<List<Component>, StorageOperationStatus> componentsList = toscaOperationFacade.getCatalogComponents(assetTypeEnum, null, false);
950 if (componentsList.isRight()) {
951 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(componentsList.right().value())));
953 return Either.left(componentsList.left().value());
955 Either<List<Component>, StorageOperationStatus> result = getFilteredComponents(filters, assetTypeEnum, false);
956 // category hierarchy mismatch or category/subCategory/distributionStatus not found
957 if (result.isRight()) {
958 List<String> params = getErrorResponseParams(filters, assetTypeEnum);
959 return Either.right(componentsUtils
960 .getResponseFormat(componentsUtils.convertFromStorageResponse(result.right().value()), params.get(0), params.get(1), params.get(2)));
962 if (result.left().value().isEmpty()) {// no assets found for requested
965 return Either.right(componentsUtils.getResponseFormat(ActionStatus.NO_ASSETS_FOUND, assetType, query));
967 return Either.left(result.left().value());
970 private Either<List<Component>, StorageOperationStatus> getFilteredComponents(Map<FilterKeyEnum, String> filters, ComponentTypeEnum assetType,
971 boolean inTransaction) {
972 Either<List<Component>, StorageOperationStatus> assetResult = Either.left(new LinkedList<>());
973 if (assetType == ComponentTypeEnum.RESOURCE) {
974 assetResult = getFilteredResources(filters, inTransaction);
975 } else if (assetType == ComponentTypeEnum.SERVICE) {
976 assetResult = getFilteredServices(filters, inTransaction);
981 private <T extends Component> Either<List<T>, StorageOperationStatus> getFilteredServices(Map<FilterKeyEnum, String> filters,
982 boolean inTransaction) {
983 Either<List<T>, StorageOperationStatus> components = null;
984 String categoryName = filters.get(FilterKeyEnum.CATEGORY);
985 String distributionStatus = filters.get(FilterKeyEnum.DISTRIBUTION_STATUS);
986 DistributionStatusEnum distEnum = DistributionStatusEnum.findState(distributionStatus);
987 if (distributionStatus != null && distEnum == null) {
988 filters.remove(FilterKeyEnum.CATEGORY);
989 return Either.right(StorageOperationStatus.CATEGORY_NOT_FOUND);
991 if (categoryName != null) { // primary filter
992 components = fetchByCategoryOrSubCategoryName(categoryName, NodeTypeEnum.ServiceNewCategory, NodeTypeEnum.Service, inTransaction, null);
993 if (components.isLeft() && distEnum != null) {// secondary filter
994 Predicate<T> statusFilter = p -> ((Service) p).getDistributionStatus() == distEnum;
995 return Either.left(components.left().value().stream().filter(statusFilter).collect(Collectors.toList()));
997 filters.remove(FilterKeyEnum.DISTRIBUTION_STATUS);
1000 Set<DistributionStatusEnum> distStatusSet = new HashSet<>();
1001 distStatusSet.add(distEnum);
1002 Either<List<Service>, StorageOperationStatus> servicesWithDistStatus = toscaOperationFacade.getServicesWithDistStatus(distStatusSet, null);
1003 if (servicesWithDistStatus.isRight()) { // not found == empty list
1004 return Either.left(new ArrayList<>());
1006 return Either.left((List<T>) servicesWithDistStatus.left().value());
1009 public Either<List<? extends Component>, ResponseFormat> getCatalogComponentsByUuidAndAssetType(String assetType, String uuid) {
1010 if (assetType == null || uuid == null) {
1011 log.debug("getCatalogComponentsByUuidAndAssetType: One of the function parameteres is null");
1012 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
1014 ComponentTypeEnum assetTypeEnum = AssetTypeEnum.convertToComponentTypeEnum(assetType);
1015 if (assetTypeEnum == null) {
1016 log.debug("getCatalogComponentsByUuidAndAssetType: Corresponding ComponentTypeEnum not found");
1017 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
1019 Map<GraphPropertyEnum, Object> additionalPropertiesToMatch = new EnumMap<>(GraphPropertyEnum.class);
1020 switch (assetTypeEnum) {
1022 additionalPropertiesToMatch.put(GraphPropertyEnum.COMPONENT_TYPE, ComponentTypeEnum.RESOURCE.name());
1025 additionalPropertiesToMatch.put(GraphPropertyEnum.COMPONENT_TYPE, ComponentTypeEnum.SERVICE.name());
1028 log.debug("getCatalogComponentsByUuidAndAssetType: Corresponding ComponentTypeEnum not allowed for this API");
1029 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
1031 Either<List<Component>, StorageOperationStatus> componentsListByUuid = toscaOperationFacade
1032 .getComponentListByUuid(uuid, additionalPropertiesToMatch);
1033 if (componentsListByUuid.isRight()) {
1034 log.debug("getCatalogComponentsByUuidAndAssetType: " + assetTypeEnum.getValue() + " fetching failed");
1035 ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(componentsListByUuid.right().value(), assetTypeEnum);
1036 return Either.right(componentsUtils.getResponseFormat(actionStatus, uuid));
1038 log.debug("getCatalogComponentsByUuidAndAssetType: " + assetTypeEnum.getValue() + assetTypeEnum.getValue() + "fetching successful");
1039 return Either.left(componentsListByUuid.left().value());
1042 public List<String> getAllComponentTypesParamNames() {
1043 List<String> paramNames = new ArrayList<>();
1044 paramNames.add(ComponentTypeEnum.SERVICE_PARAM_NAME);
1045 paramNames.add(ComponentTypeEnum.RESOURCE_PARAM_NAME);
1046 paramNames.add(ComponentTypeEnum.PRODUCT_PARAM_NAME);
1050 public List<String> getAllSupportedRoles() {
1051 Role[] values = Role.values();
1052 List<String> roleNames = new ArrayList<>();
1053 for (Role role : values) {
1054 roleNames.add(role.name());
1059 public Either<Map<String, String>, ActionStatus> getResourceTypesMap() {
1060 return elementOperation.getResourceTypesMap();
1063 private Optional<NameValuePair> findInvalidFilter(String query, ComponentTypeEnum assetType) {
1064 List<NameValuePair> params = URLEncodedUtils.parse(query, StandardCharsets.UTF_8);
1065 List<String> validKeys = FilterKeyEnum.getValidFiltersByAssetType(assetType);
1066 Predicate<NameValuePair> noMatch = p -> !validKeys.contains(p.getName());
1067 return params.stream().filter(noMatch).findAny();
1070 private List<String> getErrorResponseParams(Map<FilterKeyEnum, String> filters, ComponentTypeEnum assetType) {
1071 List<String> params = new ArrayList<>();
1072 if (1 == filters.size()) {
1073 params.add(assetType.getValue().toLowerCase());
1074 params.add(filters.keySet().iterator().next().getName());
1075 params.add(filters.values().iterator().next());
1077 params.add(assetType.getValue());
1078 params.add(filters.get(FilterKeyEnum.SUB_CATEGORY));
1079 params.add(filters.get(FilterKeyEnum.CATEGORY));
1084 public Either<List<Component>, StorageOperationStatus> getFilteredResources(Map<FilterKeyEnum, String> filters, boolean inTransaction) {
1085 String subCategoryName = filters.get(FilterKeyEnum.SUB_CATEGORY);
1086 String categoryName = filters.get(FilterKeyEnum.CATEGORY);
1087 ResourceTypeEnum resourceType = ResourceTypeEnum.getType(filters.get(FilterKeyEnum.RESOURCE_TYPE));
1088 Either<List<ImmutablePair<SubCategoryData, GraphEdge>>, StorageOperationStatus> subcategories = null;
1089 Optional<ImmutablePair<SubCategoryData, GraphEdge>> subCategoryData;
1090 if (categoryName != null) {
1091 subcategories = getAllSubCategories(categoryName);
1092 if (subcategories.isRight()) {
1093 filters.remove(FilterKeyEnum.SUB_CATEGORY);
1094 return Either.right(subcategories.right().value());
1097 if (subCategoryName != null) { // primary filter
1098 if (categoryName != null) {
1099 subCategoryData = validateCategoryHierarcy(subcategories.left().value(), subCategoryName);
1100 if (!subCategoryData.isPresent()) {
1101 return Either.right(StorageOperationStatus.MATCH_NOT_FOUND);
1103 return fetchByCategoryOrSubCategoryUid(subCategoryData.get().getLeft().getUniqueId(), NodeTypeEnum.Resource, inTransaction,
1106 return fetchByCategoryOrSubCategoryName(subCategoryName, NodeTypeEnum.ResourceSubcategory, NodeTypeEnum.Resource, inTransaction,
1109 if (subcategories != null) {
1110 return fetchByMainCategory(subcategories.left().value(), inTransaction, resourceType);
1112 return fetchComponentMetaDataByResourceType(filters.get(FilterKeyEnum.RESOURCE_TYPE), inTransaction);
1115 private Either<List<ImmutablePair<SubCategoryData, GraphEdge>>, StorageOperationStatus> getAllSubCategories(String categoryName) {
1116 Either<CategoryData, StorageOperationStatus> categoryResult = elementOperation
1117 .getNewCategoryData(categoryName, NodeTypeEnum.ResourceNewCategory, CategoryData.class);
1118 if (categoryResult.isRight()) {
1119 return Either.right(categoryResult.right().value());
1121 CategoryData categoryData = categoryResult.left().value();
1122 Either<List<ImmutablePair<SubCategoryData, GraphEdge>>, JanusGraphOperationStatus> childrenNodes = janusGraphGenericDao
1123 .getChildrenNodes(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.ResourceNewCategory), (String) categoryData.getUniqueId(),
1124 GraphEdgeLabels.SUB_CATEGORY, NodeTypeEnum.ResourceSubcategory, SubCategoryData.class);
1125 if (childrenNodes.isRight()) {
1126 return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(childrenNodes.right().value()));
1128 return Either.left(childrenNodes.left().value());
1131 private Optional<ImmutablePair<SubCategoryData, GraphEdge>> validateCategoryHierarcy(List<ImmutablePair<SubCategoryData, GraphEdge>> childNodes,
1132 String subCategoryName) {
1133 Predicate<ImmutablePair<SubCategoryData, GraphEdge>> matchName = p -> p.getLeft().getSubCategoryDataDefinition().getName()
1134 .equals(subCategoryName);
1135 return childNodes.stream().filter(matchName).findAny();
1138 protected <T extends Component> Either<List<T>, StorageOperationStatus> fetchByCategoryOrSubCategoryUid(String categoryUid,
1139 NodeTypeEnum categoryType,
1140 boolean inTransaction,
1141 ResourceTypeEnum resourceType) {
1143 return collectComponents(categoryType, categoryUid, resourceType);
1145 if (!inTransaction) {
1146 janusGraphDao.commit();
1151 protected <T extends Component> Either<List<T>, StorageOperationStatus> fetchByCategoryOrSubCategoryName(String categoryName,
1152 NodeTypeEnum categoryType,
1153 NodeTypeEnum neededType,
1154 boolean inTransaction,
1155 ResourceTypeEnum resourceType) {
1156 List<T> components = new ArrayList<>();
1158 Class categoryClazz = categoryType == NodeTypeEnum.ServiceNewCategory ? CategoryData.class : SubCategoryData.class;
1159 Map<String, Object> props = new HashMap<>();
1160 props.put(GraphPropertiesDictionary.NORMALIZED_NAME.getProperty(), ValidationUtils.normalizeCategoryName4Uniqueness(categoryName));
1161 Either<List<GraphNode>, JanusGraphOperationStatus> getCategory = janusGraphGenericDao.getByCriteria(categoryType, props, categoryClazz);
1162 if (getCategory.isRight()) {
1163 return Either.right(StorageOperationStatus.CATEGORY_NOT_FOUND);
1165 for (GraphNode category : getCategory.left().value()) {
1166 Either<List<T>, StorageOperationStatus> result = collectComponents(neededType, category.getUniqueId(), resourceType);
1167 if (result.isRight() && result.right().value() != StorageOperationStatus.NOT_FOUND) {
1169 } else if (result.isLeft()) {
1170 components.addAll(result.left().value());
1173 if (components.isEmpty()) {
1174 return Either.right(StorageOperationStatus.NOT_FOUND);
1176 return Either.left(components);
1178 if (!inTransaction) {
1179 janusGraphDao.commit();
1184 private <T extends Component> Either<List<T>, StorageOperationStatus> collectComponents(NodeTypeEnum neededType, String categoryUid,
1185 ResourceTypeEnum resourceType) {
1186 List<T> components = new ArrayList<>();
1187 Either<GraphVertex, JanusGraphOperationStatus> categoryVertexById = janusGraphDao.getVertexById(categoryUid, JsonParseFlagEnum.NoParse);
1188 if (categoryVertexById.isRight()) {
1189 JanusGraphOperationStatus status = categoryVertexById.right().value();
1190 log.debug("#collectComponents Failed to get category vertex with uid {}, status is {}.", categoryUid, status);
1191 return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status));
1193 GraphVertex categoryVertex = categoryVertexById.left().value();
1194 Either<List<GraphVertex>, JanusGraphOperationStatus> componentsVertices = janusGraphDao
1195 .getParentVertices(categoryVertex, EdgeLabelEnum.CATEGORY, JsonParseFlagEnum.ParseMetadata);
1196 if (componentsVertices.isRight()) {
1197 JanusGraphOperationStatus status = componentsVertices.right().value();
1198 log.debug("#collectComponents Failed to get components vertices of category {}, status is {}.", categoryVertex, status);
1199 return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status));
1201 List<ComponentMetadataDataDefinition> componentsMetadataDataDefinition = componentsVertices.left().value().stream().filter(Objects::nonNull)
1202 .filter(componentsVertex -> Objects.nonNull(componentsVertex.getType())).map(ModelConverter::convertToComponentMetadataDataDefinition)
1203 .collect(Collectors.toList());
1204 for (ComponentMetadataDataDefinition component : componentsMetadataDataDefinition) {
1205 boolean isHighest = isTrue(component.isHighestVersion());
1206 boolean isMatchingResourceType = isMatchingByResourceType(neededType, resourceType, component);
1207 boolean isDeleted = isTrue(component.isDeleted());
1208 boolean isArchived = isTrue(component.isArchived());
1209 if (isHighest && isMatchingResourceType && !isDeleted && !isArchived) {
1210 Either<T, StorageOperationStatus> result = toscaOperationFacade
1211 .getToscaElement(component.getUniqueId(), JsonParseFlagEnum.ParseMetadata);
1212 if (result.isRight()) {
1213 return Either.right(result.right().value());
1215 components.add(result.left().value());
1218 return Either.left(components);
1221 private boolean isMatchingByResourceType(NodeTypeEnum componentType, ResourceTypeEnum resourceType,
1222 ComponentMetadataDataDefinition componentData) {
1224 if (componentType == NodeTypeEnum.Resource) {
1225 if (resourceType == null) {
1228 isMatching = resourceType == ((ResourceMetadataDataDefinition) componentData).getResourceType();
1236 private <T extends Component> Either<List<T>, StorageOperationStatus> fetchByMainCategory(
1237 List<ImmutablePair<SubCategoryData, GraphEdge>> subcategories, boolean inTransaction, ResourceTypeEnum resourceType) {
1238 List<T> components = new ArrayList<>();
1239 for (ImmutablePair<SubCategoryData, GraphEdge> subCategory : subcategories) {
1240 Either<List<T>, StorageOperationStatus> fetched = fetchByCategoryOrSubCategoryUid(subCategory.getLeft().getUniqueId(),
1241 NodeTypeEnum.Resource, inTransaction, resourceType);
1242 if (fetched.isRight()) {
1245 components.addAll(fetched.left().value());
1247 return Either.left(components);
1250 private Either<List<Component>, StorageOperationStatus> fetchComponentMetaDataByResourceType(String resourceType, boolean inTransaction) {
1251 List<Component> components = null;
1252 StorageOperationStatus status;
1253 Wrapper<StorageOperationStatus> statusWrapper = new Wrapper<>();
1254 Either<List<Component>, StorageOperationStatus> result;
1256 ComponentParametersView fetchUsersAndCategoriesFilter = new ComponentParametersView(
1257 Arrays.asList(ComponentFieldsEnum.USERS.getValue(), ComponentFieldsEnum.CATEGORIES.getValue()));
1258 Either<List<Component>, StorageOperationStatus> getResources = toscaOperationFacade
1259 .fetchMetaDataByResourceType(resourceType, fetchUsersAndCategoriesFilter);
1260 if (getResources.isRight()) {
1261 status = getResources.right().value();
1262 if (status != StorageOperationStatus.NOT_FOUND) {
1263 statusWrapper.setInnerElement(getResources.right().value());
1265 components = new ArrayList<>();
1268 components = getResources.left().value();
1270 if (!statusWrapper.isEmpty()) {
1271 result = Either.right(statusWrapper.getInnerElement());
1273 result = Either.left(components);
1277 if (!inTransaction) {
1278 janusGraphDao.commit();
1283 public CatalogUpdateTimestamp getCatalogUpdateTime(String userId) {
1285 return toscaOperationFacade.getCatalogTimes();
1287 janusGraphDao.commit();
1291 public Either<List<BaseType>, ActionStatus> getBaseTypes(final String categoryName, final String userId) {
1292 final ActionStatus status = validateUserExistsActionStatus(userId);
1293 if (ActionStatus.OK != status) {
1294 return Either.right(status);
1296 return Either.left(elementOperation.getBaseTypes(categoryName));