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