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