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