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;
64 private ComponentInstanceBusinessLogic componentInstanceBusinessLogic;
67 private ICacheMangerOperation cacheManagerOperation;
69 public ProductBusinessLogic() {
70 creationRoles = new ArrayList<>();
71 updateRoles = new ArrayList<>();
72 contactsRoles = new ArrayList<>();
74 // only PM is allowed to create/update products
75 creationRoles.add(Role.PRODUCT_MANAGER);
76 updateRoles.add(Role.PRODUCT_MANAGER);
77 // Only PM is allowed to be product contacts
78 contactsRoles.add(Role.PRODUCT_MANAGER);
82 public Either<Product, ResponseFormat> createProduct(Product product, User user) {
83 AuditingActionEnum actionEnum = AuditingActionEnum.CREATE_RESOURCE;
84 ComponentTypeEnum typeEnum = ComponentTypeEnum.PRODUCT;
86 // validate user - should be first to get the maximum auditing info in
87 // case of subsequent failures
88 log.debug("get user from DB");
89 user = validateUser(user, CREATE_PRODUCT, product, actionEnum, false);
91 validateUserRole(user, product, creationRoles, actionEnum, null);
93 if (product == null) {
94 log.debug("Invalid product json. Check product servlet log for createProduct entry params");
95 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
96 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, typeEnum);
97 return Either.right(responseFormat);
100 // warn about non-updatable fields
101 checkUnupdatableProductFields(product);
103 Either<Product, ResponseFormat> validateProductResponse = validateProductBeforeCreate(product, user, actionEnum);
104 if (validateProductResponse.isRight()) {
105 return Either.right(validateProductResponse.right().value());
108 log.debug("send product {} to dao for create", product.getComponentMetadataDefinition().getMetadataDataDefinition().getName());
110 Either<Boolean, ResponseFormat> lockResult = lockComponentByName(product.getSystemName(), product, CREATE_PRODUCT);
111 if (lockResult.isRight()) {
112 ResponseFormat responseFormat = lockResult.right().value();
113 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
114 return Either.right(responseFormat);
117 log.debug("Product name locked is {}, status = {}", product.getSystemName(), lockResult);
120 Either<Product, StorageOperationStatus> createProductEither = toscaOperationFacade.createToscaComponent(product);
122 if (createProductEither.isRight()) {
123 ResponseFormat responseFormat = componentsUtils.getResponseFormatByComponent(componentsUtils.convertFromStorageResponse(createProductEither.right().value()), product, typeEnum);
124 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, typeEnum);
125 return Either.right(responseFormat);
128 log.debug("Product created successfully");
129 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.CREATED);
130 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, typeEnum);
132 Product createdProduct = createProductEither.left().value();
134 return Either.left(createdProduct);
137 graphLockOperation.unlockComponentByName(product.getSystemName(), product.getUniqueId(), NodeTypeEnum.Product);
142 private void checkUnupdatableProductFields(Product product) {
143 checkComponentFieldsForOverrideAttempt(product);
144 if (product.getNormalizedName() != null) {
145 log.info("NormalizedName cannot be defined by user. This field will be overridden by the application");
149 private Either<Product, ResponseFormat> validateProductBeforeCreate(Product product, User user, AuditingActionEnum actionEnum) {
151 Either<Boolean, ResponseFormat> validateProductFields = validateProductFieldsBeforeCreate(user, product, actionEnum);
152 if (validateProductFields.isRight()) {
153 return Either.right(validateProductFields.right().value());
156 if (product.getIsActive() == null) {
157 log.debug("no isActive value was provided, setting to default: false");
158 product.setIsActive(false);
161 product.setCreatorUserId(user.getUserId());
164 log.debug("enrich product with version and state");
165 product.setState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT);
166 product.setVersion(INITIAL_VERSION);
168 // Generate invariant UUID - must be here and not in operation since it
169 // should stay constant during clone
170 String invariantUUID = UniqueIdBuilder.buildInvariantUUID();
171 product.setInvariantUUID(invariantUUID);
173 return Either.left(product);
176 private Either<Boolean, ResponseFormat> validateProductFieldsBeforeCreate(User user, Product product, AuditingActionEnum actionEnum) {
178 // To be removed in 1607
180 String oldName = product.getName();
182 Either<Boolean, ResponseFormat> componentNameValidation = validateProductNameAndCleanup(user, product, actionEnum);
183 if (componentNameValidation.isRight()) {
184 return componentNameValidation;
187 Either<Boolean, ResponseFormat> componentNameUniquenessValidation = validateComponentNameUnique(user, product, actionEnum);
188 if (componentNameUniquenessValidation.isRight()) {
189 return componentNameUniquenessValidation;
192 // To be removed in 1607 and replaced with generic
193 // validateTagsListAndRemoveDuplicates()
194 // See comments on the validateTagsListAndRemoveDuplicates(user,
195 // product, oldName, actionEnum) function
196 Either<Boolean, ResponseFormat> tagsValidation = validateTagsListAndRemoveDuplicates(user, product, oldName, actionEnum);
197 if (tagsValidation.isRight()) {
198 return tagsValidation;
201 validateIcon(user, product, actionEnum);
203 Either<Boolean, ResponseFormat> projectCodeValidation = validateProjectCode(user, product, actionEnum);
204 if (projectCodeValidation.isRight()) {
205 return projectCodeValidation;
207 Either<Boolean, ResponseFormat> categoryValidation = validateGrouping(user, product, actionEnum);
208 if (categoryValidation.isRight()) {
209 return categoryValidation;
212 Either<Boolean, ResponseFormat> contactsListValidation = validateAndUpdateProductContactsList(user, product, actionEnum);
213 if (contactsListValidation.isRight()) {
214 return contactsListValidation;
217 Either<Boolean, ResponseFormat> productFullNameValidation = validateProductFullNameAndCleanup(user, product, actionEnum);
218 if (productFullNameValidation.isRight()) {
219 return productFullNameValidation;
222 validateDescriptionAndCleanup(user, product, actionEnum);
224 return Either.left(true);
227 public Either<Map<String, Boolean>, ResponseFormat> validateProductNameExists(String productName, String userId) {
229 validateUserExists(userId, "validate Product Name Exists", false);
230 Either<Boolean, StorageOperationStatus> dataModelResponse = toscaOperationFacade.validateComponentNameUniqueness(productName, null, ComponentTypeEnum.PRODUCT);
234 if (dataModelResponse.isLeft()) {
235 Map<String, Boolean> result = new HashMap<>();
236 result.put("isValid", dataModelResponse.left().value());
237 log.debug("validation was successfully performed.");
238 return Either.left(result);
241 ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(dataModelResponse.right().value()));
243 return Either.right(responseFormat);
246 private Either<Boolean, ResponseFormat> validateAndUpdateProductContactsList(User user, Product product, AuditingActionEnum actionEnum) {
247 List<String> contacts = product.getContacts();
248 if (!ValidationUtils.validateListNotEmpty(contacts)) {
249 log.debug("Contacts list cannot be empty for product {}", product.getName());
250 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.EMPTY_PRODUCT_CONTACTS_LIST);
251 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
252 return Either.right(responseFormat);
255 boolean isProductCreatorInContacts = false;
256 String modifierUserId = user.getUserId();
257 for (String contact : contacts) {
258 if (contact.equals(modifierUserId)) {
259 log.trace("modifier userId found in product contacts");
260 isProductCreatorInContacts = true;
261 // No need to validate for this userId - it's modifier's
264 if (!ValidationUtils.validateContactId(contact)) {
265 log.debug("Product contacts has invalid userId {} for product {}", contact, product.getName());
266 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_INVALID_CONTACT, ComponentTypeEnum.PRODUCT.getValue());
267 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
268 return Either.right(responseFormat);
273 contactUser = validateUserExists(contact, CREATE_PRODUCT, false);
274 validateUserRole(contactUser, contactsRoles);
275 } catch(ComponentException e){
276 log.debug("Cannot set contact with userId {} as product contact, error: {}", contact, e.getActionStatus());
277 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_PRODUCT_CONTACT, contact);
278 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
279 throw new ComponentException(e.getActionStatus(), e.getParams());
283 if (!isProductCreatorInContacts) {
284 log.debug("modifier userId {} not found in product contacts - adding it", modifierUserId);
285 contacts.add(modifierUserId);
288 // passed - setting all contacts userIds to lowercase
289 List<String> tempContacts = contacts.stream()
290 .map(String::toLowerCase)
291 .collect(Collectors.toList());
292 ValidationUtils.removeDuplicateFromList(tempContacts);
293 product.setContacts(tempContacts);
295 return Either.left(true);
298 private Either<Boolean, ResponseFormat> validateGrouping(User user, Product product, AuditingActionEnum actionEnum) {
299 List<CategoryDefinition> categories = product.getCategories();
300 if (categories == null || categories.isEmpty()) {
301 log.debug("Grouping list is empty for product: {}", product.getName());
302 return Either.left(true);
304 Map<String, Map<String, Set<String>>> nonDuplicatedCategories = new HashMap<>();
305 // remove duplicated entries
306 for (CategoryDefinition cat : categories) {
307 String catName = cat.getName();
308 if (!ValidationUtils.validateStringNotEmpty(catName)) {
309 // error missing cat name
310 log.debug("Missing category name for product: {}", product.getName());
311 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_CATEGORY, ComponentTypeEnum.PRODUCT.getValue());
312 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
313 return Either.right(responseFormat);
315 Map<String, Set<String>> catEntry = nonDuplicatedCategories.get(catName);
316 if (catEntry == null) {
317 catEntry = new HashMap<>();
318 nonDuplicatedCategories.put(catName, catEntry);
320 List<SubCategoryDefinition> subcategories = cat.getSubcategories();
321 if (subcategories == null || subcategories.isEmpty()) {
322 // error missing subcat for cat
323 log.debug("Missing sub-categories for category {} in product {}", catName, product.getName());
324 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_SUBCATEGORY);
325 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
326 return Either.right(responseFormat);
328 for (SubCategoryDefinition subcat : subcategories) {
329 String subCatName = subcat.getName();
330 if (!ValidationUtils.validateStringNotEmpty(subCatName)) {
331 // error missing sub cat name for cat
332 log.debug("Missing or empty sub-category for category {} in product {}", catName, product.getName());
333 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_SUBCATEGORY);
334 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
335 return Either.right(responseFormat);
337 Set<String> subcatEntry = catEntry.get(subCatName);
338 if (subcatEntry == null) {
339 subcatEntry = new HashSet<>();
340 catEntry.put(subCatName, subcatEntry);
342 List<GroupingDefinition> groupings = subcat.getGroupings();
343 for (GroupingDefinition group : groupings) {
344 String groupName = group.getName();
345 if (!ValidationUtils.validateStringNotEmpty(groupName)) {
346 // error missing grouping for sub cat name and cat
347 log.debug("Missing or empty groupng name for sub-category: {} for categor: {} in product: {}", subCatName, catName, product.getName());
348 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_SUBCATEGORY);
349 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
350 return Either.right(responseFormat);
352 if (!subcatEntry.contains(groupName)) {
353 subcatEntry.add(groupName);
355 log.debug("Grouping: {}, already exist for category: {} and subcategory: {}", groupName, catName, subCatName);
359 } // for end of checking duplicated
360 // validate existence
361 Either<List<CategoryDefinition>, ActionStatus> allProductCategories = elementDao.getAllProductCategories();
363 if (allProductCategories.isRight()) {
364 log.debug("No product categories {}", allProductCategories.right().value());
365 ResponseFormat responseFormat = componentsUtils.getResponseFormat(allProductCategories.right().value());
366 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
367 return Either.right(responseFormat);
370 // convert non-duplicated to data modeling format and update in the
372 List<CategoryDefinition> newCatList = new ArrayList<>();
374 // over all categories from request
375 for (Map.Entry<String, Map<String, Set<String>>> entry : nonDuplicatedCategories.entrySet()) {
377 CategoryDefinition categoryDefinition = null;
378 // over all categories from Titan
379 List<CategoryDefinition> categoriesList = allProductCategories.left().value();
380 if (categoriesList != null) {
381 for (CategoryDefinition catInDb : categoriesList) {
382 if (entry.getKey().equals(catInDb.getName())) {
386 categoryDefinition = new CategoryDefinition(catInDb);
387 SubCategoryDefinition subCategory = null;
389 Map<String, Set<String>> subcats = entry.getValue();
390 for (Map.Entry<String, Set<String>> subcat : subcats.entrySet()) {
392 List<SubCategoryDefinition> subcategoriesList = catInDb.getSubcategories();
393 if (subcategoriesList != null) {
394 for (SubCategoryDefinition subcatInDb : subcategoriesList) {
395 if (subcatInDb.getName().equals(subcat.getKey())) {
397 subCategory = new SubCategoryDefinition(subcatInDb);
399 Set<String> grouping = subcat.getValue();
401 GroupingDefinition groupingDefinition = null;
402 for (String group : grouping) {
404 List<GroupingDefinition> groupings = subcatInDb.getGroupings();
405 if (groupings != null) {
406 for (GroupingDefinition groupInDb : groupings) {
407 if (groupInDb.getName().equals(group)) {
409 groupingDefinition = new GroupingDefinition(groupInDb);
414 // error grouping isn't defined
416 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_GROUP_ASSOCIATION, CategoryTypeEnum.GROUPING.getValue(), group);
417 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
418 return Either.right(responseFormat);
420 subCategory.addGrouping(groupingDefinition);
426 // error sub category isn't defined in Titan
427 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_GROUP_ASSOCIATION, CategoryTypeEnum.SUBCATEGORY.getValue(), subcat.getKey());
428 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
429 return Either.right(responseFormat);
431 categoryDefinition.addSubCategory(subCategory);
437 // error category isn't defined in Titan
438 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_GROUP_ASSOCIATION, CategoryTypeEnum.CATEGORY.getValue(), entry.getKey());
439 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
440 return Either.right(responseFormat);
442 newCatList.add(categoryDefinition);
444 product.setCategories(newCatList);
445 return Either.left(true);
448 public Either<Product, ResponseFormat> getProduct(String productId, User user) {
449 String ecompErrorContext = "Get product";
450 validateUserNotEmpty(user, ecompErrorContext);
451 validateUserExists(user, ecompErrorContext, false);
453 Either<Product, StorageOperationStatus> storageStatus = toscaOperationFacade.getToscaElement(productId);
455 if (storageStatus.isRight()) {
456 log.debug("failed to get resource by id {}", productId);
457 if (storageStatus.right().value().equals(StorageOperationStatus.NOT_FOUND)) {
459 return Either.right(componentsUtils.getResponseFormat(ActionStatus.PRODUCT_NOT_FOUND, ComponentTypeEnum.PRODUCT.getValue()));
461 return Either.right(componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(storageStatus.right().value()), ""));
464 return Either.left(storageStatus.left().value());
467 public Either<Product, ResponseFormat> deleteProduct(String productId, User user) {
468 String ecompErrorContext = "Delete product";
469 validateUserNotEmpty(user, ecompErrorContext);
470 validateUserExists(user, ecompErrorContext, false);
472 Either<Product, StorageOperationStatus> storageStatus = toscaOperationFacade.deleteToscaComponent(productId);
474 if (storageStatus.isRight()) {
475 log.debug("failed to delete resource by id {}", productId);
476 return Either.right(componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(storageStatus.right().value()), ""));
478 return Either.left(storageStatus.left().value());
481 private Either<Boolean, ResponseFormat> validateProductFullNameAndCleanup(User user, Product product, AuditingActionEnum actionEnum) {
482 String fullName = product.getFullName();
483 if (!ValidationUtils.validateStringNotEmpty(fullName)) {
484 ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.MISSING_ONE_OF_COMPONENT_NAMES, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_FULL_NAME);
485 componentsUtils.auditComponentAdmin(errorResponse, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
486 return Either.right(errorResponse);
489 fullName = ValidationUtils.removeNoneUtf8Chars(fullName);
490 fullName = ValidationUtils.removeHtmlTags(fullName);
491 fullName = ValidationUtils.normaliseWhitespace(fullName);
492 fullName = ValidationUtils.stripOctets(fullName);
494 if (!ValidationUtils.validateProductFullNameLength(fullName)) {
495 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_FULL_NAME);
496 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
497 return Either.right(responseFormat);
500 if (!ValidationUtils.validateIsEnglish(fullName)) {
501 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_FULL_NAME);
502 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
503 return Either.right(responseFormat);
506 product.setFullName(fullName);
507 return Either.left(true);
510 private Either<Boolean, ResponseFormat> validateProductNameAndCleanup(User user, Product product, AuditingActionEnum actionEnum) {
511 String name = product.getName();
512 if (!ValidationUtils.validateStringNotEmpty(name)) {
513 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.MISSING_ONE_OF_COMPONENT_NAMES, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_ABBREVIATED_NAME);
514 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
515 return Either.right(responseFormat);
518 // Product name is required to have same validation and normalization as
520 if (!ValidationUtils.validateCategoryDisplayNameFormat(name)) {
521 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_ABBREVIATED_NAME);
522 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
523 return Either.right(responseFormat);
526 String normalizedName4Display = ValidationUtils.normalizeCategoryName4Display(name);
528 if (!ValidationUtils.validateCategoryDisplayNameLength(normalizedName4Display)) {
529 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_ABBREVIATED_NAME);
530 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
531 return Either.right(responseFormat);
534 product.setName(normalizedName4Display);
535 String normalizedName4Uniqueness = ValidationUtils.normaliseComponentName(normalizedName4Display);
536 product.setNormalizedName(normalizedName4Uniqueness);
538 return Either.left(true);
541 // This is a workaround for a current tag--->product name behaviour, which
542 // will be changed in 1607.
543 // It was agreed with Ella on 23/2/16 that the tag validation of product
544 // will be made against the old product name (before normalization),
545 // and in 1607 US will be defined where UI will no longer pass tag of
546 // component name, and BE will add it by itself after all needed
548 private Either<Boolean, ResponseFormat> validateTagsListAndRemoveDuplicates(User user, Product product, String oldProductName, AuditingActionEnum actionEnum) {
549 List<String> tagsList = product.getTags();
550 validateComponentTags(tagsList, oldProductName, ComponentTypeEnum.PRODUCT, user, product, actionEnum);
551 ValidationUtils.removeDuplicateFromList(tagsList);
552 return Either.left(true);
556 public void setDeploymentArtifactsPlaceHolder(org.openecomp.sdc.be.model.Component component, User user) {
560 public Either<Product, ResponseFormat> updateProductMetadata(String productId, Product updatedProduct, User user) {
561 ComponentTypeEnum typeEnum = ComponentTypeEnum.PRODUCT;
562 user = validateUser(user, "Update Product", updatedProduct, null, false);
563 // validate user role
564 validateUserRole(user, updatedProduct, updateRoles, null, null);
565 if (updatedProduct == null) {
566 log.debug("Invalid product json. Check product servlet log for updateProduct entry params");
567 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
568 return Either.right(responseFormat);
571 Either<Product, StorageOperationStatus> storageStatus = toscaOperationFacade.getToscaElement(productId);
572 if (storageStatus.isRight()) {
573 if (storageStatus.right().value().equals(StorageOperationStatus.NOT_FOUND)) {
574 return Either.right(componentsUtils.getResponseFormat(ActionStatus.PRODUCT_NOT_FOUND, ComponentTypeEnum.PRODUCT.name().toLowerCase()));
576 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(storageStatus.right().value(), typeEnum), ""));
579 Product currentProduct = storageStatus.left().value();
581 if (!ComponentValidationUtils.canWorkOnComponent(productId, toscaOperationFacade, user.getUserId())) {
582 log.info("Restricted operation for user: {}, on product: {}" , user.getUserId(), currentProduct.getCreatorUserId());
583 return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
586 Either<Product, ResponseFormat> validationRsponse = validateAndUpdateProductMetadata(user, currentProduct, updatedProduct);
587 if (validationRsponse.isRight()) {
588 log.info("product update metadata: validations field.");
589 return validationRsponse;
592 Product productToUpdate = validationRsponse.left().value();
594 Either<Boolean, ResponseFormat> lockResult = lockComponent(currentProduct.getUniqueId(), currentProduct, "Update Product Metadata");
595 if (lockResult.isRight()) {
596 return Either.right(lockResult.right().value());
599 Either<Product, StorageOperationStatus> updateResponse = toscaOperationFacade.updateToscaElement(productToUpdate);
600 if (updateResponse.isRight()) {
601 toscaOperationFacade.rollback();
602 log.debug("failed to update product {}", productToUpdate.getUniqueId());
603 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
605 toscaOperationFacade.commit();
606 return Either.left(updateResponse.left().value());
608 graphLockOperation.unlockComponent(productId, NodeTypeEnum.Product);
612 private Either<Product, ResponseFormat> validateAndUpdateProductMetadata(User user, Product currentProduct, Product updatedProduct) {
614 boolean hasBeenCertified = ValidationUtils.hasBeenCertified(currentProduct.getVersion());
615 Either<Boolean, ResponseFormat> response = validateAndUpdateProductName(user, currentProduct, updatedProduct);
616 if (response.isRight()) {
617 ResponseFormat errorResponse = response.right().value();
618 return Either.right(errorResponse);
621 response = validateAndUpdateFullName(user, currentProduct, updatedProduct);
622 if (response.isRight()) {
623 ResponseFormat errorResponse = response.right().value();
624 return Either.right(errorResponse);
627 response = validateAndUpdateDescription(user, currentProduct, updatedProduct, null);
628 if (response.isRight()) {
629 ResponseFormat errorResponse = response.right().value();
630 return Either.right(errorResponse);
633 response = validateAndUpdateCategory(user, currentProduct, updatedProduct);
634 if (response.isRight()) {
635 ResponseFormat errorResponse = response.right().value();
636 return Either.right(errorResponse);
639 response = validateAndUpdateContactList(user, currentProduct, updatedProduct);
640 if (response.isRight()) {
641 ResponseFormat errorResponse = response.right().value();
642 return Either.right(errorResponse);
645 response = validateAndUpdateTags(user, currentProduct, updatedProduct);
646 if (response.isRight()) {
647 ResponseFormat errorResponse = response.right().value();
648 return Either.right(errorResponse);
651 response = validateAndUpdateProjectCode(user, currentProduct, updatedProduct);
652 if (response.isRight()) {
653 ResponseFormat errorResponse = response.right().value();
654 return Either.right(errorResponse);
657 if (updatedProduct.getIsActive() != null) {
658 currentProduct.setIsActive(updatedProduct.getIsActive());
661 response = validateAndUpdateIcon(user, currentProduct, updatedProduct, hasBeenCertified);
662 if (response.isRight()) {
663 ResponseFormat errorResponse = response.right().value();
664 return Either.right(errorResponse);
667 String currentInvariantUuid = currentProduct.getInvariantUUID();
668 String updatedInvariantUuid = updatedProduct.getInvariantUUID();
670 if ((updatedInvariantUuid != null) && (!updatedInvariantUuid.equals(currentInvariantUuid))) {
671 log.warn("Product invariant UUID is automatically set and cannot be updated");
672 updatedProduct.setInvariantUUID(currentInvariantUuid);
674 return Either.left(currentProduct);
678 private Either<Boolean, ResponseFormat> validateAndUpdateProductName(User user, Product currentProduct, Product updatedProduct) {
679 String updatedProductName = updatedProduct.getName();
681 String currentProductName = currentProduct.getName();
682 if (updatedProductName != null) {
683 Either<Boolean, ResponseFormat> validatProductNameResponse = validateProductNameAndCleanup(user, updatedProduct, null);
684 if (validatProductNameResponse.isRight()) {
685 ResponseFormat errorRespons = validatProductNameResponse.right().value();
686 return Either.right(errorRespons);
688 updatedProductName = updatedProduct.getName();
689 if (!currentProductName.equals(updatedProductName)) {
690 Either<Boolean, ResponseFormat> productNameUniquenessValidation = validateComponentNameUnique(user, updatedProduct, null);
691 if (productNameUniquenessValidation.isRight()) {
692 return productNameUniquenessValidation;
694 currentProduct.setName(updatedProductName);
695 tags = updatedProductName;
696 updatedProductName = ValidationUtils.normalizeCategoryName4Display(updatedProductName);
697 currentProduct.getComponentMetadataDefinition().getMetadataDataDefinition().setNormalizedName(ValidationUtils.normaliseComponentName(updatedProductName));
698 List<String> updatedTags = updatedProduct.getTags();
699 // As discussed with Ella currently (1604) we are not removing
700 // the old name from tags.
701 if (updatedTags == null) {
702 updatedTags = currentProduct.getTags();
704 updatedTags.add(tags);
707 return Either.left(true);
710 private Either<Boolean, ResponseFormat> validateAndUpdateFullName(User user, Product currentProduct, Product updatedProduct) {
711 String updatedProductName = updatedProduct.getFullName();
712 String currentProductName = currentProduct.getFullName();
713 if (updatedProductName != null && !currentProductName.equals(updatedProductName)) {
714 Either<Boolean, ResponseFormat> validatProductNameResponse = validateProductFullNameAndCleanup(user, updatedProduct, null);
715 if (validatProductNameResponse.isRight()) {
716 ResponseFormat errorRespons = validatProductNameResponse.right().value();
717 return Either.right(errorRespons);
719 currentProduct.setFullName(updatedProduct.getFullName());
721 return Either.left(true);
724 private Either<Boolean, ResponseFormat> validateAndUpdateCategory(User user, Product currentProduct, Product updatedProduct) {
726 Either<Boolean, ResponseFormat> validateCategoryResponse = validateGrouping(user, updatedProduct, null);
727 if (validateCategoryResponse.isRight()) {
728 ResponseFormat errorResponse = validateCategoryResponse.right().value();
729 return Either.right(errorResponse);
732 List<CategoryDefinition> categoryUpdated = updatedProduct.getCategories();
733 if (categoryUpdated != null) {
734 currentProduct.setCategories(categoryUpdated);
736 return Either.left(true);
739 private Either<Boolean, ResponseFormat> validateAndUpdateContactList(User user, Product currentProduct, Product updatedProduct) {
740 List<String> updatedContacts = updatedProduct.getContacts();
741 List<String> currentContacts = currentProduct.getContacts();
742 if (updatedContacts != null) {
743 if (!(currentContacts.containsAll(updatedContacts) && updatedContacts.containsAll(currentContacts))) {
744 Either<Boolean, ResponseFormat> validatResponse = validateAndUpdateProductContactsList(user, updatedProduct, null);
745 if (validatResponse.isRight()) {
746 ResponseFormat errorRespons = validatResponse.right().value();
747 return Either.right(errorRespons);
749 currentProduct.setContacts(updatedProduct.getContacts());
752 return Either.left(true);
755 private Either<Boolean, ResponseFormat> validateAndUpdateTags(User user, Product currentProduct, Product updatedProduct) {
756 List<String> tagsUpdated = updatedProduct.getTags();
757 List<String> tagsCurrent = currentProduct.getTags();
758 if (tagsUpdated != null) {
759 if (!(tagsCurrent.containsAll(tagsUpdated) && tagsUpdated.containsAll(tagsCurrent))) {
760 Either<Boolean, ResponseFormat> validatResponse = validateTagsListAndRemoveDuplicates(user, updatedProduct, currentProduct.getName(), null);
761 if (validatResponse.isRight()) {
762 ResponseFormat errorRespons = validatResponse.right().value();
763 return Either.right(errorRespons);
765 currentProduct.setTags(updatedProduct.getTags());
768 return Either.left(true);
772 public Either<List<String>, ResponseFormat> deleteMarkedComponents() {
773 // markAsDeleted isnt implemented yet
774 return Either.left(new ArrayList<>());
778 protected boolean validateTagPattern(String tag) {
779 return ValidationUtils.validateCategoryDisplayNameFormat(tag);
782 public Either<Product, ResponseFormat> getProductByNameAndVersion(String productName, String productVersion, String userId) {
783 validateUserExists(userId, "get Service By Name And Version", false);
784 Either<Product, StorageOperationStatus> storageStatus = toscaOperationFacade.getComponentByNameAndVersion(ComponentTypeEnum.PRODUCT, productName, productVersion);
785 if (storageStatus.isRight()) {
786 log.debug("failed to get service by name {} and version {}", productName, productVersion);
787 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(storageStatus.right().value(), ComponentTypeEnum.PRODUCT), productName));
789 Product product = storageStatus.left().value();
790 return Either.left(product);
794 public ComponentInstanceBusinessLogic getComponentInstanceBL() {
795 return componentInstanceBusinessLogic;
799 public Either<List<ComponentInstance>, ResponseFormat> getComponentInstancesFilteredByPropertiesAndInputs(String componentId, String userId) {
803 public ICacheMangerOperation getCacheManagerOperation() {
804 return cacheManagerOperation;
807 public void setCacheManagerOperation(ICacheMangerOperation cacheManagerOperation) {
808 this.cacheManagerOperation = cacheManagerOperation;
812 public Either<UiComponentDataTransfer, ResponseFormat> getUiComponentDataTransferByComponentId(String componentId,
813 List<String> dataParamsToReturn) {
814 // TODO Auto-generated method stub