Repository: olingo-odata4 Updated Branches: refs/heads/master a3a84c9e8 -> 1ce51fd4e
[OLINGO-1202]Bound function scenarios, samples and tests Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/1ce51fd4 Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/1ce51fd4 Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/1ce51fd4 Branch: refs/heads/master Commit: 1ce51fd4ec59ef46091d32459c69e8e9eec671af Parents: a3a84c9 Author: Archana Rai <archana....@sap.com> Authored: Mon Nov 13 16:07:34 2017 +0530 Committer: Archana Rai <archana....@sap.com> Committed: Mon Nov 13 16:07:34 2017 +0530 ---------------------------------------------------------------------- .../tecsvc/http/BasicBoundFunctionITCase.java | 372 +++++++++++++++++++ .../commons/core/edm/EdmProviderImpl.java | 8 +- .../EdmProviderImplOverloadingTest.java | 6 +- .../olingo/server/tecsvc/data/FunctionData.java | 87 ++++- .../TechnicalPrimitiveComplexProcessor.java | 32 +- .../tecsvc/provider/FunctionProvider.java | 17 + .../server/tecsvc/provider/SchemaProvider.java | 1 + samples/tutorials/p9_action/pom.xml | 2 +- .../myservice/mynamespace/data/Storage.java | 24 ++ .../mynamespace/service/DemoEdmProvider.java | 70 ++++ .../service/DemoEntityCollectionProcessor.java | 21 ++ .../service/DemoEntityProcessor.java | 30 +- 12 files changed, 659 insertions(+), 11 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/1ce51fd4/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/BasicBoundFunctionITCase.java ---------------------------------------------------------------------- diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/BasicBoundFunctionITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/BasicBoundFunctionITCase.java new file mode 100644 index 0000000..efeca67 --- /dev/null +++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/BasicBoundFunctionITCase.java @@ -0,0 +1,372 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.olingo.fit.tecsvc.http; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.net.HttpURLConnection; +import java.net.URL; + +import org.apache.commons.io.IOUtils; +import org.apache.olingo.client.api.ODataClient; +import org.apache.olingo.commons.api.http.HttpHeader; +import org.apache.olingo.commons.api.http.HttpMethod; +import org.apache.olingo.commons.api.http.HttpStatusCode; +import org.apache.olingo.fit.AbstractBaseTestITCase; +import org.apache.olingo.fit.tecsvc.TecSvcConst; +import org.junit.Test; + +public class BasicBoundFunctionITCase extends AbstractBaseTestITCase { + + private static final String SERVICE_URI = TecSvcConst.BASE_URI + "/"; + + @Test + public void boundFunctionReturningDerievedType() throws Exception { + URL url = new URL(SERVICE_URI + "ESBase(111)/olingo.odata.test1.ETTwoBase/" + + "olingo.odata.test1.BFESBaseRTESTwoBase()"); + + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod(HttpMethod.GET.name()); + connection.setRequestProperty(HttpHeader.ACCEPT, "application/json"); + connection.connect(); + + assertEquals(HttpStatusCode.OK.getStatusCode(), connection.getResponseCode()); + final String expected = "\"PropertyInt16\":111," + + "\"PropertyString\":\"TEST A\"," + + "\"AdditionalPropertyString_5\":\"TEST A 0815\"," + + "\"AdditionalPropertyString_6\":\"TEST B 0815\""; + String content = IOUtils.toString(connection.getInputStream()); + assertTrue(content.contains(expected)); + connection.disconnect(); + } + + @Test + public void boundFunctionReturningNavigationType() throws Exception { + URL url = new URL(SERVICE_URI + "ESTwoKeyNav(PropertyInt16=1,PropertyString='1')" + + "/NavPropertyETTwoKeyNavMany/olingo.odata.test1.BFC_RTESTwoKeyNav_()"); + + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod(HttpMethod.GET.name()); + connection.setRequestProperty(HttpHeader.ACCEPT, "application/json"); + connection.connect(); + + assertEquals(HttpStatusCode.OK.getStatusCode(), connection.getResponseCode()); + final String expected = "\"PropertyCompNav\":{" + + "\"PropertyInt16\":1," + + "\"PropertyComp\":{" + + "\"PropertyString\":\"First Resource - positive values\"," + + "\"PropertyBinary\":\"ASNFZ4mrze8=\"," + + "\"PropertyBoolean\":true," + + "\"PropertyByte\":255," + + "\"PropertyDate\":\"2012-12-03\"," + + "\"PropertyDateTimeOffset\":\"2012-12-03T07:16:23Z\"," + + "\"PropertyDecimal\":34," + + "\"PropertySingle\":1.79E20," + + "\"PropertyDouble\":-1.79E20," + + "\"PropertyDuration\":\"PT6S\"," + + "\"PropertyGuid\":\"01234567-89ab-cdef-0123-456789abcdef\"," + + "\"PropertyInt16\":32767," + + "\"PropertyInt32\":2147483647," + + "\"PropertyInt64\":9223372036854775807," + + "\"PropertySByte\":127," + + "\"PropertyTimeOfDay\":\"21:05:59\""; + String content = IOUtils.toString(connection.getInputStream()); + assertTrue(content.contains(expected)); + connection.disconnect(); + } + + @Test + public void boundFunctionCETReturningCT() throws Exception { + URL url = new URL(SERVICE_URI + "ESAllPrim/olingo.odata.test1.BFNESAllPrimRTCTAllPrim()"); + + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod(HttpMethod.GET.name()); + connection.setRequestProperty(HttpHeader.ACCEPT, "application/json"); + connection.connect(); + + assertEquals(HttpStatusCode.OK.getStatusCode(), connection.getResponseCode()); + String content = IOUtils.toString(connection.getInputStream()); + assertNotNull(content); + connection.disconnect(); + } + + + @Test + public void boundFunctionCETReturningET() throws Exception { + URL url = new URL(SERVICE_URI + "ESTwoKeyNav/olingo.odata.test1.BFCESTwoKeyNavRTTwoKeyNav()"); + + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod(HttpMethod.GET.name()); + connection.setRequestProperty(HttpHeader.ACCEPT, "application/json"); + connection.connect(); + + assertEquals(HttpStatusCode.OK.getStatusCode(), connection.getResponseCode()); + String content = IOUtils.toString(connection.getInputStream()); + assertNotNull(content); + connection.disconnect(); + } + + @Test + public void boundFunctionCETWithParamReturningET() throws Exception { + URL url = new URL(SERVICE_URI + "ESKeyNav/olingo.odata.test1.BFCESKeyNavRTETKeyNavParam(ParameterString='qw')"); + + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod(HttpMethod.GET.name()); + connection.setRequestProperty(HttpHeader.ACCEPT, "application/json"); + connection.connect(); + + assertEquals(HttpStatusCode.OK.getStatusCode(), connection.getResponseCode()); + String content = IOUtils.toString(connection.getInputStream()); + assertNotNull(content); + connection.disconnect(); + } + + + @Test + public void boundFunctionCETParamReturningET() throws Exception { + URL url = new URL(SERVICE_URI + "ESKeyNav/olingo.odata.test1.BFCESKeyNavRTETKeyNavParam" + + "(ParameterString=@p1)?@p1=%27qw%27"); + + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod(HttpMethod.GET.name()); + connection.setRequestProperty(HttpHeader.ACCEPT, "application/json"); + connection.connect(); + + assertEquals(HttpStatusCode.OK.getStatusCode(), connection.getResponseCode()); + String content = IOUtils.toString(connection.getInputStream()); + assertNotNull(content); + connection.disconnect(); + } + + + @Test + public void boundFunctionCETParamReturningCET() throws Exception { + URL url = new URL(SERVICE_URI + "ESBaseTwoKeyNav/olingo.odata.test1.BFCESBaseTwoKeyNavRTESBaseTwoKey()"); + + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod(HttpMethod.GET.name()); + connection.setRequestProperty(HttpHeader.ACCEPT, "application/json"); + connection.connect(); + + assertEquals(HttpStatusCode.OK.getStatusCode(), connection.getResponseCode()); + String content = IOUtils.toString(connection.getInputStream()); + assertNotNull(content); + connection.disconnect(); + } + + + @Test + public void boundFunctionCETReturningPT() throws Exception { + URL url = new URL(SERVICE_URI + "ESTwoKeyNav/olingo.odata.test1.BFNESTwoKeyNavRTString()"); + + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod(HttpMethod.GET.name()); + connection.setRequestProperty(HttpHeader.ACCEPT, "application/json"); + connection.connect(); + + assertEquals(HttpStatusCode.OK.getStatusCode(), connection.getResponseCode()); + String content = IOUtils.toString(connection.getInputStream()); + assertNotNull(content); + connection.disconnect(); + } + + + @Test + public void boundFunctionCETReturningCCT() throws Exception { + URL url = new URL(SERVICE_URI + "ESTwoKeyNav/olingo.odata.test1.BFCESTwoKeyNavRTCollCTNavFiveProp()"); + + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod(HttpMethod.GET.name()); + connection.setRequestProperty(HttpHeader.ACCEPT, "application/json"); + connection.connect(); + + assertEquals(HttpStatusCode.OK.getStatusCode(), connection.getResponseCode()); + String content = IOUtils.toString(connection.getInputStream()); + assertNotNull(content); + connection.disconnect(); + } + + + @Test + public void boundFunctionCETReturningCPT() throws Exception { + URL url = new URL(SERVICE_URI + "ESTwoKeyNav/olingo.odata.test1.BFCESTwoKeyNavRTCollDecimal()"); + + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod(HttpMethod.GET.name()); + connection.setRequestProperty(HttpHeader.ACCEPT, "application/json"); + connection.connect(); + + assertEquals(HttpStatusCode.OK.getStatusCode(), connection.getResponseCode()); + String content = IOUtils.toString(connection.getInputStream()); + assertNotNull(content); + connection.disconnect(); + } + + @Test + public void boundFunctionETReturningCT() throws Exception { + URL url = new URL(SERVICE_URI + "ESTwoKeyNav(PropertyInt16=1,PropertyString='1')/" + + "olingo.odata.test1.BFCETTwoKeyNavRTCTTwoPrim()"); + + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod(HttpMethod.GET.name()); + connection.setRequestProperty(HttpHeader.ACCEPT, "application/json"); + connection.connect(); + + assertEquals(HttpStatusCode.OK.getStatusCode(), connection.getResponseCode()); + String content = IOUtils.toString(connection.getInputStream()); + assertNotNull(content); + connection.disconnect(); + } + + @Test + public void boundFunctionETReturningET() throws Exception { + URL url = new URL(SERVICE_URI + "ESKeyNav(1)/olingo.odata.test1.BFCETKeyNavRTETKeyNav()"); + + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod(HttpMethod.GET.name()); + connection.setRequestProperty(HttpHeader.ACCEPT, "application/json"); + connection.connect(); + + assertEquals(HttpStatusCode.OK.getStatusCode(), connection.getResponseCode()); + String content = IOUtils.toString(connection.getInputStream()); + assertNotNull(content); + connection.disconnect(); + } + + @Test + public void boundFunctionETReturningCET() throws Exception { + URL url = new URL(SERVICE_URI + "ESTwoKeyNav(PropertyInt16=1,PropertyString='1')/" + + "olingo.odata.test1.BFCSINavRTESTwoKeyNav()"); + + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod(HttpMethod.GET.name()); + connection.setRequestProperty(HttpHeader.ACCEPT, "application/json"); + connection.connect(); + + assertEquals(HttpStatusCode.OK.getStatusCode(), connection.getResponseCode()); + String content = IOUtils.toString(connection.getInputStream()); + assertNotNull(content); + connection.disconnect(); + } + + + @Test + public void boundFunctionETSetPath() throws Exception { + URL url = new URL(SERVICE_URI + "ESTwoKeyNav(PropertyInt16=1,PropertyString='1')/" + + "NavPropertyETTwoKeyNavMany/olingo.odata.test1.BFC_RTESTwoKeyNav_()"); + + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod(HttpMethod.GET.name()); + connection.setRequestProperty(HttpHeader.ACCEPT, "application/json"); + connection.connect(); + + assertEquals(HttpStatusCode.OK.getStatusCode(), connection.getResponseCode()); + String content = IOUtils.toString(connection.getInputStream()); + assertNotNull(content); + connection.disconnect(); + } + + @Test + public void boundFunctionETIsComposible() throws Exception { + URL url = new URL(SERVICE_URI + "ESTwoKeyNav/olingo.odata.test1.BFESTwoKeyNavRTESTwoKeyNav()" + + "?$top=1&$skip=1&$select=PropertyString"); + + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod(HttpMethod.GET.name()); + connection.setRequestProperty(HttpHeader.ACCEPT, "application/json"); + connection.connect(); + + assertEquals(HttpStatusCode.OK.getStatusCode(), connection.getResponseCode()); + String content = IOUtils.toString(connection.getInputStream()); + assertNotNull(content); + connection.disconnect(); + } + + @Test + public void boundFunctionETIsComposibleFilter() throws Exception { + URL url = new URL(SERVICE_URI + "ESTwoKeyNav/olingo.odata.test1.BFESTwoKeyNavRTESTwoKeyNav()?" + + "$filter=PropertyString%20eq%20%272%27"); + + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod(HttpMethod.GET.name()); + connection.setRequestProperty(HttpHeader.ACCEPT, "application/json"); + connection.connect(); + + assertEquals(HttpStatusCode.OK.getStatusCode(), connection.getResponseCode()); + String content = IOUtils.toString(connection.getInputStream()); + assertNotNull(content); + connection.disconnect(); + } + + @Test + public void boundFunctionETIsComposibleOrderBy() throws Exception { + URL url = new URL(SERVICE_URI + "ESTwoKeyNav/olingo.odata.test1.BFESTwoKeyNavRTESTwoKeyNav()?" + + "$orderby=PropertyInt16%20desc"); + + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod(HttpMethod.GET.name()); + connection.setRequestProperty(HttpHeader.ACCEPT, "application/json"); + connection.connect(); + + assertEquals(HttpStatusCode.OK.getStatusCode(), connection.getResponseCode()); + String content = IOUtils.toString(connection.getInputStream()); + assertNotNull(content); + connection.disconnect(); + } + + @Test + public void boundFunctionOverload() throws Exception { + URL url = new URL(SERVICE_URI + "ESTwoKeyNav/olingo.odata.test1.BFC_RTESTwoKeyNav_()"); + + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod(HttpMethod.GET.name()); + connection.setRequestProperty(HttpHeader.ACCEPT, "application/json"); + connection.connect(); + + assertEquals(HttpStatusCode.OK.getStatusCode(), connection.getResponseCode()); + String content = IOUtils.toString(connection.getInputStream()); + assertNotNull(content); + connection.disconnect(); + } + + @Test + public void boundFunctionOverloadParam() throws Exception { + URL url = new URL(SERVICE_URI + "ESTwoKeyNav/olingo.odata.test1.BFC_RTESTwoKeyNav_(ParameterString='abc')"); + + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod(HttpMethod.GET.name()); + connection.setRequestProperty(HttpHeader.ACCEPT, "application/json"); + connection.connect(); + + assertEquals(HttpStatusCode.OK.getStatusCode(), connection.getResponseCode()); + String content = IOUtils.toString(connection.getInputStream()); + assertNotNull(content); + connection.disconnect(); + } + + + + @Override + protected ODataClient getClient() { + return null; + } + +} http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/1ce51fd4/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 6f5ea64..6f8e7f4 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 @@ -184,6 +184,9 @@ public class EdmProviderImpl extends AbstractEdm { Boolean isBindingParameterCollection) throws ODataException { CsdlComplexType complexType = provider.getComplexType(bindingParameterTypeName); + if(provider.getEntityType(parameter.getTypeFQN()) == null){ + return false; + } List<CsdlProperty> properties = provider.getEntityType(parameter.getTypeFQN()).getProperties(); for (CsdlProperty property : properties) { String paramPropertyTypeName = property.getTypeAsFQNObject().getFullQualifiedNameAsString(); @@ -234,7 +237,10 @@ public class EdmProviderImpl extends AbstractEdm { throw new EdmException("No parameter specified for bound function: " + functionName); } final CsdlParameter bindingParameter = providerParameters.get(0); - if (bindingParameterTypeName.equals(bindingParameter.getTypeFQN()) + if ((bindingParameterTypeName.equals(bindingParameter.getTypeFQN()) + ||isEntityPreviousTypeCompatibleToBindingParam(bindingParameterTypeName, bindingParameter) || + isComplexPreviousTypeCompatibleToBindingParam(bindingParameterTypeName, bindingParameter, + isBindingParameterCollection)) && isBindingParameterCollection.booleanValue() == bindingParameter.isCollection() && parameterNamesCopy.size() == providerParameters.size() - 1) { http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/1ce51fd4/lib/commons-core/src/test/java/org/apache/olingo/server/core/edm/provider/EdmProviderImplOverloadingTest.java ---------------------------------------------------------------------- diff --git a/lib/commons-core/src/test/java/org/apache/olingo/server/core/edm/provider/EdmProviderImplOverloadingTest.java b/lib/commons-core/src/test/java/org/apache/olingo/server/core/edm/provider/EdmProviderImplOverloadingTest.java index 45d3d2b..916ca22 100644 --- a/lib/commons-core/src/test/java/org/apache/olingo/server/core/edm/provider/EdmProviderImplOverloadingTest.java +++ b/lib/commons-core/src/test/java/org/apache/olingo/server/core/edm/provider/EdmProviderImplOverloadingTest.java @@ -37,8 +37,10 @@ import org.apache.olingo.commons.api.edm.EdmFunction; 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.CsdlEdmProvider; +import org.apache.olingo.commons.api.edm.provider.CsdlEntityType; import org.apache.olingo.commons.api.edm.provider.CsdlFunction; import org.apache.olingo.commons.api.edm.provider.CsdlParameter; +import org.apache.olingo.commons.api.edm.provider.CsdlProperty; import org.apache.olingo.commons.core.edm.EdmProviderImpl; import org.junit.Before; import org.junit.Test; @@ -70,7 +72,9 @@ public class EdmProviderImplOverloadingTest { new CsdlAction().setName(operationName1.getName()).setBound(true).setParameters(action2Parameters); actions.add(action); when(provider.getActions(operationName1)).thenReturn(actions); - + CsdlEntityType type = new CsdlEntityType().setProperties(new ArrayList<CsdlProperty>()); + when(provider.getEntityType(operationType1)).thenReturn(type); + when(provider.getEntityType(operationType2)).thenReturn(type); List<CsdlFunction> functions = new ArrayList<CsdlFunction>(); CsdlFunction function = new CsdlFunction().setName(operationName1.getName()); functions.add(function); http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/1ce51fd4/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/FunctionData.java ---------------------------------------------------------------------- diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/FunctionData.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/FunctionData.java index ef1fa70..42c9f2e 100644 --- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/FunctionData.java +++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/FunctionData.java @@ -18,10 +18,15 @@ */ package org.apache.olingo.server.tecsvc.data; +import java.math.BigDecimal; +import java.sql.Timestamp; import java.util.ArrayList; import java.util.Arrays; +import java.util.Calendar; import java.util.List; import java.util.Map; +import java.util.TimeZone; +import java.util.UUID; import org.apache.olingo.commons.api.data.ComplexValue; import org.apache.olingo.commons.api.data.Entity; @@ -35,6 +40,8 @@ import org.apache.olingo.server.tecsvc.provider.ComplexTypeProvider; public class FunctionData { + private static final UUID GUID = UUID.fromString("01234567-89ab-cdef-0123-456789abcdef");; + protected static EntityCollection entityCollectionFunction(final String name, final Map<String, Parameter> parameters, final Map<String, EntityCollection> data) throws DataProviderException { @@ -97,6 +104,8 @@ public class FunctionData { return DataCreator.createPrimitive(name, (short) 12345); } else if (name.equals("UFCRTString")) { return DataCreator.createPrimitive(name, "UFCRTString string value"); + }else if ( name.equals("BFNESTwoKeyNavRTString") ) { + return DataCreator.createPrimitive(name, "BFNESTwoKeyNavRTString string value"); } else if (name.equals("UFCRTCollString")) { return data.get("ESCollAllPrim").getEntities().get(0).getProperty("CollPropertyString"); } else if (name.equals("UFCRTCTTwoPrim")) { @@ -173,7 +182,42 @@ public class FunctionData { } } return DataCreator.createPrimitive(null, count); - } else { + } else if (name.equals("_FC_RTTimeOfDay_")) { + return DataCreator.createPrimitive(name, getParameterTimeOfDay(parameters)); + } else if (name.equals("BFNESAllPrimRTCTAllPrim")) { + return DataCreator.createComplex(name, + ComplexTypeProvider.nameCTAllPrim.getFullQualifiedNameAsString(), + DataCreator.createPrimitive("PropertyString", "First Resource - first"), + DataCreator.createPrimitive("PropertyBinary", + new byte[] { 0x01, 0x23, 0x45, 0x67, (byte) 0x89, (byte) 0xAB, (byte) 0xCD, (byte) 0xEF }), + DataCreator.createPrimitive("PropertyBoolean", true), + DataCreator.createPrimitive("PropertyByte", (short) 255), + DataCreator.createPrimitive("PropertyDate", getDate(2012, 10, 3)), + DataCreator.createPrimitive("PropertyDateTimeOffset", getTimestamp(2012, 10, 3, 7, 16, 23, 123456700)), + DataCreator.createPrimitive("PropertyDecimal", BigDecimal.valueOf(34.27)), + DataCreator.createPrimitive("PropertySingle", (float) 1.79000000E+20), + DataCreator.createPrimitive("PropertyDouble", -1.7900000000000000E+19), + DataCreator.createPrimitive("PropertyDuration", BigDecimal.valueOf(6)), + DataCreator.createPrimitive("PropertyGuid", GUID), + DataCreator.createPrimitive("PropertyInt16", Short.MAX_VALUE), + DataCreator.createPrimitive("PropertyInt32", Integer.MAX_VALUE), + DataCreator.createPrimitive("PropertyInt64", Long.MAX_VALUE), + DataCreator.createPrimitive("PropertySByte", Byte.MAX_VALUE), + DataCreator.createPrimitive("PropertyTimeOfDay", getTime(1, 0, 1))); + } else if (name.equals("BFCESTwoKeyNavRTCollCTNavFiveProp")) { + return DataCreator.createComplexCollection(name, + ComplexTypeProvider.nameCTNavFiveProp.getFullQualifiedNameAsString(), + Arrays.asList( + DataCreator.createPrimitive("PropertyInt16", (short) 1))); + } else if (name.equals("BFCESTwoKeyNavRTCollDecimal")) { + return DataCreator.createPrimitiveCollection(name, + 1d); + } else if (name.equals("BFCETTwoKeyNavRTCTTwoPrim")) { + return DataCreator.createComplex(name, + ComplexTypeProvider.nameCTTwoPrim.getFullQualifiedNameAsString(), + DataCreator.createPrimitive("PropertyInt16", (short) 16), + DataCreator.createPrimitive("PropertyString", "BFCETTwoKeyNavRTCTTwoPrim string value")); + } else { throw new DataProviderException("Function " + name + " is not yet implemented.", HttpStatusCode.NOT_IMPLEMENTED); } @@ -186,4 +230,45 @@ public class FunctionData { private static String getParameterString(final Map<String, Parameter> parameters) { return parameters.containsKey("ParameterString") ? (String) parameters.get("ParameterString").getValue() : null; } + + private static Calendar getParameterTimeOfDay(final Map<String, Parameter> parameters) { + return parameters.containsKey("ParameterTimeOfDay") ? (Calendar) parameters.get("ParameterTimeOfDay") + .getValue() : null; + } + + private static Calendar getDate(final int year, final int month, final int day) { + // Date values are always in the local timezone. + Calendar date = Calendar.getInstance(); + date.clear(); + date.set(year, month - 1, day, 0, 0, 0); + date.set(Calendar.MILLISECOND, 0); + return date; + } + + private static Calendar getTime(final int hour, final int minute, final int second) { + // Time values are always in the local timezone. + Calendar time = Calendar.getInstance(); + time.clear(); + time.set(1970, Calendar.JANUARY, 1, hour, minute, second); + time.set(Calendar.MILLISECOND, 0); + return time; + } + + private static Timestamp getTimestamp(final int year, final int month, final int day, + final int hour, final int minute, final int second, final int nanosecond) { + Timestamp timestamp = new Timestamp(getDateTime(year, month, day, hour, minute, second).getTimeInMillis()); + timestamp.setNanos(nanosecond); + return timestamp; + } + + + private static Calendar getDateTime(final int year, final int month, final int day, + final int hour, final int minute, final int second) { + // Date/Time values are serialized with a timezone offset, so we choose a predictable timezone. + Calendar dateTime = Calendar.getInstance(TimeZone.getTimeZone("GMT")); + dateTime.clear(); + dateTime.set(year, month - 1, day, hour, minute, second); + dateTime.set(Calendar.MILLISECOND, 0); + return dateTime; + } } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/1ce51fd4/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 2a99ea9..d3983a3 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 @@ -76,6 +76,7 @@ import org.apache.olingo.server.api.uri.UriResourceProperty; import org.apache.olingo.server.api.uri.queryoption.ExpandOption; import org.apache.olingo.server.api.uri.queryoption.SelectOption; import org.apache.olingo.server.tecsvc.data.DataProvider; +import org.apache.olingo.server.tecsvc.data.DataProvider.DataProviderException; /** * Technical Processor which provides functionality related to primitive and complex types and collections thereof. @@ -228,7 +229,7 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor getPropertyData( dataProvider.readFunctionPrimitiveComplex(((UriResourceFunction) resourceParts.get(0)).getFunction(), ((UriResourceFunction) resourceParts.get(0)).getParameters(), resource), path) : - getPropertyData(entity, path); + getData(entity, path, resourceParts, resource); // TODO: implement filter on collection properties (on a shallow copy of the values) // FilterHandler.applyFilterSystemQuery(uriInfo.getFilterOption(), property, uriInfo, serviceMetadata.getEdm()); @@ -257,13 +258,21 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor getComplexTypeFilter() != null) { type = ((UriResourceComplexProperty)resourceParts.get(resourceParts.size() - trailing - 1)). getComplexTypeFilter(); - } else { + }else if(resourceParts.get(resourceParts.size() - trailing - 1) + instanceof UriResourceFunction && + ((UriResourceFunction)resourceParts.get(resourceParts.size() - trailing - 1)). + getFunction() != null){ + type = ((UriResourceFunction)resourceParts.get(resourceParts.size() - trailing - 1)). + getType(); + }else { type = edmProperty == null ? ((UriResourceFunction) resourceParts.get(0)).getType() : edmProperty.getType(); } final EdmReturnType returnType = resourceParts.get(0) instanceof UriResourceFunction ? - ((UriResourceFunction) resourceParts.get(0)).getFunction().getReturnType() : null; + ((UriResourceFunction) resourceParts.get(0)).getFunction().getReturnType() : + resourceParts.get(1) instanceof UriResourceFunction ? + ((UriResourceFunction) resourceParts.get(1)).getFunction().getReturnType():null ; if (representationType == RepresentationType.VALUE) { response.setContent(serializePrimitiveValue(property, edmProperty, (EdmPrimitiveType) type, returnType)); @@ -291,6 +300,20 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor } } + private Property getData(Entity entity, List<String> path, List<UriResource> resourceParts, UriInfoResource resource) + throws DataProviderException { + if(resourceParts.size()>1 && resourceParts.get(1) instanceof UriResourceFunction){ + return dataProvider.readFunctionPrimitiveComplex(((UriResourceFunction) resourceParts.get(1)).getFunction(), + ((UriResourceFunction) resourceParts.get(1)).getParameters(), resource); + } + return getPropertyData(entity, path); + } + + private Property getFunctionData(UriResource uriResource) { + // TODO Auto-generated method stub + return null; + } + private void updateProperty(final ODataRequest request, ODataResponse response, final UriInfo uriInfo, final ContentType requestFormat, final ContentType responseFormat, final RepresentationType representationType) throws ODataApplicationException, ODataLibraryException { @@ -516,7 +539,8 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor && kind != UriResourceKind.primitiveProperty && kind != UriResourceKind.complexProperty && kind != UriResourceKind.count - && kind != UriResourceKind.value) { + && kind != UriResourceKind.value + && kind != UriResourceKind.function) { throw new ODataApplicationException("Invalid resource type.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/1ce51fd4/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/provider/FunctionProvider.java ---------------------------------------------------------------------- diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/provider/FunctionProvider.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/provider/FunctionProvider.java index 2776d2d..182469d 100644 --- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/provider/FunctionProvider.java +++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/provider/FunctionProvider.java @@ -120,6 +120,9 @@ public class FunctionProvider { public static final FullQualifiedName nameBFESTwoKeyNavRTESTwoKeyNav = new FullQualifiedName(SchemaProvider.NAMESPACE, "BFESTwoKeyNavRTESTwoKeyNav"); + + public static final FullQualifiedName nameBFESBaseRTESTwoBase = + new FullQualifiedName(SchemaProvider.NAMESPACE, "BFESBaseRTESTwoBase"); public static final FullQualifiedName nameBFCESTwoKeyNavRTCTNavFiveProp = new FullQualifiedName( SchemaProvider.NAMESPACE, "BFCESTwoKeyNavRTCTNavFiveProp"); @@ -984,6 +987,20 @@ public class FunctionProvider { new CsdlReturnType().setType(EntityTypeProvider.nameETTwoKeyNav).setCollection(true) .setNullable(false))); + } else if (functionName.equals(nameBFESBaseRTESTwoBase)) { + return Collections.singletonList( + new CsdlFunction() + .setName("BFESBaseRTESTwoBase") + .setBound(true) + .setParameters(Collections.singletonList( + new CsdlParameter().setName("BindingParam").setType(EntityTypeProvider.nameETBase) + .setNullable(false))) + .setComposable(true) + .setEntitySetPath("BindingParam/olingo.odata.test1.ETTwoBase") + .setReturnType( + new CsdlReturnType().setType(EntityTypeProvider.nameETTwoBase) + .setNullable(false))); + } else if (functionName.equals(nameBFCESKeyNavRTESTwoKeyNav)) { return Collections.singletonList( new CsdlFunction() http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/1ce51fd4/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/provider/SchemaProvider.java ---------------------------------------------------------------------- diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/provider/SchemaProvider.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/provider/SchemaProvider.java index 6d39976..074870e 100644 --- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/provider/SchemaProvider.java +++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/provider/SchemaProvider.java @@ -211,6 +211,7 @@ public class SchemaProvider { functions.addAll(prov.getFunctions(FunctionProvider.nameBFCESKeyNavRTESTwoKeyNav)); functions.addAll(prov.getFunctions(FunctionProvider.nameBFNESTwoKeyNavRTString)); functions.addAll(prov.getFunctions(FunctionProvider.nameBFCESTwoKeyNavRTCollDecimal)); + functions.addAll(prov.getFunctions(FunctionProvider.nameBFESBaseRTESTwoBase)); // functions.addAll(prov.getFunctions(FunctionProvider.nameBFCCTPrimCompRTESTwoKeyNavParam)); http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/1ce51fd4/samples/tutorials/p9_action/pom.xml ---------------------------------------------------------------------- diff --git a/samples/tutorials/p9_action/pom.xml b/samples/tutorials/p9_action/pom.xml index 7afaeee..cb5232f 100644 --- a/samples/tutorials/p9_action/pom.xml +++ b/samples/tutorials/p9_action/pom.xml @@ -30,7 +30,7 @@ <name>${project.artifactId}-Webapp</name> <build> - <finalName>DemoService</finalName> + <finalName>DemoService-Action</finalName> </build> <properties> http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/1ce51fd4/samples/tutorials/p9_action/src/main/java/myservice/mynamespace/data/Storage.java ---------------------------------------------------------------------- diff --git a/samples/tutorials/p9_action/src/main/java/myservice/mynamespace/data/Storage.java b/samples/tutorials/p9_action/src/main/java/myservice/mynamespace/data/Storage.java index 243dd8c..87598fc 100644 --- a/samples/tutorials/p9_action/src/main/java/myservice/mynamespace/data/Storage.java +++ b/samples/tutorials/p9_action/src/main/java/myservice/mynamespace/data/Storage.java @@ -144,6 +144,30 @@ public class Storage { return null; } + + public EntityCollection readEntitySetData(String edmEntityTypeName) throws ODataApplicationException { + + if (edmEntityTypeName.equals(DemoEdmProvider.ET_PRODUCT_NAME)) { + return getEntityCollection(productList); + } else if(edmEntityTypeName.equals(DemoEdmProvider.ET_CATEGORY_NAME)) { + return getEntityCollection(categoryList); + } + + return null; + } + + + public Entity readEntityData(String entityTypeName) { + + if (entityTypeName.equals(DemoEdmProvider.ET_PRODUCT_NAME)) { + return getEntityCollection(productList).getEntities().get(0); + } else if(entityTypeName.equals(DemoEdmProvider.ET_CATEGORY_NAME)) { + return getEntityCollection(categoryList).getEntities().get(0); + } + + return null; + + } public Entity readEntityData(EdmEntitySet edmEntitySet, List<UriParameter> keyParams) throws ODataApplicationException { http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/1ce51fd4/samples/tutorials/p9_action/src/main/java/myservice/mynamespace/service/DemoEdmProvider.java ---------------------------------------------------------------------- diff --git a/samples/tutorials/p9_action/src/main/java/myservice/mynamespace/service/DemoEdmProvider.java b/samples/tutorials/p9_action/src/main/java/myservice/mynamespace/service/DemoEdmProvider.java index 3f2f538..6e4ace6 100644 --- a/samples/tutorials/p9_action/src/main/java/myservice/mynamespace/service/DemoEdmProvider.java +++ b/samples/tutorials/p9_action/src/main/java/myservice/mynamespace/service/DemoEdmProvider.java @@ -82,6 +82,12 @@ public class DemoEdmProvider extends CsdlAbstractEdmProvider { public static final String FUNCTION_COUNT_CATEGORIES = "CountCategories"; public static final FullQualifiedName FUNCTION_COUNT_CATEGORIES_FQN = new FullQualifiedName(NAMESPACE, FUNCTION_COUNT_CATEGORIES); + //Bound Function + public static final String FUNCTION_PROVIDE_DISCOUNT = "GetDiscountProducts"; + public static final FullQualifiedName FUNCTION_PROVIDE_DISCOUNT_FQN = new FullQualifiedName(NAMESPACE, FUNCTION_PROVIDE_DISCOUNT); + + public static final String FUNCTION_PROVIDE_DISCOUNT_FOR_PRODUCT = "GetDiscountProduct"; + public static final FullQualifiedName FUNCTION_PROVIDE_DISCOUNT_FOR_PRODUCT_FQN = new FullQualifiedName(NAMESPACE, FUNCTION_PROVIDE_DISCOUNT_FOR_PRODUCT); // Function/Action Parameters public static final String PARAMETER_AMOUNT = "Amount"; @@ -89,6 +95,9 @@ public class DemoEdmProvider extends CsdlAbstractEdmProvider { //Bound Action Binding Parameter public static final String PARAMETER_CATEGORY = "ParamCategory"; + //Bound Function Binding Parameter + public static final String PARAMETER_BIND = "BindingParameter"; + @Override public List<CsdlAction> getActions(final FullQualifiedName actionName) { // It is allowed to overload actions, so we have to provide a list of Actions for each action name @@ -196,6 +205,65 @@ public class DemoEdmProvider extends CsdlAbstractEdmProvider { functions.add(function); return functions; + } else if (functionName.equals(FUNCTION_PROVIDE_DISCOUNT_FQN)) { + + final List<CsdlFunction> functions = new ArrayList<CsdlFunction>(); + + // Create the parameter for the function + final List<CsdlParameter> parameters = new ArrayList<CsdlParameter>(); + CsdlParameter parameter = new CsdlParameter(); + parameter.setName(PARAMETER_BIND); + parameter.setNullable(false); + parameter.setType(ET_CATEGORY_FQN); + parameter.setCollection(true); + parameters.add(parameter); + parameter = new CsdlParameter(); + parameter.setName(PARAMETER_AMOUNT); + parameter.setType(EdmPrimitiveTypeKind.Int32.getFullQualifiedName()); + parameters.add(parameter); + + // Create the return type of the function + final CsdlReturnType returnType = new CsdlReturnType(); + returnType.setCollection(true).setType(ET_PRODUCT_FQN); + + // Create the function + final CsdlFunction function = new CsdlFunction(); + function.setName(FUNCTION_PROVIDE_DISCOUNT_FQN.getName()) + .setParameters(parameters) + .setBound(true).setReturnType(returnType); + functions.add(function); + + return functions; + + } else if (functionName.equals(FUNCTION_PROVIDE_DISCOUNT_FOR_PRODUCT_FQN)) { + + final List<CsdlFunction> functions = new ArrayList<CsdlFunction>(); + + // Create the parameter for the function + final List<CsdlParameter> parameters = new ArrayList<CsdlParameter>(); + CsdlParameter parameter = new CsdlParameter(); + parameter.setName(PARAMETER_BIND); + parameter.setNullable(false); + parameter.setType(ET_CATEGORY_FQN); + parameters.add(parameter); + parameter = new CsdlParameter(); + parameter.setName(PARAMETER_AMOUNT); + parameter.setType(EdmPrimitiveTypeKind.Int32.getFullQualifiedName()); + parameters.add(parameter); + + // Create the return type of the function + final CsdlReturnType returnType = new CsdlReturnType(); + returnType.setType(ET_PRODUCT_FQN); + + // Create the function + final CsdlFunction function = new CsdlFunction(); + function.setName(FUNCTION_PROVIDE_DISCOUNT_FOR_PRODUCT_FQN.getName()) + .setParameters(parameters) + .setBound(true).setReturnType(returnType); + functions.add(function); + + return functions; + } return null; @@ -343,6 +411,8 @@ public class DemoEdmProvider extends CsdlAbstractEdmProvider { // add functions List<CsdlFunction> functions = new ArrayList<CsdlFunction>(); functions.addAll(getFunctions(FUNCTION_COUNT_CATEGORIES_FQN)); + functions.addAll(getFunctions(FUNCTION_PROVIDE_DISCOUNT_FQN)); + functions.addAll(getFunctions(FUNCTION_PROVIDE_DISCOUNT_FOR_PRODUCT_FQN)); schema.setFunctions(functions); // add EntityContainer http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/1ce51fd4/samples/tutorials/p9_action/src/main/java/myservice/mynamespace/service/DemoEntityCollectionProcessor.java ---------------------------------------------------------------------- diff --git a/samples/tutorials/p9_action/src/main/java/myservice/mynamespace/service/DemoEntityCollectionProcessor.java b/samples/tutorials/p9_action/src/main/java/myservice/mynamespace/service/DemoEntityCollectionProcessor.java index 471f2d1..c058296 100644 --- a/samples/tutorials/p9_action/src/main/java/myservice/mynamespace/service/DemoEntityCollectionProcessor.java +++ b/samples/tutorials/p9_action/src/main/java/myservice/mynamespace/service/DemoEntityCollectionProcessor.java @@ -170,6 +170,27 @@ public class DemoEntityCollectionProcessor implements EntityCollectionProcessor // note: we don't need to check uriResourceNavigation.isCollection(), // because we are the EntityCollectionProcessor responseEntityCollection = storage.getRelatedEntityCollection(sourceEntity, targetEntityType); + } else if (lastSegment instanceof UriResourceFunction) {// For bound function + UriResourceFunction uriResourceFunction = (UriResourceFunction) lastSegment; + // 2nd: fetch the data from backend + // first fetch the target entity type + String targetEntityType = uriResourceFunction.getFunction().getReturnType().getType().getName(); + // contextURL displays the last segment + for(EdmEntitySet entitySet : serviceMetadata.getEdm().getEntityContainer().getEntitySets()){ + if(targetEntityType.equals(entitySet.getEntityType().getName())){ + responseEdmEntitySet = entitySet; + break; + } + } + + // error handling for null entities + if (targetEntityType == null || responseEdmEntitySet == null) { + throw new ODataApplicationException("Entity not found.", + HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT); + } + + // then fetch the entity collection for the target type + responseEntityCollection = storage.readEntitySetData(targetEntityType); } } else { // this would be the case for e.g. Products(1)/Category/Products throw new ODataApplicationException("Not supported", http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/1ce51fd4/samples/tutorials/p9_action/src/main/java/myservice/mynamespace/service/DemoEntityProcessor.java ---------------------------------------------------------------------- diff --git a/samples/tutorials/p9_action/src/main/java/myservice/mynamespace/service/DemoEntityProcessor.java b/samples/tutorials/p9_action/src/main/java/myservice/mynamespace/service/DemoEntityProcessor.java index ffdee3f..54af258 100644 --- a/samples/tutorials/p9_action/src/main/java/myservice/mynamespace/service/DemoEntityProcessor.java +++ b/samples/tutorials/p9_action/src/main/java/myservice/mynamespace/service/DemoEntityProcessor.java @@ -156,9 +156,9 @@ public class DemoEntityProcessor implements EntityProcessor { List<UriParameter> keyPredicates = uriResourceEntitySet.getKeyPredicates(); responseEntity = storage.readEntityData(startEdmEntitySet, keyPredicates); } else if (segmentCount == 2) { // navigation - UriResource navSegment = resourceParts.get(1); // in our example we don't support more complex URIs - if (navSegment instanceof UriResourceNavigation) { - UriResourceNavigation uriResourceNavigation = (UriResourceNavigation) navSegment; + UriResource segment = resourceParts.get(1); // in our example we don't support more complex URIs + if (segment instanceof UriResourceNavigation) { + UriResourceNavigation uriResourceNavigation = (UriResourceNavigation) segment; EdmNavigationProperty edmNavigationProperty = uriResourceNavigation.getProperty(); responseEdmEntityType = edmNavigationProperty.getType(); // contextURL displays the last segment @@ -181,6 +181,30 @@ public class DemoEntityProcessor implements EntityProcessor { } else { // e.g. DemoService.svc/Categories(3)/Products(5) responseEntity = storage.getRelatedEntity(sourceEntity, responseEdmEntityType, navKeyPredicates); } + }else if (segment instanceof UriResourceFunction) { + UriResourceFunction uriResourceFunction = (UriResourceFunction) segment; + + // 2nd: fetch the data from backend. + // first fetch the target entity type + String targetEntityType = uriResourceFunction.getFunction().getReturnType().getType().getName(); + + // contextURL displays the last segment + for(EdmEntitySet entitySet : serviceMetadata.getEdm().getEntityContainer().getEntitySets()){ + if(targetEntityType.equals(entitySet.getEntityType().getName())){ + responseEdmEntityType = entitySet.getEntityType(); + responseEdmEntitySet = entitySet; + break; + } + } + + // error handling for null entities + if (targetEntityType == null || responseEdmEntitySet == null) { + throw new ODataApplicationException("Entity not found.", + HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT); + } + + // then fetch the entity collection for the target type + responseEntity = storage.readEntityData(targetEntityType); } } else { // this would be the case for e.g. Products(1)/Category/Products(1)/Category