Repository: olingo-odata4
Updated Branches:
  refs/heads/master 90781859b -> 03ad0444f


[OLINGO-545] support for navigation in technical service

Change-Id: I53e0330d9d8d73a868361c26569b992cb0bb91f3

Signed-off-by: Christian Amend <[email protected]>


Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/03ad0444
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/03ad0444
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/03ad0444

Branch: refs/heads/master
Commit: 03ad0444fa295ede4dba3ec13b8102b8fa5c56ee
Parents: 9078185
Author: Klaus Straubinger <[email protected]>
Authored: Tue Feb 17 15:57:48 2015 +0100
Committer: Christian Amend <[email protected]>
Committed: Tue Feb 17 16:32:57 2015 +0100

----------------------------------------------------------------------
 .../fit/tecsvc/client/NavigationITCase.java     | 142 +++++++++++++++++++
 .../apache/olingo/server/api/uri/UriHelper.java |   9 ++
 .../olingo/server/core/uri/UriHelperImpl.java   |  16 ++-
 .../olingo/server/tecsvc/data/DataProvider.java |  52 +++----
 .../processor/TechnicalEntityProcessor.java     |  89 ++++--------
 .../TechnicalPrimitiveComplexProcessor.java     | 124 +++++++---------
 .../tecsvc/processor/TechnicalProcessor.java    |  91 +++++++++++-
 7 files changed, 349 insertions(+), 174 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/03ad0444/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/NavigationITCase.java
----------------------------------------------------------------------
diff --git 
a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/NavigationITCase.java 
b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/NavigationITCase.java
new file mode 100644
index 0000000..0693836
--- /dev/null
+++ 
b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/NavigationITCase.java
@@ -0,0 +1,142 @@
+/* 
+ * 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.client;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import org.apache.olingo.client.api.CommonODataClient;
+import 
org.apache.olingo.client.api.communication.response.ODataRetrieveResponse;
+import org.apache.olingo.client.api.v4.ODataClient;
+import org.apache.olingo.client.core.ODataClientFactory;
+import org.apache.olingo.commons.api.domain.v4.ODataEntity;
+import org.apache.olingo.commons.api.domain.v4.ODataEntitySet;
+import org.apache.olingo.commons.api.domain.v4.ODataProperty;
+import org.apache.olingo.commons.api.format.ODataFormat;
+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 final class NavigationITCase extends AbstractBaseTestITCase {
+
+  private final CommonODataClient<?> client = getClient();
+
+  @Test
+  public void oneLevelToEntity() throws Exception {
+    final ODataRetrieveResponse<ODataEntity> response =
+        client.getRetrieveRequestFactory().<ODataEntity> getEntityRequest(
+            client.newURIBuilder(TecSvcConst.BASE_URI)
+                .appendEntitySetSegment("ESAllPrim").appendKeySegment(32767)
+                .appendNavigationSegment("NavPropertyETTwoPrimOne").build())
+            .execute();
+    assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode());
+
+    final ODataEntity entity = response.getBody();
+    assertNotNull(entity);
+    final ODataProperty property = entity.getProperty("PropertyString");
+    assertNotNull(property);
+    assertNotNull(property.getPrimitiveValue());
+    assertEquals("Test String4", property.getPrimitiveValue().toValue());
+  }
+
+  @Test
+  public void oneLevelToEntityWithKey() throws Exception {
+    final ODataRetrieveResponse<ODataEntity> response =
+        client.getRetrieveRequestFactory().<ODataEntity> getEntityRequest(
+            client.newURIBuilder(TecSvcConst.BASE_URI)
+                .appendEntitySetSegment("ESAllPrim").appendKeySegment(32767)
+                
.appendNavigationSegment("NavPropertyETTwoPrimMany").appendKeySegment(-365).build())
+            .execute();
+    assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode());
+
+    final ODataEntity entity = response.getBody();
+    assertNotNull(entity);
+    final ODataProperty property = entity.getProperty("PropertyString");
+    assertNotNull(property);
+    assertNotNull(property.getPrimitiveValue());
+    assertEquals("Test String2", property.getPrimitiveValue().toValue());
+  }
+
+  @Test
+  public void twoLevelsToEntityWithKey() throws Exception {
+    final ODataRetrieveResponse<ODataEntity> response =
+        client.getRetrieveRequestFactory().<ODataEntity> getEntityRequest(
+            client.newURIBuilder(TecSvcConst.BASE_URI)
+                .appendEntitySetSegment("ESTwoPrim").appendKeySegment(32767)
+                .appendNavigationSegment("NavPropertyETAllPrimOne")
+                
.appendNavigationSegment("NavPropertyETTwoPrimMany").appendKeySegment(-365).build())
+            .execute();
+    assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode());
+
+    final ODataEntity entity = response.getBody();
+    assertNotNull(entity);
+    final ODataProperty property = entity.getProperty("PropertyString");
+    assertNotNull(property);
+    assertNotNull(property.getPrimitiveValue());
+    assertEquals("Test String2", property.getPrimitiveValue().toValue());
+  }
+
+  @Test
+  public void twoLevelsToEntitySet() throws Exception {
+    final ODataRetrieveResponse<ODataEntitySet> response =
+        client.getRetrieveRequestFactory().<ODataEntitySet> 
getEntitySetRequest(
+            client.newURIBuilder(TecSvcConst.BASE_URI)
+                .appendEntitySetSegment("ESTwoPrim").appendKeySegment(32767)
+                .appendNavigationSegment("NavPropertyETAllPrimOne")
+                .appendNavigationSegment("NavPropertyETTwoPrimMany").build())
+            .execute();
+    assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode());
+
+    final ODataEntitySet entitySet = response.getBody();
+    assertNotNull(entitySet);
+    assertEquals(1, entitySet.getEntities().size());
+    final ODataEntity entity = entitySet.getEntities().get(0);
+    assertNotNull(entity);
+    final ODataProperty property = entity.getProperty("PropertyString");
+    assertNotNull(property);
+    assertNotNull(property.getPrimitiveValue());
+    assertEquals("Test String2", property.getPrimitiveValue().toValue());
+  }
+
+  @Test
+  public void twoLevelsToProperty() throws Exception {
+    final ODataRetrieveResponse<ODataProperty> response =
+        client.getRetrieveRequestFactory().<ODataProperty> getPropertyRequest(
+            client.newURIBuilder(TecSvcConst.BASE_URI)
+                .appendEntitySetSegment("ESKeyNav").appendKeySegment(1)
+                .appendNavigationSegment("NavPropertyETKeyNavOne")
+                
.appendNavigationSegment("NavPropertyETKeyNavMany").appendKeySegment(3)
+                
.appendPropertySegment("PropertyComp").appendPropertySegment("PropertyInt16").build())
+            .execute();
+    assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode());
+
+    final ODataProperty property = response.getBody();
+    assertNotNull(property);
+    assertNotNull(property.getPrimitiveValue());
+    assertEquals(1, property.getPrimitiveValue().toValue());
+  }
+
+  @Override
+  protected CommonODataClient<?> getClient() {
+    ODataClient odata = ODataClientFactory.getV4();
+    odata.getConfiguration().setDefaultPubFormat(ODataFormat.JSON);
+    return odata;
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/03ad0444/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/UriHelper.java
----------------------------------------------------------------------
diff --git 
a/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/UriHelper.java 
b/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/UriHelper.java
index 16ec276..672ce4b 100644
--- 
a/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/UriHelper.java
+++ 
b/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/UriHelper.java
@@ -22,6 +22,7 @@ import java.util.List;
 
 import org.apache.olingo.commons.api.data.Entity;
 import org.apache.olingo.commons.api.edm.EdmEntitySet;
+import org.apache.olingo.commons.api.edm.EdmEntityType;
 import org.apache.olingo.commons.api.edm.EdmStructuredType;
 import org.apache.olingo.server.api.serializer.SerializerException;
 import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
@@ -56,4 +57,12 @@ public interface UriHelper {
    * @return the relative canonical URL
    */
   String buildCanonicalURL(EdmEntitySet edmEntitySet, Entity entity) throws 
SerializerException;
+
+  /**
+   * Builds the key predicate for the given entity.
+   * @param edmEntityType the entity type of the entity
+   * @param entity        the entity data
+   * @return the key predicate
+   */
+  String buildKeyPredicate(EdmEntityType edmEntityType, Entity entity) throws 
SerializerException;
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/03ad0444/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriHelperImpl.java
----------------------------------------------------------------------
diff --git 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriHelperImpl.java
 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriHelperImpl.java
index 8bbbc3f..6e946de 100644
--- 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriHelperImpl.java
+++ 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriHelperImpl.java
@@ -50,10 +50,13 @@ public class UriHelperImpl implements UriHelper {
 
   @Override
   public String buildCanonicalURL(final EdmEntitySet edmEntitySet, final 
Entity entity) throws SerializerException {
-    StringBuilder result = new StringBuilder(edmEntitySet.getName());
-    result.append('(');
-    final EdmEntityType entityType = edmEntitySet.getEntityType();
-    final List<String> keyNames = entityType.getKeyPredicateNames();
+    return edmEntitySet.getName() + '(' + 
buildKeyPredicate(edmEntitySet.getEntityType(), entity) + ')';
+  }
+
+  @Override
+  public String buildKeyPredicate(final EdmEntityType edmEntityType, final 
Entity entity) throws SerializerException {
+    StringBuilder result = new StringBuilder();
+    final List<String> keyNames = edmEntityType.getKeyPredicateNames();
     boolean first = true;
     for (final String keyName : keyNames) {
       if (first) {
@@ -64,7 +67,7 @@ public class UriHelperImpl implements UriHelper {
       if (keyNames.size() > 1) {
         result.append(Encoder.encode(keyName)).append('=');
       }
-      final EdmProperty edmProperty = 
entityType.getStructuralProperty(keyName);
+      final EdmProperty edmProperty = 
edmEntityType.getStructuralProperty(keyName);
       final EdmPrimitiveType type = (EdmPrimitiveType) edmProperty.getType();
       final Object propertyValue = entity.getProperty(keyName).getValue();
       try {
@@ -78,7 +81,6 @@ public class UriHelperImpl implements UriHelper {
             SerializerException.MessageKeys.WRONG_PROPERTY_VALUE, 
edmProperty.getName(), propertyValue.toString());
       }
     }
-    result.append(')');
     return result.toString();
   }
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/03ad0444/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java
----------------------------------------------------------------------
diff --git 
a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java
 
b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java
index c35ba86..cb94467 100644
--- 
a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java
+++ 
b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java
@@ -58,34 +58,34 @@ public class DataProvider {
 
   public Entity read(final EdmEntitySet edmEntitySet, final List<UriParameter> 
keys) throws DataProviderException {
     final EntitySet entitySet = readAll(edmEntitySet);
-    if (entitySet == null) {
-      return null;
-    } else {
-      final EdmEntityType edmEntityType = edmEntitySet.getEntityType();
-      try {
-        for (final Entity entity : entitySet.getEntities()) {
-          boolean found = true;
-          for (final UriParameter key : keys) {
-            final EdmProperty property = (EdmProperty) 
edmEntityType.getProperty(key.getName());
-            final EdmPrimitiveType type = (EdmPrimitiveType) 
property.getType();
-            final Object value = entity.getProperty(key.getName()).getValue();
-            final Object keyValue = 
type.valueOfString(type.fromUriLiteral(key.getText()),
-                property.isNullable(), property.getMaxLength(), 
property.getPrecision(), property.getScale(),
-                property.isUnicode(),
-                Calendar.class.isAssignableFrom(value.getClass()) ? 
Calendar.class : value.getClass());
-            if (!value.equals(keyValue)) {
-              found = false;
-              break;
-            }
-          }
-          if (found) {
-            return entity;
+    return entitySet == null ? null : read(edmEntitySet.getEntityType(), 
entitySet, keys);
+  }
+
+  public Entity read(final EdmEntityType edmEntityType, final EntitySet 
entitySet, final List<UriParameter> keys)
+      throws DataProviderException {
+    try {
+      for (final Entity entity : entitySet.getEntities()) {
+        boolean found = true;
+        for (final UriParameter key : keys) {
+          final EdmProperty property = (EdmProperty) 
edmEntityType.getProperty(key.getName());
+          final EdmPrimitiveType type = (EdmPrimitiveType) property.getType();
+          final Object value = entity.getProperty(key.getName()).getValue();
+          final Object keyValue = 
type.valueOfString(type.fromUriLiteral(key.getText()),
+              property.isNullable(), property.getMaxLength(), 
property.getPrecision(), property.getScale(),
+              property.isUnicode(),
+              Calendar.class.isAssignableFrom(value.getClass()) ? 
Calendar.class : value.getClass());
+          if (!value.equals(keyValue)) {
+            found = false;
+            break;
           }
         }
-        return null;
-      } catch (final EdmPrimitiveTypeException e) {
-        throw new DataProviderException("Wrong key!", e);
+        if (found) {
+          return entity;
+        }
       }
+      return null;
+    } catch (final EdmPrimitiveTypeException e) {
+      throw new DataProviderException("Wrong key!", e);
     }
   }
 
@@ -201,7 +201,7 @@ public class DataProvider {
         property.setValue(property.getValueType(), value);
       }
     } else if (edmProperty.isCollection()) {
-      if (newProperty != null && 
!newProperty.asLinkedComplex().getValue().isEmpty()) {
+      if (newProperty != null && !newProperty.asCollection().isEmpty()) {
         throw new DataProviderException("Update of a complex-collection 
property not supported!");
       } else {
         property.asCollection().clear();

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/03ad0444/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java
----------------------------------------------------------------------
diff --git 
a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java
 
b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java
index 6cd3195..9868366 100644
--- 
a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java
+++ 
b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java
@@ -18,7 +18,6 @@
  */
 package org.apache.olingo.server.tecsvc.processor;
 
-import java.util.List;
 import java.util.Locale;
 
 import org.apache.olingo.commons.api.data.ContextURL;
@@ -45,13 +44,11 @@ import 
org.apache.olingo.server.api.processor.EntityCollectionProcessor;
 import org.apache.olingo.server.api.processor.EntityProcessor;
 import org.apache.olingo.server.api.processor.MediaEntityProcessor;
 import 
org.apache.olingo.server.api.serializer.EntityCollectionSerializerOptions;
-import org.apache.olingo.server.api.serializer.ODataSerializer;
 import org.apache.olingo.server.api.serializer.EntitySerializerOptions;
+import org.apache.olingo.server.api.serializer.ODataSerializer;
 import org.apache.olingo.server.api.serializer.SerializerException;
 import org.apache.olingo.server.api.uri.UriInfo;
-import org.apache.olingo.server.api.uri.UriResource;
 import org.apache.olingo.server.api.uri.UriResourceEntitySet;
-import org.apache.olingo.server.api.uri.UriResourceKind;
 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;
@@ -71,14 +68,14 @@ public class TechnicalEntityProcessor extends 
TechnicalProcessor
   public void readEntityCollection(final ODataRequest request, ODataResponse 
response, final UriInfo uriInfo,
       final ContentType requestedContentType) throws 
ODataApplicationException, SerializerException {
     validateOptions(uriInfo.asUriInfoResource());
-    blockNavigation(uriInfo);
-
-    final EdmEntitySet edmEntitySet = 
getEdmEntitySet(uriInfo.asUriInfoResource());
-    final EntitySet entitySet = readEntitySetInternal(edmEntitySet,
-        uriInfo.getCountOption() != null && 
uriInfo.getCountOption().getValue());
+    final EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo);
+    EntitySet entitySet = readEntityCollection(uriInfo);
     if (entitySet == null) {
       throw new ODataApplicationException("Nothing found.", 
HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT);
     } else {
+      if (uriInfo.getCountOption() != null && 
uriInfo.getCountOption().getValue()) {
+        setCount(entitySet);
+      }
       final ODataFormat format = 
ODataFormat.fromContentType(requestedContentType);
       ODataSerializer serializer = odata.createSerializer(format);
       final ExpandOption expand = uriInfo.getExpandOption();
@@ -107,15 +104,12 @@ public class TechnicalEntityProcessor extends 
TechnicalProcessor
   public void countEntityCollection(final ODataRequest request, ODataResponse 
response, final UriInfo uriInfo)
       throws ODataApplicationException, SerializerException {
     validateOptions(uriInfo.asUriInfoResource());
-    blockNavigation(uriInfo);
-
-    final List<UriResource> resourceParts = 
uriInfo.asUriInfoResource().getUriResourceParts();
-    final EntitySet entitySet =
-        readEntitySetInternal(((UriResourceEntitySet) 
resourceParts.get(resourceParts.size() - 2)).getEntitySet(),
-            true);
+    getEdmEntitySet(uriInfo);  // including checks
+    EntitySet entitySet = readEntityCollection(uriInfo);
     if (entitySet == null) {
       throw new ODataApplicationException("Nothing found.", 
HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT);
     } else {
+      setCount(entitySet);
       
response.setContent(odata.createFixedFormatSerializer().count(entitySet.getCount()));
       response.setStatusCode(HttpStatusCode.OK.getStatusCode());
       response.setHeader(HttpHeader.CONTENT_TYPE, HttpContentType.TEXT_PLAIN);
@@ -126,12 +120,8 @@ public class TechnicalEntityProcessor extends 
TechnicalProcessor
   public void readEntity(final ODataRequest request, ODataResponse response, 
final UriInfo uriInfo,
       final ContentType requestedContentType) throws 
ODataApplicationException, SerializerException {
     validateOptions(uriInfo.asUriInfoResource());
-    blockNavigation(uriInfo);
-
-    final EdmEntitySet edmEntitySet = 
getEdmEntitySet(uriInfo.asUriInfoResource());
-    final UriResourceEntitySet resourceEntitySet = (UriResourceEntitySet) 
uriInfo.getUriResourceParts().get(0);
-    final Entity entity = dataProvider.read(edmEntitySet, 
resourceEntitySet.getKeyPredicates());
-    checkEntity(entity);
+    final EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo);
+    final Entity entity = readEntity(uriInfo);
 
     final ODataFormat format = 
ODataFormat.fromContentType(requestedContentType);
     ODataSerializer serializer = odata.createSerializer(format);
@@ -150,10 +140,8 @@ public class TechnicalEntityProcessor extends 
TechnicalProcessor
   @Override
   public void readMediaEntity(final ODataRequest request, ODataResponse 
response, final UriInfo uriInfo,
       final ContentType responseFormat) throws ODataApplicationException, 
SerializerException {
-    blockNavigation(uriInfo);
-    final UriResourceEntitySet resourceEntitySet = (UriResourceEntitySet) 
uriInfo.getUriResourceParts().get(0);
-    final Entity entity = dataProvider.read(resourceEntitySet.getEntitySet(), 
resourceEntitySet.getKeyPredicates());
-    checkEntity(entity);
+    getEdmEntitySet(uriInfo);  // including checks
+    final Entity entity = readEntity(uriInfo);
     
response.setContent(odata.createFixedFormatSerializer().binary(dataProvider.readMedia(entity)));
     response.setStatusCode(HttpStatusCode.OK.getStatusCode());
     response.setHeader(HttpHeader.CONTENT_TYPE, entity.getMediaContentType());
@@ -170,7 +158,10 @@ public class TechnicalEntityProcessor extends 
TechnicalProcessor
   public void createEntity(final ODataRequest request, ODataResponse response, 
final UriInfo uriInfo,
       final ContentType requestFormat, final ContentType responseFormat)
           throws ODataApplicationException, DeserializerException, 
SerializerException {
-    blockNavigation(uriInfo);
+    if (uriInfo.asUriInfoResource().getUriResourceParts().size() > 1) {
+      throw new ODataApplicationException("Invalid resource type.",
+          HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
+    }
     checkRequestFormat(requestFormat);
     final UriResourceEntitySet resourceEntitySet = (UriResourceEntitySet) 
uriInfo.getUriResourceParts().get(0);
     final EdmEntitySet edmEntitySet = resourceEntitySet.getEntitySet();
@@ -204,11 +195,8 @@ public class TechnicalEntityProcessor extends 
TechnicalProcessor
   public void updateEntity(final ODataRequest request, final ODataResponse 
response, final UriInfo uriInfo,
       final ContentType requestFormat, final ContentType responseFormat)
           throws ODataApplicationException, DeserializerException, 
SerializerException {
-    blockNavigation(uriInfo);
-    final UriResourceEntitySet resourceEntitySet = (UriResourceEntitySet) 
uriInfo.getUriResourceParts().get(0);
-    final EdmEntitySet edmEntitySet = resourceEntitySet.getEntitySet();
-    Entity entity = dataProvider.read(edmEntitySet, 
resourceEntitySet.getKeyPredicates());
-    checkEntity(entity);
+    final EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo);
+    Entity entity = readEntity(uriInfo);
     checkRequestFormat(requestFormat);
     ODataDeserializer deserializer = 
odata.createDeserializer(ODataFormat.fromContentType(requestFormat));
     final Entity changedEntity = deserializer.entity(request.getBody(), 
edmEntitySet.getEntityType());
@@ -220,11 +208,8 @@ public class TechnicalEntityProcessor extends 
TechnicalProcessor
   public void updateMediaEntity(final ODataRequest request, ODataResponse 
response, final UriInfo uriInfo,
       final ContentType requestFormat, final ContentType responseFormat)
           throws ODataApplicationException, DeserializerException, 
SerializerException {
-    blockNavigation(uriInfo);
-    final UriResourceEntitySet resourceEntitySet = (UriResourceEntitySet) 
uriInfo.getUriResourceParts().get(0);
-    final EdmEntitySet edmEntitySet = resourceEntitySet.getEntitySet();
-    final Entity entity = dataProvider.read(edmEntitySet, 
resourceEntitySet.getKeyPredicates());
-    checkEntity(entity);
+    getEdmEntitySet(uriInfo);  // including checks
+    Entity entity = readEntity(uriInfo);
     checkRequestFormat(requestFormat);
     dataProvider.setMedia(entity, 
odata.createFixedFormatDeserializer().binary(request.getBody()),
         requestFormat.toContentTypeString());
@@ -234,11 +219,9 @@ public class TechnicalEntityProcessor extends 
TechnicalProcessor
   @Override
   public void deleteEntity(final ODataRequest request, ODataResponse response, 
final UriInfo uriInfo)
       throws ODataApplicationException {
-    blockNavigation(uriInfo);
-    final UriResourceEntitySet resourceEntitySet = (UriResourceEntitySet) 
uriInfo.getUriResourceParts().get(0);
-    final Entity entity = dataProvider.read(resourceEntitySet.getEntitySet(), 
resourceEntitySet.getKeyPredicates());
-    checkEntity(entity);
-    dataProvider.delete(resourceEntitySet.getEntitySet(), entity);
+    final EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo);
+    final Entity entity = readEntity(uriInfo);
+    dataProvider.delete(edmEntitySet, entity);
     response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
   }
 
@@ -250,31 +233,11 @@ public class TechnicalEntityProcessor extends 
TechnicalProcessor
         HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
   }
 
-  private void blockNavigation(final UriInfo uriInfo) throws 
ODataApplicationException {
-    final List<UriResource> parts = 
uriInfo.asUriInfoResource().getUriResourceParts();
-    if (parts.size() > 2
-        || parts.size() == 2
-            && parts.get(1).getKind() != UriResourceKind.count
-            && parts.get(1).getKind() != UriResourceKind.value) {
-      throw new ODataApplicationException("Invalid resource type.",
-          HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
-    }
-  }
-
-  private EntitySet readEntitySetInternal(final EdmEntitySet edmEntitySet, 
final boolean withCount)
-      throws DataProvider.DataProviderException {
-    EntitySet entitySet = dataProvider.readAll(edmEntitySet);
+  private void setCount(EntitySet entitySet) {
     // TODO: set count (correctly) and next link
-    if (withCount && entitySet.getCount() == null) {
+    if (entitySet.getCount() == null) {
       entitySet.setCount(entitySet.getEntities().size());
     }
-    return entitySet;
-  }
-
-  private void checkEntity(final Entity entity) throws 
ODataApplicationException {
-    if (entity == null) {
-      throw new ODataApplicationException("Nothing found.", 
HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT);
-    }
   }
 
   private void checkRequestFormat(final ContentType requestFormat) throws 
ODataApplicationException {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/03ad0444/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 c77b9a4..596fe95 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
@@ -61,7 +61,6 @@ 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.UriResourceEntitySet;
 import org.apache.olingo.server.api.uri.UriResourceKind;
 import org.apache.olingo.server.api.uri.UriResourceProperty;
 import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
@@ -73,9 +72,9 @@ import org.apache.olingo.server.tecsvc.data.DataProvider;
  */
 public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor
     implements PrimitiveProcessor, PrimitiveValueProcessor, 
ActionPrimitiveProcessor,
-        PrimitiveCollectionProcessor, ActionPrimitiveCollectionProcessor,
-        ComplexProcessor, ActionComplexProcessor,
-        ComplexCollectionProcessor, ActionComplexCollectionProcessor {
+    PrimitiveCollectionProcessor, ActionPrimitiveCollectionProcessor,
+    ComplexProcessor, ActionComplexProcessor,
+    ComplexCollectionProcessor, ActionComplexCollectionProcessor {
 
   public TechnicalPrimitiveComplexProcessor(final DataProvider dataProvider) {
     super(dataProvider);
@@ -84,11 +83,6 @@ public class TechnicalPrimitiveComplexProcessor extends 
TechnicalProcessor
   @Override
   public void readPrimitive(final ODataRequest request, ODataResponse 
response, final UriInfo uriInfo,
       final ContentType contentType) throws ODataApplicationException, 
SerializerException {
-    if(isFunctionImport(uriInfo)) {
-      throw new ODataApplicationException("Function imports are not supported 
yet in technical scenario.",
-              HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
-    }
-
     readProperty(response, uriInfo, contentType, RepresentationType.PRIMITIVE);
   }
 
@@ -108,8 +102,7 @@ public class TechnicalPrimitiveComplexProcessor extends 
TechnicalProcessor
 
   @Override
   public void processActionPrimitive(final ODataRequest request, final 
ODataResponse response,
-                                      final UriInfo uriInfo,
-                                      final ContentType requestFormat, final 
ContentType responseFormat)
+      final UriInfo uriInfo, final ContentType requestFormat, final 
ContentType responseFormat)
       throws ODataApplicationException, DeserializerException, 
SerializerException {
     throw new ODataApplicationException("Not supported yet.",
         HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
@@ -118,10 +111,6 @@ public class TechnicalPrimitiveComplexProcessor extends 
TechnicalProcessor
   @Override
   public void readPrimitiveCollection(final ODataRequest request, 
ODataResponse response, final UriInfo uriInfo,
       final ContentType contentType) throws ODataApplicationException, 
SerializerException {
-    if(isFunctionImport(uriInfo)) {
-      throw new ODataApplicationException("Function imports are not supported 
yet in technical scenario.",
-              HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
-    }
     readProperty(response, uriInfo, contentType, 
RepresentationType.COLLECTION_PRIMITIVE);
   }
 
@@ -141,10 +130,8 @@ public class TechnicalPrimitiveComplexProcessor extends 
TechnicalProcessor
 
   @Override
   public void processActionPrimitiveCollection(final ODataRequest request, 
final ODataResponse response,
-                                               final UriInfo uriInfo,
-                                               final ContentType 
requestFormat, final ContentType responseFormat)
-          throws ODataApplicationException, DeserializerException,
-      SerializerException {
+      final UriInfo uriInfo, final ContentType requestFormat, final 
ContentType responseFormat)
+      throws ODataApplicationException, DeserializerException, 
SerializerException {
     throw new ODataApplicationException("Not supported yet.",
         HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
   }
@@ -152,10 +139,6 @@ public class TechnicalPrimitiveComplexProcessor extends 
TechnicalProcessor
   @Override
   public void readComplex(final ODataRequest request, ODataResponse response, 
final UriInfo uriInfo,
       final ContentType contentType) throws ODataApplicationException, 
SerializerException {
-    if(isFunctionImport(uriInfo)) {
-      throw new ODataApplicationException("Function imports are not supported 
yet in technical scenario.",
-              HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
-    }
     readProperty(response, uriInfo, contentType, RepresentationType.COMPLEX);
   }
 
@@ -168,9 +151,9 @@ public class TechnicalPrimitiveComplexProcessor extends 
TechnicalProcessor
   }
 
   @Override
-  public void processActionComplex(ODataRequest request, ODataResponse 
response, UriInfo uriInfo, ContentType
-      requestFormat, ContentType responseFormat) throws 
ODataApplicationException, DeserializerException,
-      SerializerException {
+  public void processActionComplex(ODataRequest request, ODataResponse 
response, UriInfo uriInfo,
+      ContentType requestFormat, ContentType responseFormat)
+      throws ODataApplicationException, DeserializerException, 
SerializerException {
     throw new ODataApplicationException("Not supported yet.",
         HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
   }
@@ -184,10 +167,6 @@ public class TechnicalPrimitiveComplexProcessor extends 
TechnicalProcessor
   @Override
   public void readComplexCollection(final ODataRequest request, ODataResponse 
response, final UriInfo uriInfo,
       final ContentType contentType) throws ODataApplicationException, 
SerializerException {
-    if(isFunctionImport(uriInfo)) {
-      throw new ODataApplicationException("Function imports are not supported 
yet in technical scenario.",
-              HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
-    }
     readProperty(response, uriInfo, contentType, 
RepresentationType.COLLECTION_COMPLEX);
   }
 
@@ -201,9 +180,8 @@ public class TechnicalPrimitiveComplexProcessor extends 
TechnicalProcessor
 
   @Override
   public void processActionComplexCollection(ODataRequest request, 
ODataResponse response,
-                                             UriInfo uriInfo, ContentType 
requestFormat,
-                                             ContentType responseFormat)
-          throws ODataApplicationException, DeserializerException, 
SerializerException {
+      UriInfo uriInfo, ContentType requestFormat, ContentType responseFormat)
+      throws ODataApplicationException, DeserializerException, 
SerializerException {
     throw new ODataApplicationException("Not supported yet.",
         HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
   }
@@ -214,22 +192,18 @@ public class TechnicalPrimitiveComplexProcessor extends 
TechnicalProcessor
     deleteProperty(response, uriInfo);
   }
 
-  private boolean isFunctionImport(final UriInfo uriInfo) {
-    final List<UriResource> resourceParts = 
uriInfo.asUriInfoResource().getUriResourceParts();
-    return !resourceParts.isEmpty() && resourceParts.get(0).getKind() == 
UriResourceKind.function;
-  }
-
   private void readProperty(final ODataResponse response, final UriInfo 
uriInfo, final ContentType contentType,
       final RepresentationType representationType) throws 
ODataApplicationException, SerializerException {
     final UriInfoResource resource = uriInfo.asUriInfoResource();
     validateOptions(resource);
     validatePath(resource);
+    final EdmEntitySet edmEntitySet = getEdmEntitySet(resource);
 
     final List<UriResource> resourceParts = resource.getUriResourceParts();
-    final UriResourceEntitySet resourceEntitySet = (UriResourceEntitySet) 
resourceParts.get(0);
-    final List<String> path = getPropertyPath(resourceParts);
+    final List<String> path = getPropertyPath(resourceParts, 0);
 
-    final Property property = getPropertyData(resourceEntitySet, path);
+    final Entity entity = readEntity(uriInfo);
+    final Property property = getPropertyData(entity, path);
 
     if (property == null) {
       throw new ODataApplicationException("Nothing found.", 
HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT);
@@ -237,8 +211,8 @@ public class TechnicalPrimitiveComplexProcessor extends 
TechnicalProcessor
       if (property.getValue() == null) {
         response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
       } else {
-        final EdmEntitySet edmEntitySet = getEdmEntitySet(resource);
-        final EdmProperty edmProperty = ((UriResourceProperty) 
resourceParts.get(path.size())).getProperty();
+        final EdmProperty edmProperty = ((UriResourceProperty) 
resourceParts.get(resourceParts.size() - 1))
+            .getProperty();
 
         final ODataFormat format = ODataFormat.fromContentType(contentType);
         ODataSerializer serializer = odata.createSerializer(format);
@@ -247,8 +221,7 @@ public class TechnicalPrimitiveComplexProcessor extends 
TechnicalProcessor
         final UriHelper helper = odata.createUriHelper();
         final ContextURL contextURL = format == ODataFormat.JSON_NO_METADATA ? 
null :
             ContextURL.with().entitySet(edmEntitySet)
-                .keyPath(helper.buildContextURLKeyPredicate(
-                    ((UriResourceEntitySet) 
resourceParts.get(0)).getKeyPredicates()))
+                
.keyPath(helper.buildKeyPredicate(edmEntitySet.getEntityType(), entity))
                 .navOrPropertyPath(buildPropertyPath(path))
                 .selectList(edmProperty.isPrimitive() ? null :
                     helper.buildContextURLSelectList((EdmStructuredType) 
edmProperty.getType(), expand, select))
@@ -286,13 +259,15 @@ public class TechnicalPrimitiveComplexProcessor extends 
TechnicalProcessor
   private void deleteProperty(final ODataResponse response, final UriInfo 
uriInfo) throws ODataApplicationException {
     final UriInfoResource resource = uriInfo.asUriInfoResource();
     validatePath(resource);
+    getEdmEntitySet(uriInfo);  // including checks
 
     final List<UriResource> resourceParts = resource.getUriResourceParts();
-    final UriResourceEntitySet resourceEntitySet = (UriResourceEntitySet) 
resourceParts.get(0);
-    final List<String> path = getPropertyPath(resourceParts);
+    final List<String> path = getPropertyPath(resourceParts, 0);
 
-    final EdmProperty edmProperty = ((UriResourceProperty) 
resourceParts.get(path.size())).getProperty();
-    final Property property = getPropertyData(resourceEntitySet, path);
+    final Property property = getPropertyData(readEntity(uriInfo), path);
+
+    final EdmProperty edmProperty = ((UriResourceProperty) 
resourceParts.get(resourceParts.size() - 1))
+        .getProperty();
 
     if (edmProperty.isNullable() == null || edmProperty.isNullable()) {
       property.setValue(property.getValueType(), edmProperty.isCollection() ? 
Collections.emptyList() : null);
@@ -302,36 +277,31 @@ public class TechnicalPrimitiveComplexProcessor extends 
TechnicalProcessor
     }
   }
 
-  private Property getPropertyData(final UriResourceEntitySet 
resourceEntitySet, final List<String> path)
+  private Property getPropertyData(final Entity entity, final List<String> 
path)
       throws ODataApplicationException {
-    final Entity entity = dataProvider.read(resourceEntitySet.getEntitySet(), 
resourceEntitySet.getKeyPredicates());
-    if (entity == null) {
-      throw new ODataApplicationException("Nothing found.", 
HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT);
-    } else {
-      Property property = entity.getProperty(path.get(0));
-      for (final String name : path.subList(1, path.size())) {
-        if (property != null && (property.isLinkedComplex() || 
property.isComplex())) {
-          final List<Property> complex = property.isLinkedComplex() ?
-              property.asLinkedComplex().getValue() : property.asComplex();
-          property = null;
-          for (final Property innerProperty : complex) {
-            if (innerProperty.getName().equals(name)) {
-              property = innerProperty;
-              break;
-            }
+    Property property = entity.getProperty(path.get(0));
+    for (final String name : path.subList(1, path.size())) {
+      if (property != null && (property.isLinkedComplex() || 
property.isComplex())) {
+        final List<Property> complex = property.isLinkedComplex() ?
+            property.asLinkedComplex().getValue() : property.asComplex();
+        property = null;
+        for (final Property innerProperty : complex) {
+          if (innerProperty.getName().equals(name)) {
+            property = innerProperty;
+            break;
           }
         }
       }
-      return property;
     }
+    return property;
   }
 
-  private List<String> getPropertyPath(final List<UriResource> path) {
+  private List<String> getPropertyPath(final List<UriResource> path, final int 
trailing) {
     List<String> result = new LinkedList<String>();
-    int index = 1;
-    while (index < path.size() && path.get(index) instanceof 
UriResourceProperty) {
-      result.add(((UriResourceProperty) 
path.get(index)).getProperty().getName());
-      index++;
+    int index = path.size() - trailing - 1;
+    while (path.get(index) instanceof UriResourceProperty) {
+      result.add(0, ((UriResourceProperty) 
path.get(index)).getProperty().getName());
+      index--;
     }
     return result;
   }
@@ -350,17 +320,18 @@ public class TechnicalPrimitiveComplexProcessor extends 
TechnicalProcessor
     final UriInfoResource resource = uriInfo.asUriInfoResource();
     validateOptions(resource);
     validatePath(resource);
+    getEdmEntitySet(uriInfo);  // including checks
 
     final List<UriResource> resourceParts = resource.getUriResourceParts();
-    final UriResourceEntitySet resourceEntitySet = (UriResourceEntitySet) 
resourceParts.get(0);
-    final List<String> path = getPropertyPath(resourceParts);
+    final List<String> path = getPropertyPath(resourceParts, 1);
 
-    final Property property = getPropertyData(resourceEntitySet, path);
+    final Property property = getPropertyData(readEntity(uriInfo), path);
 
     if (property == null || property.getValue() == null) {
       response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
     } else {
-      final EdmProperty edmProperty = ((UriResourceProperty) 
resourceParts.get(path.size())).getProperty();
+      final EdmProperty edmProperty = ((UriResourceProperty) 
resourceParts.get(resourceParts.size() - 2))
+          .getProperty();
       final EdmPrimitiveType type = (EdmPrimitiveType) edmProperty.getType();
       final FixedFormatSerializer serializer = 
odata.createFixedFormatSerializer();
       response.setContent(type == 
EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Binary) ?
@@ -376,7 +347,8 @@ public class TechnicalPrimitiveComplexProcessor extends 
TechnicalProcessor
     final List<UriResource> resourcePaths = uriInfo.getUriResourceParts();
     for (final UriResource segment : resourcePaths.subList(1, 
resourcePaths.size())) {
       final UriResourceKind kind = segment.getKind();
-      if (kind != UriResourceKind.primitiveProperty
+      if (kind != UriResourceKind.navigationProperty
+          && kind != UriResourceKind.primitiveProperty
           && kind != UriResourceKind.complexProperty
           && kind != UriResourceKind.count
           && kind != UriResourceKind.value) {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/03ad0444/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 4fa3d36..3ecb4ed 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
@@ -18,19 +18,25 @@
  */
 package org.apache.olingo.server.tecsvc.processor;
 
-
 import java.util.List;
 import java.util.Locale;
 
+import org.apache.olingo.commons.api.data.Entity;
+import org.apache.olingo.commons.api.data.EntitySet;
+import org.apache.olingo.commons.api.data.Link;
+import org.apache.olingo.commons.api.edm.EdmBindingTarget;
 import org.apache.olingo.commons.api.edm.EdmEntitySet;
+import org.apache.olingo.commons.api.edm.EdmNavigationProperty;
 import org.apache.olingo.commons.api.http.HttpStatusCode;
 import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.ODataApplicationException;
 import org.apache.olingo.server.api.ServiceMetadata;
 import org.apache.olingo.server.api.processor.Processor;
 import org.apache.olingo.server.api.uri.UriInfoResource;
+import org.apache.olingo.server.api.uri.UriParameter;
 import org.apache.olingo.server.api.uri.UriResource;
 import org.apache.olingo.server.api.uri.UriResourceEntitySet;
+import org.apache.olingo.server.api.uri.UriResourceNavigation;
 import org.apache.olingo.server.tecsvc.data.DataProvider;
 
 /**
@@ -63,7 +69,88 @@ public abstract class TechnicalProcessor implements 
Processor {
       throw new ODataApplicationException("Type filters are not supported.",
           HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
     }
-    return uriResource.getEntitySet();
+    EdmEntitySet entitySet = uriResource.getEntitySet();
+
+    int navigationCount = 0;
+    while (++navigationCount < resourcePaths.size()
+        && resourcePaths.get(navigationCount) instanceof 
UriResourceNavigation) {
+      final UriResourceNavigation uriNavigationResource = 
(UriResourceNavigation) resourcePaths.get(navigationCount);
+      if (uriNavigationResource.getTypeFilterOnCollection() != null
+          || uriNavigationResource.getTypeFilterOnEntry() != null) {
+        throw new ODataApplicationException("Type filters are not supported.",
+            HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
+      }
+      if (uriNavigationResource.getProperty().containsTarget()) {
+        throw new ODataApplicationException("Containment navigation is not 
supported.",
+            HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
+      }
+      final EdmBindingTarget target = 
entitySet.getRelatedBindingTarget(uriNavigationResource.getProperty().getName());
+      if (target instanceof EdmEntitySet) {
+        entitySet = (EdmEntitySet) target;
+      } else {
+        throw new ODataApplicationException("Singletons are not supported.",
+            HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
+      }
+    }
+
+    return entitySet;
+  }
+
+  /**
+   * Reads an entity as specified in the resource path, including navigation.
+   * If there is navigation and the navigation ends on an entity collection,
+   * returns the entity before the final navigation segment.
+   */
+  protected Entity readEntity(final UriInfoResource uriInfo) throws 
ODataApplicationException {
+    final List<UriResource> resourcePaths = uriInfo.getUriResourceParts();
+    final UriResourceEntitySet uriResource = (UriResourceEntitySet) 
resourcePaths.get(0);
+    Entity entity = dataProvider.read(uriResource.getEntitySet(), 
uriResource.getKeyPredicates());
+    if (entity == null) {
+      throw new ODataApplicationException("Nothing found.", 
HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT);
+    }
+
+    int navigationCount = 0;
+    while (++navigationCount < resourcePaths.size()
+        && resourcePaths.get(navigationCount) instanceof 
UriResourceNavigation) {
+      final UriResourceNavigation uriNavigationResource = 
(UriResourceNavigation) resourcePaths.get(navigationCount);
+      final EdmNavigationProperty navigationProperty = 
uriNavigationResource.getProperty();
+      final List<UriParameter> key = uriNavigationResource.getKeyPredicates();
+      if (navigationProperty.isCollection() && key.isEmpty()) {
+        return entity;
+      }
+      final Link link = entity.getNavigationLink(navigationProperty.getName());
+      entity = link == null ? null :
+          key.isEmpty() ?
+              link.getInlineEntity() :
+              dataProvider.read(navigationProperty.getType(), 
link.getInlineEntitySet(), key);
+      if (entity == null) {
+        throw new ODataApplicationException("Nothing found.", 
HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT);
+      }
+    }
+
+    return entity;
+  }
+
+  protected EntitySet readEntityCollection(final UriInfoResource uriInfo) 
throws ODataApplicationException {
+    final List<UriResource> resourcePaths = uriInfo.getUriResourceParts();
+    if (resourcePaths.size() > 1 && resourcePaths.get(1) instanceof 
UriResourceNavigation) {
+      final Entity entity = readEntity(uriInfo);
+      final Link link = 
entity.getNavigationLink(getLastNavigation(uriInfo).getProperty().getName());
+      return link == null ? null : link.getInlineEntitySet();
+    } else {
+      return dataProvider.readAll(((UriResourceEntitySet) 
resourcePaths.get(0)).getEntitySet());
+    }
+  }
+
+  private UriResourceNavigation getLastNavigation(final UriInfoResource 
uriInfo) {
+    final List<UriResource> resourcePaths = uriInfo.getUriResourceParts();
+    int navigationCount = 1;
+    while (navigationCount < resourcePaths.size()
+        && resourcePaths.get(navigationCount) instanceof 
UriResourceNavigation) {
+      navigationCount++;
+    }
+    
+    return (UriResourceNavigation) resourcePaths.get(--navigationCount);
   }
 
   protected void validateOptions(final UriInfoResource uriInfo) throws 
ODataApplicationException {

Reply via email to