2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
19 * Modifications copyright (c) 2019 Nokia
20 * ================================================================================
22 package org.openecomp.sdc.be.components.impl;
24 import fj.data.Either;
25 import java.util.ArrayList;
26 import java.util.HashMap;
27 import java.util.HashSet;
28 import java.util.List;
31 import java.util.stream.Collectors;
32 import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
33 import org.openecomp.sdc.be.components.impl.exceptions.ComponentException;
34 import org.openecomp.sdc.be.components.validation.component.ComponentContactIdValidator;
35 import org.openecomp.sdc.be.components.validation.component.ComponentDescriptionValidator;
36 import org.openecomp.sdc.be.components.validation.component.ComponentIconValidator;
37 import org.openecomp.sdc.be.components.validation.component.ComponentNameValidator;
38 import org.openecomp.sdc.be.components.validation.component.ComponentProjectCodeValidator;
39 import org.openecomp.sdc.be.components.validation.component.ComponentTagsValidator;
40 import org.openecomp.sdc.be.components.validation.component.ComponentValidator;
41 import org.openecomp.sdc.be.dao.api.ActionStatus;
42 import org.openecomp.sdc.be.datamodel.api.CategoryTypeEnum;
43 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
44 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
45 import org.openecomp.sdc.be.model.ComponentInstance;
46 import org.openecomp.sdc.be.model.LifecycleStateEnum;
47 import org.openecomp.sdc.be.model.Product;
48 import org.openecomp.sdc.be.model.User;
49 import org.openecomp.sdc.be.model.category.CategoryDefinition;
50 import org.openecomp.sdc.be.model.category.GroupingDefinition;
51 import org.openecomp.sdc.be.model.category.SubCategoryDefinition;
52 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ArtifactsOperations;
53 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.InterfaceOperation;
54 import org.openecomp.sdc.be.model.operations.api.IElementOperation;
55 import org.openecomp.sdc.be.model.operations.api.IGroupInstanceOperation;
56 import org.openecomp.sdc.be.model.operations.api.IGroupOperation;
57 import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation;
58 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
59 import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation;
60 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
61 import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils;
62 import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
63 import org.openecomp.sdc.be.ui.model.UiComponentDataTransfer;
64 import org.openecomp.sdc.be.user.Role;
65 import org.openecomp.sdc.common.log.wrappers.Logger;
66 import org.openecomp.sdc.common.util.ValidationUtils;
67 import org.openecomp.sdc.exception.ResponseFormat;
68 import org.springframework.beans.factory.annotation.Autowired;
70 @org.springframework.stereotype.Component("productBusinessLogic")
71 public class ProductBusinessLogic extends ComponentBusinessLogic {
73 private static final String PRODUCT_FULL_NAME = "full";
74 private static final String PRODUCT_ABBREVIATED_NAME = "abbreviated";
75 private static final Logger log = Logger.getLogger(ProductBusinessLogic.class);
76 private static final String INITIAL_VERSION = "0.1";
77 private static final String CREATE_PRODUCT = "Create Product";
78 private static List<Role> creationRoles;
79 private static List<Role> updateRoles;
80 private static List<Role> contactsRoles;
81 private final ComponentInstanceBusinessLogic componentInstanceBusinessLogic;
84 public ProductBusinessLogic(IElementOperation elementDao, IGroupOperation groupOperation, IGroupInstanceOperation groupInstanceOperation,
85 IGroupTypeOperation groupTypeOperation, GroupBusinessLogic groupBusinessLogic, InterfaceOperation interfaceOperation,
86 InterfaceLifecycleOperation interfaceLifecycleTypeOperation, ArtifactsBusinessLogic artifactsBusinessLogic,
87 ComponentInstanceBusinessLogic componentInstanceBusinessLogic, ArtifactsOperations artifactToscaOperation,
88 ComponentContactIdValidator componentContactIdValidator, ComponentNameValidator componentNameValidator,
89 ComponentTagsValidator componentTagsValidator, ComponentValidator componentValidator,
90 ComponentIconValidator componentIconValidator, ComponentProjectCodeValidator componentProjectCodeValidator,
91 ComponentDescriptionValidator componentDescriptionValidator) {
92 super(elementDao, groupOperation, groupInstanceOperation, groupTypeOperation, groupBusinessLogic, interfaceOperation,
93 interfaceLifecycleTypeOperation, artifactsBusinessLogic, artifactToscaOperation, componentContactIdValidator, componentNameValidator,
94 componentTagsValidator, componentValidator, componentIconValidator, componentProjectCodeValidator, componentDescriptionValidator);
95 this.componentInstanceBusinessLogic = componentInstanceBusinessLogic;
96 creationRoles = new ArrayList<>();
97 updateRoles = new ArrayList<>();
98 contactsRoles = new ArrayList<>();
99 // only PM is allowed to create/update products
100 creationRoles.add(Role.PRODUCT_MANAGER);
101 updateRoles.add(Role.PRODUCT_MANAGER);
102 // Only PM is allowed to be product contacts
103 contactsRoles.add(Role.PRODUCT_MANAGER);
106 public Either<Product, ResponseFormat> createProduct(Product product, User user) {
107 AuditingActionEnum actionEnum = AuditingActionEnum.CREATE_RESOURCE;
108 ComponentTypeEnum typeEnum = ComponentTypeEnum.PRODUCT;
109 // validate user - should be first to get the maximum auditing info in
111 // case of subsequent failures
112 log.debug("get user from DB");
113 user = validateUser(user, CREATE_PRODUCT, product, actionEnum, false);
114 // validate user role
115 validateUserRole(user, product, creationRoles, actionEnum, null);
116 if (product == null) {
117 log.debug("Invalid product json. Check product servlet log for createProduct entry params");
118 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
119 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, typeEnum);
120 return Either.right(responseFormat);
122 // warn about non-updatable fields
123 checkUnupdatableProductFields(product);
124 Either<Product, ResponseFormat> validateProductResponse = validateProductBeforeCreate(product, user, actionEnum);
125 if (validateProductResponse.isRight()) {
126 return Either.right(validateProductResponse.right().value());
128 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);
135 log.debug("Product name locked is {}, status = {}", product.getSystemName(), lockResult);
137 Either<Product, StorageOperationStatus> createProductEither = toscaOperationFacade.createToscaComponent(product);
138 if (createProductEither.isRight()) {
139 ResponseFormat responseFormat = componentsUtils
140 .getResponseFormatByComponent(componentsUtils.convertFromStorageResponse(createProductEither.right().value()), product, typeEnum);
141 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, typeEnum);
142 return Either.right(responseFormat);
144 log.debug("Product created successfully");
145 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.CREATED);
146 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, typeEnum);
147 Product createdProduct = createProductEither.left().value();
148 return Either.left(createdProduct);
150 graphLockOperation.unlockComponentByName(product.getSystemName(), product.getUniqueId(), NodeTypeEnum.Product);
154 private void checkUnupdatableProductFields(Product product) {
155 checkComponentFieldsForOverrideAttempt(product);
156 if (product.getNormalizedName() != null) {
157 log.info("NormalizedName cannot be defined by user. This field will be overridden by the application");
161 private Either<Product, ResponseFormat> validateProductBeforeCreate(Product product, User user, AuditingActionEnum actionEnum) {
162 Either<Boolean, ResponseFormat> validateProductFields = validateProductFieldsBeforeCreate(user, product, actionEnum);
163 if (validateProductFields.isRight()) {
164 return Either.right(validateProductFields.right().value());
166 if (product.getIsActive() == null) {
167 log.debug("no isActive value was provided, setting to default: false");
168 product.setIsActive(false);
170 product.setCreatorUserId(user.getUserId());
172 log.debug("enrich product with version and state");
173 product.setState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT);
174 product.setVersion(INITIAL_VERSION);
175 // Generate invariant UUID - must be here and not in operation since it
177 // should stay constant during clone
178 String invariantUUID = UniqueIdBuilder.buildInvariantUUID();
179 product.setInvariantUUID(invariantUUID);
180 return Either.left(product);
183 private Either<Boolean, ResponseFormat> validateProductFieldsBeforeCreate(User user, Product product, AuditingActionEnum actionEnum) {
184 // To be removed in 1607
187 String oldName = product.getName();
188 Either<Boolean, ResponseFormat> componentNameValidation = validateProductNameAndCleanup(user, product, actionEnum);
189 if (componentNameValidation.isRight()) {
190 return componentNameValidation;
193 componentNameValidator.validateComponentNameUnique(user, product, actionEnum);
194 } catch (ComponentException exp) {
195 return Either.right(exp.getResponseFormat());
197 // To be removed in 1607 and replaced with generic
199 // validateTagsListAndRemoveDuplicates()
201 // See comments on the validateTagsListAndRemoveDuplicates(user,
203 // product, oldName, actionEnum) function
204 Either<Boolean, ResponseFormat> tagsValidation = validateTagsListAndRemoveDuplicates(user, product, oldName, actionEnum);
205 if (tagsValidation.isRight()) {
206 return tagsValidation;
208 componentTagsValidator.validateAndCorrectField(user, product, actionEnum);
210 componentProjectCodeValidator.validateAndCorrectField(user, product, actionEnum);
211 } catch (ComponentException exp) {
212 return Either.right(exp.getResponseFormat());
214 Either<Boolean, ResponseFormat> categoryValidation = validateGrouping(user, product, actionEnum);
215 if (categoryValidation.isRight()) {
216 return categoryValidation;
218 Either<Boolean, ResponseFormat> contactsListValidation = validateAndUpdateProductContactsList(user, product, actionEnum);
219 if (contactsListValidation.isRight()) {
220 return contactsListValidation;
222 Either<Boolean, ResponseFormat> productFullNameValidation = validateProductFullNameAndCleanup(user, product, actionEnum);
223 if (productFullNameValidation.isRight()) {
224 return productFullNameValidation;
226 componentDescriptionValidator.validateAndCorrectField(user, product, actionEnum);
227 return Either.left(true);
230 public Either<Map<String, Boolean>, ResponseFormat> validateProductNameExists(String productName, String userId) {
231 validateUserExists(userId);
232 Either<Boolean, StorageOperationStatus> dataModelResponse = toscaOperationFacade
233 .validateComponentNameUniqueness(productName, null, ComponentTypeEnum.PRODUCT);
235 janusGraphDao.commit();
236 if (dataModelResponse.isLeft()) {
237 Map<String, Boolean> result = new HashMap<>();
238 result.put("isValid", dataModelResponse.left().value());
239 log.debug("validation was successfully performed.");
240 return Either.left(result);
242 ResponseFormat responseFormat = componentsUtils
243 .getResponseFormat(componentsUtils.convertFromStorageResponse(dataModelResponse.right().value()));
244 return Either.right(responseFormat);
247 private Either<Boolean, ResponseFormat> validateAndUpdateProductContactsList(User user, Product product, AuditingActionEnum actionEnum) {
248 List<String> contacts = product.getContacts();
249 if (!ValidationUtils.validateListNotEmpty(contacts)) {
250 log.debug("Contacts list cannot be empty for product {}", product.getName());
251 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.EMPTY_PRODUCT_CONTACTS_LIST);
252 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
253 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
267 .getResponseFormat(ActionStatus.COMPONENT_INVALID_CONTACT, ComponentTypeEnum.PRODUCT.getValue());
268 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
269 return Either.right(responseFormat);
273 contactUser = validateUserExists(contact);
274 validateUserRole(contactUser, contactsRoles);
275 } catch (ByActionStatusComponentException 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 ByActionStatusComponentException(e.getActionStatus(), e.getParams());
282 if (!isProductCreatorInContacts) {
283 log.debug("modifier userId {} not found in product contacts - adding it", modifierUserId);
284 contacts.add(modifierUserId);
286 // passed - setting all contacts userIds to lowercase
287 List<String> tempContacts = contacts.stream().map(String::toLowerCase).collect(Collectors.toList());
288 ValidationUtils.removeDuplicateFromList(tempContacts);
289 product.setContacts(tempContacts);
290 return Either.left(true);
293 private Either<Boolean, ResponseFormat> validateGrouping(User user, Product product, AuditingActionEnum actionEnum) {
294 List<CategoryDefinition> categories = product.getCategories();
295 if (categories == null || categories.isEmpty()) {
296 log.debug("Grouping list is empty for product: {}", product.getName());
297 return Either.left(true);
299 Map<String, Map<String, Set<String>>> nonDuplicatedCategories = new HashMap<>();
300 // remove duplicated entries
301 for (CategoryDefinition cat : categories) {
302 String catName = cat.getName();
303 if (!ValidationUtils.validateStringNotEmpty(catName)) {
304 // error missing cat name
305 log.debug("Missing category name for product: {}", product.getName());
306 ResponseFormat responseFormat = componentsUtils
307 .getResponseFormat(ActionStatus.COMPONENT_MISSING_CATEGORY, ComponentTypeEnum.PRODUCT.getValue());
308 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
309 return Either.right(responseFormat);
311 Map<String, Set<String>> catEntry = nonDuplicatedCategories.get(catName);
312 if (catEntry == null) {
313 catEntry = new HashMap<>();
314 nonDuplicatedCategories.put(catName, catEntry);
316 List<SubCategoryDefinition> subcategories = cat.getSubcategories();
317 if (subcategories == null || subcategories.isEmpty()) {
318 // error missing subcat for cat
319 log.debug("Missing sub-categories for category {} in product {}", catName, product.getName());
320 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_SUBCATEGORY);
321 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
322 return Either.right(responseFormat);
324 for (SubCategoryDefinition subcat : subcategories) {
325 String subCatName = subcat.getName();
326 if (!ValidationUtils.validateStringNotEmpty(subCatName)) {
327 // error missing sub cat name for cat
328 log.debug("Missing or empty sub-category for category {} in product {}", catName, product.getName());
329 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_SUBCATEGORY);
330 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
331 return Either.right(responseFormat);
333 Set<String> subcatEntry = catEntry.get(subCatName);
334 if (subcatEntry == null) {
335 subcatEntry = new HashSet<>();
336 catEntry.put(subCatName, subcatEntry);
338 List<GroupingDefinition> groupings = subcat.getGroupings();
339 for (GroupingDefinition group : groupings) {
340 String groupName = group.getName();
341 if (!ValidationUtils.validateStringNotEmpty(groupName)) {
342 // error missing grouping for sub cat name and cat
343 log.debug("Missing or empty groupng name for sub-category: {} for categor: {} in product: {}", subCatName, catName,
345 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_SUBCATEGORY);
346 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
347 return Either.right(responseFormat);
349 if (!subcatEntry.contains(groupName)) {
350 subcatEntry.add(groupName);
352 log.debug("Grouping: {}, already exist for category: {} and subcategory: {}", groupName, catName, subCatName);
356 } // for end of checking duplicated
358 // validate existence
359 Either<List<CategoryDefinition>, ActionStatus> allProductCategories = elementDao.getAllProductCategories();
360 if (allProductCategories.isRight()) {
361 log.debug("No product categories {}", allProductCategories.right().value());
362 ResponseFormat responseFormat = componentsUtils.getResponseFormat(allProductCategories.right().value());
363 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
364 return Either.right(responseFormat);
367 // convert non-duplicated to data modeling format and update in the
370 List<CategoryDefinition> newCatList = new ArrayList<>();
371 // over all categories from request
372 for (Map.Entry<String, Map<String, Set<String>>> entry : nonDuplicatedCategories.entrySet()) {
374 CategoryDefinition categoryDefinition = null;
375 // over all categories from JanusGraph
376 List<CategoryDefinition> categoriesList = allProductCategories.left().value();
377 if (categoriesList != null) {
378 for (CategoryDefinition catInDb : categoriesList) {
379 if (entry.getKey().equals(catInDb.getName())) {
383 categoryDefinition = new CategoryDefinition(catInDb);
384 SubCategoryDefinition subCategory = null;
385 Map<String, Set<String>> subcats = entry.getValue();
386 for (Map.Entry<String, Set<String>> subcat : subcats.entrySet()) {
388 List<SubCategoryDefinition> subcategoriesList = catInDb.getSubcategories();
389 if (subcategoriesList != null) {
390 for (SubCategoryDefinition subcatInDb : subcategoriesList) {
391 if (subcatInDb.getName().equals(subcat.getKey())) {
393 subCategory = new SubCategoryDefinition(subcatInDb);
395 Set<String> grouping = subcat.getValue();
397 GroupingDefinition groupingDefinition = null;
398 for (String group : grouping) {
400 List<GroupingDefinition> groupings = subcatInDb.getGroupings();
401 if (groupings != null) {
402 for (GroupingDefinition groupInDb : groupings) {
403 if (groupInDb.getName().equals(group)) {
405 groupingDefinition = new GroupingDefinition(groupInDb);
410 // error grouping isn't defined
413 ResponseFormat responseFormat = componentsUtils
414 .getResponseFormat(ActionStatus.INVALID_GROUP_ASSOCIATION, CategoryTypeEnum.GROUPING.getValue(),
417 .auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
418 return Either.right(responseFormat);
420 subCategory.addGrouping(groupingDefinition);
426 // error sub category isn't defined in JanusGraph
427 ResponseFormat responseFormat = componentsUtils
428 .getResponseFormat(ActionStatus.INVALID_GROUP_ASSOCIATION, CategoryTypeEnum.SUBCATEGORY.getValue(),
430 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
431 return Either.right(responseFormat);
433 categoryDefinition.addSubCategory(subCategory);
439 // error category isn't defined in JanusGraph
440 ResponseFormat responseFormat = componentsUtils
441 .getResponseFormat(ActionStatus.INVALID_GROUP_ASSOCIATION, CategoryTypeEnum.CATEGORY.getValue(), entry.getKey());
442 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
443 return Either.right(responseFormat);
445 newCatList.add(categoryDefinition);
447 product.setCategories(newCatList);
448 return Either.left(true);
451 public Either<Product, ResponseFormat> getProduct(String productId, User user) {
452 String ecompErrorContext = "Get product";
453 validateUserNotEmpty(user, ecompErrorContext);
454 validateUserExists(user);
455 Either<Product, StorageOperationStatus> storageStatus = toscaOperationFacade.getToscaElement(productId);
456 if (storageStatus.isRight()) {
457 log.debug("failed to get resource by id {}", productId);
458 if (storageStatus.right().value() == StorageOperationStatus.NOT_FOUND) {
460 return Either.right(componentsUtils.getResponseFormat(ActionStatus.PRODUCT_NOT_FOUND, ComponentTypeEnum.PRODUCT.getValue()));
463 componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(storageStatus.right().value()), ""));
466 return Either.left(storageStatus.left().value());
469 public Either<Product, ResponseFormat> deleteProduct(String productId, User user) {
470 String ecompErrorContext = "Delete product";
471 validateUserNotEmpty(user, ecompErrorContext);
472 validateUserExists(user);
473 Either<Product, StorageOperationStatus> storageStatus = toscaOperationFacade.deleteToscaComponent(productId);
474 if (storageStatus.isRight()) {
475 log.debug("failed to delete resource by id {}", productId);
477 .right(componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(storageStatus.right().value()), ""));
479 return Either.left(storageStatus.left().value());
482 private Either<Boolean, ResponseFormat> validateProductFullNameAndCleanup(User user, Product product, AuditingActionEnum actionEnum) {
483 String fullName = product.getFullName();
484 if (!ValidationUtils.validateStringNotEmpty(fullName)) {
485 ResponseFormat errorResponse = componentsUtils
486 .getResponseFormat(ActionStatus.MISSING_ONE_OF_COMPONENT_NAMES, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_FULL_NAME);
487 componentsUtils.auditComponentAdmin(errorResponse, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
488 return Either.right(errorResponse);
490 fullName = ValidationUtils.removeNoneUtf8Chars(fullName);
491 fullName = ValidationUtils.removeHtmlTags(fullName);
492 fullName = ValidationUtils.normaliseWhitespace(fullName);
493 fullName = ValidationUtils.stripOctets(fullName);
494 if (!ValidationUtils.validateProductFullNameLength(fullName)) {
495 ResponseFormat responseFormat = componentsUtils
496 .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_FULL_NAME);
497 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
498 return Either.right(responseFormat);
500 if (!ValidationUtils.validateIsEnglish(fullName)) {
501 ResponseFormat responseFormat = componentsUtils
502 .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_FULL_NAME);
503 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
504 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
514 .getResponseFormat(ActionStatus.MISSING_ONE_OF_COMPONENT_NAMES, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_ABBREVIATED_NAME);
515 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
516 return Either.right(responseFormat);
518 // Product name is required to have same validation and normalization as
521 if (!ValidationUtils.validateCategoryDisplayNameFormat(name)) {
522 ResponseFormat responseFormat = componentsUtils
523 .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, ComponentTypeEnum.PRODUCT.getValue(),
524 PRODUCT_ABBREVIATED_NAME);
525 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
526 return Either.right(responseFormat);
528 String normalizedName4Display = ValidationUtils.normalizeCategoryName4Display(name);
529 if (!ValidationUtils.validateCategoryDisplayNameLength(normalizedName4Display)) {
530 ResponseFormat responseFormat = componentsUtils
531 .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, ComponentTypeEnum.PRODUCT.getValue(),
532 PRODUCT_ABBREVIATED_NAME);
533 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
534 return Either.right(responseFormat);
536 product.setName(normalizedName4Display);
537 String normalizedName4Uniqueness = ValidationUtils.normaliseComponentName(normalizedName4Display);
538 product.setNormalizedName(normalizedName4Uniqueness);
539 return Either.left(true);
541 // This is a workaround for a current tag--->product name behaviour, which
543 // will be changed in 1607.
545 // It was agreed with Ella on 23/2/16 that the tag validation of product
547 // will be made against the old product name (before normalization),
549 // and in 1607 US will be defined where UI will no longer pass tag of
551 // component name, and BE will add it by itself after all needed
554 private Either<Boolean, ResponseFormat> validateTagsListAndRemoveDuplicates(User user, Product product, String oldProductName,
555 AuditingActionEnum actionEnum) {
556 componentTagsValidator.validateAndCorrectField(user, product, actionEnum);
557 return Either.left(true);
561 public void setDeploymentArtifactsPlaceHolder(org.openecomp.sdc.be.model.Component component, User user) {
564 public Either<Product, ResponseFormat> updateProductMetadata(String productId, Product updatedProduct, User user) {
565 ComponentTypeEnum typeEnum = ComponentTypeEnum.PRODUCT;
566 user = validateUser(user, "Update Product", updatedProduct, null, false);
567 // validate user role
568 validateUserRole(user, updatedProduct, updateRoles, null, null);
569 if (updatedProduct == null) {
570 log.debug("Invalid product json. Check product servlet log for updateProduct entry params");
571 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
572 return Either.right(responseFormat);
574 Either<Product, StorageOperationStatus> storageStatus = toscaOperationFacade.getToscaElement(productId);
575 if (storageStatus.isRight()) {
576 if (storageStatus.right().value() == StorageOperationStatus.NOT_FOUND) {
578 .right(componentsUtils.getResponseFormat(ActionStatus.PRODUCT_NOT_FOUND, ComponentTypeEnum.PRODUCT.name().toLowerCase()));
581 .right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(storageStatus.right().value(), typeEnum), ""));
583 Product currentProduct = storageStatus.left().value();
584 if (!ComponentValidationUtils.canWorkOnComponent(productId, toscaOperationFacade, user.getUserId())) {
585 log.info("Restricted operation for user: {}, on product: {}", user.getUserId(), currentProduct.getCreatorUserId());
586 return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
588 Either<Product, ResponseFormat> validationRsponse = validateAndUpdateProductMetadata(user, currentProduct, updatedProduct);
589 if (validationRsponse.isRight()) {
590 log.info("product update metadata: validations field.");
591 return validationRsponse;
593 Product productToUpdate = validationRsponse.left().value();
595 lockComponent(currentProduct.getUniqueId(), currentProduct, "Update Product Metadata");
597 Either<Product, StorageOperationStatus> updateResponse = toscaOperationFacade.updateToscaElement(productToUpdate);
598 if (updateResponse.isRight()) {
599 toscaOperationFacade.rollback();
600 log.debug("failed to update product {}", productToUpdate.getUniqueId());
601 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
603 toscaOperationFacade.commit();
604 return Either.left(updateResponse.left().value());
606 graphLockOperation.unlockComponent(productId, NodeTypeEnum.Product);
610 private Either<Product, ResponseFormat> validateAndUpdateProductMetadata(User user, Product currentProduct, Product updatedProduct) {
611 boolean hasBeenCertified = ValidationUtils.hasBeenCertified(currentProduct.getVersion());
612 Either<Boolean, ResponseFormat> response = validateAndUpdateProductName(user, currentProduct, updatedProduct);
613 if (response.isRight()) {
614 ResponseFormat errorResponse = response.right().value();
615 return Either.right(errorResponse);
617 response = validateAndUpdateFullName(user, currentProduct, updatedProduct);
618 if (response.isRight()) {
619 ResponseFormat errorResponse = response.right().value();
620 return Either.right(errorResponse);
622 response = validateAndUpdateDescription(user, currentProduct, updatedProduct, null);
623 if (response.isRight()) {
624 ResponseFormat errorResponse = response.right().value();
625 return Either.right(errorResponse);
627 response = validateAndUpdateCategory(user, currentProduct, updatedProduct);
628 if (response.isRight()) {
629 ResponseFormat errorResponse = response.right().value();
630 return Either.right(errorResponse);
632 response = validateAndUpdateContactList(user, currentProduct, updatedProduct);
633 if (response.isRight()) {
634 ResponseFormat errorResponse = response.right().value();
635 return Either.right(errorResponse);
637 response = validateAndUpdateTags(user, currentProduct, updatedProduct);
638 if (response.isRight()) {
639 ResponseFormat errorResponse = response.right().value();
640 return Either.right(errorResponse);
642 response = validateAndUpdateProjectCode(user, currentProduct, updatedProduct);
643 if (response.isRight()) {
644 ResponseFormat errorResponse = response.right().value();
645 return Either.right(errorResponse);
647 if (updatedProduct.getIsActive() != null) {
648 currentProduct.setIsActive(updatedProduct.getIsActive());
650 response = validateAndUpdateIcon(user, currentProduct, updatedProduct, hasBeenCertified);
651 if (response.isRight()) {
652 ResponseFormat errorResponse = response.right().value();
653 return Either.right(errorResponse);
655 String currentInvariantUuid = currentProduct.getInvariantUUID();
656 String updatedInvariantUuid = updatedProduct.getInvariantUUID();
657 if ((updatedInvariantUuid != null) && (!updatedInvariantUuid.equals(currentInvariantUuid))) {
658 log.warn("Product invariant UUID is automatically set and cannot be updated");
659 updatedProduct.setInvariantUUID(currentInvariantUuid);
661 return Either.left(currentProduct);
664 private Either<Boolean, ResponseFormat> validateAndUpdateProductName(User user, Product currentProduct, Product updatedProduct) {
665 String updatedProductName = updatedProduct.getName();
667 String currentProductName = currentProduct.getName();
668 if (updatedProductName != null) {
669 Either<Boolean, ResponseFormat> validatProductNameResponse = validateProductNameAndCleanup(user, updatedProduct, null);
670 if (validatProductNameResponse.isRight()) {
671 ResponseFormat errorRespons = validatProductNameResponse.right().value();
672 return Either.right(errorRespons);
674 updatedProductName = updatedProduct.getName();
675 if (!currentProductName.equals(updatedProductName)) {
677 componentNameValidator.validateComponentNameUnique(user, updatedProduct, null);
678 } catch (ComponentException exp) {
679 return Either.right(exp.getResponseFormat());
681 currentProduct.setName(updatedProductName);
682 tags = updatedProductName;
683 updatedProductName = ValidationUtils.normalizeCategoryName4Display(updatedProductName);
684 currentProduct.getComponentMetadataDefinition().getMetadataDataDefinition()
685 .setNormalizedName(ValidationUtils.normaliseComponentName(updatedProductName));
686 List<String> updatedTags = updatedProduct.getTags();
687 // As discussed with Ella currently (1604) we are not removing
689 // the old name from tags.
690 if (updatedTags == null) {
691 updatedTags = currentProduct.getTags();
693 updatedTags.add(tags);
696 return Either.left(true);
699 private Either<Boolean, ResponseFormat> validateAndUpdateFullName(User user, Product currentProduct, Product updatedProduct) {
700 String updatedProductName = updatedProduct.getFullName();
701 String currentProductName = currentProduct.getFullName();
702 if (updatedProductName != null && !currentProductName.equals(updatedProductName)) {
703 Either<Boolean, ResponseFormat> validatProductNameResponse = validateProductFullNameAndCleanup(user, updatedProduct, null);
704 if (validatProductNameResponse.isRight()) {
705 ResponseFormat errorRespons = validatProductNameResponse.right().value();
706 return Either.right(errorRespons);
708 currentProduct.setFullName(updatedProduct.getFullName());
710 return Either.left(true);
713 private Either<Boolean, ResponseFormat> validateAndUpdateCategory(User user, Product currentProduct, Product updatedProduct) {
714 Either<Boolean, ResponseFormat> validateCategoryResponse = validateGrouping(user, updatedProduct, null);
715 if (validateCategoryResponse.isRight()) {
716 ResponseFormat errorResponse = validateCategoryResponse.right().value();
717 return Either.right(errorResponse);
719 List<CategoryDefinition> categoryUpdated = updatedProduct.getCategories();
720 if (categoryUpdated != null) {
721 currentProduct.setCategories(categoryUpdated);
723 return Either.left(true);
726 private Either<Boolean, ResponseFormat> validateAndUpdateContactList(User user, Product currentProduct, Product updatedProduct) {
727 List<String> updatedContacts = updatedProduct.getContacts();
728 List<String> currentContacts = currentProduct.getContacts();
729 if (updatedContacts != null) {
730 if (!(currentContacts.containsAll(updatedContacts) && updatedContacts.containsAll(currentContacts))) {
731 Either<Boolean, ResponseFormat> validatResponse = validateAndUpdateProductContactsList(user, updatedProduct, null);
732 if (validatResponse.isRight()) {
733 ResponseFormat errorRespons = validatResponse.right().value();
734 return Either.right(errorRespons);
736 currentProduct.setContacts(updatedProduct.getContacts());
739 return Either.left(true);
742 private Either<Boolean, ResponseFormat> validateAndUpdateTags(User user, Product currentProduct, Product updatedProduct) {
743 List<String> tagsUpdated = updatedProduct.getTags();
744 List<String> tagsCurrent = currentProduct.getTags();
745 if (tagsUpdated != null) {
746 if (!(tagsCurrent.containsAll(tagsUpdated) && tagsUpdated.containsAll(tagsCurrent))) {
747 Either<Boolean, ResponseFormat> validatResponse = validateTagsListAndRemoveDuplicates(user, updatedProduct, currentProduct.getName(),
749 if (validatResponse.isRight()) {
750 ResponseFormat errorRespons = validatResponse.right().value();
751 return Either.right(errorRespons);
753 currentProduct.setTags(updatedProduct.getTags());
756 return Either.left(true);
760 public Either<List<String>, ResponseFormat> deleteMarkedComponents() {
761 // markAsDeleted isnt implemented yet
762 return Either.left(new ArrayList<>());
765 public Either<Product, ResponseFormat> getProductByNameAndVersion(String productName, String productVersion, String userId) {
766 validateUserExists(userId);
767 Either<Product, StorageOperationStatus> storageStatus = toscaOperationFacade
768 .getComponentByNameAndVersion(ComponentTypeEnum.PRODUCT, productName, productVersion);
769 if (storageStatus.isRight()) {
770 log.debug("failed to get service by name {} and version {}", productName, productVersion);
771 return Either.right(componentsUtils
772 .getResponseFormat(componentsUtils.convertFromStorageResponse(storageStatus.right().value(), ComponentTypeEnum.PRODUCT),
775 Product product = storageStatus.left().value();
776 return Either.left(product);
780 public ComponentInstanceBusinessLogic getComponentInstanceBL() {
781 return componentInstanceBusinessLogic;
785 public Either<List<ComponentInstance>, ResponseFormat> getComponentInstancesFilteredByPropertiesAndInputs(String componentId, String userId) {
790 public Either<UiComponentDataTransfer, ResponseFormat> getUiComponentDataTransferByComponentId(String componentId,
791 List<String> dataParamsToReturn) {
792 // TODO Auto-generated method stub