2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2019 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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
21 package org.onap.sdc.toscaparser.api;
23 import com.google.common.collect.Lists;
24 import org.onap.sdc.toscaparser.api.elements.constraints.Constraint;
25 import org.onap.sdc.toscaparser.api.elements.constraints.Schema;
26 import org.onap.sdc.toscaparser.api.functions.Function;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
30 import java.util.ArrayList;
31 import java.util.Collections;
32 import java.util.LinkedHashMap;
33 import java.util.List;
35 import java.util.Objects;
36 import java.util.stream.Collectors;
38 public class Property {
39 // TOSCA built-in Property type
40 private static final Logger LOGGER = LoggerFactory.getLogger(Property.class.getName());
42 private static final String TYPE = "type";
43 private static final String REQUIRED = "required";
44 private static final String DESCRIPTION = "description";
45 private static final String DEFAULT = "default";
46 private static final String CONSTRAINTS = "constraints";
47 private static String entrySchema = "entry_schema";
48 private static String dataType = "datatypes";
50 private static final String[] PROPERTY_KEYS = {
51 TYPE, REQUIRED, DESCRIPTION, DEFAULT, CONSTRAINTS};
53 private static final String ENTRYTYPE = "type";
54 private static final String ENTRYPROPERTIES = "properties";
55 private static final String PATH_DELIMITER = "#";
56 private static final String[] ENTRY_SCHEMA_KEYS = {
57 ENTRYTYPE, ENTRYPROPERTIES};
61 private Schema schema;
62 private LinkedHashMap<String, Object> customDef;
64 public Property(Map.Entry<String, Object> propertyEntry) {
65 name = propertyEntry.getKey();
66 value = propertyEntry.getValue();
69 public Property(String propname,
71 LinkedHashMap<String, Object> propschemaDict,
72 LinkedHashMap<String, Object> propcustomDef) {
76 customDef = propcustomDef;
77 schema = new Schema(propname, propschemaDict);
80 public String getType() {
81 return schema.getType();
84 public boolean isRequired() {
85 return schema.isRequired();
88 public String getDescription() {
89 return schema.getDescription();
92 public Object getDefault() {
93 return schema.getDefault();
96 public ArrayList<Constraint> getConstraints() {
97 return schema.getConstraints();
100 public LinkedHashMap<String, Object> getEntrySchema() {
101 return schema.getEntrySchema();
105 public String getName() {
109 public Object getValue() {
114 public Object setValue(Object vob) {
119 public void validate() {
120 // Validate if not a reference property
121 if (!Function.isFunction(value)) {
122 if (getType().equals(Schema.STRING)) {
123 value = value.toString();
125 value = DataEntity.validateDatatype(getType(), value,
129 validateConstraints();
133 private void validateConstraints() {
134 if (getConstraints() != null) {
135 for (Constraint constraint : getConstraints()) {
136 constraint.validate(value);
142 public String toString() {
144 + "name='" + name + '\''
146 + ", schema=" + schema
147 + ", customDef=" + customDef
152 * Retrieves property value as list of strings if<br>
153 * - the value is simple<br>
154 * - the value is list of simple values<br>
155 * - the provided path refers to a simple property inside a data type<br>
157 * @param propertyPath valid name of property for search.<br>
158 * If a name refers to a simple field inside a datatype, the property name should be defined with # delimiter.<br>
159 * @return List of property values. If not found, empty list will be returned.<br>
160 * If property value is a list either of simple fields or of simple fields inside a datatype, all values from the list should be returned
162 public List<String> getLeafPropertyValue(String propertyPath) {
163 List<String> propertyValueList = Collections.emptyList();
165 if (LOGGER.isDebugEnabled()) {
166 LOGGER.debug("getLeafPropertyValue=> A new request: propertyPath: {}, value: {}", propertyPath, getValue());
168 if (propertyPath == null || getValue() == null
169 //if entry_schema disappears, it is datatype,
170 // otherwise it is map of simple types - should be ignored
171 || isValueMapOfSimpleTypes()) {
172 LOGGER.error("It is a wrong request - ignoring! propertyPath: {}, value: {}", propertyPath, getValue());
173 return propertyValueList;
175 String[] path = propertyPath.split(PATH_DELIMITER);
177 if (Schema.isRequestedTypeSimple(getPropertyTypeByPath(path))) {
178 //the internal property type in the path is either simple or list of simple types
179 if (isValueInsideDataType()) {
180 if (LOGGER.isDebugEnabled()) {
181 LOGGER.debug("The requested is an internal simple property inside of a data type");
183 //requested value is an internal simple property inside of a data type
184 propertyValueList = getSimplePropertyValueForComplexType(path);
186 if (LOGGER.isDebugEnabled()) {
187 LOGGER.debug("The requested property has simple type or list of simple types");
189 //the requested property is simple type or list of simple types
190 propertyValueList = getSimplePropertyValueForSimpleType();
193 return propertyValueList;
196 private boolean isValueMapOfSimpleTypes() {
197 if (getValue() instanceof Map && getEntrySchema() != null) {
198 LOGGER.warn("This property value is a map of simple types");
204 private boolean isValueInsideDataType() {
205 //value is either a list of values for data type
207 return (Schema.LIST.equals(getType()) && isDataTypeInEntrySchema())
208 || (getEntrySchema() == null && getType().contains(dataType));
211 private Object getSimpleValueFromComplexObject(Object current, String[] path) {
212 if (current == null) {
217 if (path.length > index) {
218 for (int i = index; i < path.length; i++) {
219 if (current instanceof Map) {
220 current = ((Map<String, Object>) current).get(path[i]);
221 } else if (current instanceof List) {
222 current = ((List) current).get(0);
229 if (current != null) {
235 private List<String> getSimplePropertyValueForSimpleType() {
236 if (getValue() instanceof List || getValue() instanceof Map) {
237 return getSimplePropertyValueForComplexType(null);
239 return Lists.newArrayList(String.valueOf(value));
242 private List<String> getSimplePropertyValueForComplexType(String[] path) {
243 if (getValue() instanceof List) {
244 return ((List<Object>) getValue()).stream()
247 return getSimpleValueFromComplexObject(v, path);
252 //it might be null when get_input can't be resolved
254 // - get_input has two parameters: 1. list and 2. index in this list
255 //and list has no value
256 // - neither value no default is defined for get_input
257 .filter(Objects::nonNull)
258 .map(String::valueOf)
259 .collect(Collectors.toList());
262 List<String> valueList = Lists.newArrayList();
263 String valueString = String.valueOf(getSimpleValueFromComplexObject(getValue(), path));
264 if (Objects.nonNull(valueString)) {
265 valueList.add(valueString);
270 private String getPropertyTypeByPath(String[] path) {
271 String propertyType = calculatePropertyType();
273 if (path.length > 0 && !path[0].isEmpty()) {
274 return getInternalPropertyType(propertyType, path, 0);
279 private String calculatePropertyType() {
280 String propertyType = getType();
281 if (Schema.LIST.equals(propertyType)) {
282 //if it is list, return entry schema type
283 return (String) getEntrySchema().get(ENTRYTYPE);
288 private String calculatePropertyType(LinkedHashMap<String, Object> property) {
289 String type = (String) property.get(TYPE);
290 if (Schema.LIST.equals(type)) {
291 //it might be a data type
292 return getEntrySchemaType(property);
297 private String getInternalPropertyType(String dataTypeName, String[] path, int index) {
298 if (path.length > index) {
299 LinkedHashMap<String, Object> complexProperty = (LinkedHashMap<String, Object>) customDef.get(dataTypeName);
300 if (complexProperty != null) {
301 LinkedHashMap<String, Object> dataTypeProperties = (LinkedHashMap<String, Object>) complexProperty.get(ENTRYPROPERTIES);
302 return getPropertyTypeFromCustomDefDeeply(path, index, dataTypeProperties);
305 //stop searching - seems as wrong flow: the path is finished but the value is not found yet
309 private String getEntrySchemaType(LinkedHashMap<String, Object> property) {
310 LinkedHashMap<String, Object> entrySchema = (LinkedHashMap<String, Object>) property.get(Property.entrySchema);
311 if (entrySchema != null) {
312 return (String) entrySchema.get(TYPE);
317 private String getPropertyTypeFromCustomDefDeeply(String[] path, int index, LinkedHashMap<String, Object> properties) {
318 if (properties != null) {
319 LinkedHashMap<String, Object> foundProperty = (LinkedHashMap<String, Object>) (properties).get(path[index]);
320 if (foundProperty != null) {
321 String propertyType = calculatePropertyType(foundProperty);
322 if (propertyType == null || index == path.length - 1) {
325 return getInternalPropertyType(propertyType, path, index + 1);
331 private boolean isDataTypeInEntrySchema() {
332 String entrySchemaType = (String) getEntrySchema().get(ENTRYTYPE);
333 return entrySchemaType != null && entrySchemaType.contains(dataType);
341 class Property(object):
342 '''TOSCA built-in Property type.'''
345 TYPE, REQUIRED, DESCRIPTION, DEFAULT, CONSTRAINTS
347 'type', 'required', 'description', 'default', 'constraints'
350 ENTRY_SCHEMA_KEYS = (
351 ENTRYTYPE, ENTRYPROPERTIES
356 def __init__(self, property_name, value, schema_dict, custom_def=None):
357 self.name = property_name
359 self.custom_def = custom_def
360 self.schema = Schema(property_name, schema_dict)
364 return self.schema.type
368 return self.schema.required
371 def description(self):
372 return self.schema.description
376 return self.schema.default
379 def constraints(self):
380 return self.schema.constraints
383 def entry_schema(self):
384 return self.schema.entry_schema
387 '''Validate if not a reference property.'''
388 if not is_function(self.value):
389 if self.type == Schema.STRING:
390 self.value = str(self.value)
391 self.value = DataEntity.validate_datatype(self.type, self.value,
395 self._validate_constraints()
397 def _validate_constraints(self):
399 for constraint in self.constraints:
400 constraint.validate(self.value)