Implement Attributes/Outputs BE (part 2)
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / components / impl / BaseBusinessLogic.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 static org.openecomp.sdc.common.log.enums.EcompLoggerErrorCode.BUSINESS_PROCESS_ERROR;
26
27 import com.google.gson.JsonElement;
28 import fj.data.Either;
29 import java.util.ArrayList;
30 import java.util.Arrays;
31 import java.util.Collections;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.function.Function;
35 import org.apache.commons.lang3.ArrayUtils;
36 import org.apache.commons.lang3.StringUtils;
37 import org.apache.commons.lang3.tuple.ImmutablePair;
38 import org.openecomp.sdc.be.components.impl.exceptions.BusinessLogicException;
39 import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
40 import org.openecomp.sdc.be.components.impl.exceptions.ByResponseFormatComponentException;
41 import org.openecomp.sdc.be.components.impl.exceptions.ComponentException;
42 import org.openecomp.sdc.be.components.validation.UserValidations;
43 import org.openecomp.sdc.be.config.BeEcompErrorManager;
44 import org.openecomp.sdc.be.config.BeEcompErrorManager.ErrorSeverity;
45 import org.openecomp.sdc.be.dao.api.ActionStatus;
46 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphGenericDao;
47 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
48 import org.openecomp.sdc.be.dao.jsongraph.JanusGraphDao;
49 import org.openecomp.sdc.be.datamodel.utils.ArtifactUtils;
50 import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
51 import org.openecomp.sdc.be.datatypes.elements.PropertyRule;
52 import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition;
53 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
54 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
55 import org.openecomp.sdc.be.datatypes.tosca.ToscaDataDefinition;
56 import org.openecomp.sdc.be.impl.ComponentsUtils;
57 import org.openecomp.sdc.be.model.ArtifactDefinition;
58 import org.openecomp.sdc.be.model.Component;
59 import org.openecomp.sdc.be.model.ComponentInstInputsMap;
60 import org.openecomp.sdc.be.model.ComponentInstOutputsMap;
61 import org.openecomp.sdc.be.model.ComponentInstance;
62 import org.openecomp.sdc.be.model.ComponentInstanceProperty;
63 import org.openecomp.sdc.be.model.ComponentParametersView;
64 import org.openecomp.sdc.be.model.DataTypeDefinition;
65 import org.openecomp.sdc.be.model.IComplexDefaultValue;
66 import org.openecomp.sdc.be.model.IPropertyInputCommon;
67 import org.openecomp.sdc.be.model.LifecycleStateEnum;
68 import org.openecomp.sdc.be.model.PolicyDefinition;
69 import org.openecomp.sdc.be.model.PropertyConstraint;
70 import org.openecomp.sdc.be.model.PropertyDefinition;
71 import org.openecomp.sdc.be.model.User;
72 import org.openecomp.sdc.be.model.cache.ApplicationDataTypeCache;
73 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ArtifactsOperations;
74 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.InterfaceOperation;
75 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ToscaOperationFacade;
76 import org.openecomp.sdc.be.model.operations.StorageException;
77 import org.openecomp.sdc.be.model.operations.api.IElementOperation;
78 import org.openecomp.sdc.be.model.operations.api.IGraphLockOperation;
79 import org.openecomp.sdc.be.model.operations.api.IGroupInstanceOperation;
80 import org.openecomp.sdc.be.model.operations.api.IGroupOperation;
81 import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation;
82 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
83 import org.openecomp.sdc.be.model.operations.impl.AttributeOperation;
84 import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter;
85 import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation;
86 import org.openecomp.sdc.be.model.operations.impl.PolicyTypeOperation;
87 import org.openecomp.sdc.be.model.operations.impl.PropertyOperation;
88 import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils;
89 import org.openecomp.sdc.be.model.tosca.ToscaPropertyType;
90 import org.openecomp.sdc.be.model.tosca.ToscaType;
91 import org.openecomp.sdc.be.model.tosca.converters.PropertyValueConverter;
92 import org.openecomp.sdc.be.model.tosca.validators.DataTypeValidatorConverter;
93 import org.openecomp.sdc.be.model.tosca.validators.PropertyTypeValidator;
94 import org.openecomp.sdc.be.user.Role;
95 import org.openecomp.sdc.be.user.UserBusinessLogic;
96 import org.openecomp.sdc.common.api.ArtifactTypeEnum;
97 import org.openecomp.sdc.common.datastructure.Wrapper;
98 import org.openecomp.sdc.common.log.wrappers.Logger;
99 import org.openecomp.sdc.exception.ResponseFormat;
100 import org.springframework.beans.factory.annotation.Autowired;
101
102 public abstract class BaseBusinessLogic {
103
104     private static final String FAILED_TO_LOCK_COMPONENT_ERROR = "Failed to lock component {} error - {}";
105
106     private static final Logger log = Logger.getLogger(BaseBusinessLogic.class);
107     private static final String EMPTY_VALUE = null;
108     private static final String SCHEMA_DOESN_T_EXISTS_FOR_PROPERTY_OF_TYPE = "Schema doesn't exists for property of type {}";
109     private static final String PROPERTY_IN_SCHEMA_DEFINITION_INSIDE_PROPERTY_OF_TYPE_DOESN_T_EXIST = "Property in Schema Definition inside property of type {} doesn't exist";
110     private static final String ADD_PROPERTY_VALUE = "Add property value";
111     private static final String THE_VALUE_OF_PROPERTY_FROM_TYPE_IS_INVALID = "The value {} of property from type {} is invalid";
112     protected IGroupTypeOperation groupTypeOperation;
113     protected InterfaceOperation interfaceOperation;
114     protected IElementOperation elementDao;
115     protected ComponentsUtils componentsUtils;
116     protected UserBusinessLogic userAdmin;
117     protected IGraphLockOperation graphLockOperation;
118     protected JanusGraphDao janusGraphDao;
119     protected JanusGraphGenericDao janusGraphGenericDao;
120     protected PropertyOperation propertyOperation;
121     protected AttributeOperation attributeOperation;
122     protected ApplicationDataTypeCache applicationDataTypeCache;
123     protected ToscaOperationFacade toscaOperationFacade;
124     protected ApplicationDataTypeCache dataTypeCache;
125     protected IGroupOperation groupOperation;
126     protected IGroupInstanceOperation groupInstanceOperation;
127     protected InterfaceLifecycleOperation interfaceLifecycleTypeOperation;
128     protected PolicyTypeOperation policyTypeOperation;
129     protected ArtifactsOperations artifactToscaOperation;
130     protected UserValidations userValidations;
131
132     DataTypeValidatorConverter dataTypeValidatorConverter = DataTypeValidatorConverter.getInstance();
133
134     protected BaseBusinessLogic(IElementOperation elementDao, IGroupOperation groupOperation,
135         IGroupInstanceOperation groupInstanceOperation, IGroupTypeOperation groupTypeOperation, InterfaceOperation interfaceOperation,
136         InterfaceLifecycleOperation interfaceLifecycleTypeOperation, ArtifactsOperations artifactToscaOperation) {
137         this.elementDao = elementDao;
138         this.groupOperation = groupOperation;
139         this.groupInstanceOperation = groupInstanceOperation;
140         this.groupTypeOperation = groupTypeOperation;
141         this.interfaceOperation = interfaceOperation;
142         this.interfaceLifecycleTypeOperation = interfaceLifecycleTypeOperation;
143         this.artifactToscaOperation = artifactToscaOperation;
144     }
145
146     @Autowired
147     public void setUserAdmin(UserBusinessLogic userAdmin) {
148         this.userAdmin = userAdmin;
149     }
150
151     @Autowired
152     public void setUserValidations(UserValidations userValidations) {
153         this.userValidations = userValidations;
154     }
155
156     @Autowired
157     public void setComponentsUtils(ComponentsUtils componentsUtils) {
158         this.componentsUtils = componentsUtils;
159     }
160
161     @Autowired
162     public void setJanusGraphDao(JanusGraphDao janusGraphDao) {
163         this.janusGraphDao = janusGraphDao;
164     }
165
166     @Autowired
167     public void setApplicationDataTypeCache(ApplicationDataTypeCache applicationDataTypeCache) {
168         this.applicationDataTypeCache = applicationDataTypeCache;
169     }
170
171     @Autowired
172     public void setJanusGraphGenericDao(JanusGraphGenericDao janusGraphGenericDao) {
173         this.janusGraphGenericDao = janusGraphGenericDao;
174     }
175
176     @Autowired
177     public void setGraphLockOperation(IGraphLockOperation graphLockOperation) {
178         this.graphLockOperation = graphLockOperation;
179     }
180
181     @Autowired
182     public void setToscaOperationFacade(ToscaOperationFacade toscaOperationFacade) {
183         this.toscaOperationFacade = toscaOperationFacade;
184     }
185
186     @Autowired
187     void setPolicyTypeOperation(PolicyTypeOperation policyTypeOperation) {
188         this.policyTypeOperation = policyTypeOperation;
189     }
190
191     @Autowired
192     public void setDataTypeCache(ApplicationDataTypeCache dataTypeCache) {
193         this.dataTypeCache = dataTypeCache;
194     }
195
196     @Autowired
197     public void setPropertyOperation(PropertyOperation propertyOperation) {
198         this.propertyOperation = propertyOperation;
199     }
200
201     @Autowired
202     public void setAttributeOperation(AttributeOperation attributeOperation) {
203         this.attributeOperation = attributeOperation;
204     }
205
206     User validateUserNotEmpty(User user, String ecompErrorContext) {
207         return userValidations.validateUserNotEmpty(user, ecompErrorContext);
208     }
209
210     protected User validateUserExists(String userId) {
211         return userValidations.validateUserExists(userId);
212     }
213
214     public User validateUserExists(User user) {
215         return userValidations.validateUserExists(user);
216     }
217
218     ActionStatus validateUserExistsActionStatus(String userId) {
219         return userValidations.validateUserExistsActionStatus(userId);
220     }
221
222     protected void validateUserRole(User user, List<Role> roles) {
223         userValidations.validateUserRole(user, roles);
224     }
225
226     protected void lockComponent(Component component, String ecompErrorContext) {
227         lockComponent(component.getUniqueId(), component, ecompErrorContext);
228     }
229
230     protected boolean isVolumeGroup(List<String> artifactsInGroup,List <ArtifactDefinition> deploymentArtifacts) {
231         for (String artifactId : artifactsInGroup) {
232             ArtifactDefinition artifactDef = ArtifactUtils.findArtifactInList(deploymentArtifacts, artifactId);
233             if (artifactDef != null
234                     && artifactDef.getArtifactType().equalsIgnoreCase(ArtifactTypeEnum.HEAT_VOL.getType())) {
235                 return true;
236             }
237         }
238         return false;
239     }
240
241     protected void lockComponent(Component component, boolean shouldLock, String ecompErrorContext) {
242         if(shouldLock){
243             lockComponent(component.getUniqueId(), component, ecompErrorContext);
244         }
245     }
246
247     protected void lockComponent(String componentId, Component component, String ecompErrorContext) {
248         ActionStatus lock = lockElement(componentId, component, ecompErrorContext);
249         if (lock!= ActionStatus.OK) {
250             logAndThrowComponentException(lock, component.getUniqueId(), component.getName());
251         }
252     }
253
254     protected void lockComponent(String componentId, Component component, boolean needLock, String ecompErrorContext) {
255         if (needLock) {
256             lockComponent(componentId, component, ecompErrorContext);
257         }
258     }
259
260     private ResponseFormat logAndThrowComponentException(ActionStatus status, String componentId, String name){
261         log.debug(FAILED_TO_LOCK_COMPONENT_ERROR, componentId, status);
262         throw new ByActionStatusComponentException(status, name);
263     }
264
265     private ActionStatus lockElement(String componentId, Component component, String ecompErrorContext) {
266         ComponentTypeEnum componentType = component.getComponentType();
267         NodeTypeEnum nodeType = componentType.getNodeType();
268         StorageOperationStatus lockResourceStatus = graphLockOperation.lockComponent(componentId, nodeType);
269
270         if (lockResourceStatus == StorageOperationStatus.OK) {
271             return ActionStatus.OK;
272         } else {
273             BeEcompErrorManager.getInstance().logBeFailedLockObjectError(ecompErrorContext, nodeType.getName(), componentId);
274             return componentsUtils.convertFromStorageResponse(lockResourceStatus, componentType);
275         }
276     }
277
278     protected void unlockComponent(boolean failed, Component component, boolean inTransaction) {
279         if (component != null) {
280             ComponentTypeEnum componentType = component.getComponentType();
281             NodeTypeEnum nodeType = componentType.getNodeType();
282             if (!inTransaction) {
283                 if (failed) {
284                     janusGraphDao.rollback();
285                 } else {
286                     janusGraphDao.commit();
287                 }
288             }
289             // unlock resource
290             graphLockOperation.unlockComponent(component.getUniqueId(), nodeType);
291         }
292         else log.debug("component is NULL");
293     }
294
295     protected void unlockComponent(boolean failed, Component component) {
296         unlockComponent(failed, component, false);
297     }
298     void unlockComponentById(boolean failed, String componentId) {
299         Either<Component, StorageOperationStatus> component = toscaOperationFacade.getToscaElement(componentId);
300         if(component.isLeft()) {
301             unlockComponent(failed, component.left().value(), false);
302         }
303     }
304
305     <T> Boolean validateJsonBody(T bodyObject, Class<T> clazz) {
306         if (bodyObject == null) {
307             log.debug("Invalid JSON received for object of type {}", clazz.getSimpleName());
308             throw new ByActionStatusComponentException(ActionStatus.INVALID_CONTENT);
309         } else {
310             return true;
311         }
312     }
313
314
315     ComponentTypeEnum validateComponentType(String componentType) {
316         ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentType);
317         if (componentTypeEnum == null) {
318             log.debug("Invalid component type {}", componentType);
319             throw new ByActionStatusComponentException(ActionStatus.UNSUPPORTED_ERROR, componentType);
320         } else {
321             return componentTypeEnum;
322         }
323     }
324
325     Component validateComponentExists(String componentId, ComponentTypeEnum componentType, ComponentParametersView filter) {
326
327         Either<Component, StorageOperationStatus> toscaElement = toscaOperationFacade.getToscaElement(componentId, filter == null ? new ComponentParametersView() : filter);
328         if(toscaElement.isRight()){
329             handleGetComponentError(componentId, componentType, toscaElement.right().value());
330         }
331         return validateComponentType(toscaElement.left().value(), componentType);
332     }
333
334     private Component validateComponentType(Component cmpt, ComponentTypeEnum componentType) {
335         if (componentType != cmpt.getComponentType()) {
336             log.debug("component {} is not of requested type {}", cmpt.getUniqueId(), componentType);
337             throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(StorageOperationStatus.NOT_FOUND, componentType));
338         }
339         return cmpt;
340     }
341
342     <T extends PropertyDataDefinition> String updateInputPropertyObjectValue(T property) {
343         Either<Map<String, DataTypeDefinition>, JanusGraphOperationStatus> allDataTypesEither = dataTypeCache.getAll();
344         if (allDataTypesEither.isRight()) {
345             JanusGraphOperationStatus status = allDataTypesEither.right().value();
346             BeEcompErrorManager.getInstance().logInternalFlowError("UpdatePropertyValueOnComponentInstance", "Failed to update property value on instance. Status is " + status, ErrorSeverity.ERROR);
347             throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status)));
348         }
349         Map<String, DataTypeDefinition> allDataTypes = allDataTypesEither.left().value();
350         String propertyType = property.getType();
351         String innerType = getInnerType(property);
352         // Specific Update Logic
353         Either<Object, Boolean> isValid =
354                 propertyOperation.validateAndUpdatePropertyValue(propertyType, property.getValue(), true,
355                         innerType, allDataTypes);
356         String newValue = property.getValue();
357         if (isValid.isRight()) {
358             Boolean res = isValid.right().value();
359             if (Boolean.FALSE.equals(res)) {
360                 throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(JanusGraphOperationStatus.ILLEGAL_ARGUMENT)));
361             }
362         } else {
363             Object object = isValid.left().value();
364             if (object != null) {
365                 newValue = object.toString();
366             }
367         }
368         return newValue;
369     }
370
371     <T extends PropertyDataDefinition> String getInnerType(T property){
372         ToscaPropertyType type = ToscaPropertyType.isValidType(property.getType());
373         log.debug("#getInnerType - The type of the property {} is {}", property.getUniqueId(), property.getType());
374         String innerType = null;
375         if (type == ToscaPropertyType.LIST || type == ToscaPropertyType.MAP) {
376             if (property.getSchema() == null) {
377                 log.debug(SCHEMA_DOESN_T_EXISTS_FOR_PROPERTY_OF_TYPE, type);
378                 throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(StorageOperationStatus.INVALID_VALUE));
379             }
380             PropertyDataDefinition innerProperty = property.getSchema().getProperty();
381             if (innerProperty == null) {
382                 log.debug(PROPERTY_IN_SCHEMA_DEFINITION_INSIDE_PROPERTY_OF_TYPE_DOESN_T_EXIST, type);
383                 throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(StorageOperationStatus.INVALID_VALUE));
384             }
385             innerType = innerProperty.getType();
386         }
387         return innerType;
388     }
389
390     public void validateCanWorkOnComponent(Component component, String userId) {
391         ActionStatus actionStatus = ActionStatus.RESTRICTED_OPERATION;
392         // verify resource is not archived
393         if (Boolean.TRUE.equals(component.isArchived())){
394             actionStatus = ActionStatus.COMPONENT_IS_ARCHIVED;
395             throw new ByActionStatusComponentException(actionStatus, component.getName());
396         }
397
398         if (component.getLifecycleState() != LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT) {
399             log.debug("Component {} is not checked-out", component.getName());
400             throw new ByActionStatusComponentException(actionStatus);
401         }
402
403         // verify userId is not null
404         if (userId == null) {
405             log.debug("Current user userId is null");
406             throw new ByActionStatusComponentException(actionStatus);
407         }
408
409         // verify component last update user is the current user
410         String lastUpdaterUserId = component.getLastUpdaterUserId();
411         if (!userId.equals(lastUpdaterUserId)) {
412             log.debug("Current user is not last updater, last updater userId: {}, current user userId: {}", lastUpdaterUserId, userId);
413             throw new ByActionStatusComponentException(actionStatus);
414         }
415
416         // verify resource is not deleted
417         if (Boolean.TRUE.equals(component.getIsDeleted())) {
418             log.debug("Component {} is marked as deleted", component.getUniqueId());
419             throw new ByActionStatusComponentException(actionStatus);
420         }
421
422     }
423
424     ComponentTypeEnum getComponentTypeByParentComponentType(ComponentTypeEnum parentComponentType) {
425         switch (parentComponentType) {
426             case SERVICE:
427             case RESOURCE:
428                 return ComponentTypeEnum.RESOURCE;
429             case PRODUCT:
430                 return ComponentTypeEnum.SERVICE;
431             default:
432                 break;
433         }
434         return null;
435     }
436
437     protected Map<String, DataTypeDefinition> getAllDataTypes(ApplicationDataTypeCache applicationDataTypeCache) {
438         Either<Map<String, DataTypeDefinition>, JanusGraphOperationStatus> allDataTypes = applicationDataTypeCache.getAll();
439         if (allDataTypes.isRight()) {
440             JanusGraphOperationStatus operationStatus = allDataTypes.right().value();
441             if (operationStatus == JanusGraphOperationStatus.NOT_FOUND) {
442                 BeEcompErrorManager.getInstance().logInternalDataError("FetchDataTypes", "Data types are not loaded", ErrorSeverity.ERROR);
443                 throw new ByActionStatusComponentException(ActionStatus.DATA_TYPE_CANNOT_BE_EMPTY);
444             } else {
445                 BeEcompErrorManager.getInstance().logInternalFlowError("FetchDataTypes", "Failed to fetch data types", ErrorSeverity.ERROR);
446                 throw new ByActionStatusComponentException(ActionStatus.GENERAL_ERROR);
447             }
448         }
449         return allDataTypes.left().value();
450     }
451
452     Either<Boolean, ResponseFormat> validatePropertyDefaultValue(IComplexDefaultValue property, Map<String, DataTypeDefinition> dataTypes) {
453         String type;
454         String innerType = null;
455         if (!propertyOperation.isPropertyTypeValid(property)) {
456             log.info("Invalid type for property '{}' type '{}'", property.getName(), property.getType());
457             ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_PROPERTY_TYPE, property.getType(), property.getName());
458             return Either.right(responseFormat);
459         }
460         type = property.getType();
461         if (type.equals(ToscaPropertyType.LIST.getType()) || type.equals(ToscaPropertyType.MAP.getType())) {
462             ImmutablePair<String, Boolean> propertyInnerTypeValid = propertyOperation.isPropertyInnerTypeValid(property, dataTypes);
463             innerType = propertyInnerTypeValid.getLeft();
464             if (Boolean.FALSE.equals(propertyInnerTypeValid.getRight())) {
465                 log.info("Invalid inner type for property '{}' type '{}', dataTypeCount '{}'", property.getName(), property.getType(), dataTypes.size());
466                 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_PROPERTY_INNER_TYPE, innerType, property.getName());
467                 return Either.right(responseFormat);
468             }
469         }
470         if (!propertyOperation.isPropertyDefaultValueValid(property, dataTypes)) {
471             log.info("Invalid default value for property '{}' type '{}'", property.getName(), property.getType());
472             ResponseFormat responseFormat;
473             if (type.equals(ToscaPropertyType.LIST.getType()) || type.equals(ToscaPropertyType.MAP.getType())) {
474                 responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_COMPLEX_DEFAULT_VALUE, property.getName(), type, innerType,
475                         property.getDefaultValue());
476             } else {
477                 responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_DEFAULT_VALUE, property.getName(), type,
478                         property.getDefaultValue());
479             }
480             return Either.right(responseFormat);
481
482         }
483         return Either.left(true);
484     }
485
486     void validateComponentTypeEnum(ComponentTypeEnum componentTypeEnum, String errorContext, Wrapper<ResponseFormat> errorWrapper) {
487         if (componentTypeEnum == null) {
488             BeEcompErrorManager.getInstance().logInvalidInputError(errorContext, "invalid component type", ErrorSeverity.INFO);
489             errorWrapper.setInnerElement(componentsUtils.getResponseFormat(ActionStatus.NOT_ALLOWED));
490         }
491
492     }
493
494     protected void validateCanWorkOnComponent(String componentId, ComponentTypeEnum componentTypeEnum, String userId, Wrapper<ResponseFormat> errorWrapper) {
495         if (!ComponentValidationUtils.canWorkOnComponent(componentId, toscaOperationFacade, userId)) {
496             log.info("Restricted operation for user {} on {} {}", userId, componentTypeEnum.getValue(), componentId);
497             errorWrapper.setInnerElement(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
498         }
499
500     }
501
502     void validateComponentLock(String componentId, ComponentTypeEnum componentTypeEnum, Wrapper<ResponseFormat> errorWrapper) {
503         StorageOperationStatus lockStatus = graphLockOperation.lockComponent(componentId, componentTypeEnum.getNodeType());
504         if (lockStatus != StorageOperationStatus.OK) {
505             log.debug("Failed to lock {} {}", componentTypeEnum.getValue(), componentId);
506             errorWrapper.setInnerElement(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(lockStatus)));
507         }
508
509     }
510
511     protected ToscaPropertyType getType(String propertyType) {
512         return ToscaPropertyType.isValidType(propertyType);
513     }
514
515     void commitOrRollback(Either<?, ResponseFormat> result) {
516         if (result == null || result.isRight()) {
517             log.warn("operation failed. do rollback");
518             janusGraphDao.rollback();
519         } else {
520             log.debug("operation success. do commit");
521             janusGraphDao.commit();
522         }
523     }
524
525     protected Either<Boolean, ResponseFormat> lockComponentByName(String name, Component component, String ecompErrorContext) {
526         ComponentTypeEnum componentType = component.getComponentType();
527         NodeTypeEnum nodeType = componentType.getNodeType();
528         StorageOperationStatus lockResourceStatus = graphLockOperation.lockComponentByName(name, nodeType);
529
530         if (lockResourceStatus == StorageOperationStatus.OK) {
531             return Either.left(true);
532         } else {
533             BeEcompErrorManager.getInstance().logBeFailedLockObjectError(ecompErrorContext, nodeType.getName(), name);
534             ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(lockResourceStatus, componentType);
535             ResponseFormat responseFormat = componentsUtils.getResponseFormat(actionStatus, component.getName());
536             log.debug(FAILED_TO_LOCK_COMPONENT_ERROR, name, actionStatus);
537             return Either.right(responseFormat);
538         }
539     }
540
541     protected Component validateComponentExistsByFilter(String componentId, ComponentTypeEnum componentType, ComponentParametersView componentParametersView) {
542         return toscaOperationFacade.getToscaElement(componentId, componentParametersView)
543                 .left()
544                 .on(err -> handleGetComponentError(componentId, componentType, err));
545
546     }
547
548     private Component handleGetComponentError(String componentId, ComponentTypeEnum componentType, StorageOperationStatus getComponentError) {
549         ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(getComponentError, componentType);
550         log.debug("error fetching component with id {}. error status: {}", componentId, getComponentError);
551         throw new ByActionStatusComponentException(actionStatus, componentId);
552     }
553
554     @SafeVarargs
555     static <T extends Enum<T>> boolean enumHasValueFilter(String name, Function<String, T> enumGetter, T... enumValues) {
556         T enumFound = enumGetter.apply(name);
557         return Arrays.asList(enumValues).contains(enumFound);
558     }
559
560     String validatePropValueBeforeCreate(IPropertyInputCommon property, String value, boolean isValidate,
561         Map<String, DataTypeDefinition> allDataTypes) {
562         String propertyType = property.getType();
563         String updatedInnerType = updateInnerType(property);
564         Either<Object, Boolean> isValid = validateAndUpdatePropertyValue(propertyType, value, isValidate, updatedInnerType, allDataTypes);
565         String newValue = value;
566         if (isValid.isRight()) {
567             Boolean res = isValid.right().value();
568             if (Boolean.FALSE.equals(res)) {
569                 throw new StorageException(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(
570                         JanusGraphOperationStatus.ILLEGAL_ARGUMENT));
571             }
572         } else {
573             Object object = isValid.left().value();
574             if (object != null) {
575                 newValue = object.toString();
576             }
577         }
578         ImmutablePair<String, Boolean> pair = validateAndUpdateRules(propertyType, property.getRules(), updatedInnerType, allDataTypes, isValidate);
579         log.trace("After validateAndUpdateRules. pair = {}", pair);
580         if (Boolean.FALSE.equals(pair.getRight())) {
581             BeEcompErrorManager.getInstance().logBeInvalidValueError(ADD_PROPERTY_VALUE, pair.getLeft(), property.getName(), propertyType);
582             throw new StorageException(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(
583                     JanusGraphOperationStatus.ILLEGAL_ARGUMENT));
584         }
585         return newValue;
586     }
587
588     private String updateInnerType(IPropertyInputCommon property) {
589         ToscaPropertyType type = ToscaPropertyType.isValidType(property.getType());
590         if (type == ToscaPropertyType.LIST || type == ToscaPropertyType.MAP) {
591             SchemaDefinition def = property.getSchema();
592             if (def == null) {
593                 log.debug(SCHEMA_DOESN_T_EXISTS_FOR_PROPERTY_OF_TYPE, type);
594                 failOnIllegalArgument();
595             }
596             PropertyDataDefinition propDef = def.getProperty();
597             if (propDef == null) {
598                 log.debug(PROPERTY_IN_SCHEMA_DEFINITION_INSIDE_PROPERTY_OF_TYPE_DOESN_T_EXIST, type);
599                 failOnIllegalArgument();
600             }
601             return propDef.getType();
602         }
603         return null;
604     }
605
606     private void failOnIllegalArgument() {
607         throw new ByActionStatusComponentException(
608                 componentsUtils.convertFromStorageResponse(
609                         DaoStatusConverter.convertJanusGraphStatusToStorageStatus(JanusGraphOperationStatus.ILLEGAL_ARGUMENT)));
610     }
611
612     public Either<Object, Boolean> validateAndUpdatePropertyValue(String propertyType, String value, boolean isValidate, String innerType, Map<String, DataTypeDefinition> dataTypes) {
613         log.trace("Going to validate property value and its type. type = {}, value = {}", propertyType, value);
614         ToscaPropertyType type = getType(propertyType);
615
616         if (isValidate) {
617
618             if (type == null) {
619                 DataTypeDefinition dataTypeDefinition = dataTypes.get(propertyType);
620                 ImmutablePair<JsonElement, Boolean> validateResult = dataTypeValidatorConverter.validateAndUpdate(value, dataTypeDefinition, dataTypes);
621                 if (Boolean.FALSE.equals(validateResult.right)) {
622                     log.debug(THE_VALUE_OF_PROPERTY_FROM_TYPE_IS_INVALID, value, propertyType);
623                     return Either.right(false);
624                 }
625                 JsonElement jsonElement = validateResult.left;
626                 String valueFromJsonElement = getValueFromJsonElement(jsonElement);
627                 return Either.left(valueFromJsonElement);
628             }
629             log.trace("before validating property type {}", propertyType);
630             boolean isValidProperty = isValidValue(type, value, innerType, dataTypes);
631             if (!isValidProperty) {
632                 log.debug(THE_VALUE_OF_PROPERTY_FROM_TYPE_IS_INVALID, value, type);
633                 return Either.right(false);
634             }
635         }
636         Object convertedValue = value;
637         if (!isEmptyValue(value) && isValidate) {
638             PropertyValueConverter converter = type.getConverter();
639             convertedValue = converter.convert(value, innerType, dataTypes);
640         }
641         return Either.left(convertedValue);
642     }
643
644     private ImmutablePair<String, Boolean> validateAndUpdateRules(String propertyType, List<PropertyRule> rules, String innerType, Map<String, DataTypeDefinition> dataTypes, boolean isValidate) {
645
646         if (rules == null || rules.isEmpty()) {
647             return ImmutablePair.of(null, true);
648         }
649
650         for (PropertyRule rule : rules) {
651             String value = rule.getValue();
652             Either<Object, Boolean> updateResult = validateAndUpdatePropertyValue(propertyType, value, isValidate, innerType, dataTypes);
653             if (updateResult.isRight()) {
654                 Boolean status = updateResult.right().value();
655                 if (Boolean.FALSE.equals(status)) {
656                     return ImmutablePair.of(value, status);
657                 }
658             } else {
659                 String newValue = null;
660                 Object object = updateResult.left().value();
661                 if (object != null) {
662                     newValue = object.toString();
663                 }
664                 rule.setValue(newValue);
665             }
666         }
667
668         return ImmutablePair.of(null, true);
669     }
670
671     protected boolean isValidValue(ToscaPropertyType type, String value, String innerType, Map<String, DataTypeDefinition> dataTypes) {
672         if (isEmptyValue(value)) {
673             return true;
674         }
675
676         PropertyTypeValidator validator = type.getValidator();
677
678         return validator.isValid(value, innerType, dataTypes);
679     }
680
681     public boolean isEmptyValue(String value) {
682         return value == null;
683     }
684
685     protected String getValueFromJsonElement(JsonElement jsonElement) {
686         if (jsonElement == null || jsonElement.isJsonNull()) {
687             return EMPTY_VALUE;
688         }
689         if (jsonElement.toString().isEmpty()) {
690             return "";
691         }
692         return jsonElement.toString();
693     }
694
695     protected void rollbackWithException(ActionStatus actionStatus, String... params) {
696         janusGraphDao.rollback();
697         throw new ByActionStatusComponentException(actionStatus, params);
698     }
699
700     public  <T extends ToscaDataDefinition> Either<List<T>, ResponseFormat> declareProperties(final String userId,
701                                                                                               final String componentId,
702                                                                                               final ComponentTypeEnum componentTypeEnum,
703                                                                                               final ComponentInstInputsMap componentInstInputsMap) {
704         return Either.left(new ArrayList<>());
705     }
706
707     public  <T extends ToscaDataDefinition> Either<List<T>, ResponseFormat> declareAttributes(final String userId,
708                                                                                               final String componentId,
709                                                                                               final ComponentTypeEnum componentTypeEnum,
710                                                                                               final ComponentInstOutputsMap componentInstOutputsMap) {
711         return Either.left(new ArrayList<>());
712     }
713
714     public <T extends PropertyDataDefinition> List<PropertyConstraint> setInputConstraint(T inputDefinition) {
715         if (StringUtils.isNotBlank(inputDefinition.getParentPropertyType())
716                 && StringUtils.isNotBlank(inputDefinition.getSubPropertyInputPath())) {
717             return setConstraint(inputDefinition);
718         }
719
720         return Collections.emptyList();
721     }
722
723     private <T extends PropertyDataDefinition> List<PropertyConstraint> setConstraint(T inputDefinition) {
724         List<PropertyConstraint> constraints = new ArrayList<>();
725         String[] inputPathArr = inputDefinition.getSubPropertyInputPath().split("#");
726         if (inputPathArr.length > 1) {
727             inputPathArr = ArrayUtils.remove(inputPathArr, 0);
728         }
729
730         Map<String, DataTypeDefinition> dataTypeDefinitionMap =
731                 applicationDataTypeCache.getAll().left().value();
732
733         String propertyType = inputDefinition.getParentPropertyType();
734
735         for (String anInputPathArr : inputPathArr) {
736             if (ToscaType.isPrimitiveType(propertyType)) {
737                 constraints.addAll(
738                         dataTypeDefinitionMap.get(propertyType).getConstraints());
739             } else if (!ToscaType.isCollectionType(propertyType)) {
740                 propertyType = setConstraintForComplexType(dataTypeDefinitionMap, propertyType, anInputPathArr,
741                         constraints);
742             }
743         }
744
745         return constraints;
746     }
747
748     private String setConstraintForComplexType(Map<String, DataTypeDefinition> dataTypeDefinitionMap,
749                                                String propertyType,
750                                                String anInputPathArr,
751                                                List<PropertyConstraint> constraints) {
752         String type = null;
753         List<PropertyDefinition> propertyDefinitions =
754                 dataTypeDefinitionMap.get(propertyType).getProperties();
755         for (PropertyDefinition propertyDefinition : propertyDefinitions) {
756             if (propertyDefinition.getName().equals(anInputPathArr)) {
757                 if (ToscaType.isPrimitiveType(propertyDefinition.getType())) {
758                     constraints.addAll(propertyDefinition.safeGetConstraints());
759                 } else {
760                     type = propertyDefinition.getType();
761                 }
762                 break;
763             }
764         }
765
766         return type;
767     }
768
769
770     protected void rollbackWithException(StorageException e) {
771         janusGraphDao.rollback();
772         throw e;
773     }
774
775     protected void rollbackWithException(ComponentException e) {
776         janusGraphDao.rollback();
777         throw e;
778     }
779
780     protected void unlockRollbackWithException(Component component, RuntimeException e) {
781         janusGraphDao.rollback();
782         graphLockOperation.unlockComponent(component.getUniqueId(), component.getComponentType().getNodeType());
783         throw e;
784     }
785
786     protected void unlockWithCommit(Component component){
787         ComponentTypeEnum componentType = component.getComponentType();
788         NodeTypeEnum nodeType = componentType.getNodeType();
789         janusGraphDao.commit();
790         graphLockOperation.unlockComponent(component.getUniqueId(), nodeType);
791     }
792
793     protected ComponentInstance componentInstanceException(StorageOperationStatus storageOperationStatus) {
794         throw new StorageException(storageOperationStatus);
795     }
796
797     protected Component componentException(StorageOperationStatus storageOperationStatus) {
798         throw new StorageException(storageOperationStatus);
799     }
800
801     protected PolicyDefinition storageExceptionPolicyDefinition(StorageOperationStatus storageOperationStatus) {
802         throw new StorageException(storageOperationStatus);
803     }
804
805     protected PolicyDefinition componentExceptionPolicyDefinition(ResponseFormat responseFormat) {
806         throw new ByResponseFormatComponentException(responseFormat);
807     }
808
809     protected Component componentException(ResponseFormat responseFormat) {
810         throw new ByResponseFormatComponentException(responseFormat);
811     }
812
813     protected List<ComponentInstanceProperty> componentInstancePropertyListException(StorageOperationStatus storageOperationStatus) {
814         throw new StorageException(storageOperationStatus);
815     }
816
817     protected Component getComponent(final String componentId) throws BusinessLogicException {
818
819         final Either<Component, StorageOperationStatus> result = toscaOperationFacade.getToscaElement(componentId);
820
821         if (result.isRight()) {
822             final StorageOperationStatus errorStatus = result.right().value();
823             log.error(BUSINESS_PROCESS_ERROR, this.getClass().getName(),
824                 "Failed to fetch component information by component id, error {}", errorStatus);
825             throw new BusinessLogicException(componentsUtils.getResponseFormat(
826                 componentsUtils.convertFromStorageResponse(errorStatus)));
827         }
828         return result.left().value();
829     }
830
831 }