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;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
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.XMLEvent;
|
||||
|
||||
import org.apache.olingo.commons.api.edm.EdmException;
|
||||
import org.apache.olingo.commons.api.edm.FullQualifiedName;
|
||||
import org.apache.olingo.commons.api.edm.geo.SRID;
|
||||
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.CsdlBindingTarget;
|
||||
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.CsdlEntitySet;
|
||||
import org.apache.olingo.commons.api.edm.provider.CsdlEntityType;
|
||||
|
@ -92,16 +95,22 @@ import org.apache.olingo.server.api.edmx.EdmxReferenceIncludeAnnotation;
|
|||
*/
|
||||
public class MetadataParser {
|
||||
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) {
|
||||
this.parseAnnotations = true;
|
||||
}
|
||||
|
||||
public void setReferenceResolver(ReferenceResolver resolver) {
|
||||
this.referenceResolver = resolver;
|
||||
}
|
||||
|
||||
public ServiceMetadata buildServiceMetadata(Reader csdl) throws XMLStreamException {
|
||||
XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
|
||||
XMLEventReader reader = xmlInputFactory.createXMLEventReader(csdl);
|
||||
|
||||
SchemaBasedEdmProvider provider = new SchemaBasedEdmProvider();
|
||||
SchemaBasedEdmProvider provider = new SchemaBasedEdmProvider(referenceResolver);
|
||||
final ArrayList<EdmxReference> references = new ArrayList<EdmxReference>();
|
||||
|
||||
new ElementReader<SchemaBasedEdmProvider>() {
|
||||
|
@ -109,6 +118,8 @@ public class MetadataParser {
|
|||
void build(XMLEventReader reader, StartElement element, SchemaBasedEdmProvider provider,
|
||||
String name) throws XMLStreamException {
|
||||
String version = attr(element, "Version");
|
||||
String xmlBase = attrNS(element, XML_LINK_NS, "base");
|
||||
provider.setXMLBase(xmlBase);
|
||||
if ("4.0".equals(version)) {
|
||||
readDataServicesAndReference(reader, element, provider, references);
|
||||
} else {
|
||||
|
@ -124,14 +135,18 @@ public class MetadataParser {
|
|||
event.asStartElement().getName().getLocalPart() :
|
||||
event.asEndElement().getName().getLocalPart()));
|
||||
}
|
||||
provider.addReferences(references);
|
||||
return new ServiceMetadataImpl(provider, references, null);
|
||||
}
|
||||
|
||||
CsdlEdmProvider buildEdmProvider(Reader csdl) throws XMLStreamException {
|
||||
SchemaBasedEdmProvider buildEdmProvider(Reader csdl) throws XMLStreamException {
|
||||
XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
|
||||
XMLEventReader reader = xmlInputFactory.createXMLEventReader(csdl);
|
||||
|
||||
SchemaBasedEdmProvider provider = new SchemaBasedEdmProvider();
|
||||
return buildEdmProvider(reader);
|
||||
}
|
||||
|
||||
SchemaBasedEdmProvider buildEdmProvider(XMLEventReader reader) throws XMLStreamException {
|
||||
SchemaBasedEdmProvider provider = new SchemaBasedEdmProvider(this.referenceResolver);
|
||||
new ElementReader<SchemaBasedEdmProvider>() {
|
||||
@Override
|
||||
void build(XMLEventReader reader, StartElement element, SchemaBasedEdmProvider provider,
|
||||
|
@ -141,8 +156,7 @@ public class MetadataParser {
|
|||
readDataServicesAndReference(reader, element, provider, new ArrayList<EdmxReference>());
|
||||
}
|
||||
}
|
||||
}.read(reader, null, provider, "Edmx");
|
||||
|
||||
}.read(reader, null, provider, "Edmx");
|
||||
return provider;
|
||||
}
|
||||
|
||||
|
@ -776,6 +790,14 @@ public class MetadataParser {
|
|||
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)
|
||||
throws XMLStreamException {
|
||||
CsdlProperty property = new CsdlProperty();
|
||||
|
@ -1020,4 +1042,32 @@ public class MetadataParser {
|
|||
abstract void build(XMLEventReader reader, StartElement element, T t, String name)
|
||||
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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
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.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.CsdlTypeDefinition;
|
||||
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 {
|
||||
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 SchemaBasedEdmProvider(ReferenceResolver referenceResolver) {
|
||||
this.referenceResolver = referenceResolver;
|
||||
}
|
||||
|
||||
public void addSchema(CsdlSchema schema) {
|
||||
void addSchema(CsdlSchema schema) {
|
||||
this.edmSchemas.add(schema);
|
||||
}
|
||||
|
||||
|
@ -55,6 +67,39 @@ public class SchemaBasedEdmProvider implements CsdlEdmProvider {
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -220,22 +265,26 @@ public class SchemaBasedEdmProvider implements CsdlEdmProvider {
|
|||
|
||||
@Override
|
||||
public List<CsdlAliasInfo> getAliasInfos() throws ODataException {
|
||||
CsdlSchema schema = null;
|
||||
ArrayList<CsdlAliasInfo> list = new ArrayList<CsdlAliasInfo>();
|
||||
for (CsdlSchema s : this.edmSchemas) {
|
||||
if (s.getEntityContainer() != null) {
|
||||
schema = s;
|
||||
break;
|
||||
if (s.getAlias() != null) {
|
||||
CsdlAliasInfo ai = new CsdlAliasInfo();
|
||||
ai.setAlias(s.getAlias());
|
||||
ai.setNamespace(s.getNamespace());
|
||||
list.add(ai);
|
||||
}
|
||||
}
|
||||
|
||||
if (schema == null) {
|
||||
schema = this.edmSchemas.get(0);
|
||||
for(EdmxReference reference:this.references.values()) {
|
||||
for(EdmxReferenceInclude include:reference.getIncludes()) {
|
||||
if (include.getAlias() != null) {
|
||||
CsdlAliasInfo ai = new CsdlAliasInfo();
|
||||
ai.setAlias(include.getAlias());
|
||||
ai.setNamespace(include.getNamespace());
|
||||
list.add(ai);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CsdlAliasInfo ai = new CsdlAliasInfo();
|
||||
ai.setAlias(schema.getAlias());
|
||||
ai.setNamespace(schema.getNamespace());
|
||||
return Arrays.asList(ai);
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -304,6 +353,33 @@ public class SchemaBasedEdmProvider implements CsdlEdmProvider {
|
|||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
|
||||
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