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 java.util.ArrayList;
24 import java.util.HashMap;
25 import java.util.HashSet;
26 import java.util.List;
29 import java.util.stream.Collectors;
31 import org.openecomp.sdc.be.dao.api.ActionStatus;
32 import org.openecomp.sdc.be.datamodel.api.CategoryTypeEnum;
33 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
34 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
35 import org.openecomp.sdc.be.model.ComponentInstance;
36 import org.openecomp.sdc.be.model.LifecycleStateEnum;
37 import org.openecomp.sdc.be.model.Product;
38 import org.openecomp.sdc.be.model.User;
39 import org.openecomp.sdc.be.model.category.CategoryDefinition;
40 import org.openecomp.sdc.be.model.category.GroupingDefinition;
41 import org.openecomp.sdc.be.model.category.SubCategoryDefinition;
42 import org.openecomp.sdc.be.model.jsontitan.operations.ToscaOperationFacade;
43 import org.openecomp.sdc.be.model.operations.api.ICacheMangerOperation;
44 import org.openecomp.sdc.be.model.operations.api.IElementOperation;
45 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
46 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
47 import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils;
48 import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
49 import org.openecomp.sdc.be.ui.model.UiComponentDataTransfer;
50 import org.openecomp.sdc.be.user.Role;
51 import org.openecomp.sdc.common.util.ValidationUtils;
52 import org.openecomp.sdc.exception.ResponseFormat;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55 import org.springframework.beans.factory.annotation.Autowired;
57 import fj.data.Either;
59 @org.springframework.stereotype.Component("productBusinessLogic")
60 public class ProductBusinessLogic extends ComponentBusinessLogic {
62 private static final String PRODUCT_FULL_NAME = "full";
63 private static final String PRODUCT_ABBREVIATED_NAME = "abbreviated";
64 private static final Logger log = LoggerFactory.getLogger(ProductBusinessLogic.class);
65 private static final String INITIAL_VERSION = "0.1";
66 private static List<Role> creationRoles;
67 private static List<Role> updateRoles;
68 private static List<Role> contactsRoles;
70 public ProductBusinessLogic() {
71 creationRoles = new ArrayList<>();
72 updateRoles = new ArrayList<>();
73 contactsRoles = new ArrayList<>();
75 // only PM is allowed to create/update products
76 creationRoles.add(Role.PRODUCT_MANAGER);
77 updateRoles.add(Role.PRODUCT_MANAGER);
78 // Only PM is allowed to be product contacts
79 contactsRoles.add(Role.PRODUCT_MANAGER);
83 private IElementOperation elementDao;
86 private ComponentInstanceBusinessLogic componentInstanceBusinessLogic;
89 private ICacheMangerOperation cacheManagerOperation;
92 ToscaOperationFacade toscaOperationFacade;
94 public Either<Product, ResponseFormat> createProduct(Product product, User user) {
95 AuditingActionEnum actionEnum = AuditingActionEnum.CREATE_RESOURCE;
96 ComponentTypeEnum typeEnum = ComponentTypeEnum.PRODUCT;
98 // validate user - should be first to get the maximum auditing info in
99 // case of subsequent failures
100 log.debug("get user from DB");
101 Either<User, ResponseFormat> eitherCreator = validateUser(user, "Create Product", product, actionEnum, false);
102 if (eitherCreator.isRight()) {
103 return Either.right(eitherCreator.right().value());
105 user = eitherCreator.left().value();
107 // validate user role
108 Either<Boolean, ResponseFormat> validateRes = validateUserRole(user, product, creationRoles, actionEnum, null);
109 if (validateRes.isRight()) {
110 return Either.right(validateRes.right().value());
113 if (product == null) {
114 log.debug("Invalid product json. Check product servlet log for createProduct entry params");
115 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
116 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, typeEnum);
117 return Either.right(responseFormat);
120 // warn about non-updatable fields
121 checkUnupdatableProductFields(product);
123 Either<Product, ResponseFormat> validateProductResponse = validateProductBeforeCreate(product, user, actionEnum);
124 if (validateProductResponse.isRight()) {
125 return Either.right(validateProductResponse.right().value());
128 log.debug("send product {} to dao for create", product.getComponentMetadataDefinition().getMetadataDataDefinition().getName());
130 Either<Boolean, ResponseFormat> lockResult = lockComponentByName(product.getSystemName(), product, "Create Product");
131 if (lockResult.isRight()) {
132 ResponseFormat responseFormat = lockResult.right().value();
133 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
134 return Either.right(responseFormat);
137 log.debug("Product name locked is {}, status = {}", product.getSystemName(), lockResult);
140 Either<Product, StorageOperationStatus> createProductEither = toscaOperationFacade.createToscaComponent(product);
142 if (createProductEither.isRight()) {
143 ResponseFormat responseFormat = componentsUtils.getResponseFormatByComponent(componentsUtils.convertFromStorageResponse(createProductEither.right().value()), product, typeEnum);
144 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, typeEnum);
145 return Either.right(responseFormat);
148 log.debug("Product created successfully");
149 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.CREATED);
150 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, typeEnum);
152 Product createdProduct = createProductEither.left().value();
154 return Either.left(createdProduct);
157 graphLockOperation.unlockComponentByName(product.getSystemName(), product.getUniqueId(), NodeTypeEnum.Product);
162 private void checkUnupdatableProductFields(Product product) {
163 checkComponentFieldsForOverrideAttempt(product);
164 if (product.getNormalizedName() != null) {
165 log.info("NormalizedName cannot be defined by user. This field will be overridden by the application");
169 private Either<Product, ResponseFormat> validateProductBeforeCreate(Product product, User user, AuditingActionEnum actionEnum) {
171 Either<Boolean, ResponseFormat> validateProductFields = validateProductFieldsBeforeCreate(user, product, actionEnum);
172 if (validateProductFields.isRight()) {
173 return Either.right(validateProductFields.right().value());
176 if (product.getIsActive() == null) {
177 log.debug("no isActive value was provided, setting to default: false");
178 product.setIsActive(false);
181 product.setCreatorUserId(user.getUserId());
184 log.debug("enrich product with version and state");
185 product.setState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT);
186 product.setVersion(INITIAL_VERSION);
188 // Generate invariant UUID - must be here and not in operation since it
189 // should stay constant during clone
190 String invariantUUID = UniqueIdBuilder.buildInvariantUUID();
191 product.setInvariantUUID(invariantUUID);
193 return Either.left(product);
196 private Either<Boolean, ResponseFormat> validateProductFieldsBeforeCreate(User user, Product product, AuditingActionEnum actionEnum) {
198 // To be removed in 1607
200 String oldName = product.getName();
202 Either<Boolean, ResponseFormat> componentNameValidation = validateProductNameAndCleanup(user, product, actionEnum);
203 if (componentNameValidation.isRight()) {
204 return componentNameValidation;
207 Either<Boolean, ResponseFormat> componentNameUniquenessValidation = validateComponentNameUnique(user, product, actionEnum);
208 if (componentNameUniquenessValidation.isRight()) {
209 return componentNameUniquenessValidation;
212 // To be removed in 1607 and replaced with generic
213 // validateTagsListAndRemoveDuplicates()
214 // See comments on the validateTagsListAndRemoveDuplicates(user,
215 // product, oldName, actionEnum) function
216 Either<Boolean, ResponseFormat> tagsValidation = validateTagsListAndRemoveDuplicates(user, product, oldName, actionEnum);
217 if (tagsValidation.isRight()) {
218 return tagsValidation;
221 Either<Boolean, ResponseFormat> validateIconResponse = validateIcon(user, product, actionEnum);
222 if (validateIconResponse.isRight()) {
223 return validateIconResponse;
226 Either<Boolean, ResponseFormat> projectCodeValidation = validateProjectCode(user, product, actionEnum);
227 if (projectCodeValidation.isRight()) {
228 return projectCodeValidation;
230 Either<Boolean, ResponseFormat> categoryValidation = validateGrouping(user, product, actionEnum);
231 if (categoryValidation.isRight()) {
232 return categoryValidation;
235 Either<Boolean, ResponseFormat> contactsListValidation = validateAndUpdateProductContactsList(user, product, actionEnum);
236 if (contactsListValidation.isRight()) {
237 return contactsListValidation;
240 Either<Boolean, ResponseFormat> productFullNameValidation = validateProductFullNameAndCleanup(user, product, actionEnum);
241 if (productFullNameValidation.isRight()) {
242 return productFullNameValidation;
245 Either<Boolean, ResponseFormat> descValidation = validateDescriptionAndCleanup(user, product, actionEnum);
246 if (descValidation.isRight()) {
247 return descValidation;
250 return Either.left(true);
253 public Either<Map<String, Boolean>, ResponseFormat> validateProductNameExists(String productName, String userId) {
255 Either<User, ResponseFormat> resp = validateUserExists(userId, "validate Product Name Exists", false);
256 if (resp.isRight()) {
257 return Either.right(resp.right().value());
260 Either<Boolean, StorageOperationStatus> dataModelResponse = toscaOperationFacade.validateComponentNameUniqueness(productName, null, ComponentTypeEnum.PRODUCT);
264 if (dataModelResponse.isLeft()) {
265 Map<String, Boolean> result = new HashMap<>();
266 result.put("isValid", dataModelResponse.left().value());
267 log.debug("validation was successfully performed.");
268 return Either.left(result);
271 ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(dataModelResponse.right().value()));
273 return Either.right(responseFormat);
276 private Either<Boolean, ResponseFormat> validateAndUpdateProductContactsList(User user, Product product, AuditingActionEnum actionEnum) {
277 List<String> contacts = product.getContacts();
278 if (!ValidationUtils.validateListNotEmpty(contacts)) {
279 log.debug("Contacts list cannot be empty for product {}", product.getName());
280 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.EMPTY_PRODUCT_CONTACTS_LIST);
281 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
282 return Either.right(responseFormat);
285 boolean isProductCreatorInContacts = false;
286 String modifierUserId = user.getUserId();
287 for (String contact : contacts) {
288 if (contact.equals(modifierUserId)) {
289 log.trace("modifier userId found in product contacts");
290 isProductCreatorInContacts = true;
291 // No need to validate for this userId - it's modifier's
294 if (!ValidationUtils.validateContactId(contact)) {
295 log.debug("Product contacts has invalid userId {} for product {}", contact, product.getName());
296 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_INVALID_CONTACT, ComponentTypeEnum.PRODUCT.getValue());
297 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
298 return Either.right(responseFormat);
301 User contactUser = new User();
302 contactUser.setUserId(contact);
303 Either<User, ResponseFormat> validateUser = validateUserExists(contact, "Create Product", false);
304 if (validateUser.isRight()) {
305 log.debug("Cannot set contact with userId {} as product contact, error: {}", contact, validateUser.right().value());
306 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_PRODUCT_CONTACT, contact);
307 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
308 return Either.right(responseFormat);
311 contactUser = validateUser.left().value();
313 Either<Boolean, ResponseFormat> validateUserRole = validateUserRole(contactUser, contactsRoles);
314 if (validateUserRole.isRight()) {
315 log.debug("Cannot set contact with userId {} as product contact, error: {}", contact, validateUserRole.right().value());
316 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_PRODUCT_CONTACT, contact);
317 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
318 return Either.right(responseFormat);
323 if (!isProductCreatorInContacts) {
324 log.debug("modifier userId {} not found in product contacts - adding it", modifierUserId);
325 contacts.add(modifierUserId);
328 // passed - setting all contacts userIds to lowercase
329 List<String> tempContacts = contacts.stream().map(e -> e.toLowerCase()).collect(Collectors.toList());
330 ValidationUtils.removeDuplicateFromList(tempContacts);
331 product.setContacts(tempContacts);
333 return Either.left(true);
336 private Either<Boolean, ResponseFormat> validateGrouping(User user, Product product, AuditingActionEnum actionEnum) {
337 List<CategoryDefinition> categories = product.getCategories();
338 if (categories == null || categories.isEmpty()) {
339 log.debug("Grouping list is empty for product: {}", product.getName());
340 return Either.left(true);
342 Map<String, Map<String, Set<String>>> nonDuplicatedCategories = new HashMap<String, Map<String, Set<String>>>();
343 // remove duplicated entries
344 for (CategoryDefinition cat : categories) {
345 String catName = cat.getName();
346 if (ValidationUtils.validateStringNotEmpty(catName) == false) {
347 // error missing cat name
348 log.debug("Missing category name for product: {}", product.getName());
349 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_CATEGORY, ComponentTypeEnum.PRODUCT.getValue());
350 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
351 return Either.right(responseFormat);
353 Map<String, Set<String>> catEntry = nonDuplicatedCategories.get(catName);
354 if (catEntry == null) {
355 catEntry = new HashMap<String, Set<String>>();
356 nonDuplicatedCategories.put(catName, catEntry);
358 List<SubCategoryDefinition> subcategories = cat.getSubcategories();
359 if (subcategories == null || subcategories.isEmpty()) {
360 // error missing subcat for cat
361 log.debug("Missing sub-categories for category {} in product {}", catName, product.getName());
362 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_SUBCATEGORY);
363 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
364 return Either.right(responseFormat);
366 for (SubCategoryDefinition subcat : subcategories) {
367 String subCatName = subcat.getName();
368 if (ValidationUtils.validateStringNotEmpty(subCatName) == false) {
369 // error missing sub cat name for cat
370 log.debug("Missing or empty sub-category for category {} in product {}", catName, product.getName());
371 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_SUBCATEGORY);
372 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
373 return Either.right(responseFormat);
375 Set<String> subcatEntry = catEntry.get(subCatName);
376 if (subcatEntry == null) {
377 subcatEntry = new HashSet<String>();
378 catEntry.put(subCatName, subcatEntry);
380 List<GroupingDefinition> groupings = subcat.getGroupings();
381 for (GroupingDefinition group : groupings) {
382 String groupName = group.getName();
383 if (ValidationUtils.validateStringNotEmpty(groupName) == false) {
384 // error missing grouping for sub cat name and cat
385 log.debug("Missing or empty groupng name for sub-category: {} for categor: {} in product: {}", subCatName, catName, product.getName());
386 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_SUBCATEGORY);
387 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
388 return Either.right(responseFormat);
390 if (!subcatEntry.contains(groupName)) {
391 subcatEntry.add(groupName);
393 log.debug("Grouping: {}, already exist for category: {} and subcategory: {}", groupName, catName, subCatName);
397 } // for end of checking duplicated
398 // validate existence
399 Either<List<CategoryDefinition>, ActionStatus> allProductCategories = elementDao.getAllProductCategories();
401 if (allProductCategories.isRight()) {
402 log.debug("No product categories {}", allProductCategories.right().value());
403 ResponseFormat responseFormat = componentsUtils.getResponseFormat(allProductCategories.right().value());
404 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
405 return Either.right(responseFormat);
408 // convert non-duplicated to data modeling format and update in the
410 List<CategoryDefinition> newCatList = new ArrayList<CategoryDefinition>();
412 // over all categories from request
413 for (Map.Entry<String, Map<String, Set<String>>> entry : nonDuplicatedCategories.entrySet()) {
415 CategoryDefinition categoryDefinition = null;
416 // over all categories from Titan
417 List<CategoryDefinition> categoriesList = allProductCategories.left().value();
418 if (categoriesList != null) {
419 for (CategoryDefinition catInDb : categoriesList) {
420 if (entry.getKey().equals(catInDb.getName())) {
424 categoryDefinition = new CategoryDefinition(catInDb);
425 SubCategoryDefinition subCategory = null;
427 Map<String, Set<String>> subcats = entry.getValue();
428 for (Map.Entry<String, Set<String>> subcat : subcats.entrySet()) {
430 List<SubCategoryDefinition> subcategoriesList = catInDb.getSubcategories();
431 if (subcategoriesList != null) {
432 for (SubCategoryDefinition subcatInDb : subcategoriesList) {
433 if (subcatInDb.getName().equals(subcat.getKey())) {
435 subCategory = new SubCategoryDefinition(subcatInDb);
437 Set<String> grouping = subcat.getValue();
439 GroupingDefinition groupingDefinition = null;
440 for (String group : grouping) {
442 List<GroupingDefinition> groupings = subcatInDb.getGroupings();
443 if (groupings != null) {
444 for (GroupingDefinition groupInDb : groupings) {
445 if (groupInDb.getName().equals(group)) {
447 groupingDefinition = new GroupingDefinition(groupInDb);
452 // error grouping isn't defined
454 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_GROUP_ASSOCIATION, CategoryTypeEnum.GROUPING.getValue(), group);
455 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
456 return Either.right(responseFormat);
458 subCategory.addGrouping(groupingDefinition);
464 // error sub category isn't defined in Titan
465 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_GROUP_ASSOCIATION, CategoryTypeEnum.SUBCATEGORY.getValue(), subcat.getKey());
466 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
467 return Either.right(responseFormat);
469 categoryDefinition.addSubCategory(subCategory);
475 // error category isn't defined in Titan
476 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_GROUP_ASSOCIATION, CategoryTypeEnum.CATEGORY.getValue(), entry.getKey());
477 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
478 return Either.right(responseFormat);
480 newCatList.add(categoryDefinition);
482 product.setCategories(newCatList);
483 return Either.left(true);
486 public Either<Product, ResponseFormat> getProduct(String productId, User user) {
487 String ecompErrorContext = "Get product";
488 Either<User, ResponseFormat> validateEmptyResult = validateUserNotEmpty(user, ecompErrorContext);
489 if (validateEmptyResult.isRight()) {
490 return Either.right(validateEmptyResult.right().value());
493 Either<User, ResponseFormat> eitherCreator = validateUserExists(user, ecompErrorContext, false);
494 if (eitherCreator.isRight()) {
495 return Either.right(eitherCreator.right().value());
498 Either<Product, StorageOperationStatus> storageStatus = toscaOperationFacade.getToscaElement(productId);
500 if (storageStatus.isRight()) {
501 log.debug("failed to get resource by id {}", productId);
502 if (storageStatus.right().value().equals(StorageOperationStatus.NOT_FOUND)) {
504 return Either.right(componentsUtils.getResponseFormat(ActionStatus.PRODUCT_NOT_FOUND, ComponentTypeEnum.PRODUCT.getValue()));
506 return Either.right(componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(storageStatus.right().value()), ""));
509 return Either.left(storageStatus.left().value());
512 public Either<Product, ResponseFormat> deleteProduct(String productId, User user) {
513 String ecompErrorContext = "Delete product";
514 Either<User, ResponseFormat> validateEmptyResult = validateUserNotEmpty(user, ecompErrorContext);
515 if (validateEmptyResult.isRight()) {
516 return Either.right(validateEmptyResult.right().value());
519 Either<User, ResponseFormat> eitherCreator = validateUserExists(user, ecompErrorContext, false);
520 if (eitherCreator.isRight()) {
521 return Either.right(eitherCreator.right().value());
524 Either<Product, StorageOperationStatus> storageStatus = toscaOperationFacade.deleteToscaComponent(productId);
526 if (storageStatus.isRight()) {
527 log.debug("failed to delete resource by id {}", productId);
528 return Either.right(componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(storageStatus.right().value()), ""));
530 return Either.left(storageStatus.left().value());
533 private Either<Boolean, ResponseFormat> validateProductFullNameAndCleanup(User user, Product product, AuditingActionEnum actionEnum) {
534 String fullName = product.getFullName();
535 if (!ValidationUtils.validateStringNotEmpty(fullName)) {
536 ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.MISSING_ONE_OF_COMPONENT_NAMES, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_FULL_NAME);
537 componentsUtils.auditComponentAdmin(errorResponse, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
538 return Either.right(errorResponse);
541 fullName = ValidationUtils.removeNoneUtf8Chars(fullName);
542 fullName = ValidationUtils.removeHtmlTags(fullName);
543 fullName = ValidationUtils.normaliseWhitespace(fullName);
544 fullName = ValidationUtils.stripOctets(fullName);
546 if (!ValidationUtils.validateProductFullNameLength(fullName)) {
547 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_FULL_NAME);
548 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
549 return Either.right(responseFormat);
552 if (!ValidationUtils.validateIsEnglish(fullName)) {
553 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_FULL_NAME);
554 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
555 return Either.right(responseFormat);
558 product.setFullName(fullName);
559 return Either.left(true);
562 private Either<Boolean, ResponseFormat> validateProductNameAndCleanup(User user, Product product, AuditingActionEnum actionEnum) {
563 String name = product.getName();
564 if (!ValidationUtils.validateStringNotEmpty(name)) {
565 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.MISSING_ONE_OF_COMPONENT_NAMES, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_ABBREVIATED_NAME);
566 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
567 return Either.right(responseFormat);
570 // Product name is required to have same validation and normalization as
572 if (!ValidationUtils.validateCategoryDisplayNameFormat(name)) {
573 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_ABBREVIATED_NAME);
574 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
575 return Either.right(responseFormat);
578 String normalizedName4Display = ValidationUtils.normalizeCategoryName4Display(name);
580 if (!ValidationUtils.validateCategoryDisplayNameLength(normalizedName4Display)) {
581 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_ABBREVIATED_NAME);
582 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
583 return Either.right(responseFormat);
586 product.setName(normalizedName4Display);
587 String normalizedName4Uniqueness = ValidationUtils.normaliseComponentName(normalizedName4Display);
588 product.setNormalizedName(normalizedName4Uniqueness);
590 return Either.left(true);
593 // This is a workaround for a current tag--->product name behaviour, which
594 // will be changed in 1607.
595 // It was agreed with Ella on 23/2/16 that the tag validation of product
596 // will be made against the old product name (before normalization),
597 // and in 1607 US will be defined where UI will no longer pass tag of
598 // component name, and BE will add it by itself after all needed
600 private Either<Boolean, ResponseFormat> validateTagsListAndRemoveDuplicates(User user, Product product, String oldProductName, AuditingActionEnum actionEnum) {
601 List<String> tagsList = product.getTags();
603 Either<Boolean, ResponseFormat> validateTags = validateComponentTags(tagsList, oldProductName, ComponentTypeEnum.PRODUCT);
604 if (validateTags.isRight()) {
605 ResponseFormat responseFormat = validateTags.right().value();
606 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
607 return Either.right(responseFormat);
609 ValidationUtils.removeDuplicateFromList(tagsList);
610 return Either.left(true);
614 public void setDeploymentArtifactsPlaceHolder(org.openecomp.sdc.be.model.Component component, User user) {
618 public Either<Product, ResponseFormat> updateProductMetadata(String productId, Product updatedProduct, User user) {
619 ComponentTypeEnum typeEnum = ComponentTypeEnum.PRODUCT;
620 Either<User, ResponseFormat> eitherCreator = validateUser(user, "Update Product", updatedProduct, null, false);
621 if (eitherCreator.isRight()) {
622 return Either.right(eitherCreator.right().value());
624 user = eitherCreator.left().value();
626 // validate user role
627 Either<Boolean, ResponseFormat> validateRes = validateUserRole(user, updatedProduct, updateRoles, null, null);
628 if (validateRes.isRight()) {
629 return Either.right(validateRes.right().value());
632 if (updatedProduct == null) {
633 log.debug("Invalid product json. Check product servlet log for updateProduct entry params");
634 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
635 return Either.right(responseFormat);
638 Either<Product, StorageOperationStatus> storageStatus = toscaOperationFacade.getToscaElement(productId);
639 if (storageStatus.isRight()) {
640 if (storageStatus.right().value().equals(StorageOperationStatus.NOT_FOUND)) {
641 return Either.right(componentsUtils.getResponseFormat(ActionStatus.PRODUCT_NOT_FOUND, ComponentTypeEnum.PRODUCT.name().toLowerCase()));
643 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(storageStatus.right().value(), typeEnum), ""));
646 Product currentProduct = storageStatus.left().value();
648 if (!ComponentValidationUtils.canWorkOnComponent(productId, toscaOperationFacade, user.getUserId())) {
649 log.info("Restricted operation for user: {}, on product: {}" , user.getUserId(), currentProduct.getCreatorUserId());
650 return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
653 Either<Product, ResponseFormat> validationRsponse = validateAndUpdateProductMetadata(user, currentProduct, updatedProduct);
654 if (validationRsponse.isRight()) {
655 log.info("product update metadata: validations field.");
656 return validationRsponse;
659 Product productToUpdate = validationRsponse.left().value();
661 Either<Boolean, ResponseFormat> lockResult = lockComponent(currentProduct.getUniqueId(), currentProduct, "Update Product Metadata");
662 if (lockResult.isRight()) {
663 return Either.right(lockResult.right().value());
666 Either<Product, StorageOperationStatus> updateResponse = toscaOperationFacade.updateToscaElement(productToUpdate);
667 if (updateResponse.isRight()) {
668 toscaOperationFacade.rollback();
669 log.debug("failed to update product {}", productToUpdate.getUniqueId());
670 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
672 toscaOperationFacade.commit();
673 return Either.left(updateResponse.left().value());
675 graphLockOperation.unlockComponent(productId, NodeTypeEnum.Product);
679 private Either<Product, ResponseFormat> validateAndUpdateProductMetadata(User user, Product currentProduct, Product updatedProduct) {
681 boolean hasBeenCertified = ValidationUtils.hasBeenCertified(currentProduct.getVersion());
682 Either<Boolean, ResponseFormat> response = validateAndUpdateProductName(user, currentProduct, updatedProduct);
683 if (response.isRight()) {
684 ResponseFormat errorResponse = response.right().value();
685 return Either.right(errorResponse);
688 response = validateAndUpdateFullName(user, currentProduct, updatedProduct);
689 if (response.isRight()) {
690 ResponseFormat errorResponse = response.right().value();
691 return Either.right(errorResponse);
694 response = validateAndUpdateDescription(user, currentProduct, updatedProduct, null);
695 if (response.isRight()) {
696 ResponseFormat errorResponse = response.right().value();
697 return Either.right(errorResponse);
700 response = validateAndUpdateCategory(user, currentProduct, updatedProduct);
701 if (response.isRight()) {
702 ResponseFormat errorResponse = response.right().value();
703 return Either.right(errorResponse);
706 response = validateAndUpdateContactList(user, currentProduct, updatedProduct);
707 if (response.isRight()) {
708 ResponseFormat errorResponse = response.right().value();
709 return Either.right(errorResponse);
712 response = validateAndUpdateTags(user, currentProduct, updatedProduct);
713 if (response.isRight()) {
714 ResponseFormat errorResponse = response.right().value();
715 return Either.right(errorResponse);
718 response = validateAndUpdateProjectCode(user, currentProduct, updatedProduct);
719 if (response.isRight()) {
720 ResponseFormat errorResponse = response.right().value();
721 return Either.right(errorResponse);
724 if (updatedProduct.getIsActive() != null) {
725 currentProduct.setIsActive(updatedProduct.getIsActive());
728 response = validateAndUpdateIcon(user, currentProduct, updatedProduct, hasBeenCertified);
729 if (response.isRight()) {
730 ResponseFormat errorResponse = response.right().value();
731 return Either.right(errorResponse);
734 String currentInvariantUuid = currentProduct.getInvariantUUID();
735 String updatedInvariantUuid = updatedProduct.getInvariantUUID();
737 if ((updatedInvariantUuid != null) && (!updatedInvariantUuid.equals(currentInvariantUuid))) {
738 log.warn("Product invariant UUID is automatically set and cannot be updated");
739 updatedProduct.setInvariantUUID(currentInvariantUuid);
741 return Either.left(currentProduct);
745 private Either<Boolean, ResponseFormat> validateAndUpdateProductName(User user, Product currentProduct, Product updatedProduct) {
746 String updatedProductName = updatedProduct.getName();
748 String currentProductName = currentProduct.getName();
749 if (updatedProductName != null) {
750 Either<Boolean, ResponseFormat> validatProductNameResponse = validateProductNameAndCleanup(user, updatedProduct, null);
751 if (validatProductNameResponse.isRight()) {
752 ResponseFormat errorRespons = validatProductNameResponse.right().value();
753 return Either.right(errorRespons);
755 updatedProductName = updatedProduct.getName();
756 if (!currentProductName.equals(updatedProductName)) {
757 Either<Boolean, ResponseFormat> productNameUniquenessValidation = validateComponentNameUnique(user, updatedProduct, null);
758 if (productNameUniquenessValidation.isRight()) {
759 return productNameUniquenessValidation;
761 currentProduct.setName(updatedProductName);
762 tags = updatedProductName;
763 updatedProductName = ValidationUtils.normalizeCategoryName4Display(updatedProductName);
764 currentProduct.getComponentMetadataDefinition().getMetadataDataDefinition().setNormalizedName(ValidationUtils.normaliseComponentName(updatedProductName));
765 List<String> updatedTags = updatedProduct.getTags();
766 // As discussed with Ella currently (1604) we are not removing
767 // the old name from tags.
768 if (updatedTags == null) {
769 updatedTags = currentProduct.getTags();
771 updatedTags.add(tags);
774 return Either.left(true);
777 private Either<Boolean, ResponseFormat> validateAndUpdateFullName(User user, Product currentProduct, Product updatedProduct) {
778 String updatedProductName = updatedProduct.getFullName();
779 String currentProductName = currentProduct.getFullName();
780 if (updatedProductName != null && !currentProductName.equals(updatedProductName)) {
781 Either<Boolean, ResponseFormat> validatProductNameResponse = validateProductFullNameAndCleanup(user, updatedProduct, null);
782 if (validatProductNameResponse.isRight()) {
783 ResponseFormat errorRespons = validatProductNameResponse.right().value();
784 return Either.right(errorRespons);
786 currentProduct.setFullName(updatedProduct.getFullName());
788 return Either.left(true);
791 private Either<Boolean, ResponseFormat> validateAndUpdateCategory(User user, Product currentProduct, Product updatedProduct) {
792 List<CategoryDefinition> categoryUpdated = updatedProduct.getCategories();
794 Either<Boolean, ResponseFormat> validatCategoryResponse = validateGrouping(user, updatedProduct, null);
795 if (validatCategoryResponse.isRight()) {
796 ResponseFormat errorResponse = validatCategoryResponse.right().value();
797 return Either.right(errorResponse);
800 categoryUpdated = updatedProduct.getCategories();
801 if (categoryUpdated != null) {
802 currentProduct.setCategories(categoryUpdated);
804 return Either.left(true);
807 private Either<Boolean, ResponseFormat> validateAndUpdateContactList(User user, Product currentProduct, Product updatedProduct) {
808 List<String> updatedContacts = updatedProduct.getContacts();
809 List<String> currentContacts = currentProduct.getContacts();
810 if (updatedContacts != null) {
811 if (!(currentContacts.containsAll(updatedContacts) && updatedContacts.containsAll(currentContacts))) {
812 Either<Boolean, ResponseFormat> validatResponse = validateAndUpdateProductContactsList(user, updatedProduct, null);
813 if (validatResponse.isRight()) {
814 ResponseFormat errorRespons = validatResponse.right().value();
815 return Either.right(errorRespons);
817 currentProduct.setContacts(updatedProduct.getContacts());
820 return Either.left(true);
823 private Either<Boolean, ResponseFormat> validateAndUpdateTags(User user, Product currentProduct, Product updatedProduct) {
824 List<String> tagsUpdated = updatedProduct.getTags();
825 List<String> tagsCurrent = currentProduct.getTags();
826 if (tagsUpdated != null) {
827 if (!(tagsCurrent.containsAll(tagsUpdated) && tagsUpdated.containsAll(tagsCurrent))) {
828 Either<Boolean, ResponseFormat> validatResponse = validateTagsListAndRemoveDuplicates(user, updatedProduct, currentProduct.getName(), null);
829 if (validatResponse.isRight()) {
830 ResponseFormat errorRespons = validatResponse.right().value();
831 return Either.right(errorRespons);
833 currentProduct.setTags(updatedProduct.getTags());
836 return Either.left(true);
840 public Either<List<String>, ResponseFormat> deleteMarkedComponents() {
841 // markAsDeleted isnt implemented yet
842 return Either.left(new ArrayList<>());
846 protected boolean validateTagPattern(String tag) {
847 return ValidationUtils.validateCategoryDisplayNameFormat(tag);
850 public Either<Product, ResponseFormat> getProductByNameAndVersion(String productName, String productVersion, String userId) {
851 Either<User, ResponseFormat> resp = validateUserExists(userId, "get Service By Name And Version", false);
852 if (resp.isRight()) {
853 return Either.right(resp.right().value());
855 Either<Product, StorageOperationStatus> storageStatus = toscaOperationFacade.getComponentByNameAndVersion(ComponentTypeEnum.PRODUCT, productName, productVersion);
856 if (storageStatus.isRight()) {
857 log.debug("failed to get service by name {} and version {}", productName, productVersion);
858 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(storageStatus.right().value(), ComponentTypeEnum.PRODUCT), productName));
860 Product product = storageStatus.left().value();
861 return Either.left(product);
865 public ComponentInstanceBusinessLogic getComponentInstanceBL() {
866 return componentInstanceBusinessLogic;
870 public Either<List<ComponentInstance>, ResponseFormat> getComponentInstancesFilteredByPropertiesAndInputs(String componentId, ComponentTypeEnum componentTypeEnum, String userId, String searchText) {
874 public ICacheMangerOperation getCacheManagerOperation() {
875 return cacheManagerOperation;
878 public void setCacheManagerOperation(ICacheMangerOperation cacheManagerOperation) {
879 this.cacheManagerOperation = cacheManagerOperation;
883 public Either<UiComponentDataTransfer, ResponseFormat> getUiComponentDataTransferByComponentId(String componentId,
884 List<String> dataParamsToReturn) {
885 // TODO Auto-generated method stub