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=========================================================
21 package org.openecomp.sdc.be.components.impl;
23 import fj.data.Either;
24 import org.openecomp.sdc.be.components.impl.exceptions.ComponentException;
25 import org.openecomp.sdc.be.dao.api.ActionStatus;
26 import org.openecomp.sdc.be.datamodel.api.CategoryTypeEnum;
27 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
28 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
29 import org.openecomp.sdc.be.model.ComponentInstance;
30 import org.openecomp.sdc.be.model.LifecycleStateEnum;
31 import org.openecomp.sdc.be.model.Product;
32 import org.openecomp.sdc.be.model.User;
33 import org.openecomp.sdc.be.model.category.CategoryDefinition;
34 import org.openecomp.sdc.be.model.category.GroupingDefinition;
35 import org.openecomp.sdc.be.model.category.SubCategoryDefinition;
36 import org.openecomp.sdc.be.model.operations.api.ICacheMangerOperation;
37 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
38 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
39 import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils;
40 import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
41 import org.openecomp.sdc.be.ui.model.UiComponentDataTransfer;
42 import org.openecomp.sdc.be.user.Role;
43 import org.openecomp.sdc.common.log.wrappers.Logger;
44 import org.openecomp.sdc.common.util.ValidationUtils;
45 import org.openecomp.sdc.exception.ResponseFormat;
46 import org.springframework.beans.factory.annotation.Autowired;
49 import java.util.stream.Collectors;
51 @org.springframework.stereotype.Component("productBusinessLogic")
52 public class ProductBusinessLogic extends ComponentBusinessLogic {
54 private static final String PRODUCT_FULL_NAME = "full";
55 private static final String PRODUCT_ABBREVIATED_NAME = "abbreviated";
56 private static final Logger log = Logger.getLogger(ProductBusinessLogic.class);
57 private static final String INITIAL_VERSION = "0.1";
58 private static final String CREATE_PRODUCT = "Create Product";
59 private static List<Role> creationRoles;
60 private static List<Role> updateRoles;
61 private static List<Role> contactsRoles;
63 public ProductBusinessLogic() {
64 creationRoles = new ArrayList<>();
65 updateRoles = new ArrayList<>();
66 contactsRoles = new ArrayList<>();
68 // only PM is allowed to create/update products
69 creationRoles.add(Role.PRODUCT_MANAGER);
70 updateRoles.add(Role.PRODUCT_MANAGER);
71 // Only PM is allowed to be product contacts
72 contactsRoles.add(Role.PRODUCT_MANAGER);
76 private ComponentInstanceBusinessLogic componentInstanceBusinessLogic;
79 private ICacheMangerOperation cacheManagerOperation;
81 public Either<Product, ResponseFormat> createProduct(Product product, User user) {
82 AuditingActionEnum actionEnum = AuditingActionEnum.CREATE_RESOURCE;
83 ComponentTypeEnum typeEnum = ComponentTypeEnum.PRODUCT;
85 // validate user - should be first to get the maximum auditing info in
86 // case of subsequent failures
87 log.debug("get user from DB");
88 user = validateUser(user, CREATE_PRODUCT, product, actionEnum, false);
90 validateUserRole(user, product, creationRoles, actionEnum, null);
92 if (product == null) {
93 log.debug("Invalid product json. Check product servlet log for createProduct entry params");
94 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
95 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, typeEnum);
96 return Either.right(responseFormat);
99 // warn about non-updatable fields
100 checkUnupdatableProductFields(product);
102 Either<Product, ResponseFormat> validateProductResponse = validateProductBeforeCreate(product, user, actionEnum);
103 if (validateProductResponse.isRight()) {
104 return Either.right(validateProductResponse.right().value());
107 log.debug("send product {} to dao for create", product.getComponentMetadataDefinition().getMetadataDataDefinition().getName());
109 Either<Boolean, ResponseFormat> lockResult = lockComponentByName(product.getSystemName(), product, CREATE_PRODUCT);
110 if (lockResult.isRight()) {
111 ResponseFormat responseFormat = lockResult.right().value();
112 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
113 return Either.right(responseFormat);
116 log.debug("Product name locked is {}, status = {}", product.getSystemName(), lockResult);
119 Either<Product, StorageOperationStatus> createProductEither = toscaOperationFacade.createToscaComponent(product);
121 if (createProductEither.isRight()) {
122 ResponseFormat responseFormat = componentsUtils.getResponseFormatByComponent(componentsUtils.convertFromStorageResponse(createProductEither.right().value()), product, typeEnum);
123 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, typeEnum);
124 return Either.right(responseFormat);
127 log.debug("Product created successfully");
128 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.CREATED);
129 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, typeEnum);
131 Product createdProduct = createProductEither.left().value();
133 return Either.left(createdProduct);
136 graphLockOperation.unlockComponentByName(product.getSystemName(), product.getUniqueId(), NodeTypeEnum.Product);
141 private void checkUnupdatableProductFields(Product product) {
142 checkComponentFieldsForOverrideAttempt(product);
143 if (product.getNormalizedName() != null) {
144 log.info("NormalizedName cannot be defined by user. This field will be overridden by the application");
148 private Either<Product, ResponseFormat> validateProductBeforeCreate(Product product, User user, AuditingActionEnum actionEnum) {
150 Either<Boolean, ResponseFormat> validateProductFields = validateProductFieldsBeforeCreate(user, product, actionEnum);
151 if (validateProductFields.isRight()) {
152 return Either.right(validateProductFields.right().value());
155 if (product.getIsActive() == null) {
156 log.debug("no isActive value was provided, setting to default: false");
157 product.setIsActive(false);
160 product.setCreatorUserId(user.getUserId());
163 log.debug("enrich product with version and state");
164 product.setState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT);
165 product.setVersion(INITIAL_VERSION);
167 // Generate invariant UUID - must be here and not in operation since it
168 // should stay constant during clone
169 String invariantUUID = UniqueIdBuilder.buildInvariantUUID();
170 product.setInvariantUUID(invariantUUID);
172 return Either.left(product);
175 private Either<Boolean, ResponseFormat> validateProductFieldsBeforeCreate(User user, Product product, AuditingActionEnum actionEnum) {
177 // To be removed in 1607
179 String oldName = product.getName();
181 Either<Boolean, ResponseFormat> componentNameValidation = validateProductNameAndCleanup(user, product, actionEnum);
182 if (componentNameValidation.isRight()) {
183 return componentNameValidation;
186 Either<Boolean, ResponseFormat> componentNameUniquenessValidation = validateComponentNameUnique(user, product, actionEnum);
187 if (componentNameUniquenessValidation.isRight()) {
188 return componentNameUniquenessValidation;
191 // To be removed in 1607 and replaced with generic
192 // validateTagsListAndRemoveDuplicates()
193 // See comments on the validateTagsListAndRemoveDuplicates(user,
194 // product, oldName, actionEnum) function
195 Either<Boolean, ResponseFormat> tagsValidation = validateTagsListAndRemoveDuplicates(user, product, oldName, actionEnum);
196 if (tagsValidation.isRight()) {
197 return tagsValidation;
200 validateIcon(user, product, actionEnum);
202 Either<Boolean, ResponseFormat> projectCodeValidation = validateProjectCode(user, product, actionEnum);
203 if (projectCodeValidation.isRight()) {
204 return projectCodeValidation;
206 Either<Boolean, ResponseFormat> categoryValidation = validateGrouping(user, product, actionEnum);
207 if (categoryValidation.isRight()) {
208 return categoryValidation;
211 Either<Boolean, ResponseFormat> contactsListValidation = validateAndUpdateProductContactsList(user, product, actionEnum);
212 if (contactsListValidation.isRight()) {
213 return contactsListValidation;
216 Either<Boolean, ResponseFormat> productFullNameValidation = validateProductFullNameAndCleanup(user, product, actionEnum);
217 if (productFullNameValidation.isRight()) {
218 return productFullNameValidation;
221 validateDescriptionAndCleanup(user, product, actionEnum);
223 return Either.left(true);
226 public Either<Map<String, Boolean>, ResponseFormat> validateProductNameExists(String productName, String userId) {
228 validateUserExists(userId, "validate Product Name Exists", false);
229 Either<Boolean, StorageOperationStatus> dataModelResponse = toscaOperationFacade.validateComponentNameUniqueness(productName, null, ComponentTypeEnum.PRODUCT);
233 if (dataModelResponse.isLeft()) {
234 Map<String, Boolean> result = new HashMap<>();
235 result.put("isValid", dataModelResponse.left().value());
236 log.debug("validation was successfully performed.");
237 return Either.left(result);
240 ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(dataModelResponse.right().value()));
242 return Either.right(responseFormat);
245 private Either<Boolean, ResponseFormat> validateAndUpdateProductContactsList(User user, Product product, AuditingActionEnum actionEnum) {
246 List<String> contacts = product.getContacts();
247 if (!ValidationUtils.validateListNotEmpty(contacts)) {
248 log.debug("Contacts list cannot be empty for product {}", product.getName());
249 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.EMPTY_PRODUCT_CONTACTS_LIST);
250 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
251 return Either.right(responseFormat);
254 boolean isProductCreatorInContacts = false;
255 String modifierUserId = user.getUserId();
256 for (String contact : contacts) {
257 if (contact.equals(modifierUserId)) {
258 log.trace("modifier userId found in product contacts");
259 isProductCreatorInContacts = true;
260 // No need to validate for this userId - it's modifier's
263 if (!ValidationUtils.validateContactId(contact)) {
264 log.debug("Product contacts has invalid userId {} for product {}", contact, product.getName());
265 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_INVALID_CONTACT, ComponentTypeEnum.PRODUCT.getValue());
266 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
267 return Either.right(responseFormat);
272 contactUser = validateUserExists(contact, CREATE_PRODUCT, false);
273 validateUserRole(contactUser, contactsRoles);
274 } catch(ComponentException e){
275 log.debug("Cannot set contact with userId {} as product contact, error: {}", contact, e.getActionStatus());
276 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_PRODUCT_CONTACT, contact);
277 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
278 throw new ComponentException(e.getActionStatus(), e.getParams());
282 if (!isProductCreatorInContacts) {
283 log.debug("modifier userId {} not found in product contacts - adding it", modifierUserId);
284 contacts.add(modifierUserId);
287 // passed - setting all contacts userIds to lowercase
288 List<String> tempContacts = contacts.stream()
289 .map(String::toLowerCase)
290 .collect(Collectors.toList());
291 ValidationUtils.removeDuplicateFromList(tempContacts);
292 product.setContacts(tempContacts);
294 return Either.left(true);
297 private Either<Boolean, ResponseFormat> validateGrouping(User user, Product product, AuditingActionEnum actionEnum) {
298 List<CategoryDefinition> categories = product.getCategories();
299 if (categories == null || categories.isEmpty()) {
300 log.debug("Grouping list is empty for product: {}", product.getName());
301 return Either.left(true);
303 Map<String, Map<String, Set<String>>> nonDuplicatedCategories = new HashMap<>();
304 // remove duplicated entries
305 for (CategoryDefinition cat : categories) {
306 String catName = cat.getName();
307 if (!ValidationUtils.validateStringNotEmpty(catName)) {
308 // error missing cat name
309 log.debug("Missing category name for product: {}", product.getName());
310 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_CATEGORY, ComponentTypeEnum.PRODUCT.getValue());
311 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
312 return Either.right(responseFormat);
314 Map<String, Set<String>> catEntry = nonDuplicatedCategories.get(catName);
315 if (catEntry == null) {
316 catEntry = new HashMap<>();
317 nonDuplicatedCategories.put(catName, catEntry);
319 List<SubCategoryDefinition> subcategories = cat.getSubcategories();
320 if (subcategories == null || subcategories.isEmpty()) {
321 // error missing subcat for cat
322 log.debug("Missing sub-categories for category {} in product {}", catName, product.getName());
323 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_SUBCATEGORY);
324 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
325 return Either.right(responseFormat);
327 for (SubCategoryDefinition subcat : subcategories) {
328 String subCatName = subcat.getName();
329 if (!ValidationUtils.validateStringNotEmpty(subCatName)) {
330 // error missing sub cat name for cat
331 log.debug("Missing or empty sub-category for category {} in product {}", catName, product.getName());
332 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_SUBCATEGORY);
333 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
334 return Either.right(responseFormat);
336 Set<String> subcatEntry = catEntry.get(subCatName);
337 if (subcatEntry == null) {
338 subcatEntry = new HashSet<>();
339 catEntry.put(subCatName, subcatEntry);
341 List<GroupingDefinition> groupings = subcat.getGroupings();
342 for (GroupingDefinition group : groupings) {
343 String groupName = group.getName();
344 if (!ValidationUtils.validateStringNotEmpty(groupName)) {
345 // error missing grouping for sub cat name and cat
346 log.debug("Missing or empty groupng name for sub-category: {} for categor: {} in product: {}", subCatName, catName, product.getName());
347 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_SUBCATEGORY);
348 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
349 return Either.right(responseFormat);
351 if (!subcatEntry.contains(groupName)) {
352 subcatEntry.add(groupName);
354 log.debug("Grouping: {}, already exist for category: {} and subcategory: {}", groupName, catName, subCatName);
358 } // for end of checking duplicated
359 // validate existence
360 Either<List<CategoryDefinition>, ActionStatus> allProductCategories = elementDao.getAllProductCategories();
362 if (allProductCategories.isRight()) {
363 log.debug("No product categories {}", allProductCategories.right().value());
364 ResponseFormat responseFormat = componentsUtils.getResponseFormat(allProductCategories.right().value());
365 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
366 return Either.right(responseFormat);
369 // convert non-duplicated to data modeling format and update in the
371 List<CategoryDefinition> newCatList = new ArrayList<>();
373 // over all categories from request
374 for (Map.Entry<String, Map<String, Set<String>>> entry : nonDuplicatedCategories.entrySet()) {
376 CategoryDefinition categoryDefinition = null;
377 // over all categories from Titan
378 List<CategoryDefinition> categoriesList = allProductCategories.left().value();
379 if (categoriesList != null) {
380 for (CategoryDefinition catInDb : categoriesList) {
381 if (entry.getKey().equals(catInDb.getName())) {
385 categoryDefinition = new CategoryDefinition(catInDb);
386 SubCategoryDefinition subCategory = null;
388 Map<String, Set<String>> subcats = entry.getValue();
389 for (Map.Entry<String, Set<String>> subcat : subcats.entrySet()) {
391 List<SubCategoryDefinition> subcategoriesList = catInDb.getSubcategories();
392 if (subcategoriesList != null) {
393 for (SubCategoryDefinition subcatInDb : subcategoriesList) {
394 if (subcatInDb.getName().equals(subcat.getKey())) {
396 subCategory = new SubCategoryDefinition(subcatInDb);
398 Set<String> grouping = subcat.getValue();
400 GroupingDefinition groupingDefinition = null;
401 for (String group : grouping) {
403 List<GroupingDefinition> groupings = subcatInDb.getGroupings();
404 if (groupings != null) {
405 for (GroupingDefinition groupInDb : groupings) {
406 if (groupInDb.getName().equals(group)) {
408 groupingDefinition = new GroupingDefinition(groupInDb);
413 // error grouping isn't defined
415 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_GROUP_ASSOCIATION, CategoryTypeEnum.GROUPING.getValue(), group);
416 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
417 return Either.right(responseFormat);
419 subCategory.addGrouping(groupingDefinition);
425 // error sub category isn't defined in Titan
426 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_GROUP_ASSOCIATION, CategoryTypeEnum.SUBCATEGORY.getValue(), subcat.getKey());
427 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
428 return Either.right(responseFormat);
430 categoryDefinition.addSubCategory(subCategory);
436 // error category isn't defined in Titan
437 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_GROUP_ASSOCIATION, CategoryTypeEnum.CATEGORY.getValue(), entry.getKey());
438 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
439 return Either.right(responseFormat);
441 newCatList.add(categoryDefinition);
443 product.setCategories(newCatList);
444 return Either.left(true);
447 public Either<Product, ResponseFormat> getProduct(String productId, User user) {
448 String ecompErrorContext = "Get product";
449 validateUserNotEmpty(user, ecompErrorContext);
450 validateUserExists(user, ecompErrorContext, false);
452 Either<Product, StorageOperationStatus> storageStatus = toscaOperationFacade.getToscaElement(productId);
454 if (storageStatus.isRight()) {
455 log.debug("failed to get resource by id {}", productId);
456 if (storageStatus.right().value().equals(StorageOperationStatus.NOT_FOUND)) {
458 return Either.right(componentsUtils.getResponseFormat(ActionStatus.PRODUCT_NOT_FOUND, ComponentTypeEnum.PRODUCT.getValue()));
460 return Either.right(componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(storageStatus.right().value()), ""));
463 return Either.left(storageStatus.left().value());
466 public Either<Product, ResponseFormat> deleteProduct(String productId, User user) {
467 String ecompErrorContext = "Delete product";
468 validateUserNotEmpty(user, ecompErrorContext);
469 validateUserExists(user, ecompErrorContext, false);
471 Either<Product, StorageOperationStatus> storageStatus = toscaOperationFacade.deleteToscaComponent(productId);
473 if (storageStatus.isRight()) {
474 log.debug("failed to delete resource by id {}", productId);
475 return Either.right(componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(storageStatus.right().value()), ""));
477 return Either.left(storageStatus.left().value());
480 private Either<Boolean, ResponseFormat> validateProductFullNameAndCleanup(User user, Product product, AuditingActionEnum actionEnum) {
481 String fullName = product.getFullName();
482 if (!ValidationUtils.validateStringNotEmpty(fullName)) {
483 ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.MISSING_ONE_OF_COMPONENT_NAMES, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_FULL_NAME);
484 componentsUtils.auditComponentAdmin(errorResponse, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
485 return Either.right(errorResponse);
488 fullName = ValidationUtils.removeNoneUtf8Chars(fullName);
489 fullName = ValidationUtils.removeHtmlTags(fullName);
490 fullName = ValidationUtils.normaliseWhitespace(fullName);
491 fullName = ValidationUtils.stripOctets(fullName);
493 if (!ValidationUtils.validateProductFullNameLength(fullName)) {
494 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_FULL_NAME);
495 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
496 return Either.right(responseFormat);
499 if (!ValidationUtils.validateIsEnglish(fullName)) {
500 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_FULL_NAME);
501 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
502 return Either.right(responseFormat);
505 product.setFullName(fullName);
506 return Either.left(true);
509 private Either<Boolean, ResponseFormat> validateProductNameAndCleanup(User user, Product product, AuditingActionEnum actionEnum) {
510 String name = product.getName();
511 if (!ValidationUtils.validateStringNotEmpty(name)) {
512 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.MISSING_ONE_OF_COMPONENT_NAMES, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_ABBREVIATED_NAME);
513 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
514 return Either.right(responseFormat);
517 // Product name is required to have same validation and normalization as
519 if (!ValidationUtils.validateCategoryDisplayNameFormat(name)) {
520 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_ABBREVIATED_NAME);
521 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
522 return Either.right(responseFormat);
525 String normalizedName4Display = ValidationUtils.normalizeCategoryName4Display(name);
527 if (!ValidationUtils.validateCategoryDisplayNameLength(normalizedName4Display)) {
528 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_ABBREVIATED_NAME);
529 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
530 return Either.right(responseFormat);
533 product.setName(normalizedName4Display);
534 String normalizedName4Uniqueness = ValidationUtils.normaliseComponentName(normalizedName4Display);
535 product.setNormalizedName(normalizedName4Uniqueness);
537 return Either.left(true);
540 // This is a workaround for a current tag--->product name behaviour, which
541 // will be changed in 1607.
542 // It was agreed with Ella on 23/2/16 that the tag validation of product
543 // will be made against the old product name (before normalization),
544 // and in 1607 US will be defined where UI will no longer pass tag of
545 // component name, and BE will add it by itself after all needed
547 private Either<Boolean, ResponseFormat> validateTagsListAndRemoveDuplicates(User user, Product product, String oldProductName, AuditingActionEnum actionEnum) {
548 List<String> tagsList = product.getTags();
549 validateComponentTags(tagsList, oldProductName, ComponentTypeEnum.PRODUCT, user, product, actionEnum);
550 ValidationUtils.removeDuplicateFromList(tagsList);
551 return Either.left(true);
555 public void setDeploymentArtifactsPlaceHolder(org.openecomp.sdc.be.model.Component component, User user) {
559 public Either<Product, ResponseFormat> updateProductMetadata(String productId, Product updatedProduct, User user) {
560 ComponentTypeEnum typeEnum = ComponentTypeEnum.PRODUCT;
561 user = validateUser(user, "Update Product", updatedProduct, null, false);
562 // validate user role
563 validateUserRole(user, updatedProduct, updateRoles, null, null);
564 if (updatedProduct == null) {
565 log.debug("Invalid product json. Check product servlet log for updateProduct entry params");
566 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
567 return Either.right(responseFormat);
570 Either<Product, StorageOperationStatus> storageStatus = toscaOperationFacade.getToscaElement(productId);
571 if (storageStatus.isRight()) {
572 if (storageStatus.right().value().equals(StorageOperationStatus.NOT_FOUND)) {
573 return Either.right(componentsUtils.getResponseFormat(ActionStatus.PRODUCT_NOT_FOUND, ComponentTypeEnum.PRODUCT.name().toLowerCase()));
575 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(storageStatus.right().value(), typeEnum), ""));
578 Product currentProduct = storageStatus.left().value();
580 if (!ComponentValidationUtils.canWorkOnComponent(productId, toscaOperationFacade, user.getUserId())) {
581 log.info("Restricted operation for user: {}, on product: {}" , user.getUserId(), currentProduct.getCreatorUserId());
582 return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
585 Either<Product, ResponseFormat> validationRsponse = validateAndUpdateProductMetadata(user, currentProduct, updatedProduct);
586 if (validationRsponse.isRight()) {
587 log.info("product update metadata: validations field.");
588 return validationRsponse;
591 Product productToUpdate = validationRsponse.left().value();
593 Either<Boolean, ResponseFormat> lockResult = lockComponent(currentProduct.getUniqueId(), currentProduct, "Update Product Metadata");
594 if (lockResult.isRight()) {
595 return Either.right(lockResult.right().value());
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) {
613 boolean hasBeenCertified = ValidationUtils.hasBeenCertified(currentProduct.getVersion());
614 Either<Boolean, ResponseFormat> response = validateAndUpdateProductName(user, currentProduct, updatedProduct);
615 if (response.isRight()) {
616 ResponseFormat errorResponse = response.right().value();
617 return Either.right(errorResponse);
620 response = validateAndUpdateFullName(user, currentProduct, updatedProduct);
621 if (response.isRight()) {
622 ResponseFormat errorResponse = response.right().value();
623 return Either.right(errorResponse);
626 response = validateAndUpdateDescription(user, currentProduct, updatedProduct, null);
627 if (response.isRight()) {
628 ResponseFormat errorResponse = response.right().value();
629 return Either.right(errorResponse);
632 response = validateAndUpdateCategory(user, currentProduct, updatedProduct);
633 if (response.isRight()) {
634 ResponseFormat errorResponse = response.right().value();
635 return Either.right(errorResponse);
638 response = validateAndUpdateContactList(user, currentProduct, updatedProduct);
639 if (response.isRight()) {
640 ResponseFormat errorResponse = response.right().value();
641 return Either.right(errorResponse);
644 response = validateAndUpdateTags(user, currentProduct, updatedProduct);
645 if (response.isRight()) {
646 ResponseFormat errorResponse = response.right().value();
647 return Either.right(errorResponse);
650 response = validateAndUpdateProjectCode(user, currentProduct, updatedProduct);
651 if (response.isRight()) {
652 ResponseFormat errorResponse = response.right().value();
653 return Either.right(errorResponse);
656 if (updatedProduct.getIsActive() != null) {
657 currentProduct.setIsActive(updatedProduct.getIsActive());
660 response = validateAndUpdateIcon(user, currentProduct, updatedProduct, hasBeenCertified);
661 if (response.isRight()) {
662 ResponseFormat errorResponse = response.right().value();
663 return Either.right(errorResponse);
666 String currentInvariantUuid = currentProduct.getInvariantUUID();
667 String updatedInvariantUuid = updatedProduct.getInvariantUUID();
669 if ((updatedInvariantUuid != null) && (!updatedInvariantUuid.equals(currentInvariantUuid))) {
670 log.warn("Product invariant UUID is automatically set and cannot be updated");
671 updatedProduct.setInvariantUUID(currentInvariantUuid);
673 return Either.left(currentProduct);
677 private Either<Boolean, ResponseFormat> validateAndUpdateProductName(User user, Product currentProduct, Product updatedProduct) {
678 String updatedProductName = updatedProduct.getName();
680 String currentProductName = currentProduct.getName();
681 if (updatedProductName != null) {
682 Either<Boolean, ResponseFormat> validatProductNameResponse = validateProductNameAndCleanup(user, updatedProduct, null);
683 if (validatProductNameResponse.isRight()) {
684 ResponseFormat errorRespons = validatProductNameResponse.right().value();
685 return Either.right(errorRespons);
687 updatedProductName = updatedProduct.getName();
688 if (!currentProductName.equals(updatedProductName)) {
689 Either<Boolean, ResponseFormat> productNameUniquenessValidation = validateComponentNameUnique(user, updatedProduct, null);
690 if (productNameUniquenessValidation.isRight()) {
691 return productNameUniquenessValidation;
693 currentProduct.setName(updatedProductName);
694 tags = updatedProductName;
695 updatedProductName = ValidationUtils.normalizeCategoryName4Display(updatedProductName);
696 currentProduct.getComponentMetadataDefinition().getMetadataDataDefinition().setNormalizedName(ValidationUtils.normaliseComponentName(updatedProductName));
697 List<String> updatedTags = updatedProduct.getTags();
698 // As discussed with Ella currently (1604) we are not removing
699 // the old name from tags.
700 if (updatedTags == null) {
701 updatedTags = currentProduct.getTags();
703 updatedTags.add(tags);
706 return Either.left(true);
709 private Either<Boolean, ResponseFormat> validateAndUpdateFullName(User user, Product currentProduct, Product updatedProduct) {
710 String updatedProductName = updatedProduct.getFullName();
711 String currentProductName = currentProduct.getFullName();
712 if (updatedProductName != null && !currentProductName.equals(updatedProductName)) {
713 Either<Boolean, ResponseFormat> validatProductNameResponse = validateProductFullNameAndCleanup(user, updatedProduct, null);
714 if (validatProductNameResponse.isRight()) {
715 ResponseFormat errorRespons = validatProductNameResponse.right().value();
716 return Either.right(errorRespons);
718 currentProduct.setFullName(updatedProduct.getFullName());
720 return Either.left(true);
723 private Either<Boolean, ResponseFormat> validateAndUpdateCategory(User user, Product currentProduct, Product updatedProduct) {
725 Either<Boolean, ResponseFormat> validateCategoryResponse = validateGrouping(user, updatedProduct, null);
726 if (validateCategoryResponse.isRight()) {
727 ResponseFormat errorResponse = validateCategoryResponse.right().value();
728 return Either.right(errorResponse);
731 List<CategoryDefinition> categoryUpdated = updatedProduct.getCategories();
732 if (categoryUpdated != null) {
733 currentProduct.setCategories(categoryUpdated);
735 return Either.left(true);
738 private Either<Boolean, ResponseFormat> validateAndUpdateContactList(User user, Product currentProduct, Product updatedProduct) {
739 List<String> updatedContacts = updatedProduct.getContacts();
740 List<String> currentContacts = currentProduct.getContacts();
741 if (updatedContacts != null) {
742 if (!(currentContacts.containsAll(updatedContacts) && updatedContacts.containsAll(currentContacts))) {
743 Either<Boolean, ResponseFormat> validatResponse = validateAndUpdateProductContactsList(user, updatedProduct, null);
744 if (validatResponse.isRight()) {
745 ResponseFormat errorRespons = validatResponse.right().value();
746 return Either.right(errorRespons);
748 currentProduct.setContacts(updatedProduct.getContacts());
751 return Either.left(true);
754 private Either<Boolean, ResponseFormat> validateAndUpdateTags(User user, Product currentProduct, Product updatedProduct) {
755 List<String> tagsUpdated = updatedProduct.getTags();
756 List<String> tagsCurrent = currentProduct.getTags();
757 if (tagsUpdated != null) {
758 if (!(tagsCurrent.containsAll(tagsUpdated) && tagsUpdated.containsAll(tagsCurrent))) {
759 Either<Boolean, ResponseFormat> validatResponse = validateTagsListAndRemoveDuplicates(user, updatedProduct, currentProduct.getName(), null);
760 if (validatResponse.isRight()) {
761 ResponseFormat errorRespons = validatResponse.right().value();
762 return Either.right(errorRespons);
764 currentProduct.setTags(updatedProduct.getTags());
767 return Either.left(true);
771 public Either<List<String>, ResponseFormat> deleteMarkedComponents() {
772 // markAsDeleted isnt implemented yet
773 return Either.left(new ArrayList<>());
777 protected boolean validateTagPattern(String tag) {
778 return ValidationUtils.validateCategoryDisplayNameFormat(tag);
781 public Either<Product, ResponseFormat> getProductByNameAndVersion(String productName, String productVersion, String userId) {
782 validateUserExists(userId, "get Service By Name And Version", false);
783 Either<Product, StorageOperationStatus> storageStatus = toscaOperationFacade.getComponentByNameAndVersion(ComponentTypeEnum.PRODUCT, productName, productVersion);
784 if (storageStatus.isRight()) {
785 log.debug("failed to get service by name {} and version {}", productName, productVersion);
786 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(storageStatus.right().value(), ComponentTypeEnum.PRODUCT), productName));
788 Product product = storageStatus.left().value();
789 return Either.left(product);
793 public ComponentInstanceBusinessLogic getComponentInstanceBL() {
794 return componentInstanceBusinessLogic;
798 public Either<List<ComponentInstance>, ResponseFormat> getComponentInstancesFilteredByPropertiesAndInputs(String componentId, String userId) {
802 public ICacheMangerOperation getCacheManagerOperation() {
803 return cacheManagerOperation;
806 public void setCacheManagerOperation(ICacheMangerOperation cacheManagerOperation) {
807 this.cacheManagerOperation = cacheManagerOperation;
811 public Either<UiComponentDataTransfer, ResponseFormat> getUiComponentDataTransferByComponentId(String componentId,
812 List<String> dataParamsToReturn) {
813 // TODO Auto-generated method stub