aca253682cb5d3d9800ac980d3f9fdfb88b6baeb
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / components / impl / ProductBusinessLogic.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
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
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
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  * ================================================================================
21  */
22 package org.openecomp.sdc.be.components.impl;
23
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;
29 import java.util.Map;
30 import java.util.Set;
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;
69
70 @org.springframework.stereotype.Component("productBusinessLogic")
71 public class ProductBusinessLogic extends ComponentBusinessLogic {
72
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;
82
83     @Autowired
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);
104     }
105
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
110
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);
121         }
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());
127         }
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);
134         }
135         log.debug("Product name locked is {}, status = {}", product.getSystemName(), lockResult);
136         try {
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);
143             }
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);
149         } finally {
150             graphLockOperation.unlockComponentByName(product.getSystemName(), product.getUniqueId(), NodeTypeEnum.Product);
151         }
152     }
153
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");
158         }
159     }
160
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());
165         }
166         if (product.getIsActive() == null) {
167             log.debug("no isActive value was provided, setting to default: false");
168             product.setIsActive(false);
169         }
170         product.setCreatorUserId(user.getUserId());
171         // enrich object
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
176
177         // should stay constant during clone
178         String invariantUUID = UniqueIdBuilder.buildInvariantUUID();
179         product.setInvariantUUID(invariantUUID);
180         return Either.left(product);
181     }
182
183     private Either<Boolean, ResponseFormat> validateProductFieldsBeforeCreate(User user, Product product, AuditingActionEnum actionEnum) {
184         // To be removed in 1607
185
186         // See below
187         String oldName = product.getName();
188         Either<Boolean, ResponseFormat> componentNameValidation = validateProductNameAndCleanup(user, product, actionEnum);
189         if (componentNameValidation.isRight()) {
190             return componentNameValidation;
191         }
192         try {
193             componentNameValidator.validateComponentNameUnique(user, product, actionEnum);
194         } catch (ComponentException exp) {
195             return Either.right(exp.getResponseFormat());
196         }
197         // To be removed in 1607 and replaced with generic
198
199         // validateTagsListAndRemoveDuplicates()
200
201         // See comments on the validateTagsListAndRemoveDuplicates(user,
202
203         // product, oldName, actionEnum) function
204         Either<Boolean, ResponseFormat> tagsValidation = validateTagsListAndRemoveDuplicates(user, product, oldName, actionEnum);
205         if (tagsValidation.isRight()) {
206             return tagsValidation;
207         }
208         componentTagsValidator.validateAndCorrectField(user, product, actionEnum);
209         try {
210             componentProjectCodeValidator.validateAndCorrectField(user, product, actionEnum);
211         } catch (ComponentException exp) {
212             return Either.right(exp.getResponseFormat());
213         }
214         Either<Boolean, ResponseFormat> categoryValidation = validateGrouping(user, product, actionEnum);
215         if (categoryValidation.isRight()) {
216             return categoryValidation;
217         }
218         Either<Boolean, ResponseFormat> contactsListValidation = validateAndUpdateProductContactsList(user, product, actionEnum);
219         if (contactsListValidation.isRight()) {
220             return contactsListValidation;
221         }
222         Either<Boolean, ResponseFormat> productFullNameValidation = validateProductFullNameAndCleanup(user, product, actionEnum);
223         if (productFullNameValidation.isRight()) {
224             return productFullNameValidation;
225         }
226         componentDescriptionValidator.validateAndCorrectField(user, product, actionEnum);
227         return Either.left(true);
228     }
229
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);
234         // DE242223
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);
241         }
242         ResponseFormat responseFormat = componentsUtils
243             .getResponseFormat(componentsUtils.convertFromStorageResponse(dataModelResponse.right().value()));
244         return Either.right(responseFormat);
245     }
246
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);
254         }
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
262                 continue;
263             }
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);
270             }
271             User contactUser;
272             try {
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());
280             }
281         }
282         if (!isProductCreatorInContacts) {
283             log.debug("modifier userId {} not found in product contacts - adding it", modifierUserId);
284             contacts.add(modifierUserId);
285         }
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);
291     }
292
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);
298         }
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);
310             }
311             Map<String, Set<String>> catEntry = nonDuplicatedCategories.get(catName);
312             if (catEntry == null) {
313                 catEntry = new HashMap<>();
314                 nonDuplicatedCategories.put(catName, catEntry);
315             }
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);
323             }
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);
332                 }
333                 Set<String> subcatEntry = catEntry.get(subCatName);
334                 if (subcatEntry == null) {
335                     subcatEntry = new HashSet<>();
336                     catEntry.put(subCatName, subcatEntry);
337                 }
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,
344                             product.getName());
345                         ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_SUBCATEGORY);
346                         componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
347                         return Either.right(responseFormat);
348                     }
349                     if (!subcatEntry.contains(groupName)) {
350                         subcatEntry.add(groupName);
351                     } else {
352                         log.debug("Grouping: {}, already exist for category: {} and subcategory: {}", groupName, catName, subCatName);
353                     }
354                 }
355             }
356         } // for end of checking duplicated
357
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);
365         }
366         boolean catExist;
367         // convert non-duplicated to data modeling format and update in the
368
369         // input object
370         List<CategoryDefinition> newCatList = new ArrayList<>();
371         // over all categories from request
372         for (Map.Entry<String, Map<String, Set<String>>> entry : nonDuplicatedCategories.entrySet()) {
373             catExist = false;
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())) {
380                         catExist = true;
381                         boolean subcatExist;
382                         // copy data
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()) {
387                             subcatExist = false;
388                             List<SubCategoryDefinition> subcategoriesList = catInDb.getSubcategories();
389                             if (subcategoriesList != null) {
390                                 for (SubCategoryDefinition subcatInDb : subcategoriesList) {
391                                     if (subcatInDb.getName().equals(subcat.getKey())) {
392                                         // copy data
393                                         subCategory = new SubCategoryDefinition(subcatInDb);
394                                         subcatExist = true;
395                                         Set<String> grouping = subcat.getValue();
396                                         boolean groupExist;
397                                         GroupingDefinition groupingDefinition = null;
398                                         for (String group : grouping) {
399                                             groupExist = false;
400                                             List<GroupingDefinition> groupings = subcatInDb.getGroupings();
401                                             if (groupings != null) {
402                                                 for (GroupingDefinition groupInDb : groupings) {
403                                                     if (groupInDb.getName().equals(group)) {
404                                                         groupExist = true;
405                                                         groupingDefinition = new GroupingDefinition(groupInDb);
406                                                     }
407                                                 }
408                                             }
409                                             if (!groupExist) {
410                                                 // error grouping isn't defined
411
412                                                 // in JanusGraph
413                                                 ResponseFormat responseFormat = componentsUtils
414                                                     .getResponseFormat(ActionStatus.INVALID_GROUP_ASSOCIATION, CategoryTypeEnum.GROUPING.getValue(),
415                                                         group);
416                                                 componentsUtils
417                                                     .auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
418                                                 return Either.right(responseFormat);
419                                             }
420                                             subCategory.addGrouping(groupingDefinition);
421                                         }
422                                     }
423                                 }
424                             }
425                             if (!subcatExist) {
426                                 // error sub category isn't defined in JanusGraph
427                                 ResponseFormat responseFormat = componentsUtils
428                                     .getResponseFormat(ActionStatus.INVALID_GROUP_ASSOCIATION, CategoryTypeEnum.SUBCATEGORY.getValue(),
429                                         subcat.getKey());
430                                 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
431                                 return Either.right(responseFormat);
432                             }
433                             categoryDefinition.addSubCategory(subCategory);
434                         }
435                     }
436                 }
437             }
438             if (!catExist) {
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);
444             }
445             newCatList.add(categoryDefinition);
446         }
447         product.setCategories(newCatList);
448         return Either.left(true);
449     }
450
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) {
459                 // TODO check error
460                 return Either.right(componentsUtils.getResponseFormat(ActionStatus.PRODUCT_NOT_FOUND, ComponentTypeEnum.PRODUCT.getValue()));
461             } else {
462                 return Either.right(
463                     componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(storageStatus.right().value()), ""));
464             }
465         }
466         return Either.left(storageStatus.left().value());
467     }
468
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);
476             return Either
477                 .right(componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(storageStatus.right().value()), ""));
478         }
479         return Either.left(storageStatus.left().value());
480     }
481
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);
489         }
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);
499         }
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);
505         }
506         product.setFullName(fullName);
507         return Either.left(true);
508     }
509
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);
517         }
518         // Product name is required to have same validation and normalization as
519
520         // category
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);
527         }
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);
535         }
536         product.setName(normalizedName4Display);
537         String normalizedName4Uniqueness = ValidationUtils.normaliseComponentName(normalizedName4Display);
538         product.setNormalizedName(normalizedName4Uniqueness);
539         return Either.left(true);
540     }
541     // This is a workaround for a current tag--->product name behaviour, which
542
543     // will be changed in 1607.
544
545     // It was agreed with Ella on 23/2/16 that the tag validation of product
546
547     // will be made against the old product name (before normalization),
548
549     // and in 1607 US will be defined where UI will no longer pass tag of
550
551     // component name, and BE will add it by itself after all needed
552
553     // normalizations.
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);
558     }
559
560     @Override
561     public void setDeploymentArtifactsPlaceHolder(org.openecomp.sdc.be.model.Component component, User user) {
562     }
563
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);
573         }
574         Either<Product, StorageOperationStatus> storageStatus = toscaOperationFacade.getToscaElement(productId);
575         if (storageStatus.isRight()) {
576             if (storageStatus.right().value() == StorageOperationStatus.NOT_FOUND) {
577                 return Either
578                     .right(componentsUtils.getResponseFormat(ActionStatus.PRODUCT_NOT_FOUND, ComponentTypeEnum.PRODUCT.name().toLowerCase()));
579             }
580             return Either
581                 .right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(storageStatus.right().value(), typeEnum), ""));
582         }
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));
587         }
588         Either<Product, ResponseFormat> validationRsponse = validateAndUpdateProductMetadata(user, currentProduct, updatedProduct);
589         if (validationRsponse.isRight()) {
590             log.info("product update metadata: validations field.");
591             return validationRsponse;
592         }
593         Product productToUpdate = validationRsponse.left().value();
594         // lock resource
595         lockComponent(currentProduct.getUniqueId(), currentProduct, "Update Product Metadata");
596         try {
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));
602             }
603             toscaOperationFacade.commit();
604             return Either.left(updateResponse.left().value());
605         } finally {
606             graphLockOperation.unlockComponent(productId, NodeTypeEnum.Product);
607         }
608     }
609
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);
616         }
617         response = validateAndUpdateFullName(user, currentProduct, updatedProduct);
618         if (response.isRight()) {
619             ResponseFormat errorResponse = response.right().value();
620             return Either.right(errorResponse);
621         }
622         response = validateAndUpdateDescription(user, currentProduct, updatedProduct, null);
623         if (response.isRight()) {
624             ResponseFormat errorResponse = response.right().value();
625             return Either.right(errorResponse);
626         }
627         response = validateAndUpdateCategory(user, currentProduct, updatedProduct);
628         if (response.isRight()) {
629             ResponseFormat errorResponse = response.right().value();
630             return Either.right(errorResponse);
631         }
632         response = validateAndUpdateContactList(user, currentProduct, updatedProduct);
633         if (response.isRight()) {
634             ResponseFormat errorResponse = response.right().value();
635             return Either.right(errorResponse);
636         }
637         response = validateAndUpdateTags(user, currentProduct, updatedProduct);
638         if (response.isRight()) {
639             ResponseFormat errorResponse = response.right().value();
640             return Either.right(errorResponse);
641         }
642         response = validateAndUpdateProjectCode(user, currentProduct, updatedProduct);
643         if (response.isRight()) {
644             ResponseFormat errorResponse = response.right().value();
645             return Either.right(errorResponse);
646         }
647         if (updatedProduct.getIsActive() != null) {
648             currentProduct.setIsActive(updatedProduct.getIsActive());
649         }
650         response = validateAndUpdateIcon(user, currentProduct, updatedProduct, hasBeenCertified);
651         if (response.isRight()) {
652             ResponseFormat errorResponse = response.right().value();
653             return Either.right(errorResponse);
654         }
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);
660         }
661         return Either.left(currentProduct);
662     }
663
664     private Either<Boolean, ResponseFormat> validateAndUpdateProductName(User user, Product currentProduct, Product updatedProduct) {
665         String updatedProductName = updatedProduct.getName();
666         String tags;
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);
673             }
674             updatedProductName = updatedProduct.getName();
675             if (!currentProductName.equals(updatedProductName)) {
676                 try {
677                     componentNameValidator.validateComponentNameUnique(user, updatedProduct, null);
678                 } catch (ComponentException exp) {
679                     return Either.right(exp.getResponseFormat());
680                 }
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
688
689                 // the old name from tags.
690                 if (updatedTags == null) {
691                     updatedTags = currentProduct.getTags();
692                 }
693                 updatedTags.add(tags);
694             }
695         }
696         return Either.left(true);
697     }
698
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);
707             }
708             currentProduct.setFullName(updatedProduct.getFullName());
709         }
710         return Either.left(true);
711     }
712
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);
718         }
719         List<CategoryDefinition> categoryUpdated = updatedProduct.getCategories();
720         if (categoryUpdated != null) {
721             currentProduct.setCategories(categoryUpdated);
722         }
723         return Either.left(true);
724     }
725
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);
735                 }
736                 currentProduct.setContacts(updatedProduct.getContacts());
737             }
738         }
739         return Either.left(true);
740     }
741
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(),
748                     null);
749                 if (validatResponse.isRight()) {
750                     ResponseFormat errorRespons = validatResponse.right().value();
751                     return Either.right(errorRespons);
752                 }
753                 currentProduct.setTags(updatedProduct.getTags());
754             }
755         }
756         return Either.left(true);
757     }
758
759     @Override
760     public Either<List<String>, ResponseFormat> deleteMarkedComponents() {
761         // markAsDeleted isnt implemented yet
762         return Either.left(new ArrayList<>());
763     }
764
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),
773                     productName));
774         }
775         Product product = storageStatus.left().value();
776         return Either.left(product);
777     }
778
779     @Override
780     public ComponentInstanceBusinessLogic getComponentInstanceBL() {
781         return componentInstanceBusinessLogic;
782     }
783
784     @Override
785     public Either<List<ComponentInstance>, ResponseFormat> getComponentInstancesFilteredByPropertiesAndInputs(String componentId, String userId) {
786         return null;
787     }
788
789     @Override
790     public Either<UiComponentDataTransfer, ResponseFormat> getUiComponentDataTransferByComponentId(String componentId,
791                                                                                                    List<String> dataParamsToReturn) {
792         // TODO Auto-generated method stub
793         return null;
794     }
795 }