From a1f9e908f1b29b3cc8c434bb3ca455196a0959bc Mon Sep 17 00:00:00 2001 From: "Sheshukov, Natalia (ns019t)" Date: Sun, 15 Apr 2018 13:11:15 +0300 Subject: JTosca Parser – support Annotations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I256e42e5f4a6e5259c17b8de56d64b44afb7f42d Issue-ID: SDC-1223 Signed-off-by: Sheshukov, Natalia (ns019t) --- .../org/onap/sdc/toscaparser/api/Property.java | 7 + .../onap/sdc/toscaparser/api/ToscaTemplate.java | 57 ++++---- .../api/elements/enums/ToscaElementNames.java | 20 +++ .../sdc/toscaparser/api/parameters/Annotation.java | 76 +++++++++++ .../onap/sdc/toscaparser/api/parameters/Input.java | 122 +++++------------ .../onap/sdc/toscaparser/api/JToscaImportTest.java | 147 ++++++++++++++------- .../csars/service-AdiodVmxVpeBvService-csar.csar | Bin 0 -> 117439 bytes 7 files changed, 270 insertions(+), 159 deletions(-) create mode 100644 src/main/java/org/onap/sdc/toscaparser/api/elements/enums/ToscaElementNames.java create mode 100644 src/main/java/org/onap/sdc/toscaparser/api/parameters/Annotation.java create mode 100644 src/test/resources/csars/service-AdiodVmxVpeBvService-csar.csar diff --git a/src/main/java/org/onap/sdc/toscaparser/api/Property.java b/src/main/java/org/onap/sdc/toscaparser/api/Property.java index 227da0a..6d05af0 100644 --- a/src/main/java/org/onap/sdc/toscaparser/api/Property.java +++ b/src/main/java/org/onap/sdc/toscaparser/api/Property.java @@ -2,7 +2,10 @@ package org.onap.sdc.toscaparser.api; import java.util.ArrayList; import java.util.LinkedHashMap; +import java.util.Map; +import org.onap.sdc.toscaparser.api.elements.PropertyDef; +import org.onap.sdc.toscaparser.api.elements.StatefulEntityType; import org.onap.sdc.toscaparser.api.elements.constraints.Constraint; import org.onap.sdc.toscaparser.api.elements.constraints.Schema; import org.onap.sdc.toscaparser.api.functions.Function; @@ -29,6 +32,10 @@ public class Property { private Schema schema; private LinkedHashMap customDef; + public Property(Map.Entry propertyEntry){ + name = propertyEntry.getKey(); + value = propertyEntry.getValue(); + } public Property(String propname, Object propvalue, LinkedHashMap propschemaDict, diff --git a/src/main/java/org/onap/sdc/toscaparser/api/ToscaTemplate.java b/src/main/java/org/onap/sdc/toscaparser/api/ToscaTemplate.java index ea76a09..bfd0716 100644 --- a/src/main/java/org/onap/sdc/toscaparser/api/ToscaTemplate.java +++ b/src/main/java/org/onap/sdc/toscaparser/api/ToscaTemplate.java @@ -1,28 +1,34 @@ package org.onap.sdc.toscaparser.api; -import org.onap.sdc.toscaparser.api.common.JToscaValidationIssue; -import org.onap.sdc.toscaparser.api.common.ValidationIssueCollector; -import org.onap.sdc.toscaparser.api.parameters.Output; -import org.onap.sdc.toscaparser.api.utils.ThreadLocalsHolder; - import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; import java.nio.file.Files; -import java.util.function.Predicate; import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Predicate; import org.onap.sdc.toscaparser.api.common.JToscaException; +import org.onap.sdc.toscaparser.api.common.JToscaValidationIssue; +import org.onap.sdc.toscaparser.api.common.ValidationIssueCollector; import org.onap.sdc.toscaparser.api.elements.EntityType; import org.onap.sdc.toscaparser.api.elements.Metadata; import org.onap.sdc.toscaparser.api.extensions.ExtTools; import org.onap.sdc.toscaparser.api.parameters.Input; +import org.onap.sdc.toscaparser.api.parameters.Output; import org.onap.sdc.toscaparser.api.prereq.CSAR; import org.onap.sdc.toscaparser.api.utils.JToscaErrorCodes; +import org.onap.sdc.toscaparser.api.utils.ThreadLocalsHolder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.yaml.snakeyaml.Yaml; @@ -281,10 +287,12 @@ public class ToscaTemplate extends Object { return (String)tpl.get(DESCRIPTION); } + @SuppressWarnings("unchecked") private ArrayList _tplImports() { return (ArrayList)tpl.get(IMPORTS); } + @SuppressWarnings("unchecked") private ArrayList _tplRepositories() { LinkedHashMap repositories = (LinkedHashMap)tpl.get(REPOSITORIES); @@ -302,11 +310,6 @@ public class ToscaTemplate extends Object { return (LinkedHashMap)_getCustomTypes(RELATIONSHIP_TYPES,null); } - @SuppressWarnings("unchecked") - private LinkedHashMap _tplRelationshipTemplates() { - return (LinkedHashMap)_tplTopologyTemplate().get(RELATIONSHIP_TEMPLATES); - } - @SuppressWarnings("unchecked") private LinkedHashMap _tplTopologyTemplate() { return (LinkedHashMap)tpl.get(TOPOLOGY_TEMPLATE); @@ -332,6 +335,7 @@ public class ToscaTemplate extends Object { * @param alImports all imports which needs to be processed * @return the linked hash map containing all import definitions */ + @SuppressWarnings("unchecked") private LinkedHashMap _getAllCustomDefs(Object alImports) { String types[] = { @@ -346,7 +350,7 @@ public class ToscaTemplate extends Object { imports = sortImports(imports); for (Map map : imports) { - List> singleImportList = new ArrayList(); + List> singleImportList = new ArrayList<>(); singleImportList.add(map); Map importNameDetails = getValidFileNameForImportReference(singleImportList); @@ -398,7 +402,7 @@ public class ToscaTemplate extends Object { List> finalList2 = new ArrayList<>(); Iterator> itr = customImports.iterator(); while(itr.hasNext()) { - Map innerMap = itr.next(); + Map innerMap = itr.next(); if (innerMap.toString().contains("../")) { finalList2.add(innerMap); itr.remove(); @@ -451,8 +455,7 @@ public class ToscaTemplate extends Object { * @param customImports the custom imports * @return the map containing import file full and relative paths */ - private Map getValidFileNameForImportReference(List> - customImports){ + private Map getValidFileNameForImportReference(List> customImports){ String importFileName; Map retMap = new HashMap<>(); for (Map map1 : customImports) { @@ -575,6 +578,7 @@ public class ToscaTemplate extends Object { } // multi level nesting - RECURSIVE + @SuppressWarnings("unchecked") private void _handleNestedToscaTemplatesWithTopology(TopologyTemplate tt) { if(++nestingLoopCounter > 10) { log.error("ToscaTemplate - _handleNestedToscaTemplatesWithTopology - Nested Topologies Loop: too many levels, aborting"); @@ -583,7 +587,6 @@ public class ToscaTemplate extends Object { // Reset Processed Imports for nested templates this.processedImports = new HashSet<>(); for(Map.Entry me: nestedToscaTplsWithTopology.entrySet()) { - String fname = me.getKey(); LinkedHashMap toscaTpl = (LinkedHashMap)me.getValue(); for(NodeTemplate nt: tt.getNodeTemplates()) { @@ -761,6 +764,9 @@ public class ToscaTemplate extends Object { } public ArrayList getInputs() { + if(inputs != null){ + inputs.stream().forEach(Input::resetAnnotaions); + } return inputs; } @@ -821,6 +827,7 @@ public class ToscaTemplate extends Object { return pparams; } + @SuppressWarnings("unchecked") private String getSubMappingNodeType(LinkedHashMap toscaTpl) { // Return substitution mappings node type if(toscaTpl != null) { @@ -830,12 +837,6 @@ public class ToscaTemplate extends Object { return null; } - private boolean _hasSubstitutionMapping() { - // Return True if the template has valid substitution mappings - return topologyTemplate != null && - topologyTemplate.getSubstitutionMappings() != null; - } - public boolean hasNestedTemplates() { // Return True if the tosca template has nested templates return nestedToscaTemplatesWithTopology != null && @@ -881,6 +882,14 @@ public class ToscaTemplate extends Object { ", nestingLoopCounter=" + nestingLoopCounter + '}'; } + + public List getInputs(boolean annotationsRequired) { + if(inputs != null && annotationsRequired){ + inputs.stream().forEach(Input::parseAnnotations); + return inputs; + } + return getInputs(); + } } /*python diff --git a/src/main/java/org/onap/sdc/toscaparser/api/elements/enums/ToscaElementNames.java b/src/main/java/org/onap/sdc/toscaparser/api/elements/enums/ToscaElementNames.java new file mode 100644 index 0000000..0ee201c --- /dev/null +++ b/src/main/java/org/onap/sdc/toscaparser/api/elements/enums/ToscaElementNames.java @@ -0,0 +1,20 @@ +package org.onap.sdc.toscaparser.api.elements.enums; + +public enum ToscaElementNames { + + TYPE ("type"), + PROPERTIES ("properties"), + ANNOTATIONS ("annotations"), + SOURCE_TYPE ("source_type"); + + private String name; + + ToscaElementNames(String name){ + this.name = name; + } + + public String getName() { + return name; + } + +} diff --git a/src/main/java/org/onap/sdc/toscaparser/api/parameters/Annotation.java b/src/main/java/org/onap/sdc/toscaparser/api/parameters/Annotation.java new file mode 100644 index 0000000..74b738f --- /dev/null +++ b/src/main/java/org/onap/sdc/toscaparser/api/parameters/Annotation.java @@ -0,0 +1,76 @@ +package org.onap.sdc.toscaparser.api.parameters; + +import java.util.ArrayList; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +import org.onap.sdc.toscaparser.api.Property; +import org.onap.sdc.toscaparser.api.elements.enums.ToscaElementNames; + +public class Annotation{ + + private final static String HEAT = "HEAT"; + + private String name; + private String type; + private ArrayList properties; + + public Annotation(){} + @SuppressWarnings("unchecked") + public Annotation(Map.Entry annotationEntry){ + if(annotationEntry != null){ + name = annotationEntry.getKey(); + Map annValue = (Map) annotationEntry.getValue(); + type = (String) annValue.get(ToscaElementNames.TYPE.getName()); + properties = fetchProperties((Map) annValue.get(ToscaElementNames.PROPERTIES.getName())); + } + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public ArrayList getProperties() { + return properties; + } + + public void setProperties(ArrayList properties) { + this.properties = properties; + } + + private ArrayList fetchProperties(Map properties) { + if(properties != null){ + return (ArrayList) properties.entrySet().stream() + .map(Property::new) + .collect(Collectors.toList()); + } + return null; + } + + public boolean isHeatSourceType(){ + if(properties == null){ + return false; + } + Optional sourceType = properties.stream() + .filter(p -> p.getName().equals(ToscaElementNames.SOURCE_TYPE.getName())) + .findFirst(); + if(!sourceType.isPresent()){ + return false; + } + return sourceType.get().getValue() != null && ((String)sourceType.get().getValue()).equals(HEAT); + } + +} diff --git a/src/main/java/org/onap/sdc/toscaparser/api/parameters/Input.java b/src/main/java/org/onap/sdc/toscaparser/api/parameters/Input.java index 7e83cfb..e7a1246 100644 --- a/src/main/java/org/onap/sdc/toscaparser/api/parameters/Input.java +++ b/src/main/java/org/onap/sdc/toscaparser/api/parameters/Input.java @@ -1,16 +1,18 @@ package org.onap.sdc.toscaparser.api.parameters; -import org.onap.sdc.toscaparser.api.DataEntity; -import org.onap.sdc.toscaparser.api.common.JToscaValidationIssue; -import org.onap.sdc.toscaparser.api.utils.ThreadLocalsHolder; - import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedHashMap; +import java.util.Map; +import java.util.stream.Collectors; +import org.onap.sdc.toscaparser.api.DataEntity; +import org.onap.sdc.toscaparser.api.common.JToscaValidationIssue; import org.onap.sdc.toscaparser.api.elements.EntityType; import org.onap.sdc.toscaparser.api.elements.constraints.Constraint; import org.onap.sdc.toscaparser.api.elements.constraints.Schema; +import org.onap.sdc.toscaparser.api.elements.enums.ToscaElementNames; +import org.onap.sdc.toscaparser.api.utils.ThreadLocalsHolder; public class Input { @@ -41,6 +43,7 @@ public class Input { private String name; private Schema schema; private LinkedHashMap customDefs; + private Map annotations; public Input(){ /** @@ -53,7 +56,20 @@ public class Input { schema = new Schema(_name,_schemaDict); customDefs = _customDefs; } - + + @SuppressWarnings("unchecked") + public void parseAnnotations() { + if(schema.getSchema() != null){ + LinkedHashMap annotations = (LinkedHashMap) schema.getSchema().get(ToscaElementNames.ANNOTATIONS.getName()); + if(annotations != null){ + setAnnotations(annotations.entrySet().stream() + .map(Annotation::new) + .filter(Annotation::isHeatSourceType) + .collect(Collectors.toMap(a -> a.getName(), a -> a))); + } + } + } + public String getName() { return name; } @@ -124,7 +140,8 @@ public class Input { } } - private void _validateValue(Object value) { + @SuppressWarnings("unchecked") + private void _validateValue(Object value) { Object datatype = null; if(EntityType.TOSCA_DEF.get(getType()) != null) { datatype = EntityType.TOSCA_DEF.get(getType()); @@ -147,87 +164,16 @@ public class Input { DataEntity.validateDatatype(getType(), value, null, (LinkedHashMap)datatype, null); } -} - -/*python - -from toscaparser.common.exception import ValidationIssueCollector -from toscaparser.common.exception import MissingRequiredFieldError -from toscaparser.common.exception import UnknownFieldError -from toscaparser.dataentity import DataEntity -from toscaparser.elements.constraints import Schema -from toscaparser.elements.entity_type import EntityType -from toscaparser.utils.gettextutils import _ - - -log = logging.getLogger('tosca') - -class Input(object): - - INPUTFIELD = (TYPE, DESCRIPTION, DEFAULT, CONSTRAINTS, REQUIRED, STATUS, - ENTRY_SCHEMA) = ('type', 'description', 'default', - 'constraints', 'required', 'status', - 'entry_schema') - - def __init__(self, name, schema_dict): - self.name = name - self.schema = Schema(name, schema_dict) - - self._validate_field() - self.validate_type(self.type) - - @property - def type(self): - return self.schema.type - - @property - def required(self): - return self.schema.required - - @property - def description(self): - return self.schema.description - - @property - def default(self): - return self.schema.default - - @property - def constraints(self): - return self.schema.constraints - - @property - def status(self): - return self.schema.status - - def validate(self, value=None): - if value is not None: - self._validate_value(value) - - def _validate_field(self): - for name in self.schema.schema: - if name not in self.INPUTFIELD: - ValidationIssueCollector.appendException( - UnknownFieldError(what='Input "%s"' % self.name, - field=name)) - - def validate_type(self, input_type): - if input_type not in Schema.PROPERTY_TYPES: - ValidationIssueCollector.appendException( - ValueError(_('Invalid type "%s".') % type)) - - # tODO(anyone) Need to test for any built-in datatype not just network - # that is, tosca.datatypes.* and not assume tosca.datatypes.network.* - # tODO(anyone) Add support for tosca.datatypes.Credential - def _validate_value(self, value): - tosca = EntityType.TOSCA_DEF - datatype = None - if self.type in tosca: - datatype = tosca[self.type] - elif EntityType.DATATYPE_NETWORK_PREFIX + self.type in tosca: - datatype = tosca[EntityType.DATATYPE_NETWORK_PREFIX + self.type] - - DataEntity.validate_datatype(self.type, value, None, datatype) + public Map getAnnotations() { + return annotations; + } -*/ + private void setAnnotations(Map annotations) { + this.annotations = annotations; + } + + public void resetAnnotaions(){ + annotations = null; + } +} diff --git a/src/test/java/org/onap/sdc/toscaparser/api/JToscaImportTest.java b/src/test/java/org/onap/sdc/toscaparser/api/JToscaImportTest.java index 589e47c..7d0c54c 100644 --- a/src/test/java/org/onap/sdc/toscaparser/api/JToscaImportTest.java +++ b/src/test/java/org/onap/sdc/toscaparser/api/JToscaImportTest.java @@ -2,63 +2,116 @@ package org.onap.sdc.toscaparser.api; import org.junit.Test; import org.onap.sdc.toscaparser.api.common.JToscaException; +import org.onap.sdc.toscaparser.api.parameters.Annotation; +import org.onap.sdc.toscaparser.api.parameters.Input; import org.onap.sdc.toscaparser.api.utils.ThreadLocalsHolder; import java.io.File; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; public class JToscaImportTest { - @Test - public void testNoMissingTypeValidationError() throws JToscaException { - String fileStr = JToscaImportTest.class.getClassLoader().getResource - ("csars/sdc-onboarding_csar.csar").getFile(); - File file = new File(fileStr); - new ToscaTemplate(file.getAbsolutePath(), null, true, null); - List missingTypeErrors = ThreadLocalsHolder.getCollector() - .getValidationIssueReport() - .stream() - .filter(s -> s.contains("JE136")) - .collect(Collectors.toList()); - assertEquals(0, missingTypeErrors.size()); - } - - @Test - public void testNoStackOverFlowError() { - Exception jte = null; - try { - String fileStr = JToscaImportTest.class.getClassLoader().getResource - ("csars/sdc-onboarding_csar.csar").getFile(); - File file = new File(fileStr); - new ToscaTemplate(file.getAbsolutePath(), null, true, null); - } catch (Exception e){ - jte = e; - } - assertEquals(null, jte); - } - - @Test - public void testNoInvalidImports() throws JToscaException { - List fileNames = new ArrayList<>(); - fileNames.add("csars/tmpCSAR_Huawei_vSPGW_fixed.csar"); - fileNames.add("csars/sdc-onboarding_csar.csar"); - fileNames.add("csars/resource-Spgw-csar-ZTE.csar"); - - for (String fileName : fileNames) { - String fileStr = JToscaImportTest.class.getClassLoader().getResource(fileName).getFile(); - File file = new File(fileStr); - new ToscaTemplate(file.getAbsolutePath(), null, true, null); - List invalidImportErrors = ThreadLocalsHolder.getCollector() - .getValidationIssueReport() - .stream() - .filter(s -> s.contains("JE195")) - .collect(Collectors.toList()); - assertEquals(0, invalidImportErrors.size()); - } - } + @Test + public void testNoMissingTypeValidationError() throws JToscaException { + String fileStr = JToscaImportTest.class.getClassLoader().getResource("csars/sdc-onboarding_csar.csar") + .getFile(); + File file = new File(fileStr); + new ToscaTemplate(file.getAbsolutePath(), null, true, null); + List missingTypeErrors = ThreadLocalsHolder.getCollector().getValidationIssueReport().stream() + .filter(s -> s.contains("JE136")).collect(Collectors.toList()); + assertEquals(0, missingTypeErrors.size()); + } + + @Test + public void testNoStackOverFlowError() { + Exception jte = null; + try { + String fileStr = JToscaImportTest.class.getClassLoader().getResource("csars/sdc-onboarding_csar.csar") + .getFile(); + File file = new File(fileStr); + new ToscaTemplate(file.getAbsolutePath(), null, true, null); + } catch (Exception e) { + jte = e; + } + assertEquals(null, jte); + } + + @Test + public void testNoInvalidImports() throws JToscaException { + List fileNames = new ArrayList<>(); + fileNames.add("csars/tmpCSAR_Huawei_vSPGW_fixed.csar"); + fileNames.add("csars/sdc-onboarding_csar.csar"); + fileNames.add("csars/resource-Spgw-csar-ZTE.csar"); + + for (String fileName : fileNames) { + String fileStr = JToscaImportTest.class.getClassLoader().getResource(fileName).getFile(); + File file = new File(fileStr); + new ToscaTemplate(file.getAbsolutePath(), null, true, null); + List invalidImportErrors = ThreadLocalsHolder.getCollector().getValidationIssueReport().stream() + .filter(s -> s.contains("JE195")).collect(Collectors.toList()); + assertEquals(0, invalidImportErrors.size()); + } + } + + @Test + public void testParseAnnotations() throws JToscaException { + + String fileStr = JToscaImportTest.class.getClassLoader().getResource("csars/service-AdiodVmxVpeBvService-csar.csar").getFile(); + File file = new File(fileStr); + ToscaTemplate toscaTemplate = new ToscaTemplate(file.getAbsolutePath(), null, true, null); + + List inputs = toscaTemplate.getInputs(); + assertNotNull(inputs); + assertTrue(inputs.stream().filter(i -> i.getAnnotations() != null).collect(Collectors.toList()).isEmpty()); + + inputs.forEach(Input::parseAnnotations); + assertTrue(!inputs.stream().filter(i -> i.getAnnotations() != null).collect(Collectors.toList()).isEmpty()); + } + + @Test + public void testGetInputsWithAndWithoutAnnotations() throws JToscaException { + + String fileStr = JToscaImportTest.class.getClassLoader().getResource("csars/service-AdiodVmxVpeBvService-csar.csar").getFile(); + File file = new File(fileStr); + ToscaTemplate toscaTemplate = new ToscaTemplate(file.getAbsolutePath(), null, true, null); + List inputs = toscaTemplate.getInputs(); + assertNotNull(inputs); + assertTrue(inputs.stream().filter(i -> i.getAnnotations() != null).collect(Collectors.toList()).isEmpty()); + + inputs = toscaTemplate.getInputs(true); + assertNotNull(inputs); + validateInputsAnnotations(inputs); + + inputs = toscaTemplate.getInputs(false); + assertNotNull(inputs); + assertTrue(inputs.stream().filter(i -> i.getAnnotations() != null).collect(Collectors.toList()).isEmpty()); + } + + private void validateInputsAnnotations(List inputs) { + List inputsWithAnnotations = inputs.stream().filter(i -> i.getAnnotations() != null) + .collect(Collectors.toList()); + assertTrue(!inputs.isEmpty()); + inputsWithAnnotations.stream().forEach(i -> validateAnnotations(i)); + } + + private void validateAnnotations(Input input) { + assertNotNull(input.getAnnotations()); + assertEquals(input.getAnnotations().size(), 1); + Annotation annotation = input.getAnnotations().get("source"); + assertEquals(annotation.getName(), "source"); + assertEquals(annotation.getType().toLowerCase(), "org.openecomp.annotations.source"); + assertNotNull(annotation.getProperties()); + Optional source_type = annotation.getProperties().stream() + .filter(p -> p.getName().equals("source_type")).findFirst(); + assertTrue(source_type.isPresent()); + assertEquals(source_type.get().getValue(), "HEAT"); + } } diff --git a/src/test/resources/csars/service-AdiodVmxVpeBvService-csar.csar b/src/test/resources/csars/service-AdiodVmxVpeBvService-csar.csar new file mode 100644 index 0000000..28aa6f4 Binary files /dev/null and b/src/test/resources/csars/service-AdiodVmxVpeBvService-csar.csar differ -- cgit 1.2.3-korg