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.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
27 import org.openecomp.sdc.be.components.impl.exceptions.ComponentException;
28 import org.openecomp.sdc.be.components.validation.component.ComponentContactIdValidator;
29 import org.openecomp.sdc.be.components.validation.component.ComponentDescriptionValidator;
30 import org.openecomp.sdc.be.components.validation.component.ComponentIconValidator;
31 import org.openecomp.sdc.be.components.validation.component.ComponentNameValidator;
32 import org.openecomp.sdc.be.components.validation.component.ComponentProjectCodeValidator;
33 import org.openecomp.sdc.be.components.validation.component.ComponentTagsValidator;
34 import org.openecomp.sdc.be.components.validation.component.ComponentValidator;
35 import org.openecomp.sdc.be.dao.api.ActionStatus;
36 import org.openecomp.sdc.be.datamodel.api.CategoryTypeEnum;
37 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
38 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
39 import org.openecomp.sdc.be.model.ComponentInstance;
40 import org.openecomp.sdc.be.model.LifecycleStateEnum;
41 import org.openecomp.sdc.be.model.Product;
42 import org.openecomp.sdc.be.model.User;
43 import org.openecomp.sdc.be.model.category.CategoryDefinition;
44 import org.openecomp.sdc.be.model.category.GroupingDefinition;
45 import org.openecomp.sdc.be.model.category.SubCategoryDefinition;
46 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ArtifactsOperations;
47 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.InterfaceOperation;
48 import org.openecomp.sdc.be.model.operations.api.IElementOperation;
49 import org.openecomp.sdc.be.model.operations.api.IGroupInstanceOperation;
50 import org.openecomp.sdc.be.model.operations.api.IGroupOperation;
51 import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation;
52 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
53 import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation;
54 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
55 import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils;
56 import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
57 import org.openecomp.sdc.be.ui.model.UiComponentDataTransfer;
58 import org.openecomp.sdc.be.user.Role;
59 import org.openecomp.sdc.common.log.wrappers.Logger;
60 import org.openecomp.sdc.common.util.ValidationUtils;
61 import org.openecomp.sdc.exception.ResponseFormat;
62 import org.springframework.beans.factory.annotation.Autowired;
64 import java.util.ArrayList;
65 import java.util.HashMap;
66 import java.util.HashSet;
67 import java.util.List;
70 import java.util.stream.Collectors;
72 @org.springframework.stereotype.Component("productBusinessLogic")
73 public class ProductBusinessLogic extends ComponentBusinessLogic {
75 private static final String PRODUCT_FULL_NAME = "full";
76 private static final String PRODUCT_ABBREVIATED_NAME = "abbreviated";
77 private static final Logger log = Logger.getLogger(ProductBusinessLogic.class);
78 private static final String INITIAL_VERSION = "0.1";
79 private static final String CREATE_PRODUCT = "Create Product";
80 private static List<Role> creationRoles;
81 private static List<Role> updateRoles;
82 private static List<Role> contactsRoles;
84 private final ComponentInstanceBusinessLogic componentInstanceBusinessLogic;
87 public ProductBusinessLogic(IElementOperation elementDao,
88 IGroupOperation groupOperation,
89 IGroupInstanceOperation groupInstanceOperation,
90 IGroupTypeOperation groupTypeOperation,
91 GroupBusinessLogic groupBusinessLogic,
92 InterfaceOperation interfaceOperation,
93 InterfaceLifecycleOperation interfaceLifecycleTypeOperation,
94 ArtifactsBusinessLogic artifactsBusinessLogic,
95 ComponentInstanceBusinessLogic componentInstanceBusinessLogic,
96 ArtifactsOperations artifactToscaOperation,
97 ComponentContactIdValidator componentContactIdValidator,
98 ComponentNameValidator componentNameValidator,
99 ComponentTagsValidator componentTagsValidator,
100 ComponentValidator componentValidator,
101 ComponentIconValidator componentIconValidator,
102 ComponentProjectCodeValidator componentProjectCodeValidator,
103 ComponentDescriptionValidator componentDescriptionValidator){
104 super(elementDao, groupOperation, groupInstanceOperation, groupTypeOperation, groupBusinessLogic,
105 interfaceOperation, interfaceLifecycleTypeOperation, artifactsBusinessLogic, artifactToscaOperation,
106 componentContactIdValidator, componentNameValidator, componentTagsValidator, componentValidator,
107 componentIconValidator, componentProjectCodeValidator, componentDescriptionValidator);
108 this.componentInstanceBusinessLogic = componentInstanceBusinessLogic;
110 creationRoles = new ArrayList<>();
111 updateRoles = new ArrayList<>();
112 contactsRoles = new ArrayList<>();
114 // only PM is allowed to create/update products
115 creationRoles.add(Role.PRODUCT_MANAGER);
116 updateRoles.add(Role.PRODUCT_MANAGER);
117 // Only PM is allowed to be product contacts
118 contactsRoles.add(Role.PRODUCT_MANAGER);
121 public Either<Product, ResponseFormat> createProduct(Product product, User user) {
122 AuditingActionEnum actionEnum = AuditingActionEnum.CREATE_RESOURCE;
123 ComponentTypeEnum typeEnum = ComponentTypeEnum.PRODUCT;
125 // validate user - should be first to get the maximum auditing info in
126 // case of subsequent failures
127 log.debug("get user from DB");
128 user = validateUser(user, CREATE_PRODUCT, product, actionEnum, false);
129 // validate user role
130 validateUserRole(user, product, creationRoles, actionEnum, null);
132 if (product == null) {
133 log.debug("Invalid product json. Check product servlet log for createProduct entry params");
134 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
135 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, typeEnum);
136 return Either.right(responseFormat);
139 // warn about non-updatable fields
140 checkUnupdatableProductFields(product);
142 Either<Product, ResponseFormat> validateProductResponse = validateProductBeforeCreate(product, user, actionEnum);
143 if (validateProductResponse.isRight()) {
144 return Either.right(validateProductResponse.right().value());
147 log.debug("send product {} to dao for create", product.getComponentMetadataDefinition().getMetadataDataDefinition().getName());
149 Either<Boolean, ResponseFormat> lockResult = lockComponentByName(product.getSystemName(), product, CREATE_PRODUCT);
150 if (lockResult.isRight()) {
151 ResponseFormat responseFormat = lockResult.right().value();
152 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
153 return Either.right(responseFormat);
156 log.debug("Product name locked is {}, status = {}", product.getSystemName(), lockResult);
159 Either<Product, StorageOperationStatus> createProductEither = toscaOperationFacade.createToscaComponent(product);
161 if (createProductEither.isRight()) {
162 ResponseFormat responseFormat = componentsUtils.getResponseFormatByComponent(componentsUtils.convertFromStorageResponse(createProductEither.right().value()), product, typeEnum);
163 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, typeEnum);
164 return Either.right(responseFormat);
167 log.debug("Product created successfully");
168 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.CREATED);
169 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, typeEnum);
171 Product createdProduct = createProductEither.left().value();
173 return Either.left(createdProduct);
176 graphLockOperation.unlockComponentByName(product.getSystemName(), product.getUniqueId(), NodeTypeEnum.Product);
181 private void checkUnupdatableProductFields(Product product) {
182 checkComponentFieldsForOverrideAttempt(product);
183 if (product.getNormalizedName() != null) {
184 log.info("NormalizedName cannot be defined by user. This field will be overridden by the application");
188 private Either<Product, ResponseFormat> validateProductBeforeCreate(Product product, User user, AuditingActionEnum actionEnum) {
190 Either<Boolean, ResponseFormat> validateProductFields = validateProductFieldsBeforeCreate(user, product, actionEnum);
191 if (validateProductFields.isRight()) {
192 return Either.right(validateProductFields.right().value());
195 if (product.getIsActive() == null) {
196 log.debug("no isActive value was provided, setting to default: false");
197 product.setIsActive(false);
200 product.setCreatorUserId(user.getUserId());
203 log.debug("enrich product with version and state");
204 product.setState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT);
205 product.setVersion(INITIAL_VERSION);
207 // Generate invariant UUID - must be here and not in operation since it
208 // should stay constant during clone
209 String invariantUUID = UniqueIdBuilder.buildInvariantUUID();
210 product.setInvariantUUID(invariantUUID);
212 return Either.left(product);
215 private Either<Boolean, ResponseFormat> validateProductFieldsBeforeCreate(User user, Product product, AuditingActionEnum actionEnum) {
217 // To be removed in 1607
219 String oldName = product.getName();
221 Either<Boolean, ResponseFormat> componentNameValidation = validateProductNameAndCleanup(user, product, actionEnum);
222 if (componentNameValidation.isRight()) {
223 return componentNameValidation;
227 componentNameValidator.validateComponentNameUnique(user, product, actionEnum);
228 } catch (ComponentException exp) {
229 return Either.right(exp.getResponseFormat());
232 // To be removed in 1607 and replaced with generic
233 // validateTagsListAndRemoveDuplicates()
234 // See comments on the validateTagsListAndRemoveDuplicates(user,
235 // product, oldName, actionEnum) function
236 Either<Boolean, ResponseFormat> tagsValidation = validateTagsListAndRemoveDuplicates(user, product, oldName, actionEnum);
237 if (tagsValidation.isRight()) {
238 return tagsValidation;
241 componentTagsValidator.validateAndCorrectField(user, product, actionEnum);
244 componentProjectCodeValidator.validateAndCorrectField(user, product, actionEnum);
245 } catch (ComponentException exp) {
246 return Either.right(exp.getResponseFormat());
248 Either<Boolean, ResponseFormat> categoryValidation = validateGrouping(user, product, actionEnum);
249 if (categoryValidation.isRight()) {
250 return categoryValidation;
253 Either<Boolean, ResponseFormat> contactsListValidation = validateAndUpdateProductContactsList(user, product, actionEnum);
254 if (contactsListValidation.isRight()) {
255 return contactsListValidation;
258 Either<Boolean, ResponseFormat> productFullNameValidation = validateProductFullNameAndCleanup(user, product, actionEnum);
259 if (productFullNameValidation.isRight()) {
260 return productFullNameValidation;
263 componentDescriptionValidator.validateAndCorrectField(user, product, actionEnum);
265 return Either.left(true);
268 public Either<Map<String, Boolean>, ResponseFormat> validateProductNameExists(String productName, String userId) {
270 validateUserExists(userId);
271 Either<Boolean, StorageOperationStatus> dataModelResponse = toscaOperationFacade.validateComponentNameUniqueness(productName, null, ComponentTypeEnum.PRODUCT);
273 janusGraphDao.commit();
275 if (dataModelResponse.isLeft()) {
276 Map<String, Boolean> result = new HashMap<>();
277 result.put("isValid", dataModelResponse.left().value());
278 log.debug("validation was successfully performed.");
279 return Either.left(result);
282 ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(dataModelResponse.right().value()));
284 return Either.right(responseFormat);
287 private Either<Boolean, ResponseFormat> validateAndUpdateProductContactsList(User user, Product product, AuditingActionEnum actionEnum) {
288 List<String> contacts = product.getContacts();
289 if (!ValidationUtils.validateListNotEmpty(contacts)) {
290 log.debug("Contacts list cannot be empty for product {}", product.getName());
291 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.EMPTY_PRODUCT_CONTACTS_LIST);
292 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
293 return Either.right(responseFormat);
296 boolean isProductCreatorInContacts = false;
297 String modifierUserId = user.getUserId();
298 for (String contact : contacts) {
299 if (contact.equals(modifierUserId)) {
300 log.trace("modifier userId found in product contacts");
301 isProductCreatorInContacts = true;
302 // No need to validate for this userId - it's modifier's
305 if (!ValidationUtils.validateContactId(contact)) {
306 log.debug("Product contacts has invalid userId {} for product {}", contact, product.getName());
307 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_INVALID_CONTACT, ComponentTypeEnum.PRODUCT.getValue());
308 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
309 return Either.right(responseFormat);
314 contactUser = validateUserExists(contact);
315 validateUserRole(contactUser, contactsRoles);
316 } catch(ByActionStatusComponentException e){
317 log.debug("Cannot set contact with userId {} as product contact, error: {}", contact, e.getActionStatus());
318 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_PRODUCT_CONTACT, contact);
319 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
320 throw new ByActionStatusComponentException(e.getActionStatus(), e.getParams());
324 if (!isProductCreatorInContacts) {
325 log.debug("modifier userId {} not found in product contacts - adding it", modifierUserId);
326 contacts.add(modifierUserId);
329 // passed - setting all contacts userIds to lowercase
330 List<String> tempContacts = contacts.stream()
331 .map(String::toLowerCase)
332 .collect(Collectors.toList());
333 ValidationUtils.removeDuplicateFromList(tempContacts);
334 product.setContacts(tempContacts);
336 return Either.left(true);
339 private Either<Boolean, ResponseFormat> validateGrouping(User user, Product product, AuditingActionEnum actionEnum) {
340 List<CategoryDefinition> categories = product.getCategories();
341 if (categories == null || categories.isEmpty()) {
342 log.debug("Grouping list is empty for product: {}", product.getName());
343 return Either.left(true);
345 Map<String, Map<String, Set<String>>> nonDuplicatedCategories = new HashMap<>();
346 // remove duplicated entries
347 for (CategoryDefinition cat : categories) {
348 String catName = cat.getName();
349 if (!ValidationUtils.validateStringNotEmpty(catName)) {
350 // error missing cat name
351 log.debug("Missing category name for product: {}", product.getName());
352 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_CATEGORY, ComponentTypeEnum.PRODUCT.getValue());
353 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
354 return Either.right(responseFormat);
356 Map<String, Set<String>> catEntry = nonDuplicatedCategories.get(catName);
357 if (catEntry == null) {
358 catEntry = new HashMap<>();
359 nonDuplicatedCategories.put(catName, catEntry);
361 List<SubCategoryDefinition> subcategories = cat.getSubcategories();
362 if (subcategories == null || subcategories.isEmpty()) {
363 // error missing subcat for cat
364 log.debug("Missing sub-categories for category {} in product {}", catName, product.getName());
365 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_SUBCATEGORY);
366 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
367 return Either.right(responseFormat);
369 for (SubCategoryDefinition subcat : subcategories) {
370 String subCatName = subcat.getName();
371 if (!ValidationUtils.validateStringNotEmpty(subCatName)) {
372 // error missing sub cat name for cat
373 log.debug("Missing or empty sub-category for category {} in product {}", catName, product.getName());
374 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_SUBCATEGORY);
375 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
376 return Either.right(responseFormat);
378 Set<String> subcatEntry = catEntry.get(subCatName);
379 if (subcatEntry == null) {
380 subcatEntry = new HashSet<>();
381 catEntry.put(subCatName, subcatEntry);
383 List<GroupingDefinition> groupings = subcat.getGroupings();
384 for (GroupingDefinition group : groupings) {
385 String groupName = group.getName();
386 if (!ValidationUtils.validateStringNotEmpty(groupName)) {
387 // error missing grouping for sub cat name and cat
388 log.debug("Missing or empty groupng name for sub-category: {} for categor: {} in product: {}", subCatName, catName, product.getName());
389 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_SUBCATEGORY);
390 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
391 return Either.right(responseFormat);
393 if (!subcatEntry.contains(groupName)) {
394 subcatEntry.add(groupName);
396 log.debug("Grouping: {}, already exist for category: {} and subcategory: {}", groupName, catName, subCatName);
400 } // for end of checking duplicated
401 // validate existence
402 Either<List<CategoryDefinition>, ActionStatus> allProductCategories = elementDao.getAllProductCategories();
404 if (allProductCategories.isRight()) {
405 log.debug("No product categories {}", allProductCategories.right().value());
406 ResponseFormat responseFormat = componentsUtils.getResponseFormat(allProductCategories.right().value());
407 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
408 return Either.right(responseFormat);
411 // convert non-duplicated to data modeling format and update in the
413 List<CategoryDefinition> newCatList = new ArrayList<>();
415 // over all categories from request
416 for (Map.Entry<String, Map<String, Set<String>>> entry : nonDuplicatedCategories.entrySet()) {
418 CategoryDefinition categoryDefinition = null;
419 // over all categories from JanusGraph
420 List<CategoryDefinition> categoriesList = allProductCategories.left().value();
421 if (categoriesList != null) {
422 for (CategoryDefinition catInDb : categoriesList) {
423 if (entry.getKey().equals(catInDb.getName())) {
427 categoryDefinition = new CategoryDefinition(catInDb);
428 SubCategoryDefinition subCategory = null;
430 Map<String, Set<String>> subcats = entry.getValue();
431 for (Map.Entry<String, Set<String>> subcat : subcats.entrySet()) {
433 List<SubCategoryDefinition> subcategoriesList = catInDb.getSubcategories();
434 if (subcategoriesList != null) {
435 for (SubCategoryDefinition subcatInDb : subcategoriesList) {
436 if (subcatInDb.getName().equals(subcat.getKey())) {
438 subCategory = new SubCategoryDefinition(subcatInDb);
440 Set<String> grouping = subcat.getValue();
442 GroupingDefinition groupingDefinition = null;
443 for (String group : grouping) {
445 List<GroupingDefinition> groupings = subcatInDb.getGroupings();
446 if (groupings != null) {
447 for (GroupingDefinition groupInDb : groupings) {
448 if (groupInDb.getName().equals(group)) {
450 groupingDefinition = new GroupingDefinition(groupInDb);
455 // error grouping isn't defined
457 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_GROUP_ASSOCIATION, CategoryTypeEnum.GROUPING.getValue(), group);
458 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
459 return Either.right(responseFormat);
461 subCategory.addGrouping(groupingDefinition);
467 // error sub category isn't defined in JanusGraph
468 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_GROUP_ASSOCIATION, CategoryTypeEnum.SUBCATEGORY.getValue(), subcat.getKey());
469 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
470 return Either.right(responseFormat);
472 categoryDefinition.addSubCategory(subCategory);
478 // error category isn't defined in JanusGraph
479 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_GROUP_ASSOCIATION, CategoryTypeEnum.CATEGORY.getValue(), entry.getKey());
480 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
481 return Either.right(responseFormat);
483 newCatList.add(categoryDefinition);
485 product.setCategories(newCatList);
486 return Either.left(true);
489 public Either<Product, ResponseFormat> getProduct(String productId, User user) {
490 String ecompErrorContext = "Get product";
491 validateUserNotEmpty(user, ecompErrorContext);
492 validateUserExists(user);
494 Either<Product, StorageOperationStatus> storageStatus = toscaOperationFacade.getToscaElement(productId);
496 if (storageStatus.isRight()) {
497 log.debug("failed to get resource by id {}", productId);
498 if (storageStatus.right().value() == StorageOperationStatus.NOT_FOUND) {
500 return Either.right(componentsUtils.getResponseFormat(ActionStatus.PRODUCT_NOT_FOUND, ComponentTypeEnum.PRODUCT.getValue()));
502 return Either.right(componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(storageStatus.right().value()), ""));
505 return Either.left(storageStatus.left().value());
508 public Either<Product, ResponseFormat> deleteProduct(String productId, User user) {
509 String ecompErrorContext = "Delete product";
510 validateUserNotEmpty(user, ecompErrorContext);
511 validateUserExists(user);
513 Either<Product, StorageOperationStatus> storageStatus = toscaOperationFacade.deleteToscaComponent(productId);
515 if (storageStatus.isRight()) {
516 log.debug("failed to delete resource by id {}", productId);
517 return Either.right(componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(storageStatus.right().value()), ""));
519 return Either.left(storageStatus.left().value());
522 private Either<Boolean, ResponseFormat> validateProductFullNameAndCleanup(User user, Product product, AuditingActionEnum actionEnum) {
523 String fullName = product.getFullName();
524 if (!ValidationUtils.validateStringNotEmpty(fullName)) {
525 ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.MISSING_ONE_OF_COMPONENT_NAMES, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_FULL_NAME);
526 componentsUtils.auditComponentAdmin(errorResponse, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
527 return Either.right(errorResponse);
530 fullName = ValidationUtils.removeNoneUtf8Chars(fullName);
531 fullName = ValidationUtils.removeHtmlTags(fullName);
532 fullName = ValidationUtils.normaliseWhitespace(fullName);
533 fullName = ValidationUtils.stripOctets(fullName);
535 if (!ValidationUtils.validateProductFullNameLength(fullName)) {
536 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_FULL_NAME);
537 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
538 return Either.right(responseFormat);
541 if (!ValidationUtils.validateIsEnglish(fullName)) {
542 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_FULL_NAME);
543 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
544 return Either.right(responseFormat);
547 product.setFullName(fullName);
548 return Either.left(true);
551 private Either<Boolean, ResponseFormat> validateProductNameAndCleanup(User user, Product product, AuditingActionEnum actionEnum) {
552 String name = product.getName();
553 if (!ValidationUtils.validateStringNotEmpty(name)) {
554 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.MISSING_ONE_OF_COMPONENT_NAMES, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_ABBREVIATED_NAME);
555 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
556 return Either.right(responseFormat);
559 // Product name is required to have same validation and normalization as
561 if (!ValidationUtils.validateCategoryDisplayNameFormat(name)) {
562 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_ABBREVIATED_NAME);
563 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
564 return Either.right(responseFormat);
567 String normalizedName4Display = ValidationUtils.normalizeCategoryName4Display(name);
569 if (!ValidationUtils.validateCategoryDisplayNameLength(normalizedName4Display)) {
570 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_ABBREVIATED_NAME);
571 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
572 return Either.right(responseFormat);
575 product.setName(normalizedName4Display);
576 String normalizedName4Uniqueness = ValidationUtils.normaliseComponentName(normalizedName4Display);
577 product.setNormalizedName(normalizedName4Uniqueness);
579 return Either.left(true);
582 // This is a workaround for a current tag--->product name behaviour, which
583 // will be changed in 1607.
584 // It was agreed with Ella on 23/2/16 that the tag validation of product
585 // will be made against the old product name (before normalization),
586 // and in 1607 US will be defined where UI will no longer pass tag of
587 // component name, and BE will add it by itself after all needed
589 private Either<Boolean, ResponseFormat> validateTagsListAndRemoveDuplicates(User user, Product product, String oldProductName, AuditingActionEnum actionEnum) {
590 componentTagsValidator.validateAndCorrectField(user, product, actionEnum);
591 return Either.left(true);
595 public void setDeploymentArtifactsPlaceHolder(org.openecomp.sdc.be.model.Component component, User user) {
599 public Either<Product, ResponseFormat> updateProductMetadata(String productId, Product updatedProduct, User user) {
600 ComponentTypeEnum typeEnum = ComponentTypeEnum.PRODUCT;
601 user = validateUser(user, "Update Product", updatedProduct, null, false);
602 // validate user role
603 validateUserRole(user, updatedProduct, updateRoles, null, null);
604 if (updatedProduct == null) {
605 log.debug("Invalid product json. Check product servlet log for updateProduct entry params");
606 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
607 return Either.right(responseFormat);
610 Either<Product, StorageOperationStatus> storageStatus = toscaOperationFacade.getToscaElement(productId);
611 if (storageStatus.isRight()) {
612 if (storageStatus.right().value() == StorageOperationStatus.NOT_FOUND) {
613 return Either.right(componentsUtils.getResponseFormat(ActionStatus.PRODUCT_NOT_FOUND, ComponentTypeEnum.PRODUCT.name().toLowerCase()));
615 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(storageStatus.right().value(), typeEnum), ""));
618 Product currentProduct = storageStatus.left().value();
620 if (!ComponentValidationUtils.canWorkOnComponent(productId, toscaOperationFacade, user.getUserId())) {
621 log.info("Restricted operation for user: {}, on product: {}" , user.getUserId(), currentProduct.getCreatorUserId());
622 return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
625 Either<Product, ResponseFormat> validationRsponse = validateAndUpdateProductMetadata(user, currentProduct, updatedProduct);
626 if (validationRsponse.isRight()) {
627 log.info("product update metadata: validations field.");
628 return validationRsponse;
631 Product productToUpdate = validationRsponse.left().value();
633 lockComponent(currentProduct.getUniqueId(), currentProduct, "Update Product Metadata");
635 Either<Product, StorageOperationStatus> updateResponse = toscaOperationFacade.updateToscaElement(productToUpdate);
636 if (updateResponse.isRight()) {
637 toscaOperationFacade.rollback();
638 log.debug("failed to update product {}", productToUpdate.getUniqueId());
639 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
641 toscaOperationFacade.commit();
642 return Either.left(updateResponse.left().value());
644 graphLockOperation.unlockComponent(productId, NodeTypeEnum.Product);
648 private Either<Product, ResponseFormat> validateAndUpdateProductMetadata(User user, Product currentProduct, Product updatedProduct) {
650 boolean hasBeenCertified = ValidationUtils.hasBeenCertified(currentProduct.getVersion());
651 Either<Boolean, ResponseFormat> response = validateAndUpdateProductName(user, currentProduct, updatedProduct);
652 if (response.isRight()) {
653 ResponseFormat errorResponse = response.right().value();
654 return Either.right(errorResponse);
657 response = validateAndUpdateFullName(user, currentProduct, updatedProduct);
658 if (response.isRight()) {
659 ResponseFormat errorResponse = response.right().value();
660 return Either.right(errorResponse);
663 response = validateAndUpdateDescription(user, currentProduct, updatedProduct, null);
664 if (response.isRight()) {
665 ResponseFormat errorResponse = response.right().value();
666 return Either.right(errorResponse);
669 response = validateAndUpdateCategory(user, currentProduct, updatedProduct);
670 if (response.isRight()) {
671 ResponseFormat errorResponse = response.right().value();
672 return Either.right(errorResponse);
675 response = validateAndUpdateContactList(user, currentProduct, updatedProduct);
676 if (response.isRight()) {
677 ResponseFormat errorResponse = response.right().value();
678 return Either.right(errorResponse);
681 response = validateAndUpdateTags(user, currentProduct, updatedProduct);
682 if (response.isRight()) {
683 ResponseFormat errorResponse = response.right().value();
684 return Either.right(errorResponse);
687 response = validateAndUpdateProjectCode(user, currentProduct, updatedProduct);
688 if (response.isRight()) {
689 ResponseFormat errorResponse = response.right().value();
690 return Either.right(errorResponse);
693 if (updatedProduct.getIsActive() != null) {
694 currentProduct.setIsActive(updatedProduct.getIsActive());
697 response = validateAndUpdateIcon(user, currentProduct, updatedProduct, hasBeenCertified);
698 if (response.isRight()) {
699 ResponseFormat errorResponse = response.right().value();
700 return Either.right(errorResponse);
703 String currentInvariantUuid = currentProduct.getInvariantUUID();
704 String updatedInvariantUuid = updatedProduct.getInvariantUUID();
706 if ((updatedInvariantUuid != null) && (!updatedInvariantUuid.equals(currentInvariantUuid))) {
707 log.warn("Product invariant UUID is automatically set and cannot be updated");
708 updatedProduct.setInvariantUUID(currentInvariantUuid);
710 return Either.left(currentProduct);
714 private Either<Boolean, ResponseFormat> validateAndUpdateProductName(User user, Product currentProduct, Product updatedProduct) {
715 String updatedProductName = updatedProduct.getName();
717 String currentProductName = currentProduct.getName();
718 if (updatedProductName != null) {
719 Either<Boolean, ResponseFormat> validatProductNameResponse = validateProductNameAndCleanup(user, updatedProduct, null);
720 if (validatProductNameResponse.isRight()) {
721 ResponseFormat errorRespons = validatProductNameResponse.right().value();
722 return Either.right(errorRespons);
724 updatedProductName = updatedProduct.getName();
725 if (!currentProductName.equals(updatedProductName)) {
727 componentNameValidator.validateComponentNameUnique(user, updatedProduct, null);
728 } catch (ComponentException exp) {
729 return Either.right(exp.getResponseFormat());
731 currentProduct.setName(updatedProductName);
732 tags = updatedProductName;
733 updatedProductName = ValidationUtils.normalizeCategoryName4Display(updatedProductName);
734 currentProduct.getComponentMetadataDefinition().getMetadataDataDefinition().setNormalizedName(ValidationUtils.normaliseComponentName(updatedProductName));
735 List<String> updatedTags = updatedProduct.getTags();
736 // As discussed with Ella currently (1604) we are not removing
737 // the old name from tags.
738 if (updatedTags == null) {
739 updatedTags = currentProduct.getTags();
741 updatedTags.add(tags);
744 return Either.left(true);
747 private Either<Boolean, ResponseFormat> validateAndUpdateFullName(User user, Product currentProduct, Product updatedProduct) {
748 String updatedProductName = updatedProduct.getFullName();
749 String currentProductName = currentProduct.getFullName();
750 if (updatedProductName != null && !currentProductName.equals(updatedProductName)) {
751 Either<Boolean, ResponseFormat> validatProductNameResponse = validateProductFullNameAndCleanup(user, updatedProduct, null);
752 if (validatProductNameResponse.isRight()) {
753 ResponseFormat errorRespons = validatProductNameResponse.right().value();
754 return Either.right(errorRespons);
756 currentProduct.setFullName(updatedProduct.getFullName());
758 return Either.left(true);
761 private Either<Boolean, ResponseFormat> validateAndUpdateCategory(User user, Product currentProduct, Product updatedProduct) {
763 Either<Boolean, ResponseFormat> validateCategoryResponse = validateGrouping(user, updatedProduct, null);
764 if (validateCategoryResponse.isRight()) {
765 ResponseFormat errorResponse = validateCategoryResponse.right().value();
766 return Either.right(errorResponse);
769 List<CategoryDefinition> categoryUpdated = updatedProduct.getCategories();
770 if (categoryUpdated != null) {
771 currentProduct.setCategories(categoryUpdated);
773 return Either.left(true);
776 private Either<Boolean, ResponseFormat> validateAndUpdateContactList(User user, Product currentProduct, Product updatedProduct) {
777 List<String> updatedContacts = updatedProduct.getContacts();
778 List<String> currentContacts = currentProduct.getContacts();
779 if (updatedContacts != null) {
780 if (!(currentContacts.containsAll(updatedContacts) && updatedContacts.containsAll(currentContacts))) {
781 Either<Boolean, ResponseFormat> validatResponse = validateAndUpdateProductContactsList(user, updatedProduct, null);
782 if (validatResponse.isRight()) {
783 ResponseFormat errorRespons = validatResponse.right().value();
784 return Either.right(errorRespons);
786 currentProduct.setContacts(updatedProduct.getContacts());
789 return Either.left(true);
792 private Either<Boolean, ResponseFormat> validateAndUpdateTags(User user, Product currentProduct, Product updatedProduct) {
793 List<String> tagsUpdated = updatedProduct.getTags();
794 List<String> tagsCurrent = currentProduct.getTags();
795 if (tagsUpdated != null) {
796 if (!(tagsCurrent.containsAll(tagsUpdated) && tagsUpdated.containsAll(tagsCurrent))) {
797 Either<Boolean, ResponseFormat> validatResponse = validateTagsListAndRemoveDuplicates(user, updatedProduct, currentProduct.getName(), null);
798 if (validatResponse.isRight()) {
799 ResponseFormat errorRespons = validatResponse.right().value();
800 return Either.right(errorRespons);
802 currentProduct.setTags(updatedProduct.getTags());
805 return Either.left(true);
809 public Either<List<String>, ResponseFormat> deleteMarkedComponents() {
810 // markAsDeleted isnt implemented yet
811 return Either.left(new ArrayList<>());
814 public Either<Product, ResponseFormat> getProductByNameAndVersion(String productName, String productVersion, String userId) {
815 validateUserExists(userId);
816 Either<Product, StorageOperationStatus> storageStatus = toscaOperationFacade.getComponentByNameAndVersion(ComponentTypeEnum.PRODUCT, productName, productVersion);
817 if (storageStatus.isRight()) {
818 log.debug("failed to get service by name {} and version {}", productName, productVersion);
819 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(storageStatus.right().value(), ComponentTypeEnum.PRODUCT), productName));
821 Product product = storageStatus.left().value();
822 return Either.left(product);
826 public ComponentInstanceBusinessLogic getComponentInstanceBL() {
827 return componentInstanceBusinessLogic;
831 public Either<List<ComponentInstance>, ResponseFormat> getComponentInstancesFilteredByPropertiesAndInputs(String componentId, String userId) {
836 public Either<UiComponentDataTransfer, ResponseFormat> getUiComponentDataTransferByComponentId(String componentId,
837 List<String> dataParamsToReturn) {
838 // TODO Auto-generated method stub