Repository: olingo-odata4 Updated Branches: refs/heads/master aea44a33a -> ce4bc57a8
[OLINGO-1062]Cannot consume Term defined in external Vocabulary Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/ce4bc57a Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/ce4bc57a Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/ce4bc57a Branch: refs/heads/master Commit: ce4bc57a84c0f79392a868159734bbf268d3fc4b Parents: aea44a3 Author: ramya vasanth <[email protected]> Authored: Wed Jun 21 10:59:27 2017 +0530 Committer: ramya vasanth <[email protected]> Committed: Wed Jun 21 10:59:27 2017 +0530 ---------------------------------------------------------------------- .../olingo/fit/tecsvc/client/BasicITCase.java | 61 +++++++++ .../olingo/fit/tecsvc/http/BasicHttpITCase.java | 25 ++++ .../test/resources/edmxWithCoreAnnotation.xml | 49 ++++++++ .../serialization/ClientODataDeserializer.java | 4 + .../client/api/serialization/ODataReader.java | 12 ++ .../ClientODataDeserializerImpl.java | 17 +++ .../core/serialization/ODataReaderImpl.java | 13 ++ .../apache/olingo/client/core/MetadataTest.java | 41 ++++++ .../org/apache/olingo/client/core/VOC_Core.xml | 125 +++++++++++++++++++ .../client/core/edmxWithCoreAnnotation.xml | 48 +++++++ .../commons/core/edm/EdmProviderImpl.java | 17 +++ .../olingo/server/core/ODataHandlerImpl.java | 5 +- .../olingo/server/core/uri/parser/Parser.java | 13 +- .../TechnicalPrimitiveComplexProcessor.java | 14 ++- .../tecsvc/processor/TechnicalProcessor.java | 95 ++++++++++---- 15 files changed, 509 insertions(+), 30 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ce4bc57a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java ---------------------------------------------------------------------- diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java index 63a0d0e..6d1b51b 100644 --- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java +++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java @@ -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; @@ -115,6 +121,8 @@ public class BasicITCase extends AbstractParamTecSvcITCase { private static final String PROPERTY_COMP_NAV = "CollPropertyCompNav"; 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() { @@ -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()); + } + } } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ce4bc57a/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/BasicHttpITCase.java ---------------------------------------------------------------------- diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/BasicHttpITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/BasicHttpITCase.java index 55a04f5..7e4b9b0 100644 --- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/BasicHttpITCase.java +++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/BasicHttpITCase.java @@ -181,5 +181,30 @@ public class BasicHttpITCase extends AbstractBaseTestITCase { protected ODataClient getClient() { 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 ''.")); + } } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ce4bc57a/fit/src/test/resources/edmxWithCoreAnnotation.xml ---------------------------------------------------------------------- diff --git a/fit/src/test/resources/edmxWithCoreAnnotation.xml b/fit/src/test/resources/edmxWithCoreAnnotation.xml new file mode 100644 index 0000000..e10fcf8 --- /dev/null +++ b/fit/src/test/resources/edmxWithCoreAnnotation.xml @@ -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> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ce4bc57a/lib/client-api/src/main/java/org/apache/olingo/client/api/serialization/ClientODataDeserializer.java ---------------------------------------------------------------------- diff --git a/lib/client-api/src/main/java/org/apache/olingo/client/api/serialization/ClientODataDeserializer.java b/lib/client-api/src/main/java/org/apache/olingo/client/api/serialization/ClientODataDeserializer.java index ba18683..47935b1 100644 --- a/lib/client-api/src/main/java/org/apache/olingo/client/api/serialization/ClientODataDeserializer.java +++ b/lib/client-api/src/main/java/org/apache/olingo/client/api/serialization/ClientODataDeserializer.java @@ -19,15 +19,19 @@ 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. http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ce4bc57a/lib/client-api/src/main/java/org/apache/olingo/client/api/serialization/ODataReader.java ---------------------------------------------------------------------- diff --git a/lib/client-api/src/main/java/org/apache/olingo/client/api/serialization/ODataReader.java b/lib/client-api/src/main/java/org/apache/olingo/client/api/serialization/ODataReader.java index a374adb..43f46e5 100644 --- a/lib/client-api/src/main/java/org/apache/olingo/client/api/serialization/ODataReader.java +++ b/lib/client-api/src/main/java/org/apache/olingo/client/api/serialization/ODataReader.java @@ -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; @@ -47,6 +48,15 @@ public interface ODataReader { * @return metadata representation. */ 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. @@ -56,6 +66,8 @@ public interface ODataReader { * @return metadata representation. */ Edm readMetadata(Map<String, CsdlSchema> xmlSchemas); + + Edm readMetadata(Map<String, CsdlSchema> xmlSchemas, List<CsdlSchema> termDefinitionSchema); /** * Parses an OData service document. http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ce4bc57a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/ClientODataDeserializerImpl.java ---------------------------------------------------------------------- diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/ClientODataDeserializerImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/ClientODataDeserializerImpl.java index ec361ab..ca3d88a 100644 --- a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/ClientODataDeserializerImpl.java +++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/ClientODataDeserializerImpl.java @@ -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; @@ -117,6 +120,20 @@ public class ClientODataDeserializerImpl implements ClientODataDeserializer { throw new IllegalArgumentException("Could not parse as Edmx document", e); } } + + @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 { http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ce4bc57a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/ODataReaderImpl.java ---------------------------------------------------------------------- diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/ODataReaderImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/ODataReaderImpl.java index 6b8c956..c72ce6a 100644 --- a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/ODataReaderImpl.java +++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/ODataReaderImpl.java @@ -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; @@ -67,12 +68,24 @@ public class ODataReaderImpl implements ODataReader { } @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 { return client.getBinder().getODataServiceDocument( http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ce4bc57a/lib/client-core/src/test/java/org/apache/olingo/client/core/MetadataTest.java ---------------------------------------------------------------------- diff --git a/lib/client-core/src/test/java/org/apache/olingo/client/core/MetadataTest.java b/lib/client-core/src/test/java/org/apache/olingo/client/core/MetadataTest.java index c150e64..181335b 100644 --- a/lib/client-core/src/test/java/org/apache/olingo/client/core/MetadataTest.java +++ b/lib/client-core/src/test/java/org/apache/olingo/client/core/MetadataTest.java @@ -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()); + } + } } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ce4bc57a/lib/client-core/src/test/resources/org/apache/olingo/client/core/VOC_Core.xml ---------------------------------------------------------------------- diff --git a/lib/client-core/src/test/resources/org/apache/olingo/client/core/VOC_Core.xml b/lib/client-core/src/test/resources/org/apache/olingo/client/core/VOC_Core.xml new file mode 100644 index 0000000..4e30cad --- /dev/null +++ b/lib/client-core/src/test/resources/org/apache/olingo/client/core/VOC_Core.xml @@ -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> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ce4bc57a/lib/client-core/src/test/resources/org/apache/olingo/client/core/edmxWithCoreAnnotation.xml ---------------------------------------------------------------------- diff --git a/lib/client-core/src/test/resources/org/apache/olingo/client/core/edmxWithCoreAnnotation.xml b/lib/client-core/src/test/resources/org/apache/olingo/client/core/edmxWithCoreAnnotation.xml new file mode 100644 index 0000000..8dfa974 --- /dev/null +++ b/lib/client-core/src/test/resources/org/apache/olingo/client/core/edmxWithCoreAnnotation.xml @@ -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> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ce4bc57a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/EdmProviderImpl.java ---------------------------------------------------------------------- diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/EdmProviderImpl.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/EdmProviderImpl.java index 53c69f4..362bae7 100644 --- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/EdmProviderImpl.java +++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/EdmProviderImpl.java @@ -59,10 +59,16 @@ 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) { @@ -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) { http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ce4bc57a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandlerImpl.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandlerImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandlerImpl.java index d1a9cf2..6d8ed1b 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandlerImpl.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandlerImpl.java @@ -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(); http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ce4bc57a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java index 0ce8c75..edbb369 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java @@ -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(); } } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ce4bc57a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalPrimitiveComplexProcessor.java ---------------------------------------------------------------------- diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalPrimitiveComplexProcessor.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalPrimitiveComplexProcessor.java index f97b7eb..a7aff95 100644 --- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalPrimitiveComplexProcessor.java +++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalPrimitiveComplexProcessor.java @@ -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; http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ce4bc57a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java ---------------------------------------------------------------------- diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java index fc6991f..9220db9 100644 --- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java +++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java @@ -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) { @@ -100,24 +126,24 @@ public abstract class TechnicalProcessor implements Processor { List<UriResource> resourcePaths) throws ODataApplicationException { int navigationCount = 0; while ((entitySet != null || singleton!=null) - && ++navigationCount < resourcePaths.size() + && ++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); } } }
