Reformat catalog-model
[sdc.git] / catalog-model / src / main / java / org / openecomp / sdc / be / model / operations / impl / AbstractOperation.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20 package org.openecomp.sdc.be.model.operations.impl;
21
22 import com.google.gson.Gson;
23 import com.google.gson.GsonBuilder;
24 import com.google.gson.JsonElement;
25 import com.google.gson.reflect.TypeToken;
26 import fj.data.Either;
27 import java.lang.reflect.Type;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.function.Supplier;
31 import java.util.stream.Collectors;
32 import org.apache.commons.lang3.tuple.ImmutablePair;
33 import org.openecomp.sdc.be.config.BeEcompErrorManager;
34 import org.openecomp.sdc.be.config.BeEcompErrorManager.ErrorSeverity;
35 import org.openecomp.sdc.be.dao.graph.datatype.GraphEdge;
36 import org.openecomp.sdc.be.dao.janusgraph.HealingJanusGraphGenericDao;
37 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
38 import org.openecomp.sdc.be.dao.neo4j.GraphEdgeLabels;
39 import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
40 import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition;
41 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
42 import org.openecomp.sdc.be.model.DataTypeDefinition;
43 import org.openecomp.sdc.be.model.IComplexDefaultValue;
44 import org.openecomp.sdc.be.model.PropertyConstraint;
45 import org.openecomp.sdc.be.model.cache.ApplicationDataTypeCache;
46 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
47 import org.openecomp.sdc.be.model.operations.impl.PropertyOperation.PropertyConstraintDeserialiser;
48 import org.openecomp.sdc.be.model.tosca.ToscaPropertyType;
49 import org.openecomp.sdc.be.model.tosca.converters.PropertyValueConverter;
50 import org.openecomp.sdc.be.model.tosca.validators.DataTypeValidatorConverter;
51 import org.openecomp.sdc.be.model.tosca.validators.PropertyTypeValidator;
52 import org.openecomp.sdc.be.resources.data.ResourceMetadataData;
53 import org.openecomp.sdc.common.log.wrappers.Logger;
54 import org.springframework.beans.factory.annotation.Autowired;
55
56 public abstract class AbstractOperation {
57
58     public static final String EMPTY_VALUE = null;
59     private static final Logger log = Logger.getLogger(AbstractOperation.class.getName());
60     @Autowired
61     protected HealingJanusGraphGenericDao janusGraphGenericDao;
62     protected Gson gson = new Gson();
63     @Autowired
64     protected ApplicationDataTypeCache applicationDataTypeCache;
65     protected DataTypeValidatorConverter dataTypeValidatorConverter = DataTypeValidatorConverter.getInstance();
66
67     public <ElementDefinition> JanusGraphOperationStatus findAllResourceElementsDefinitionRecursively(String resourceId,
68                                                                                                       List<ElementDefinition> elements,
69                                                                                                       NodeElementFetcher<ElementDefinition> singleNodeFetcher) {
70         if (log.isTraceEnabled()) {
71             log.trace("Going to fetch elements under resource {}", resourceId);
72         }
73         JanusGraphOperationStatus resourceAttributesStatus = singleNodeFetcher.findAllNodeElements(resourceId, elements);
74         if (resourceAttributesStatus != JanusGraphOperationStatus.OK) {
75             return resourceAttributesStatus;
76         }
77         Either<ImmutablePair<ResourceMetadataData, GraphEdge>, JanusGraphOperationStatus> parentNodes = janusGraphGenericDao
78             .getChild(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.Resource), resourceId, GraphEdgeLabels.DERIVED_FROM, NodeTypeEnum.Resource,
79                 ResourceMetadataData.class);
80         if (parentNodes.isRight()) {
81             JanusGraphOperationStatus parentNodesStatus = parentNodes.right().value();
82             if (parentNodesStatus != JanusGraphOperationStatus.NOT_FOUND) {
83                 BeEcompErrorManager.getInstance().logInternalFlowError("findAllResourceElementsDefinitionRecursively",
84                     "Failed to find parent elements of resource " + resourceId + ". status is " + parentNodesStatus, ErrorSeverity.ERROR);
85                 return parentNodesStatus;
86             }
87         }
88         if (parentNodes.isLeft()) {
89             ImmutablePair<ResourceMetadataData, GraphEdge> parnetNodePair = parentNodes.left().value();
90             String parentUniqueId = parnetNodePair.getKey().getMetadataDataDefinition().getUniqueId();
91             JanusGraphOperationStatus addParentIntStatus = findAllResourceElementsDefinitionRecursively(parentUniqueId, elements, singleNodeFetcher);
92             if (addParentIntStatus != JanusGraphOperationStatus.OK) {
93                 BeEcompErrorManager.getInstance().logInternalFlowError("findAllResourceElementsDefinitionRecursively",
94                     "Failed to find all resource elements of resource " + parentUniqueId, ErrorSeverity.ERROR);
95                 return addParentIntStatus;
96             }
97         }
98         return JanusGraphOperationStatus.OK;
99     }
100
101     protected <T, TStatus> void handleTransactionCommitRollback(boolean inTransaction, Either<T, TStatus> result) {
102         if (!inTransaction) {
103             if (result == null || result.isRight()) {
104                 log.error("Going to execute rollback on graph.");
105                 janusGraphGenericDao.rollback();
106             } else {
107                 log.debug("Going to execute commit on graph.");
108                 janusGraphGenericDao.commit();
109             }
110         }
111     }
112
113     /**
114      * @param propertyDefinition
115      * @return
116      */
117     protected StorageOperationStatus validateAndUpdateProperty(IComplexDefaultValue propertyDefinition, Map<String, DataTypeDefinition> dataTypes) {
118         log.trace("Going to validate property type and value. {}", propertyDefinition);
119         String propertyType = propertyDefinition.getType();
120         String value = propertyDefinition.getDefaultValue();
121         ToscaPropertyType type = getType(propertyType);
122         if (type == null) {
123             DataTypeDefinition dataTypeDefinition = dataTypes.get(propertyType);
124             if (dataTypeDefinition == null) {
125                 log.debug("The type {}  of property cannot be found.", propertyType);
126                 return StorageOperationStatus.INVALID_TYPE;
127             }
128             return validateAndUpdateComplexValue(propertyDefinition, propertyType, value, dataTypeDefinition, dataTypes);
129         }
130         String innerType = null;
131         Either<String, JanusGraphOperationStatus> checkInnerType = getInnerType(type, propertyDefinition::getSchema);
132         if (checkInnerType.isRight()) {
133             return StorageOperationStatus.INVALID_TYPE;
134         }
135         innerType = checkInnerType.left().value();
136         log.trace("After validating property type {}", propertyType);
137         boolean isValidProperty = isValidValue(type, value, innerType, dataTypes);
138         if (!isValidProperty) {
139             log.info("The value {} of property from type {} is invalid", value, type);
140             return StorageOperationStatus.INVALID_VALUE;
141         }
142         PropertyValueConverter converter = type.getConverter();
143         if (isEmptyValue(value)) {
144             log.debug("Default value was not sent for property {}. Set default value to {}", propertyDefinition.getName(), EMPTY_VALUE);
145             propertyDefinition.setDefaultValue(EMPTY_VALUE);
146         } else if (!isEmptyValue(value)) {
147             String convertedValue = converter.convert(value, innerType, dataTypes);
148             propertyDefinition.setDefaultValue(convertedValue);
149         }
150         return StorageOperationStatus.OK;
151     }
152
153     protected ToscaPropertyType getType(String propertyType) {
154         return ToscaPropertyType.isValidType(propertyType);
155     }
156
157     protected boolean isValidValue(ToscaPropertyType type, String value, String innerType, Map<String, DataTypeDefinition> dataTypes) {
158         if (isEmptyValue(value)) {
159             return true;
160         }
161         PropertyTypeValidator validator = type.getValidator();
162         return validator.isValid(value, innerType, dataTypes);
163     }
164
165     public boolean isEmptyValue(String value) {
166         return value == null;
167     }
168
169     protected StorageOperationStatus validateAndUpdateComplexValue(IComplexDefaultValue propertyDefinition, String propertyType, String value,
170                                                                    DataTypeDefinition dataTypeDefinition, Map<String, DataTypeDefinition> dataTypes) {
171         ImmutablePair<JsonElement, Boolean> validateResult = dataTypeValidatorConverter.validateAndUpdate(value, dataTypeDefinition, dataTypes);
172         if (!validateResult.right.booleanValue()) {
173             log.debug("The value {} of property from type {} is invalid", propertyType, propertyType);
174             return StorageOperationStatus.INVALID_VALUE;
175         }
176         JsonElement jsonElement = validateResult.left;
177         log.trace("Going to update value in property definition {} {}", propertyDefinition.getName(),
178             (jsonElement != null ? jsonElement.toString() : null));
179         updateValue(propertyDefinition, jsonElement);
180         return StorageOperationStatus.OK;
181     }
182
183     protected void updateValue(IComplexDefaultValue propertyDefinition, JsonElement jsonElement) {
184         propertyDefinition.setDefaultValue(getValueFromJsonElement(jsonElement));
185     }
186
187     protected String getValueFromJsonElement(JsonElement jsonElement) {
188         if (jsonElement == null || jsonElement.isJsonNull()) {
189             return EMPTY_VALUE;
190         } else {
191             return jsonElement.toString();
192         }
193     }
194
195     protected Either<String, JanusGraphOperationStatus> getInnerType(ToscaPropertyType type, Supplier<SchemaDefinition> schemeGen) {
196         String innerType = null;
197         if (type == ToscaPropertyType.LIST || type == ToscaPropertyType.MAP) {
198             SchemaDefinition def = schemeGen.get();
199             if (def == null) {
200                 log.debug("Schema doesn't exists for property of type {}", type);
201                 return Either.right(JanusGraphOperationStatus.ILLEGAL_ARGUMENT);
202             }
203             PropertyDataDefinition propDef = def.getProperty();
204             if (propDef == null) {
205                 log.debug("Property in Schema Definition inside property of type {} doesn't exist", type);
206                 return Either.right(JanusGraphOperationStatus.ILLEGAL_ARGUMENT);
207             }
208             innerType = propDef.getType();
209         }
210         return Either.left(innerType);
211     }
212
213     /**
214      * Convert Constarint object to json in order to add it to the Graph
215      *
216      * @param constraints
217      * @return
218      */
219     public List<String> convertConstraintsToString(List<PropertyConstraint> constraints) {
220         if (constraints == null || constraints.isEmpty()) {
221             return null;
222         }
223         return constraints.stream().map(gson::toJson).collect(Collectors.toList());
224     }
225
226     public List<PropertyConstraint> convertConstraints(List<String> constraints) {
227         if (constraints == null || constraints.isEmpty()) {
228             return null;
229         }
230         Type constraintType = new TypeToken<PropertyConstraint>() {
231         }.getType();
232         Gson gson = new GsonBuilder().registerTypeAdapter(constraintType, new PropertyConstraintDeserialiser()).create();
233         return constraints.stream().map(c -> gson.fromJson(c, PropertyConstraint.class)).collect(Collectors.toList());
234     }
235
236     interface NodeElementFetcher<ElementDefinition> {
237
238         JanusGraphOperationStatus findAllNodeElements(String nodeId, List<ElementDefinition> listTofill);
239     }
240 }