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.dao.api.ActionStatus;
29 import org.openecomp.sdc.be.datamodel.api.CategoryTypeEnum;
30 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
31 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
32 import org.openecomp.sdc.be.model.ComponentInstance;
33 import org.openecomp.sdc.be.model.LifecycleStateEnum;
34 import org.openecomp.sdc.be.model.Product;
35 import org.openecomp.sdc.be.model.User;
36 import org.openecomp.sdc.be.model.category.CategoryDefinition;
37 import org.openecomp.sdc.be.model.category.GroupingDefinition;
38 import org.openecomp.sdc.be.model.category.SubCategoryDefinition;
39 import org.openecomp.sdc.be.model.operations.api.ICacheMangerOperation;
40 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
41 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
42 import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils;
43 import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
44 import org.openecomp.sdc.be.ui.model.UiComponentDataTransfer;
45 import org.openecomp.sdc.be.user.Role;
46 import org.openecomp.sdc.common.log.wrappers.Logger;
47 import org.openecomp.sdc.common.util.ValidationUtils;
48 import org.openecomp.sdc.exception.ResponseFormat;
49 import org.springframework.beans.factory.annotation.Autowired;
52 import java.util.stream.Collectors;
54 @org.springframework.stereotype.Component("productBusinessLogic")
55 public class ProductBusinessLogic extends ComponentBusinessLogic {
57 private static final String PRODUCT_FULL_NAME = "full";
58 private static final String PRODUCT_ABBREVIATED_NAME = "abbreviated";
59 private static final Logger log = Logger.getLogger(ProductBusinessLogic.class);
60 private static final String INITIAL_VERSION = "0.1";
61 private static final String CREATE_PRODUCT = "Create Product";
62 private static List<Role> creationRoles;
63 private static List<Role> updateRoles;
64 private static List<Role> contactsRoles;
67 private ComponentInstanceBusinessLogic componentInstanceBusinessLogic;
70 private ICacheMangerOperation cacheManagerOperation;
72 public ProductBusinessLogic() {
73 creationRoles = new ArrayList<>();
74 updateRoles = new ArrayList<>();
75 contactsRoles = new ArrayList<>();
77 // only PM is allowed to create/update products
78 creationRoles.add(Role.PRODUCT_MANAGER);
79 updateRoles.add(Role.PRODUCT_MANAGER);
80 // Only PM is allowed to be product contacts
81 contactsRoles.add(Role.PRODUCT_MANAGER);
85 public Either<Product, ResponseFormat> createProduct(Product product, User user) {
86 AuditingActionEnum actionEnum = AuditingActionEnum.CREATE_RESOURCE;
87 ComponentTypeEnum typeEnum = ComponentTypeEnum.PRODUCT;
89 // validate user - should be first to get the maximum auditing info in
90 // case of subsequent failures
91 log.debug("get user from DB");
92 user = validateUser(user, CREATE_PRODUCT, product, actionEnum, false);
94 validateUserRole(user, product, creationRoles, actionEnum, null);
96 if (product == null) {
97 log.debug("Invalid product json. Check product servlet log for createProduct entry params");
98 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
99 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, typeEnum);
100 return Either.right(responseFormat);
103 // warn about non-updatable fields
104 checkUnupdatableProductFields(product);
106 Either<Product, ResponseFormat> validateProductResponse = validateProductBeforeCreate(product, user, actionEnum);
107 if (validateProductResponse.isRight()) {
108 return Either.right(validateProductResponse.right().value());
111 log.debug("send product {} to dao for create", product.getComponentMetadataDefinition().getMetadataDataDefinition().getName());
113 Either<Boolean, ResponseFormat> lockResult = lockComponentByName(product.getSystemName(), product, CREATE_PRODUCT);
114 if (lockResult.isRight()) {
115 ResponseFormat responseFormat = lockResult.right().value();
116 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
117 return Either.right(responseFormat);
120 log.debug("Product name locked is {}, status = {}", product.getSystemName(), lockResult);
123 Either<Product, StorageOperationStatus> createProductEither = toscaOperationFacade.createToscaComponent(product);
125 if (createProductEither.isRight()) {
126 ResponseFormat responseFormat = componentsUtils.getResponseFormatByComponent(componentsUtils.convertFromStorageResponse(createProductEither.right().value()), product, typeEnum);
127 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, typeEnum);
128 return Either.right(responseFormat);
131 log.debug("Product created successfully");
132 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.CREATED);
133 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, typeEnum);
135 Product createdProduct = createProductEither.left().value();
137 return Either.left(createdProduct);
140 graphLockOperation.unlockComponentByName(product.getSystemName(), product.getUniqueId(), NodeTypeEnum.Product);
145 private void checkUnupdatableProductFields(Product product) {
146 checkComponentFieldsForOverrideAttempt(product);
147 if (product.getNormalizedName() != null) {
148 log.info("NormalizedName cannot be defined by user. This field will be overridden by the application");
152 private Either<Product, ResponseFormat> validateProductBeforeCreate(Product product, User user, AuditingActionEnum actionEnum) {
154 Either<Boolean, ResponseFormat> validateProductFields = validateProductFieldsBeforeCreate(user, product, actionEnum);
155 if (validateProductFields.isRight()) {
156 return Either.right(validateProductFields.right().value());
159 if (product.getIsActive() == null) {
160 log.debug("no isActive value was provided, setting to default: false");
161 product.setIsActive(false);
164 product.setCreatorUserId(user.getUserId());
167 log.debug("enrich product with version and state");
168 product.setState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT);
169 product.setVersion(INITIAL_VERSION);
171 // Generate invariant UUID - must be here and not in operation since it
172 // should stay constant during clone
173 String invariantUUID = UniqueIdBuilder.buildInvariantUUID();
174 product.setInvariantUUID(invariantUUID);
176 return Either.left(product);
179 private Either<Boolean, ResponseFormat> validateProductFieldsBeforeCreate(User user, Product product, AuditingActionEnum actionEnum) {
181 // To be removed in 1607
183 String oldName = product.getName();
185 Either<Boolean, ResponseFormat> componentNameValidation = validateProductNameAndCleanup(user, product, actionEnum);
186 if (componentNameValidation.isRight()) {
187 return componentNameValidation;
190 Either<Boolean, ResponseFormat> componentNameUniquenessValidation = validateComponentNameUnique(user, product, actionEnum);
191 if (componentNameUniquenessValidation.isRight()) {
192 return componentNameUniquenessValidation;
195 // To be removed in 1607 and replaced with generic
196 // validateTagsListAndRemoveDuplicates()
197 // See comments on the validateTagsListAndRemoveDuplicates(user,
198 // product, oldName, actionEnum) function
199 Either<Boolean, ResponseFormat> tagsValidation = validateTagsListAndRemoveDuplicates(user, product, oldName, actionEnum);
200 if (tagsValidation.isRight()) {
201 return tagsValidation;
204 validateIcon(user, product, actionEnum);
206 Either<Boolean, ResponseFormat> projectCodeValidation = validateProjectCode(user, product, actionEnum);
207 if (projectCodeValidation.isRight()) {
208 return projectCodeValidation;
210 Either<Boolean, ResponseFormat> categoryValidation = validateGrouping(user, product, actionEnum);
211 if (categoryValidation.isRight()) {
212 return categoryValidation;
215 Either<Boolean, ResponseFormat> contactsListValidation = validateAndUpdateProductContactsList(user, product, actionEnum);
216 if (contactsListValidation.isRight()) {
217 return contactsListValidation;
220 Either<Boolean, ResponseFormat> productFullNameValidation = validateProductFullNameAndCleanup(user, product, actionEnum);
221 if (productFullNameValidation.isRight()) {
222 return productFullNameValidation;
225 validateDescriptionAndCleanup(user, product, actionEnum);
227 return Either.left(true);
230 public Either<Map<String, Boolean>, ResponseFormat> validateProductNameExists(String productName, String userId) {
232 validateUserExists(userId, "validate Product Name Exists", false);
233 Either<Boolean, StorageOperationStatus> dataModelResponse = toscaOperationFacade.validateComponentNameUniqueness(productName, null, ComponentTypeEnum.PRODUCT);
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);
244 ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(dataModelResponse.right().value()));
246 return Either.right(responseFormat);
249 private Either<Boolean, ResponseFormat> validateAndUpdateProductContactsList(User user, Product product, AuditingActionEnum actionEnum) {
250 List<String> contacts = product.getContacts();
251 if (!ValidationUtils.validateListNotEmpty(contacts)) {
252 log.debug("Contacts list cannot be empty for product {}", product.getName());
253 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.EMPTY_PRODUCT_CONTACTS_LIST);
254 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
255 return Either.right(responseFormat);
258 boolean isProductCreatorInContacts = false;
259 String modifierUserId = user.getUserId();
260 for (String contact : contacts) {
261 if (contact.equals(modifierUserId)) {
262 log.trace("modifier userId found in product contacts");
263 isProductCreatorInContacts = true;
264 // No need to validate for this userId - it's modifier's
267 if (!ValidationUtils.validateContactId(contact)) {
268 log.debug("Product contacts has invalid userId {} for product {}", contact, product.getName());
269 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_INVALID_CONTACT, ComponentTypeEnum.PRODUCT.getValue());
270 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
271 return Either.right(responseFormat);
276 contactUser = validateUserExists(contact, CREATE_PRODUCT, false);
277 validateUserRole(contactUser, contactsRoles);
278 } catch(ByActionStatusComponentException e){
279 log.debug("Cannot set contact with userId {} as product contact, error: {}", contact, e.getActionStatus());
280 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_PRODUCT_CONTACT, contact);
281 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
282 throw new ByActionStatusComponentException(e.getActionStatus(), e.getParams());
286 if (!isProductCreatorInContacts) {
287 log.debug("modifier userId {} not found in product contacts - adding it", modifierUserId);
288 contacts.add(modifierUserId);
291 // passed - setting all contacts userIds to lowercase
292 List<String> tempContacts = contacts.stream()
293 .map(String::toLowerCase)
294 .collect(Collectors.toList());
295 ValidationUtils.removeDuplicateFromList(tempContacts);
296 product.setContacts(tempContacts);
298 return Either.left(true);
301 private Either<Boolean, ResponseFormat> validateGrouping(User user, Product product, AuditingActionEnum actionEnum) {
302 List<CategoryDefinition> categories = product.getCategories();
303 if (categories == null || categories.isEmpty()) {
304 log.debug("Grouping list is empty for product: {}", product.getName());
305 return Either.left(true);
307 Map<String, Map<String, Set<String>>> nonDuplicatedCategories = new HashMap<>();
308 // remove duplicated entries
309 for (CategoryDefinition cat : categories) {
310 String catName = cat.getName();
311 if (!ValidationUtils.validateStringNotEmpty(catName)) {
312 // error missing cat name
313 log.debug("Missing category name for product: {}", product.getName());
314 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_CATEGORY, ComponentTypeEnum.PRODUCT.getValue());
315 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
316 return Either.right(responseFormat);
318 Map<String, Set<String>> catEntry = nonDuplicatedCategories.get(catName);
319 if (catEntry == null) {
320 catEntry = new HashMap<>();
321 nonDuplicatedCategories.put(catName, catEntry);
323 List<SubCategoryDefinition> subcategories = cat.getSubcategories();
324 if (subcategories == null || subcategories.isEmpty()) {
325 // error missing subcat for cat
326 log.debug("Missing sub-categories for category {} in product {}", catName, product.getName());
327 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_SUBCATEGORY);
328 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
329 return Either.right(responseFormat);
331 for (SubCategoryDefinition subcat : subcategories) {
332 String subCatName = subcat.getName();
333 if (!ValidationUtils.validateStringNotEmpty(subCatName)) {
334 // error missing sub cat name for cat
335 log.debug("Missing or empty sub-category for category {} in product {}", catName, product.getName());
336 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_SUBCATEGORY);
337 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
338 return Either.right(responseFormat);
340 Set<String> subcatEntry = catEntry.get(subCatName);
341 if (subcatEntry == null) {
342 subcatEntry = new HashSet<>();
343 catEntry.put(subCatName, subcatEntry);
345 List<GroupingDefinition> groupings = subcat.getGroupings();
346 for (GroupingDefinition group : groupings) {
347 String groupName = group.getName();
348 if (!ValidationUtils.validateStringNotEmpty(groupName)) {
349 // error missing grouping for sub cat name and cat
350 log.debug("Missing or empty groupng name for sub-category: {} for categor: {} in product: {}", subCatName, catName, product.getName());
351 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_SUBCATEGORY);
352 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
353 return Either.right(responseFormat);
355 if (!subcatEntry.contains(groupName)) {
356 subcatEntry.add(groupName);
358 log.debug("Grouping: {}, already exist for category: {} and subcategory: {}", groupName, catName, subCatName);
362 } // for end of checking duplicated
363 // validate existence
364 Either<List<CategoryDefinition>, ActionStatus> allProductCategories = elementDao.getAllProductCategories();
366 if (allProductCategories.isRight()) {
367 log.debug("No product categories {}", allProductCategories.right().value());
368 ResponseFormat responseFormat = componentsUtils.getResponseFormat(allProductCategories.right().value());
369 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
370 return Either.right(responseFormat);
373 // convert non-duplicated to data modeling format and update in the
375 List<CategoryDefinition> newCatList = new ArrayList<>();
377 // over all categories from request
378 for (Map.Entry<String, Map<String, Set<String>>> entry : nonDuplicatedCategories.entrySet()) {
380 CategoryDefinition categoryDefinition = null;
381 // over all categories from Titan
382 List<CategoryDefinition> categoriesList = allProductCategories.left().value();
383 if (categoriesList != null) {
384 for (CategoryDefinition catInDb : categoriesList) {
385 if (entry.getKey().equals(catInDb.getName())) {
389 categoryDefinition = new CategoryDefinition(catInDb);
390 SubCategoryDefinition subCategory = null;
392 Map<String, Set<String>> subcats = entry.getValue();
393 for (Map.Entry<String, Set<String>> subcat : subcats.entrySet()) {
395 List<SubCategoryDefinition> subcategoriesList = catInDb.getSubcategories();
396 if (subcategoriesList != null) {
397 for (SubCategoryDefinition subcatInDb : subcategoriesList) {
398 if (subcatInDb.getName().equals(subcat.getKey())) {
400 subCategory = new SubCategoryDefinition(subcatInDb);
402 Set<String> grouping = subcat.getValue();
404 GroupingDefinition groupingDefinition = null;
405 for (String group : grouping) {
407 List<GroupingDefinition> groupings = subcatInDb.getGroupings();
408 if (groupings != null) {
409 for (GroupingDefinition groupInDb : groupings) {
410 if (groupInDb.getName().equals(group)) {
412 groupingDefinition = new GroupingDefinition(groupInDb);
417 // error grouping isn't defined
419 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_GROUP_ASSOCIATION, CategoryTypeEnum.GROUPING.getValue(), group);
420 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
421 return Either.right(responseFormat);
423 subCategory.addGrouping(groupingDefinition);
429 // error sub category isn't defined in Titan
430 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_GROUP_ASSOCIATION, CategoryTypeEnum.SUBCATEGORY.getValue(), subcat.getKey());
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 Titan
441 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_GROUP_ASSOCIATION, CategoryTypeEnum.CATEGORY.getValue(), entry.getKey());
442 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
443 return Either.right(responseFormat);
445 newCatList.add(categoryDefinition);
447 product.setCategories(newCatList);
448 return Either.left(true);
451 public Either<Product, ResponseFormat> getProduct(String productId, User user) {
452 String ecompErrorContext = "Get product";
453 validateUserNotEmpty(user, ecompErrorContext);
454 validateUserExists(user, ecompErrorContext, false);
456 Either<Product, StorageOperationStatus> storageStatus = toscaOperationFacade.getToscaElement(productId);
458 if (storageStatus.isRight()) {
459 log.debug("failed to get resource by id {}", productId);
460 if (storageStatus.right().value().equals(StorageOperationStatus.NOT_FOUND)) {
462 return Either.right(componentsUtils.getResponseFormat(ActionStatus.PRODUCT_NOT_FOUND, ComponentTypeEnum.PRODUCT.getValue()));
464 return Either.right(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, ecompErrorContext, false);
475 Either<Product, StorageOperationStatus> storageStatus = toscaOperationFacade.deleteToscaComponent(productId);
477 if (storageStatus.isRight()) {
478 log.debug("failed to delete resource by id {}", productId);
479 return Either.right(componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(storageStatus.right().value()), ""));
481 return Either.left(storageStatus.left().value());
484 private Either<Boolean, ResponseFormat> validateProductFullNameAndCleanup(User user, Product product, AuditingActionEnum actionEnum) {
485 String fullName = product.getFullName();
486 if (!ValidationUtils.validateStringNotEmpty(fullName)) {
487 ResponseFormat errorResponse = componentsUtils.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);
492 fullName = ValidationUtils.removeNoneUtf8Chars(fullName);
493 fullName = ValidationUtils.removeHtmlTags(fullName);
494 fullName = ValidationUtils.normaliseWhitespace(fullName);
495 fullName = ValidationUtils.stripOctets(fullName);
497 if (!ValidationUtils.validateProductFullNameLength(fullName)) {
498 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_FULL_NAME);
499 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
500 return Either.right(responseFormat);
503 if (!ValidationUtils.validateIsEnglish(fullName)) {
504 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_FULL_NAME);
505 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
506 return Either.right(responseFormat);
509 product.setFullName(fullName);
510 return Either.left(true);
513 private Either<Boolean, ResponseFormat> validateProductNameAndCleanup(User user, Product product, AuditingActionEnum actionEnum) {
514 String name = product.getName();
515 if (!ValidationUtils.validateStringNotEmpty(name)) {
516 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.MISSING_ONE_OF_COMPONENT_NAMES, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_ABBREVIATED_NAME);
517 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
518 return Either.right(responseFormat);
521 // Product name is required to have same validation and normalization as
523 if (!ValidationUtils.validateCategoryDisplayNameFormat(name)) {
524 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_ABBREVIATED_NAME);
525 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
526 return Either.right(responseFormat);
529 String normalizedName4Display = ValidationUtils.normalizeCategoryName4Display(name);
531 if (!ValidationUtils.validateCategoryDisplayNameLength(normalizedName4Display)) {
532 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_ABBREVIATED_NAME);
533 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
534 return Either.right(responseFormat);
537 product.setName(normalizedName4Display);
538 String normalizedName4Uniqueness = ValidationUtils.normaliseComponentName(normalizedName4Display);
539 product.setNormalizedName(normalizedName4Uniqueness);
541 return Either.left(true);
544 // This is a workaround for a current tag--->product name behaviour, which
545 // will be changed in 1607.
546 // It was agreed with Ella on 23/2/16 that the tag validation of product
547 // will be made against the old product name (before normalization),
548 // and in 1607 US will be defined where UI will no longer pass tag of
549 // component name, and BE will add it by itself after all needed
551 private Either<Boolean, ResponseFormat> validateTagsListAndRemoveDuplicates(User user, Product product, String oldProductName, AuditingActionEnum actionEnum) {
552 List<String> tagsList = product.getTags();
553 validateComponentTags(tagsList, oldProductName, ComponentTypeEnum.PRODUCT, user, product, actionEnum);
554 ValidationUtils.removeDuplicateFromList(tagsList);
555 return Either.left(true);
559 public void setDeploymentArtifactsPlaceHolder(org.openecomp.sdc.be.model.Component component, User user) {
563 public Either<Product, ResponseFormat> updateProductMetadata(String productId, Product updatedProduct, User user) {
564 ComponentTypeEnum typeEnum = ComponentTypeEnum.PRODUCT;
565 user = validateUser(user, "Update Product", updatedProduct, null, false);
566 // validate user role
567 validateUserRole(user, updatedProduct, updateRoles, null, null);
568 if (updatedProduct == null) {
569 log.debug("Invalid product json. Check product servlet log for updateProduct entry params");
570 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
571 return Either.right(responseFormat);
574 Either<Product, StorageOperationStatus> storageStatus = toscaOperationFacade.getToscaElement(productId);
575 if (storageStatus.isRight()) {
576 if (storageStatus.right().value().equals(StorageOperationStatus.NOT_FOUND)) {
577 return Either.right(componentsUtils.getResponseFormat(ActionStatus.PRODUCT_NOT_FOUND, ComponentTypeEnum.PRODUCT.name().toLowerCase()));
579 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(storageStatus.right().value(), typeEnum), ""));
582 Product currentProduct = storageStatus.left().value();
584 if (!ComponentValidationUtils.canWorkOnComponent(productId, toscaOperationFacade, user.getUserId())) {
585 log.info("Restricted operation for user: {}, on product: {}" , user.getUserId(), currentProduct.getCreatorUserId());
586 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;
595 Product productToUpdate = validationRsponse.left().value();
597 Either<Boolean, ResponseFormat> lockResult = lockComponent(currentProduct.getUniqueId(), currentProduct, "Update Product Metadata");
598 if (lockResult.isRight()) {
599 return Either.right(lockResult.right().value());
602 Either<Product, StorageOperationStatus> updateResponse = toscaOperationFacade.updateToscaElement(productToUpdate);
603 if (updateResponse.isRight()) {
604 toscaOperationFacade.rollback();
605 log.debug("failed to update product {}", productToUpdate.getUniqueId());
606 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
608 toscaOperationFacade.commit();
609 return Either.left(updateResponse.left().value());
611 graphLockOperation.unlockComponent(productId, NodeTypeEnum.Product);
615 private Either<Product, ResponseFormat> validateAndUpdateProductMetadata(User user, Product currentProduct, Product updatedProduct) {
617 boolean hasBeenCertified = ValidationUtils.hasBeenCertified(currentProduct.getVersion());
618 Either<Boolean, ResponseFormat> response = validateAndUpdateProductName(user, currentProduct, updatedProduct);
619 if (response.isRight()) {
620 ResponseFormat errorResponse = response.right().value();
621 return Either.right(errorResponse);
624 response = validateAndUpdateFullName(user, currentProduct, updatedProduct);
625 if (response.isRight()) {
626 ResponseFormat errorResponse = response.right().value();
627 return Either.right(errorResponse);
630 response = validateAndUpdateDescription(user, currentProduct, updatedProduct, null);
631 if (response.isRight()) {
632 ResponseFormat errorResponse = response.right().value();
633 return Either.right(errorResponse);
636 response = validateAndUpdateCategory(user, currentProduct, updatedProduct);
637 if (response.isRight()) {
638 ResponseFormat errorResponse = response.right().value();
639 return Either.right(errorResponse);
642 response = validateAndUpdateContactList(user, currentProduct, updatedProduct);
643 if (response.isRight()) {
644 ResponseFormat errorResponse = response.right().value();
645 return Either.right(errorResponse);
648 response = validateAndUpdateTags(user, currentProduct, updatedProduct);
649 if (response.isRight()) {
650 ResponseFormat errorResponse = response.right().value();
651 return Either.right(errorResponse);
654 response = validateAndUpdateProjectCode(user, currentProduct, updatedProduct);
655 if (response.isRight()) {
656 ResponseFormat errorResponse = response.right().value();
657 return Either.right(errorResponse);
660 if (updatedProduct.getIsActive() != null) {
661 currentProduct.setIsActive(updatedProduct.getIsActive());
664 response = validateAndUpdateIcon(user, currentProduct, updatedProduct, hasBeenCertified);
665 if (response.isRight()) {
666 ResponseFormat errorResponse = response.right().value();
667 return Either.right(errorResponse);
670 String currentInvariantUuid = currentProduct.getInvariantUUID();
671 String updatedInvariantUuid = updatedProduct.getInvariantUUID();
673 if ((updatedInvariantUuid != null) && (!updatedInvariantUuid.equals(currentInvariantUuid))) {
674 log.warn("Product invariant UUID is automatically set and cannot be updated");
675 updatedProduct.setInvariantUUID(currentInvariantUuid);
677 return Either.left(currentProduct);
681 private Either<Boolean, ResponseFormat> validateAndUpdateProductName(User user, Product currentProduct, Product updatedProduct) {
682 String updatedProductName = updatedProduct.getName();
684 String currentProductName = currentProduct.getName();
685 if (updatedProductName != null) {
686 Either<Boolean, ResponseFormat> validatProductNameResponse = validateProductNameAndCleanup(user, updatedProduct, null);
687 if (validatProductNameResponse.isRight()) {
688 ResponseFormat errorRespons = validatProductNameResponse.right().value();
689 return Either.right(errorRespons);
691 updatedProductName = updatedProduct.getName();
692 if (!currentProductName.equals(updatedProductName)) {
693 Either<Boolean, ResponseFormat> productNameUniquenessValidation = validateComponentNameUnique(user, updatedProduct, null);
694 if (productNameUniquenessValidation.isRight()) {
695 return productNameUniquenessValidation;
697 currentProduct.setName(updatedProductName);
698 tags = updatedProductName;
699 updatedProductName = ValidationUtils.normalizeCategoryName4Display(updatedProductName);
700 currentProduct.getComponentMetadataDefinition().getMetadataDataDefinition().setNormalizedName(ValidationUtils.normaliseComponentName(updatedProductName));
701 List<String> updatedTags = updatedProduct.getTags();
702 // As discussed with Ella currently (1604) we are not removing
703 // the old name from tags.
704 if (updatedTags == null) {
705 updatedTags = currentProduct.getTags();
707 updatedTags.add(tags);
710 return Either.left(true);
713 private Either<Boolean, ResponseFormat> validateAndUpdateFullName(User user, Product currentProduct, Product updatedProduct) {
714 String updatedProductName = updatedProduct.getFullName();
715 String currentProductName = currentProduct.getFullName();
716 if (updatedProductName != null && !currentProductName.equals(updatedProductName)) {
717 Either<Boolean, ResponseFormat> validatProductNameResponse = validateProductFullNameAndCleanup(user, updatedProduct, null);
718 if (validatProductNameResponse.isRight()) {
719 ResponseFormat errorRespons = validatProductNameResponse.right().value();
720 return Either.right(errorRespons);
722 currentProduct.setFullName(updatedProduct.getFullName());
724 return Either.left(true);
727 private Either<Boolean, ResponseFormat> validateAndUpdateCategory(User user, Product currentProduct, Product updatedProduct) {
729 Either<Boolean, ResponseFormat> validateCategoryResponse = validateGrouping(user, updatedProduct, null);
730 if (validateCategoryResponse.isRight()) {
731 ResponseFormat errorResponse = validateCategoryResponse.right().value();
732 return Either.right(errorResponse);
735 List<CategoryDefinition> categoryUpdated = updatedProduct.getCategories();
736 if (categoryUpdated != null) {
737 currentProduct.setCategories(categoryUpdated);
739 return Either.left(true);
742 private Either<Boolean, ResponseFormat> validateAndUpdateContactList(User user, Product currentProduct, Product updatedProduct) {
743 List<String> updatedContacts = updatedProduct.getContacts();
744 List<String> currentContacts = currentProduct.getContacts();
745 if (updatedContacts != null) {
746 if (!(currentContacts.containsAll(updatedContacts) && updatedContacts.containsAll(currentContacts))) {
747 Either<Boolean, ResponseFormat> validatResponse = validateAndUpdateProductContactsList(user, updatedProduct, null);
748 if (validatResponse.isRight()) {
749 ResponseFormat errorRespons = validatResponse.right().value();
750 return Either.right(errorRespons);
752 currentProduct.setContacts(updatedProduct.getContacts());
755 return Either.left(true);
758 private Either<Boolean, ResponseFormat> validateAndUpdateTags(User user, Product currentProduct, Product updatedProduct) {
759 List<String> tagsUpdated = updatedProduct.getTags();
760 List<String> tagsCurrent = currentProduct.getTags();
761 if (tagsUpdated != null) {
762 if (!(tagsCurrent.containsAll(tagsUpdated) && tagsUpdated.containsAll(tagsCurrent))) {
763 Either<Boolean, ResponseFormat> validatResponse = validateTagsListAndRemoveDuplicates(user, updatedProduct, currentProduct.getName(), null);
764 if (validatResponse.isRight()) {
765 ResponseFormat errorRespons = validatResponse.right().value();
766 return Either.right(errorRespons);
768 currentProduct.setTags(updatedProduct.getTags());
771 return Either.left(true);
775 public Either<List<String>, ResponseFormat> deleteMarkedComponents() {
776 // markAsDeleted isnt implemented yet
777 return Either.left(new ArrayList<>());
781 protected boolean validateTagPattern(String tag) {
782 return ValidationUtils.validateCategoryDisplayNameFormat(tag);
785 public Either<Product, ResponseFormat> getProductByNameAndVersion(String productName, String productVersion, String userId) {
786 validateUserExists(userId, "get Service By Name And Version", false);
787 Either<Product, StorageOperationStatus> storageStatus = toscaOperationFacade.getComponentByNameAndVersion(ComponentTypeEnum.PRODUCT, productName, productVersion);
788 if (storageStatus.isRight()) {
789 log.debug("failed to get service by name {} and version {}", productName, productVersion);
790 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(storageStatus.right().value(), ComponentTypeEnum.PRODUCT), productName));
792 Product product = storageStatus.left().value();
793 return Either.left(product);
797 public ComponentInstanceBusinessLogic getComponentInstanceBL() {
798 return componentInstanceBusinessLogic;
802 public Either<List<ComponentInstance>, ResponseFormat> getComponentInstancesFilteredByPropertiesAndInputs(String componentId, String userId) {
806 public ICacheMangerOperation getCacheManagerOperation() {
807 return cacheManagerOperation;
810 public void setCacheManagerOperation(ICacheMangerOperation cacheManagerOperation) {
811 this.cacheManagerOperation = cacheManagerOperation;
815 public Either<UiComponentDataTransfer, ResponseFormat> getUiComponentDataTransferByComponentId(String componentId,
816 List<String> dataParamsToReturn) {
817 // TODO Auto-generated method stub