diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/MetadataParser.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/MetadataParser.java index d4f5d1c23..873be7d56 100644 --- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/MetadataParser.java +++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/MetadataParser.java @@ -100,6 +100,7 @@ public class MetadataParser { private ReferenceResolver referenceResolver = new DefaultReferenceResolver(); private boolean useLocalCoreVocabularies = true; private boolean implicitlyLoadCoreVocabularies = false; + private boolean recusivelyLoadReferences = false; /** * Avoid reading the annotations in the $metadata @@ -131,6 +132,16 @@ public class MetadataParser { return this; } + /** + * Load the core libraries from local classpath + * @param load true for yes; false otherwise + * @return + */ + public MetadataParser recursivelyLoadReferences(boolean load) { + this.recusivelyLoadReferences = load; + return this; + } + /** * Load the core vocabularies, irrespective of if they are defined in the $metadata * @param load @@ -143,7 +154,7 @@ public class MetadataParser { public ServiceMetadata buildServiceMetadata(Reader csdl) throws XMLStreamException { SchemaBasedEdmProvider provider = buildEdmProvider(csdl, this.referenceResolver, - this.implicitlyLoadCoreVocabularies, this.useLocalCoreVocabularies); + this.implicitlyLoadCoreVocabularies, this.useLocalCoreVocabularies, true); return new ServiceMetadataImpl(provider, provider.getReferences(), null); } @@ -151,27 +162,27 @@ public class MetadataParser { XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance(); XMLEventReader reader = xmlInputFactory.createXMLEventReader(csdl); return buildEdmProvider(reader, this.referenceResolver, - this.implicitlyLoadCoreVocabularies, this.useLocalCoreVocabularies); + this.implicitlyLoadCoreVocabularies, this.useLocalCoreVocabularies, true); } protected SchemaBasedEdmProvider buildEdmProvider(Reader csdl, - ReferenceResolver resolver, boolean loadCore, boolean useLocal) + ReferenceResolver resolver, boolean loadCore, boolean useLocal, boolean loadReferenceSchemas) throws XMLStreamException { XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance(); XMLEventReader reader = xmlInputFactory.createXMLEventReader(csdl); - return buildEdmProvider(reader, resolver, loadCore, useLocal); + return buildEdmProvider(reader, resolver, loadCore, useLocal, loadReferenceSchemas); } protected SchemaBasedEdmProvider buildEdmProvider(InputStream csdl, - ReferenceResolver resolver, boolean loadCore, boolean useLocal) + ReferenceResolver resolver, boolean loadCore, boolean useLocal, boolean loadReferenceSchemas) throws XMLStreamException { XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance(); XMLEventReader reader = xmlInputFactory.createXMLEventReader(csdl); - return buildEdmProvider(reader, resolver, loadCore, useLocal); + return buildEdmProvider(reader, resolver, loadCore, useLocal, loadReferenceSchemas); } protected SchemaBasedEdmProvider buildEdmProvider(XMLEventReader reader, - ReferenceResolver resolver, boolean loadCore, boolean useLocal) + ReferenceResolver resolver, boolean loadCore, boolean useLocal, boolean loadReferenceSchemas) throws XMLStreamException { SchemaBasedEdmProvider provider = new SchemaBasedEdmProvider(); @@ -211,7 +222,7 @@ public class MetadataParser { } // load all the reference schemas - if (resolver != null) { + if (resolver != null && loadReferenceSchemas) { loadReferencesSchemas(provider, xmlBase.length() == 0 ? null : fixXmlBase(xmlBase.toString()), resolver, loadCore, useLocal); } @@ -245,15 +256,17 @@ public class MetadataParser { } else { // do not implicitly load core vocabularies any more. But if the // references loading the core vocabularies try to use local if we can - refProvider = buildEdmProvider(is, resolver, false, useLocal); + refProvider = buildEdmProvider(is, resolver, false, useLocal, this.recusivelyLoadReferences); } } - CsdlSchema refSchema = refProvider.getSchema(include.getNamespace(), false); - provider.addReferenceSchema(include.getNamespace(), refProvider); - if (include.getAlias() != null) { - refSchema.setAlias(include.getAlias()); - provider.addReferenceSchema(include.getAlias(), refProvider); + if (refProvider != null) { + CsdlSchema refSchema = refProvider.getSchema(include.getNamespace(), false); + provider.addReferenceSchema(include.getNamespace(), refProvider); + if (include.getAlias() != null) { + refSchema.setAlias(include.getAlias()); + provider.addReferenceSchema(include.getAlias(), refProvider); + } } } } catch (XMLStreamException e) { @@ -295,7 +308,7 @@ public class MetadataParser { if (schema == null) { InputStream is = this.getClass().getClassLoader().getResourceAsStream(resource); if (is != null) { - SchemaBasedEdmProvider childProvider = buildEdmProvider(is, null, false, false); + SchemaBasedEdmProvider childProvider = buildEdmProvider(is, null, false, false, true); provider.addVocabularySchema(namespace, childProvider); } else { throw new XMLStreamException("failed to load "+resource+" core vocabulary"); @@ -654,17 +667,19 @@ public class MetadataParser { void build(XMLEventReader reader, StartElement element, T target, String name) throws XMLStreamException { - // attribute based expressions. - readAttributeExpressions(element, target); - // element based expressions - for (ConstantExpressionType type:ConstantExpressionType.values()) { - if (name.equals(type.name())) { - if (reader.peek().isCharacters()) { - CsdlExpression expr = new CsdlConstantExpression(type, elementValue(reader, element)); - write(target, expr); - } - } + if (!name.equals("Annotation")) { + // attribute based expressions. + readAttributeExpressions(element, target); + + for (ConstantExpressionType type:ConstantExpressionType.values()) { + if (name.equals(type.name())) { + if (reader.peek().isCharacters()) { + CsdlExpression expr = new CsdlConstantExpression(type, elementValue(reader, element)); + write(target, expr); + } + } + } } if (name.equals("Collection")) { @@ -719,6 +734,8 @@ public class MetadataParser { expr.setType(attr(element, "Type")); readPropertyValues(reader, element, expr); write(target, expr); + } else if (name.equals("Annotation")) { + readAnnotations(reader, element, (CsdlAnnotatable)target); } } }.read(reader, element, target, "Collection", "AnnotationPath", @@ -726,7 +743,7 @@ public class MetadataParser { "Apply", "Function", "Cast", "If", "IsOf", "LabeledElement", "LabeledElementReference", "Null", "Record","Binary", "Bool", "Date", "DateTimeOffset", "Decimal", "Duration", "EnumMember", "Float", "Guid", - "Int", "String", "TimeOfDay"); + "Int", "String", "TimeOfDay", "Annotation"); } private void readAttributeExpressions(StartElement element, T target) @@ -781,13 +798,17 @@ public class MetadataParser { @Override void build(XMLEventReader reader, StartElement element, CsdlRecord record, String name) throws XMLStreamException { - CsdlPropertyValue value = new CsdlPropertyValue(); - value.setProperty(attr(element, "Property")); - readAttributeExpressions(element, value); - readExpressions(reader, element, value); - record.getPropertyValues().add(value); + if (name.equals("PropertyValue")) { + CsdlPropertyValue value = new CsdlPropertyValue(); + value.setProperty(attr(element, "Property")); + readAttributeExpressions(element, value); + readExpressions(reader, element, value); + record.getPropertyValues().add(value); + } else if (name.equals("Annotation")) { + readAnnotations(reader, element, record); + } } - }.read(reader, element, record, "PropertyValue"); + }.read(reader, element, record, "PropertyValue", "Annotation"); } private void readFunction(XMLEventReader reader, StartElement element, CsdlSchema schema) @@ -1134,7 +1155,7 @@ public class MetadataParser { } abstract class ElementReader { - void read(XMLEventReader reader, StartElement element, T t, String... names) + void read(XMLEventReader reader, StartElement parentElement, T t, String... names) throws XMLStreamException { while (reader.hasNext()) { XMLEvent event = reader.peek(); @@ -1153,11 +1174,17 @@ public class MetadataParser { continue; } + if (parentElement != null && event.isEndElement() + && ((EndElement) event).getName().equals(parentElement.getName())) { + // end reached + break; + } + boolean hit = false; for (String name : names) { if (event.isStartElement()) { - element = event.asStartElement(); + StartElement element = event.asStartElement(); if (element.getName().getLocalPart().equals(name)) { reader.nextEvent(); // advance cursor start which is current build(reader, element, t, name); diff --git a/lib/server-core-ext/src/test/java/org/apache/olingo/server/core/MetadataParserAnnotationsTest.java b/lib/server-core-ext/src/test/java/org/apache/olingo/server/core/MetadataParserAnnotationsTest.java index 0c6288a24..f62cfef95 100644 --- a/lib/server-core-ext/src/test/java/org/apache/olingo/server/core/MetadataParserAnnotationsTest.java +++ b/lib/server-core-ext/src/test/java/org/apache/olingo/server/core/MetadataParserAnnotationsTest.java @@ -110,6 +110,9 @@ public class MetadataParserAnnotationsTest { assertEquals(7, apply.getParameters().size()); assertTrue(apply.getParameters().get(1) instanceof CsdlPath); assertTrue(apply.getParameters().get(4) instanceof CsdlConstantExpression); + + assertEquals("OData.Description", apply.getAnnotations().get(0).getTerm()); + assertEquals("concat apply", apply.getAnnotations().get(0).getExpression().asConstant().getValue()); } @Test @@ -148,6 +151,10 @@ public class MetadataParserAnnotationsTest { CsdlIsOf isOf = (CsdlIsOf)a.getExpression(); assertEquals("Self.PreferredCustomer", isOf.getType()); assertTrue(isOf.getValue() instanceof CsdlPath); + + assertEquals("OData.Description", isOf.getAnnotations().get(0).getTerm()); + assertEquals("preferred customer", isOf.getAnnotations().get(0).getExpression().asConstant().getValue()); + } @Test @@ -186,6 +193,8 @@ public class MetadataParserAnnotationsTest { CsdlPropertyValue value = expr.getPropertyValues().get(0); assertEquals("NonUpdatableNavigationProperties", value.getProperty()); assertTrue(value.getValue() instanceof CsdlCollection); + assertEquals("OData.Description", expr.getAnnotations().get(0).getTerm()); + assertEquals("descripiton test", expr.getAnnotations().get(0).getExpression().asConstant().getValue()); CsdlCollection collection = (CsdlCollection)value.getValue(); assertEquals(2, collection.getItems().size()); diff --git a/lib/server-core-ext/src/test/java/org/apache/olingo/server/core/MetadataParserTest.java b/lib/server-core-ext/src/test/java/org/apache/olingo/server/core/MetadataParserTest.java index 5b6d49068..a0e6aebcd 100644 --- a/lib/server-core-ext/src/test/java/org/apache/olingo/server/core/MetadataParserTest.java +++ b/lib/server-core-ext/src/test/java/org/apache/olingo/server/core/MetadataParserTest.java @@ -24,7 +24,11 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.FileReader; +import java.io.InputStream; +import java.net.URI; import java.util.List; import org.apache.olingo.commons.api.ex.ODataException; @@ -187,5 +191,26 @@ public class MetadataParserTest { public void testParsingWithNoFormat() throws Exception { MetadataParser parser = new MetadataParser(); provider = (CsdlEdmProvider) parser.buildEdmProvider(new FileReader("src/test/resources/skip-annotation.xml")); - } + } + + @Test + public void testReferenceLoad() throws Exception { + MetadataParser parser = new MetadataParser(); + parser.recursivelyLoadReferences(false); + parser.referenceResolver(new ReferenceResolver() { + @Override + public InputStream resolveReference(URI uri, String xmlBase) { + String str = uri.toASCIIString(); + if (str.startsWith("http://localhost/")) { + try { + return new FileInputStream("src/test/resources/"+str.substring(17)); + } catch (FileNotFoundException e) { + return null; + } + } + return null; + } + }); + provider = (CsdlEdmProvider) parser.buildEdmProvider(new FileReader("src/test/resources/test.xml")); + } } diff --git a/lib/server-core-ext/src/test/resources/a.xml b/lib/server-core-ext/src/test/resources/a.xml new file mode 100644 index 000000000..4426058c3 --- /dev/null +++ b/lib/server-core-ext/src/test/resources/a.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/server-core-ext/src/test/resources/annotations.xml b/lib/server-core-ext/src/test/resources/annotations.xml index ca581f08e..7efbf7224 100644 --- a/lib/server-core-ext/src/test/resources/annotations.xml +++ b/lib/server-core-ext/src/test/resources/annotations.xml @@ -52,6 +52,7 @@ Available/Unit available) + @@ -79,6 +80,7 @@ Customer + @@ -105,6 +107,7 @@ Category + diff --git a/lib/server-core-ext/src/test/resources/b.xml b/lib/server-core-ext/src/test/resources/b.xml new file mode 100644 index 000000000..dd5253efe --- /dev/null +++ b/lib/server-core-ext/src/test/resources/b.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/lib/server-core-ext/src/test/resources/test.xml b/lib/server-core-ext/src/test/resources/test.xml new file mode 100644 index 000000000..ef0bb166a --- /dev/null +++ b/lib/server-core-ext/src/test/resources/test.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + \ No newline at end of file