OLINGO-861: Adding support to resolve entities defined in the reference documents
This commit is contained in:
parent
7a68ae68ad
commit
801899a085
|
@ -18,9 +18,12 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.olingo.server.core;
|
package org.apache.olingo.server.core;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
@ -33,6 +36,7 @@ import javax.xml.stream.events.EndElement;
|
||||||
import javax.xml.stream.events.StartElement;
|
import javax.xml.stream.events.StartElement;
|
||||||
import javax.xml.stream.events.XMLEvent;
|
import javax.xml.stream.events.XMLEvent;
|
||||||
|
|
||||||
|
import org.apache.olingo.commons.api.edm.EdmException;
|
||||||
import org.apache.olingo.commons.api.edm.FullQualifiedName;
|
import org.apache.olingo.commons.api.edm.FullQualifiedName;
|
||||||
import org.apache.olingo.commons.api.edm.geo.SRID;
|
import org.apache.olingo.commons.api.edm.geo.SRID;
|
||||||
import org.apache.olingo.commons.api.edm.provider.CsdlAction;
|
import org.apache.olingo.commons.api.edm.provider.CsdlAction;
|
||||||
|
@ -42,7 +46,6 @@ import org.apache.olingo.commons.api.edm.provider.CsdlAnnotation;
|
||||||
import org.apache.olingo.commons.api.edm.provider.CsdlAnnotations;
|
import org.apache.olingo.commons.api.edm.provider.CsdlAnnotations;
|
||||||
import org.apache.olingo.commons.api.edm.provider.CsdlBindingTarget;
|
import org.apache.olingo.commons.api.edm.provider.CsdlBindingTarget;
|
||||||
import org.apache.olingo.commons.api.edm.provider.CsdlComplexType;
|
import org.apache.olingo.commons.api.edm.provider.CsdlComplexType;
|
||||||
import org.apache.olingo.commons.api.edm.provider.CsdlEdmProvider;
|
|
||||||
import org.apache.olingo.commons.api.edm.provider.CsdlEntityContainer;
|
import org.apache.olingo.commons.api.edm.provider.CsdlEntityContainer;
|
||||||
import org.apache.olingo.commons.api.edm.provider.CsdlEntitySet;
|
import org.apache.olingo.commons.api.edm.provider.CsdlEntitySet;
|
||||||
import org.apache.olingo.commons.api.edm.provider.CsdlEntityType;
|
import org.apache.olingo.commons.api.edm.provider.CsdlEntityType;
|
||||||
|
@ -92,16 +95,22 @@ import org.apache.olingo.server.api.edmx.EdmxReferenceIncludeAnnotation;
|
||||||
*/
|
*/
|
||||||
public class MetadataParser {
|
public class MetadataParser {
|
||||||
private boolean parseAnnotations = false;
|
private boolean parseAnnotations = false;
|
||||||
|
private final String XML_LINK_NS = "http://www.w3.org/1999/xlink";
|
||||||
|
private ReferenceResolver referenceResolver = new DefaultReferenceResolver();
|
||||||
|
|
||||||
public void setParseAnnotations(boolean f) {
|
public void setParseAnnotations(boolean f) {
|
||||||
this.parseAnnotations = true;
|
this.parseAnnotations = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setReferenceResolver(ReferenceResolver resolver) {
|
||||||
|
this.referenceResolver = resolver;
|
||||||
|
}
|
||||||
|
|
||||||
public ServiceMetadata buildServiceMetadata(Reader csdl) throws XMLStreamException {
|
public ServiceMetadata buildServiceMetadata(Reader csdl) throws XMLStreamException {
|
||||||
XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
|
XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
|
||||||
XMLEventReader reader = xmlInputFactory.createXMLEventReader(csdl);
|
XMLEventReader reader = xmlInputFactory.createXMLEventReader(csdl);
|
||||||
|
|
||||||
SchemaBasedEdmProvider provider = new SchemaBasedEdmProvider();
|
SchemaBasedEdmProvider provider = new SchemaBasedEdmProvider(referenceResolver);
|
||||||
final ArrayList<EdmxReference> references = new ArrayList<EdmxReference>();
|
final ArrayList<EdmxReference> references = new ArrayList<EdmxReference>();
|
||||||
|
|
||||||
new ElementReader<SchemaBasedEdmProvider>() {
|
new ElementReader<SchemaBasedEdmProvider>() {
|
||||||
|
@ -109,6 +118,8 @@ public class MetadataParser {
|
||||||
void build(XMLEventReader reader, StartElement element, SchemaBasedEdmProvider provider,
|
void build(XMLEventReader reader, StartElement element, SchemaBasedEdmProvider provider,
|
||||||
String name) throws XMLStreamException {
|
String name) throws XMLStreamException {
|
||||||
String version = attr(element, "Version");
|
String version = attr(element, "Version");
|
||||||
|
String xmlBase = attrNS(element, XML_LINK_NS, "base");
|
||||||
|
provider.setXMLBase(xmlBase);
|
||||||
if ("4.0".equals(version)) {
|
if ("4.0".equals(version)) {
|
||||||
readDataServicesAndReference(reader, element, provider, references);
|
readDataServicesAndReference(reader, element, provider, references);
|
||||||
} else {
|
} else {
|
||||||
|
@ -124,14 +135,18 @@ public class MetadataParser {
|
||||||
event.asStartElement().getName().getLocalPart() :
|
event.asStartElement().getName().getLocalPart() :
|
||||||
event.asEndElement().getName().getLocalPart()));
|
event.asEndElement().getName().getLocalPart()));
|
||||||
}
|
}
|
||||||
|
provider.addReferences(references);
|
||||||
return new ServiceMetadataImpl(provider, references, null);
|
return new ServiceMetadataImpl(provider, references, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
CsdlEdmProvider buildEdmProvider(Reader csdl) throws XMLStreamException {
|
SchemaBasedEdmProvider buildEdmProvider(Reader csdl) throws XMLStreamException {
|
||||||
XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
|
XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
|
||||||
XMLEventReader reader = xmlInputFactory.createXMLEventReader(csdl);
|
XMLEventReader reader = xmlInputFactory.createXMLEventReader(csdl);
|
||||||
|
return buildEdmProvider(reader);
|
||||||
|
}
|
||||||
|
|
||||||
SchemaBasedEdmProvider provider = new SchemaBasedEdmProvider();
|
SchemaBasedEdmProvider buildEdmProvider(XMLEventReader reader) throws XMLStreamException {
|
||||||
|
SchemaBasedEdmProvider provider = new SchemaBasedEdmProvider(this.referenceResolver);
|
||||||
new ElementReader<SchemaBasedEdmProvider>() {
|
new ElementReader<SchemaBasedEdmProvider>() {
|
||||||
@Override
|
@Override
|
||||||
void build(XMLEventReader reader, StartElement element, SchemaBasedEdmProvider provider,
|
void build(XMLEventReader reader, StartElement element, SchemaBasedEdmProvider provider,
|
||||||
|
@ -142,7 +157,6 @@ public class MetadataParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.read(reader, null, provider, "Edmx");
|
}.read(reader, null, provider, "Edmx");
|
||||||
|
|
||||||
return provider;
|
return provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -776,6 +790,14 @@ public class MetadataParser {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String attrNS(StartElement element, String ns, String name) {
|
||||||
|
Attribute attr = element.getAttributeByName(new QName(ns, name));
|
||||||
|
if (attr != null) {
|
||||||
|
return attr.getValue();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private CsdlProperty readProperty(XMLEventReader reader, StartElement element)
|
private CsdlProperty readProperty(XMLEventReader reader, StartElement element)
|
||||||
throws XMLStreamException {
|
throws XMLStreamException {
|
||||||
CsdlProperty property = new CsdlProperty();
|
CsdlProperty property = new CsdlProperty();
|
||||||
|
@ -1020,4 +1042,32 @@ public class MetadataParser {
|
||||||
abstract void build(XMLEventReader reader, StartElement element, T t, String name)
|
abstract void build(XMLEventReader reader, StartElement element, T t, String name)
|
||||||
throws XMLStreamException;
|
throws XMLStreamException;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DefaultReferenceResolver implements ReferenceResolver{
|
||||||
|
@Override
|
||||||
|
public SchemaBasedEdmProvider resolveReference(URI referenceUri, String xmlBase) {
|
||||||
|
URL schemaURL = null;
|
||||||
|
try {
|
||||||
|
if (referenceUri.isAbsolute()) {
|
||||||
|
schemaURL = referenceUri.toURL();
|
||||||
|
} else {
|
||||||
|
if (xmlBase != null) {
|
||||||
|
schemaURL = new URL(xmlBase+referenceUri.toString());
|
||||||
|
} else {
|
||||||
|
throw new EdmException("No xml:base set to read the references from the metadata");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
|
||||||
|
XMLEventReader reader = xmlInputFactory.createXMLEventReader(schemaURL.openStream());
|
||||||
|
return buildEdmProvider(reader);
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
throw new EdmException(e);
|
||||||
|
} catch (XMLStreamException e) {
|
||||||
|
throw new EdmException(e);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new EdmException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.olingo.server.core;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
public interface ReferenceResolver {
|
||||||
|
/**
|
||||||
|
* Resolve the reference locally or from redirection from different source than defined in the
|
||||||
|
* metadata document.
|
||||||
|
* @param referenceUri reference URI for the schema file
|
||||||
|
* @param xmlBase xml:base if provided by the metadata document; null otherwise
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
SchemaBasedEdmProvider resolveReference(URI referenceUri, String xmlBase);
|
||||||
|
}
|
|
@ -19,8 +19,9 @@
|
||||||
package org.apache.olingo.server.core;
|
package org.apache.olingo.server.core;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import org.apache.olingo.commons.api.edm.FullQualifiedName;
|
import org.apache.olingo.commons.api.edm.FullQualifiedName;
|
||||||
import org.apache.olingo.commons.api.edm.provider.CsdlAction;
|
import org.apache.olingo.commons.api.edm.provider.CsdlAction;
|
||||||
|
@ -41,11 +42,22 @@ import org.apache.olingo.commons.api.edm.provider.CsdlSingleton;
|
||||||
import org.apache.olingo.commons.api.edm.provider.CsdlTerm;
|
import org.apache.olingo.commons.api.edm.provider.CsdlTerm;
|
||||||
import org.apache.olingo.commons.api.edm.provider.CsdlTypeDefinition;
|
import org.apache.olingo.commons.api.edm.provider.CsdlTypeDefinition;
|
||||||
import org.apache.olingo.commons.api.ex.ODataException;
|
import org.apache.olingo.commons.api.ex.ODataException;
|
||||||
|
import org.apache.olingo.server.api.edmx.EdmxReference;
|
||||||
|
import org.apache.olingo.server.api.edmx.EdmxReferenceInclude;
|
||||||
|
|
||||||
public class SchemaBasedEdmProvider implements CsdlEdmProvider {
|
public class SchemaBasedEdmProvider implements CsdlEdmProvider {
|
||||||
private final List<CsdlSchema> edmSchemas = new ArrayList<CsdlSchema>();
|
private final List<CsdlSchema> edmSchemas = new ArrayList<CsdlSchema>();
|
||||||
|
private final Map<String, EdmxReference> references = new ConcurrentHashMap<String, EdmxReference>();
|
||||||
|
private final Map<String, SchemaBasedEdmProvider> referenceSchemas
|
||||||
|
= new ConcurrentHashMap<String, SchemaBasedEdmProvider>();
|
||||||
|
private String xmlBase;
|
||||||
|
private ReferenceResolver referenceResolver;
|
||||||
|
|
||||||
public void addSchema(CsdlSchema schema) {
|
public SchemaBasedEdmProvider(ReferenceResolver referenceResolver) {
|
||||||
|
this.referenceResolver = referenceResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addSchema(CsdlSchema schema) {
|
||||||
this.edmSchemas.add(schema);
|
this.edmSchemas.add(schema);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,6 +67,39 @@ public class SchemaBasedEdmProvider implements CsdlEdmProvider {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return getReferenceSchema(ns);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CsdlSchema getReferenceSchema(String ns) {
|
||||||
|
if (ns == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (this.referenceSchemas.get(ns) == null) {
|
||||||
|
EdmxReference reference = this.references.get(ns);
|
||||||
|
if (reference != null) {
|
||||||
|
SchemaBasedEdmProvider provider = this.referenceResolver.resolveReference(reference.getUri(), xmlBase);
|
||||||
|
for (EdmxReferenceInclude include : reference.getIncludes()) {
|
||||||
|
this.referenceSchemas.put(include.getNamespace(), provider);
|
||||||
|
if (include.getAlias() != null) {
|
||||||
|
CsdlSchema schema = provider.getSchema(include.getNamespace());
|
||||||
|
schema.setAlias(include.getAlias());
|
||||||
|
this.referenceSchemas.put(include.getAlias(), provider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.referenceSchemas.get(ns) != null) {
|
||||||
|
return this.referenceSchemas.get(ns).getSchema(ns);
|
||||||
|
}
|
||||||
|
|
||||||
|
// it is possible that we may be looking for Reference schema of Reference
|
||||||
|
for (SchemaBasedEdmProvider provider:this.referenceSchemas.values()) {
|
||||||
|
CsdlSchema schema = provider.getSchema(ns);
|
||||||
|
if (schema != null) {
|
||||||
|
return schema;
|
||||||
|
}
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,22 +265,26 @@ public class SchemaBasedEdmProvider implements CsdlEdmProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<CsdlAliasInfo> getAliasInfos() throws ODataException {
|
public List<CsdlAliasInfo> getAliasInfos() throws ODataException {
|
||||||
CsdlSchema schema = null;
|
ArrayList<CsdlAliasInfo> list = new ArrayList<CsdlAliasInfo>();
|
||||||
for (CsdlSchema s : this.edmSchemas) {
|
for (CsdlSchema s : this.edmSchemas) {
|
||||||
if (s.getEntityContainer() != null) {
|
if (s.getAlias() != null) {
|
||||||
schema = s;
|
CsdlAliasInfo ai = new CsdlAliasInfo();
|
||||||
break;
|
ai.setAlias(s.getAlias());
|
||||||
|
ai.setNamespace(s.getNamespace());
|
||||||
|
list.add(ai);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for(EdmxReference reference:this.references.values()) {
|
||||||
if (schema == null) {
|
for(EdmxReferenceInclude include:reference.getIncludes()) {
|
||||||
schema = this.edmSchemas.get(0);
|
if (include.getAlias() != null) {
|
||||||
|
CsdlAliasInfo ai = new CsdlAliasInfo();
|
||||||
|
ai.setAlias(include.getAlias());
|
||||||
|
ai.setNamespace(include.getNamespace());
|
||||||
|
list.add(ai);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return list;
|
||||||
CsdlAliasInfo ai = new CsdlAliasInfo();
|
|
||||||
ai.setAlias(schema.getAlias());
|
|
||||||
ai.setNamespace(schema.getNamespace());
|
|
||||||
return Arrays.asList(ai);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -304,6 +353,33 @@ public class SchemaBasedEdmProvider implements CsdlEdmProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CsdlAnnotations getAnnotationsGroup(FullQualifiedName targetName, String qualifier) throws ODataException {
|
public CsdlAnnotations getAnnotationsGroup(FullQualifiedName targetName, String qualifier) throws ODataException {
|
||||||
|
CsdlSchema schema = getSchema(targetName.getNamespace());
|
||||||
|
if (schema != null) {
|
||||||
|
return schema.getAnnotationGroup(targetName.getName(), qualifier);
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void addReferences(ArrayList<EdmxReference> references) {
|
||||||
|
if (references != null && !references.isEmpty()) {
|
||||||
|
for (EdmxReference ref:references) {
|
||||||
|
for (EdmxReferenceInclude include : ref.getIncludes()) {
|
||||||
|
if (include.getAlias() != null) {
|
||||||
|
this.references.put(include.getAlias(), ref);
|
||||||
|
}
|
||||||
|
this.references.put(include.getNamespace(), ref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setXMLBase(String base) {
|
||||||
|
if (base != null) {
|
||||||
|
if (base.endsWith("/")) {
|
||||||
|
this.xmlBase = base;
|
||||||
|
} else {
|
||||||
|
this.xmlBase = base+"/";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue