OLINGO-880: Enable MetadataParser to load core vocabularies based on a perference setting, these are loaded loaded from local classpath, instead of making a web call

This commit is contained in:
Ramesh Reddy 2016-02-12 09:16:00 -06:00
parent 801899a085
commit 187c229b60
10 changed files with 808 additions and 56 deletions

View File

@ -19,6 +19,7 @@
package org.apache.olingo.server.core; package org.apache.olingo.server.core;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.Reader; import java.io.Reader;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URI; import java.net.URI;
@ -95,38 +96,68 @@ 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 static final String XML_LINK_NS = "http://www.w3.org/1999/xlink";
private ReferenceResolver referenceResolver = new DefaultReferenceResolver(); private ReferenceResolver defaultReferenceResolver = new DefaultReferenceResolver();
private boolean loadCoreVocabularies = false;
public void setParseAnnotations(boolean f) { public MetadataParser parseAnnotations(boolean parse) {
this.parseAnnotations = true; this.parseAnnotations = parse;
return this;
} }
public void setReferenceResolver(ReferenceResolver resolver) { public MetadataParser referenceResolver(ReferenceResolver resolver) {
this.referenceResolver = resolver; this.defaultReferenceResolver = resolver;
return this;
}
public MetadataParser loadCoreVocabularies(boolean load) {
this.loadCoreVocabularies = load;
return this;
} }
public ServiceMetadata buildServiceMetadata(Reader csdl) throws XMLStreamException { public ServiceMetadata buildServiceMetadata(Reader csdl) throws XMLStreamException {
SchemaBasedEdmProvider provider = buildEdmProvider(csdl,
this.defaultReferenceResolver, this.loadCoreVocabularies);
return new ServiceMetadataImpl(provider, provider.getReferences(), null);
}
public SchemaBasedEdmProvider buildEdmProvider(Reader csdl) throws XMLStreamException {
return buildEdmProvider(csdl, this.defaultReferenceResolver, this.loadCoreVocabularies);
}
protected SchemaBasedEdmProvider buildEdmProvider(Reader csdl,
ReferenceResolver referenceResolver, boolean loadCoreVocabularies) throws XMLStreamException {
XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance(); XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
XMLEventReader reader = xmlInputFactory.createXMLEventReader(csdl); XMLEventReader reader = xmlInputFactory.createXMLEventReader(csdl);
return buildEdmProvider(reader, referenceResolver, loadCoreVocabularies);
}
protected SchemaBasedEdmProvider buildEdmProvider(InputStream csdl,
ReferenceResolver referenceResolver, boolean loadCoreVocabularies) throws XMLStreamException {
XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
XMLEventReader reader = xmlInputFactory.createXMLEventReader(csdl);
return buildEdmProvider(reader, referenceResolver, loadCoreVocabularies);
}
protected SchemaBasedEdmProvider buildEdmProvider(XMLEventReader reader,
ReferenceResolver referenceResolver, boolean loadCoreVocabularies) throws XMLStreamException {
SchemaBasedEdmProvider provider = new SchemaBasedEdmProvider(referenceResolver); SchemaBasedEdmProvider provider = new SchemaBasedEdmProvider(referenceResolver);
final ArrayList<EdmxReference> references = new ArrayList<EdmxReference>();
new ElementReader<SchemaBasedEdmProvider>() { new ElementReader<SchemaBasedEdmProvider>() {
@Override @Override
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 xmlBase = attrNS(element, XML_LINK_NS, "base"); String xmlBase = attrNS(element, XML_LINK_NS, "base");
provider.setXMLBase(xmlBase); provider.setXMLBase(xmlBase);
String version = attr(element, "Version");
if ("4.0".equals(version)) { if ("4.0".equals(version)) {
readDataServicesAndReference(reader, element, provider, references); readDataServicesAndReference(reader, element, provider);
} else { } else {
throw new XMLStreamException("Currently only V4 is supported."); throw new XMLStreamException("Currently only V4 is supported.");
} }
} }
}.read(reader, null, provider, "Edmx"); }.read(reader, null, provider, "Edmx");
// make sure there is nothing left to read, due to parser error
if(reader.hasNext()) { if(reader.hasNext()) {
XMLEvent event = reader.peek(); XMLEvent event = reader.peek();
throw new XMLStreamException( throw new XMLStreamException(
@ -135,34 +166,33 @@ 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);
}
SchemaBasedEdmProvider buildEdmProvider(Reader csdl) throws XMLStreamException { // load the core vocabularies
XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance(); if (loadCoreVocabularies) {
XMLEventReader reader = xmlInputFactory.createXMLEventReader(csdl); loadVocabularySchema(provider, "Org.OData.Core.V1", "Org.OData.Core.V1.xml");
return buildEdmProvider(reader); loadVocabularySchema(provider, "Org.OData.Capabilities.V1", "Org.OData.Capabilities.V1.xml");
loadVocabularySchema(provider, "Org.OData.Measures.V1", "Org.OData.Measures.V1.xml");
} }
SchemaBasedEdmProvider buildEdmProvider(XMLEventReader reader) throws XMLStreamException {
SchemaBasedEdmProvider provider = new SchemaBasedEdmProvider(this.referenceResolver);
new ElementReader<SchemaBasedEdmProvider>() {
@Override
void build(XMLEventReader reader, StartElement element, SchemaBasedEdmProvider provider,
String name) throws XMLStreamException {
String version = attr(element, "Version");
if ("4.0".equals(version)) {
readDataServicesAndReference(reader, element, provider, new ArrayList<EdmxReference>());
}
}
}.read(reader, null, provider, "Edmx");
return provider; return provider;
} }
private void loadVocabularySchema(SchemaBasedEdmProvider provider, String namespace,
String resource) throws XMLStreamException {
CsdlSchema schema = provider.getSchema(namespace, false);
if (schema == null) {
InputStream is = this.getClass().getClassLoader().getResourceAsStream(resource);
if (is != null) {
SchemaBasedEdmProvider childProvider = buildEdmProvider(is, null, false);
provider.addSchema(childProvider.getSchema(namespace, false));
} else {
throw new XMLStreamException("failed to load "+resource+" core vocabulary");
}
}
}
private void readDataServicesAndReference(XMLEventReader reader, private void readDataServicesAndReference(XMLEventReader reader,
StartElement element, SchemaBasedEdmProvider provider, StartElement element, SchemaBasedEdmProvider provider) throws XMLStreamException {
final ArrayList<EdmxReference> references) throws XMLStreamException { final ArrayList<EdmxReference> references = new ArrayList<EdmxReference>();
new ElementReader<SchemaBasedEdmProvider>() { new ElementReader<SchemaBasedEdmProvider>() {
@Override @Override
void build(XMLEventReader reader, StartElement element, SchemaBasedEdmProvider provider, void build(XMLEventReader reader, StartElement element, SchemaBasedEdmProvider provider,
@ -174,6 +204,7 @@ public class MetadataParser {
} }
} }
}.read(reader, element, provider, "DataServices", "Reference"); }.read(reader, element, provider, "DataServices", "Reference");
provider.addReferences(references);
} }
private void readReference(XMLEventReader reader, StartElement element, private void readReference(XMLEventReader reader, StartElement element,
@ -782,7 +813,7 @@ public class MetadataParser {
return property; return property;
} }
private String attr(StartElement element, String name) { private static String attr(StartElement element, String name) {
Attribute attr = element.getAttributeByName(new QName(name)); Attribute attr = element.getAttributeByName(new QName(name));
if (attr != null) { if (attr != null) {
return attr.getValue(); return attr.getValue();
@ -790,7 +821,7 @@ public class MetadataParser {
return null; return null;
} }
private String attrNS(StartElement element, String ns, String name) { private static String attrNS(StartElement element, String ns, String name) {
Attribute attr = element.getAttributeByName(new QName(ns, name)); Attribute attr = element.getAttributeByName(new QName(ns, name));
if (attr != null) { if (attr != null) {
return attr.getValue(); return attr.getValue();
@ -1043,9 +1074,9 @@ public class MetadataParser {
throws XMLStreamException; throws XMLStreamException;
} }
class DefaultReferenceResolver implements ReferenceResolver{ private static class DefaultReferenceResolver implements ReferenceResolver {
@Override @Override
public SchemaBasedEdmProvider resolveReference(URI referenceUri, String xmlBase) { public InputStream resolveReference(URI referenceUri, String xmlBase) {
URL schemaURL = null; URL schemaURL = null;
try { try {
if (referenceUri.isAbsolute()) { if (referenceUri.isAbsolute()) {
@ -1057,14 +1088,9 @@ public class MetadataParser {
throw new EdmException("No xml:base set to read the references from the metadata"); throw new EdmException("No xml:base set to read the references from the metadata");
} }
} }
return schemaURL.openStream();
XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
XMLEventReader reader = xmlInputFactory.createXMLEventReader(schemaURL.openStream());
return buildEdmProvider(reader);
} catch (MalformedURLException e) { } catch (MalformedURLException e) {
throw new EdmException(e); throw new EdmException(e);
} catch (XMLStreamException e) {
throw new EdmException(e);
} catch (IOException e) { } catch (IOException e) {
throw new EdmException(e); throw new EdmException(e);
} }

View File

@ -18,6 +18,7 @@
*/ */
package org.apache.olingo.server.core; package org.apache.olingo.server.core;
import java.io.InputStream;
import java.net.URI; import java.net.URI;
public interface ReferenceResolver { public interface ReferenceResolver {
@ -28,5 +29,5 @@ public interface ReferenceResolver {
* @param xmlBase xml:base if provided by the metadata document; null otherwise * @param xmlBase xml:base if provided by the metadata document; null otherwise
* @return * @return
*/ */
SchemaBasedEdmProvider resolveReference(URI referenceUri, String xmlBase); InputStream resolveReference(URI referenceUri, String xmlBase);
} }

View File

@ -18,11 +18,15 @@
*/ */
package org.apache.olingo.server.core; package org.apache.olingo.server.core;
import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import javax.xml.stream.XMLStreamException;
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.provider.CsdlAction; import org.apache.olingo.commons.api.edm.provider.CsdlAction;
import org.apache.olingo.commons.api.edm.provider.CsdlActionImport; import org.apache.olingo.commons.api.edm.provider.CsdlActionImport;
@ -61,14 +65,25 @@ public class SchemaBasedEdmProvider implements CsdlEdmProvider {
this.edmSchemas.add(schema); this.edmSchemas.add(schema);
} }
private CsdlSchema getSchema(String ns) { List<EdmxReference> getReferences(){
return new ArrayList<EdmxReference>(references.values());
}
CsdlSchema getSchema(String ns) {
return getSchema(ns, true);
}
CsdlSchema getSchema(String ns, boolean checkReferences) {
for (CsdlSchema s : this.edmSchemas) { for (CsdlSchema s : this.edmSchemas) {
if (s.getNamespace().equals(ns)) { if (s.getNamespace().equals(ns)) {
return s; return s;
} }
} }
if (checkReferences) {
return getReferenceSchema(ns); return getReferenceSchema(ns);
} }
return null;
}
private CsdlSchema getReferenceSchema(String ns) { private CsdlSchema getReferenceSchema(String ns) {
if (ns == null) { if (ns == null) {
@ -77,7 +92,23 @@ public class SchemaBasedEdmProvider implements CsdlEdmProvider {
if (this.referenceSchemas.get(ns) == null) { if (this.referenceSchemas.get(ns) == null) {
EdmxReference reference = this.references.get(ns); EdmxReference reference = this.references.get(ns);
if (reference != null) { if (reference != null) {
SchemaBasedEdmProvider provider = this.referenceResolver.resolveReference(reference.getUri(), xmlBase); SchemaBasedEdmProvider provider = null;
if (this.referenceResolver == null) {
throw new EdmException("Failed to load Reference "+reference.getUri());
} else {
InputStream is = this.referenceResolver.resolveReference(reference.getUri(), this.xmlBase);
if (is != null) {
try {
MetadataParser parser = new MetadataParser();
provider = parser.buildEdmProvider(is, this.referenceResolver, false);
} catch (XMLStreamException e) {
throw new EdmException("Failed to load Reference "+reference.getUri()+" parsing failed");
}
} else {
throw new EdmException("Failed to load Reference "+reference.getUri()+" loading failed");
}
}
// copy references
for (EdmxReferenceInclude include : reference.getIncludes()) { for (EdmxReferenceInclude include : reference.getIncludes()) {
this.referenceSchemas.put(include.getNamespace(), provider); this.referenceSchemas.put(include.getNamespace(), provider);
if (include.getAlias() != null) { if (include.getAlias() != null) {

View File

@ -0,0 +1,388 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<!--
OData Version 4.0 Plus Errata 02
OASIS Standard incorporating Approved Errata 02
30 October 2014
Copyright (c) OASIS Open 2014. All Rights Reserved.
Source: http://docs.oasis-open.org/odata/odata/v4.0/errata02/os/complete/vocabularies/
-->
<!--
Technical Committee:
OASIS Open Data Protocol (OData) TC
https://www.oasis-open.org/committees/odata
Chairs:
- Barbara Hartel (barbara.hartel@sap.com), SAP AG
- Ram Jeyaraman (Ram.Jeyaraman@microsoft.com), Microsoft
Editors:
- Ralf Handl (ralf.handl@sap.com), SAP AG
- Michael Pizzo (mikep@microsoft.com), Microsoft
- Martin Zurmuehl (martin.zurmuehl@sap.com), SAP AG
Additional artifacts:
This CSDL document is one component of a Work Product which consists of:
- OData Version 4.0 Part 1: Protocol
- OData Version 4.0 Part 2: URL Conventions
- OData Version 4.0 Part 3: Common Schema Definition Language (CSDL)
- OData ABNF Construction Rules Version 4.0
- OData ABNF Test Cases
- OData Core Vocabulary
- OData Capabilities Vocabulary (this document)
- OData Measures Vocabulary
- OData Metadata Service Entity Model
- OData EDMX XML Schema
- OData EDM XML Schema
Related work:
This work product is related to the following two Work Products, each of
which define alternate formats for OData payloads
- OData Atom Format Version 4.0
- OData JSON Format Version 4.0
This specification replaces or supersedes:
- None
Declared XML namespaces:
- http://docs.oasis-open.org/odata/ns/edmx
- http://docs.oasis-open.org/odata/ns/edm
Abstract:
The Open Data Protocol (OData) enables the creation of REST-based data
services, which allow resources, identified using Uniform Resource
Identifiers (URLs) and defined in a data model, to be published and
edited by Web clients using simple HTTP messages. This document defines
the URL syntax for requests and the serialization format for primitive
literals in request and response payloads.
Overview:
This document contains terms describing capabilities of an OData service.
-->
<edmx:Edmx xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" Version="4.0">
<edmx:Reference Uri="http://docs.oasis-open.org/odata/odata/v4.0/os/vocabularies/Org.OData.Core.V1.xml">
<edmx:Include Alias="Core" Namespace="Org.OData.Core.V1" />
</edmx:Reference>
<edmx:DataServices>
<Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="Org.OData.Capabilities.V1" Alias="Capabilities">
<Annotation Term="Core.Description">
<String>
The Capabilities vocabulary aims to provide a way for service authors to describe
certain capabilities of an OData Service.
</String>
</Annotation>
<Annotation Term="Core.LongDescription">
<String>
There are some capabilities which are strongly recommended for services to support even
though they are optional. Support for $top and $skip is a good example as
supporting these query options helps with performance of a service and are essential. Such
capabilities are assumed to be default capabilities of an OData service even in
the case that a capabilities annotation doesnt exist. Capabilities annotations are
mainly expected to be used to explicitly specify that a service doesnt support such
capabilities. Capabilities annotations can as well be used to declaratively
specify the support of such capabilities.
On the other hand, there are some capabilities that a service may choose to support or
not support and in varying degrees. $filter and $orderby are such good examples.
This vocabulary aims to define terms to specify support or no support for such
capabilities.
A service is assumed to support by default the following capabilities even though an
annotation doesnt exist:
- Countability ($count)
- Client pageability ($top, $skip)
- Expandability ($expand)
- Indexability by key
- Batch support ($batch)
- Navigability of navigation properties
A service is expected to support the following capabilities. If not supported, the
service is expected to call out the restrictions using annotations:
- Filterability ($filter)
- Sortability ($orderby)
- Queryability of top level entity sets
- Query functions
A client cannot assume that a service supports certain capabilities. A client can try, but
it needs to be prepared to handle an error in case the following capabilities are not
supported:
- Insertability
- Updatability
- Deletability
</String>
</Annotation>
<!-- Conformance Level -->
<Term Name="ConformanceLevel" Type="Capabilities.ConformanceLevelType" AppliesTo="EntityContainer" />
<EnumType Name="ConformanceLevelType">
<Member Name="Minimal" />
<Member Name="Intermediate" />
<Member Name="Advanced" />
</EnumType>
<!-- Request Capabilities -->
<Term Name="SupportedFormats" Type="Collection(Edm.String)">
<Annotation Term="Core.Description" String="Media types of supported formats, including format parameters" />
<Annotation Term="Core.IsMediaType" />
</Term>
<Term Name="AcceptableEncodings" Type="Collection(Edm.String)" AppliesTo="EntityContainer">
<Annotation Term="Core.Description" String="List of acceptable compression methods for ($batch) requests, e.g. gzip" />
</Term>
<!-- Supported Preferences -->
<Term Name="AsynchronousRequestsSupported" Type="Core.Tag" DefaultValue="true" AppliesTo="EntityContainer">
<Annotation Term="Core.Description" String="Service supports the asynchronous request preference" />
</Term>
<Term Name="BatchContinueOnErrorSupported" Type="Core.Tag" DefaultValue="true" AppliesTo="EntityContainer">
<Annotation Term="Core.Description" String="Service supports the continue on error preference" />
</Term>
<Term Name="IsolationSupported" Type="Capabilities.IsolationLevel" AppliesTo="EntityContainer">
<Annotation Term="Core.Description" String="Supported odata.isolation levels" />
</Term>
<EnumType Name="IsolationLevel" IsFlags="true">
<Member Name="Snapshot" Value="1" />
</EnumType>
<Term Name="CallbackSupported" Type="Capabilities.CallbackType" AppliesTo="EntityContainer EntitySet">
<Annotation Term="Core.Description" String="Supports callbacks for the specified protocols" />
</Term>
<Term Name="CrossJoinSupported" Type="Core.Tag" DefaultValue="true" AppliesTo="EntityContainer">
<Annotation Term="Core.Description" String="Supports cross joins for the entity sets in this container" />
</Term>
<ComplexType Name="CallbackType">
<Property Name="CallbackProtocols" Type="Collection(Capabilities.CallbackProtocol)" />
<Annotation Term="Core.Description"
String="A non-empty collection lists the full set of supported protocols. A empty collection means 'only HTTP is supported'" />
</ComplexType>
<ComplexType Name="CallbackProtocol">
<Property Name="Id" Type="Edm.String">
<Annotation Term="Core.Description" String="Protcol Identifier" />
</Property>
<Property Name="UrlTemplate" Type="Edm.String">
<Annotation Term="Core.Description"
String="URL Template including parameters. Parameters are enclosed in curly braces {} as defined in RFC6570" />
</Property>
<Property Name="DocumentationUrl" Type="Edm.String" Nullable="true">
<Annotation Term="Core.Description" String="Human readable description of the meaning of the URL Template parameters" />
<Annotation Term="Core.IsURL" />
</Property>
</ComplexType>
<Term Name="ChangeTracking" Type="Capabilities.ChangeTrackingType" AppliesTo="EntityContainer EntitySet">
<Annotation Term="Core.Description" String="Change tracking capabilities of this service or entity set" />
</Term>
<ComplexType Name="ChangeTrackingType">
<Property Name="Supported" Type="Edm.Boolean" DefaultValue="true">
<Annotation Term="Core.Description" String="This entity set supports the odata.track-changes preference" />
</Property>
<Property Name="FilterableProperties" Type="Collection(Edm.PropertyPath)">
<Annotation Term="Core.Description" String="Change tracking supports filters on these properties" />
</Property>
<Property Name="ExpandableProperties" Type="Collection(Edm.NavigationPropertyPath)">
<Annotation Term="Core.Description" String="Change tracking supports these properties expanded" />
</Property>
</ComplexType>
<!--Query Capabilities -->
<Term Name="CountRestrictions" Type="Capabilities.CountRestrictionsType" AppliesTo="EntitySet">
<Annotation Term="Core.Description" String="Restrictions on /$count path suffix and $count=true system query option" />
</Term>
<ComplexType Name="CountRestrictionsType">
<Property Name="Countable" Type="Edm.Boolean" DefaultValue="true">
<Annotation Term="Core.Description" String="Entities can be counted" />
</Property>
<Property Name="NonCountableProperties" Type="Collection(Edm.PropertyPath)">
<Annotation Term="Core.Description" String="These collection properties do not allow /$count segments" />
</Property>
<Property Name="NonCountableNavigationProperties" Type="Collection(Edm.NavigationPropertyPath)">
<Annotation Term="Core.Description" String="These navigation properties do not allow /$count segments" />
</Property>
</ComplexType>
<Term Name="NavigationRestrictions" Type="Capabilities.NavigationRestrictionsType" AppliesTo="EntitySet">
<Annotation Term="Core.Description" String="Restrictions on navigating properties according to OData URL conventions" />
</Term>
<ComplexType Name="NavigationRestrictionsType">
<Property Name="Navigability" Type="Capabilities.NavigationType">
<Annotation Term="Core.Description" String="Supported Navigability" />
</Property>
<Property Name="RestrictedProperties" Type="Collection(Capabilities.NavigationPropertyRestriction)" />
</ComplexType>
<ComplexType Name="NavigationPropertyRestriction">
<Property Name="NavigationProperty" Type="Edm.NavigationPropertyPath">
<Annotation Term="Core.Description" String="Navigation properties can be navigated" />
</Property>
<Property Name="Navigability" Type="Capabilities.NavigationType">
<Annotation Term="Core.Description" String="Navigation properties can be navigated to this level" />
</Property>
</ComplexType>
<EnumType Name="NavigationType">
<Member Name="Recursive">
<Annotation Term="Core.Description" String="Navigation properties can be recursively navigated" />
</Member>
<Member Name="Single">
<Annotation Term="Core.Description" String="Navigation properties can be navigated to a single level" />
</Member>
<Member Name="None">
<Annotation Term="Core.Description" String="Navigation properties are not navigable" />
</Member>
</EnumType>
<Term Name="IndexableByKey" Type="Core.Tag" DefaultValue="true" AppliesTo="EntitySet">
<Annotation Term="Core.Description" String="Supports key values according to OData URL conventions" />
</Term>
<Term Name="TopSupported" Type="Core.Tag" DefaultValue="true" AppliesTo="EntitySet">
<Annotation Term="Core.Description" String="Supports $top" />
</Term>
<Term Name="SkipSupported" Type="Core.Tag" DefaultValue="true" AppliesTo="EntitySet">
<Annotation Term="Core.Description" String="Supports $skip" />
</Term>
<Term Name="BatchSupported" Type="Core.Tag" DefaultValue="true" AppliesTo="EntityContainer">
<Annotation Term="Core.Description" String="Supports $batch requests" />
</Term>
<Term Name="FilterFunctions" Type="Collection(Edm.String)" AppliesTo="EntityContainer EntitySet">
<Annotation Term="Core.Description" String="List of functions supported in $filter" />
</Term>
<Term Name="FilterRestrictions" Type="Capabilities.FilterRestrictionsType" AppliesTo="EntitySet">
<Annotation Term="Core.Description" String="Restrictions on $filter expressions" />
</Term>
<ComplexType Name="FilterRestrictionsType">
<Property Name="Filterable" Type="Edm.Boolean" DefaultValue="true">
<Annotation Term="Core.Description" String="$filter is supported" />
</Property>
<Property Name="RequiresFilter" Type="Edm.Boolean" Nullable="true">
<Annotation Term="Core.Description" String="$filter is required" />
</Property>
<Property Name="RequiredProperties" Type="Collection(Edm.PropertyPath)">
<Annotation Term="Core.Description"
String="These properties must be specified in the $filter clause (properties of derived types are not allowed here)" />
</Property>
<Property Name="NonFilterableProperties" Type="Collection(Edm.PropertyPath)">
<Annotation Term="Core.Description" String="These properties cannot be used in $filter expressions" />
</Property>
</ComplexType>
<Term Name="SortRestrictions" Type="Capabilities.SortRestrictionsType" AppliesTo="EntitySet">
<Annotation Term="Core.Description" String="Restrictions on $orderby expressions" />
</Term>
<ComplexType Name="SortRestrictionsType">
<Property Name="Sortable" Type="Edm.Boolean" DefaultValue="true">
<Annotation Term="Core.Description" String="$orderby is supported" />
</Property>
<Property Name="AscendingOnlyProperties" Type="Collection(Edm.PropertyPath)">
<Annotation Term="Core.Description" String="These properties can only be used for sorting in Ascending order" />
</Property>
<Property Name="DescendingOnlyProperties" Type="Collection(Edm.PropertyPath)">
<Annotation Term="Core.Description" String="These properties can only be used for sorting in Descending order" />
</Property>
<Property Name="NonSortableProperties" Type="Collection(Edm.PropertyPath)">
<Annotation Term="Core.Description" String="These properties cannot be used in $orderby expressions" />
</Property>
</ComplexType>
<Term Name="ExpandRestrictions" Type="Capabilities.ExpandRestrictionsType" AppliesTo="EntitySet">
<Annotation Term="Core.Description" String="Restrictions on $expand expressions" />
</Term>
<ComplexType Name="ExpandRestrictionsType">
<Property Name="Expandable" Type="Edm.Boolean" DefaultValue="true">
<Annotation Term="Core.Description" String="$expand is supported" />
</Property>
<Property Name="NonExpandableProperties" Type="Collection(Edm.NavigationPropertyPath)">
<Annotation Term="Core.Description" String="These properties cannot be used in $expand expressions" />
</Property>
</ComplexType>
<Term Name="SearchRestrictions" Type="Capabilities.SearchRestrictionsType" AppliesTo="EntitySet">
<Annotation Term="Core.Description" String="Restrictions on $search expressions" />
</Term>
<ComplexType Name="SearchRestrictionsType">
<Property Name="Searchable" Type="Edm.Boolean" DefaultValue="true">
<Annotation Term="Core.Description" String="$search is supported" />
</Property>
<Property Name="UnsupportedExpressions" Type="Capabilities.SearchExpressions" DefaultValue="none">
<Annotation Term="Core.Description" String="Expressions supported in $search" />
</Property>
</ComplexType>
<EnumType Name="SearchExpressions" IsFlags="true">
<Member Name="none" Value="0" />
<Member Name="AND" Value="1" />
<Member Name="OR" Value="2" />
<Member Name="NOT" Value="4" />
<Member Name="phrase" Value="8" />
<Member Name="group" Value="16" />
</EnumType>
<!-- Data Modification Capabilities -->
<Term Name="InsertRestrictions" Type="Capabilities.InsertRestrictionsType" AppliesTo="EntitySet">
<Annotation Term="Core.Description" String="Restrictions on insert operations" />
</Term>
<ComplexType Name="InsertRestrictionsType">
<Property Name="Insertable" Type="Edm.Boolean" DefaultValue="true">
<Annotation Term="Core.Description" String="Entities can be inserted" />
</Property>
<Property Name="NonInsertableNavigationProperties" Type="Collection(Edm.NavigationPropertyPath)">
<Annotation Term="Core.Description" String="These navigation properties do not allow deep inserts" />
</Property>
</ComplexType>
<Term Name="UpdateRestrictions" Type="Capabilities.UpdateRestrictionsType" AppliesTo="EntitySet">
<Annotation Term="Core.Description" String="Restrictions on update operations" />
</Term>
<ComplexType Name="UpdateRestrictionsType">
<Property Name="Updatable" Type="Edm.Boolean" DefaultValue="true">
<Annotation Term="Core.Description" String="Entities can be updated" />
</Property>
<Property Name="NonUpdatableNavigationProperties" Type="Collection(Edm.NavigationPropertyPath)">
<Annotation Term="Core.Description" String="These navigation properties do not allow rebinding" />
</Property>
</ComplexType>
<Term Name="DeleteRestrictions" Type="Capabilities.DeleteRestrictionsType" AppliesTo="EntitySet">
<Annotation Term="Core.Description" String="Restrictions on delete operations" />
</Term>
<ComplexType Name="DeleteRestrictionsType">
<Property Name="Deletable" Type="Edm.Boolean" DefaultValue="true">
<Annotation Term="Core.Description" String="Entities can be deleted" />
</Property>
<Property Name="NonDeletableNavigationProperties" Type="Collection(Edm.NavigationPropertyPath)">
<Annotation Term="Core.Description" String="These navigation properties do not allow DeleteLink requests" />
</Property>
</ComplexType>
</Schema>
</edmx:DataServices>
</edmx:Edmx>

View File

@ -0,0 +1,187 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<!--
OData Version 4.0 Plus Errata 02
OASIS Standard incorporating Approved Errata 02
30 October 2014
Copyright (c) OASIS Open 2014. All Rights Reserved.
Source: http://docs.oasis-open.org/odata/odata/v4.0/errata02/os/complete/vocabularies/
-->
<!--
Technical Committee:
OASIS Open Data Protocol (OData) TC
https://www.oasis-open.org/committees/odata
Chairs:
- Barbara Hartel (barbara.hartel@sap.com), SAP AG
- Ram Jeyaraman (Ram.Jeyaraman@microsoft.com), Microsoft
Editors:
- Ralf Handl (ralf.handl@sap.com), SAP AG
- Michael Pizzo (mikep@microsoft.com), Microsoft
- Martin Zurmuehl (martin.zurmuehl@sap.com), SAP AG
Additional artifacts:
This CSDL document is one component of a Work Product which consists of:
- OData Version 4.0 Part 1: Protocol
- OData Version 4.0 Part 2: URL Conventions
- OData Version 4.0 Part 3: Common Schema Definition Language (CSDL)
- OData ABNF Construction Rules Version 4.0
- OData ABNF Test Cases
- OData Core Vocabulary (this document)
- OData Capabilities Vocabulary
- OData Measures Vocabulary
- OData Metadata Service Entity Model
- OData EDMX XML Schema
- OData EDM XML Schema
Related work:
This work product is related to the following two Work Products, each of
which define alternate formats for OData payloads
- OData Atom Format Version 4.0
- OData JSON Format Version 4.0
This specification replaces or supersedes:
- None
Declared XML namespaces:
- http://docs.oasis-open.org/odata/ns/edmx
- http://docs.oasis-open.org/odata/ns/edm
Abstract:
The Open Data Protocol (OData) enables the creation of REST-based data
services, which allow resources, identified using Uniform Resource
Identifiers (URLs) and defined in a data model, to be published and
edited by Web clients using simple HTTP messages. This document defines
the URL syntax for requests and the serialization format for primitive
literals in request and response payloads.
Overview:
This document contains Core terms needed to write vocabularies.
-->
<edmx:Edmx xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" Version="4.0">
<edmx:DataServices>
<Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="Org.OData.Core.V1" Alias="Core">
<Annotation Term="Core.Description">
<String>Core terms needed to write vocabularies</String>
</Annotation>
<!--Documentation -->
<Term Name="Description" Type="Edm.String">
<Annotation Term="Core.Description" String="A brief description of a model element" />
<Annotation Term="Core.IsLanguageDependent" />
</Term>
<Term Name="LongDescription" Type="Edm.String">
<Annotation Term="Core.Description" String="A lengthy description of a model element" />
<Annotation Term="Core.IsLanguageDependent" />
</Term>
<!-- Localization -->
<Term Name="IsLanguageDependent" Type="Core.Tag" DefaultValue="true" AppliesTo="Term Property">
<Annotation Term="Core.Description" String="Properties and terms annotated with this term are language-dependent" />
<Annotation Term="Core.RequiresType" String="Edm.String" />
</Term>
<!-- Term Restrictions -->
<TypeDefinition Name="Tag" UnderlyingType="Edm.Boolean">
<Annotation Term="Core.Description" String="This is the type to use for all tagging terms" />
</TypeDefinition>
<Term Name="RequiresType" Type="Edm.String" AppliesTo="Term">
<Annotation Term="Core.Description"
String="Terms annotated with this term can only be applied to elements that have a type that is identical to or derived from the given type name" />
</Term>
<!--Resource Paths -->
<Term Name="ResourcePath" Type="Edm.String" AppliesTo="EntitySet Singleton ActionImport FunctionImport">
<Annotation Term="Core.Description"
String="Resource path for entity container child, can be relative to xml:base and the request URL" />
<Annotation Term="Core.IsUrl" />
</Term>
<Term Name="DereferenceableIDs" Type="Core.Tag" DefaultValue="true" AppliesTo="EntityContainer">
<Annotation Term="Core.Description" String="Entity-ids are URLs that locate the identified entity" />
</Term>
<Term Name="ConventionalIDs" Type="Core.Tag" DefaultValue="true" AppliesTo="EntityContainer">
<Annotation Term="Core.Description" String="Entity-ids follow OData URL conventions" />
</Term>
<!-- Permissions -->
<Term Name="Permissions" Type="Core.Permission" AppliesTo="Property">
<Annotation Term="Core.Description" String="Permissions available for a property.The value of 2 is reserved for future use." />
</Term>
<EnumType Name="Permission" IsFlags="true">
<Member Name="None" Value="0" />
<Member Name="Read" Value="1" />
<Member Name="ReadWrite" Value="3" />
</EnumType>
<!-- Metadata Extensions -->
<Term Name="Immutable" Type="Core.Tag" DefaultValue="true" AppliesTo="Property">
<Annotation Term="Core.Description"
String="A value for this non-key property can be provided on insert and remains unchanged on update" />
</Term>
<Term Name="Computed" Type="Core.Tag" DefaultValue="true" AppliesTo="Property">
<Annotation Term="Core.Description" String="A value for this property is generated on both insert and update" />
</Term>
<Term Name="IsURL" Type="Core.Tag" DefaultValue="true" AppliesTo="Property Term">
<Annotation Term="Core.Description" String="Properties and terms annotated with this term MUST contain a valid URL" />
<Annotation Term="Core.RequiresType" String="Edm.String" />
</Term>
<Term Name="AcceptableMediaTypes" Type="Collection(Edm.String)" AppliesTo="EntityType Property">
<Annotation Term="Core.Description"
String="Lists the MIME types acceptable for the annotated entity type marked with HasStream=&quot;true&quot; or the annotated stream property" />
<Annotation Term="Core.IsMediaType" />
</Term>
<Term Name="MediaType" Type="Edm.String" AppliesTo="Property">
<Annotation Term="Core.IsMediaType" />
<Annotation Term="Core.RequiresType" String="Edm.Binary" />
</Term>
<Term Name="IsMediaType" Type="Core.Tag" DefaultValue="true" AppliesTo="Property Term">
<Annotation Term="Core.Description" String="Properties and terms annotated with this term MUST contain a valid MIME type" />
<Annotation Term="Core.RequiresType" String="Edm.String" />
</Term>
<Term Name="OptimisticConcurrency" Type="Collection(Edm.PropertyPath)" AppliesTo="EntitySet">
<Annotation Term="Core.Description"
String="Data modification requires the use of Etags. A non-empty collection contains the set of properties that are used to compute the ETag" />
</Term>
</Schema>
</edmx:DataServices>
</edmx:Edmx>

View File

@ -0,0 +1,110 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<!--
OData Version 4.0 Plus Errata 02
OASIS Standard incorporating Approved Errata 02
30 October 2014
Copyright (c) OASIS Open 2014. All Rights Reserved.
Source: http://docs.oasis-open.org/odata/odata/v4.0/errata02/os/complete/vocabularies/
-->
<!--
Technical Committee:
OASIS Open Data Protocol (OData) TC
https://www.oasis-open.org/committees/odata
Chairs:
- Barbara Hartel (barbara.hartel@sap.com), SAP AG
- Ram Jeyaraman (Ram.Jeyaraman@microsoft.com), Microsoft
Editors:
- Ralf Handl (ralf.handl@sap.com), SAP AG
- Michael Pizzo (mikep@microsoft.com), Microsoft
- Martin Zurmuehl (martin.zurmuehl@sap.com), SAP AG
Additional artifacts:
This CSDL document is one component of a Work Product which consists of:
- OData Version 4.0 Part 1: Protocol
- OData Version 4.0 Part 2: URL Conventions
- OData Version 4.0 Part 3: Common Schema Definition Language (CSDL)
- OData ABNF Construction Rules Version 4.0
- OData ABNF Test Cases
- OData Core Vocabulary
- OData Capabilities Vocabulary
- OData Measures Vocabulary (this document)
- OData Metadata Service Entity Model
- OData EDMX XML Schema
- OData EDM XML Schema
Related work:
This work product is related to the following two Work Products, each of
which define alternate formats for OData payloads
- OData Atom Format Version 4.0
- OData JSON Format Version 4.0
This specification replaces or supersedes:
- None
Declared XML namespaces:
- http://docs.oasis-open.org/odata/ns/edmx
- http://docs.oasis-open.org/odata/ns/edm
Abstract:
The Open Data Protocol (OData) enables the creation of REST-based data
services, which allow resources, identified using Uniform Resource
Identifiers (URLs) and defined in a data model, to be published and
edited by Web clients using simple HTTP messages. This document defines
the URL syntax for requests and the serialization format for primitive
literals in request and response payloads.
Overview:
This document contains terms describing monetary amounts and measured quantities.
-->
<edmx:Edmx xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" Version="4.0">
<edmx:Reference Uri="http://docs.oasis-open.org/odata/odata/v4.0/os/vocabularies/Org.OData.Core.V1.xml">
<edmx:Include Alias="Core" Namespace="Org.OData.Core.V1" />
</edmx:Reference>
<edmx:DataServices>
<Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="Org.OData.Measures.V1" Alias="Measures">
<Annotation Term="Core.Description">
<String>Terms describing monetary amounts and measured quantities</String>
</Annotation>
<Term Name="ISOCurrency" Type="Edm.String" AppliesTo="Property">
<Annotation Term="Core.Description" String="The currency for this monetary amount as an ISO 4217 currency code" />
</Term>
<Term Name="Scale" Type="Edm.Byte" AppliesTo="Property">
<Annotation Term="Core.Description"
String="The number of significant decimal places in the scale part (less than or equal to the number declared in the Scale facet)" />
<Annotation Term="Core.RequiresType" String="Edm.Decimal" />
</Term>
<Term Name="Unit" Type="Edm.String" AppliesTo="Property">
<Annotation Term="Core.Description" String="The unit of measure for this measured quantity, e.g. cm for centimeters or % for percentages" />
</Term>
</Schema>
</edmx:DataServices>
</edmx:Edmx>

View File

@ -51,7 +51,7 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
public class MetadataParserAnnotationsTest { public class MetadataParserAnnotationsTest {
final String NS = "Org.OData.Core.V1"; final String NS = "Org.OData.AnnoatationTest";
final FullQualifiedName NSF = new FullQualifiedName(NS); final FullQualifiedName NSF = new FullQualifiedName(NS);
CsdlEdmProvider provider = null; CsdlEdmProvider provider = null;
@ -59,7 +59,8 @@ public class MetadataParserAnnotationsTest {
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
MetadataParser parser = new MetadataParser(); MetadataParser parser = new MetadataParser();
parser.setParseAnnotations(true); parser.parseAnnotations(true);
parser.loadCoreVocabularies(true);
provider = (CsdlEdmProvider) parser.buildEdmProvider(new FileReader("src/test/resources/annotations.xml")); provider = (CsdlEdmProvider) parser.buildEdmProvider(new FileReader("src/test/resources/annotations.xml"));
} }
@ -205,4 +206,10 @@ public class MetadataParserAnnotationsTest {
CsdlTerm term = this.provider.getTerm(new FullQualifiedName(NS, "IsURI")); CsdlTerm term = this.provider.getTerm(new FullQualifiedName(NS, "IsURI"));
assertEquals(Arrays.asList("Property", "PropertyPath"), term.getAppliesTo()); assertEquals(Arrays.asList("Property", "PropertyPath"), term.getAppliesTo());
} }
@Test
public void checkCoreVocabularies() throws ODataException {
CsdlTerm term = this.provider.getTerm(new FullQualifiedName("Org.OData.Core.V1", "Description"));
assertEquals("Edm.String", term.getType());
}
} }

View File

@ -54,7 +54,7 @@ public class MetadataParserTest {
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
MetadataParser parser = new MetadataParser(); MetadataParser parser = new MetadataParser();
parser.setParseAnnotations(true); parser.parseAnnotations(true);
provider = (CsdlEdmProvider) parser.buildEdmProvider(new FileReader("src/test/resources/trippin.xml")); provider = (CsdlEdmProvider) parser.buildEdmProvider(new FileReader("src/test/resources/trippin.xml"));
} }

View File

@ -50,6 +50,8 @@ public class TripPinServlet extends HttpServlet {
ServiceMetadata metadata = null; ServiceMetadata metadata = null;
try { try {
parser.parseAnnotations(true);
parser.loadCoreVocabularies(true);
metadata = parser.buildServiceMetadata(new FileReader("src/test/resources/trippin.xml")); metadata = parser.buildServiceMetadata(new FileReader("src/test/resources/trippin.xml"));
} catch (XMLStreamException e) { } catch (XMLStreamException e) {
throw new IOException(e); throw new IOException(e);

View File

@ -13,7 +13,7 @@
Version="4.0"> Version="4.0">
<edmx:DataServices> <edmx:DataServices>
<Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm"
Namespace="Org.OData.Core.V1" Alias="Core"> Namespace="Org.OData.AnnoatationTest" Alias="test">
<Annotation Term="Core.Description"> <Annotation Term="Core.Description">
<String>Core terms needed to write vocabularies</String> <String>Core terms needed to write vocabularies</String>