OLINGO-1252: adding ability load reference schemas recursively, but locallized to the schema they represent

This commit is contained in:
Ramesh Reddy 2018-04-05 12:41:42 -05:00
parent d9aff6300f
commit fd8bfa33d4
3 changed files with 124 additions and 60 deletions

View File

@ -27,6 +27,8 @@ import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
@ -100,7 +102,8 @@ public class MetadataParser {
private ReferenceResolver referenceResolver = new DefaultReferenceResolver();
private boolean useLocalCoreVocabularies = true;
private boolean implicitlyLoadCoreVocabularies = false;
private boolean recusivelyLoadReferences = false;
private boolean recursivelyLoadReferences = false;
private Map<String, SchemaBasedEdmProvider> globalReferenceMap = new HashMap<String, SchemaBasedEdmProvider>();
/**
* Avoid reading the annotations in the $metadata
@ -138,7 +141,7 @@ public class MetadataParser {
* @return
*/
public MetadataParser recursivelyLoadReferences(boolean load) {
this.recusivelyLoadReferences = load;
this.recursivelyLoadReferences = load;
return this;
}
@ -154,35 +157,37 @@ public class MetadataParser {
public ServiceMetadata buildServiceMetadata(Reader csdl) throws XMLStreamException {
SchemaBasedEdmProvider provider = buildEdmProvider(csdl, this.referenceResolver,
this.implicitlyLoadCoreVocabularies, this.useLocalCoreVocabularies, true);
this.implicitlyLoadCoreVocabularies, this.useLocalCoreVocabularies, true, null);
return new ServiceMetadataImpl(provider, provider.getReferences(), null);
}
public SchemaBasedEdmProvider buildEdmProvider(Reader csdl) throws XMLStreamException {
XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
XMLEventReader reader = xmlInputFactory.createXMLEventReader(csdl);
return buildEdmProvider(reader, this.referenceResolver,
this.implicitlyLoadCoreVocabularies, this.useLocalCoreVocabularies, true);
return buildEdmProvider(reader, this.referenceResolver, this.implicitlyLoadCoreVocabularies,
this.useLocalCoreVocabularies, true, null);
}
protected SchemaBasedEdmProvider buildEdmProvider(Reader csdl,
ReferenceResolver resolver, boolean loadCore, boolean useLocal, boolean loadReferenceSchemas)
protected SchemaBasedEdmProvider buildEdmProvider(Reader csdl, ReferenceResolver resolver,
boolean loadCore, boolean useLocal,
boolean loadReferenceSchemas, String namespace)
throws XMLStreamException {
XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
XMLEventReader reader = xmlInputFactory.createXMLEventReader(csdl);
return buildEdmProvider(reader, resolver, loadCore, useLocal, loadReferenceSchemas);
return buildEdmProvider(reader, resolver, loadCore, useLocal, loadReferenceSchemas, namespace);
}
protected SchemaBasedEdmProvider buildEdmProvider(InputStream csdl,
ReferenceResolver resolver, boolean loadCore, boolean useLocal, boolean loadReferenceSchemas)
protected SchemaBasedEdmProvider buildEdmProvider(InputStream csdl, ReferenceResolver resolver,
boolean loadCore, boolean useLocal,
boolean loadReferenceSchemas, String namespace)
throws XMLStreamException {
XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
XMLEventReader reader = xmlInputFactory.createXMLEventReader(csdl);
return buildEdmProvider(reader, resolver, loadCore, useLocal, loadReferenceSchemas);
return buildEdmProvider(reader, resolver, loadCore, useLocal, loadReferenceSchemas, namespace);
}
protected SchemaBasedEdmProvider buildEdmProvider(XMLEventReader reader,
ReferenceResolver resolver, boolean loadCore, boolean useLocal, boolean loadReferenceSchemas)
ReferenceResolver resolver, boolean loadCore, boolean useLocal, boolean loadReferenceSchemas, String namespace)
throws XMLStreamException {
SchemaBasedEdmProvider provider = new SchemaBasedEdmProvider();
@ -221,6 +226,10 @@ public class MetadataParser {
loadCoreVocabulary(provider, "Org.OData.Measures.V1");
}
if (namespace != null && !namespace.equals("") && !globalReferenceMap.containsKey(namespace)) {
globalReferenceMap.put(namespace, provider);
}
// load all the reference schemas
if (resolver != null && loadReferenceSchemas) {
loadReferencesSchemas(provider, xmlBase.length() == 0 ? null
@ -239,8 +248,8 @@ public class MetadataParser {
for (EdmxReferenceInclude include : reference.getIncludes()) {
// check if the schema is already loaded before.
if (provider.getSchema(include.getNamespace()) != null) {
// check if the schema is already loaded before in current provider.
if (provider.getSchemaDirectly(include.getNamespace()) != null) {
continue;
}
@ -249,6 +258,9 @@ public class MetadataParser {
continue;
}
// check if the schema is already loaded before in parent providers
refProvider = this.globalReferenceMap.get(include.getNamespace());
if (refProvider == null) {
InputStream is = this.referenceResolver.resolveReference(reference.getUri(), xmlBase);
if (is == null) {
@ -256,7 +268,8 @@ 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, this.recusivelyLoadReferences);
refProvider = buildEdmProvider(is, resolver, false, useLocal,
this.recursivelyLoadReferences, include.getNamespace());
}
}
@ -308,7 +321,7 @@ public class MetadataParser {
if (schema == null) {
InputStream is = this.getClass().getClassLoader().getResourceAsStream(resource);
if (is != null) {
SchemaBasedEdmProvider childProvider = buildEdmProvider(is, null, false, false, true);
SchemaBasedEdmProvider childProvider = buildEdmProvider(is, null, false, false, true, "");
provider.addVocabularySchema(namespace, childProvider);
} else {
throw new XMLStreamException("failed to load "+resource+" core vocabulary");

View File

@ -19,8 +19,10 @@
package org.apache.olingo.server.core;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.olingo.commons.api.edm.FullQualifiedName;
@ -88,38 +90,44 @@ public class SchemaBasedEdmProvider implements CsdlEdmProvider {
}
CsdlSchema getSchema(String ns, boolean checkReferences) {
if (checkReferences) {
return getSchemaRecursively(ns, new HashSet<String>());
} else {
return getSchemaDirectly(ns);
}
}
CsdlSchema getSchemaDirectly(String ns) {
for (CsdlSchema s : this.edmSchemas) {
if (s.getNamespace().equals(ns)) {
return s;
}
}
CsdlSchema s = null;
if (checkReferences) {
s = getReferenceSchema(ns);
if (s == null) {
s = getVocabularySchema(ns);
}
}
return s;
}
CsdlSchema getReferenceSchema(String ns) {
if (ns == null) {
return null;
}
if (this.referenceSchemas.get(ns) != null) {
return this.referenceSchemas.get(ns).getSchema(ns);
CsdlSchema getSchemaRecursively(String ns, Set<String> parsedPath) {
// find the schema by namespace in current provider
CsdlSchema schema = getSchemaDirectly(ns);
if (schema != null) {
return schema;
}
// it is possible that we may be looking for Reference schema of Reference
for (SchemaBasedEdmProvider provider:this.referenceSchemas.values()) {
CsdlSchema schema = provider.getSchema(ns);
// find the schema by namespace in the reference schema provider
for (Map.Entry<String, SchemaBasedEdmProvider> entry : this.referenceSchemas.entrySet()) {
String namespace = entry.getKey();
if (parsedPath.contains(namespace)) {
continue;
}
SchemaBasedEdmProvider provider = entry.getValue();
parsedPath.add(namespace);
schema = provider.getSchemaRecursively(ns, parsedPath);
if (schema != null) {
return schema;
}
}
return null;
return getVocabularySchema(ns);
}
@Override

View File

@ -46,6 +46,7 @@ import org.apache.olingo.commons.api.edm.provider.CsdlNavigationPropertyBinding;
import org.apache.olingo.commons.api.edm.provider.CsdlParameter;
import org.apache.olingo.commons.api.edm.provider.CsdlProperty;
import org.apache.olingo.commons.api.edm.provider.CsdlSingleton;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@ -56,6 +57,21 @@ public class MetadataParserTest {
CsdlEdmProvider provider = null;
ReferenceResolver testReferenceResolver = 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;
}
};
@Before
public void setUp() throws Exception {
MetadataParser parser = new MetadataParser();
@ -197,20 +213,47 @@ public class MetadataParserTest {
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;
}
});
parser.referenceResolver(this.testReferenceResolver);
provider = (CsdlEdmProvider) parser.buildEdmProvider(new FileReader("src/test/resources/test.xml"));
}
@Test
public void testReferenceLoadRecursively() throws Exception {
MetadataParser parser = new MetadataParser();
parser.recursivelyLoadReferences(true);
parser.referenceResolver(testReferenceResolver);
SchemaBasedEdmProvider providerTest = parser.buildEdmProvider(new FileReader("src/test/resources/test.xml"));
Assert.assertNotNull(providerTest.getSchema("Microsoft.OData.SampleService.Models.TripPin", false));
Assert.assertNull(providerTest.getSchema("org.apache.olingo.a", false));
Assert.assertNull(providerTest.getSchema("org.apache.olingo.b", false));
Assert.assertNotNull(providerTest.getSchema("org.apache.olingo.a", true));
Assert.assertNotNull(providerTest.getSchema("org.apache.olingo.b", true));
}
@Test
public void testCircleReferenceShouldNotStackOverflow() throws Exception {
MetadataParser parser = new MetadataParser();
parser.recursivelyLoadReferences(true);
parser.referenceResolver(testReferenceResolver);
SchemaBasedEdmProvider providerTest = parser.buildEdmProvider(new FileReader("src/test/resources/test.xml"));
Assert.assertNull(providerTest.getSchema("Not Found", true));
}
@Test
public void testLoadCoreVocabulary() throws Exception {
MetadataParser parser = new MetadataParser();
parser.implicitlyLoadCoreVocabularies(true);
parser.referenceResolver(testReferenceResolver);
SchemaBasedEdmProvider provider = parser.buildEdmProvider(new FileReader("src/test/resources/test.xml"));
Assert.assertNotNull(provider.getVocabularySchema("Org.OData.Core.V1"));
Assert.assertNotNull(provider.getSchema("Org.OData.Core.V1"));
}
}