Improve handling 'empty'/null string in Service fields
[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.apache.commons.lang3.StringUtils;
33 import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
34 import org.openecomp.sdc.be.components.impl.exceptions.ComponentException;
35 import org.openecomp.sdc.be.components.validation.component.ComponentContactIdValidator;
36 import org.openecomp.sdc.be.components.validation.component.ComponentDescriptionValidator;
37 import org.openecomp.sdc.be.components.validation.component.ComponentIconValidator;
38 import org.openecomp.sdc.be.components.validation.component.ComponentNameValidator;
39 import org.openecomp.sdc.be.components.validation.component.ComponentProjectCodeValidator;
40 import org.openecomp.sdc.be.components.validation.component.ComponentTagsValidator;
41 import org.openecomp.sdc.be.components.validation.component.ComponentValidator;
42 import org.openecomp.sdc.be.dao.api.ActionStatus;
43 import org.openecomp.sdc.be.datamodel.api.CategoryTypeEnum;
44 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
45 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
46 import org.openecomp.sdc.be.model.ComponentInstance;
47 import org.openecomp.sdc.be.model.LifecycleStateEnum;
48 import org.openecomp.sdc.be.model.Product;
49 import org.openecomp.sdc.be.model.User;
50 import org.openecomp.sdc.be.model.category.CategoryDefinition;
51 import org.openecomp.sdc.be.model.category.GroupingDefinition;
52 import org.openecomp.sdc.be.model.category.SubCategoryDefinition;
53 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ArtifactsOperations;
54 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.InterfaceOperation;
55 import org.openecomp.sdc.be.model.operations.api.IElementOperation;
56 import org.openecomp.sdc.be.model.operations.api.IGroupInstanceOperation;
57 import org.openecomp.sdc.be.model.operations.api.IGroupOperation;
58 import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation;
59 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
60 import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation;
61 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
62 import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils;
63 import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
64 import org.openecomp.sdc.be.ui.model.UiComponentDataTransfer;
65 import org.openecomp.sdc.be.user.Role;
66 import org.openecomp.sdc.common.log.wrappers.Logger;
67 import org.openecomp.sdc.common.util.ValidationUtils;
68 import org.openecomp.sdc.exception.ResponseFormat;
69 import org.springframework.beans.factory.annotation.Autowired;
70
71 @org.springframework.stereotype.Component("productBusinessLogic")
72 public class ProductBusinessLogic extends ComponentBusinessLogic {
73
74     private static final String PRODUCT_FULL_NAME = "full";
75     private static final String PRODUCT_ABBREVIATED_NAME = "abbreviated";
76     private static final Logger log = Logger.getLogger(ProductBusinessLogic.class);
77     private static final String INITIAL_VERSION = "0.1";
78     private static final String CREATE_PRODUCT = "Create Product";
79     private static List<Role> creationRoles;
80     private static List<Role> updateRoles;
81     private static List<Role> contactsRoles;
82     private final ComponentInstanceBusinessLogic componentInstanceBusinessLogic;
83
84     @Autowired
85     public ProductBusinessLogic(IElementOperation elementDao, IGroupOperation groupOperation, IGroupInstanceOperation groupInstanceOperation,
86                                 IGroupTypeOperation groupTypeOperation, GroupBusinessLogic groupBusinessLogic, InterfaceOperation interfaceOperation,
87                                 InterfaceLifecycleOperation interfaceLifecycleTypeOperation, ArtifactsBusinessLogic artifactsBusinessLogic,
88                                 ComponentInstanceBusinessLogic componentInstanceBusinessLogic, ArtifactsOperations artifactToscaOperation,
89                                 ComponentContactIdValidator componentContactIdValidator, ComponentNameValidator componentNameValidator,
90                                 ComponentTagsValidator componentTagsValidator, ComponentValidator componentValidator,
91                                 ComponentIconValidator componentIconValidator, ComponentProjectCodeValidator componentProjectCodeValidator,
92                                 ComponentDescriptionValidator componentDescriptionValidator) {
93         super(elementDao, groupOperation, groupInstanceOperation, groupTypeOperation, groupBusinessLogic, interfaceOperation,
94             interfaceLifecycleTypeOperation, artifactsBusinessLogic, artifactToscaOperation, componentContactIdValidator, componentNameValidator,
95             componentTagsValidator, componentValidator, componentIconValidator, componentProjectCodeValidator, componentDescriptionValidator);
96         this.componentInstanceBusinessLogic = componentInstanceBusinessLogic;
97         creationRoles = new ArrayList<>();
98         updateRoles = new ArrayList<>();
99         contactsRoles = new ArrayList<>();
100         // only PM is allowed to create/update products
101         creationRoles.add(Role.PRODUCT_MANAGER);
102         updateRoles.add(Role.PRODUCT_MANAGER);
103         // Only PM is allowed to be product contacts
104         contactsRoles.add(Role.PRODUCT_MANAGER);
105     }
106
107     public Either<Product, ResponseFormat> createProduct(Product product, User user) {
108         AuditingActionEnum actionEnum = AuditingActionEnum.CREATE_RESOURCE;
109         ComponentTypeEnum typeEnum = ComponentTypeEnum.PRODUCT;
110         // validate user - should be first to get the maximum auditing info in
111
112         // case of subsequent failures
113         log.debug("get user from DB");
114         user = validateUser(user, CREATE_PRODUCT, product, actionEnum, false);
115         // validate user role
116         validateUserRole(user, product, creationRoles, actionEnum, null);
117         if (product == null) {
118             log.debug("Invalid product json. Check product servlet log for createProduct entry params");
119             ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
120             componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, typeEnum);
121             return Either.right(responseFormat);
122         }
123         // warn about non-updatable fields
124         checkUnupdatableProductFields(product);
125         Either<Product, ResponseFormat> validateProductResponse = validateProductBeforeCreate(product, user, actionEnum);
126         if (validateProductResponse.isRight()) {
127             return Either.right(validateProductResponse.right().value());
128         }
129         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);
135         }
136         log.debug("Product name locked is {}, status = {}", product.getSystemName(), lockResult);
137         try {
138             Either<Product, StorageOperationStatus> createProductEither = toscaOperationFacade.createToscaComponent(product);
139             if (createProductEither.isRight()) {
140                 ResponseFormat responseFormat = componentsUtils
141                     .getResponseFormatByComponent(componentsUtils.convertFromStorageResponse(createProductEither.right().value()), product, typeEnum);
142                 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, typeEnum);
143                 return Either.right(responseFormat);
144             }
145             log.debug("Product created successfully");
146             ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.CREATED);
147             componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, typeEnum);
148             Product createdProduct = createProductEither.left().value();
149             return Either.left(createdProduct);
150         } finally {
151             graphLockOperation.unlockComponentByName(product.getSystemName(), product.getUniqueId(), NodeTypeEnum.Product);
152         }
153     }
154
155     private void checkUnupdatableProductFields(Product product) {
156         checkComponentFieldsForOverrideAttempt(product);
157         if (product.getNormalizedName() != null) {
158             log.info("NormalizedName cannot be defined by user. This field will be overridden by the application");
159         }
160     }
161
162     private Either<Product, ResponseFormat> validateProductBeforeCreate(Product product, User user, AuditingActionEnum actionEnum) {
163         Either<Boolean, ResponseFormat> validateProductFields = validateProductFieldsBeforeCreate(user, product, actionEnum);
164         if (validateProductFields.isRight()) {
165             return Either.right(validateProductFields.right().value());
166         }
167         if (product.getIsActive() == null) {
168             log.debug("no isActive value was provided, setting to default: false");
169             product.setIsActive(false);
170         }
171         product.setCreatorUserId(user.getUserId());
172         // enrich object
173         log.debug("enrich product with version and state");
174         product.setState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT);
175         product.setVersion(INITIAL_VERSION);
176         // Generate invariant UUID - must be here and not in operation since it
177
178         // should stay constant during clone
179         String invariantUUID = UniqueIdBuilder.buildInvariantUUID();
180         product.setInvariantUUID(invariantUUID);
181         return Either.left(product);
182     }
183
184     private Either<Boolean, ResponseFormat> validateProductFieldsBeforeCreate(User user, Product product, AuditingActionEnum actionEnum) {
185         // To be removed in 1607
186
187         // See below
188         String oldName = product.getName();
189         Either<Boolean, ResponseFormat> componentNameValidation = validateProductNameAndCleanup(user, product, actionEnum);
190         if (componentNameValidation.isRight()) {
191             return componentNameValidation;
192         }
193         try {
194             componentNameValidator.validateComponentNameUnique(user, product, actionEnum);
195         } catch (ComponentException exp) {
196             return Either.right(exp.getResponseFormat());
197         }
198         // To be removed in 1607 and replaced with generic
199
200         // validateTagsListAndRemoveDuplicates()
201
202         // See comments on the validateTagsListAndRemoveDuplicates(user,
203
204         // product, oldName, actionEnum) function
205         Either<Boolean, ResponseFormat> tagsValidation = validateTagsListAndRemoveDuplicates(user, product, oldName, actionEnum);
206         if (tagsValidation.isRight()) {
207             return tagsValidation;
208         }
209         componentTagsValidator.validateAndCorrectField(user, product, actionEnum);
210         try {
211             componentProjectCodeValidator.validateAndCorrectField(user, product, actionEnum);
212         } catch (ComponentException exp) {
213             return Either.right(exp.getResponseFormat());
214         }
215         Either<Boolean, ResponseFormat> categoryValidation = validateGrouping(user, product, actionEnum);
216         if (categoryValidation.isRight()) {
217             return categoryValidation;
218         }
219         Either<Boolean, ResponseFormat> contactsListValidation = validateAndUpdateProductContactsList(user, product, actionEnum);
220         if (contactsListValidation.isRight()) {
221             return contactsListValidation;
222         }
223         Either<Boolean, ResponseFormat> productFullNameValidation = validateProductFullNameAndCleanup(user, product, actionEnum);
224         if (productFullNameValidation.isRight()) {
225             return productFullNameValidation;
226         }
227         componentDescriptionValidator.validateAndCorrectField(user, product, actionEnum);
228         return Either.left(true);
229     }
230
231     public Either<Map<String, Boolean>, ResponseFormat> validateProductNameExists(String productName, String userId) {
232         validateUserExists(userId);
233         Either<Boolean, StorageOperationStatus> dataModelResponse = toscaOperationFacade
234             .validateComponentNameUniqueness(productName, null, ComponentTypeEnum.PRODUCT);
235         // DE242223
236         janusGraphDao.commit();
237         if (dataModelResponse.isLeft()) {
238             Map<String, Boolean> result = new HashMap<>();
239             result.put("isValid", dataModelResponse.left().value());
240             log.debug("validation was successfully performed.");
241             return Either.left(result);
242         }
243         ResponseFormat responseFormat = componentsUtils
244             .getResponseFormat(componentsUtils.convertFromStorageResponse(dataModelResponse.right().value()));
245         return Either.right(responseFormat);
246     }
247
248     private Either<Boolean, ResponseFormat> validateAndUpdateProductContactsList(User user, Product product, AuditingActionEnum actionEnum) {
249         List<String> contacts = product.getContacts();
250         if (!ValidationUtils.validateListNotEmpty(contacts)) {
251             log.debug("Contacts list cannot be empty for product {}", product.getName());
252             ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.EMPTY_PRODUCT_CONTACTS_LIST);
253             componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
254             return Either.right(responseFormat);
255         }
256         boolean isProductCreatorInContacts = false;
257         String modifierUserId = user.getUserId();
258         for (String contact : contacts) {
259             if (contact.equals(modifierUserId)) {
260                 log.trace("modifier userId found in product contacts");
261                 isProductCreatorInContacts = true;
262                 // No need to validate for this userId - it's modifier's
263                 continue;
264             }
265             if (!ValidationUtils.validateContactId(contact)) {
266                 log.debug("Product contacts has invalid userId {} for product {}", contact, product.getName());
267                 ResponseFormat responseFormat = componentsUtils
268                     .getResponseFormat(ActionStatus.COMPONENT_INVALID_CONTACT, ComponentTypeEnum.PRODUCT.getValue());
269                 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
270                 return Either.right(responseFormat);
271             }
272             User contactUser;
273             try {
274                 contactUser = validateUserExists(contact);
275                 validateUserRole(contactUser, contactsRoles);
276             } catch (ByActionStatusComponentException e) {
277                 log.debug("Cannot set contact with userId {} as product contact, error: {}", contact, e.getActionStatus());
278                 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_PRODUCT_CONTACT, contact);
279                 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
280                 throw new ByActionStatusComponentException(e.getActionStatus(), e.getParams());
281             }
282         }
283         if (!isProductCreatorInContacts) {
284             log.debug("modifier userId {} not found in product contacts - adding it", modifierUserId);
285             contacts.add(modifierUserId);
286         }
287         // passed - setting all contacts userIds to lowercase
288         List<String> tempContacts = contacts.stream().map(String::toLowerCase).collect(Collectors.toList());
289         ValidationUtils.removeDuplicateFromList(tempContacts);
290         product.setContacts(tempContacts);
291         return Either.left(true);
292     }
293
294     private Either<Boolean, ResponseFormat> validateGrouping(User user, Product product, AuditingActionEnum actionEnum) {
295         List<CategoryDefinition> categories = product.getCategories();
296         if (categories == null || categories.isEmpty()) {
297             log.debug("Grouping list is empty for product: {}", product.getName());
298             return Either.left(true);
299         }
300         Map<String, Map<String, Set<String>>> nonDuplicatedCategories = new HashMap<>();
301         // remove duplicated entries
302         for (CategoryDefinition cat : categories) {
303             String catName = cat.getName();
304             if (StringUtils.isEmpty(catName)) {
305                 // error missing cat name
306                 log.debug("Missing category name for product: {}", product.getName());
307                 ResponseFormat responseFormat = componentsUtils
308                     .getResponseFormat(ActionStatus.COMPONENT_MISSING_CATEGORY, ComponentTypeEnum.PRODUCT.getValue());
309                 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
310                 return Either.right(responseFormat);
311             }
312             Map<String, Set<String>> catEntry = nonDuplicatedCategories.get(catName);
313             if (catEntry == null) {
314                 catEntry = new HashMap<>();
315                 nonDuplicatedCategories.put(catName, catEntry);
316             }
317             List<SubCategoryDefinition> subcategories = cat.getSubcategories();
318             if (subcategories == null || subcategories.isEmpty()) {
319                 // error missing subcat for cat
320                 log.debug("Missing sub-categories for category {} in product {}", catName, product.getName());
321                 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_SUBCATEGORY);
322                 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
323                 return Either.right(responseFormat);
324             }
325             for (SubCategoryDefinition subcat : subcategories) {
326                 String subCatName = subcat.getName();
327                 if (StringUtils.isEmpty(subCatName)) {
328                     // error missing sub cat name for cat
329                     log.debug("Missing or empty sub-category for category {} in product {}", catName, product.getName());
330                     ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_SUBCATEGORY);
331                     componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
332                     return Either.right(responseFormat);
333                 }
334                 Set<String> subcatEntry = catEntry.get(subCatName);
335                 if (subcatEntry == null) {
336                     subcatEntry = new HashSet<>();
337                     catEntry.put(subCatName, subcatEntry);
338                 }
339                 List<GroupingDefinition> groupings = subcat.getGroupings();
340                 for (GroupingDefinition group : groupings) {
341                     String groupName = group.getName();
342                     if (StringUtils.isEmpty(groupName)) {
343                         // error missing grouping for sub cat name and cat
344                         log.debug("Missing or empty groupng name for sub-category: {} for categor: {} in product: {}", subCatName, catName,
345                             product.getName());
346                         ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_MISSING_SUBCATEGORY);
347                         componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
348                         return Either.right(responseFormat);
349                     }
350                     if (!subcatEntry.contains(groupName)) {
351                         subcatEntry.add(groupName);
352                     } else {
353                         log.debug("Grouping: {}, already exist for category: {} and subcategory: {}", groupName, catName, subCatName);
354                     }
355                 }
356             }
357         } // for end of checking duplicated
358
359         // validate existence
360         Either<List<CategoryDefinition>, ActionStatus> allProductCategories = elementDao.getAllProductCategories();
361         if (allProductCategories.isRight()) {
362             log.debug("No product categories {}", allProductCategories.right().value());
363             ResponseFormat responseFormat = componentsUtils.getResponseFormat(allProductCategories.right().value());
364             componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
365             return Either.right(responseFormat);
366         }
367         boolean catExist;
368         // convert non-duplicated to data modeling format and update in the
369
370         // input object
371         List<CategoryDefinition> newCatList = new ArrayList<>();
372         // over all categories from request
373         for (Map.Entry<String, Map<String, Set<String>>> entry : nonDuplicatedCategories.entrySet()) {
374             catExist = false;
375             CategoryDefinition categoryDefinition = null;
376             // over all categories from JanusGraph
377             List<CategoryDefinition> categoriesList = allProductCategories.left().value();
378             if (categoriesList != null) {
379                 for (CategoryDefinition catInDb : categoriesList) {
380                     if (entry.getKey().equals(catInDb.getName())) {
381                         catExist = true;
382                         boolean subcatExist;
383                         // copy data
384                         categoryDefinition = new CategoryDefinition(catInDb);
385                         SubCategoryDefinition subCategory = null;
386                         Map<String, Set<String>> subcats = entry.getValue();
387                         for (Map.Entry<String, Set<String>> subcat : subcats.entrySet()) {
388                             subcatExist = false;
389                             List<SubCategoryDefinition> subcategoriesList = catInDb.getSubcategories();
390                             if (subcategoriesList != null) {
391                                 for (SubCategoryDefinition subcatInDb : subcategoriesList) {
392                                     if (subcatInDb.getName().equals(subcat.getKey())) {
393                                         // copy data
394                                         subCategory = new SubCategoryDefinition(subcatInDb);
395                                         subcatExist = true;
396                                         Set<String> grouping = subcat.getValue();
397                                         boolean groupExist;
398                                         GroupingDefinition groupingDefinition = null;
399                                         for (String group : grouping) {
400                                             groupExist = false;
401                                             List<GroupingDefinition> groupings = subcatInDb.getGroupings();
402                                             if (groupings != null) {
403                                                 for (GroupingDefinition groupInDb : groupings) {
404                                                     if (groupInDb.getName().equals(group)) {
405                                                         groupExist = true;
406                                                         groupingDefinition = new GroupingDefinition(groupInDb);
407                                                     }
408                                                 }
409                                             }
410                                             if (!groupExist) {
411                                                 // error grouping isn't defined
412
413                                                 // in JanusGraph
414                                                 ResponseFormat responseFormat = componentsUtils
415                                                     .getResponseFormat(ActionStatus.INVALID_GROUP_ASSOCIATION, CategoryTypeEnum.GROUPING.getValue(),
416                                                         group);
417                                                 componentsUtils
418                                                     .auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
419                                                 return Either.right(responseFormat);
420                                             }
421                                             subCategory.addGrouping(groupingDefinition);
422                                         }
423                                     }
424                                 }
425                             }
426                             if (!subcatExist) {
427                                 // error sub category isn't defined in JanusGraph
428                                 ResponseFormat responseFormat = componentsUtils
429                                     .getResponseFormat(ActionStatus.INVALID_GROUP_ASSOCIATION, CategoryTypeEnum.SUBCATEGORY.getValue(),
430                                         subcat.getKey());
431                                 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
432                                 return Either.right(responseFormat);
433                             }
434                             categoryDefinition.addSubCategory(subCategory);
435                         }
436                     }
437                 }
438             }
439             if (!catExist) {
440                 // error category isn't defined in JanusGraph
441                 ResponseFormat responseFormat = componentsUtils
442                     .getResponseFormat(ActionStatus.INVALID_GROUP_ASSOCIATION, CategoryTypeEnum.CATEGORY.getValue(), entry.getKey());
443                 componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
444                 return Either.right(responseFormat);
445             }
446             newCatList.add(categoryDefinition);
447         }
448         product.setCategories(newCatList);
449         return Either.left(true);
450     }
451
452     public Either<Product, ResponseFormat> getProduct(String productId, User user) {
453         String ecompErrorContext = "Get product";
454         validateUserNotEmpty(user, ecompErrorContext);
455         validateUserExists(user);
456         Either<Product, StorageOperationStatus> storageStatus = toscaOperationFacade.getToscaElement(productId);
457         if (storageStatus.isRight()) {
458             log.debug("failed to get resource by id {}", productId);
459             if (storageStatus.right().value() == StorageOperationStatus.NOT_FOUND) {
460                 // TODO check error
461                 return Either.right(componentsUtils.getResponseFormat(ActionStatus.PRODUCT_NOT_FOUND, ComponentTypeEnum.PRODUCT.getValue()));
462             } else {
463                 return Either.right(
464                     componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(storageStatus.right().value()), ""));
465             }
466         }
467         return Either.left(storageStatus.left().value());
468     }
469
470     public Either<Product, ResponseFormat> deleteProduct(String productId, User user) {
471         String ecompErrorContext = "Delete product";
472         validateUserNotEmpty(user, ecompErrorContext);
473         validateUserExists(user);
474         Either<Product, StorageOperationStatus> storageStatus = toscaOperationFacade.deleteToscaComponent(productId);
475         if (storageStatus.isRight()) {
476             log.debug("failed to delete resource by id {}", productId);
477             return Either
478                 .right(componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(storageStatus.right().value()), ""));
479         }
480         return Either.left(storageStatus.left().value());
481     }
482
483     private Either<Boolean, ResponseFormat> validateProductFullNameAndCleanup(User user, Product product, AuditingActionEnum actionEnum) {
484         String fullName = product.getFullName();
485         if (StringUtils.isEmpty(fullName)) {
486             ResponseFormat errorResponse = componentsUtils
487                 .getResponseFormat(ActionStatus.MISSING_ONE_OF_COMPONENT_NAMES, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_FULL_NAME);
488             componentsUtils.auditComponentAdmin(errorResponse, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
489             return Either.right(errorResponse);
490         }
491         fullName = ValidationUtils.removeNoneUtf8Chars(fullName);
492         fullName = ValidationUtils.removeHtmlTags(fullName);
493         fullName = ValidationUtils.normaliseWhitespace(fullName);
494         fullName = ValidationUtils.stripOctets(fullName);
495         if (!ValidationUtils.validateProductFullNameLength(fullName)) {
496             ResponseFormat responseFormat = componentsUtils
497                 .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_FULL_NAME);
498             componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
499             return Either.right(responseFormat);
500         }
501         if (!ValidationUtils.validateIsEnglish(fullName)) {
502             ResponseFormat responseFormat = componentsUtils
503                 .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_FULL_NAME);
504             componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
505             return Either.right(responseFormat);
506         }
507         product.setFullName(fullName);
508         return Either.left(true);
509     }
510
511     private Either<Boolean, ResponseFormat> validateProductNameAndCleanup(User user, Product product, AuditingActionEnum actionEnum) {
512         String name = product.getName();
513         if (StringUtils.isEmpty(name)) {
514             ResponseFormat responseFormat = componentsUtils
515                 .getResponseFormat(ActionStatus.MISSING_ONE_OF_COMPONENT_NAMES, ComponentTypeEnum.PRODUCT.getValue(), PRODUCT_ABBREVIATED_NAME);
516             componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
517             return Either.right(responseFormat);
518         }
519         // Product name is required to have same validation and normalization as
520
521         // category
522         if (!ValidationUtils.validateCategoryDisplayNameFormat(name)) {
523             ResponseFormat responseFormat = componentsUtils
524                 .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, ComponentTypeEnum.PRODUCT.getValue(),
525                     PRODUCT_ABBREVIATED_NAME);
526             componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
527             return Either.right(responseFormat);
528         }
529         String normalizedName4Display = ValidationUtils.normalizeCategoryName4Display(name);
530         if (!ValidationUtils.validateCategoryDisplayNameLength(normalizedName4Display)) {
531             ResponseFormat responseFormat = componentsUtils
532                 .getResponseFormat(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, ComponentTypeEnum.PRODUCT.getValue(),
533                     PRODUCT_ABBREVIATED_NAME);
534             componentsUtils.auditComponentAdmin(responseFormat, user, product, actionEnum, ComponentTypeEnum.PRODUCT);
535             return Either.right(responseFormat);
536         }
537         product.setName(normalizedName4Display);
538         String normalizedName4Uniqueness = ValidationUtils.normaliseComponentName(normalizedName4Display);
539         product.setNormalizedName(normalizedName4Uniqueness);
540         return Either.left(true);
541     }
542     // This is a workaround for a current tag--->product name behaviour, which
543
544     // will be changed in 1607.
545
546     // It was agreed with Ella on 23/2/16 that the tag validation of product
547
548     // will be made against the old product name (before normalization),
549
550     // and in 1607 US will be defined where UI will no longer pass tag of
551
552     // component name, and BE will add it by itself after all needed
553
554     // normalizations.
555     private Either<Boolean, ResponseFormat> validateTagsListAndRemoveDuplicates(User user, Product product, String oldProductName,
556                                                                                 AuditingActionEnum actionEnum) {
557         componentTagsValidator.validateAndCorrectField(user, product, actionEnum);
558         return Either.left(true);
559     }
560
561     @Override
562     public void setDeploymentArtifactsPlaceHolder(org.openecomp.sdc.be.model.Component component, User user) {
563     }
564
565     public Either<Product, ResponseFormat> updateProductMetadata(String productId, Product updatedProduct, User user) {
566         ComponentTypeEnum typeEnum = ComponentTypeEnum.PRODUCT;
567         user = validateUser(user, "Update Product", updatedProduct, null, false);
568         // validate user role
569         validateUserRole(user, updatedProduct, updateRoles, null, null);
570         if (updatedProduct == null) {
571             log.debug("Invalid product json. Check product servlet log for updateProduct entry params");
572             ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
573             return Either.right(responseFormat);
574         }
575         Either<Product, StorageOperationStatus> storageStatus = toscaOperationFacade.getToscaElement(productId);
576         if (storageStatus.isRight()) {
577             if (storageStatus.right().value() == StorageOperationStatus.NOT_FOUND) {
578                 return Either
579                     .right(componentsUtils.getResponseFormat(ActionStatus.PRODUCT_NOT_FOUND, ComponentTypeEnum.PRODUCT.name().toLowerCase()));
580             }
581             return Either
582                 .right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(storageStatus.right().value(), typeEnum), ""));
583         }
584         Product currentProduct = storageStatus.left().value();
585         if (!ComponentValidationUtils.canWorkOnComponent(productId, toscaOperationFacade, user.getUserId())) {
586             log.info("Restricted operation for user: {}, on product: {}", user.getUserId(), currentProduct.getCreatorUserId());
587             return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
588         }
589         Either<Product, ResponseFormat> validationRsponse = validateAndUpdateProductMetadata(user, currentProduct, updatedProduct);
590         if (validationRsponse.isRight()) {
591             log.info("product update metadata: validations field.");
592             return validationRsponse;
593         }
594         Product productToUpdate = validationRsponse.left().value();
595         // lock resource
596         lockComponent(currentProduct.getUniqueId(), currentProduct, "Update Product Metadata");
597         try {
598             Either<Product, StorageOperationStatus> updateResponse = toscaOperationFacade.updateToscaElement(productToUpdate);
599             if (updateResponse.isRight()) {
600                 toscaOperationFacade.rollback();
601                 log.debug("failed to update product {}", productToUpdate.getUniqueId());
602                 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
603             }
604             toscaOperationFacade.commit();
605             return Either.left(updateResponse.left().value());
606         } finally {
607             graphLockOperation.unlockComponent(productId, NodeTypeEnum.Product);
608         }
609     }
610
611     private Either<Product, ResponseFormat> validateAndUpdateProductMetadata(User user, Product currentProduct, Product updatedProduct) {
612         boolean hasBeenCertified = ValidationUtils.hasBeenCertified(currentProduct.getVersion());
613         Either<Boolean, ResponseFormat> response = validateAndUpdateProductName(user, currentProduct, updatedProduct);
614         if (response.isRight()) {
615             ResponseFormat errorResponse = response.right().value();
616             return Either.right(errorResponse);
617         }
618         response = validateAndUpdateFullName(user, currentProduct, updatedProduct);
619         if (response.isRight()) {
620             ResponseFormat errorResponse = response.right().value();
621             return Either.right(errorResponse);
622         }
623         response = validateAndUpdateDescription(user, currentProduct, updatedProduct, null);
624         if (response.isRight()) {
625             ResponseFormat errorResponse = response.right().value();
626             return Either.right(errorResponse);
627         }
628         response = validateAndUpdateCategory(user, currentProduct, updatedProduct);
629         if (response.isRight()) {
630             ResponseFormat errorResponse = response.right().value();
631             return Either.right(errorResponse);
632         }
633         response = validateAndUpdateContactList(user, currentProduct, updatedProduct);
634         if (response.isRight()) {
635             ResponseFormat errorResponse = response.right().value();
636             return Either.right(errorResponse);
637         }
638         response = validateAndUpdateTags(user, currentProduct, updatedProduct);
639         if (response.isRight()) {
640             ResponseFormat errorResponse = response.right().value();
641             return Either.right(errorResponse);
642         }
643         response = validateAndUpdateProjectCode(user, currentProduct, updatedProduct);
644         if (response.isRight()) {
645             ResponseFormat errorResponse = response.right().value();
646             return Either.right(errorResponse);
647         }
648         if (updatedProduct.getIsActive() != null) {
649             currentProduct.setIsActive(updatedProduct.getIsActive());
650         }
651         response = validateAndUpdateIcon(user, currentProduct, updatedProduct, hasBeenCertified);
652         if (response.isRight()) {
653             ResponseFormat errorResponse = response.right().value();
654             return Either.right(errorResponse);
655         }
656         String currentInvariantUuid = currentProduct.getInvariantUUID();
657         String updatedInvariantUuid = updatedProduct.getInvariantUUID();
658         if ((updatedInvariantUuid != null) && (!updatedInvariantUuid.equals(currentInvariantUuid))) {
659             log.warn("Product invariant UUID is automatically set and cannot be updated");
660             updatedProduct.setInvariantUUID(currentInvariantUuid);
661         }
662         return Either.left(currentProduct);
663     }
664
665     private Either<Boolean, ResponseFormat> validateAndUpdateProductName(User user, Product currentProduct, Product updatedProduct) {
666         String updatedProductName = updatedProduct.getName();
667         String tags;
668         String currentProductName = currentProduct.getName();
669         if (updatedProductName != null) {
670             Either<Boolean, ResponseFormat> validatProductNameResponse = validateProductNameAndCleanup(user, updatedProduct, null);
671             if (validatProductNameResponse.isRight()) {
672                 ResponseFormat errorRespons = validatProductNameResponse.right().value();
673                 return Either.right(errorRespons);
674             }
675             updatedProductName = updatedProduct.getName();
676             if (!currentProductName.equals(updatedProductName)) {
677                 try {
678                     componentNameValidator.validateComponentNameUnique(user, updatedProduct, null);
679                 } catch (ComponentException exp) {
680                     return Either.right(exp.getResponseFormat());
681                 }
682                 currentProduct.setName(updatedProductName);
683                 tags = updatedProductName;
684                 updatedProductName = ValidationUtils.normalizeCategoryName4Display(updatedProductName);
685                 currentProduct.getComponentMetadataDefinition().getMetadataDataDefinition()
686                     .setNormalizedName(ValidationUtils.normaliseComponentName(updatedProductName));
687                 List<String> updatedTags = updatedProduct.getTags();
688                 // As discussed with Ella currently (1604) we are not removing
689
690                 // the old name from tags.
691                 if (updatedTags == null) {
692                     updatedTags = currentProduct.getTags();
693                 }
694                 updatedTags.add(tags);
695             }
696         }
697         return Either.left(true);
698     }
699
700     private Either<Boolean, ResponseFormat> validateAndUpdateFullName(User user, Product currentProduct, Product updatedProduct) {
701         String updatedProductName = updatedProduct.getFullName();
702         String currentProductName = currentProduct.getFullName();
703         if (updatedProductName != null && !currentProductName.equals(updatedProductName)) {
704             Either<Boolean, ResponseFormat> validatProductNameResponse = validateProductFullNameAndCleanup(user, updatedProduct, null);
705             if (validatProductNameResponse.isRight()) {
706                 ResponseFormat errorRespons = validatProductNameResponse.right().value();
707                 return Either.right(errorRespons);
708             }
709             currentProduct.setFullName(updatedProduct.getFullName());
710         }
711         return Either.left(true);
712     }
713
714     private Either<Boolean, ResponseFormat> validateAndUpdateCategory(User user, Product currentProduct, Product updatedProduct) {
715         Either<Boolean, ResponseFormat> validateCategoryResponse = validateGrouping(user, updatedProduct, null);
716         if (validateCategoryResponse.isRight()) {
717             ResponseFormat errorResponse = validateCategoryResponse.right().value();
718             return Either.right(errorResponse);
719         }
720         List<CategoryDefinition> categoryUpdated = updatedProduct.getCategories();
721         if (categoryUpdated != null) {
722             currentProduct.setCategories(categoryUpdated);
723         }
724         return Either.left(true);
725     }
726
727     private Either<Boolean, ResponseFormat> validateAndUpdateContactList(User user, Product currentProduct, Product updatedProduct) {
728         List<String> updatedContacts = updatedProduct.getContacts();
729         List<String> currentContacts = currentProduct.getContacts();
730         if (updatedContacts != null) {
731             if (!(currentContacts.containsAll(updatedContacts) && updatedContacts.containsAll(currentContacts))) {
732                 Either<Boolean, ResponseFormat> validatResponse = validateAndUpdateProductContactsList(user, updatedProduct, null);
733                 if (validatResponse.isRight()) {
734                     ResponseFormat errorRespons = validatResponse.right().value();
735                     return Either.right(errorRespons);
736                 }
737                 currentProduct.setContacts(updatedProduct.getContacts());
738             }
739         }
740         return Either.left(true);
741     }
742
743     private Either<Boolean, ResponseFormat> validateAndUpdateTags(User user, Product currentProduct, Product updatedProduct) {
744         List<String> tagsUpdated = updatedProduct.getTags();
745         List<String> tagsCurrent = currentProduct.getTags();
746         if (tagsUpdated != null) {
747             if (!(tagsCurrent.containsAll(tagsUpdated) && tagsUpdated.containsAll(tagsCurrent))) {
748                 Either<Boolean, ResponseFormat> validatResponse = validateTagsListAndRemoveDuplicates(user, updatedProduct, currentProduct.getName(),
749                     null);
750                 if (validatResponse.isRight()) {
751                     ResponseFormat errorRespons = validatResponse.right().value();
752                     return Either.right(errorRespons);
753                 }
754                 currentProduct.setTags(updatedProduct.getTags());
755             }
756         }
757         return Either.left(true);
758     }
759
760     @Override
761     public Either<List<String>, ResponseFormat> deleteMarkedComponents() {
762         // markAsDeleted isnt implemented yet
763         return Either.left(new ArrayList<>());
764     }
765
766     public Either<Product, ResponseFormat> getProductByNameAndVersion(String productName, String productVersion, String userId) {
767         validateUserExists(userId);
768         Either<Product, StorageOperationStatus> storageStatus = toscaOperationFacade
769             .getComponentByNameAndVersion(ComponentTypeEnum.PRODUCT, productName, productVersion);
770         if (storageStatus.isRight()) {
771             log.debug("failed to get service by name {} and version {}", productName, productVersion);
772             return Either.right(componentsUtils
773                 .getResponseFormat(componentsUtils.convertFromStorageResponse(storageStatus.right().value(), ComponentTypeEnum.PRODUCT),
774                     productName));
775         }
776         Product product = storageStatus.left().value();
777         return Either.left(product);
778     }
779
780     @Override
781     public ComponentInstanceBusinessLogic getComponentInstanceBL() {
782         return componentInstanceBusinessLogic;
783     }
784
785     @Override
786     public Either<List<ComponentInstance>, ResponseFormat> getComponentInstancesFilteredByPropertiesAndInputs(String componentId, String userId) {
787         return null;
788     }
789
790     @Override
791     public Either<UiComponentDataTransfer, ResponseFormat> getUiComponentDataTransferByComponentId(String componentId,
792                                                                                                    List<String> dataParamsToReturn) {
793         // TODO Auto-generated method stub
794         return null;
795     }
796 }