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.CatalogUpdateTimestamp;
71 import org.openecomp.sdc.be.model.Component;
72 import org.openecomp.sdc.be.model.ComponentParametersView;
73 import org.openecomp.sdc.be.model.DistributionStatusEnum;
74 import org.openecomp.sdc.be.model.LifecycleStateEnum;
75 import org.openecomp.sdc.be.model.Product;
76 import org.openecomp.sdc.be.model.PropertyScope;
77 import org.openecomp.sdc.be.model.Resource;
78 import org.openecomp.sdc.be.model.Service;
79 import org.openecomp.sdc.be.model.Tag;
80 import org.openecomp.sdc.be.model.User;
81 import org.openecomp.sdc.be.model.catalog.CatalogComponent;
82 import org.openecomp.sdc.be.model.category.CategoryDefinition;
83 import org.openecomp.sdc.be.model.category.GroupingDefinition;
84 import org.openecomp.sdc.be.model.category.SubCategoryDefinition;
85 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ArtifactsOperations;
86 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.InterfaceOperation;
87 import org.openecomp.sdc.be.model.jsonjanusgraph.utils.ModelConverter;
88 import org.openecomp.sdc.be.model.operations.api.IElementOperation;
89 import org.openecomp.sdc.be.model.operations.api.IGroupInstanceOperation;
90 import org.openecomp.sdc.be.model.operations.api.IGroupOperation;
91 import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation;
92 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
93 import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter;
94 import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation;
95 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
96 import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
97 import org.openecomp.sdc.be.resources.data.category.CategoryData;
98 import org.openecomp.sdc.be.resources.data.category.SubCategoryData;
99 import org.openecomp.sdc.be.ui.model.UiCategories;
100 import org.openecomp.sdc.be.user.Role;
101 import org.openecomp.sdc.be.user.UserBusinessLogic;
102 import org.openecomp.sdc.common.datastructure.Wrapper;
103 import org.openecomp.sdc.common.log.wrappers.Logger;
104 import org.openecomp.sdc.common.util.ValidationUtils;
105 import org.openecomp.sdc.exception.ResponseFormat;
106 import org.springframework.beans.factory.annotation.Autowired;
108 @org.springframework.stereotype.Component("elementsBusinessLogic")
109 public class ElementBusinessLogic extends BaseBusinessLogic {
111 private static final Logger log = Logger.getLogger(ElementBusinessLogic.class);
112 private static final String SERVICES = "services";
113 private static final String RESOURCES = "resources";
114 private static final String VALIDATION_OF_USER_FAILED_USER_ID = "Validation of user failed, userId {}";
115 private static final String COMPONENT_TYPE_IS_INVALID = "Component type {} is invalid";
116 private static final String VALIDATION_OF_USER_ROLE_FAILED_USER_ID = "Validation of user role failed, userId {}";
117 private final IElementOperation elementOperation;
118 private final UserBusinessLogic userAdminManager;
121 public ElementBusinessLogic(IElementOperation elementDao, IGroupOperation groupOperation, IGroupInstanceOperation groupInstanceOperation,
122 IGroupTypeOperation groupTypeOperation, GroupBusinessLogic groupBusinessLogic, InterfaceOperation interfaceOperation,
123 InterfaceLifecycleOperation interfaceLifecycleTypeOperation, ArtifactsOperations artifactToscaOperation,
124 IElementOperation elementOperation, UserBusinessLogic userAdminManager) {
125 super(elementDao, groupOperation, groupInstanceOperation, groupTypeOperation, interfaceOperation, interfaceLifecycleTypeOperation,
126 artifactToscaOperation);
127 this.elementOperation = elementOperation;
128 this.userAdminManager = userAdminManager;
135 public Either<Map<String, List<? extends Component>>, ResponseFormat> getFollowed(User user) {
136 // Used for not getting duplicated followed. Cheaper than checking ArrayList.contains
137 Either<Map<String, Set<? extends Component>>, ResponseFormat> response = null;
139 String role = user.getRole();
140 String userId = user.getUserId();
141 Role currentRole = Role.valueOf(role);
142 switch (currentRole) {
144 response = handleDesigner(userId);
146 case PRODUCT_STRATEGIST:
147 response = handleProductStrategist();
149 case PRODUCT_MANAGER:
150 response = handleProductManager(userId);
153 response = handleAdmin();
156 response = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
159 // 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)
160 return convertedToListResponse(response);
163 private Either<Map<String, List<? extends Component>>, ResponseFormat> convertedToListResponse(
164 Either<Map<String, Set<? extends Component>>, ResponseFormat> setResponse) {
165 Map<String, List<? extends Component>> arrayResponse = new HashMap<>();
166 if (setResponse.isLeft()) {
167 for (Map.Entry<String, Set<? extends Component>> entry : setResponse.left().value().entrySet()) {
168 arrayResponse.put(entry.getKey(), new ArrayList(new HashSet(entry.getValue())));
170 return Either.left(arrayResponse);
172 return Either.right(setResponse.right().value());
175 private Either<Map<String, Set<? extends Component>>, ResponseFormat> handleAdmin() {
176 Either<Map<String, Set<? extends Component>>, ResponseFormat> response;
177 // userId should stay null
178 Set<LifecycleStateEnum> lifecycleStates = new HashSet<>();
179 lifecycleStates.add(LifecycleStateEnum.CERTIFIED);
180 response = getFollowedResourcesAndServices(null, lifecycleStates, new HashSet<>());
184 private Either<Map<String, Set<? extends Component>>, ResponseFormat> handleDesigner(String userId) {
185 Set<LifecycleStateEnum> lifecycleStates = new HashSet<>();
186 Set<LifecycleStateEnum> lastStateStates = new HashSet<>();
187 Either<Map<String, Set<? extends Component>>, ResponseFormat> response;
188 lifecycleStates.add(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN);
189 lifecycleStates.add(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT);
190 lifecycleStates.add(LifecycleStateEnum.CERTIFIED);
192 lastStateStates.add(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN);
193 response = getFollowedResourcesAndServices(userId, lifecycleStates, lastStateStates);
197 private Either<Map<String, Set<? extends Component>>, ResponseFormat> handleProductStrategist() {
198 // Should be empty list according to Ella, 13/03/16
199 Map<String, Set<? extends Component>> result = new HashMap<>();
200 result.put("products", new HashSet<>());
201 return Either.left(result);
204 private Either<Map<String, Set<? extends Component>>, ResponseFormat> handleProductManager(String userId) {
205 Set<LifecycleStateEnum> lifecycleStates = new HashSet<>();
206 Set<LifecycleStateEnum> lastStateStates = new HashSet<>();
207 Either<Map<String, Set<? extends Component>>, ResponseFormat> response;
208 lifecycleStates.add(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN);
209 lifecycleStates.add(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT);
210 lifecycleStates.add(LifecycleStateEnum.CERTIFIED);
212 lastStateStates.add(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN);
213 response = getFollowedProducts(userId, lifecycleStates, lastStateStates);
217 private Either<Map<String, Set<? extends Component>>, ResponseFormat> getFollowedResourcesAndServices(String userId,
218 Set<LifecycleStateEnum> lifecycleStates,
219 Set<LifecycleStateEnum> lastStateStates) {
221 Either<Set<Resource>, StorageOperationStatus> resources = toscaOperationFacade
222 .getFollowed(userId, lifecycleStates, lastStateStates, ComponentTypeEnum.RESOURCE);
223 if (resources.isLeft()) {
224 Either<Set<Service>, StorageOperationStatus> services = toscaOperationFacade
225 .getFollowed(userId, lifecycleStates, lastStateStates, ComponentTypeEnum.SERVICE);
226 if (services.isLeft()) {
227 Map<String, Set<? extends Component>> result = new HashMap<>();
228 result.put(SERVICES, services.left().value());
229 result.put(RESOURCES, resources.left().value());
230 return Either.left(result);
232 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(services.right().value())));
235 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(resources.right().value())));
238 janusGraphDao.commit();
242 private Either<Map<String, Set<? extends Component>>, ResponseFormat> getFollowedProducts(String userId, Set<LifecycleStateEnum> lifecycleStates,
243 Set<LifecycleStateEnum> lastStateStates) {
244 Either<Set<Product>, StorageOperationStatus> products = toscaOperationFacade
245 .getFollowed(userId, lifecycleStates, lastStateStates, ComponentTypeEnum.PRODUCT);
246 if (products.isLeft()) {
247 Map<String, Set<? extends Component>> result = new HashMap<>();
248 result.put("products", products.left().value());
249 return Either.left(result);
251 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(products.right().value())));
256 * New categories flow - start
258 public Either<List<CategoryDefinition>, ActionStatus> getAllResourceCategories() {
259 return elementOperation.getAllResourceCategories();
262 public Either<List<CategoryDefinition>, ActionStatus> getAllServiceCategories() {
263 return elementOperation.getAllServiceCategories();
266 public Either<CategoryDefinition, ResponseFormat> createCategory(CategoryDefinition category, String componentTypeParamName, String userId) {
267 AuditingActionEnum auditingAction = AuditingActionEnum.ADD_CATEGORY;
268 ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName);
269 String componentType = componentTypeEnum == null ? componentTypeParamName : componentTypeEnum.getValue();
270 CategoryTypeEnum categoryType = CategoryTypeEnum.CATEGORY;
271 User user = validateUserExists(userId);
272 if (category == null) {
273 log.debug("Category json is invalid");
274 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
275 handleCategoryAuditing(responseFormat, user, null, auditingAction, componentType);
276 return Either.right(responseFormat);
278 String categoryName = category.getName();
279 // For auditing of failures we need the original non-normalized name
280 String origCategoryName = categoryName;
281 if (componentTypeEnum == null) {
282 log.debug(COMPONENT_TYPE_IS_INVALID, componentTypeParamName);
283 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
284 handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
285 return Either.right(responseFormat);
287 Either<Boolean, ResponseFormat> validateUserRole = validateUserRole(user, componentTypeEnum);
288 if (validateUserRole.isRight()) {
289 log.debug(VALIDATION_OF_USER_ROLE_FAILED_USER_ID, userId);
290 ResponseFormat responseFormat = validateUserRole.right().value();
291 handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
292 return Either.right(responseFormat);
294 if (!ValidationUtils.validateCategoryDisplayNameFormat(categoryName)) {
295 log.debug("Category display name format is invalid, name {}, componentType {}", categoryName, componentType);
296 ResponseFormat responseFormat = componentsUtils
297 .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, componentType, categoryType.getValue());
298 handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
299 return Either.right(responseFormat);
301 categoryName = ValidationUtils.normalizeCategoryName4Display(categoryName);
302 if (!ValidationUtils.validateCategoryDisplayNameLength(categoryName)) {
303 log.debug("Category display name length is invalid, should be from 4 to 25 chars, name {}, componentType {}", categoryName,
305 ResponseFormat responseFormat = componentsUtils
306 .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, componentType, categoryType.getValue());
307 handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
308 return Either.right(responseFormat);
310 category.setName(categoryName);
311 String normalizedName = ValidationUtils.normalizeCategoryName4Uniqueness(categoryName);
312 category.setNormalizedName(normalizedName);
313 if (ValidationUtils.validateCategoryIconNotEmpty(category.getIcons())) {
314 log.debug("createCategory: setting category icon to default icon since service category was created without an icon ");
315 category.setIcons(Arrays.asList(DEFAULT_ICON));
317 NodeTypeEnum nodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, categoryType);
318 Either<Boolean, ActionStatus> categoryUniqueEither = elementOperation.isCategoryUniqueForType(nodeType, normalizedName);
319 if (categoryUniqueEither.isRight()) {
320 log.debug("Failed to check category uniqueness, name {}, componentType {}", categoryName, componentType);
321 ResponseFormat responseFormat = componentsUtils.getResponseFormat(categoryUniqueEither.right().value());
322 handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
323 return Either.right(responseFormat);
325 Boolean isCategoryUnique = categoryUniqueEither.left().value();
326 if (!isCategoryUnique) {
327 log.debug("Category is not unique, name {}, componentType {}", categoryName, componentType);
328 ResponseFormat responseFormat = componentsUtils
329 .getResponseFormat(ActionStatus.COMPONENT_CATEGORY_ALREADY_EXISTS, componentType, categoryName);
330 handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
331 return Either.right(responseFormat);
333 Either<CategoryDefinition, ActionStatus> createCategoryByType = elementOperation.createCategory(category, nodeType);
334 if (createCategoryByType.isRight()) {
335 log.debug("Failed to create category, name {}, componentType {}", categoryName, componentType);
336 ResponseFormat responseFormat = componentsUtils
337 .getResponseFormat(ActionStatus.COMPONENT_CATEGORY_ALREADY_EXISTS, componentType, categoryName);
338 handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
339 return Either.right(componentsUtils.getResponseFormat(createCategoryByType.right().value()));
341 category = createCategoryByType.left().value();
342 log.debug("Created category for component {}, name {}, uniqueId {}", componentType, categoryName, category.getUniqueId());
343 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.CREATED);
344 handleCategoryAuditing(responseFormat, user, category.getName(), auditingAction, componentType);
345 return Either.left(category);
348 public Either<SubCategoryDefinition, ResponseFormat> createSubCategory(SubCategoryDefinition subCategory, String componentTypeParamName,
349 String parentCategoryId, String userId) {
350 AuditingActionEnum auditingAction = AuditingActionEnum.ADD_SUB_CATEGORY;
351 ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName);
352 String componentType = componentTypeEnum == null ? componentTypeParamName : componentTypeEnum.getValue();
353 CategoryTypeEnum categoryType = CategoryTypeEnum.SUBCATEGORY;
355 String parentCategoryName = parentCategoryId;
356 if (subCategory == null) {
357 log.debug("Sub-category json is invalid");
358 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
359 handleCategoryAuditing(responseFormat, null, parentCategoryName, null, auditingAction, componentType);
360 return Either.right(responseFormat);
362 String subCategoryName = subCategory.getName();
363 // For auditing of failures we need the original non-normalized name
364 String origSubCategoryName = subCategoryName;
367 user = validateUserExists(userId);
368 } catch (ByActionStatusComponentException e) {
369 ResponseFormat responseFormat = componentsUtils.getResponseFormat(e.getActionStatus(), e.getParams());
370 handleComponentException(userId, auditingAction, componentType, parentCategoryName, origSubCategoryName, responseFormat);
372 } catch (ByResponseFormatComponentException e) {
373 ResponseFormat responseFormat = e.getResponseFormat();
374 handleComponentException(userId, auditingAction, componentType, parentCategoryName, origSubCategoryName, responseFormat);
377 if (componentTypeEnum == null) {
378 log.debug(COMPONENT_TYPE_IS_INVALID, componentTypeParamName);
379 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
380 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
381 return Either.right(responseFormat);
383 Either<Boolean, ResponseFormat> validateComponentType = validateComponentTypeForCategory(componentTypeEnum, categoryType);
384 if (validateComponentType.isRight()) {
385 log.debug("Validation of component type for sub-category failed");
386 ResponseFormat responseFormat = validateComponentType.right().value();
387 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
388 return Either.right(responseFormat);
390 Either<Boolean, ResponseFormat> validateUserRole = validateUserRole(user, componentTypeEnum);
391 if (validateUserRole.isRight()) {
392 log.debug(VALIDATION_OF_USER_ROLE_FAILED_USER_ID, userId);
393 ResponseFormat responseFormat = validateUserRole.right().value();
394 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
395 return Either.right(responseFormat);
397 NodeTypeEnum parentNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.CATEGORY);
398 NodeTypeEnum childNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.SUBCATEGORY);
399 CategoryDefinition categoryDefinition;
400 Either<CategoryDefinition, ResponseFormat> validateCategoryExists = validateCategoryExists(parentNodeType, parentCategoryId,
402 if (validateCategoryExists.isRight()) {
403 log.debug("Validation of parent category exists failed, parent categoryId {}", parentCategoryId);
404 ResponseFormat responseFormat = validateCategoryExists.right().value();
405 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
406 return Either.right(responseFormat);
408 categoryDefinition = validateCategoryExists.left().value();
409 parentCategoryName = categoryDefinition.getName();
410 if (!ValidationUtils.validateCategoryDisplayNameFormat(subCategoryName)) {
411 log.debug("Sub-category display name format is invalid, name {}, componentType {}", subCategoryName, componentType);
412 ResponseFormat responseFormat = componentsUtils
413 .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, componentType, categoryType.getValue());
414 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
415 return Either.right(responseFormat);
417 subCategoryName = ValidationUtils.normalizeCategoryName4Display(subCategoryName);
418 if (!ValidationUtils.validateCategoryDisplayNameLength(subCategoryName)) {
419 log.debug("Sub-category display name length is invalid, should be from 4 to 25 chars, name {}, componentType {}", subCategoryName,
421 ResponseFormat responseFormat = componentsUtils
422 .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, componentType, categoryType.getValue());
423 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
424 return Either.right(responseFormat);
426 String normalizedName = ValidationUtils.normalizeCategoryName4Uniqueness(subCategoryName);
427 subCategory.setNormalizedName(normalizedName);
428 // Uniqueness under this category
429 Either<Boolean, ActionStatus> subCategoryUniqueForCategory = elementOperation
430 .isSubCategoryUniqueForCategory(childNodeType, normalizedName, parentCategoryId);
431 if (subCategoryUniqueForCategory.isRight()) {
432 log.debug("Failed to check sub-category uniqueness, parent name {}, subcategory norm name {}, componentType {}", parentCategoryName,
433 normalizedName, componentType);
434 ResponseFormat responseFormat = componentsUtils.getResponseFormat(subCategoryUniqueForCategory.right().value());
435 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
436 return Either.right(responseFormat);
438 Boolean isSubUnique = subCategoryUniqueForCategory.left().value();
440 log.debug("Sub-category is not unique for category, parent name {}, subcategory norm name {}, componentType {}", parentCategoryName,
441 normalizedName, componentType);
442 ResponseFormat responseFormat = componentsUtils
443 .getResponseFormat(ActionStatus.COMPONENT_SUB_CATEGORY_EXISTS_FOR_CATEGORY, componentType, subCategoryName, parentCategoryName);
444 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
445 return Either.right(responseFormat);
447 // Setting name of subcategory to fit the similar subcategory name
451 // For example if Network-->kUKU exists for service category Network,
453 // and user is trying to create Router-->Kuku for service category
457 // his subcategory name will be Router-->kUKU.
458 Either<SubCategoryDefinition, ActionStatus> subCategoryUniqueForType = elementOperation
459 .getSubCategoryUniqueForType(childNodeType, normalizedName);
460 if (subCategoryUniqueForType.isRight()) {
461 log.debug("Failed validation of whether similar sub-category exists, normalizedName {} componentType {}", normalizedName, componentType);
462 ResponseFormat responseFormat = componentsUtils.getResponseFormat(subCategoryUniqueForType.right().value());
463 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
464 return Either.right(responseFormat);
466 SubCategoryDefinition subCategoryDefinition = subCategoryUniqueForType.left().value();
467 if (subCategoryDefinition != null) {
468 subCategoryName = subCategoryDefinition.getName();
470 subCategory.setName(subCategoryName);
471 ///////////////////////////////////////////// Validations end
472 Either<SubCategoryDefinition, ActionStatus> createSubCategory = elementOperation
473 .createSubCategory(parentCategoryId, subCategory, childNodeType);
474 if (createSubCategory.isRight()) {
475 log.debug("Failed to create sub-category, name {}, componentType {}", subCategoryName, componentType);
476 ResponseFormat responseFormat = componentsUtils.getResponseFormat(subCategoryUniqueForType.right().value());
477 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
478 return Either.right(responseFormat);
480 SubCategoryDefinition subCategoryCreated = createSubCategory.left().value();
481 log.debug("Created sub-category for component {}, name {}, uniqueId {}", componentType, subCategoryName, subCategoryCreated.getUniqueId());
482 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.CREATED);
483 handleCategoryAuditing(responseFormat, user, parentCategoryName, subCategoryCreated.getName(), auditingAction, componentType);
484 return Either.left(subCategoryCreated);
487 private void handleComponentException(String userId, AuditingActionEnum auditingAction, String componentType, String parentCategoryName,
488 String origSubCategoryName, ResponseFormat responseFormat) {
490 log.debug(VALIDATION_OF_USER_FAILED_USER_ID, userId);
492 user.setUserId(userId);
493 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
496 private void handleComponentException(GroupingDefinition grouping, String userId, AuditingActionEnum auditingAction, String componentType,
497 String parentCategoryName, String parentSubCategoryName, ResponseFormat responseFormat) {
499 log.debug(VALIDATION_OF_USER_FAILED_USER_ID, userId);
501 user.setUserId(userId);
502 String groupingNameForAudit = grouping == null ? null : grouping.getName();
503 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, groupingNameForAudit, auditingAction, componentType);
506 private void handleComponentException(String componentType, String userId, ResponseFormat responseFormat) {
509 user.setUserId(userId);
510 log.debug(VALIDATION_OF_USER_FAILED_USER_ID, userId);
511 componentsUtils.auditGetCategoryHierarchy(user, componentType, responseFormat);
514 public Either<GroupingDefinition, ResponseFormat> createGrouping(GroupingDefinition grouping, String componentTypeParamName,
515 String grandParentCategoryId, String parentSubCategoryId, String userId) {
516 AuditingActionEnum auditingAction = AuditingActionEnum.ADD_GROUPING;
517 ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName);
518 String componentType = componentTypeEnum == null ? componentTypeParamName : componentTypeEnum.getValue();
519 CategoryTypeEnum categoryType = CategoryTypeEnum.GROUPING;
521 String parentCategoryName = grandParentCategoryId;
522 String parentSubCategoryName = parentSubCategoryId;
525 user = validateUserExists(userId);
526 } catch (ByResponseFormatComponentException e) {
527 ResponseFormat responseFormat = e.getResponseFormat();
528 handleComponentException(grouping, userId, auditingAction, componentType, parentCategoryName, parentSubCategoryName, responseFormat);
530 } catch (ByActionStatusComponentException e) {
531 ResponseFormat responseFormat = componentsUtils.getResponseFormat(e.getActionStatus(), e.getParams());
532 handleComponentException(grouping, userId, auditingAction, componentType, parentCategoryName, parentSubCategoryName, responseFormat);
535 if (grouping == null) {
536 log.debug("Grouping json is invalid");
537 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
538 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, null, auditingAction, componentType);
539 return Either.right(responseFormat);
541 String groupingName = grouping.getName();
542 // For auditing of failures we need the original non-normalized name
543 String origGroupingName = groupingName;
544 if (componentTypeEnum == null) {
545 log.debug(COMPONENT_TYPE_IS_INVALID, componentTypeParamName);
546 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
547 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
548 return Either.right(responseFormat);
550 Either<Boolean, ResponseFormat> validateComponentType = validateComponentTypeForCategory(componentTypeEnum, categoryType);
551 if (validateComponentType.isRight()) {
552 log.debug("Validation of component type for grouping failed");
553 ResponseFormat responseFormat = validateComponentType.right().value();
554 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
555 return Either.right(responseFormat);
557 Either<Boolean, ResponseFormat> validateUserRole = validateUserRole(user, componentTypeEnum);
558 if (validateUserRole.isRight()) {
559 log.debug(VALIDATION_OF_USER_ROLE_FAILED_USER_ID, userId);
560 ResponseFormat responseFormat = validateUserRole.right().value();
561 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
562 return Either.right(responseFormat);
564 NodeTypeEnum grandParentNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.CATEGORY);
565 NodeTypeEnum parentNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.SUBCATEGORY);
566 NodeTypeEnum childNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.GROUPING);
568 CategoryDefinition categoryDefinition;
569 Either<CategoryDefinition, ResponseFormat> validateCategoryExists = validateCategoryExists(grandParentNodeType, grandParentCategoryId,
571 if (validateCategoryExists.isRight()) {
572 log.debug("Validation of parent category exists failed, parent categoryId {}", grandParentCategoryId);
573 ResponseFormat responseFormat = validateCategoryExists.right().value();
574 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
575 return Either.right(responseFormat);
577 categoryDefinition = validateCategoryExists.left().value();
578 parentCategoryName = categoryDefinition.getName();
579 // Validate subcategory
580 SubCategoryDefinition subCategoryDefinition;
581 Either<SubCategoryDefinition, ResponseFormat> validateSubCategoryExists = validateSubCategoryExists(parentNodeType, parentSubCategoryId,
583 if (validateSubCategoryExists.isRight()) {
584 log.debug("Validation of parent sub-category exists failed, parent sub-category id {}", parentSubCategoryId);
585 ResponseFormat responseFormat = validateSubCategoryExists.right().value();
586 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
587 return Either.right(responseFormat);
589 subCategoryDefinition = validateSubCategoryExists.left().value();
590 parentSubCategoryName = subCategoryDefinition.getName();
591 if (!ValidationUtils.validateCategoryDisplayNameFormat(groupingName)) {
592 log.debug("Sub-category display name format is invalid, name {}, componentType {}", groupingName, componentType);
593 ResponseFormat responseFormat = componentsUtils
594 .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, componentType, categoryType.getValue());
595 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
596 return Either.right(responseFormat);
598 groupingName = ValidationUtils.normalizeCategoryName4Display(groupingName);
599 if (!ValidationUtils.validateCategoryDisplayNameLength(groupingName)) {
600 log.debug("Grouping display name length is invalid, should be from 4 to 25 chars, name {}, componentType {}", groupingName,
602 ResponseFormat responseFormat = componentsUtils
603 .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, componentType, categoryType.getValue());
604 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
605 return Either.right(responseFormat);
607 String normalizedName = ValidationUtils.normalizeCategoryName4Uniqueness(groupingName);
608 grouping.setNormalizedName(normalizedName);
609 // Uniqueness under this category
610 Either<Boolean, ActionStatus> groupingUniqueForSubCategory = elementOperation
611 .isGroupingUniqueForSubCategory(childNodeType, normalizedName, parentSubCategoryId);
612 if (groupingUniqueForSubCategory.isRight()) {
613 log.debug("Failed to check grouping uniqueness, parent name {}, grouping norm name {}, componentType {}", parentSubCategoryName,
614 normalizedName, componentType);
615 ResponseFormat responseFormat = componentsUtils.getResponseFormat(groupingUniqueForSubCategory.right().value());
616 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
617 return Either.right(responseFormat);
619 Boolean isGroupingUnique = groupingUniqueForSubCategory.left().value();
620 if (!isGroupingUnique) {
621 log.debug("Grouping is not unique for sub-category, parent name {}, grouping norm name {}, componentType {}", parentSubCategoryName,
622 normalizedName, componentType);
623 ResponseFormat responseFormat = componentsUtils
624 .getResponseFormat(ActionStatus.COMPONENT_GROUPING_EXISTS_FOR_SUB_CATEGORY, componentType, groupingName, parentSubCategoryName);
625 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
626 return Either.right(responseFormat);
628 // Setting name of grouping to fit the similar grouping name ignoring
632 // For example if Network-->kUKU exists for service sub-category
634 // Network, and user is trying to create grouping Router-->Kuku for
636 // service sub-category Router,
638 // his grouping name will be Router-->kUKU.
639 Either<GroupingDefinition, ActionStatus> groupingUniqueForType = elementOperation.getGroupingUniqueForType(childNodeType, normalizedName);
640 if (groupingUniqueForType.isRight()) {
641 log.debug("Failed validation of whether similar grouping exists, normalizedName {} componentType {}", normalizedName, componentType);
642 ResponseFormat responseFormat = componentsUtils.getResponseFormat(groupingUniqueForType.right().value());
643 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
644 return Either.right(responseFormat);
646 GroupingDefinition groupingDefinition = groupingUniqueForType.left().value();
647 if (groupingDefinition != null) {
648 groupingName = groupingDefinition.getName();
650 grouping.setName(groupingName);
651 ///////////////////////////////////////////// Validations end
652 Either<GroupingDefinition, ActionStatus> createGrouping = elementOperation.createGrouping(parentSubCategoryId, grouping, childNodeType);
653 if (createGrouping.isRight()) {
654 log.debug("Failed to create grouping, name {}, componentType {}", groupingName, componentType);
655 ResponseFormat responseFormat = componentsUtils.getResponseFormat(createGrouping.right().value());
656 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
657 return Either.right(responseFormat);
659 GroupingDefinition groupingCreated = createGrouping.left().value();
660 log.debug("Created grouping for component {}, name {}, uniqueId {}", componentType, groupingName, groupingCreated.getUniqueId());
661 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.CREATED);
662 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, groupingCreated.getName(), auditingAction,
664 return Either.left(groupingCreated);
667 public Either<List<CategoryDefinition>, ResponseFormat> getAllCategories(String componentType, String userId) {
668 ResponseFormat responseFormat;
669 User user = new User();
670 if (userId == null) {
671 user.setUserId("UNKNOWN");
672 responseFormat = componentsUtils.getResponseFormat(ActionStatus.MISSING_INFORMATION);
673 componentsUtils.auditGetCategoryHierarchy(user, componentType, responseFormat);
674 return Either.right(responseFormat);
677 user = validateUserExists(userId);
678 } catch (ByActionStatusComponentException e) {
679 responseFormat = componentsUtils.getResponseFormat(e.getActionStatus(), e.getParams());
680 handleComponentException(componentType, userId, responseFormat);
682 } catch (ByResponseFormatComponentException e) {
683 responseFormat = e.getResponseFormat();
684 handleComponentException(componentType, userId, responseFormat);
687 ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentType);
688 if (componentTypeEnum == null) {
689 log.debug("Cannot create category for component type {}", componentType);
690 responseFormat = componentsUtils.getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, "component type");
691 componentsUtils.auditGetCategoryHierarchy(user, componentType, responseFormat);
692 return Either.right(responseFormat);
694 NodeTypeEnum nodeTypeEnum = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.CATEGORY);
695 Either<List<CategoryDefinition>, ActionStatus> getAllCategoriesByType = elementOperation.getAllCategories(nodeTypeEnum, false);
696 if (getAllCategoriesByType.isRight()) {
697 responseFormat = componentsUtils.getResponseFormat(getAllCategoriesByType.right().value());
698 componentsUtils.auditGetCategoryHierarchy(user, componentType, responseFormat);
699 return Either.right(responseFormat);
701 List<CategoryDefinition> categories = getAllCategoriesByType.left().value();
702 responseFormat = componentsUtils.getResponseFormat(ActionStatus.OK);
703 componentsUtils.auditGetCategoryHierarchy(user, componentType, responseFormat);
704 return Either.left(categories);
707 public Either<UiCategories, ResponseFormat> getAllCategories(String userId) {
708 ResponseFormat responseFormat;
709 UiCategories categories = new UiCategories();
710 User user = validateUserExists(userId);
711 // GET resource categories
712 Either<List<CategoryDefinition>, ActionStatus> getResourceCategoriesByType = elementOperation
713 .getAllCategories(NodeTypeEnum.ResourceNewCategory, false);
714 if (getResourceCategoriesByType.isRight()) {
715 responseFormat = componentsUtils.getResponseFormat(getResourceCategoriesByType.right().value());
716 componentsUtils.auditGetCategoryHierarchy(user, ComponentTypeEnum.RESOURCE.getValue(), responseFormat);
717 return Either.right(responseFormat);
719 categories.setResourceCategories(getResourceCategoriesByType.left().value());
720 // GET service categories
721 Either<List<CategoryDefinition>, ActionStatus> getServiceCategoriesByType = elementOperation
722 .getAllCategories(NodeTypeEnum.ServiceNewCategory, false);
723 if (getServiceCategoriesByType.isRight()) {
724 responseFormat = componentsUtils.getResponseFormat(getServiceCategoriesByType.right().value());
725 componentsUtils.auditGetCategoryHierarchy(user, ComponentTypeEnum.SERVICE.getValue(), responseFormat);
726 return Either.right(responseFormat);
728 categories.setServiceCategories(getServiceCategoriesByType.left().value());
729 categories.setProductCategories(new ArrayList<>());
730 return Either.left(categories);
733 public Either<CategoryDefinition, ResponseFormat> deleteCategory(String categoryId, String componentTypeParamName, String userId) {
734 validateUserExists(userId);
735 ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName);
736 if (componentTypeEnum == null) {
737 log.debug("Cannot create category for component type {}", componentTypeParamName);
738 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
740 NodeTypeEnum nodeTypeEnum = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.CATEGORY);
741 Either<CategoryDefinition, ActionStatus> deleteCategoryByType = elementOperation.deleteCategory(nodeTypeEnum, categoryId);
742 if (deleteCategoryByType.isRight()) {
743 // auditing, logging here...
744 return Either.right(componentsUtils.getResponseFormat(deleteCategoryByType.right().value()));
746 CategoryDefinition category = deleteCategoryByType.left().value();
747 log.debug("Delete category for component {}, name {}, uniqueId {}", nodeTypeEnum, category.getName(), category.getUniqueId());
748 return Either.left(category);
751 public Either<SubCategoryDefinition, ResponseFormat> deleteSubCategory(String parentSubCategoryId, String componentTypeParamName, String userId) {
752 validateUserExists(userId);
753 ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName);
754 if (componentTypeEnum == null) {
755 log.debug("Cannot delete sub-category for component type {}", componentTypeParamName);
756 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
758 NodeTypeEnum nodeTypeEnum = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.SUBCATEGORY);
759 Either<SubCategoryDefinition, ActionStatus> deleteSubCategoryByType = elementOperation.deleteSubCategory(nodeTypeEnum, parentSubCategoryId);
760 if (deleteSubCategoryByType.isRight()) {
761 // auditing, logging here...
762 return Either.right(componentsUtils.getResponseFormat(deleteSubCategoryByType.right().value()));
764 SubCategoryDefinition subCategory = deleteSubCategoryByType.left().value();
765 log.debug("Deleted sub-category for component {}, name {}, uniqueId {}", nodeTypeEnum, subCategory.getName(), subCategory.getUniqueId());
766 return Either.left(subCategory);
769 public Either<GroupingDefinition, ResponseFormat> deleteGrouping(String groupingId, String componentTypeParamName, String userId) {
770 validateUserExists(userId);
771 ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName);
772 if (componentTypeEnum == null) {
773 log.debug("Cannot delete grouping for component type {}", componentTypeParamName);
774 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
776 NodeTypeEnum nodeTypeEnum = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.GROUPING);
777 Either<GroupingDefinition, ActionStatus> deleteGroupingByType = elementOperation.deleteGrouping(nodeTypeEnum, groupingId);
778 if (deleteGroupingByType.isRight()) {
779 // auditing, logging here...
780 return Either.right(componentsUtils.getResponseFormat(deleteGroupingByType.right().value()));
782 GroupingDefinition deletedGrouping = deleteGroupingByType.left().value();
783 log.debug("Deleted grouping for component {}, name {}, uniqueId {}", nodeTypeEnum, deletedGrouping.getName(), deletedGrouping.getUniqueId());
784 return Either.left(deletedGrouping);
787 private Either<Boolean, ResponseFormat> validateUserRole(User user, ComponentTypeEnum componentTypeEnum) {
788 String role = user.getRole();
789 boolean validAdminAction =
790 role.equals(Role.ADMIN.name()) && (componentTypeEnum == ComponentTypeEnum.SERVICE || componentTypeEnum == ComponentTypeEnum.RESOURCE);
791 boolean validProductAction = role.equals(Role.PRODUCT_STRATEGIST.name()) && (componentTypeEnum == ComponentTypeEnum.PRODUCT);
792 if (!(validAdminAction || validProductAction)) {
793 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION);
794 log.debug("User not permitted to perform operation on category, userId = {}, role = {}, componentType = {}", user.getUserId(), role,
796 return Either.right(responseFormat);
798 return Either.left(true);
801 private Either<Boolean, ResponseFormat> validateComponentTypeForCategory(ComponentTypeEnum componentType, CategoryTypeEnum categoryType) {
802 boolean validResourceAction = componentType == ComponentTypeEnum.RESOURCE && (categoryType == CategoryTypeEnum.CATEGORY
803 || categoryType == CategoryTypeEnum.SUBCATEGORY);
804 boolean validServiceAction = componentType == ComponentTypeEnum.SERVICE && categoryType == CategoryTypeEnum.CATEGORY;
805 boolean validProductAction = componentType == ComponentTypeEnum.PRODUCT; // can
814 if (!(validResourceAction || validServiceAction || validProductAction)) {
815 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
816 log.debug("It's not allowed to create category type {} for component type {}", categoryType, componentType);
817 return Either.right(responseFormat);
819 return Either.left(true);
822 private Either<CategoryDefinition, ResponseFormat> validateCategoryExists(NodeTypeEnum nodeType, String categoryId,
823 ComponentTypeEnum componentType) {
824 Either<CategoryDefinition, ActionStatus> categoryByTypeAndId = elementOperation.getCategory(nodeType, categoryId);
825 if (categoryByTypeAndId.isRight()) {
826 log.debug("Failed to fetch parent category, parent categoryId {}", categoryId);
827 ActionStatus actionStatus = categoryByTypeAndId.right().value();
828 ResponseFormat responseFormat;
829 if (actionStatus == ActionStatus.COMPONENT_CATEGORY_NOT_FOUND) {
830 responseFormat = componentsUtils
831 .getResponseFormat(actionStatus, componentType.getValue().toLowerCase(), CategoryTypeEnum.CATEGORY.getValue(), "");
833 responseFormat = componentsUtils.getResponseFormat(actionStatus);
835 return Either.right(responseFormat);
837 return Either.left(categoryByTypeAndId.left().value());
840 private Either<SubCategoryDefinition, ResponseFormat> validateSubCategoryExists(NodeTypeEnum nodeType, String subCategoryId,
841 ComponentTypeEnum componentType) {
842 Either<SubCategoryDefinition, ActionStatus> subCategoryByTypeAndId = elementOperation.getSubCategory(nodeType, subCategoryId);
843 if (subCategoryByTypeAndId.isRight()) {
844 log.debug("Failed to fetch parent category, parent categoryId {}", subCategoryId);
845 ActionStatus actionStatus = subCategoryByTypeAndId.right().value();
846 ResponseFormat responseFormat;
847 if (actionStatus == ActionStatus.COMPONENT_CATEGORY_NOT_FOUND) {
848 responseFormat = componentsUtils
849 .getResponseFormat(actionStatus, componentType.getValue().toLowerCase(), CategoryTypeEnum.SUBCATEGORY.getValue(), "");
851 responseFormat = componentsUtils.getResponseFormat(actionStatus);
853 return Either.right(responseFormat);
855 return Either.left(subCategoryByTypeAndId.left().value());
858 private void handleCategoryAuditing(ResponseFormat responseFormat, User user, String category, AuditingActionEnum auditingAction,
859 String componentType) {
860 componentsUtils.auditCategory(responseFormat, user, category, null, null, auditingAction, componentType);
863 private void handleCategoryAuditing(ResponseFormat responseFormat, User user, String category, String subCategory,
864 AuditingActionEnum auditingAction, String componentType) {
865 componentsUtils.auditCategory(responseFormat, user, category, subCategory, null, auditingAction, componentType);
868 private void handleCategoryAuditing(ResponseFormat responseFormat, User user, String category, String subCategory, String grouping,
869 AuditingActionEnum auditingAction, String componentType) {
870 componentsUtils.auditCategory(responseFormat, user, category, subCategory, grouping, auditingAction, componentType);
874 * New categories flow - end
876 public Either<List<Tag>, ActionStatus> getAllTags(String userId) {
877 ActionStatus status = validateUserExistsActionStatus(userId);
878 if (ActionStatus.OK != status) {
879 return Either.right(status);
881 return elementOperation.getAllTags();
884 public Either<List<PropertyScope>, ActionStatus> getAllPropertyScopes(String userId) {
885 ActionStatus status = validateUserExistsActionStatus(userId);
886 if (ActionStatus.OK != status) {
887 return Either.right(status);
889 return elementOperation.getAllPropertyScopes();
892 public Either<List<ArtifactType>, ActionStatus> getAllArtifactTypes(final String userId) {
893 ActionStatus status = validateUserExistsActionStatus(userId);
894 if (ActionStatus.OK != status) {
895 return Either.right(status);
897 return Either.left(elementOperation.getAllArtifactTypes());
900 public Either<Configuration.HeatDeploymentArtifactTimeout, ActionStatus> getDefaultHeatTimeout() {
901 return elementOperation.getDefaultHeatTimeout();
904 public Either<Map<String, List<CatalogComponent>>, ResponseFormat> getCatalogComponents(String userId, List<OriginTypeEnum> excludeTypes) {
906 return toscaOperationFacade.getCatalogOrArchiveComponents(true, excludeTypes)
907 .bimap(this::groupByComponentType, err -> componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(err)));
909 janusGraphDao.commit();
913 private Map<String, List<CatalogComponent>> groupByComponentType(List<CatalogComponent> components) {
914 Map<String, List<CatalogComponent>> map = components.stream()
915 .collect(Collectors.groupingBy(cmpt -> cmptTypeToString(cmpt.getComponentType())));
916 // fixed response for UI!!! UI need to receive always map!
918 map = new HashMap<>();
920 map.computeIfAbsent(RESOURCES, k -> new ArrayList());
921 map.computeIfAbsent(SERVICES, k -> new ArrayList());
925 private String cmptTypeToString(ComponentTypeEnum componentTypeEnum) {
926 switch (componentTypeEnum) {
932 throw new IllegalStateException("resources or services only");
936 public Either<List<? extends Component>, ResponseFormat> getFilteredCatalogComponents(String assetType, Map<FilterKeyEnum, String> filters,
938 ComponentTypeEnum assetTypeEnum = AssetTypeEnum.convertToComponentTypeEnum(assetType);
940 Optional<NameValuePair> invalidFilter = findInvalidFilter(query, assetTypeEnum);
941 if (invalidFilter.isPresent()) {
942 log.debug("getFilteredAssetList: invalid filter key");
943 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_FILTER_KEY, invalidFilter.get().getName(),
944 FilterKeyEnum.getValidFiltersByAssetType(assetTypeEnum).toString()));
947 if (filters == null || filters.isEmpty()) {
948 Either<List<Component>, StorageOperationStatus> componentsList = toscaOperationFacade.getCatalogComponents(assetTypeEnum, null, false);
949 if (componentsList.isRight()) {
950 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(componentsList.right().value())));
952 return Either.left(componentsList.left().value());
954 Either<List<Component>, StorageOperationStatus> result = getFilteredComponents(filters, assetTypeEnum, false);
955 // category hierarchy mismatch or category/subCategory/distributionStatus not found
956 if (result.isRight()) {
957 List<String> params = getErrorResponseParams(filters, assetTypeEnum);
958 return Either.right(componentsUtils
959 .getResponseFormat(componentsUtils.convertFromStorageResponse(result.right().value()), params.get(0), params.get(1), params.get(2)));
961 if (result.left().value().isEmpty()) {// no assets found for requested
964 return Either.right(componentsUtils.getResponseFormat(ActionStatus.NO_ASSETS_FOUND, assetType, query));
966 return Either.left(result.left().value());
969 private Either<List<Component>, StorageOperationStatus> getFilteredComponents(Map<FilterKeyEnum, String> filters, ComponentTypeEnum assetType,
970 boolean inTransaction) {
971 Either<List<Component>, StorageOperationStatus> assetResult = Either.left(new LinkedList<>());
972 if (assetType == ComponentTypeEnum.RESOURCE) {
973 assetResult = getFilteredResources(filters, inTransaction);
974 } else if (assetType == ComponentTypeEnum.SERVICE) {
975 assetResult = getFilteredServices(filters, inTransaction);
980 private <T extends Component> Either<List<T>, StorageOperationStatus> getFilteredServices(Map<FilterKeyEnum, String> filters,
981 boolean inTransaction) {
982 Either<List<T>, StorageOperationStatus> components = null;
983 String categoryName = filters.get(FilterKeyEnum.CATEGORY);
984 String distributionStatus = filters.get(FilterKeyEnum.DISTRIBUTION_STATUS);
985 DistributionStatusEnum distEnum = DistributionStatusEnum.findState(distributionStatus);
986 if (distributionStatus != null && distEnum == null) {
987 filters.remove(FilterKeyEnum.CATEGORY);
988 return Either.right(StorageOperationStatus.CATEGORY_NOT_FOUND);
990 if (categoryName != null) { // primary filter
991 components = fetchByCategoryOrSubCategoryName(categoryName, NodeTypeEnum.ServiceNewCategory, NodeTypeEnum.Service, inTransaction, null);
992 if (components.isLeft() && distEnum != null) {// secondary filter
993 Predicate<T> statusFilter = p -> ((Service) p).getDistributionStatus() == distEnum;
994 return Either.left(components.left().value().stream().filter(statusFilter).collect(Collectors.toList()));
996 filters.remove(FilterKeyEnum.DISTRIBUTION_STATUS);
999 Set<DistributionStatusEnum> distStatusSet = new HashSet<>();
1000 distStatusSet.add(distEnum);
1001 Either<List<Service>, StorageOperationStatus> servicesWithDistStatus = toscaOperationFacade.getServicesWithDistStatus(distStatusSet, null);
1002 if (servicesWithDistStatus.isRight()) { // not found == empty list
1003 return Either.left(new ArrayList<>());
1005 return Either.left((List<T>) servicesWithDistStatus.left().value());
1008 public Either<List<? extends Component>, ResponseFormat> getCatalogComponentsByUuidAndAssetType(String assetType, String uuid) {
1009 if (assetType == null || uuid == null) {
1010 log.debug("getCatalogComponentsByUuidAndAssetType: One of the function parameteres is null");
1011 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
1013 ComponentTypeEnum assetTypeEnum = AssetTypeEnum.convertToComponentTypeEnum(assetType);
1014 if (assetTypeEnum == null) {
1015 log.debug("getCatalogComponentsByUuidAndAssetType: Corresponding ComponentTypeEnum not found");
1016 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
1018 Map<GraphPropertyEnum, Object> additionalPropertiesToMatch = new EnumMap<>(GraphPropertyEnum.class);
1019 switch (assetTypeEnum) {
1021 additionalPropertiesToMatch.put(GraphPropertyEnum.COMPONENT_TYPE, ComponentTypeEnum.RESOURCE.name());
1024 additionalPropertiesToMatch.put(GraphPropertyEnum.COMPONENT_TYPE, ComponentTypeEnum.SERVICE.name());
1027 log.debug("getCatalogComponentsByUuidAndAssetType: Corresponding ComponentTypeEnum not allowed for this API");
1028 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
1030 Either<List<Component>, StorageOperationStatus> componentsListByUuid = toscaOperationFacade
1031 .getComponentListByUuid(uuid, additionalPropertiesToMatch);
1032 if (componentsListByUuid.isRight()) {
1033 log.debug("getCatalogComponentsByUuidAndAssetType: " + assetTypeEnum.getValue() + " fetching failed");
1034 ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(componentsListByUuid.right().value(), assetTypeEnum);
1035 return Either.right(componentsUtils.getResponseFormat(actionStatus, uuid));
1037 log.debug("getCatalogComponentsByUuidAndAssetType: " + assetTypeEnum.getValue() + assetTypeEnum.getValue() + "fetching successful");
1038 return Either.left(componentsListByUuid.left().value());
1041 public List<String> getAllComponentTypesParamNames() {
1042 List<String> paramNames = new ArrayList<>();
1043 paramNames.add(ComponentTypeEnum.SERVICE_PARAM_NAME);
1044 paramNames.add(ComponentTypeEnum.RESOURCE_PARAM_NAME);
1045 paramNames.add(ComponentTypeEnum.PRODUCT_PARAM_NAME);
1049 public List<String> getAllSupportedRoles() {
1050 Role[] values = Role.values();
1051 List<String> roleNames = new ArrayList<>();
1052 for (Role role : values) {
1053 roleNames.add(role.name());
1058 public Either<Map<String, String>, ActionStatus> getResourceTypesMap() {
1059 return elementOperation.getResourceTypesMap();
1062 private Optional<NameValuePair> findInvalidFilter(String query, ComponentTypeEnum assetType) {
1063 List<NameValuePair> params = URLEncodedUtils.parse(query, StandardCharsets.UTF_8);
1064 List<String> validKeys = FilterKeyEnum.getValidFiltersByAssetType(assetType);
1065 Predicate<NameValuePair> noMatch = p -> !validKeys.contains(p.getName());
1066 return params.stream().filter(noMatch).findAny();
1069 private List<String> getErrorResponseParams(Map<FilterKeyEnum, String> filters, ComponentTypeEnum assetType) {
1070 List<String> params = new ArrayList<>();
1071 if (1 == filters.size()) {
1072 params.add(assetType.getValue().toLowerCase());
1073 params.add(filters.keySet().iterator().next().getName());
1074 params.add(filters.values().iterator().next());
1076 params.add(assetType.getValue());
1077 params.add(filters.get(FilterKeyEnum.SUB_CATEGORY));
1078 params.add(filters.get(FilterKeyEnum.CATEGORY));
1083 public Either<List<Component>, StorageOperationStatus> getFilteredResources(Map<FilterKeyEnum, String> filters, boolean inTransaction) {
1084 String subCategoryName = filters.get(FilterKeyEnum.SUB_CATEGORY);
1085 String categoryName = filters.get(FilterKeyEnum.CATEGORY);
1086 ResourceTypeEnum resourceType = ResourceTypeEnum.getType(filters.get(FilterKeyEnum.RESOURCE_TYPE));
1087 Either<List<ImmutablePair<SubCategoryData, GraphEdge>>, StorageOperationStatus> subcategories = null;
1088 Optional<ImmutablePair<SubCategoryData, GraphEdge>> subCategoryData;
1089 if (categoryName != null) {
1090 subcategories = getAllSubCategories(categoryName);
1091 if (subcategories.isRight()) {
1092 filters.remove(FilterKeyEnum.SUB_CATEGORY);
1093 return Either.right(subcategories.right().value());
1096 if (subCategoryName != null) { // primary filter
1097 if (categoryName != null) {
1098 subCategoryData = validateCategoryHierarcy(subcategories.left().value(), subCategoryName);
1099 if (!subCategoryData.isPresent()) {
1100 return Either.right(StorageOperationStatus.MATCH_NOT_FOUND);
1102 return fetchByCategoryOrSubCategoryUid(subCategoryData.get().getLeft().getUniqueId(), NodeTypeEnum.Resource, inTransaction,
1105 return fetchByCategoryOrSubCategoryName(subCategoryName, NodeTypeEnum.ResourceSubcategory, NodeTypeEnum.Resource, inTransaction,
1108 if (subcategories != null) {
1109 return fetchByMainCategory(subcategories.left().value(), inTransaction, resourceType);
1111 return fetchComponentMetaDataByResourceType(filters.get(FilterKeyEnum.RESOURCE_TYPE), inTransaction);
1114 private Either<List<ImmutablePair<SubCategoryData, GraphEdge>>, StorageOperationStatus> getAllSubCategories(String categoryName) {
1115 Either<CategoryData, StorageOperationStatus> categoryResult = elementOperation
1116 .getNewCategoryData(categoryName, NodeTypeEnum.ResourceNewCategory, CategoryData.class);
1117 if (categoryResult.isRight()) {
1118 return Either.right(categoryResult.right().value());
1120 CategoryData categoryData = categoryResult.left().value();
1121 Either<List<ImmutablePair<SubCategoryData, GraphEdge>>, JanusGraphOperationStatus> childrenNodes = janusGraphGenericDao
1122 .getChildrenNodes(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.ResourceNewCategory), (String) categoryData.getUniqueId(),
1123 GraphEdgeLabels.SUB_CATEGORY, NodeTypeEnum.ResourceSubcategory, SubCategoryData.class);
1124 if (childrenNodes.isRight()) {
1125 return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(childrenNodes.right().value()));
1127 return Either.left(childrenNodes.left().value());
1130 private Optional<ImmutablePair<SubCategoryData, GraphEdge>> validateCategoryHierarcy(List<ImmutablePair<SubCategoryData, GraphEdge>> childNodes,
1131 String subCategoryName) {
1132 Predicate<ImmutablePair<SubCategoryData, GraphEdge>> matchName = p -> p.getLeft().getSubCategoryDataDefinition().getName()
1133 .equals(subCategoryName);
1134 return childNodes.stream().filter(matchName).findAny();
1137 protected <T extends Component> Either<List<T>, StorageOperationStatus> fetchByCategoryOrSubCategoryUid(String categoryUid,
1138 NodeTypeEnum categoryType,
1139 boolean inTransaction,
1140 ResourceTypeEnum resourceType) {
1142 return collectComponents(categoryType, categoryUid, resourceType);
1144 if (!inTransaction) {
1145 janusGraphDao.commit();
1150 protected <T extends Component> Either<List<T>, StorageOperationStatus> fetchByCategoryOrSubCategoryName(String categoryName,
1151 NodeTypeEnum categoryType,
1152 NodeTypeEnum neededType,
1153 boolean inTransaction,
1154 ResourceTypeEnum resourceType) {
1155 List<T> components = new ArrayList<>();
1157 Class categoryClazz = categoryType == NodeTypeEnum.ServiceNewCategory ? CategoryData.class : SubCategoryData.class;
1158 Map<String, Object> props = new HashMap<>();
1159 props.put(GraphPropertiesDictionary.NORMALIZED_NAME.getProperty(), ValidationUtils.normalizeCategoryName4Uniqueness(categoryName));
1160 Either<List<GraphNode>, JanusGraphOperationStatus> getCategory = janusGraphGenericDao.getByCriteria(categoryType, props, categoryClazz);
1161 if (getCategory.isRight()) {
1162 return Either.right(StorageOperationStatus.CATEGORY_NOT_FOUND);
1164 for (GraphNode category : getCategory.left().value()) {
1165 Either<List<T>, StorageOperationStatus> result = collectComponents(neededType, category.getUniqueId(), resourceType);
1166 if (result.isRight() && result.right().value() != StorageOperationStatus.NOT_FOUND) {
1168 } else if (result.isLeft()) {
1169 components.addAll(result.left().value());
1172 if (components.isEmpty()) {
1173 return Either.right(StorageOperationStatus.NOT_FOUND);
1175 return Either.left(components);
1177 if (!inTransaction) {
1178 janusGraphDao.commit();
1183 private <T extends Component> Either<List<T>, StorageOperationStatus> collectComponents(NodeTypeEnum neededType, String categoryUid,
1184 ResourceTypeEnum resourceType) {
1185 List<T> components = new ArrayList<>();
1186 Either<GraphVertex, JanusGraphOperationStatus> categoryVertexById = janusGraphDao.getVertexById(categoryUid, JsonParseFlagEnum.NoParse);
1187 if (categoryVertexById.isRight()) {
1188 JanusGraphOperationStatus status = categoryVertexById.right().value();
1189 log.debug("#collectComponents Failed to get category vertex with uid {}, status is {}.", categoryUid, status);
1190 return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status));
1192 GraphVertex categoryVertex = categoryVertexById.left().value();
1193 Either<List<GraphVertex>, JanusGraphOperationStatus> componentsVertices = janusGraphDao
1194 .getParentVertices(categoryVertex, EdgeLabelEnum.CATEGORY, JsonParseFlagEnum.ParseMetadata);
1195 if (componentsVertices.isRight()) {
1196 JanusGraphOperationStatus status = componentsVertices.right().value();
1197 log.debug("#collectComponents Failed to get components vertices of category {}, status is {}.", categoryVertex, status);
1198 return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status));
1200 List<ComponentMetadataDataDefinition> componentsMetadataDataDefinition = componentsVertices.left().value().stream().filter(Objects::nonNull)
1201 .filter(componentsVertex -> Objects.nonNull(componentsVertex.getType())).map(ModelConverter::convertToComponentMetadataDataDefinition)
1202 .collect(Collectors.toList());
1203 for (ComponentMetadataDataDefinition component : componentsMetadataDataDefinition) {
1204 boolean isHighest = isTrue(component.isHighestVersion());
1205 boolean isMatchingResourceType = isMatchingByResourceType(neededType, resourceType, component);
1206 boolean isDeleted = isTrue(component.isDeleted());
1207 boolean isArchived = isTrue(component.isArchived());
1208 if (isHighest && isMatchingResourceType && !isDeleted && !isArchived) {
1209 Either<T, StorageOperationStatus> result = toscaOperationFacade
1210 .getToscaElement(component.getUniqueId(), JsonParseFlagEnum.ParseMetadata);
1211 if (result.isRight()) {
1212 return Either.right(result.right().value());
1214 components.add(result.left().value());
1217 return Either.left(components);
1220 private boolean isMatchingByResourceType(NodeTypeEnum componentType, ResourceTypeEnum resourceType,
1221 ComponentMetadataDataDefinition componentData) {
1223 if (componentType == NodeTypeEnum.Resource) {
1224 if (resourceType == null) {
1227 isMatching = resourceType == ((ResourceMetadataDataDefinition) componentData).getResourceType();
1235 private <T extends Component> Either<List<T>, StorageOperationStatus> fetchByMainCategory(
1236 List<ImmutablePair<SubCategoryData, GraphEdge>> subcategories, boolean inTransaction, ResourceTypeEnum resourceType) {
1237 List<T> components = new ArrayList<>();
1238 for (ImmutablePair<SubCategoryData, GraphEdge> subCategory : subcategories) {
1239 Either<List<T>, StorageOperationStatus> fetched = fetchByCategoryOrSubCategoryUid(subCategory.getLeft().getUniqueId(),
1240 NodeTypeEnum.Resource, inTransaction, resourceType);
1241 if (fetched.isRight()) {
1244 components.addAll(fetched.left().value());
1246 return Either.left(components);
1249 private Either<List<Component>, StorageOperationStatus> fetchComponentMetaDataByResourceType(String resourceType, boolean inTransaction) {
1250 List<Component> components = null;
1251 StorageOperationStatus status;
1252 Wrapper<StorageOperationStatus> statusWrapper = new Wrapper<>();
1253 Either<List<Component>, StorageOperationStatus> result;
1255 ComponentParametersView fetchUsersAndCategoriesFilter = new ComponentParametersView(
1256 Arrays.asList(ComponentFieldsEnum.USERS.getValue(), ComponentFieldsEnum.CATEGORIES.getValue()));
1257 Either<List<Component>, StorageOperationStatus> getResources = toscaOperationFacade
1258 .fetchMetaDataByResourceType(resourceType, fetchUsersAndCategoriesFilter);
1259 if (getResources.isRight()) {
1260 status = getResources.right().value();
1261 if (status != StorageOperationStatus.NOT_FOUND) {
1262 statusWrapper.setInnerElement(getResources.right().value());
1264 components = new ArrayList<>();
1267 components = getResources.left().value();
1269 if (!statusWrapper.isEmpty()) {
1270 result = Either.right(statusWrapper.getInnerElement());
1272 result = Either.left(components);
1276 if (!inTransaction) {
1277 janusGraphDao.commit();
1282 public CatalogUpdateTimestamp getCatalogUpdateTime(String userId) {
1284 return toscaOperationFacade.getCatalogTimes();
1286 janusGraphDao.commit();