2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
19 * Modifications copyright (c) 2019 Nokia
20 * ================================================================================
23 package org.openecomp.sdc.be.components.impl;
25 import fj.data.Either;
26 import org.apache.commons.lang3.tuple.ImmutablePair;
27 import org.apache.http.NameValuePair;
28 import org.apache.http.client.utils.URLEncodedUtils;
29 import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
30 import org.openecomp.sdc.be.components.impl.exceptions.ByResponseFormatComponentException;
31 import org.openecomp.sdc.be.config.Configuration;
32 import org.openecomp.sdc.be.dao.api.ActionStatus;
33 import org.openecomp.sdc.be.dao.graph.datatype.GraphEdge;
34 import org.openecomp.sdc.be.dao.graph.datatype.GraphNode;
35 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
36 import org.openecomp.sdc.be.dao.jsongraph.GraphVertex;
37 import org.openecomp.sdc.be.dao.jsongraph.types.EdgeLabelEnum;
38 import org.openecomp.sdc.be.dao.jsongraph.types.JsonParseFlagEnum;
39 import org.openecomp.sdc.be.dao.neo4j.GraphEdgeLabels;
40 import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary;
41 import org.openecomp.sdc.be.datamodel.api.CategoryTypeEnum;
42 import org.openecomp.sdc.be.datamodel.utils.NodeTypeConvertUtils;
43 import org.openecomp.sdc.be.datatypes.components.ComponentMetadataDataDefinition;
44 import org.openecomp.sdc.be.datatypes.components.ResourceMetadataDataDefinition;
45 import org.openecomp.sdc.be.datatypes.enums.AssetTypeEnum;
46 import org.openecomp.sdc.be.datatypes.enums.ComponentFieldsEnum;
47 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
48 import org.openecomp.sdc.be.datatypes.enums.FilterKeyEnum;
49 import org.openecomp.sdc.be.datatypes.enums.GraphPropertyEnum;
50 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
51 import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum;
52 import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
53 import org.openecomp.sdc.be.model.ArtifactType;
54 import org.openecomp.sdc.be.model.CatalogUpdateTimestamp;
55 import org.openecomp.sdc.be.model.Component;
56 import org.openecomp.sdc.be.model.ComponentParametersView;
57 import org.openecomp.sdc.be.model.DistributionStatusEnum;
58 import org.openecomp.sdc.be.model.LifecycleStateEnum;
59 import org.openecomp.sdc.be.model.Product;
60 import org.openecomp.sdc.be.model.PropertyScope;
61 import org.openecomp.sdc.be.model.Resource;
62 import org.openecomp.sdc.be.model.Service;
63 import org.openecomp.sdc.be.model.Tag;
64 import org.openecomp.sdc.be.model.User;
65 import org.openecomp.sdc.be.model.catalog.CatalogComponent;
66 import org.openecomp.sdc.be.model.category.CategoryDefinition;
67 import org.openecomp.sdc.be.model.category.GroupingDefinition;
68 import org.openecomp.sdc.be.model.category.SubCategoryDefinition;
69 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ArtifactsOperations;
70 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.InterfaceOperation;
71 import org.openecomp.sdc.be.model.jsonjanusgraph.utils.ModelConverter;
72 import org.openecomp.sdc.be.model.operations.api.IElementOperation;
73 import org.openecomp.sdc.be.model.operations.api.IGroupInstanceOperation;
74 import org.openecomp.sdc.be.model.operations.api.IGroupOperation;
75 import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation;
76 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
77 import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter;
78 import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation;
79 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
80 import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
81 import org.openecomp.sdc.be.resources.data.category.CategoryData;
82 import org.openecomp.sdc.be.resources.data.category.SubCategoryData;
83 import org.openecomp.sdc.be.ui.model.UiCategories;
84 import org.openecomp.sdc.be.user.Role;
85 import org.openecomp.sdc.be.user.UserBusinessLogic;
86 import org.openecomp.sdc.common.datastructure.Wrapper;
87 import org.openecomp.sdc.common.log.wrappers.Logger;
88 import org.openecomp.sdc.common.util.ValidationUtils;
89 import org.openecomp.sdc.exception.ResponseFormat;
90 import org.springframework.beans.factory.annotation.Autowired;
92 import java.nio.charset.StandardCharsets;
93 import java.util.ArrayList;
94 import java.util.Arrays;
95 import java.util.EnumMap;
96 import java.util.HashMap;
97 import java.util.HashSet;
98 import java.util.LinkedList;
99 import java.util.List;
100 import java.util.Map;
101 import java.util.Objects;
102 import java.util.Optional;
103 import java.util.Set;
104 import java.util.function.Predicate;
105 import java.util.stream.Collectors;
107 import static org.apache.commons.lang.BooleanUtils.isTrue;
108 import static org.openecomp.sdc.be.components.impl.ImportUtils.Constants.DEFAULT_ICON;
110 @org.springframework.stereotype.Component("elementsBusinessLogic")
111 public class ElementBusinessLogic extends BaseBusinessLogic {
113 private static final Logger log = Logger.getLogger(ElementBusinessLogic.class);
114 private static final String SERVICES = "services";
115 private static final String RESOURCES = "resources";
116 private static final String VALIDATION_OF_USER_FAILED_USER_ID = "Validation of user failed, userId {}";
117 private static final String COMPONENT_TYPE_IS_INVALID = "Component type {} is invalid";
118 private static final String VALIDATION_OF_USER_ROLE_FAILED_USER_ID = "Validation of user role failed, userId {}";
120 private final IElementOperation elementOperation;
121 private final UserBusinessLogic userAdminManager;
124 public ElementBusinessLogic(IElementOperation elementDao,
125 IGroupOperation groupOperation,
126 IGroupInstanceOperation groupInstanceOperation,
127 IGroupTypeOperation groupTypeOperation,
128 GroupBusinessLogic groupBusinessLogic,
129 InterfaceOperation interfaceOperation,
130 InterfaceLifecycleOperation interfaceLifecycleTypeOperation,
131 ArtifactsOperations artifactToscaOperation, IElementOperation elementOperation,
132 UserBusinessLogic userAdminManager) {
133 super(elementDao, groupOperation, groupInstanceOperation, groupTypeOperation,
134 interfaceOperation, interfaceLifecycleTypeOperation, artifactToscaOperation);
135 this.elementOperation = elementOperation;
136 this.userAdminManager = userAdminManager;
143 public Either<Map<String, List<? extends Component>>, ResponseFormat> getFollowed(User user) {
144 // Used for not getting duplicated followed. Cheaper than checking ArrayList.contains
145 Either<Map<String, Set<? extends Component>>, ResponseFormat> response = null;
147 String role = user.getRole();
148 String userId = user.getUserId();
149 Role currentRole = Role.valueOf(role);
151 switch (currentRole) {
153 response = handleDesigner(userId);
156 case PRODUCT_STRATEGIST:
157 response = handleProductStrategist();
160 case PRODUCT_MANAGER:
161 response = handleProductManager(userId);
165 response = handleAdmin();
169 response = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
172 // converting the Set to List so the rest of the code will handle it normally (Was changed because the same element with the same uuid was returned twice)
173 return convertedToListResponse(response);
177 private Either<Map<String, List<? extends Component>>, ResponseFormat> convertedToListResponse(Either<Map<String, Set<? extends Component>>, ResponseFormat> setResponse) {
179 Map<String, List<? extends Component>> arrayResponse = new HashMap<>();
180 if (setResponse.isLeft()) {
181 for (Map.Entry<String, Set<? extends Component>> entry : setResponse.left().value().entrySet()) {
182 arrayResponse.put(entry.getKey(), new ArrayList(new HashSet(entry.getValue())));
184 return Either.left(arrayResponse);
186 return Either.right(setResponse.right().value());
189 private Either<Map<String, Set<? extends Component>>, ResponseFormat> handleAdmin() {
190 Either<Map<String, Set<? extends Component>>, ResponseFormat> response;
191 // userId should stay null
192 Set<LifecycleStateEnum> lifecycleStates = new HashSet<>();
193 lifecycleStates.add(LifecycleStateEnum.CERTIFIED);
194 response = getFollowedResourcesAndServices(null, lifecycleStates, new HashSet<>());
198 private Either<Map<String, Set<? extends Component>>, ResponseFormat> handleDesigner(String userId) {
199 Set<LifecycleStateEnum> lifecycleStates = new HashSet<>();
200 Set<LifecycleStateEnum> lastStateStates = new HashSet<>();
201 Either<Map<String, Set<? extends Component>>, ResponseFormat> response;
202 lifecycleStates.add(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN);
203 lifecycleStates.add(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT);
204 lifecycleStates.add(LifecycleStateEnum.CERTIFIED);
206 lastStateStates.add(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN);
207 response = getFollowedResourcesAndServices(userId, lifecycleStates, lastStateStates);
211 private Either<Map<String, Set<? extends Component>>, ResponseFormat> handleProductStrategist() {
212 // Should be empty list according to Ella, 13/03/16
213 Map<String, Set<? extends Component>> result = new HashMap<>();
214 result.put("products", new HashSet<>());
215 return Either.left(result);
218 private Either<Map<String, Set<? extends Component>>, ResponseFormat> handleProductManager(String userId) {
219 Set<LifecycleStateEnum> lifecycleStates = new HashSet<>();
220 Set<LifecycleStateEnum> lastStateStates = new HashSet<>();
221 Either<Map<String, Set<? extends Component>>, ResponseFormat> response;
222 lifecycleStates.add(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN);
223 lifecycleStates.add(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT);
224 lifecycleStates.add(LifecycleStateEnum.CERTIFIED);
226 lastStateStates.add(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN);
227 response = getFollowedProducts(userId, lifecycleStates, lastStateStates);
231 private Either<Map<String, Set<? extends Component>>, ResponseFormat> getFollowedResourcesAndServices(String userId, Set<LifecycleStateEnum> lifecycleStates, Set<LifecycleStateEnum> lastStateStates) {
234 Either<Set<Resource>, StorageOperationStatus> resources = toscaOperationFacade.getFollowed(userId, lifecycleStates, lastStateStates, ComponentTypeEnum.RESOURCE);
236 if (resources.isLeft()) {
237 Either<Set<Service>, StorageOperationStatus> services = toscaOperationFacade.getFollowed(userId, lifecycleStates, lastStateStates, ComponentTypeEnum.SERVICE);
238 if (services.isLeft()) {
239 Map<String, Set<? extends Component>> result = new HashMap<>();
240 result.put(SERVICES, services.left().value());
241 result.put(RESOURCES, resources.left().value());
242 return Either.left(result);
244 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(services.right().value())));
247 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(resources.right().value())));
250 janusGraphDao.commit();
254 private Either<Map<String, Set<? extends Component>>, ResponseFormat> getFollowedProducts(String userId, Set<LifecycleStateEnum> lifecycleStates, Set<LifecycleStateEnum> lastStateStates) {
255 Either<Set<Product>, StorageOperationStatus> products = toscaOperationFacade.getFollowed(userId, lifecycleStates, lastStateStates, ComponentTypeEnum.PRODUCT);
256 if (products.isLeft()) {
257 Map<String, Set<? extends Component>> result = new HashMap<>();
258 result.put("products", products.left().value());
259 return Either.left(result);
261 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(products.right().value())));
266 * New categories flow - start
268 public Either<List<CategoryDefinition>, ActionStatus> getAllResourceCategories() {
269 return elementOperation.getAllResourceCategories();
272 public Either<List<CategoryDefinition>, ActionStatus> getAllServiceCategories() {
273 return elementOperation.getAllServiceCategories();
276 public Either<CategoryDefinition, ResponseFormat> createCategory(CategoryDefinition category, String componentTypeParamName, String userId) {
278 AuditingActionEnum auditingAction = AuditingActionEnum.ADD_CATEGORY;
279 ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName);
280 String componentType = componentTypeEnum == null ? componentTypeParamName : componentTypeEnum.getValue();
281 CategoryTypeEnum categoryType = CategoryTypeEnum.CATEGORY;
283 User user = validateUserExists(userId);
284 if (category == null) {
285 log.debug("Category json is invalid");
286 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
287 handleCategoryAuditing(responseFormat, user, null, auditingAction, componentType);
288 return Either.right(responseFormat);
291 String categoryName = category.getName();
292 // For auditing of failures we need the original non-normalized name
293 String origCategoryName = categoryName;
294 if (componentTypeEnum == null) {
295 log.debug(COMPONENT_TYPE_IS_INVALID, componentTypeParamName);
296 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
297 handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
298 return Either.right(responseFormat);
301 Either<Boolean, ResponseFormat> validateUserRole = validateUserRole(user, componentTypeEnum);
302 if (validateUserRole.isRight()) {
303 log.debug(VALIDATION_OF_USER_ROLE_FAILED_USER_ID, userId);
304 ResponseFormat responseFormat = validateUserRole.right().value();
305 handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
306 return Either.right(responseFormat);
309 if (!ValidationUtils.validateCategoryDisplayNameFormat(categoryName)) {
310 log.debug("Category display name format is invalid, name {}, componentType {}", categoryName, componentType);
311 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, componentType, categoryType.getValue());
312 handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
313 return Either.right(responseFormat);
316 categoryName = ValidationUtils.normalizeCategoryName4Display(categoryName);
318 if (!ValidationUtils.validateCategoryDisplayNameLength(categoryName)) {
319 log.debug("Category display name length is invalid, should be from 4 to 25 chars, name {}, componentType {}", categoryName, componentType);
320 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, componentType, categoryType.getValue());
321 handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
322 return Either.right(responseFormat);
325 category.setName(categoryName);
327 String normalizedName = ValidationUtils.normalizeCategoryName4Uniqueness(categoryName);
328 category.setNormalizedName(normalizedName);
330 if (ValidationUtils.validateCategoryIconNotEmpty(category.getIcons())){
331 log.debug("createCategory: setting category icon to default icon since service category was created without an icon ");
332 category.setIcons(Arrays.asList(DEFAULT_ICON));
335 NodeTypeEnum nodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, categoryType);
337 Either<Boolean, ActionStatus> categoryUniqueEither = elementOperation.isCategoryUniqueForType(nodeType, normalizedName);
338 if (categoryUniqueEither.isRight()) {
339 log.debug("Failed to check category uniqueness, name {}, componentType {}", categoryName, componentType);
340 ResponseFormat responseFormat = componentsUtils.getResponseFormat(categoryUniqueEither.right().value());
341 handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
342 return Either.right(responseFormat);
345 Boolean isCategoryUnique = categoryUniqueEither.left().value();
346 if (!isCategoryUnique) {
347 log.debug("Category is not unique, name {}, componentType {}", categoryName, componentType);
348 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_CATEGORY_ALREADY_EXISTS, componentType, categoryName);
349 handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
350 return Either.right(responseFormat);
353 Either<CategoryDefinition, ActionStatus> createCategoryByType = elementOperation.createCategory(category, nodeType);
354 if (createCategoryByType.isRight()) {
355 log.debug("Failed to create category, name {}, componentType {}", categoryName, componentType);
356 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_CATEGORY_ALREADY_EXISTS, componentType, categoryName);
357 handleCategoryAuditing(responseFormat, user, origCategoryName, auditingAction, componentType);
358 return Either.right(componentsUtils.getResponseFormat(createCategoryByType.right().value()));
360 category = createCategoryByType.left().value();
361 log.debug("Created category for component {}, name {}, uniqueId {}", componentType, categoryName, category.getUniqueId());
362 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.CREATED);
363 handleCategoryAuditing(responseFormat, user, category.getName(), auditingAction, componentType);
364 return Either.left(category);
367 public Either<SubCategoryDefinition, ResponseFormat> createSubCategory(SubCategoryDefinition subCategory, String componentTypeParamName, String parentCategoryId, String userId) {
369 AuditingActionEnum auditingAction = AuditingActionEnum.ADD_SUB_CATEGORY;
370 ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName);
371 String componentType = componentTypeEnum == null ? componentTypeParamName : componentTypeEnum.getValue();
372 CategoryTypeEnum categoryType = CategoryTypeEnum.SUBCATEGORY;
374 String parentCategoryName = parentCategoryId;
376 if (subCategory == null) {
377 log.debug("Sub-category json is invalid");
378 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
379 handleCategoryAuditing(responseFormat, null, parentCategoryName, null, auditingAction, componentType);
380 return Either.right(responseFormat);
383 String subCategoryName = subCategory.getName();
384 // For auditing of failures we need the original non-normalized name
385 String origSubCategoryName = subCategoryName;
388 user = validateUserExists(userId);
389 } catch(ByActionStatusComponentException e){
390 ResponseFormat responseFormat = componentsUtils.getResponseFormat(e.getActionStatus(), e.getParams());
391 handleComponentException(userId, auditingAction, componentType, parentCategoryName, origSubCategoryName,
394 } catch(ByResponseFormatComponentException e){
395 ResponseFormat responseFormat = e.getResponseFormat();
396 handleComponentException(userId, auditingAction, componentType, parentCategoryName, origSubCategoryName,
400 if (componentTypeEnum == null) {
401 log.debug(COMPONENT_TYPE_IS_INVALID, componentTypeParamName);
402 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
403 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
404 return Either.right(responseFormat);
407 Either<Boolean, ResponseFormat> validateComponentType = validateComponentTypeForCategory(componentTypeEnum, categoryType);
408 if (validateComponentType.isRight()) {
409 log.debug("Validation of component type for sub-category failed");
410 ResponseFormat responseFormat = validateComponentType.right().value();
411 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
412 return Either.right(responseFormat);
415 Either<Boolean, ResponseFormat> validateUserRole = validateUserRole(user, componentTypeEnum);
416 if (validateUserRole.isRight()) {
417 log.debug(VALIDATION_OF_USER_ROLE_FAILED_USER_ID, userId);
418 ResponseFormat responseFormat = validateUserRole.right().value();
419 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
420 return Either.right(responseFormat);
423 NodeTypeEnum parentNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.CATEGORY);
424 NodeTypeEnum childNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.SUBCATEGORY);
426 CategoryDefinition categoryDefinition;
427 Either<CategoryDefinition, ResponseFormat> validateCategoryExists = validateCategoryExists(parentNodeType, parentCategoryId, componentTypeEnum);
428 if (validateCategoryExists.isRight()) {
429 log.debug("Validation of parent category exists failed, parent categoryId {}", parentCategoryId);
430 ResponseFormat responseFormat = validateCategoryExists.right().value();
431 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
432 return Either.right(responseFormat);
435 categoryDefinition = validateCategoryExists.left().value();
436 parentCategoryName = categoryDefinition.getName();
438 if (!ValidationUtils.validateCategoryDisplayNameFormat(subCategoryName)) {
439 log.debug("Sub-category display name format is invalid, name {}, componentType {}", subCategoryName, componentType);
440 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, componentType, categoryType.getValue());
441 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
442 return Either.right(responseFormat);
445 subCategoryName = ValidationUtils.normalizeCategoryName4Display(subCategoryName);
447 if (!ValidationUtils.validateCategoryDisplayNameLength(subCategoryName)) {
448 log.debug("Sub-category display name length is invalid, should be from 4 to 25 chars, name {}, componentType {}", subCategoryName, componentType);
449 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, componentType, categoryType.getValue());
450 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
451 return Either.right(responseFormat);
454 String normalizedName = ValidationUtils.normalizeCategoryName4Uniqueness(subCategoryName);
455 subCategory.setNormalizedName(normalizedName);
457 // Uniqueness under this category
458 Either<Boolean, ActionStatus> subCategoryUniqueForCategory = elementOperation.isSubCategoryUniqueForCategory(childNodeType, normalizedName, parentCategoryId);
459 if (subCategoryUniqueForCategory.isRight()) {
460 log.debug("Failed to check sub-category uniqueness, parent name {}, subcategory norm name {}, componentType {}", parentCategoryName, normalizedName, componentType);
461 ResponseFormat responseFormat = componentsUtils.getResponseFormat(subCategoryUniqueForCategory.right().value());
462 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
463 return Either.right(responseFormat);
466 Boolean isSubUnique = subCategoryUniqueForCategory.left().value();
468 log.debug("Sub-category is not unique for category, parent name {}, subcategory norm name {}, componentType {}", parentCategoryName, normalizedName, componentType);
469 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_SUB_CATEGORY_EXISTS_FOR_CATEGORY, componentType, subCategoryName, parentCategoryName);
470 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
471 return Either.right(responseFormat);
474 // Setting name of subcategory to fit the similar subcategory name
476 // For example if Network-->kUKU exists for service category Network,
477 // and user is trying to create Router-->Kuku for service category
479 // his subcategory name will be Router-->kUKU.
480 Either<SubCategoryDefinition, ActionStatus> subCategoryUniqueForType = elementOperation.getSubCategoryUniqueForType(childNodeType, normalizedName);
481 if (subCategoryUniqueForType.isRight()) {
482 log.debug("Failed validation of whether similar sub-category exists, normalizedName {} componentType {}", normalizedName, componentType);
483 ResponseFormat responseFormat = componentsUtils.getResponseFormat(subCategoryUniqueForType.right().value());
484 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
485 return Either.right(responseFormat);
487 SubCategoryDefinition subCategoryDefinition = subCategoryUniqueForType.left().value();
488 if (subCategoryDefinition != null) {
489 subCategoryName = subCategoryDefinition.getName();
492 subCategory.setName(subCategoryName);
493 ///////////////////////////////////////////// Validations end
495 Either<SubCategoryDefinition, ActionStatus> createSubCategory = elementOperation.createSubCategory(parentCategoryId, subCategory, childNodeType);
496 if (createSubCategory.isRight()) {
497 log.debug("Failed to create sub-category, name {}, componentType {}", subCategoryName, componentType);
498 ResponseFormat responseFormat = componentsUtils.getResponseFormat(subCategoryUniqueForType.right().value());
499 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction, componentType);
500 return Either.right(responseFormat);
503 SubCategoryDefinition subCategoryCreated = createSubCategory.left().value();
504 log.debug("Created sub-category for component {}, name {}, uniqueId {}", componentType, subCategoryName, subCategoryCreated.getUniqueId());
505 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.CREATED);
506 handleCategoryAuditing(responseFormat, user, parentCategoryName, subCategoryCreated.getName(), auditingAction, componentType);
507 return Either.left(subCategoryCreated);
510 private void handleComponentException(String userId, AuditingActionEnum auditingAction, String componentType,
511 String parentCategoryName, String origSubCategoryName, ResponseFormat responseFormat) {
513 log.debug(VALIDATION_OF_USER_FAILED_USER_ID, userId);
515 user.setUserId(userId);
516 handleCategoryAuditing(responseFormat, user, parentCategoryName, origSubCategoryName, auditingAction,
520 private void handleComponentException(GroupingDefinition grouping, String userId, AuditingActionEnum auditingAction,
521 String componentType, String parentCategoryName, String parentSubCategoryName, ResponseFormat responseFormat) {
523 log.debug(VALIDATION_OF_USER_FAILED_USER_ID, userId);
525 user.setUserId(userId);
526 String groupingNameForAudit = grouping == null ? null : grouping.getName();
527 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, groupingNameForAudit,
528 auditingAction, componentType);
531 private void handleComponentException(String componentType, String userId, ResponseFormat responseFormat) {
534 user.setUserId(userId);
535 log.debug(VALIDATION_OF_USER_FAILED_USER_ID, userId);
536 componentsUtils.auditGetCategoryHierarchy(user, componentType, responseFormat);
539 public Either<GroupingDefinition, ResponseFormat> createGrouping(GroupingDefinition grouping, String componentTypeParamName, String grandParentCategoryId, String parentSubCategoryId, String userId) {
541 AuditingActionEnum auditingAction = AuditingActionEnum.ADD_GROUPING;
542 ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName);
543 String componentType = componentTypeEnum == null ? componentTypeParamName : componentTypeEnum.getValue();
544 CategoryTypeEnum categoryType = CategoryTypeEnum.GROUPING;
546 String parentCategoryName = grandParentCategoryId;
547 String parentSubCategoryName = parentSubCategoryId;
551 user = validateUserExists(userId);
552 } catch(ByResponseFormatComponentException e){
553 ResponseFormat responseFormat = e.getResponseFormat();
554 handleComponentException(grouping, userId, auditingAction, componentType, parentCategoryName,
555 parentSubCategoryName,
558 } catch(ByActionStatusComponentException e){
559 ResponseFormat responseFormat = componentsUtils.getResponseFormat(e.getActionStatus(), e.getParams());
560 handleComponentException(grouping, userId, auditingAction, componentType, parentCategoryName,
561 parentSubCategoryName, responseFormat);
565 if (grouping == null) {
566 log.debug("Grouping json is invalid");
567 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
568 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, null, auditingAction, componentType);
569 return Either.right(responseFormat);
572 String groupingName = grouping.getName();
573 // For auditing of failures we need the original non-normalized name
574 String origGroupingName = groupingName;
576 if (componentTypeEnum == null) {
577 log.debug(COMPONENT_TYPE_IS_INVALID, componentTypeParamName);
578 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
579 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
580 return Either.right(responseFormat);
583 Either<Boolean, ResponseFormat> validateComponentType = validateComponentTypeForCategory(componentTypeEnum, categoryType);
584 if (validateComponentType.isRight()) {
585 log.debug("Validation of component type for grouping failed");
586 ResponseFormat responseFormat = validateComponentType.right().value();
587 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
588 return Either.right(responseFormat);
591 Either<Boolean, ResponseFormat> validateUserRole = validateUserRole(user, componentTypeEnum);
592 if (validateUserRole.isRight()) {
593 log.debug(VALIDATION_OF_USER_ROLE_FAILED_USER_ID, userId);
594 ResponseFormat responseFormat = validateUserRole.right().value();
595 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
596 return Either.right(responseFormat);
599 NodeTypeEnum grandParentNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.CATEGORY);
600 NodeTypeEnum parentNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.SUBCATEGORY);
601 NodeTypeEnum childNodeType = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.GROUPING);
604 CategoryDefinition categoryDefinition;
605 Either<CategoryDefinition, ResponseFormat> validateCategoryExists = validateCategoryExists(grandParentNodeType, grandParentCategoryId, componentTypeEnum);
606 if (validateCategoryExists.isRight()) {
607 log.debug("Validation of parent category exists failed, parent categoryId {}", grandParentCategoryId);
608 ResponseFormat responseFormat = validateCategoryExists.right().value();
609 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
610 return Either.right(responseFormat);
613 categoryDefinition = validateCategoryExists.left().value();
614 parentCategoryName = categoryDefinition.getName();
616 // Validate subcategory
617 SubCategoryDefinition subCategoryDefinition;
618 Either<SubCategoryDefinition, ResponseFormat> validateSubCategoryExists = validateSubCategoryExists(parentNodeType, parentSubCategoryId, componentTypeEnum);
619 if (validateSubCategoryExists.isRight()) {
620 log.debug("Validation of parent sub-category exists failed, parent sub-category id {}", parentSubCategoryId);
621 ResponseFormat responseFormat = validateSubCategoryExists.right().value();
622 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
623 return Either.right(responseFormat);
626 subCategoryDefinition = validateSubCategoryExists.left().value();
627 parentSubCategoryName = subCategoryDefinition.getName();
629 if (!ValidationUtils.validateCategoryDisplayNameFormat(groupingName)) {
630 log.debug("Sub-category display name format is invalid, name {}, componentType {}", groupingName, componentType);
631 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, componentType, categoryType.getValue());
632 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
633 return Either.right(responseFormat);
636 groupingName = ValidationUtils.normalizeCategoryName4Display(groupingName);
638 if (!ValidationUtils.validateCategoryDisplayNameLength(groupingName)) {
639 log.debug("Grouping display name length is invalid, should be from 4 to 25 chars, name {}, componentType {}", groupingName, componentType);
640 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, componentType, categoryType.getValue());
641 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
642 return Either.right(responseFormat);
645 String normalizedName = ValidationUtils.normalizeCategoryName4Uniqueness(groupingName);
646 grouping.setNormalizedName(normalizedName);
648 // Uniqueness under this category
649 Either<Boolean, ActionStatus> groupingUniqueForSubCategory = elementOperation.isGroupingUniqueForSubCategory(childNodeType, normalizedName, parentSubCategoryId);
650 if (groupingUniqueForSubCategory.isRight()) {
651 log.debug("Failed to check grouping uniqueness, parent name {}, grouping norm name {}, componentType {}", parentSubCategoryName, normalizedName, componentType);
652 ResponseFormat responseFormat = componentsUtils.getResponseFormat(groupingUniqueForSubCategory.right().value());
653 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
654 return Either.right(responseFormat);
657 Boolean isGroupingUnique = groupingUniqueForSubCategory.left().value();
658 if (!isGroupingUnique) {
659 log.debug("Grouping is not unique for sub-category, parent name {}, grouping norm name {}, componentType {}", parentSubCategoryName, normalizedName, componentType);
660 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_GROUPING_EXISTS_FOR_SUB_CATEGORY, componentType, groupingName, parentSubCategoryName);
661 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
662 return Either.right(responseFormat);
665 // Setting name of grouping to fit the similar grouping name ignoring
667 // For example if Network-->kUKU exists for service sub-category
668 // Network, and user is trying to create grouping Router-->Kuku for
669 // service sub-category Router,
670 // his grouping name will be Router-->kUKU.
671 Either<GroupingDefinition, ActionStatus> groupingUniqueForType = elementOperation.getGroupingUniqueForType(childNodeType, normalizedName);
672 if (groupingUniqueForType.isRight()) {
673 log.debug("Failed validation of whether similar grouping exists, normalizedName {} componentType {}", normalizedName, componentType);
674 ResponseFormat responseFormat = componentsUtils.getResponseFormat(groupingUniqueForType.right().value());
675 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
676 return Either.right(responseFormat);
678 GroupingDefinition groupingDefinition = groupingUniqueForType.left().value();
679 if (groupingDefinition != null) {
680 groupingName = groupingDefinition.getName();
683 grouping.setName(groupingName);
684 ///////////////////////////////////////////// Validations end
686 Either<GroupingDefinition, ActionStatus> createGrouping = elementOperation.createGrouping(parentSubCategoryId, grouping, childNodeType);
687 if (createGrouping.isRight()) {
688 log.debug("Failed to create grouping, name {}, componentType {}", groupingName, componentType);
689 ResponseFormat responseFormat = componentsUtils.getResponseFormat(createGrouping.right().value());
690 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, origGroupingName, auditingAction, componentType);
691 return Either.right(responseFormat);
694 GroupingDefinition groupingCreated = createGrouping.left().value();
695 log.debug("Created grouping for component {}, name {}, uniqueId {}", componentType, groupingName, groupingCreated.getUniqueId());
696 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.CREATED);
697 handleCategoryAuditing(responseFormat, user, parentCategoryName, parentSubCategoryName, groupingCreated.getName(), auditingAction, componentType);
698 return Either.left(groupingCreated);
703 public Either<List<CategoryDefinition>, ResponseFormat> getAllCategories(String componentType, String userId) {
704 ResponseFormat responseFormat;
705 User user = new User();
706 if (userId == null) {
707 user.setUserId("UNKNOWN");
708 responseFormat = componentsUtils.getResponseFormat(ActionStatus.MISSING_INFORMATION);
709 componentsUtils.auditGetCategoryHierarchy(user, componentType, responseFormat);
710 return Either.right(responseFormat);
713 user = validateUserExists(userId);
714 } catch (ByActionStatusComponentException e){
715 responseFormat = componentsUtils.getResponseFormat(e.getActionStatus(), e.getParams());
716 handleComponentException(componentType, userId, responseFormat);
718 } catch (ByResponseFormatComponentException e){
719 responseFormat = e.getResponseFormat();
720 handleComponentException(componentType, userId, responseFormat);
723 ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentType);
724 if (componentTypeEnum == null) {
725 log.debug("Cannot create category for component type {}", componentType);
726 responseFormat = componentsUtils.getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, "component type");
727 componentsUtils.auditGetCategoryHierarchy(user, componentType, responseFormat);
728 return Either.right(responseFormat);
731 NodeTypeEnum nodeTypeEnum = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.CATEGORY);
732 Either<List<CategoryDefinition>, ActionStatus> getAllCategoriesByType = elementOperation.getAllCategories(nodeTypeEnum, false);
733 if (getAllCategoriesByType.isRight()) {
734 responseFormat = componentsUtils.getResponseFormat(getAllCategoriesByType.right().value());
735 componentsUtils.auditGetCategoryHierarchy(user, componentType, responseFormat);
736 return Either.right(responseFormat);
738 List<CategoryDefinition> categories = getAllCategoriesByType.left().value();
739 responseFormat = componentsUtils.getResponseFormat(ActionStatus.OK);
740 componentsUtils.auditGetCategoryHierarchy(user, componentType, responseFormat);
741 return Either.left(categories);
746 public Either<UiCategories, ResponseFormat> getAllCategories(String userId) {
747 ResponseFormat responseFormat;
748 UiCategories categories = new UiCategories();
750 User user = validateUserExists(userId);
752 // GET resource categories
753 Either<List<CategoryDefinition>, ActionStatus> getResourceCategoriesByType = elementOperation.getAllCategories(NodeTypeEnum.ResourceNewCategory, false);
754 if (getResourceCategoriesByType.isRight()) {
755 responseFormat = componentsUtils.getResponseFormat(getResourceCategoriesByType.right().value());
756 componentsUtils.auditGetCategoryHierarchy(user, ComponentTypeEnum.RESOURCE.getValue(), responseFormat);
757 return Either.right(responseFormat);
759 categories.setResourceCategories(getResourceCategoriesByType.left().value());
761 // GET service categories
762 Either<List<CategoryDefinition>, ActionStatus> getServiceCategoriesByType = elementOperation.getAllCategories(NodeTypeEnum.ServiceNewCategory, false);
763 if (getServiceCategoriesByType.isRight()) {
764 responseFormat = componentsUtils.getResponseFormat(getServiceCategoriesByType.right().value());
765 componentsUtils.auditGetCategoryHierarchy(user, ComponentTypeEnum.SERVICE.getValue(), responseFormat);
766 return Either.right(responseFormat);
768 categories.setServiceCategories(getServiceCategoriesByType.left().value());
769 categories.setProductCategories(new ArrayList<>());
770 return Either.left(categories);
773 public Either<CategoryDefinition, ResponseFormat> deleteCategory(String categoryId, String componentTypeParamName, String userId) {
775 validateUserExists(userId);
777 ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName);
778 if (componentTypeEnum == null) {
779 log.debug("Cannot create category for component type {}", componentTypeParamName);
780 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
783 NodeTypeEnum nodeTypeEnum = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.CATEGORY);
785 Either<CategoryDefinition, ActionStatus> deleteCategoryByType = elementOperation.deleteCategory(nodeTypeEnum, categoryId);
786 if (deleteCategoryByType.isRight()) {
787 // auditing, logging here...
788 return Either.right(componentsUtils.getResponseFormat(deleteCategoryByType.right().value()));
790 CategoryDefinition category = deleteCategoryByType.left().value();
791 log.debug("Delete category for component {}, name {}, uniqueId {}", nodeTypeEnum, category.getName(), category.getUniqueId());
792 return Either.left(category);
795 public Either<SubCategoryDefinition, ResponseFormat> deleteSubCategory(String parentSubCategoryId, String componentTypeParamName, String userId) {
797 validateUserExists(userId);
799 ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName);
800 if (componentTypeEnum == null) {
801 log.debug("Cannot delete sub-category for component type {}", componentTypeParamName);
802 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
805 NodeTypeEnum nodeTypeEnum = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.SUBCATEGORY);
807 Either<SubCategoryDefinition, ActionStatus> deleteSubCategoryByType = elementOperation.deleteSubCategory(nodeTypeEnum, parentSubCategoryId);
808 if (deleteSubCategoryByType.isRight()) {
809 // auditing, logging here...
810 return Either.right(componentsUtils.getResponseFormat(deleteSubCategoryByType.right().value()));
812 SubCategoryDefinition subCategory = deleteSubCategoryByType.left().value();
813 log.debug("Deleted sub-category for component {}, name {}, uniqueId {}", nodeTypeEnum, subCategory.getName(), subCategory.getUniqueId());
814 return Either.left(subCategory);
817 public Either<GroupingDefinition, ResponseFormat> deleteGrouping(String groupingId, String componentTypeParamName, String userId) {
819 validateUserExists(userId);
821 ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentTypeParamName);
822 if (componentTypeEnum == null) {
823 log.debug("Cannot delete grouping for component type {}", componentTypeParamName);
824 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
827 NodeTypeEnum nodeTypeEnum = NodeTypeConvertUtils.getCategoryNodeTypeByComponentParam(componentTypeEnum, CategoryTypeEnum.GROUPING);
829 Either<GroupingDefinition, ActionStatus> deleteGroupingByType = elementOperation.deleteGrouping(nodeTypeEnum, groupingId);
830 if (deleteGroupingByType.isRight()) {
831 // auditing, logging here...
832 return Either.right(componentsUtils.getResponseFormat(deleteGroupingByType.right().value()));
834 GroupingDefinition deletedGrouping = deleteGroupingByType.left().value();
835 log.debug("Deleted grouping for component {}, name {}, uniqueId {}", nodeTypeEnum, deletedGrouping.getName(), deletedGrouping.getUniqueId());
836 return Either.left(deletedGrouping);
839 private Either<Boolean, ResponseFormat> validateUserRole(User user, ComponentTypeEnum componentTypeEnum) {
840 String role = user.getRole();
841 boolean validAdminAction = role.equals(Role.ADMIN.name()) && (componentTypeEnum == ComponentTypeEnum.SERVICE || componentTypeEnum == ComponentTypeEnum.RESOURCE);
842 boolean validProductAction = role.equals(Role.PRODUCT_STRATEGIST.name()) && (componentTypeEnum == ComponentTypeEnum.PRODUCT);
844 if (!(validAdminAction || validProductAction)) {
845 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION);
846 log.debug("User not permitted to perform operation on category, userId = {}, role = {}, componentType = {}", user.getUserId(), role, componentTypeEnum);
847 return Either.right(responseFormat);
849 return Either.left(true);
852 private Either<Boolean, ResponseFormat> validateComponentTypeForCategory(ComponentTypeEnum componentType, CategoryTypeEnum categoryType) {
853 boolean validResourceAction = componentType == ComponentTypeEnum.RESOURCE && (categoryType == CategoryTypeEnum.CATEGORY || categoryType == CategoryTypeEnum.SUBCATEGORY);
854 boolean validServiceAction = componentType == ComponentTypeEnum.SERVICE && categoryType == CategoryTypeEnum.CATEGORY;
855 boolean validProductAction = componentType == ComponentTypeEnum.PRODUCT; // can
861 if (!(validResourceAction || validServiceAction || validProductAction)) {
862 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
863 log.debug("It's not allowed to create category type {} for component type {}", categoryType, componentType);
864 return Either.right(responseFormat);
866 return Either.left(true);
869 private Either<CategoryDefinition, ResponseFormat> validateCategoryExists(NodeTypeEnum nodeType, String categoryId, ComponentTypeEnum componentType) {
870 Either<CategoryDefinition, ActionStatus> categoryByTypeAndId = elementOperation.getCategory(nodeType, categoryId);
871 if (categoryByTypeAndId.isRight()) {
872 log.debug("Failed to fetch parent category, parent categoryId {}", categoryId);
873 ActionStatus actionStatus = categoryByTypeAndId.right().value();
874 ResponseFormat responseFormat;
875 if (actionStatus == ActionStatus.COMPONENT_CATEGORY_NOT_FOUND) {
876 responseFormat = componentsUtils.getResponseFormat(actionStatus, componentType.getValue().toLowerCase(), CategoryTypeEnum.CATEGORY.getValue(), "");
878 responseFormat = componentsUtils.getResponseFormat(actionStatus);
880 return Either.right(responseFormat);
882 return Either.left(categoryByTypeAndId.left().value());
885 private Either<SubCategoryDefinition, ResponseFormat> validateSubCategoryExists(NodeTypeEnum nodeType, String subCategoryId, ComponentTypeEnum componentType) {
886 Either<SubCategoryDefinition, ActionStatus> subCategoryByTypeAndId = elementOperation.getSubCategory(nodeType, subCategoryId);
887 if (subCategoryByTypeAndId.isRight()) {
888 log.debug("Failed to fetch parent category, parent categoryId {}", subCategoryId);
889 ActionStatus actionStatus = subCategoryByTypeAndId.right().value();
890 ResponseFormat responseFormat;
891 if (actionStatus == ActionStatus.COMPONENT_CATEGORY_NOT_FOUND) {
892 responseFormat = componentsUtils.getResponseFormat(actionStatus, componentType.getValue().toLowerCase(), CategoryTypeEnum.SUBCATEGORY.getValue(), "");
894 responseFormat = componentsUtils.getResponseFormat(actionStatus);
896 return Either.right(responseFormat);
898 return Either.left(subCategoryByTypeAndId.left().value());
901 private void handleCategoryAuditing(ResponseFormat responseFormat, User user, String category, AuditingActionEnum auditingAction, String componentType) {
902 componentsUtils.auditCategory(responseFormat, user, category, null, null, auditingAction, componentType);
905 private void handleCategoryAuditing(ResponseFormat responseFormat, User user, String category, String subCategory, AuditingActionEnum auditingAction, String componentType) {
906 componentsUtils.auditCategory(responseFormat, user, category, subCategory, null, auditingAction, componentType);
909 private void handleCategoryAuditing(ResponseFormat responseFormat, User user, String category, String subCategory, String grouping, AuditingActionEnum auditingAction, String componentType) {
910 componentsUtils.auditCategory(responseFormat, user, category, subCategory, grouping, auditingAction, componentType);
914 * New categories flow - end
917 public Either<List<Tag>, ActionStatus> getAllTags(String userId) {
918 ActionStatus status = validateUserExistsActionStatus(userId);
919 if (ActionStatus.OK != status) {
920 return Either.right(status);
922 return elementOperation.getAllTags();
925 public Either<List<PropertyScope>, ActionStatus> getAllPropertyScopes(String userId) {
926 ActionStatus status = validateUserExistsActionStatus(userId);
927 if (ActionStatus.OK != status) {
928 return Either.right(status);
930 return elementOperation.getAllPropertyScopes();
933 public Either<List<ArtifactType>, ActionStatus> getAllArtifactTypes(final String userId) {
934 ActionStatus status = validateUserExistsActionStatus(userId);
935 if (ActionStatus.OK != status) {
936 return Either.right(status);
938 return Either.left(elementOperation.getAllArtifactTypes());
941 public Either<Configuration.HeatDeploymentArtifactTimeout, ActionStatus> getDefaultHeatTimeout() {
942 return elementOperation.getDefaultHeatTimeout();
945 public Either<Map<String, List<CatalogComponent>>, ResponseFormat> getCatalogComponents(String userId, List<OriginTypeEnum> excludeTypes) {
947 return toscaOperationFacade.getCatalogOrArchiveComponents(true, excludeTypes)
948 .bimap(this::groupByComponentType,
949 err -> componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(err)));
951 janusGraphDao.commit();
955 private Map<String, List<CatalogComponent>> groupByComponentType(List<CatalogComponent> components) {
956 Map<String, List<CatalogComponent>> map = components.stream().collect(Collectors.groupingBy(cmpt -> cmptTypeToString(cmpt.getComponentType())));
958 // fixed response for UI!!! UI need to receive always map!
960 map = new HashMap<>();
962 map.computeIfAbsent(RESOURCES, k -> new ArrayList());
963 map.computeIfAbsent(SERVICES, k -> new ArrayList());
967 private String cmptTypeToString(ComponentTypeEnum componentTypeEnum) {
968 switch (componentTypeEnum) {
974 throw new IllegalStateException("resources or services only");
978 public Either<List<? extends Component>, ResponseFormat> getFilteredCatalogComponents(String assetType, Map<FilterKeyEnum, String> filters, String query) {
979 ComponentTypeEnum assetTypeEnum = AssetTypeEnum.convertToComponentTypeEnum(assetType);
982 Optional<NameValuePair> invalidFilter = findInvalidFilter(query, assetTypeEnum);
983 if (invalidFilter.isPresent()) {
984 log.debug("getFilteredAssetList: invalid filter key");
985 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_FILTER_KEY, invalidFilter.get().getName(), FilterKeyEnum.getValidFiltersByAssetType(assetTypeEnum).toString()));
989 if (filters == null || filters.isEmpty()) {
990 Either<List<Component>, StorageOperationStatus> componentsList = toscaOperationFacade.getCatalogComponents(assetTypeEnum, null, false);
991 if (componentsList.isRight()) {
992 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(componentsList.right().value())));
994 return Either.left(componentsList.left().value());
997 Either<List<Component>, StorageOperationStatus> result = getFilteredComponents(filters, assetTypeEnum, false);
999 // category hierarchy mismatch or category/subCategory/distributionStatus not found
1000 if (result.isRight()) {
1001 List<String> params = getErrorResponseParams(filters, assetTypeEnum);
1002 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(result.right().value()), params.get(0), params.get(1), params.get(2)));
1004 if (result.left().value().isEmpty()) {// no assets found for requested
1006 return Either.right(componentsUtils.getResponseFormat(ActionStatus.NO_ASSETS_FOUND, assetType, query));
1008 return Either.left(result.left().value());
1011 private Either<List<Component>, StorageOperationStatus> getFilteredComponents(Map<FilterKeyEnum, String> filters, ComponentTypeEnum assetType, boolean inTransaction) {
1012 Either<List<Component>, StorageOperationStatus> assetResult = Either.left(new LinkedList<>());
1013 if (assetType == ComponentTypeEnum.RESOURCE) {
1015 assetResult = getFilteredResources(filters, inTransaction);
1017 } else if (assetType == ComponentTypeEnum.SERVICE) {
1019 assetResult = getFilteredServices(filters, inTransaction);
1024 private <T extends Component> Either<List<T>, StorageOperationStatus> getFilteredServices(Map<FilterKeyEnum, String> filters, boolean inTransaction) {
1026 Either<List<T>, StorageOperationStatus> components = null;
1028 String categoryName = filters.get(FilterKeyEnum.CATEGORY);
1029 String distributionStatus = filters.get(FilterKeyEnum.DISTRIBUTION_STATUS);
1030 DistributionStatusEnum distEnum = DistributionStatusEnum.findState(distributionStatus);
1031 if (distributionStatus != null && distEnum == null) {
1032 filters.remove(FilterKeyEnum.CATEGORY);
1033 return Either.right(StorageOperationStatus.CATEGORY_NOT_FOUND);
1036 if (categoryName != null) { // primary filter
1037 components = fetchByCategoryOrSubCategoryName(categoryName, NodeTypeEnum.ServiceNewCategory, NodeTypeEnum.Service, inTransaction, null);
1038 if (components.isLeft() && distEnum != null) {// secondary filter
1039 Predicate<T> statusFilter = p -> ((Service) p).getDistributionStatus() == distEnum;
1040 return Either.left(components.left().value().stream().filter(statusFilter).collect(Collectors.toList()));
1042 filters.remove(FilterKeyEnum.DISTRIBUTION_STATUS);
1046 Set<DistributionStatusEnum> distStatusSet = new HashSet<>();
1047 distStatusSet.add(distEnum);
1048 Either<List<Service>, StorageOperationStatus> servicesWithDistStatus = toscaOperationFacade.getServicesWithDistStatus(distStatusSet, null);
1049 if (servicesWithDistStatus.isRight()) { // not found == empty list
1050 return Either.left(new ArrayList<>());
1053 return Either.left((List<T>) servicesWithDistStatus.left().value());
1056 public Either<List<? extends Component>, ResponseFormat> getCatalogComponentsByUuidAndAssetType(String assetType, String uuid) {
1058 if (assetType == null || uuid == null) {
1059 log.debug("getCatalogComponentsByUuidAndAssetType: One of the function parameteres is null");
1060 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
1063 ComponentTypeEnum assetTypeEnum = AssetTypeEnum.convertToComponentTypeEnum(assetType);
1065 if (assetTypeEnum == null) {
1066 log.debug("getCatalogComponentsByUuidAndAssetType: Corresponding ComponentTypeEnum not found");
1067 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
1070 Map<GraphPropertyEnum, Object> additionalPropertiesToMatch = new EnumMap<>(GraphPropertyEnum.class);
1072 switch (assetTypeEnum) {
1074 additionalPropertiesToMatch.put(GraphPropertyEnum.COMPONENT_TYPE, ComponentTypeEnum.RESOURCE.name());
1077 additionalPropertiesToMatch.put(GraphPropertyEnum.COMPONENT_TYPE, ComponentTypeEnum.SERVICE.name());
1080 log.debug("getCatalogComponentsByUuidAndAssetType: Corresponding ComponentTypeEnum not allowed for this API");
1081 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
1084 Either<List<Component>, StorageOperationStatus> componentsListByUuid = toscaOperationFacade.getComponentListByUuid(uuid, additionalPropertiesToMatch);
1085 if (componentsListByUuid.isRight()) {
1086 log.debug("getCatalogComponentsByUuidAndAssetType: " + assetTypeEnum.getValue() + " fetching failed");
1087 ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(componentsListByUuid.right().value(), assetTypeEnum);
1088 return Either.right(componentsUtils.getResponseFormat(actionStatus, uuid));
1091 log.debug("getCatalogComponentsByUuidAndAssetType: " + assetTypeEnum.getValue() + assetTypeEnum.getValue() + "fetching successful");
1092 return Either.left(componentsListByUuid.left().value());
1095 public List<String> getAllComponentTypesParamNames() {
1096 List<String> paramNames = new ArrayList<>();
1097 paramNames.add(ComponentTypeEnum.SERVICE_PARAM_NAME);
1098 paramNames.add(ComponentTypeEnum.RESOURCE_PARAM_NAME);
1099 paramNames.add(ComponentTypeEnum.PRODUCT_PARAM_NAME);
1103 public List<String> getAllSupportedRoles() {
1104 Role[] values = Role.values();
1105 List<String> roleNames = new ArrayList<>();
1106 for (Role role : values) {
1107 roleNames.add(role.name());
1112 public Either<Map<String, String>, ActionStatus> getResourceTypesMap() {
1113 return elementOperation.getResourceTypesMap();
1116 private Optional<NameValuePair> findInvalidFilter(String query, ComponentTypeEnum assetType) {
1117 List<NameValuePair> params = URLEncodedUtils.parse(query, StandardCharsets.UTF_8);
1118 List<String> validKeys = FilterKeyEnum.getValidFiltersByAssetType(assetType);
1119 Predicate<NameValuePair> noMatch = p -> !validKeys.contains(p.getName());
1120 return params.stream().filter(noMatch).findAny();
1123 private List<String> getErrorResponseParams(Map<FilterKeyEnum, String> filters, ComponentTypeEnum assetType) {
1124 List<String> params = new ArrayList<>();
1125 if (1 == filters.size()) {
1126 params.add(assetType.getValue().toLowerCase());
1127 params.add(filters.keySet().iterator().next().getName());
1128 params.add(filters.values().iterator().next());
1130 params.add(assetType.getValue());
1131 params.add(filters.get(FilterKeyEnum.SUB_CATEGORY));
1132 params.add(filters.get(FilterKeyEnum.CATEGORY));
1137 public Either<List<Component>, StorageOperationStatus> getFilteredResources(Map<FilterKeyEnum, String> filters, boolean inTransaction) {
1139 String subCategoryName = filters.get(FilterKeyEnum.SUB_CATEGORY);
1140 String categoryName = filters.get(FilterKeyEnum.CATEGORY);
1141 ResourceTypeEnum resourceType = ResourceTypeEnum.getType(filters.get(FilterKeyEnum.RESOURCE_TYPE));
1142 Either<List<ImmutablePair<SubCategoryData, GraphEdge>>, StorageOperationStatus> subcategories = null;
1143 Optional<ImmutablePair<SubCategoryData, GraphEdge>> subCategoryData;
1145 if (categoryName != null) {
1146 subcategories = getAllSubCategories(categoryName);
1147 if (subcategories.isRight()) {
1148 filters.remove(FilterKeyEnum.SUB_CATEGORY);
1149 return Either.right(subcategories.right().value());
1152 if (subCategoryName != null) { // primary filter
1153 if (categoryName != null) {
1154 subCategoryData = validateCategoryHierarcy(subcategories.left().value(), subCategoryName);
1155 if (!subCategoryData.isPresent()) {
1156 return Either.right(StorageOperationStatus.MATCH_NOT_FOUND);
1158 return fetchByCategoryOrSubCategoryUid(subCategoryData.get().getLeft().getUniqueId(), NodeTypeEnum.Resource, inTransaction, resourceType);
1161 return fetchByCategoryOrSubCategoryName(subCategoryName, NodeTypeEnum.ResourceSubcategory, NodeTypeEnum.Resource, inTransaction, resourceType);
1163 if (subcategories != null) {
1164 return fetchByMainCategory(subcategories.left().value(), inTransaction, resourceType);
1166 return fetchComponentMetaDataByResourceType(filters.get(FilterKeyEnum.RESOURCE_TYPE), inTransaction);
1169 private Either<List<ImmutablePair<SubCategoryData, GraphEdge>>, StorageOperationStatus> getAllSubCategories(String categoryName) {
1170 Either<CategoryData, StorageOperationStatus> categoryResult = elementOperation.getNewCategoryData(categoryName, NodeTypeEnum.ResourceNewCategory, CategoryData.class);
1171 if (categoryResult.isRight()) {
1172 return Either.right(categoryResult.right().value());
1174 CategoryData categoryData = categoryResult.left().value();
1176 Either<List<ImmutablePair<SubCategoryData, GraphEdge>>, JanusGraphOperationStatus> childrenNodes = janusGraphGenericDao
1177 .getChildrenNodes(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.ResourceNewCategory), (String) categoryData.getUniqueId(),
1178 GraphEdgeLabels.SUB_CATEGORY, NodeTypeEnum.ResourceSubcategory, SubCategoryData.class);
1179 if (childrenNodes.isRight()) {
1180 return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(childrenNodes.right().value()));
1182 return Either.left(childrenNodes.left().value());
1185 private Optional<ImmutablePair<SubCategoryData, GraphEdge>> validateCategoryHierarcy(List<ImmutablePair<SubCategoryData, GraphEdge>> childNodes, String subCategoryName) {
1186 Predicate<ImmutablePair<SubCategoryData, GraphEdge>> matchName = p -> p.getLeft().getSubCategoryDataDefinition().getName().equals(subCategoryName);
1187 return childNodes.stream().filter(matchName).findAny();
1190 protected <T extends Component> Either<List<T>, StorageOperationStatus> fetchByCategoryOrSubCategoryUid(String categoryUid, NodeTypeEnum categoryType, boolean inTransaction, ResourceTypeEnum resourceType) {
1192 return collectComponents(categoryType, categoryUid, resourceType);
1194 if (!inTransaction) {
1195 janusGraphDao.commit();
1200 protected <T extends Component> Either<List<T>, StorageOperationStatus> fetchByCategoryOrSubCategoryName(String categoryName, NodeTypeEnum categoryType, NodeTypeEnum neededType, boolean inTransaction, ResourceTypeEnum resourceType) {
1201 List<T> components = new ArrayList<>();
1203 Class categoryClazz = categoryType == NodeTypeEnum.ServiceNewCategory ? CategoryData.class : SubCategoryData.class;
1204 Map<String, Object> props = new HashMap<>();
1205 props.put(GraphPropertiesDictionary.NORMALIZED_NAME.getProperty(), ValidationUtils.normalizeCategoryName4Uniqueness(categoryName));
1206 Either<List<GraphNode>, JanusGraphOperationStatus> getCategory = janusGraphGenericDao.getByCriteria(categoryType, props, categoryClazz);
1207 if (getCategory.isRight()) {
1208 return Either.right(StorageOperationStatus.CATEGORY_NOT_FOUND);
1210 for (GraphNode category : getCategory.left().value()) {
1211 Either<List<T>, StorageOperationStatus> result = collectComponents(neededType, category.getUniqueId(), resourceType);
1212 if (result.isRight() && result.right().value() != StorageOperationStatus.NOT_FOUND) {
1214 } else if (result.isLeft()){
1215 components.addAll(result.left().value());
1218 if (components.isEmpty()){
1219 return Either.right(StorageOperationStatus.NOT_FOUND);
1221 return Either.left(components);
1223 if (!inTransaction) {
1224 janusGraphDao.commit();
1230 private <T extends Component> Either<List<T>, StorageOperationStatus> collectComponents(NodeTypeEnum neededType, String categoryUid, ResourceTypeEnum resourceType) {
1231 List<T> components = new ArrayList<>();
1232 Either<GraphVertex, JanusGraphOperationStatus> categoryVertexById = janusGraphDao.getVertexById(categoryUid, JsonParseFlagEnum.NoParse);
1233 if (categoryVertexById.isRight()){
1234 JanusGraphOperationStatus status = categoryVertexById.right().value();
1235 log.debug("#collectComponents Failed to get category vertex with uid {}, status is {}.", categoryUid, status);
1236 return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status));
1238 GraphVertex categoryVertex = categoryVertexById.left().value();
1239 Either<List<GraphVertex>, JanusGraphOperationStatus> componentsVertices = janusGraphDao.getParentVertices(categoryVertex, EdgeLabelEnum.CATEGORY, JsonParseFlagEnum.ParseMetadata);
1240 if (componentsVertices.isRight()){
1241 JanusGraphOperationStatus status = componentsVertices.right().value();
1242 log.debug("#collectComponents Failed to get components vertices of category {}, status is {}.", categoryVertex, status);
1243 return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status));
1245 List<ComponentMetadataDataDefinition> componentsMetadataDataDefinition = componentsVertices.left().value()
1247 .filter(Objects::nonNull)
1248 .filter(componentsVertex -> Objects.nonNull(componentsVertex.getType()))
1249 .map(ModelConverter::convertToComponentMetadataDataDefinition)
1250 .collect(Collectors.toList());
1251 for (ComponentMetadataDataDefinition component : componentsMetadataDataDefinition) {
1252 boolean isHighest = isTrue(component.isHighestVersion());
1253 boolean isMatchingResourceType = isMatchingByResourceType(neededType, resourceType, component);
1254 boolean isDeleted = isTrue(component.isDeleted());
1255 boolean isArchived = isTrue(component.isArchived());
1256 if (isHighest && isMatchingResourceType && !isDeleted && !isArchived) {
1257 Either<T, StorageOperationStatus> result = toscaOperationFacade.getToscaElement(component.getUniqueId(), JsonParseFlagEnum.ParseMetadata);
1258 if (result.isRight()) {
1259 return Either.right(result.right().value());
1261 components.add(result.left().value());
1264 return Either.left(components);
1267 private boolean isMatchingByResourceType(NodeTypeEnum componentType, ResourceTypeEnum resourceType, ComponentMetadataDataDefinition componentData) {
1270 if (componentType == NodeTypeEnum.Resource) {
1271 if (resourceType == null) {
1274 isMatching = resourceType == ((ResourceMetadataDataDefinition) componentData).getResourceType();
1282 private <T extends Component> Either<List<T>, StorageOperationStatus> fetchByMainCategory(List<ImmutablePair<SubCategoryData, GraphEdge>> subcategories, boolean inTransaction, ResourceTypeEnum resourceType) {
1283 List<T> components = new ArrayList<>();
1285 for (ImmutablePair<SubCategoryData, GraphEdge> subCategory : subcategories) {
1286 Either<List<T>, StorageOperationStatus> fetched = fetchByCategoryOrSubCategoryUid(subCategory.getLeft().getUniqueId(), NodeTypeEnum.Resource,
1287 inTransaction, resourceType);
1288 if (fetched.isRight()) {
1291 components.addAll(fetched.left().value());
1293 return Either.left(components);
1296 private Either<List<Component>, StorageOperationStatus> fetchComponentMetaDataByResourceType(String resourceType, boolean inTransaction) {
1297 List<Component> components = null;
1298 StorageOperationStatus status;
1299 Wrapper<StorageOperationStatus> statusWrapper = new Wrapper<>();
1300 Either<List<Component>, StorageOperationStatus> result;
1302 ComponentParametersView fetchUsersAndCategoriesFilter = new ComponentParametersView(Arrays.asList(ComponentFieldsEnum.USERS.getValue(), ComponentFieldsEnum.CATEGORIES.getValue()));
1303 Either<List<Component>, StorageOperationStatus> getResources = toscaOperationFacade.fetchMetaDataByResourceType(resourceType, fetchUsersAndCategoriesFilter);
1304 if (getResources.isRight()) {
1305 status = getResources.right().value();
1306 if (status != StorageOperationStatus.NOT_FOUND) {
1307 statusWrapper.setInnerElement(getResources.right().value());
1309 components = new ArrayList<>();
1312 components = getResources.left().value();
1314 if (!statusWrapper.isEmpty()) {
1315 result = Either.right(statusWrapper.getInnerElement());
1317 result = Either.left(components);
1321 if (!inTransaction) {
1322 janusGraphDao.commit();
1328 public CatalogUpdateTimestamp getCatalogUpdateTime(String userId) {
1331 return toscaOperationFacade.getCatalogTimes();
1334 janusGraphDao.commit();