Skip to content

Commit 8382b41

Browse files
refactor parsers structure
1 parent c58eefb commit 8382b41

8 files changed

Lines changed: 705 additions & 523 deletions

File tree

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package org.apache.cloudstack.tosca.parser;
18+
19+
public class ToscaConstants {
20+
public enum TypeOfToscaField {
21+
ATTRIBUTE, PROPERTY
22+
}
23+
24+
public static final String DATA_TYPES_KEY = "data_types";
25+
public static final String NODE_TYPES_KEY = "node_types";
26+
27+
public static final String NODE_TYPES_ATTRIBUTES_KEY = "attributes";
28+
public static final String PROPERTIES_KEY = "properties";
29+
public static final String DEPENDENCY_KEY = "dependency";
30+
public static final String NODE_TEMPLATES_REQUIREMENTS_KEY = "requirements";
31+
32+
public static final String FIELDS_TYPE_KEY = "type";
33+
public static final String FIELDS_REQUIRED_KEY = "required";
34+
public static final String FIELDS_VALIDATION_KEY = "validation";
35+
public static final String FIELDS_DESCRIPTION_KEY = "description";
36+
public static final String FIELDS_ENTRY_SCHEMA_KEY = "entry_schema";
37+
public static final String FIELDS_ENTRY_DEFAULT_VALUE_KEY = "default_value";
38+
39+
public static final String SERVICE_TEMPLATE_TOSCA_VERSION_KEY = "tosca_definitions_version";
40+
public static final String SERVICE_TEMPLATE_DESCRIPTION_KEY = "description";
41+
public static final String SERVICE_TEMPLATE_SERVICE_TEMPLATE_KEY = "service_template";
42+
public static final String SERVICE_TEMPLATE_INPUTS_KEY = "inputs";
43+
public static final String SERVICE_TEMPLATE_NODE_TEMPLATES_KEY = "node_templates";
44+
}
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package org.apache.cloudstack.tosca.parser;
18+
19+
import org.apache.cloudstack.tosca.functions.ToscaBooleanFunctions;
20+
import org.apache.cloudstack.tosca.functions.ToscaFunction;
21+
import org.apache.cloudstack.tosca.model.ToscaAttributeDefinition;
22+
import org.apache.cloudstack.tosca.model.ToscaCollectionType;
23+
import org.apache.cloudstack.tosca.model.ToscaDataTypeDefinition;
24+
import org.apache.cloudstack.tosca.model.ToscaFieldDefinition;
25+
import org.apache.cloudstack.tosca.model.ToscaPrimitiveType;
26+
import org.apache.cloudstack.tosca.model.ToscaPropertyDefinition;
27+
import org.apache.cloudstack.tosca.model.ToscaTypeDefinition;
28+
import org.apache.commons.collections.MapUtils;
29+
import org.apache.commons.lang3.EnumUtils;
30+
import org.apache.logging.log4j.LogManager;
31+
import org.apache.logging.log4j.Logger;
32+
33+
import java.util.List;
34+
import java.util.Map;
35+
import java.util.stream.Collectors;
36+
37+
public class ToscaFieldParser {
38+
private final Logger logger = LogManager.getLogger(ToscaFieldParser.class);
39+
40+
/**
41+
* Parses a field (property or attribute) of a TOSCA resource.
42+
* @param rawFields The body of the field. Example: "{ name: { type: string, description: Name } }"
43+
* @param typeOfToscaField The type of the field that will be parsed.
44+
* @param dataTypes Available data types. If null, then the type of the fields must be a primitive or a collection.
45+
* @return a map of {@link ToscaFieldDefinition} representing the fields, whose key is the name of the field and whose value is the field itself.
46+
*/
47+
protected Map<String, ? extends ToscaFieldDefinition> parseField(Object rawFields, ToscaConstants.TypeOfToscaField typeOfToscaField, Map<String, ToscaDataTypeDefinition> dataTypes) {
48+
Map<String, Object> fields = ToscaYamlHelper.asMap(rawFields);
49+
logger.debug("Parsing the following {}: {}.",
50+
() -> typeOfToscaField == ToscaConstants.TypeOfToscaField.ATTRIBUTE ? "attributes" : "properties", fields::keySet);
51+
52+
return fields.entrySet().stream().map((field) -> {
53+
String name = field.getKey();
54+
Map<String, Object> fieldBody = ToscaYamlHelper.asMap(field.getValue());
55+
String description = ToscaYamlHelper.asString(fieldBody.get(ToscaConstants.FIELDS_DESCRIPTION_KEY));
56+
ToscaTypeDefinition type = parseType(fieldBody, dataTypes);
57+
58+
if (typeOfToscaField == ToscaConstants.TypeOfToscaField.ATTRIBUTE) {
59+
ToscaAttributeDefinition attributeDefinition = new ToscaAttributeDefinition(name, description, type);
60+
logger.debug("Successfully parsed the following attribute: [{}].", attributeDefinition::toString);
61+
return attributeDefinition;
62+
}
63+
64+
boolean required = ToscaYamlHelper.asBoolean(fieldBody.get(ToscaConstants.FIELDS_REQUIRED_KEY));
65+
ToscaFunction.ToscaBooleanFunction validation = parseToscaBooleanFunction(ToscaYamlHelper.asMap(fieldBody.get(ToscaConstants.FIELDS_VALIDATION_KEY)));
66+
ToscaPropertyDefinition propertyDefinition = new ToscaPropertyDefinition(name, description, type, required, validation);
67+
logger.debug("Successfully parsed the following property: [{}].", propertyDefinition::toString);
68+
return propertyDefinition;
69+
}).collect(Collectors.toMap(ToscaFieldDefinition::getName, (field) -> field));
70+
}
71+
72+
/**
73+
* Parses the type of TOSCA resource. Types can be primitive, collection, or data type, and are represented by the {@link ToscaTypeDefinition} class.
74+
* @param typeBody The body of the type. Example: "{ type: list, entry_schema: { type: NodeOffering } }"
75+
* @param dataTypes The available data types. If null, then the type being parsed must be either a primitive or a collection.
76+
* @return a {@link ToscaTypeDefinition} representing the type of the field. Null if the type is not recognized.
77+
*/
78+
protected ToscaTypeDefinition parseType(Map<String, Object> typeBody, Map<String, ToscaDataTypeDefinition> dataTypes) {
79+
String rawType = ToscaYamlHelper.asString(typeBody.get(ToscaConstants.FIELDS_TYPE_KEY));
80+
logger.debug("Parsing the following type: [{}].", rawType);
81+
ToscaPrimitiveType primitiveType = EnumUtils.getEnumIgnoreCase(ToscaPrimitiveType.class, rawType);
82+
if (primitiveType != null) {
83+
logger.debug("The type is a primitive, returning its corresponding ToscaTypeDefinition.");
84+
return ToscaTypeDefinition.ofPrimitive(primitiveType);
85+
}
86+
87+
ToscaCollectionType collectionType = EnumUtils.getEnumIgnoreCase(ToscaCollectionType.class, rawType);
88+
if (collectionType != null) {
89+
logger.debug("The type is a collection, returning its corresponding ToscaTypeDefinition.");
90+
return ToscaTypeDefinition.ofCollection(collectionType, parseType(ToscaYamlHelper.asMap(typeBody.get(ToscaConstants.FIELDS_ENTRY_SCHEMA_KEY)), dataTypes));
91+
}
92+
93+
if (MapUtils.isEmpty(dataTypes) || !dataTypes.containsKey(rawType)) {
94+
logger.debug("The [{}] type is not recognized, returning null.", rawType);
95+
return null;
96+
}
97+
98+
logger.debug("The type is a data type, returning its corresponding ToscaTypeDefinition based in the declared data types: {}.", dataTypes::keySet);
99+
return ToscaTypeDefinition.ofDataType(dataTypes.get(rawType));
100+
}
101+
102+
/**
103+
* Parses a TOSCA boolean ({@link ToscaFunction.ToscaBooleanFunction}) function.
104+
* @param validationBody The body of the validation field. Example: "{ $valid_values: [ $value, [ CloudManaged, ExternalManaged ] ] }")
105+
* @return a {@link ToscaFunction.ToscaBooleanFunction} representing the boolean function. If the function is not recognized, returns null.
106+
*/
107+
protected ToscaFunction.ToscaBooleanFunction parseToscaBooleanFunction(Map<String, Object> validationBody) {
108+
if (MapUtils.isEmpty(validationBody)) {
109+
return null;
110+
}
111+
112+
Map.Entry<String, Object> function = validationBody.entrySet().iterator().next();
113+
String name = function.getKey();
114+
Object arguments = function.getValue();
115+
logger.debug("Parsing the following TOSCA boolean function: [{}].", name);
116+
switch (name) {
117+
case "$valid_values":
118+
return parseValidValuesFunction(arguments);
119+
}
120+
return null;
121+
}
122+
123+
/**
124+
* Parses the $valid_values TOSCA function.
125+
* @param arguments The arguments of the $valid_values function. Example: "{ $valid_values: [ $value, [ CloudManaged, ExternalManaged ] ] }"
126+
* @return a {@link ToscaBooleanFunctions.ValidValues} (typed as {@link ToscaFunction.ToscaBooleanFunction}) representing the $valid_values function.
127+
*/
128+
private ToscaFunction.ToscaBooleanFunction parseValidValuesFunction(Object arguments) {
129+
List<Object> args = (List<Object>) arguments;
130+
List<Object> validValues = (List<Object>) args.get(1);
131+
return new ToscaBooleanFunctions.ValidValues(validValues);
132+
}
133+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package org.apache.cloudstack.tosca.parser;
18+
19+
import org.apache.cloudstack.tosca.model.ToscaAttributeDefinition;
20+
import org.apache.cloudstack.tosca.model.ToscaDataTypeDefinition;
21+
import org.apache.cloudstack.tosca.model.ToscaNodeType;
22+
import org.apache.cloudstack.tosca.model.ToscaPropertyDefinition;
23+
import org.apache.logging.log4j.LogManager;
24+
import org.apache.logging.log4j.Logger;
25+
26+
import javax.inject.Inject;
27+
import java.util.Map;
28+
import java.util.stream.Collectors;
29+
30+
public class ToscaNodeTypeParser {
31+
private final Logger logger = LogManager.getLogger(ToscaNodeTypeParser.class);
32+
33+
private final ToscaFieldParser toscaFieldParser;
34+
35+
@Inject
36+
public ToscaNodeTypeParser(ToscaFieldParser toscaFieldParser) {
37+
this.toscaFieldParser = toscaFieldParser;
38+
}
39+
40+
/**
41+
* Parses a node type definition file.
42+
* @param nodeTypeContent The YAML content of the node type definition file.
43+
* @return a {@link ToscaNodeType} representing the node type.
44+
*/
45+
public ToscaNodeType parseNodeTypeDefinitionFile(String nodeTypeContent) {
46+
Object rawYaml = ToscaYamlHelper.loadYaml(nodeTypeContent);
47+
Map<String, Object> yamlRoot = ToscaYamlHelper.asMap(rawYaml);
48+
Map<String, ToscaDataTypeDefinition> dataTypes = parseDataTypes(yamlRoot);
49+
return parseNodeType(yamlRoot, dataTypes);
50+
}
51+
52+
/**
53+
* Parses all data types defined in the TOSCA file.
54+
* @param yamlRoot The root of the YAML file.
55+
* @return a map of {@link ToscaDataTypeDefinition} representing the data types, whose key is the name of the data type and whose value is the data type itself.
56+
*/
57+
protected Map<String, ToscaDataTypeDefinition> parseDataTypes(Map<String, Object> yamlRoot) {
58+
Map<String, Object> dataTypesRaw = ToscaYamlHelper.asMap(yamlRoot.get(ToscaConstants.DATA_TYPES_KEY));
59+
logger.info("Parsing the following data types: {}.", dataTypesRaw::keySet);
60+
return dataTypesRaw.entrySet().stream().map(dataTypeEntry -> {
61+
String dataTypeName = dataTypeEntry.getKey();
62+
Map<String, Object> dataTypeBody = ToscaYamlHelper.asMap(dataTypeEntry.getValue());
63+
Map<String, ToscaPropertyDefinition> propertyDefinitions = (Map<String, ToscaPropertyDefinition>) toscaFieldParser.parseField(dataTypeBody.get(ToscaConstants.PROPERTIES_KEY), ToscaConstants.TypeOfToscaField.PROPERTY, null);
64+
return new ToscaDataTypeDefinition(dataTypeName, propertyDefinitions);
65+
}).collect(Collectors.toMap(ToscaDataTypeDefinition::getName, (dataType) -> dataType));
66+
}
67+
68+
/**
69+
* Parses a node type definition.
70+
* @param yamlRoot The root of the YAML node type definition file.
71+
* @param dataTypes Available data types.
72+
* @return a {@link ToscaNodeType} representing the node type.
73+
*/
74+
protected ToscaNodeType parseNodeType(Map<String, Object> yamlRoot, Map<String, ToscaDataTypeDefinition> dataTypes) {
75+
Map.Entry<String, Object> nodeTypeRaw = ToscaYamlHelper.asMap(yamlRoot.get(ToscaConstants.NODE_TYPES_KEY)).entrySet().iterator().next();
76+
String nodeTypeName = nodeTypeRaw.getKey();
77+
logger.info("Parsing the following node type: [{}].", nodeTypeName);
78+
Map<String, Object> nodeTypeBody = ToscaYamlHelper.asMap(nodeTypeRaw.getValue());
79+
Map<String, ToscaPropertyDefinition> propertyDefinitions = (Map<String, ToscaPropertyDefinition>) toscaFieldParser.parseField(nodeTypeBody.get(ToscaConstants.PROPERTIES_KEY), ToscaConstants.TypeOfToscaField.PROPERTY, dataTypes);
80+
Map<String, ToscaAttributeDefinition> attributeDefinitions = (Map<String, ToscaAttributeDefinition>) toscaFieldParser.parseField(nodeTypeBody.get(ToscaConstants.NODE_TYPES_ATTRIBUTES_KEY), ToscaConstants.TypeOfToscaField.ATTRIBUTE, dataTypes);
81+
ToscaNodeType nodeType = new ToscaNodeType(nodeTypeName, propertyDefinitions, attributeDefinitions);
82+
logger.info("Successfully parsed the following node type: [{}].", nodeType::toString);
83+
return nodeType;
84+
}
85+
}

0 commit comments

Comments
 (0)