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