[OLINGO-1062]Cannot consume Term defined in external Vocabulary
This commit is contained in:
parent
aea44a33a0
commit
ce4bc57a84
|
@ -29,9 +29,12 @@ import static org.junit.Assert.assertTrue;
|
|||
import static org.junit.Assert.fail;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.math.BigDecimal;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
|
@ -83,9 +86,12 @@ import org.apache.olingo.commons.api.edm.EdmActionImport;
|
|||
import org.apache.olingo.commons.api.edm.EdmAnnotation;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntityContainer;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntitySet;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntityType;
|
||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
|
||||
import org.apache.olingo.commons.api.edm.EdmProperty;
|
||||
import org.apache.olingo.commons.api.edm.EdmTerm;
|
||||
import org.apache.olingo.commons.api.edm.FullQualifiedName;
|
||||
import org.apache.olingo.commons.api.edm.annotation.EdmExpression;
|
||||
import org.apache.olingo.commons.api.ex.ODataError;
|
||||
import org.apache.olingo.commons.api.format.ContentType;
|
||||
import org.apache.olingo.commons.api.http.HttpHeader;
|
||||
|
@ -116,6 +122,8 @@ public class BasicITCase extends AbstractParamTecSvcITCase {
|
|||
private static final String COL_PROPERTY_COMP = "CollPropertyComp";
|
||||
private static final String PROPERTY_COMP_TWO_PRIM = "PropertyCompTwoPrim";
|
||||
|
||||
private static final String SERVICE_ROOT_URL = "http://localhost:9080/odata-server-tecsvc/";
|
||||
|
||||
@Test
|
||||
public void readServiceDocument() {
|
||||
ODataServiceDocumentRequest request = getClient().getRetrieveRequestFactory()
|
||||
|
@ -1603,4 +1611,57 @@ public class BasicITCase extends AbstractParamTecSvcITCase {
|
|||
getEntities().get(1).getTypeName().toString());
|
||||
assertEquals("olingo.odata.test1.ETAllPrim", entity.getTypeName().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readViaXmlMetadataAnnotation() throws URISyntaxException, IOException {
|
||||
InputStream input = Thread.currentThread().getContextClassLoader().
|
||||
getResourceAsStream("edmxWithCoreAnnotation.xml");
|
||||
final XMLMetadata metadata = getClient().getDeserializer(ContentType.APPLICATION_XML).toMetadata(input);
|
||||
String vocabUrl = metadata.getReferences().get(0).getUri().toString();
|
||||
vocabUrl = vocabUrl.substring(vocabUrl.indexOf("../") + 3);
|
||||
vocabUrl = SERVICE_ROOT_URL + vocabUrl;
|
||||
URI uri = new URI(vocabUrl);
|
||||
input.close();
|
||||
ODataRawRequest request = getClient().getRetrieveRequestFactory().getRawRequest(uri);
|
||||
assertNotNull(request);
|
||||
setCookieHeader(request);
|
||||
|
||||
ODataRawResponse response = request.execute();
|
||||
saveCookieHeader(response);
|
||||
assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode());
|
||||
|
||||
List<InputStream> streams = new ArrayList<InputStream>();
|
||||
streams.add(response.getRawResponse());
|
||||
Edm edm = getClient().getReader().readMetadata(Thread.currentThread().getContextClassLoader().
|
||||
getResourceAsStream("edmxWithCoreAnnotation.xml"), streams);
|
||||
assertNotNull(edm);
|
||||
final EdmEntityType person = edm.getEntityType(
|
||||
new FullQualifiedName("Microsoft.Exchange.Services.OData.Model", "Person"));
|
||||
assertNotNull(person);
|
||||
EdmProperty concurrency = (EdmProperty) person.getProperty("Concurrency");
|
||||
List<EdmAnnotation> annotations = concurrency.getAnnotations();
|
||||
for (EdmAnnotation annotation : annotations) {
|
||||
annotation.getExpression();
|
||||
EdmTerm term = annotation.getTerm();
|
||||
assertNotNull(term);
|
||||
assertEquals("Computed", term.getName());
|
||||
assertEquals("Org.OData.Core.V1.Computed",
|
||||
term.getFullQualifiedName().getFullQualifiedNameAsString());
|
||||
assertEquals(1, term.getAnnotations().size());
|
||||
}
|
||||
EdmProperty userName = (EdmProperty) person.getProperty("UserName");
|
||||
List<EdmAnnotation> userNameAnnotations = userName.getAnnotations();
|
||||
for (EdmAnnotation annotation : userNameAnnotations) {
|
||||
EdmTerm term = annotation.getTerm();
|
||||
assertNotNull(term);
|
||||
assertEquals("Permissions", term.getName());
|
||||
assertEquals("Org.OData.Core.V1.Permissions",
|
||||
term.getFullQualifiedName().getFullQualifiedNameAsString());
|
||||
EdmExpression expression = annotation.getExpression();
|
||||
assertNotNull(expression);
|
||||
assertTrue(expression.isConstant());
|
||||
assertEquals("Org.OData.Core.V1.Permission/Read", expression.asConstant().getValueAsString());
|
||||
assertEquals("EnumMember", expression.getExpressionName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -182,4 +182,29 @@ public class BasicHttpITCase extends AbstractBaseTestITCase {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidTopUrl() throws Exception {
|
||||
URL url = new URL(SERVICE_URI + "?$top");
|
||||
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
connection.setRequestMethod(HttpMethod.GET.name());
|
||||
connection.connect();
|
||||
|
||||
assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), connection.getResponseCode());
|
||||
assertTrue(IOUtils.toString(connection.getErrorStream()).
|
||||
contains("The system query option '$top' has the not-allowed value ''."));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidSkipUrl() throws Exception {
|
||||
URL url = new URL(SERVICE_URI + "?$skip=");
|
||||
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
connection.setRequestMethod(HttpMethod.GET.name());
|
||||
connection.connect();
|
||||
|
||||
assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), connection.getResponseCode());
|
||||
assertTrue(IOUtils.toString(connection.getErrorStream()).
|
||||
contains("The system query option '$skip' has the not-allowed value ''."));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
<?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.
|
||||
|
||||
-->
|
||||
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
|
||||
<edmx:Reference Uri="../v4.0/cs02/vocabularies/Org.OData.Core.V1.xml"/>
|
||||
<edmx:DataServices m:DataServiceVersion="4.0" m:MaxDataServiceVersion="4.0" xmlns:m="http://docs.oasis-open.org/odata/ns/metadata">
|
||||
<Schema Namespace="Microsoft.Exchange.Services.OData.Model" xmlns="http://docs.oasis-open.org/odata/ns/edm">
|
||||
<EntityType Name="Person" OpenType="true">
|
||||
<Key>
|
||||
<PropertyRef Name="UserName"/>
|
||||
</Key>
|
||||
<Property Name="UserName" Type="Edm.String" Nullable="false">
|
||||
<Annotation Term="Org.OData.Core.V1.Permissions">
|
||||
<EnumMember>Org.OData.Core.V1.Permission/Read</EnumMember>
|
||||
</Annotation>
|
||||
</Property>
|
||||
<Property Name="FirstName" Type="Edm.String" Nullable="false"/>
|
||||
<Property Name="LastName" Type="Edm.String" Nullable="false"/>
|
||||
<Property Name="Emails" Type="Collection(Edm.String)"/>
|
||||
<Property Name="AddressInfo" Type="Collection(Microsoft.OData.SampleService.Models.TripPin.Location)"/>
|
||||
<Property Name="Gender" Type="Microsoft.OData.SampleService.Models.TripPin.PersonGender"/>
|
||||
<Property Name="Concurrency" Type="Edm.Int64" Nullable="false">
|
||||
<Annotation Term="Org.OData.Core.V1.Computed" Bool="true"/>
|
||||
</Property>
|
||||
</EntityType>
|
||||
<EntityContainer Name="EntityContainer" m:IsDefaultEntityContainer="true">
|
||||
<EntitySet Name="People" EntityType="Microsoft.Exchange.Services.OData.Model.Person"/>
|
||||
</EntityContainer>
|
||||
</Schema>
|
||||
</edmx:DataServices>
|
||||
</edmx:Edmx>
|
|
@ -19,16 +19,20 @@
|
|||
package org.apache.olingo.client.api.serialization;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.olingo.client.api.data.ResWrap;
|
||||
import org.apache.olingo.client.api.data.ServiceDocument;
|
||||
import org.apache.olingo.client.api.edm.xml.XMLMetadata;
|
||||
import org.apache.olingo.commons.api.data.Delta;
|
||||
import org.apache.olingo.commons.api.edm.provider.CsdlSchema;
|
||||
|
||||
public interface ClientODataDeserializer extends ODataDeserializer {
|
||||
|
||||
XMLMetadata toMetadata(InputStream input);
|
||||
|
||||
List<CsdlSchema> fetchTermDefinitionSchema(List<InputStream> input);
|
||||
|
||||
/**
|
||||
* Gets the ServiceDocument object represented by the given InputStream.
|
||||
*
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
package org.apache.olingo.client.api.serialization;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.olingo.client.api.data.ResWrap;
|
||||
|
@ -48,6 +49,15 @@ public interface ODataReader {
|
|||
*/
|
||||
Edm readMetadata(InputStream input);
|
||||
|
||||
/**
|
||||
* Parses a stream into metadata representation.
|
||||
* Also parses a term definition stream into Term representation.
|
||||
* @param input
|
||||
* @param termDefinitions
|
||||
* @return
|
||||
*/
|
||||
Edm readMetadata(InputStream input, List<InputStream> termDefinitions);
|
||||
|
||||
/**
|
||||
* Parses a stream into metadata representation, including referenced metadata documents.
|
||||
*
|
||||
|
@ -57,6 +67,8 @@ public interface ODataReader {
|
|||
*/
|
||||
Edm readMetadata(Map<String, CsdlSchema> xmlSchemas);
|
||||
|
||||
Edm readMetadata(Map<String, CsdlSchema> xmlSchemas, List<CsdlSchema> termDefinitionSchema);
|
||||
|
||||
/**
|
||||
* Parses an OData service document.
|
||||
*
|
||||
|
|
|
@ -20,6 +20,8 @@ package org.apache.olingo.client.core.serialization;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
|
||||
|
@ -38,6 +40,7 @@ import org.apache.olingo.commons.api.data.Entity;
|
|||
import org.apache.olingo.commons.api.data.EntityCollection;
|
||||
import org.apache.olingo.commons.api.data.Property;
|
||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
|
||||
import org.apache.olingo.commons.api.edm.provider.CsdlSchema;
|
||||
import org.apache.olingo.commons.api.ex.ODataError;
|
||||
import org.apache.olingo.commons.api.format.ContentType;
|
||||
|
||||
|
@ -118,6 +121,20 @@ public class ClientODataDeserializerImpl implements ClientODataDeserializer {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CsdlSchema> fetchTermDefinitionSchema(final List<InputStream> input) {
|
||||
List<CsdlSchema> schemas = new ArrayList<CsdlSchema>();
|
||||
try {
|
||||
for (InputStream stream : input) {
|
||||
ClientCsdlEdmx edmx = getXmlMapper().readValue(stream, ClientCsdlEdmx.class);
|
||||
schemas.addAll(edmx.getDataServices().getSchemas());
|
||||
}
|
||||
return schemas;
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException("Could not parse as Term definition", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResWrap<ServiceDocument> toServiceDocument(final InputStream input) throws ODataDeserializerException {
|
||||
return contentType.isCompatible(ContentType.APPLICATION_XML) ?
|
||||
|
|
|
@ -20,6 +20,7 @@ package org.apache.olingo.client.core.serialization;
|
|||
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
@ -66,12 +67,24 @@ public class ODataReaderImpl implements ODataReader {
|
|||
return readMetadata(client.getDeserializer(ContentType.APPLICATION_XML).toMetadata(input).getSchemaByNsOrAlias());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Edm readMetadata(final InputStream input, List<InputStream> termDefinition) {
|
||||
return readMetadata(client.getDeserializer(ContentType.APPLICATION_XML).toMetadata(input).getSchemaByNsOrAlias(),
|
||||
client.getDeserializer(ContentType.APPLICATION_XML).fetchTermDefinitionSchema(termDefinition));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Edm readMetadata(final Map<String, CsdlSchema> xmlSchemas) {
|
||||
ClientCsdlEdmProvider prov = new ClientCsdlEdmProvider(xmlSchemas);
|
||||
return new EdmProviderImpl(prov);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Edm readMetadata(final Map<String, CsdlSchema> xmlSchemas, List<CsdlSchema> termDefinitionSchema) {
|
||||
ClientCsdlEdmProvider prov = new ClientCsdlEdmProvider(xmlSchemas);
|
||||
return new EdmProviderImpl(prov, termDefinitionSchema);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientServiceDocument readServiceDocument(final InputStream input, final ContentType contentType)
|
||||
throws ODataDeserializerException {
|
||||
|
|
|
@ -24,6 +24,7 @@ import static org.junit.Assert.assertNotNull;
|
|||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.olingo.client.api.edm.xml.XMLMetadata;
|
||||
|
@ -40,9 +41,12 @@ import org.apache.olingo.commons.api.edm.EdmEnumType;
|
|||
import org.apache.olingo.commons.api.edm.EdmFunction;
|
||||
import org.apache.olingo.commons.api.edm.EdmFunctionImport;
|
||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
|
||||
import org.apache.olingo.commons.api.edm.EdmProperty;
|
||||
import org.apache.olingo.commons.api.edm.EdmSchema;
|
||||
import org.apache.olingo.commons.api.edm.EdmTerm;
|
||||
import org.apache.olingo.commons.api.edm.EdmTypeDefinition;
|
||||
import org.apache.olingo.commons.api.edm.FullQualifiedName;
|
||||
import org.apache.olingo.commons.api.edm.annotation.EdmExpression;
|
||||
import org.apache.olingo.commons.api.edm.annotation.EdmUrlRef;
|
||||
import org.apache.olingo.commons.api.edm.constants.EdmTypeKind;
|
||||
import org.apache.olingo.commons.api.edm.provider.CsdlAnnotation;
|
||||
|
@ -414,4 +418,41 @@ public class MetadataTest extends AbstractTest {
|
|||
assertNotNull(deleteRestrictions);
|
||||
assertEquals("Capabilities.DeleteRestrictionsType", deleteRestrictions.getType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readPropertyAnnotations() {
|
||||
List<InputStream> streams = new ArrayList<InputStream>();
|
||||
streams.add(getClass().getResourceAsStream("VOC_Core.xml"));
|
||||
final Edm edm = client.getReader().readMetadata(getClass().getResourceAsStream("edmxWithCoreAnnotation.xml"),
|
||||
streams);
|
||||
assertNotNull(edm);
|
||||
|
||||
final EdmEntityType person = edm.getEntityType(
|
||||
new FullQualifiedName("Microsoft.Exchange.Services.OData.Model", "Person"));
|
||||
assertNotNull(person);
|
||||
EdmProperty concurrency = (EdmProperty) person.getProperty("Concurrency");
|
||||
List<EdmAnnotation> annotations = concurrency.getAnnotations();
|
||||
for (EdmAnnotation annotation : annotations) {
|
||||
EdmTerm term = annotation.getTerm();
|
||||
assertNotNull(term);
|
||||
assertEquals("Computed", term.getName());
|
||||
assertEquals("Org.OData.Core.V1.Computed",
|
||||
term.getFullQualifiedName().getFullQualifiedNameAsString());
|
||||
assertEquals(1, term.getAnnotations().size());
|
||||
}
|
||||
EdmProperty userName = (EdmProperty) person.getProperty("UserName");
|
||||
List<EdmAnnotation> userNameAnnotations = userName.getAnnotations();
|
||||
for (EdmAnnotation annotation : userNameAnnotations) {
|
||||
EdmTerm term = annotation.getTerm();
|
||||
assertNotNull(term);
|
||||
assertEquals("Permissions", term.getName());
|
||||
assertEquals("Org.OData.Core.V1.Permissions",
|
||||
term.getFullQualifiedName().getFullQualifiedNameAsString());
|
||||
EdmExpression expression = annotation.getExpression();
|
||||
assertNotNull(expression);
|
||||
assertTrue(expression.isConstant());
|
||||
assertEquals("Org.OData.Core.V1.Permission/Read", expression.asConstant().getValueAsString());
|
||||
assertEquals("EnumMember", expression.getExpressionName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
<?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.
|
||||
|
||||
-->
|
||||
<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="Property Term">
|
||||
<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="Properties and terms annotated with this annotation MUST 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="true" 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>
|
|
@ -0,0 +1,48 @@
|
|||
<?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.
|
||||
|
||||
-->
|
||||
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
|
||||
<edmx:DataServices m:DataServiceVersion="4.0" m:MaxDataServiceVersion="4.0" xmlns:m="http://docs.oasis-open.org/odata/ns/metadata">
|
||||
<Schema Namespace="Microsoft.Exchange.Services.OData.Model" xmlns="http://docs.oasis-open.org/odata/ns/edm">
|
||||
<EntityType Name="Person" OpenType="true">
|
||||
<Key>
|
||||
<PropertyRef Name="UserName"/>
|
||||
</Key>
|
||||
<Property Name="UserName" Type="Edm.String" Nullable="false">
|
||||
<Annotation Term="Org.OData.Core.V1.Permissions">
|
||||
<EnumMember>Org.OData.Core.V1.Permission/Read</EnumMember>
|
||||
</Annotation>
|
||||
</Property>
|
||||
<Property Name="FirstName" Type="Edm.String" Nullable="false"/>
|
||||
<Property Name="LastName" Type="Edm.String" Nullable="false"/>
|
||||
<Property Name="Emails" Type="Collection(Edm.String)"/>
|
||||
<Property Name="AddressInfo" Type="Collection(Microsoft.OData.SampleService.Models.TripPin.Location)"/>
|
||||
<Property Name="Gender" Type="Microsoft.OData.SampleService.Models.TripPin.PersonGender"/>
|
||||
<Property Name="Concurrency" Type="Edm.Int64" Nullable="false">
|
||||
<Annotation Term="Org.OData.Core.V1.Computed" Bool="true"/>
|
||||
</Property>
|
||||
</EntityType>
|
||||
<EntityContainer Name="EntityContainer" m:IsDefaultEntityContainer="true">
|
||||
<EntitySet Name="People" EntityType="Microsoft.Exchange.Services.OData.Model.Person"/>
|
||||
</EntityContainer>
|
||||
</Schema>
|
||||
</edmx:DataServices>
|
||||
</edmx:Edmx>
|
|
@ -59,11 +59,17 @@ public class EdmProviderImpl extends AbstractEdm {
|
|||
Collections.synchronizedMap(new HashMap<FullQualifiedName, List<CsdlAction>>());
|
||||
private final Map<FullQualifiedName, List<CsdlFunction>> functionsMap =
|
||||
Collections.synchronizedMap(new HashMap<FullQualifiedName, List<CsdlFunction>>());
|
||||
private List<CsdlSchema> termSchemaDefinition = null;
|
||||
|
||||
public EdmProviderImpl(final CsdlEdmProvider provider) {
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
public EdmProviderImpl(final CsdlEdmProvider provider, final List<CsdlSchema> termSchemaDefinition) {
|
||||
this.provider = provider;
|
||||
this.termSchemaDefinition = termSchemaDefinition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EdmEntityContainer createEntityContainer(final FullQualifiedName containerName) {
|
||||
try {
|
||||
|
@ -334,6 +340,17 @@ public class EdmProviderImpl extends AbstractEdm {
|
|||
CsdlTerm providerTerm = provider.getTerm(termName);
|
||||
if (providerTerm != null) {
|
||||
return new EdmTermImpl(this, termName.getNamespace(), providerTerm);
|
||||
} else if (termSchemaDefinition != null && termSchemaDefinition.size() > 0) {
|
||||
for (CsdlSchema schema : termSchemaDefinition) {
|
||||
if (schema.getNamespace().equalsIgnoreCase(termName.getNamespace())) {
|
||||
List<CsdlTerm> terms = schema.getTerms();
|
||||
for (CsdlTerm term : terms) {
|
||||
if (term.getName().equals(termName.getName())) {
|
||||
return new EdmTermImpl(this, termName.getNamespace(), term);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} catch (ODataException e) {
|
||||
|
|
|
@ -211,7 +211,10 @@ public class ODataHandlerImpl implements ODataHandler {
|
|||
if(endIndex == -1) {
|
||||
endIndex = query.length();
|
||||
}
|
||||
final String format = query.substring(index + formatOption.length(), endIndex);
|
||||
String format = "";
|
||||
if (index + formatOption.length() < endIndex) {
|
||||
format = query.substring(index + formatOption.length(), endIndex);
|
||||
}
|
||||
return new FormatOptionImpl().setFormat(format);
|
||||
}
|
||||
return uriInfo.getFormatOption();
|
||||
|
|
|
@ -33,6 +33,7 @@ import org.apache.olingo.server.api.uri.UriInfoKind;
|
|||
import org.apache.olingo.server.api.uri.UriResource;
|
||||
import org.apache.olingo.server.api.uri.UriResourceAction;
|
||||
import org.apache.olingo.server.api.uri.UriResourceCount;
|
||||
import org.apache.olingo.server.api.uri.UriResourceEntitySet;
|
||||
import org.apache.olingo.server.api.uri.UriResourceFunction;
|
||||
import org.apache.olingo.server.api.uri.UriResourcePartTyped;
|
||||
import org.apache.olingo.server.api.uri.UriResourceRef;
|
||||
|
@ -255,11 +256,17 @@ public class Parser {
|
|||
if (lastSegment instanceof UriResourcePartTyped) {
|
||||
final UriResourcePartTyped typed = (UriResourcePartTyped) lastSegment;
|
||||
contextType = ParserHelper.getTypeInformation(typed);
|
||||
if (contextUriInfo.getIdOption() != null && contextType != null) {
|
||||
if (contextType instanceof EdmEntityType) {
|
||||
contextUriInfo.setEntityTypeCast((EdmEntityType) contextType);
|
||||
if (contextType != null) {
|
||||
if ((lastSegment instanceof UriResourceEntitySet &&
|
||||
(((UriResourceEntitySet) lastSegment).getTypeFilterOnCollection() != null
|
||||
|| ((UriResourceEntitySet) lastSegment).getTypeFilterOnEntry() != null))
|
||||
|| contextUriInfo.getIdOption() != null) {
|
||||
if (contextType instanceof EdmEntityType) {
|
||||
contextUriInfo.setEntityTypeCast((EdmEntityType) contextType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
contextIsCollection = typed.isCollection();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,6 +68,7 @@ import org.apache.olingo.server.api.uri.UriHelper;
|
|||
import org.apache.olingo.server.api.uri.UriInfo;
|
||||
import org.apache.olingo.server.api.uri.UriInfoResource;
|
||||
import org.apache.olingo.server.api.uri.UriResource;
|
||||
import org.apache.olingo.server.api.uri.UriResourceComplexProperty;
|
||||
import org.apache.olingo.server.api.uri.UriResourceFunction;
|
||||
import org.apache.olingo.server.api.uri.UriResourceKind;
|
||||
import org.apache.olingo.server.api.uri.UriResourceProperty;
|
||||
|
@ -246,9 +247,18 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor
|
|||
} else {
|
||||
final EdmProperty edmProperty = path.isEmpty() ? null :
|
||||
((UriResourceProperty) resourceParts.get(resourceParts.size() - trailing - 1)).getProperty();
|
||||
if (resourceParts.get(resourceParts.size() - trailing - 1)
|
||||
instanceof UriResourceComplexProperty &&
|
||||
((UriResourceComplexProperty)resourceParts.get(resourceParts.size() - trailing - 1)).
|
||||
getComplexTypeFilter() != null) {
|
||||
EdmType type1 = ((UriResourceComplexProperty)resourceParts.get(resourceParts.size() - trailing - 1)).
|
||||
getComplexTypeFilter();
|
||||
property.setType(type1.getFullQualifiedName().getFullQualifiedNameAsString());
|
||||
}
|
||||
final EdmType type = edmProperty == null ?
|
||||
((UriResourceFunction) resourceParts.get(0)).getType() :
|
||||
edmProperty.getType();
|
||||
((UriResourceFunction) resourceParts.get(0)).getType() :
|
||||
edmProperty.getType();
|
||||
|
||||
final EdmReturnType returnType = resourceParts.get(0) instanceof UriResourceFunction ?
|
||||
((UriResourceFunction) resourceParts.get(0)).getFunction().getReturnType() : null;
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.apache.olingo.commons.api.data.Entity;
|
|||
import org.apache.olingo.commons.api.data.EntityCollection;
|
||||
import org.apache.olingo.commons.api.data.Link;
|
||||
import org.apache.olingo.commons.api.edm.EdmBindingTarget;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntityContainer;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntitySet;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntityType;
|
||||
import org.apache.olingo.commons.api.edm.EdmFunction;
|
||||
|
@ -75,11 +76,36 @@ public abstract class TechnicalProcessor implements Processor {
|
|||
EdmEntitySet entitySet = null;
|
||||
final List<UriResource> resourcePaths = uriInfo.getUriResourceParts();
|
||||
EdmSingleton singleton = null;
|
||||
|
||||
// First must be an entity, an entity collection, a function import, or an action import.
|
||||
blockTypeFilters(resourcePaths.get(0));
|
||||
//blockTypeFilters(resourcePaths.get(0));
|
||||
if (resourcePaths.get(0) instanceof UriResourceEntitySet) {
|
||||
entitySet = ((UriResourceEntitySet) resourcePaths.get(0)).getEntitySet();
|
||||
entitySet = getEntitySetBasedOnTypeCast(((UriResourceEntitySet)resourcePaths.get(0)));
|
||||
//entitySet = ((UriResourceEntitySet) resourcePaths.get(0)).getEntitySet();
|
||||
} else if (resourcePaths.get(0) instanceof UriResourceFunction) {
|
||||
entitySet = ((UriResourceFunction) resourcePaths.get(0)).getFunctionImport().getReturnedEntitySet();
|
||||
} else if (resourcePaths.get(0) instanceof UriResourceAction) {
|
||||
entitySet = ((UriResourceAction) resourcePaths.get(0)).getActionImport().getReturnedEntitySet();
|
||||
}else if (resourcePaths.get(0) instanceof UriResourceSingleton ) {
|
||||
singleton =((UriResourceSingleton) resourcePaths.get(0)).getSingleton();
|
||||
} else {
|
||||
throw new ODataApplicationException("Invalid resource type.",
|
||||
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
|
||||
}
|
||||
|
||||
entitySet = (EdmEntitySet) getEntitySetForNavigation(entitySet, singleton, resourcePaths);
|
||||
|
||||
return entitySet;
|
||||
}
|
||||
|
||||
protected EdmEntitySet getEdmEntitySetTypeCast(final UriInfoResource uriInfo) throws ODataApplicationException {
|
||||
EdmEntitySet entitySet = null;
|
||||
final List<UriResource> resourcePaths = uriInfo.getUriResourceParts();
|
||||
EdmSingleton singleton = null;
|
||||
// First must be an entity, an entity collection, a function import, or an action import.
|
||||
//blockTypeFilters(resourcePaths.get(0));
|
||||
if (resourcePaths.get(0) instanceof UriResourceEntitySet) {
|
||||
entitySet = getEntitySetBasedOnTypeCast(((UriResourceEntitySet)resourcePaths.get(0)));
|
||||
//entitySet = ((UriResourceEntitySet) resourcePaths.get(0)).getEntitySet();
|
||||
} else if (resourcePaths.get(0) instanceof UriResourceFunction) {
|
||||
entitySet = ((UriResourceFunction) resourcePaths.get(0)).getFunctionImport().getReturnedEntitySet();
|
||||
} else if (resourcePaths.get(0) instanceof UriResourceAction) {
|
||||
|
@ -102,22 +128,22 @@ public abstract class TechnicalProcessor implements Processor {
|
|||
while ((entitySet != null || singleton!=null)
|
||||
&& ++navigationCount < resourcePaths.size()
|
||||
&& resourcePaths.get(navigationCount) instanceof UriResourceNavigation) {
|
||||
final UriResourceNavigation uriResourceNavigation =
|
||||
(UriResourceNavigation) resourcePaths.get(navigationCount);
|
||||
blockTypeFilters(uriResourceNavigation);
|
||||
if (uriResourceNavigation.getProperty().containsTarget()) {
|
||||
throw new ODataApplicationException("Containment navigation is not supported.",
|
||||
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
|
||||
}
|
||||
EdmBindingTarget target = null ;
|
||||
if(entitySet!=null){
|
||||
target = entitySet.getRelatedBindingTarget(uriResourceNavigation.getProperty().getName());
|
||||
}else if(singleton != null){
|
||||
target = singleton.getRelatedBindingTarget(uriResourceNavigation.getProperty().getName());
|
||||
}
|
||||
if (target instanceof EdmEntitySet) {
|
||||
entitySet = (EdmEntitySet) target;
|
||||
}
|
||||
final UriResourceNavigation uriResourceNavigation =
|
||||
(UriResourceNavigation) resourcePaths.get(navigationCount);
|
||||
blockTypeFilters(uriResourceNavigation);
|
||||
if (uriResourceNavigation.getProperty().containsTarget()) {
|
||||
throw new ODataApplicationException("Containment navigation is not supported.",
|
||||
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
|
||||
}
|
||||
EdmBindingTarget target = null ;
|
||||
if(entitySet!=null){
|
||||
target = entitySet.getRelatedBindingTarget(uriResourceNavigation.getProperty().getName());
|
||||
}else if(singleton != null){
|
||||
target = singleton.getRelatedBindingTarget(uriResourceNavigation.getProperty().getName());
|
||||
}
|
||||
if (target instanceof EdmEntitySet) {
|
||||
entitySet = (EdmEntitySet) target;
|
||||
}
|
||||
}
|
||||
return entitySet;
|
||||
}
|
||||
|
@ -139,11 +165,10 @@ public abstract class TechnicalProcessor implements Processor {
|
|||
protected Entity readEntity(final UriInfoResource uriInfo, final boolean ignoreLastNavigation)
|
||||
throws ODataApplicationException {
|
||||
final List<UriResource> resourcePaths = uriInfo.getUriResourceParts();
|
||||
|
||||
Entity entity = null;
|
||||
if (resourcePaths.get(0) instanceof UriResourceEntitySet) {
|
||||
final UriResourceEntitySet uriResource = (UriResourceEntitySet) resourcePaths.get(0);
|
||||
entity = dataProvider.read(uriResource.getEntitySet(), uriResource.getKeyPredicates());
|
||||
EdmEntitySet entitySet = getEntitySetBasedOnTypeCast(((UriResourceEntitySet)resourcePaths.get(0)));
|
||||
entity = dataProvider.read(entitySet, ((UriResourceEntitySet)resourcePaths.get(0)).getKeyPredicates());
|
||||
}else if (resourcePaths.get(0) instanceof UriResourceSingleton) {
|
||||
final UriResourceSingleton uriResource = (UriResourceSingleton) resourcePaths.get(0);
|
||||
entity = dataProvider.read( uriResource.getSingleton());
|
||||
|
@ -205,6 +230,27 @@ public abstract class TechnicalProcessor implements Processor {
|
|||
return entity;
|
||||
}
|
||||
|
||||
protected EdmEntitySet getEntitySetBasedOnTypeCast(UriResourceEntitySet uriResource) {
|
||||
EdmEntitySet entitySet = null;
|
||||
EdmEntityContainer container = this.serviceMetadata.getEdm().getEntityContainer();
|
||||
if (uriResource.getTypeFilterOnEntry() != null ||
|
||||
uriResource.getTypeFilterOnCollection() != null) {
|
||||
List<EdmEntitySet> entitySets = container.getEntitySets();
|
||||
for (EdmEntitySet entitySet1 : entitySets) {
|
||||
EdmEntityType entityType = entitySet1.getEntityType();
|
||||
if ((uriResource.getTypeFilterOnEntry() != null &&
|
||||
entityType.getName().equalsIgnoreCase(uriResource.getTypeFilterOnEntry().getName())) ||
|
||||
(uriResource.getTypeFilterOnCollection() != null &&
|
||||
entityType.getName().equalsIgnoreCase(uriResource.getTypeFilterOnCollection().getName()))) {
|
||||
entitySet = entitySet1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
entitySet = uriResource.getEntitySet();
|
||||
}
|
||||
return entitySet;
|
||||
}
|
||||
protected EntityCollection readEntityCollection(final UriInfoResource uriInfo) throws ODataApplicationException {
|
||||
final List<UriResource> resourcePaths = uriInfo.getUriResourceParts();
|
||||
if (resourcePaths.size() > 1 && resourcePaths.get(1) instanceof UriResourceNavigation) {
|
||||
|
@ -217,7 +263,8 @@ public abstract class TechnicalProcessor implements Processor {
|
|||
return dataProvider.readFunctionEntityCollection(uriResource.getFunction(), uriResource.getParameters(),
|
||||
uriInfo);
|
||||
} else {
|
||||
return dataProvider.readAll(((UriResourceEntitySet) resourcePaths.get(0)).getEntitySet());
|
||||
EdmEntitySet entitySet = getEntitySetBasedOnTypeCast(((UriResourceEntitySet)resourcePaths.get(0)));
|
||||
return dataProvider.readAll(entitySet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue