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.dao.api.ActionStatus;
25 import org.openecomp.sdc.be.datamodel.api.CategoryTypeEnum;
26 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
27 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
28 import org.openecomp.sdc.be.model.ComponentInstance;
29 import org.openecomp.sdc.be.model.LifecycleStateEnum;
30 import org.openecomp.sdc.be.model.Product;
31 import org.openecomp.sdc.be.model.User;
32 import org.openecomp.sdc.be.model.category.CategoryDefinition;
33 import org.openecomp.sdc.be.model.category.GroupingDefinition;
34 import org.openecomp.sdc.be.model.category.SubCategoryDefinition;
35 import org.openecomp.sdc.be.model.jsontitan.operations.ToscaOperationFacade;
36 import org.openecomp.sdc.be.model.operations.api.ICacheMangerOperation;
37 import org.openecomp.sdc.be.model.operations.api.IElementOperation;
38 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
39 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
40 import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils;
41 import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
42 import org.openecomp.sdc.be.ui.model.UiComponentDataTransfer;
43 import org.openecomp.sdc.be.user.Role;
44 import org.openecomp.sdc.common.util.ValidationUtils;
45 import org.openecomp.sdc.exception.ResponseFormat;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48 import org.springframework.beans.factory.annotation.Autowired;
50 import java.util.ArrayList;
51 import java.util.HashMap;
52 import java.util.HashSet;
53 import java.util.List;
56 import java.util.stream.Collectors;
58 @org.springframework.stereotype.Component("productBusinessLogic")
59 public class ProductBusinessLogic extends ComponentBusinessLogic {
61 private static final String PRODUCT_FULL_NAME = "full";
62 private static final String PRODUCT_ABBREVIATED_NAME = "abbreviated";
63 private static final Logger log = LoggerFactory.getLogger(ProductBusinessLogic.class);
64 private static final String INITIAL_VERSION = "0.1";
65 private static List<Role> creationRoles;
66 private static List<Role> updateRoles;
67 private static List<Role> contactsRoles;
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 private IElementOperation elementDao;
85 private ComponentInstanceBusinessLogic componentInstanceBusinessLogic;
88 private ICacheMangerOperation cacheManagerOperation;
91 ToscaOperationFacade toscaOperationFacade;
93 public Either<Product, ResponseFormat> createProduct(Product product, User user) {
94 AuditingActionEnum actionEnum = AuditingActionEnum.CREATE_RESOURCE;
95 ComponentTypeEnum typeEnum = ComponentTypeEnum.PRODUCT;
97 // validate user - should be first to get the maximum auditing info in
98 // case of subsequent failures
99 log.debug("get user from DB");
100 Either<User, ResponseFormat> eitherCreator = validateUser(user, "Create Product", product, actionEnum, false);
101 if (eitherCreator.isRight()) {
102 return Either.right(eitherCreator.right().value());
104 user = eitherCreator.left().value();
106 // validate user role
107 Either<Boolean, ResponseFormat> validateRes = validateUserRole(user, product, creationRoles, actionEnum, null);
108 if (validateRes.isRight()) {
109 return Either.right(validateRes.right().value());
112 if (product == null) {
113 log.debug("Invalid product json. Check product servlet log for createProduct entry params");
114 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
115 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, typeEnum);
116 return Either.right(responseFormat);
119 // warn about non-updatable fields
120 checkUnupdatableProductFields(product);
122 Either<Product, ResponseFormat> validateProductResponse = validateProductBeforeCreate(product, user, actionEnum);
123 if (validateProductResponse.isRight()) {
124 return Either.right(validateProductResponse.right().value());
127 log.debug("send product {} to dao for create", product.getComponentMetadataDefinition().getMetadataDataDefinition().getName());
129 Either<Boolean, ResponseFormat> lockResult = lockComponentByName(product.getSystemName(), product, "Create Product");
130 if (lockResult.isRight()) {
131 ResponseFormat responseFormat = lockResult.right().value();
132 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
133 return Either.right(responseFormat);
136 log.debug("Product name locked is {}, status = {}", product.getSystemName(), lockResult);
139 Either<Product, StorageOperationStatus> createProductEither = toscaOperationFacade.createToscaComponent(product);
141 if (createProductEither.isRight()) {
142 ResponseFormat responseFormat = componentsUtils.getResponseFormatByComponent(componentsUtils.convertFromStorageResponse(createProductEither.right().value()), product, typeEnum);
143 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, typeEnum);
144 return Either.right(responseFormat);
147 log.debug("Product created successfully");
148 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.CREATED);
149 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, typeEnum);
151 Product createdProduct = createProductEither.left().value();
153 return Either.left(createdProduct);
156 graphLockOperation.unlockComponentByName(product.getSystemName(), product.getUniqueId(), NodeTypeEnum.Product);
161 private void checkUnupdatableProductFields(Product product) {
162 checkComponentFieldsForOverrideAttempt(product);
163 if (product.getNormalizedName() != null) {
164 log.info("NormalizedName cannot be defined by user. This field will be overridden by the application");
168 private Either<Product, ResponseFormat> validateProductBeforeCreate(Product product, User user, AuditingActionEnum actionEnum) {
170 Either<Boolean, ResponseFormat> validateProductFields = validateProductFieldsBeforeCreate(user, product, actionEnum);
171 if (validateProductFields.isRight()) {
172 return Either.right(validateProductFields.right().value());
175 if (product.getIsActive() == null) {
176 log.debug("no isActive value was provided, setting to default: false");
177 product.setIsActive(false);
180 product.setCreatorUserId(user.getUserId());
183 log.debug("enrich product with version and state");
184 product.setState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT);
185 product.setVersion(INITIAL_VERSION);
187 // Generate invariant UUID - must be here and not in operation since it
188 // should stay constant during clone
189 String invariantUUID = UniqueIdBuilder.buildInvariantUUID();
190 product.setInvariantUUID(invariantUUID);
192 return Either.left(product);
195 private Either<Boolean, ResponseFormat> validateProductFieldsBeforeCreate(User user, Product product, AuditingActionEnum actionEnum) {
197 // To be removed in 1607
199 String oldName = product.getName();
201 Either<Boolean, ResponseFormat> componentNameValidation = validateProductNameAndCleanup(user, product, actionEnum);
202 if (componentNameValidation.isRight()) {
203 return componentNameValidation;
206 Either<Boolean, ResponseFormat> componentNameUniquenessValidation = validateComponentNameUnique(user, product, actionEnum);
207 if (componentNameUniquenessValidation.isRight()) {
208 return componentNameUniquenessValidation;
211 // To be removed in 1607 and replaced with generic
212 // validateTagsListAndRemoveDuplicates()
213 // See comments on the validateTagsListAndRemoveDuplicates(user,
214 // product, oldName, actionEnum) function
215 Either<Boolean, ResponseFormat> tagsValidation = validateTagsListAndRemoveDuplicates(user, product, oldName, actionEnum);
216 if (tagsValidation.isRight()) {
217 return tagsValidation;
220 Either<Boolean, ResponseFormat> validateIconResponse = validateIcon(user, product, actionEnum);
221 if (validateIconResponse.isRight()) {
222 return validateIconResponse;
225 Either<Boolean, ResponseFormat> projectCodeValidation = validateProjectCode(user, product, actionEnum);
226 if (projectCodeValidation.isRight()) {
227 return projectCodeValidation;
229 Either<Boolean, ResponseFormat> categoryValidation = validateGrouping(user, product, actionEnum);
230 if (categoryValidation.isRight()) {
231 return categoryValidation;
234 Either<Boolean, ResponseFormat> contactsListValidation = validateAndUpdateProductContactsList(user, product, actionEnum);
235 if (contactsListValidation.isRight()) {
236 return contactsListValidation;
239 Either<Boolean, ResponseFormat> productFullNameValidation = validateProductFullNameAndCleanup(user, product, actionEnum);
240 if (productFullNameValidation.isRight()) {
241 return productFullNameValidation;
244 Either<Boolean, ResponseFormat> descValidation = validateDescriptionAndCleanup(user, product, actionEnum);
245 if (descValidation.isRight()) {
246 return descValidation;
249 return Either.left(true);
252 public Either<Map<String, Boolean>, ResponseFormat> validateProductNameExists(String productName, String userId) {
254 Either<User, ResponseFormat> resp = validateUserExists(userId, "validate Product Name Exists", false);
255 if (resp.isRight()) {
256 return Either.right(resp.right().value());
259 Either<Boolean, StorageOperationStatus> dataModelResponse = toscaOperationFacade.validateComponentNameUniqueness(productName, null, ComponentTypeEnum.PRODUCT);
263 if (dataModelResponse.isLeft()) {
264 Map<String, Boolean> result = new HashMap<>();
265 result.put("isValid", dataModelResponse.left().value());
266 log.debug("validation was successfully performed.");
267 return Either.left(result);
270 ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(dataModelResponse.right().value()));
272 return Either.right(responseFormat);
275 private Either<Boolean, ResponseFormat> validateAndUpdateProductContactsList(User user, Product product, AuditingActionEnum actionEnum) {
276 List<String> contacts = product.getContacts();
277 if (!ValidationUtils.validateListNotEmpty(contacts)) {
278 log.debug("Contacts list cannot be empty for product {}", product.getName());
279 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.EMPTY_PRODUCT_CONTACTS_LIST);
280 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
281 return Either.right(responseFormat);
284 boolean isProductCreatorInContacts = false;
285 String modifierUserId = user.getUserId();
286 for (String contact : contacts) {
287 if (contact.equals(modifierUserId)) {
288 log.trace("modifier userId found in product contacts");
289 isProductCreatorInContacts = true;
290 // No need to validate for this userId - it's modifier's
293 if (!ValidationUtils.validateContactId(contact)) {
294 log.debug("Product contacts has invalid userId {} for product {}", contact, product.getName());
295 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_INVALID_CONTACT, ComponentTypeEnum.PRODUCT.getValue());
296 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
297 return Either.right(responseFormat);
300 User contactUser = new User();
301 contactUser.setUserId(contact);
302 Either<User, ResponseFormat> validateUser = validateUserExists(contact, "Create Product", false);
303 if (validateUser.isRight()) {
304 log.debug("Cannot set contact with userId {} as product contact, error: {}", contact, validateUser.right().value());
305 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_PRODUCT_CONTACT, contact);
306 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
307 return Either.right(responseFormat);
310 contactUser = validateUser.left().value();
312 Either<Boolean, ResponseFormat> validateUserRole = validateUserRole(contactUser, contactsRoles);
313 if (validateUserRole.isRight()) {
314 log.debug("Cannot set contact with userId {} as product contact, error: {}", contact, validateUserRole.right().value());
315 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_PRODUCT_CONTACT, contact);
316 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
317 return Either.right(responseFormat);
322 if (!isProductCreatorInContacts) {
323 log.debug("modifier userId {} not found in product contacts - adding it", modifierUserId);
324 contacts.add(modifierUserId);
327 // passed - setting all contacts userIds to lowercase
328 List<String> tempContacts = contacts.stream().map(e -> e.toLowerCase()).collect(Collectors.toList());
329 ValidationUtils.removeDuplicateFromList(tempContacts);
330 product.setContacts(tempContacts);
332 return Either.left(true);
335 private Either<Boolean, ResponseFormat> validateGrouping(User user, Product product, AuditingActionEnum actionEnum) {
336 List<CategoryDefinition> categories = product.getCategories();
337 if (categories == null || categories.isEmpty()) {
338 log.debug("Grouping list is empty for product: {}", product.getName());
339 return Either.left(true);
341 Map<String, Map<String, Set<String>>> nonDuplicatedCategories = new HashMap<String, Map<String, Set<String>>>();
342 // remove duplicated entries
343 for (CategoryDefinition cat : categories) {
344 String catName = cat.getName();
345 if (ValidationUtils.validateStringNotEmpty(catName) == false) {
346 // error missing cat name
347 log.debug("Missing category name for product: {}", product.getName());
348 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_CATEGORY, ComponentTypeEnum.PRODUCT.getValue());
349 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
350 return Either.right(responseFormat);
352 Map<String, Set<String>> catEntry = nonDuplicatedCategories.get(catName);
353 if (catEntry == null) {
354 catEntry = new HashMap<String, Set<String>>();
355 nonDuplicatedCategories.put(catName, catEntry);
357 List<SubCategoryDefinition> subcategories = cat.getSubcategories();
358 if (subcategories == null || subcategories.isEmpty()) {
359 // error missing subcat for cat
360 log.debug("Missing sub-categories for category {} in product {}", catName, product.getName());
361 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_SUBCATEGORY);
362 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
363 return Either.right(responseFormat);
365 for (SubCategoryDefinition subcat : subcategories) {
366 String subCatName = subcat.getName();
367 if (ValidationUtils.validateStringNotEmpty(subCatName) == false) {
368 // error missing sub cat name for cat
369 log.debug("Missing or empty sub-category for category {} in product {}", catName, product.getName());
370 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_SUBCATEGORY);
371 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
372 return Either.right(responseFormat);
374 Set<String> subcatEntry = catEntry.get(subCatName);
375 if (subcatEntry == null) {
376 subcatEntry = new HashSet<String>();
377 catEntry.put(subCatName, subcatEntry);
379 List<GroupingDefinition> groupings = subcat.getGroupings();
380 for (GroupingDefinition group : groupings) {
381 String groupName = group.getName();
382 if (ValidationUtils.validateStringNotEmpty(groupName) == false) {
383 // error missing grouping for sub cat name and cat
384 log.debug("Missing or empty groupng name for sub-category: {} for categor: {} in product: {}", subCatName, catName, product.getName());
385 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_SUBCATEGORY);
386 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
387 return Either.right(responseFormat);
389 if (!subcatEntry.contains(groupName)) {
390 subcatEntry.add(groupName);
392 log.debug("Grouping: {}, already exist for category: {} and subcategory: {}", groupName, catName, subCatName);
396 } // for end of checking duplicated
397 // validate existence
398 Either<List<CategoryDefinition>, ActionStatus> allProductCategories = elementDao.getAllProductCategories();
400 if (allProductCategories.isRight()) {
401 log.debug("No product categories {}", allProductCategories.right().value());
402 ResponseFormat responseFormat = componentsUtils.getResponseFormat(allProductCategories.right().value());
403 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
404 return Either.right(responseFormat);
407 // convert non-duplicated to data modeling format and update in the
409 List<CategoryDefinition> newCatList = new ArrayList<CategoryDefinition>();
411 // over all categories from request
412 for (Map.Entry<String, Map<String, Set<String>>> entry : nonDuplicatedCategories.entrySet()) {
414 CategoryDefinition categoryDefinition = null;
415 // over all categories from Titan
416 List<CategoryDefinition> categoriesList = allProductCategories.left().value();
417 if (categoriesList != null) {
418 for (CategoryDefinition catInDb : categoriesList) {
419 if (entry.getKey().equals(catInDb.getName())) {
423 categoryDefinition = new CategoryDefinition(catInDb);
424 SubCategoryDefinition subCategory = null;
426 Map<String, Set<String>> subcats = entry.getValue();
427 for (Map.Entry<String, Set<String>> subcat : subcats.entrySet()) {
429 List<SubCategoryDefinition> subcategoriesList = catInDb.getSubcategories();
430 if (subcategoriesList != null) {
431 for (SubCategoryDefinition subcatInDb : subcategoriesList) {
432 if (subcatInDb.getName().equals(subcat.getKey())) {
434 subCategory = new SubCategoryDefinition(subcatInDb);
436 Set<String> grouping = subcat.getValue();
438 GroupingDefinition groupingDefinition = null;
439 for (String group : grouping) {
441 List<GroupingDefinition> groupings = subcatInDb.getGroupings();
442 if (groupings != null) {
443 for (GroupingDefinition groupInDb : groupings) {
444 if (groupInDb.getName().equals(group)) {
446 groupingDefinition = new GroupingDefinition(groupInDb);
451 // error grouping isn't defined
453 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_GROUP_ASSOCIATION, CategoryTypeEnum.GROUPING.getValue(), group);
454 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
455 return Either.right(responseFormat);
457 subCategory.addGrouping(groupingDefinition);
463 // error sub category isn't defined in Titan
464 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_GROUP_ASSOCIATION, CategoryTypeEnum.SUBCATEGORY.getValue(), subcat.getKey());
465 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
466 return Either.right(responseFormat);
468 categoryDefinition.addSubCategory(subCategory);
474 // error category isn't defined in Titan
475 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_GROUP_ASSOCIATION, CategoryTypeEnum.CATEGORY.getValue(), entry.getKey());
476 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
477 return Either.right(responseFormat);
479 newCatList.add(categoryDefinition);
481 product.setCategories(newCatList);
482 return Either.left(true);
485 public Either<Product, ResponseFormat> getProduct(String productId, User user) {
486 String ecompErrorContext = "Get product";
487 Either<User, ResponseFormat> validateEmptyResult = validateUserNotEmpty(user, ecompErrorContext);
488 if (validateEmptyResult.isRight()) {
489 return Either.right(validateEmptyResult.right().value());
492 Either<User, ResponseFormat> eitherCreator = validateUserExists(user, ecompErrorContext, false);
493 if (eitherCreator.isRight()) {
494 return Either.right(eitherCreator.right().value());
497 Either<Product, StorageOperationStatus> storageStatus = toscaOperationFacade.getToscaElement(productId);
499 if (storageStatus.isRight()) {
500 log.debug("failed to get resource by id {}", productId);
501 if (storageStatus.right().value().equals(StorageOperationStatus.NOT_FOUND)) {
503 return Either.right(componentsUtils.getResponseFormat(ActionStatus.PRODUCT_NOT_FOUND, ComponentTypeEnum.PRODUCT.getValue()));
505 return Either.right(componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(storageStatus.right().value()), ""));
508 return Either.left(storageStatus.left().value());
511 public Either<Product, ResponseFormat> deleteProduct(String productId, User user) {
512 String ecompErrorContext = "Delete product";
513 Either<User, ResponseFormat> validateEmptyResult = validateUserNotEmpty(user, ecompErrorContext);
514 if (validateEmptyResult.isRight()) {
515 return Either.right(validateEmptyResult.right().value());
518 Either<User, ResponseFormat> eitherCreator = validateUserExists(user, ecompErrorContext, false);
519 if (eitherCreator.isRight()) {
520 return Either.right(eitherCreator.right().value());
523 Either<Product, StorageOperationStatus> storageStatus = toscaOperationFacade.deleteToscaComponent(productId);
525 if (storageStatus.isRight()) {
526 log.debug("failed to delete resource by id {}", productId);
527 return Either.right(componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(storageStatus.right().value()), ""));
529 return Either.left(storageStatus.left().value());
532 private Either<Boolean, ResponseFormat> validateProductFullNameAndCleanup(User user, Product product, AuditingActionEnum actionEnum) {
533 String fullName = product.getFullName();
534 if (!ValidationUtils.validateStringNotEmpty(fullName)) {
535 ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.MISSING_ONE_OF_COMPONENT_NAMES, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_FULL_NAME);
536 componentsUtils.auditComponentAdmin(errorResponse, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
537 return Either.right(errorResponse);
540 fullName = ValidationUtils.removeNoneUtf8Chars(fullName);
541 fullName = ValidationUtils.removeHtmlTags(fullName);
542 fullName = ValidationUtils.normaliseWhitespace(fullName);
543 fullName = ValidationUtils.stripOctets(fullName);
545 if (!ValidationUtils.validateProductFullNameLength(fullName)) {
546 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_FULL_NAME);
547 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
548 return Either.right(responseFormat);
551 if (!ValidationUtils.validateIsEnglish(fullName)) {
552 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_FULL_NAME);
553 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
554 return Either.right(responseFormat);
557 product.setFullName(fullName);
558 return Either.left(true);
561 private Either<Boolean, ResponseFormat> validateProductNameAndCleanup(User user, Product product, AuditingActionEnum actionEnum) {
562 String name = product.getName();
563 if (!ValidationUtils.validateStringNotEmpty(name)) {
564 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.MISSING_ONE_OF_COMPONENT_NAMES, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_ABBREVIATED_NAME);
565 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
566 return Either.right(responseFormat);
569 // Product name is required to have same validation and normalization as
571 if (!ValidationUtils.validateCategoryDisplayNameFormat(name)) {
572 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_ABBREVIATED_NAME);
573 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
574 return Either.right(responseFormat);
577 String normalizedName4Display = ValidationUtils.normalizeCategoryName4Display(name);
579 if (!ValidationUtils.validateCategoryDisplayNameLength(normalizedName4Display)) {
580 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_ABBREVIATED_NAME);
581 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
582 return Either.right(responseFormat);
585 product.setName(normalizedName4Display);
586 String normalizedName4Uniqueness = ValidationUtils.normaliseComponentName(normalizedName4Display);
587 product.setNormalizedName(normalizedName4Uniqueness);
589 return Either.left(true);
592 // This is a workaround for a current tag--->product name behaviour, which
593 // will be changed in 1607.
594 // It was agreed with Ella on 23/2/16 that the tag validation of product
595 // will be made against the old product name (before normalization),
596 // and in 1607 US will be defined where UI will no longer pass tag of
597 // component name, and BE will add it by itself after all needed
599 private Either<Boolean, ResponseFormat> validateTagsListAndRemoveDuplicates(User user, Product product, String oldProductName, AuditingActionEnum actionEnum) {
600 List<String> tagsList = product.getTags();
602 Either<Boolean, ResponseFormat> validateTags = validateComponentTags(tagsList, oldProductName, ComponentTypeEnum.PRODUCT);
603 if (validateTags.isRight()) {
604 ResponseFormat responseFormat = validateTags.right().value();
605 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
606 return Either.right(responseFormat);
608 ValidationUtils.removeDuplicateFromList(tagsList);
609 return Either.left(true);
613 public void setDeploymentArtifactsPlaceHolder(org.openecomp.sdc.be.model.Component component, User user) {
617 public Either<Product, ResponseFormat> updateProductMetadata(String productId, Product updatedProduct, User user) {
618 ComponentTypeEnum typeEnum = ComponentTypeEnum.PRODUCT;
619 Either<User, ResponseFormat> eitherCreator = validateUser(user, "Update Product", updatedProduct, null, false);
620 if (eitherCreator.isRight()) {
621 return Either.right(eitherCreator.right().value());
623 user = eitherCreator.left().value();
625 // validate user role
626 Either<Boolean, ResponseFormat> validateRes = validateUserRole(user, updatedProduct, updateRoles, null, null);
627 if (validateRes.isRight()) {
628 return Either.right(validateRes.right().value());
631 if (updatedProduct == null) {
632 log.debug("Invalid product json. Check product servlet log for updateProduct entry params");
633 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
634 return Either.right(responseFormat);
637 Either<Product, StorageOperationStatus> storageStatus = toscaOperationFacade.getToscaElement(productId);
638 if (storageStatus.isRight()) {
639 if (storageStatus.right().value().equals(StorageOperationStatus.NOT_FOUND)) {
640 return Either.right(componentsUtils.getResponseFormat(ActionStatus.PRODUCT_NOT_FOUND, ComponentTypeEnum.PRODUCT.name().toLowerCase()));
642 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(storageStatus.right().value(), typeEnum), ""));
645 Product currentProduct = storageStatus.left().value();
647 if (!ComponentValidationUtils.canWorkOnComponent(productId, toscaOperationFacade, user.getUserId())) {
648 log.info("Restricted operation for user: {}, on product: {}" , user.getUserId(), currentProduct.getCreatorUserId());
649 return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
652 Either<Product, ResponseFormat> validationRsponse = validateAndUpdateProductMetadata(user, currentProduct, updatedProduct);
653 if (validationRsponse.isRight()) {
654 log.info("product update metadata: validations field.");
655 return validationRsponse;
658 Product productToUpdate = validationRsponse.left().value();
660 Either<Boolean, ResponseFormat> lockResult = lockComponent(currentProduct.getUniqueId(), currentProduct, "Update Product Metadata");
661 if (lockResult.isRight()) {
662 return Either.right(lockResult.right().value());
665 Either<Product, StorageOperationStatus> updateResponse = toscaOperationFacade.updateToscaElement(productToUpdate);
666 if (updateResponse.isRight()) {
667 toscaOperationFacade.rollback();
668 log.debug("failed to update product {}", productToUpdate.getUniqueId());
669 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
671 toscaOperationFacade.commit();
672 return Either.left(updateResponse.left().value());
674 graphLockOperation.unlockComponent(productId, NodeTypeEnum.Product);
678 private Either<Product, ResponseFormat> validateAndUpdateProductMetadata(User user, Product currentProduct, Product updatedProduct) {
680 boolean hasBeenCertified = ValidationUtils.hasBeenCertified(currentProduct.getVersion());
681 Either<Boolean, ResponseFormat> response = validateAndUpdateProductName(user, currentProduct, updatedProduct);
682 if (response.isRight()) {
683 ResponseFormat errorResponse = response.right().value();
684 return Either.right(errorResponse);
687 response = validateAndUpdateFullName(user, currentProduct, updatedProduct);
688 if (response.isRight()) {
689 ResponseFormat errorResponse = response.right().value();
690 return Either.right(errorResponse);
693 response = validateAndUpdateDescription(user, currentProduct, updatedProduct, null);
694 if (response.isRight()) {
695 ResponseFormat errorResponse = response.right().value();
696 return Either.right(errorResponse);
699 response = validateAndUpdateCategory(user, currentProduct, updatedProduct);
700 if (response.isRight()) {
701 ResponseFormat errorResponse = response.right().value();
702 return Either.right(errorResponse);
705 response = validateAndUpdateContactList(user, currentProduct, updatedProduct);
706 if (response.isRight()) {
707 ResponseFormat errorResponse = response.right().value();
708 return Either.right(errorResponse);
711 response = validateAndUpdateTags(user, currentProduct, updatedProduct);
712 if (response.isRight()) {
713 ResponseFormat errorResponse = response.right().value();
714 return Either.right(errorResponse);
717 response = validateAndUpdateProjectCode(user, currentProduct, updatedProduct);
718 if (response.isRight()) {
719 ResponseFormat errorResponse = response.right().value();
720 return Either.right(errorResponse);
723 if (updatedProduct.getIsActive() != null) {
724 currentProduct.setIsActive(updatedProduct.getIsActive());
727 response = validateAndUpdateIcon(user, currentProduct, updatedProduct, hasBeenCertified);
728 if (response.isRight()) {
729 ResponseFormat errorResponse = response.right().value();
730 return Either.right(errorResponse);
733 String currentInvariantUuid = currentProduct.getInvariantUUID();
734 String updatedInvariantUuid = updatedProduct.getInvariantUUID();
736 if ((updatedInvariantUuid != null) && (!updatedInvariantUuid.equals(currentInvariantUuid))) {
737 log.warn("Product invariant UUID is automatically set and cannot be updated");
738 updatedProduct.setInvariantUUID(currentInvariantUuid);
740 return Either.left(currentProduct);
744 private Either<Boolean, ResponseFormat> validateAndUpdateProductName(User user, Product currentProduct, Product updatedProduct) {
745 String updatedProductName = updatedProduct.getName();
747 String currentProductName = currentProduct.getName();
748 if (updatedProductName != null) {
749 Either<Boolean, ResponseFormat> validatProductNameResponse = validateProductNameAndCleanup(user, updatedProduct, null);
750 if (validatProductNameResponse.isRight()) {
751 ResponseFormat errorRespons = validatProductNameResponse.right().value();
752 return Either.right(errorRespons);
754 updatedProductName = updatedProduct.getName();
755 if (!currentProductName.equals(updatedProductName)) {
756 Either<Boolean, ResponseFormat> productNameUniquenessValidation = validateComponentNameUnique(user, updatedProduct, null);
757 if (productNameUniquenessValidation.isRight()) {
758 return productNameUniquenessValidation;
760 currentProduct.setName(updatedProductName);
761 tags = updatedProductName;
762 updatedProductName = ValidationUtils.normalizeCategoryName4Display(updatedProductName);
763 currentProduct.getComponentMetadataDefinition().getMetadataDataDefinition().setNormalizedName(ValidationUtils.normaliseComponentName(updatedProductName));
764 List<String> updatedTags = updatedProduct.getTags();
765 // As discussed with Ella currently (1604) we are not removing
766 // the old name from tags.
767 if (updatedTags == null) {
768 updatedTags = currentProduct.getTags();
770 updatedTags.add(tags);
773 return Either.left(true);
776 private Either<Boolean, ResponseFormat> validateAndUpdateFullName(User user, Product currentProduct, Product updatedProduct) {
777 String updatedProductName = updatedProduct.getFullName();
778 String currentProductName = currentProduct.getFullName();
779 if (updatedProductName != null && !currentProductName.equals(updatedProductName)) {
780 Either<Boolean, ResponseFormat> validatProductNameResponse = validateProductFullNameAndCleanup(user, updatedProduct, null);
781 if (validatProductNameResponse.isRight()) {
782 ResponseFormat errorRespons = validatProductNameResponse.right().value();
783 return Either.right(errorRespons);
785 currentProduct.setFullName(updatedProduct.getFullName());
787 return Either.left(true);
790 private Either<Boolean, ResponseFormat> validateAndUpdateCategory(User user, Product currentProduct, Product updatedProduct) {
791 List<CategoryDefinition> categoryUpdated = updatedProduct.getCategories();
793 Either<Boolean, ResponseFormat> validatCategoryResponse = validateGrouping(user, updatedProduct, null);
794 if (validatCategoryResponse.isRight()) {
795 ResponseFormat errorResponse = validatCategoryResponse.right().value();
796 return Either.right(errorResponse);
799 categoryUpdated = updatedProduct.getCategories();
800 if (categoryUpdated != null) {
801 currentProduct.setCategories(categoryUpdated);
803 return Either.left(true);
806 private Either<Boolean, ResponseFormat> validateAndUpdateContactList(User user, Product currentProduct, Product updatedProduct) {
807 List<String> updatedContacts = updatedProduct.getContacts();
808 List<String> currentContacts = currentProduct.getContacts();
809 if (updatedContacts != null) {
810 if (!(currentContacts.containsAll(updatedContacts) && updatedContacts.containsAll(currentContacts))) {
811 Either<Boolean, ResponseFormat> validatResponse = validateAndUpdateProductContactsList(user, updatedProduct, null);
812 if (validatResponse.isRight()) {
813 ResponseFormat errorRespons = validatResponse.right().value();
814 return Either.right(errorRespons);
816 currentProduct.setContacts(updatedProduct.getContacts());
819 return Either.left(true);
822 private Either<Boolean, ResponseFormat> validateAndUpdateTags(User user, Product currentProduct, Product updatedProduct) {
823 List<String> tagsUpdated = updatedProduct.getTags();
824 List<String> tagsCurrent = currentProduct.getTags();
825 if (tagsUpdated != null) {
826 if (!(tagsCurrent.containsAll(tagsUpdated) && tagsUpdated.containsAll(tagsCurrent))) {
827 Either<Boolean, ResponseFormat> validatResponse = validateTagsListAndRemoveDuplicates(user, updatedProduct, currentProduct.getName(), null);
828 if (validatResponse.isRight()) {
829 ResponseFormat errorRespons = validatResponse.right().value();
830 return Either.right(errorRespons);
832 currentProduct.setTags(updatedProduct.getTags());
835 return Either.left(true);
839 public Either<List<String>, ResponseFormat> deleteMarkedComponents() {
840 // markAsDeleted isnt implemented yet
841 return Either.left(new ArrayList<>());
845 protected boolean validateTagPattern(String tag) {
846 return ValidationUtils.validateCategoryDisplayNameFormat(tag);
849 public Either<Product, ResponseFormat> getProductByNameAndVersion(String productName, String productVersion, String userId) {
850 Either<User, ResponseFormat> resp = validateUserExists(userId, "get Service By Name And Version", false);
851 if (resp.isRight()) {
852 return Either.right(resp.right().value());
854 Either<Product, StorageOperationStatus> storageStatus = toscaOperationFacade.getComponentByNameAndVersion(ComponentTypeEnum.PRODUCT, productName, productVersion);
855 if (storageStatus.isRight()) {
856 log.debug("failed to get service by name {} and version {}", productName, productVersion);
857 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(storageStatus.right().value(), ComponentTypeEnum.PRODUCT), productName));
859 Product product = storageStatus.left().value();
860 return Either.left(product);
864 public ComponentInstanceBusinessLogic getComponentInstanceBL() {
865 return componentInstanceBusinessLogic;
869 public Either<List<ComponentInstance>, ResponseFormat> getComponentInstancesFilteredByPropertiesAndInputs(String componentId, ComponentTypeEnum componentTypeEnum, String userId, String searchText) {
873 public ICacheMangerOperation getCacheManagerOperation() {
874 return cacheManagerOperation;
877 public void setCacheManagerOperation(ICacheMangerOperation cacheManagerOperation) {
878 this.cacheManagerOperation = cacheManagerOperation;
882 public Either<UiComponentDataTransfer, ResponseFormat> getUiComponentDataTransferByComponentId(String componentId,
883 List<String> dataParamsToReturn) {
884 // TODO Auto-generated method stub