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 fj.data.Either;
25 import java.util.ArrayList;
26 import java.util.HashMap;
27 import java.util.HashSet;
28 import java.util.List;
31 import java.util.stream.Collectors;
32 import org.apache.commons.lang3.StringUtils;
33 import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
34 import org.openecomp.sdc.be.components.impl.exceptions.ComponentException;
35 import org.openecomp.sdc.be.components.validation.component.ComponentContactIdValidator;
36 import org.openecomp.sdc.be.components.validation.component.ComponentDescriptionValidator;
37 import org.openecomp.sdc.be.components.validation.component.ComponentIconValidator;
38 import org.openecomp.sdc.be.components.validation.component.ComponentNameValidator;
39 import org.openecomp.sdc.be.components.validation.component.ComponentProjectCodeValidator;
40 import org.openecomp.sdc.be.components.validation.component.ComponentTagsValidator;
41 import org.openecomp.sdc.be.components.validation.component.ComponentValidator;
42 import org.openecomp.sdc.be.dao.api.ActionStatus;
43 import org.openecomp.sdc.be.datamodel.api.CategoryTypeEnum;
44 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
45 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
46 import org.openecomp.sdc.be.model.ComponentInstance;
47 import org.openecomp.sdc.be.model.LifecycleStateEnum;
48 import org.openecomp.sdc.be.model.Product;
49 import org.openecomp.sdc.be.model.User;
50 import org.openecomp.sdc.be.model.category.CategoryDefinition;
51 import org.openecomp.sdc.be.model.category.GroupingDefinition;
52 import org.openecomp.sdc.be.model.category.SubCategoryDefinition;
53 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ArtifactsOperations;
54 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.InterfaceOperation;
55 import org.openecomp.sdc.be.model.operations.api.IElementOperation;
56 import org.openecomp.sdc.be.model.operations.api.IGroupInstanceOperation;
57 import org.openecomp.sdc.be.model.operations.api.IGroupOperation;
58 import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation;
59 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
60 import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation;
61 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
62 import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils;
63 import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
64 import org.openecomp.sdc.be.ui.model.UiComponentDataTransfer;
65 import org.openecomp.sdc.be.user.Role;
66 import org.openecomp.sdc.common.log.wrappers.Logger;
67 import org.openecomp.sdc.common.util.ValidationUtils;
68 import org.openecomp.sdc.exception.ResponseFormat;
69 import org.springframework.beans.factory.annotation.Autowired;
71 @org.springframework.stereotype.Component("productBusinessLogic")
72 public class ProductBusinessLogic extends ComponentBusinessLogic {
74 private static final String PRODUCT_FULL_NAME = "full";
75 private static final String PRODUCT_ABBREVIATED_NAME = "abbreviated";
76 private static final Logger log = Logger.getLogger(ProductBusinessLogic.class);
77 private static final String INITIAL_VERSION = "0.1";
78 private static final String CREATE_PRODUCT = "Create Product";
79 private static List<Role> creationRoles;
80 private static List<Role> updateRoles;
81 private static List<Role> contactsRoles;
82 private final ComponentInstanceBusinessLogic componentInstanceBusinessLogic;
85 public ProductBusinessLogic(IElementOperation elementDao, IGroupOperation groupOperation, IGroupInstanceOperation groupInstanceOperation,
86 IGroupTypeOperation groupTypeOperation, GroupBusinessLogic groupBusinessLogic, InterfaceOperation interfaceOperation,
87 InterfaceLifecycleOperation interfaceLifecycleTypeOperation, ArtifactsBusinessLogic artifactsBusinessLogic,
88 ComponentInstanceBusinessLogic componentInstanceBusinessLogic, ArtifactsOperations artifactToscaOperation,
89 ComponentContactIdValidator componentContactIdValidator, ComponentNameValidator componentNameValidator,
90 ComponentTagsValidator componentTagsValidator, ComponentValidator componentValidator,
91 ComponentIconValidator componentIconValidator, ComponentProjectCodeValidator componentProjectCodeValidator,
92 ComponentDescriptionValidator componentDescriptionValidator) {
93 super(elementDao, groupOperation, groupInstanceOperation, groupTypeOperation, groupBusinessLogic, interfaceOperation,
94 interfaceLifecycleTypeOperation, artifactsBusinessLogic, artifactToscaOperation, componentContactIdValidator, componentNameValidator,
95 componentTagsValidator, componentValidator, componentIconValidator, componentProjectCodeValidator, componentDescriptionValidator);
96 this.componentInstanceBusinessLogic = componentInstanceBusinessLogic;
97 creationRoles = new ArrayList<>();
98 updateRoles = new ArrayList<>();
99 contactsRoles = new ArrayList<>();
100 // only PM is allowed to create/update products
101 creationRoles.add(Role.PRODUCT_MANAGER);
102 updateRoles.add(Role.PRODUCT_MANAGER);
103 // Only PM is allowed to be product contacts
104 contactsRoles.add(Role.PRODUCT_MANAGER);
107 public Either<Product, ResponseFormat> createProduct(Product product, User user) {
108 AuditingActionEnum actionEnum = AuditingActionEnum.CREATE_RESOURCE;
109 ComponentTypeEnum typeEnum = ComponentTypeEnum.PRODUCT;
110 // validate user - should be first to get the maximum auditing info in
112 // case of subsequent failures
113 log.debug("get user from DB");
114 user = validateUser(user, CREATE_PRODUCT, product, actionEnum, false);
115 // validate user role
116 validateUserRole(user, product, creationRoles, actionEnum, null);
117 if (product == null) {
118 log.debug("Invalid product json. Check product servlet log for createProduct entry params");
119 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
120 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, typeEnum);
121 return Either.right(responseFormat);
123 // warn about non-updatable fields
124 checkUnupdatableProductFields(product);
125 Either<Product, ResponseFormat> validateProductResponse = validateProductBeforeCreate(product, user, actionEnum);
126 if (validateProductResponse.isRight()) {
127 return Either.right(validateProductResponse.right().value());
129 log.debug("send product {} to dao for create", product.getComponentMetadataDefinition().getMetadataDataDefinition().getName());
130 Either<Boolean, ResponseFormat> lockResult = lockComponentByName(product.getSystemName(), product, CREATE_PRODUCT);
131 if (lockResult.isRight()) {
132 ResponseFormat responseFormat = lockResult.right().value();
133 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
134 return Either.right(responseFormat);
136 log.debug("Product name locked is {}, status = {}", product.getSystemName(), lockResult);
138 Either<Product, StorageOperationStatus> createProductEither = toscaOperationFacade.createToscaComponent(product);
139 if (createProductEither.isRight()) {
140 ResponseFormat responseFormat = componentsUtils
141 .getResponseFormatByComponent(componentsUtils.convertFromStorageResponse(createProductEither.right().value()), product, typeEnum);
142 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, typeEnum);
143 return Either.right(responseFormat);
145 log.debug("Product created successfully");
146 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.CREATED);
147 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, typeEnum);
148 Product createdProduct = createProductEither.left().value();
149 return Either.left(createdProduct);
151 graphLockOperation.unlockComponentByName(product.getSystemName(), product.getUniqueId(), NodeTypeEnum.Product);
155 private void checkUnupdatableProductFields(Product product) {
156 checkComponentFieldsForOverrideAttempt(product);
157 if (product.getNormalizedName() != null) {
158 log.info("NormalizedName cannot be defined by user. This field will be overridden by the application");
162 private Either<Product, ResponseFormat> validateProductBeforeCreate(Product product, User user, AuditingActionEnum actionEnum) {
163 Either<Boolean, ResponseFormat> validateProductFields = validateProductFieldsBeforeCreate(user, product, actionEnum);
164 if (validateProductFields.isRight()) {
165 return Either.right(validateProductFields.right().value());
167 if (product.getIsActive() == null) {
168 log.debug("no isActive value was provided, setting to default: false");
169 product.setIsActive(false);
171 product.setCreatorUserId(user.getUserId());
173 log.debug("enrich product with version and state");
174 product.setState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT);
175 product.setVersion(INITIAL_VERSION);
176 // Generate invariant UUID - must be here and not in operation since it
178 // should stay constant during clone
179 String invariantUUID = UniqueIdBuilder.buildInvariantUUID();
180 product.setInvariantUUID(invariantUUID);
181 return Either.left(product);
184 private Either<Boolean, ResponseFormat> validateProductFieldsBeforeCreate(User user, Product product, AuditingActionEnum actionEnum) {
185 // To be removed in 1607
188 String oldName = product.getName();
189 Either<Boolean, ResponseFormat> componentNameValidation = validateProductNameAndCleanup(user, product, actionEnum);
190 if (componentNameValidation.isRight()) {
191 return componentNameValidation;
194 componentNameValidator.validateComponentNameUnique(user, product, actionEnum);
195 } catch (ComponentException exp) {
196 return Either.right(exp.getResponseFormat());
198 // To be removed in 1607 and replaced with generic
200 // validateTagsListAndRemoveDuplicates()
202 // See comments on the validateTagsListAndRemoveDuplicates(user,
204 // product, oldName, actionEnum) function
205 Either<Boolean, ResponseFormat> tagsValidation = validateTagsListAndRemoveDuplicates(user, product, oldName, actionEnum);
206 if (tagsValidation.isRight()) {
207 return tagsValidation;
209 componentTagsValidator.validateAndCorrectField(user, product, actionEnum);
211 componentProjectCodeValidator.validateAndCorrectField(user, product, actionEnum);
212 } catch (ComponentException exp) {
213 return Either.right(exp.getResponseFormat());
215 Either<Boolean, ResponseFormat> categoryValidation = validateGrouping(user, product, actionEnum);
216 if (categoryValidation.isRight()) {
217 return categoryValidation;
219 Either<Boolean, ResponseFormat> contactsListValidation = validateAndUpdateProductContactsList(user, product, actionEnum);
220 if (contactsListValidation.isRight()) {
221 return contactsListValidation;
223 Either<Boolean, ResponseFormat> productFullNameValidation = validateProductFullNameAndCleanup(user, product, actionEnum);
224 if (productFullNameValidation.isRight()) {
225 return productFullNameValidation;
227 componentDescriptionValidator.validateAndCorrectField(user, product, actionEnum);
228 return Either.left(true);
231 public Either<Map<String, Boolean>, ResponseFormat> validateProductNameExists(String productName, String userId) {
232 validateUserExists(userId);
233 Either<Boolean, StorageOperationStatus> dataModelResponse = toscaOperationFacade
234 .validateComponentNameUniqueness(productName, null, ComponentTypeEnum.PRODUCT);
236 janusGraphDao.commit();
237 if (dataModelResponse.isLeft()) {
238 Map<String, Boolean> result = new HashMap<>();
239 result.put("isValid", dataModelResponse.left().value());
240 log.debug("validation was successfully performed.");
241 return Either.left(result);
243 ResponseFormat responseFormat = componentsUtils
244 .getResponseFormat(componentsUtils.convertFromStorageResponse(dataModelResponse.right().value()));
245 return Either.right(responseFormat);
248 private Either<Boolean, ResponseFormat> validateAndUpdateProductContactsList(User user, Product product, AuditingActionEnum actionEnum) {
249 List<String> contacts = product.getContacts();
250 if (!ValidationUtils.validateListNotEmpty(contacts)) {
251 log.debug("Contacts list cannot be empty for product {}", product.getName());
252 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.EMPTY_PRODUCT_CONTACTS_LIST);
253 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
254 return Either.right(responseFormat);
256 boolean isProductCreatorInContacts = false;
257 String modifierUserId = user.getUserId();
258 for (String contact : contacts) {
259 if (contact.equals(modifierUserId)) {
260 log.trace("modifier userId found in product contacts");
261 isProductCreatorInContacts = true;
262 // No need to validate for this userId - it's modifier's
265 if (!ValidationUtils.validateContactId(contact)) {
266 log.debug("Product contacts has invalid userId {} for product {}", contact, product.getName());
267 ResponseFormat responseFormat = componentsUtils
268 .getResponseFormat(ActionStatus.COMPONENT_INVALID_CONTACT, ComponentTypeEnum.PRODUCT.getValue());
269 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
270 return Either.right(responseFormat);
274 contactUser = validateUserExists(contact);
275 validateUserRole(contactUser, contactsRoles);
276 } catch (ByActionStatusComponentException e) {
277 log.debug("Cannot set contact with userId {} as product contact, error: {}", contact, e.getActionStatus());
278 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_PRODUCT_CONTACT, contact);
279 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
280 throw new ByActionStatusComponentException(e.getActionStatus(), e.getParams());
283 if (!isProductCreatorInContacts) {
284 log.debug("modifier userId {} not found in product contacts - adding it", modifierUserId);
285 contacts.add(modifierUserId);
287 // passed - setting all contacts userIds to lowercase
288 List<String> tempContacts = contacts.stream().map(String::toLowerCase).collect(Collectors.toList());
289 ValidationUtils.removeDuplicateFromList(tempContacts);
290 product.setContacts(tempContacts);
291 return Either.left(true);
294 private Either<Boolean, ResponseFormat> validateGrouping(User user, Product product, AuditingActionEnum actionEnum) {
295 List<CategoryDefinition> categories = product.getCategories();
296 if (categories == null || categories.isEmpty()) {
297 log.debug("Grouping list is empty for product: {}", product.getName());
298 return Either.left(true);
300 Map<String, Map<String, Set<String>>> nonDuplicatedCategories = new HashMap<>();
301 // remove duplicated entries
302 for (CategoryDefinition cat : categories) {
303 String catName = cat.getName();
304 if (StringUtils.isEmpty(catName)) {
305 // error missing cat name
306 log.debug("Missing category name for product: {}", product.getName());
307 ResponseFormat responseFormat = componentsUtils
308 .getResponseFormat(ActionStatus.COMPONENT_MISSING_CATEGORY, ComponentTypeEnum.PRODUCT.getValue());
309 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
310 return Either.right(responseFormat);
312 Map<String, Set<String>> catEntry = nonDuplicatedCategories.get(catName);
313 if (catEntry == null) {
314 catEntry = new HashMap<>();
315 nonDuplicatedCategories.put(catName, catEntry);
317 List<SubCategoryDefinition> subcategories = cat.getSubcategories();
318 if (subcategories == null || subcategories.isEmpty()) {
319 // error missing subcat for cat
320 log.debug("Missing sub-categories for category {} in product {}", catName, product.getName());
321 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_SUBCATEGORY);
322 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
323 return Either.right(responseFormat);
325 for (SubCategoryDefinition subcat : subcategories) {
326 String subCatName = subcat.getName();
327 if (StringUtils.isEmpty(subCatName)) {
328 // error missing sub cat name for cat
329 log.debug("Missing or empty sub-category for category {} in product {}", catName, product.getName());
330 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_SUBCATEGORY);
331 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
332 return Either.right(responseFormat);
334 Set<String> subcatEntry = catEntry.get(subCatName);
335 if (subcatEntry == null) {
336 subcatEntry = new HashSet<>();
337 catEntry.put(subCatName, subcatEntry);
339 List<GroupingDefinition> groupings = subcat.getGroupings();
340 for (GroupingDefinition group : groupings) {
341 String groupName = group.getName();
342 if (StringUtils.isEmpty(groupName)) {
343 // error missing grouping for sub cat name and cat
344 log.debug("Missing or empty groupng name for sub-category: {} for categor: {} in product: {}", subCatName, catName,
346 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_SUBCATEGORY);
347 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
348 return Either.right(responseFormat);
350 if (!subcatEntry.contains(groupName)) {
351 subcatEntry.add(groupName);
353 log.debug("Grouping: {}, already exist for category: {} and subcategory: {}", groupName, catName, subCatName);
357 } // for end of checking duplicated
359 // validate existence
360 Either<List<CategoryDefinition>, ActionStatus> allProductCategories = elementDao.getAllProductCategories();
361 if (allProductCategories.isRight()) {
362 log.debug("No product categories {}", allProductCategories.right().value());
363 ResponseFormat responseFormat = componentsUtils.getResponseFormat(allProductCategories.right().value());
364 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
365 return Either.right(responseFormat);
368 // convert non-duplicated to data modeling format and update in the
371 List<CategoryDefinition> newCatList = new ArrayList<>();
372 // over all categories from request
373 for (Map.Entry<String, Map<String, Set<String>>> entry : nonDuplicatedCategories.entrySet()) {
375 CategoryDefinition categoryDefinition = null;
376 // over all categories from JanusGraph
377 List<CategoryDefinition> categoriesList = allProductCategories.left().value();
378 if (categoriesList != null) {
379 for (CategoryDefinition catInDb : categoriesList) {
380 if (entry.getKey().equals(catInDb.getName())) {
384 categoryDefinition = new CategoryDefinition(catInDb);
385 SubCategoryDefinition subCategory = null;
386 Map<String, Set<String>> subcats = entry.getValue();
387 for (Map.Entry<String, Set<String>> subcat : subcats.entrySet()) {
389 List<SubCategoryDefinition> subcategoriesList = catInDb.getSubcategories();
390 if (subcategoriesList != null) {
391 for (SubCategoryDefinition subcatInDb : subcategoriesList) {
392 if (subcatInDb.getName().equals(subcat.getKey())) {
394 subCategory = new SubCategoryDefinition(subcatInDb);
396 Set<String> grouping = subcat.getValue();
398 GroupingDefinition groupingDefinition = null;
399 for (String group : grouping) {
401 List<GroupingDefinition> groupings = subcatInDb.getGroupings();
402 if (groupings != null) {
403 for (GroupingDefinition groupInDb : groupings) {
404 if (groupInDb.getName().equals(group)) {
406 groupingDefinition = new GroupingDefinition(groupInDb);
411 // error grouping isn't defined
414 ResponseFormat responseFormat = componentsUtils
415 .getResponseFormat(ActionStatus.INVALID_GROUP_ASSOCIATION, CategoryTypeEnum.GROUPING.getValue(),
418 .auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
419 return Either.right(responseFormat);
421 subCategory.addGrouping(groupingDefinition);
427 // error sub category isn't defined in JanusGraph
428 ResponseFormat responseFormat = componentsUtils
429 .getResponseFormat(ActionStatus.INVALID_GROUP_ASSOCIATION, CategoryTypeEnum.SUBCATEGORY.getValue(),
431 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
432 return Either.right(responseFormat);
434 categoryDefinition.addSubCategory(subCategory);
440 // error category isn't defined in JanusGraph
441 ResponseFormat responseFormat = componentsUtils
442 .getResponseFormat(ActionStatus.INVALID_GROUP_ASSOCIATION, CategoryTypeEnum.CATEGORY.getValue(), entry.getKey());
443 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
444 return Either.right(responseFormat);
446 newCatList.add(categoryDefinition);
448 product.setCategories(newCatList);
449 return Either.left(true);
452 public Either<Product, ResponseFormat> getProduct(String productId, User user) {
453 String ecompErrorContext = "Get product";
454 validateUserNotEmpty(user, ecompErrorContext);
455 validateUserExists(user);
456 Either<Product, StorageOperationStatus> storageStatus = toscaOperationFacade.getToscaElement(productId);
457 if (storageStatus.isRight()) {
458 log.debug("failed to get resource by id {}", productId);
459 if (storageStatus.right().value() == StorageOperationStatus.NOT_FOUND) {
461 return Either.right(componentsUtils.getResponseFormat(ActionStatus.PRODUCT_NOT_FOUND, ComponentTypeEnum.PRODUCT.getValue()));
464 componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(storageStatus.right().value()), ""));
467 return Either.left(storageStatus.left().value());
470 public Either<Product, ResponseFormat> deleteProduct(String productId, User user) {
471 String ecompErrorContext = "Delete product";
472 validateUserNotEmpty(user, ecompErrorContext);
473 validateUserExists(user);
474 Either<Product, StorageOperationStatus> storageStatus = toscaOperationFacade.deleteToscaComponent(productId);
475 if (storageStatus.isRight()) {
476 log.debug("failed to delete resource by id {}", productId);
478 .right(componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(storageStatus.right().value()), ""));
480 return Either.left(storageStatus.left().value());
483 private Either<Boolean, ResponseFormat> validateProductFullNameAndCleanup(User user, Product product, AuditingActionEnum actionEnum) {
484 String fullName = product.getFullName();
485 if (StringUtils.isEmpty(fullName)) {
486 ResponseFormat errorResponse = componentsUtils
487 .getResponseFormat(ActionStatus.MISSING_ONE_OF_COMPONENT_NAMES, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_FULL_NAME);
488 componentsUtils.auditComponentAdmin(errorResponse, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
489 return Either.right(errorResponse);
491 fullName = ValidationUtils.removeNoneUtf8Chars(fullName);
492 fullName = ValidationUtils.removeHtmlTags(fullName);
493 fullName = ValidationUtils.normaliseWhitespace(fullName);
494 fullName = ValidationUtils.stripOctets(fullName);
495 if (!ValidationUtils.validateProductFullNameLength(fullName)) {
496 ResponseFormat responseFormat = componentsUtils
497 .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_FULL_NAME);
498 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
499 return Either.right(responseFormat);
501 if (!ValidationUtils.validateIsEnglish(fullName)) {
502 ResponseFormat responseFormat = componentsUtils
503 .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_FULL_NAME);
504 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
505 return Either.right(responseFormat);
507 product.setFullName(fullName);
508 return Either.left(true);
511 private Either<Boolean, ResponseFormat> validateProductNameAndCleanup(User user, Product product, AuditingActionEnum actionEnum) {
512 String name = product.getName();
513 if (StringUtils.isEmpty(name)) {
514 ResponseFormat responseFormat = componentsUtils
515 .getResponseFormat(ActionStatus.MISSING_ONE_OF_COMPONENT_NAMES, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_ABBREVIATED_NAME);
516 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
517 return Either.right(responseFormat);
519 // Product name is required to have same validation and normalization as
522 if (!ValidationUtils.validateCategoryDisplayNameFormat(name)) {
523 ResponseFormat responseFormat = componentsUtils
524 .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, ComponentTypeEnum.PRODUCT.getValue(),
525 PRODUCT_ABBREVIATED_NAME);
526 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
527 return Either.right(responseFormat);
529 String normalizedName4Display = ValidationUtils.normalizeCategoryName4Display(name);
530 if (!ValidationUtils.validateCategoryDisplayNameLength(normalizedName4Display)) {
531 ResponseFormat responseFormat = componentsUtils
532 .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, ComponentTypeEnum.PRODUCT.getValue(),
533 PRODUCT_ABBREVIATED_NAME);
534 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
535 return Either.right(responseFormat);
537 product.setName(normalizedName4Display);
538 String normalizedName4Uniqueness = ValidationUtils.normaliseComponentName(normalizedName4Display);
539 product.setNormalizedName(normalizedName4Uniqueness);
540 return Either.left(true);
542 // This is a workaround for a current tag--->product name behaviour, which
544 // will be changed in 1607.
546 // It was agreed with Ella on 23/2/16 that the tag validation of product
548 // will be made against the old product name (before normalization),
550 // and in 1607 US will be defined where UI will no longer pass tag of
552 // component name, and BE will add it by itself after all needed
555 private Either<Boolean, ResponseFormat> validateTagsListAndRemoveDuplicates(User user, Product product, String oldProductName,
556 AuditingActionEnum actionEnum) {
557 componentTagsValidator.validateAndCorrectField(user, product, actionEnum);
558 return Either.left(true);
562 public void setDeploymentArtifactsPlaceHolder(org.openecomp.sdc.be.model.Component component, User user) {
565 public Either<Product, ResponseFormat> updateProductMetadata(String productId, Product updatedProduct, User user) {
566 ComponentTypeEnum typeEnum = ComponentTypeEnum.PRODUCT;
567 user = validateUser(user, "Update Product", updatedProduct, null, false);
568 // validate user role
569 validateUserRole(user, updatedProduct, updateRoles, null, null);
570 if (updatedProduct == null) {
571 log.debug("Invalid product json. Check product servlet log for updateProduct entry params");
572 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
573 return Either.right(responseFormat);
575 Either<Product, StorageOperationStatus> storageStatus = toscaOperationFacade.getToscaElement(productId);
576 if (storageStatus.isRight()) {
577 if (storageStatus.right().value() == StorageOperationStatus.NOT_FOUND) {
579 .right(componentsUtils.getResponseFormat(ActionStatus.PRODUCT_NOT_FOUND, ComponentTypeEnum.PRODUCT.name().toLowerCase()));
582 .right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(storageStatus.right().value(), typeEnum), ""));
584 Product currentProduct = storageStatus.left().value();
585 if (!ComponentValidationUtils.canWorkOnComponent(productId, toscaOperationFacade, user.getUserId())) {
586 log.info("Restricted operation for user: {}, on product: {}", user.getUserId(), currentProduct.getCreatorUserId());
587 return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
589 Either<Product, ResponseFormat> validationRsponse = validateAndUpdateProductMetadata(user, currentProduct, updatedProduct);
590 if (validationRsponse.isRight()) {
591 log.info("product update metadata: validations field.");
592 return validationRsponse;
594 Product productToUpdate = validationRsponse.left().value();
596 lockComponent(currentProduct.getUniqueId(), currentProduct, "Update Product Metadata");
598 Either<Product, StorageOperationStatus> updateResponse = toscaOperationFacade.updateToscaElement(productToUpdate);
599 if (updateResponse.isRight()) {
600 toscaOperationFacade.rollback();
601 log.debug("failed to update product {}", productToUpdate.getUniqueId());
602 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
604 toscaOperationFacade.commit();
605 return Either.left(updateResponse.left().value());
607 graphLockOperation.unlockComponent(productId, NodeTypeEnum.Product);
611 private Either<Product, ResponseFormat> validateAndUpdateProductMetadata(User user, Product currentProduct, Product updatedProduct) {
612 boolean hasBeenCertified = ValidationUtils.hasBeenCertified(currentProduct.getVersion());
613 Either<Boolean, ResponseFormat> response = validateAndUpdateProductName(user, currentProduct, updatedProduct);
614 if (response.isRight()) {
615 ResponseFormat errorResponse = response.right().value();
616 return Either.right(errorResponse);
618 response = validateAndUpdateFullName(user, currentProduct, updatedProduct);
619 if (response.isRight()) {
620 ResponseFormat errorResponse = response.right().value();
621 return Either.right(errorResponse);
623 response = validateAndUpdateDescription(user, currentProduct, updatedProduct, null);
624 if (response.isRight()) {
625 ResponseFormat errorResponse = response.right().value();
626 return Either.right(errorResponse);
628 response = validateAndUpdateCategory(user, currentProduct, updatedProduct);
629 if (response.isRight()) {
630 ResponseFormat errorResponse = response.right().value();
631 return Either.right(errorResponse);
633 response = validateAndUpdateContactList(user, currentProduct, updatedProduct);
634 if (response.isRight()) {
635 ResponseFormat errorResponse = response.right().value();
636 return Either.right(errorResponse);
638 response = validateAndUpdateTags(user, currentProduct, updatedProduct);
639 if (response.isRight()) {
640 ResponseFormat errorResponse = response.right().value();
641 return Either.right(errorResponse);
643 response = validateAndUpdateProjectCode(user, currentProduct, updatedProduct);
644 if (response.isRight()) {
645 ResponseFormat errorResponse = response.right().value();
646 return Either.right(errorResponse);
648 if (updatedProduct.getIsActive() != null) {
649 currentProduct.setIsActive(updatedProduct.getIsActive());
651 response = validateAndUpdateIcon(user, currentProduct, updatedProduct, hasBeenCertified);
652 if (response.isRight()) {
653 ResponseFormat errorResponse = response.right().value();
654 return Either.right(errorResponse);
656 String currentInvariantUuid = currentProduct.getInvariantUUID();
657 String updatedInvariantUuid = updatedProduct.getInvariantUUID();
658 if ((updatedInvariantUuid != null) && (!updatedInvariantUuid.equals(currentInvariantUuid))) {
659 log.warn("Product invariant UUID is automatically set and cannot be updated");
660 updatedProduct.setInvariantUUID(currentInvariantUuid);
662 return Either.left(currentProduct);
665 private Either<Boolean, ResponseFormat> validateAndUpdateProductName(User user, Product currentProduct, Product updatedProduct) {
666 String updatedProductName = updatedProduct.getName();
668 String currentProductName = currentProduct.getName();
669 if (updatedProductName != null) {
670 Either<Boolean, ResponseFormat> validatProductNameResponse = validateProductNameAndCleanup(user, updatedProduct, null);
671 if (validatProductNameResponse.isRight()) {
672 ResponseFormat errorRespons = validatProductNameResponse.right().value();
673 return Either.right(errorRespons);
675 updatedProductName = updatedProduct.getName();
676 if (!currentProductName.equals(updatedProductName)) {
678 componentNameValidator.validateComponentNameUnique(user, updatedProduct, null);
679 } catch (ComponentException exp) {
680 return Either.right(exp.getResponseFormat());
682 currentProduct.setName(updatedProductName);
683 tags = updatedProductName;
684 updatedProductName = ValidationUtils.normalizeCategoryName4Display(updatedProductName);
685 currentProduct.getComponentMetadataDefinition().getMetadataDataDefinition()
686 .setNormalizedName(ValidationUtils.normaliseComponentName(updatedProductName));
687 List<String> updatedTags = updatedProduct.getTags();
688 // As discussed with Ella currently (1604) we are not removing
690 // the old name from tags.
691 if (updatedTags == null) {
692 updatedTags = currentProduct.getTags();
694 updatedTags.add(tags);
697 return Either.left(true);
700 private Either<Boolean, ResponseFormat> validateAndUpdateFullName(User user, Product currentProduct, Product updatedProduct) {
701 String updatedProductName = updatedProduct.getFullName();
702 String currentProductName = currentProduct.getFullName();
703 if (updatedProductName != null && !currentProductName.equals(updatedProductName)) {
704 Either<Boolean, ResponseFormat> validatProductNameResponse = validateProductFullNameAndCleanup(user, updatedProduct, null);
705 if (validatProductNameResponse.isRight()) {
706 ResponseFormat errorRespons = validatProductNameResponse.right().value();
707 return Either.right(errorRespons);
709 currentProduct.setFullName(updatedProduct.getFullName());
711 return Either.left(true);
714 private Either<Boolean, ResponseFormat> validateAndUpdateCategory(User user, Product currentProduct, Product updatedProduct) {
715 Either<Boolean, ResponseFormat> validateCategoryResponse = validateGrouping(user, updatedProduct, null);
716 if (validateCategoryResponse.isRight()) {
717 ResponseFormat errorResponse = validateCategoryResponse.right().value();
718 return Either.right(errorResponse);
720 List<CategoryDefinition> categoryUpdated = updatedProduct.getCategories();
721 if (categoryUpdated != null) {
722 currentProduct.setCategories(categoryUpdated);
724 return Either.left(true);
727 private Either<Boolean, ResponseFormat> validateAndUpdateContactList(User user, Product currentProduct, Product updatedProduct) {
728 List<String> updatedContacts = updatedProduct.getContacts();
729 List<String> currentContacts = currentProduct.getContacts();
730 if (updatedContacts != null) {
731 if (!(currentContacts.containsAll(updatedContacts) && updatedContacts.containsAll(currentContacts))) {
732 Either<Boolean, ResponseFormat> validatResponse = validateAndUpdateProductContactsList(user, updatedProduct, null);
733 if (validatResponse.isRight()) {
734 ResponseFormat errorRespons = validatResponse.right().value();
735 return Either.right(errorRespons);
737 currentProduct.setContacts(updatedProduct.getContacts());
740 return Either.left(true);
743 private Either<Boolean, ResponseFormat> validateAndUpdateTags(User user, Product currentProduct, Product updatedProduct) {
744 List<String> tagsUpdated = updatedProduct.getTags();
745 List<String> tagsCurrent = currentProduct.getTags();
746 if (tagsUpdated != null) {
747 if (!(tagsCurrent.containsAll(tagsUpdated) && tagsUpdated.containsAll(tagsCurrent))) {
748 Either<Boolean, ResponseFormat> validatResponse = validateTagsListAndRemoveDuplicates(user, updatedProduct, currentProduct.getName(),
750 if (validatResponse.isRight()) {
751 ResponseFormat errorRespons = validatResponse.right().value();
752 return Either.right(errorRespons);
754 currentProduct.setTags(updatedProduct.getTags());
757 return Either.left(true);
761 public Either<List<String>, ResponseFormat> deleteMarkedComponents() {
762 // markAsDeleted isnt implemented yet
763 return Either.left(new ArrayList<>());
766 public Either<Product, ResponseFormat> getProductByNameAndVersion(String productName, String productVersion, String userId) {
767 validateUserExists(userId);
768 Either<Product, StorageOperationStatus> storageStatus = toscaOperationFacade
769 .getComponentByNameAndVersion(ComponentTypeEnum.PRODUCT, productName, productVersion);
770 if (storageStatus.isRight()) {
771 log.debug("failed to get service by name {} and version {}", productName, productVersion);
772 return Either.right(componentsUtils
773 .getResponseFormat(componentsUtils.convertFromStorageResponse(storageStatus.right().value(), ComponentTypeEnum.PRODUCT),
776 Product product = storageStatus.left().value();
777 return Either.left(product);
781 public ComponentInstanceBusinessLogic getComponentInstanceBL() {
782 return componentInstanceBusinessLogic;
786 public Either<List<ComponentInstance>, ResponseFormat> getComponentInstancesFilteredByPropertiesAndInputs(String componentId, String userId) {
791 public Either<UiComponentDataTransfer, ResponseFormat> getUiComponentDataTransferByComponentId(String componentId,
792 List<String> dataParamsToReturn) {
793 // TODO Auto-generated method stub