OLINGO-861: Adding support to resolve entities defined in the reference documents

This commit is contained in:
Ramesh Reddy 2016-02-10 10:03:20 -06:00
parent 7a68ae68ad
commit 801899a085
3 changed files with 180 additions and 22 deletions

View File

@ -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);
}
}
}
}

View File

@ -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);
}

View File

@ -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+"/";
}
}
}
}