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