You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by ch...@apache.org on 2016/11/22 13:21:30 UTC

[1/2] olingo-odata4 git commit: [OLINGO-888] Support Singletons in OData dispatcher

Repository: olingo-odata4
Updated Branches:
  refs/heads/master ecf9b9f9b -> 6a736db10


[OLINGO-888] Support Singletons in OData dispatcher

Contributed by Archana Rai via
https://issues.apache.org/jira/browse/OLINGO-888


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

Branch: refs/heads/master
Commit: 84a052dcfa3825c37377c4cfd93c01f2c7e6af53
Parents: ecf9b9f
Author: Christian Amend <ch...@sap.com>
Authored: Tue Nov 22 14:13:14 2016 +0100
Committer: Christian Amend <ch...@sap.com>
Committed: Tue Nov 22 14:13:14 2016 +0100

----------------------------------------------------------------------
 .../olingo/server/core/ODataDispatcher.java     | 215 ++++++++++++-------
 .../olingo/server/tecsvc/data/DataCreator.java  |  38 +++-
 .../olingo/server/tecsvc/data/DataProvider.java |   9 +
 .../processor/TechnicalEntityProcessor.java     |  39 +++-
 .../tecsvc/processor/TechnicalProcessor.java    |  53 +++--
 .../server/core/ODataHandlerImplTest.java       | 163 +++++++++++++-
 6 files changed, 420 insertions(+), 97 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/84a052dc/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataDispatcher.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataDispatcher.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataDispatcher.java
index 138f45a..5d48e34 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataDispatcher.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataDispatcher.java
@@ -25,6 +25,7 @@ import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
 import org.apache.olingo.commons.api.edm.EdmReturnType;
 import org.apache.olingo.commons.api.edm.EdmType;
 import org.apache.olingo.commons.api.edm.constants.EdmTypeKind;
+import org.apache.olingo.commons.api.edm.EdmSingleton;
 import org.apache.olingo.commons.api.format.ContentType;
 import org.apache.olingo.commons.api.http.HttpHeader;
 import org.apache.olingo.commons.api.http.HttpMethod;
@@ -70,6 +71,7 @@ import org.apache.olingo.server.api.uri.UriResourcePrimitiveProperty;
 import org.apache.olingo.server.api.uri.UriResourceProperty;
 import org.apache.olingo.server.core.batchhandler.BatchHandler;
 import org.apache.olingo.server.core.etag.PreconditionsValidator;
+import org.apache.olingo.server.api.uri.UriResourceSingleton;
 
 public class ODataDispatcher {
 
@@ -144,7 +146,11 @@ public class ODataDispatcher {
       handleEntityDispatching(request, response,
           ((UriResourcePartTyped) lastPathSegment).isCollection(), isEntityOrNavigationMedia(lastPathSegment));
       break;
-
+      
+    case singleton:
+      handleSingleEntityDispatching(request, response, isSingletonMedia(lastPathSegment), true);
+      break;
+      
     case count:
       checkMethod(request.getMethod(), HttpMethod.GET);
       handleCountDispatching(request, response, lastPathSegmentIndex);
@@ -304,62 +310,80 @@ public class ODataDispatcher {
   private void handleValueDispatching(final ODataRequest request, final ODataResponse response,
       final int lastPathSegmentIndex) throws ODataApplicationException, ODataLibraryException {
     // The URI Parser already checked if $value is allowed here so we only have to dispatch to the correct processor
-    final HttpMethod method = request.getMethod();
     final UriResource resource = uriInfo.getUriResourceParts().get(lastPathSegmentIndex - 1);
     if (resource instanceof UriResourceProperty
         || resource instanceof UriResourceFunction
             && ((UriResourceFunction) resource).getType().getKind() == EdmTypeKind.PRIMITIVE) {
-      final EdmType type = resource instanceof UriResourceProperty ? ((UriResourceProperty) resource).getType()
-          : ((UriResourceFunction) resource).getType();
-      final RepresentationType valueRepresentationType =
-          type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Binary) ? RepresentationType.BINARY
-              : RepresentationType.VALUE;
-      if (method == HttpMethod.GET) {
-        final ContentType requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
-            request, handler.getCustomContentTypeSupport(), valueRepresentationType);
+      handlePrimitiveValueDispatching(request, response, resource);
+    } else {
+      handleMediaValueDispatching(request, response, resource);
+    }
+  }
 
-        handler.selectProcessor(PrimitiveValueProcessor.class)
-            .readPrimitiveValue(request, response, uriInfo, requestedContentType);
-      } else if (method == HttpMethod.PUT && resource instanceof UriResourceProperty) {
-        validatePreconditions(request, false);
-        final ContentType requestFormat = getSupportedContentType(request.getHeader(HttpHeader.CONTENT_TYPE),
-            valueRepresentationType, true);
-        final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
-            request, handler.getCustomContentTypeSupport(), valueRepresentationType);
-        handler.selectProcessor(PrimitiveValueProcessor.class)
-            .updatePrimitiveValue(request, response, uriInfo, requestFormat, responseFormat);
-      } else if (method == HttpMethod.DELETE && resource instanceof UriResourceProperty) {
-        validatePreconditions(request, false);
-        handler.selectProcessor(PrimitiveValueProcessor.class)
-            .deletePrimitiveValue(request, response, uriInfo);
-      } else {
-        throwMethodNotAllowed(method);
-      }
+  private void handleMediaValueDispatching(final ODataRequest request, final ODataResponse response,
+      final UriResource resource) throws ContentNegotiatorException, 
+     ODataApplicationException, ODataLibraryException,
+      ODataHandlerException, PreconditionException {
+    final HttpMethod method = request.getMethod();
+    if (method == HttpMethod.GET) {
+      // This can be a GET on an EntitySet, Navigation or Function
+      final ContentType requestedContentType = ContentNegotiator.
+          doContentNegotiation(uriInfo.getFormatOption(),
+          request, handler.getCustomContentTypeSupport(), RepresentationType.MEDIA);
+      handler.selectProcessor(MediaEntityProcessor.class)
+          .readMediaEntity(request, response, uriInfo, requestedContentType);
+      // PUT and DELETE can only be called on EntitySets or Navigation properties which are media resources
+    } else if (method == HttpMethod.PUT && (isEntityOrNavigationMedia(resource) 
+        || isSingletonMedia(resource))) {
+      validatePreconditions(request, true);
+      final ContentType requestFormat = ContentType.parse(request.getHeader(HttpHeader.CONTENT_TYPE));
+      final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
+          request, handler.getCustomContentTypeSupport(), RepresentationType.ENTITY);
+      handler.selectProcessor(MediaEntityProcessor.class)
+          .updateMediaEntity(request, response, uriInfo, requestFormat, responseFormat);
+    } else if (method == HttpMethod.DELETE && isEntityOrNavigationMedia(resource)) {
+      validatePreconditions(request, true);
+      handler.selectProcessor(MediaEntityProcessor.class)
+          .deleteMediaEntity(request, response, uriInfo);
     } else {
-      if (method == HttpMethod.GET) {
-        // This can be a GET on an EntitySet, Navigation or Function
-        final ContentType requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
-            request, handler.getCustomContentTypeSupport(), RepresentationType.MEDIA);
-        handler.selectProcessor(MediaEntityProcessor.class)
-            .readMediaEntity(request, response, uriInfo, requestedContentType);
-        // PUT and DELETE can only be called on EntitySets or Navigation properties which are media resources
-      } else if (method == HttpMethod.PUT && isEntityOrNavigationMedia(resource)) {
-        validatePreconditions(request, true);
-        final ContentType requestFormat = ContentType.parse(request.getHeader(HttpHeader.CONTENT_TYPE));
-        final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
-            request, handler.getCustomContentTypeSupport(), RepresentationType.ENTITY);
-        handler.selectProcessor(MediaEntityProcessor.class)
-            .updateMediaEntity(request, response, uriInfo, requestFormat, responseFormat);
-      } else if (method == HttpMethod.DELETE && isEntityOrNavigationMedia(resource)) {
-        validatePreconditions(request, true);
-        handler.selectProcessor(MediaEntityProcessor.class)
-            .deleteMediaEntity(request, response, uriInfo);
-      } else {
-        throwMethodNotAllowed(method);
-      }
+      throwMethodNotAllowed(method);
     }
   }
+  
+  private void handlePrimitiveValueDispatching(final ODataRequest request, final ODataResponse response,
+      final UriResource resource) throws ContentNegotiatorException, 
+  ODataApplicationException, ODataLibraryException,
+      ODataHandlerException, PreconditionException {
+    final HttpMethod method = request.getMethod();
+    final EdmType type = resource instanceof UriResourceProperty ?
+        ((UriResourceProperty) resource).getType() : ((UriResourceFunction) resource).getType();
+    final RepresentationType valueRepresentationType =
+        type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Binary) ?
+            RepresentationType.BINARY : RepresentationType.VALUE;
+    if (method == HttpMethod.GET) {
+      final ContentType requestedContentType = ContentNegotiator.
+          doContentNegotiation(uriInfo.getFormatOption(),
+          request, handler.getCustomContentTypeSupport(), valueRepresentationType);
 
+      handler.selectProcessor(PrimitiveValueProcessor.class)
+          .readPrimitiveValue(request, response, uriInfo, requestedContentType);
+    } else if (method == HttpMethod.PUT && resource instanceof UriResourceProperty) {
+      validatePreconditions(request, false);
+      final ContentType requestFormat = getSupportedContentType(request.getHeader(HttpHeader.CONTENT_TYPE),
+          valueRepresentationType, true);
+      final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
+          request, handler.getCustomContentTypeSupport(), valueRepresentationType);
+      handler.selectProcessor(PrimitiveValueProcessor.class)
+          .updatePrimitiveValue(request, response, uriInfo, requestFormat, responseFormat);
+    } else if (method == HttpMethod.DELETE && resource instanceof UriResourceProperty) {
+      validatePreconditions(request, false);
+      handler.selectProcessor(PrimitiveValueProcessor.class)
+          .deletePrimitiveValue(request, response, uriInfo);
+    } else {
+      throwMethodNotAllowed(method);
+    }
+  }
+  
   private void handleComplexDispatching(final ODataRequest request, final ODataResponse response,
       final boolean isCollection) throws ODataApplicationException, ODataLibraryException {
     final HttpMethod method = request.getMethod();
@@ -466,44 +490,76 @@ public class ODataDispatcher {
 
   private void handleEntityDispatching(final ODataRequest request, final ODataResponse response,
       final boolean isCollection, final boolean isMedia) throws ODataApplicationException, ODataLibraryException {
-    final HttpMethod method = request.getMethod();
     if (isCollection) {
-      if (method == HttpMethod.GET) {
-        final ContentType requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
-            request, handler.getCustomContentTypeSupport(), RepresentationType.COLLECTION_ENTITY);
-        handler.selectProcessor(EntityCollectionProcessor.class)
-            .readEntityCollection(request, response, uriInfo, requestedContentType);
-      } else if (method == HttpMethod.POST) {
-        final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
-            request, handler.getCustomContentTypeSupport(), RepresentationType.ENTITY);
-        if (isMedia) {
-          final ContentType requestFormat = ContentType.parse(request.getHeader(HttpHeader.CONTENT_TYPE));
-          handler.selectProcessor(MediaEntityProcessor.class)
-              .createMediaEntity(request, response, uriInfo, requestFormat, responseFormat);
-        } else {
-          final ContentType requestFormat = getSupportedContentType(request.getHeader(HttpHeader.CONTENT_TYPE),
-              RepresentationType.ENTITY, true);
-          handler.selectProcessor(EntityProcessor.class)
-              .createEntity(request, response, uriInfo, requestFormat, responseFormat);
-        }
+      handleEntityCollectionDispatching(request, response, isMedia);
       } else {
-        throwMethodNotAllowed(method);
+        handleSingleEntityDispatching(request, response, isMedia, false);
+      }
+  }
+
+  
+  private void handleEntityCollectionDispatching(final ODataRequest request, final ODataResponse response,
+      final boolean isMedia
+      ) throws ContentNegotiatorException, ODataApplicationException, ODataLibraryException,
+          ODataHandlerException {
+    final HttpMethod method = request.getMethod();
+    if (method == HttpMethod.GET) {
+      final ContentType requestedContentType = ContentNegotiator.
+          doContentNegotiation(uriInfo.getFormatOption(),
+          request, handler.getCustomContentTypeSupport(), RepresentationType.COLLECTION_ENTITY);
+      handler.selectProcessor(EntityCollectionProcessor.class)
+          .readEntityCollection(request, response, uriInfo, requestedContentType);
+    } else if (method == HttpMethod.POST) {
+      final ContentType responseFormat = ContentNegotiator.
+          doContentNegotiation(uriInfo.getFormatOption(),
+          request, handler.getCustomContentTypeSupport(), RepresentationType.ENTITY);
+      if (isMedia) {
+        final ContentType requestFormat = ContentType.parse(
+            request.getHeader(HttpHeader.CONTENT_TYPE));
+        handler.selectProcessor(MediaEntityProcessor.class)
+            .createMediaEntity(request, response, uriInfo, requestFormat, responseFormat);
+      } else {
+        final ContentType requestFormat = getSupportedContentType(
+            request.getHeader(HttpHeader.CONTENT_TYPE),
+            RepresentationType.ENTITY, true);
+        handler.selectProcessor(EntityProcessor.class)
+            .createEntity(request, response, uriInfo, requestFormat, responseFormat);
       }
     } else {
+      throwMethodNotAllowed(method);
+    }
+  }
+  
+  private boolean isSingletonMedia(final UriResource pathSegment) { 
+   return pathSegment instanceof UriResourceSingleton
+       && ((UriResourceSingleton) pathSegment).getEntityType().hasStream();
+  }
+
+  
+   
+  private void handleSingleEntityDispatching(final ODataRequest request, final ODataResponse response,
+        final boolean isMedia, final boolean isSingleton) throws 
+    ContentNegotiatorException, ODataApplicationException,
+        ODataLibraryException, ODataHandlerException, PreconditionException {
+      final HttpMethod method = request.getMethod();
       if (method == HttpMethod.GET) {
-        final ContentType requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
+        final ContentType requestedContentType = ContentNegotiator.
+            doContentNegotiation(uriInfo.getFormatOption(),
             request, handler.getCustomContentTypeSupport(), RepresentationType.ENTITY);
         handler.selectProcessor(EntityProcessor.class)
             .readEntity(request, response, uriInfo, requestedContentType);
       } else if (method == HttpMethod.PUT || method == HttpMethod.PATCH) {
         validatePreconditions(request, false);
-        final ContentType requestFormat = getSupportedContentType(request.getHeader(HttpHeader.CONTENT_TYPE),
+        final ContentType requestFormat = getSupportedContentType(
+            request.getHeader(HttpHeader.CONTENT_TYPE),
             RepresentationType.ENTITY, true);
-        final ContentType responseFormat = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
+        final ContentType responseFormat = ContentNegotiator.
+            doContentNegotiation(uriInfo.getFormatOption(),
             request, handler.getCustomContentTypeSupport(), RepresentationType.ENTITY);
         handler.selectProcessor(EntityProcessor.class)
             .updateEntity(request, response, uriInfo, requestFormat, responseFormat);
-      } else if (method == HttpMethod.DELETE) {
+      } else if (method == HttpMethod.DELETE && !isSingleton) {
+        validateIsSingleton(method);
         validatePreconditions(request, false);
         handler.selectProcessor(isMedia ? MediaEntityProcessor.class : EntityProcessor.class)
             .deleteEntity(request, response, uriInfo);
@@ -511,8 +567,23 @@ public class ODataDispatcher {
         throwMethodNotAllowed(method);
       }
     }
+
+  /*Delete method is not allowed for Entities navigating to Singleton*/ 
+  private void validateIsSingleton(HttpMethod method) throws ODataHandlerException {
+   final int lastPathSegmentIndex = uriInfo.getUriResourceParts().size() - 1;
+   final UriResource pathSegment = uriInfo.getUriResourceParts().get(lastPathSegmentIndex);
+   if(pathSegment instanceof UriResourceNavigation){
+   if(uriInfo.getUriResourceParts().get(lastPathSegmentIndex-1) instanceof UriResourceEntitySet){
+     if(((UriResourceEntitySet)uriInfo.getUriResourceParts().
+         get(lastPathSegmentIndex-1)).getEntitySet().getRelatedBindingTarget(
+         pathSegment.getSegmentValue())instanceof EdmSingleton){
+         throwMethodNotAllowed(method);
+       }
+     }
+   }
   }
 
+
   private void validatePreconditions(final ODataRequest request, final boolean isMediaValue)
       throws PreconditionException {
     // If needed perform preconditions validation.

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/84a052dc/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataCreator.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataCreator.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataCreator.java
index dfc1d78..39f7c81 100644
--- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataCreator.java
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataCreator.java
@@ -88,13 +88,27 @@ public class DataCreator {
     data.put("ESStream", createESStream(edm, odata));
     data.put("ESWithStream", createESWithStream(edm, odata));
     data.put("ESPeople", createESPeople(edm, odata));
+    data.put("SINav", createSINav(edm, odata));
+    data.put("SI", createESTwoPrim(edm, odata));
 
+    linkSINav(data);
     linkESTwoPrim(data);
     linkESAllPrim(data);
     linkESKeyNav(data);
     linkESTwoKeyNav(data);
     linkESPeople(data);
   }
+  
+  private EntityCollection createSINav(Edm edm, OData odata) {
+    final EntityCollection entityCollection = new EntityCollection();
+
+    entityCollection.getEntities().add(createESTwoKeyNavEntity((short) 1, "1"));
+
+  setEntityType(entityCollection, edm.getEntityType(EntityTypeProvider.nameETTwoKeyNav));
+  createEntityId(edm, odata, "ESTwoKeyNav", entityCollection);
+  createOperations("ESTwoKeyNav", entityCollection, EntityTypeProvider.nameETTwoKeyNav);
+  return entityCollection;
+}
 
   private EntityCollection createESMixEnumDefCollComp(Edm edm, OData odata) {
     final EntityCollection entityCollection = new EntityCollection();
@@ -1362,7 +1376,8 @@ public class DataCreator {
     final EntityCollection entityCollection = data.get("ESTwoKeyNav");
     final List<Entity> esKeyNavTargets = data.get("ESKeyNav").getEntities();
     final List<Entity> esTwoKeyNavTargets = data.get("ESTwoKeyNav").getEntities();
-
+    final  List<Entity> SINav = data.get("SINav").getEntities();
+    
     // NavPropertyETKeyNavOne
     setLink(entityCollection.getEntities().get(0), "NavPropertyETKeyNavOne", esKeyNavTargets.get(0));
     setLink(entityCollection.getEntities().get(1), "NavPropertyETKeyNavOne", esKeyNavTargets.get(0));
@@ -1387,6 +1402,27 @@ public class DataCreator {
         esTwoKeyNavTargets.get(1));
     setLinks(entityCollection.getEntities().get(1), "NavPropertyETTwoKeyNavMany", esTwoKeyNavTargets.get(0));
     setLinks(entityCollection.getEntities().get(2), "NavPropertyETTwoKeyNavMany", esTwoKeyNavTargets.get(1));
+    // NavPropertySINav
+    setLink(entityCollection.getEntities().get(0), "NavPropertySINav", SINav.get(0));
+       setLink(entityCollection.getEntities().get(1), "NavPropertySINav", SINav.get(0));
+       setLink(entityCollection.getEntities().get(2), "NavPropertySINav", SINav.get(0));
+
+  }
+
+   private void linkSINav(final Map<String, EntityCollection> data) {
+     final EntityCollection entityCollection = data.get("SINav");
+     final List<Entity> esKeyNavTargets = data.get("ESKeyNav").getEntities();
+     final List<Entity> esTwoKeyNavTargets = data.get("ESTwoKeyNav").getEntities();
+
+     // NavPropertyETKeyNavOne
+     setLink(entityCollection.getEntities().get(0), "NavPropertyETKeyNavOne", esKeyNavTargets.get(0));
+   
+     // NavPropertyETTwoKeyNavOne
+     setLink(entityCollection.getEntities().get(0), "NavPropertyETTwoKeyNavOne", esTwoKeyNavTargets.get(0));
+
+     // NavPropertyETTwoKeyNavMany
+     setLinks(entityCollection.getEntities().get(0), "NavPropertyETTwoKeyNavMany", esTwoKeyNavTargets.get(0),
+         esTwoKeyNavTargets.get(1));
   }
 
   protected static Property createPrimitive(final String name, final Object value) {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/84a052dc/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 465ab80..b526887 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
@@ -51,6 +51,7 @@ import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
 import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
 import org.apache.olingo.commons.api.edm.EdmProperty;
 import org.apache.olingo.commons.api.edm.EdmStructuredType;
+import org.apache.olingo.commons.api.edm.EdmSingleton;
 import org.apache.olingo.commons.api.edm.EdmType;
 import org.apache.olingo.commons.api.edm.EdmTypeDefinition;
 import org.apache.olingo.commons.api.edm.FullQualifiedName;
@@ -700,4 +701,12 @@ public class DataProvider {
       super(message, statusCode.getStatusCode(), Locale.ROOT, throwable);
     }
   }
+  
+  public Entity read(EdmSingleton singleton) {
+    if (data.containsKey(singleton.getName())) {
+    EntityCollection entitySet = data.get(singleton.getName());
+    return entitySet.getEntities().get(0);
+    }
+    return null;
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/84a052dc/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 e6b625e..da2e936 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
@@ -64,6 +64,7 @@ import org.apache.olingo.server.api.uri.UriInfo;
 import org.apache.olingo.server.api.uri.UriResourceEntitySet;
 import org.apache.olingo.server.api.uri.UriResourceNavigation;
 import org.apache.olingo.server.api.uri.UriResourcePartTyped;
+import org.apache.olingo.server.api.uri.UriResourceSingleton;
 import org.apache.olingo.server.api.uri.queryoption.CountOption;
 import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
 import org.apache.olingo.server.api.uri.queryoption.IdOption;
@@ -421,10 +422,11 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
     //
 
     final EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo);
-    final EdmEntityType edmEntityType = edmEntitySet == null ?
-        (EdmEntityType) ((UriResourcePartTyped) uriInfo.getUriResourceParts()
-            .get(uriInfo.getUriResourceParts().size() - 1)).getType() :
-        edmEntitySet.getEntityType();
+    
+    //for Singleton/$ref edmEntityset will be null throw error
+    validateSingletonRef(isReference,edmEntitySet);
+   
+    final EdmEntityType edmEntityType = getEdmType(uriInfo, edmEntitySet);
 
     final Entity entity = readEntity(uriInfo);
 
@@ -456,6 +458,35 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
     response.setHeader(HttpHeader.CONTENT_TYPE, requestedFormat.toContentTypeString());
   }
 
+  /*This method validates if the $ref is called directly on Singleton
+   * Error is thrown when $ref is called on a Singleton as it is not implemented*/
+  private void validateSingletonRef(boolean isReference, EdmEntitySet edmEntitySet) throws
+  ODataApplicationException {
+   if(isReference && edmEntitySet==null){
+         throw new ODataApplicationException("$ref not implemented on singleton",
+                    HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
+        
+      }
+  
+  }
+  
+  /*This method returns edmType of the entityset or Singleton*/  
+  private EdmEntityType getEdmType(UriInfo uriInfo, EdmEntitySet edmEntitySet) {
+    if(edmEntitySet!=null){
+      return edmEntitySet.getEntityType();
+    }else if(edmEntitySet==null && uriInfo.getUriResourceParts()
+              .get(uriInfo.getUriResourceParts().size() - 1) instanceof UriResourcePartTyped){
+      return  (EdmEntityType) ((UriResourcePartTyped) uriInfo.getUriResourceParts()
+                .get(uriInfo.getUriResourceParts().size() - 1)).getType();
+    }else if((UriResourceSingleton) uriInfo.getUriResourceParts()
+              .get(0) instanceof UriResourceSingleton){
+      return (EdmEntityType)((UriResourceSingleton) uriInfo.getUriResourceParts()
+                .get(0)).getType();
+    }
+
+  return null;
+  }
+
   private void readEntityCollection(final ODataRequest request, final ODataResponse response,
       final UriInfo uriInfo, final ContentType requestedContentType, final boolean isReference)
       throws ODataApplicationException, ODataLibraryException {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/84a052dc/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 c59bec9..47a9a63 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
@@ -29,6 +29,7 @@ import org.apache.olingo.commons.api.edm.EdmEntitySet;
 import org.apache.olingo.commons.api.edm.EdmEntityType;
 import org.apache.olingo.commons.api.edm.EdmFunction;
 import org.apache.olingo.commons.api.edm.EdmNavigationProperty;
+import org.apache.olingo.commons.api.edm.EdmSingleton;
 import org.apache.olingo.commons.api.format.ContentType;
 import org.apache.olingo.commons.api.http.HttpStatusCode;
 import org.apache.olingo.server.api.OData;
@@ -43,6 +44,7 @@ import org.apache.olingo.server.api.uri.UriResourceAction;
 import org.apache.olingo.server.api.uri.UriResourceEntitySet;
 import org.apache.olingo.server.api.uri.UriResourceFunction;
 import org.apache.olingo.server.api.uri.UriResourceNavigation;
+import org.apache.olingo.server.api.uri.UriResourceSingleton;
 import org.apache.olingo.server.tecsvc.data.DataProvider;
 
 /**
@@ -72,7 +74,8 @@ public abstract class TechnicalProcessor implements Processor {
   protected EdmEntitySet getEdmEntitySet(final UriInfoResource uriInfo) throws ODataApplicationException {
     EdmEntitySet entitySet = null;
     final List<UriResource> resourcePaths = uriInfo.getUriResourceParts();
-
+    EdmSingleton singleton = null;
+    
     // First must be an entity, an entity collection, a function import, or an action import.
     blockTypeFilters(resourcePaths.get(0));
     if (resourcePaths.get(0) instanceof UriResourceEntitySet) {
@@ -81,30 +84,41 @@ public abstract class TechnicalProcessor implements Processor {
       entitySet = ((UriResourceFunction) resourcePaths.get(0)).getFunctionImport().getReturnedEntitySet();
     } else if (resourcePaths.get(0) instanceof UriResourceAction) {
       entitySet = ((UriResourceAction) resourcePaths.get(0)).getActionImport().getReturnedEntitySet();
+    }else if (resourcePaths.get(0) instanceof UriResourceSingleton ) {      
+      singleton =((UriResourceSingleton) resourcePaths.get(0)).getSingleton();
     } else {
       throw new ODataApplicationException("Invalid resource type.",
           HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
     }
 
+    entitySet = (EdmEntitySet) getEntitySetForNavigation(entitySet, singleton, resourcePaths);
+
+    return entitySet;
+  }
+  
+  private EdmBindingTarget getEntitySetForNavigation(EdmEntitySet entitySet, EdmSingleton singleton,
+      List<UriResource> resourcePaths) throws ODataApplicationException {
     int navigationCount = 0;
-    while (entitySet != null
-        && ++navigationCount < resourcePaths.size()
-        && resourcePaths.get(navigationCount) instanceof UriResourceNavigation) {
-      final UriResourceNavigation uriResourceNavigation = (UriResourceNavigation) resourcePaths.get(navigationCount);
-      blockTypeFilters(uriResourceNavigation);
-      if (uriResourceNavigation.getProperty().containsTarget()) {
-        throw new ODataApplicationException("Containment navigation is not supported.",
-            HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
-      }
-      final EdmBindingTarget target = entitySet.getRelatedBindingTarget(uriResourceNavigation.getProperty().getName());
-      if (target instanceof EdmEntitySet) {
-        entitySet = (EdmEntitySet) target;
-      } else {
-        throw new ODataApplicationException("Singletons are not supported.",
-            HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
+      while ((entitySet != null || singleton!=null)
+          && ++navigationCount < resourcePaths.size()
+          && resourcePaths.get(navigationCount) instanceof UriResourceNavigation) {
+        final UriResourceNavigation uriResourceNavigation = 
+            (UriResourceNavigation) resourcePaths.get(navigationCount);
+        blockTypeFilters(uriResourceNavigation);
+        if (uriResourceNavigation.getProperty().containsTarget()) {
+          throw new ODataApplicationException("Containment navigation is not supported.",
+              HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
+        }
+        EdmBindingTarget target = null ;
+        if(entitySet!=null){
+          target = entitySet.getRelatedBindingTarget(uriResourceNavigation.getProperty().getName());
+        }else if(singleton != null){
+          target = singleton.getRelatedBindingTarget(uriResourceNavigation.getProperty().getName());
+        }
+        if (target instanceof EdmEntitySet) {
+          entitySet = (EdmEntitySet) target;
+        }
       }
-    }
-
     return entitySet;
   }
 
@@ -130,6 +144,9 @@ public abstract class TechnicalProcessor implements Processor {
     if (resourcePaths.get(0) instanceof UriResourceEntitySet) {
       final UriResourceEntitySet uriResource = (UriResourceEntitySet) resourcePaths.get(0);
       entity = dataProvider.read(uriResource.getEntitySet(), uriResource.getKeyPredicates());
+    }else if (resourcePaths.get(0) instanceof UriResourceSingleton) {
+      final UriResourceSingleton uriResource = (UriResourceSingleton) resourcePaths.get(0);
+      entity = dataProvider.read( uriResource.getSingleton());
     } else if (resourcePaths.get(0) instanceof UriResourceFunction) {
       final UriResourceFunction uriResource = (UriResourceFunction) resourcePaths.get(0);
       final EdmFunction function = uriResource.getFunction();

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/84a052dc/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerImplTest.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerImplTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerImplTest.java
index 591e8e2..bacb700 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerImplTest.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerImplTest.java
@@ -624,6 +624,112 @@ public class ODataHandlerImplTest {
     dispatchMethodNotAllowed(HttpMethod.HEAD, uri, processor);
   }
 
+
+  @Test
+  public void dispatchSingleton() throws Exception {
+    final String uri = "SI";
+    final EntityProcessor processor = mock(EntityProcessor.class);
+    
+    dispatch(HttpMethod.GET, uri, processor);
+    verify(processor).readEntity(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class));
+
+    dispatch(HttpMethod.PATCH, uri, processor);
+    verify(processor).updateEntity(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class),
+        any(ContentType.class));
+
+    dispatch(HttpMethod.PUT, uri, processor);
+    verify(processor, times(2)).updateEntity(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class),
+        any(ContentType.class));
+
+    dispatchMethodNotAllowed(HttpMethod.POST, uri, processor);
+    dispatchMethodNotAllowed(HttpMethod.DELETE, uri, processor);
+  }
+  
+  @Test
+  public void dispatchSingletonMedia() throws Exception {
+    final String uri = "SIMedia/$value";
+    final MediaEntityProcessor processor = mock(MediaEntityProcessor.class);
+    
+    dispatch(HttpMethod.GET, uri, processor);
+    verify(processor).readMediaEntity(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class));
+
+    dispatch(HttpMethod.PUT, uri, processor);
+    verify(processor).updateMediaEntity(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class),
+        any(ContentType.class));
+
+    dispatchMethodNotAllowed(HttpMethod.PATCH, uri, processor);
+    dispatchMethodNotAllowed(HttpMethod.POST, uri, processor);
+    dispatchMethodNotAllowed(HttpMethod.DELETE, uri, processor);
+  }
+  
+  @Test
+  public void dispatchSingletonNavigation() throws Exception {
+    final String uri = "SINav/NavPropertyETTwoKeyNavOne";
+    final String sigletonNavUri = "ESTwoKeyNav(PropertyInt16=1,PropertyString='1')/NavPropertySINav";
+    final String sigletonManyNavUri = "SINav/NavPropertyETTwoKeyNavMany";
+    final EntityProcessor processor = mock(EntityProcessor.class);
+    final EntityCollectionProcessor collectionProcessor = mock(EntityCollectionProcessor.class);
+    
+    dispatch(HttpMethod.GET, sigletonNavUri, processor);
+    verify(processor).readEntity(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class));
+
+    dispatch(HttpMethod.PATCH, sigletonNavUri, processor);
+    verify(processor).updateEntity(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class),
+        any(ContentType.class));
+
+    dispatch(HttpMethod.PUT, sigletonNavUri, processor);
+    verify(processor, times(2)).updateEntity(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class),
+        any(ContentType.class));
+
+    dispatchMethodNotAllowed(HttpMethod.POST, sigletonNavUri, processor);
+    dispatchMethodNotAllowed(HttpMethod.DELETE, sigletonNavUri, processor);
+    
+    dispatch(HttpMethod.GET, uri, processor);
+    verify(processor, times(2)).readEntity(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class));
+
+    dispatch(HttpMethod.PATCH, uri, processor);
+    verify(processor,  times(3)).updateEntity(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class),
+        any(ContentType.class));
+
+    dispatch(HttpMethod.PUT, uri, processor);
+    verify(processor, times(4)).updateEntity(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class),
+        any(ContentType.class));
+    
+    dispatchMethodNotAllowed(HttpMethod.POST, uri, processor);
+
+    dispatch(HttpMethod.DELETE, uri, processor);
+    verify(processor).deleteEntity(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class));
+    
+    
+    dispatch(HttpMethod.GET, sigletonManyNavUri, collectionProcessor);
+    verify(collectionProcessor).readEntityCollection(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class));
+    
+    dispatchMethodNotAllowed(HttpMethod.PATCH, sigletonManyNavUri, processor);
+    
+    dispatchMethodNotAllowed(HttpMethod.PUT, sigletonManyNavUri, processor);
+    
+    dispatch(HttpMethod.POST, sigletonManyNavUri, processor);
+    verify(processor).createEntity(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class),
+        any(ContentType.class));
+
+
+    dispatchMethodNotAllowed(HttpMethod.DELETE, sigletonManyNavUri, processor);
+  }
+  
   @Test
   public void dispatchMedia() throws Exception {
     final String uri = "ESMedia(1)/$value";
@@ -859,6 +965,9 @@ public class ODataHandlerImplTest {
   public void dispatchReference() throws Exception {
     final String uri = "ESAllPrim(0)/NavPropertyETTwoPrimOne/$ref";
     final String uriMany = "ESAllPrim(0)/NavPropertyETTwoPrimMany/$ref";
+    final String singletonUri = "SINav/NavPropertyETKeyNavOne/$ref";
+    final String singletonUriMany = "SINav/NavPropertyETTwoKeyNavMany/$ref";
+    final String singleUri = "SINav/$ref";
     final ReferenceProcessor processor = mock(ReferenceProcessor.class);
 
     dispatch(HttpMethod.GET, uri, processor);
@@ -882,12 +991,52 @@ public class ODataHandlerImplTest {
     dispatch(HttpMethod.DELETE, uriMany, "$id=ESTwoPrim(1)", null, null, processor);
     verify(processor).deleteReference(any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class));
     
-    dispatchMethodNotAllowed(HttpMethod.HEAD, uri, processor);
+    dispatchMethodNotAllowed(HttpMethod.HEAD, uri, processor);    
+    
+    //singleton URIs
+    
+    dispatch(HttpMethod.GET, singletonUri, processor);
+    verify(processor, times(2)).readReference(any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class),
+        any(ContentType.class));
+
+    dispatch(HttpMethod.PATCH, singletonUri, processor);
+    verify(processor, times(3)).updateReference(any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class),
+        any(ContentType.class));
+
+    dispatch(HttpMethod.PUT, singletonUri, processor);
+    verify(processor, times(4)).updateReference(any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class),
+        any(ContentType.class));
+
+    dispatchMethodNotAllowed(HttpMethod.POST, singletonUri, processor); 
+    
+    dispatch(HttpMethod.GET, singleUri, processor);
+    verify(processor, times(3)).readReference(any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class),
+        any(ContentType.class));
+
+    dispatch(HttpMethod.PATCH, singleUri, processor);
+    verify(processor, times(5)).updateReference(any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class),
+        any(ContentType.class));
+
+    dispatch(HttpMethod.PUT, singleUri, processor);
+    verify(processor, times(6)).updateReference(any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class),
+        any(ContentType.class));
+
+    dispatchMethodNotAllowed(HttpMethod.POST, singleUri, processor); 
+    
+    dispatch(HttpMethod.POST, singletonUriMany, processor);
+    verify(processor, times(2)).createReference(any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class),
+        any(ContentType.class));
+
+    dispatch(HttpMethod.DELETE, singletonUriMany, "$id=ESTwoPrim(1)", null, null, processor);
+    verify(processor, times(2)).deleteReference(any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class));
+    
+    dispatchMethodNotAllowed(HttpMethod.HEAD, singletonUriMany, processor);
   }
 
   @Test
   public void dispatchReferenceCollection() throws Exception {
     final String uri = "ESAllPrim(0)/NavPropertyETTwoPrimMany/$ref";
+    final String singletonUri = "SINav/NavPropertyETTwoKeyNavMany/$ref";
     final ReferenceCollectionProcessor processor = mock(ReferenceCollectionProcessor.class);
 
     dispatch(HttpMethod.GET, uri, processor);
@@ -896,7 +1045,17 @@ public class ODataHandlerImplTest {
 
     dispatchMethodNotAllowed(HttpMethod.PATCH, uri, processor);
     dispatchMethodNotAllowed(HttpMethod.PUT, uri, processor);
-    dispatchMethodNotAllowed(HttpMethod.HEAD, uri, processor);
+    dispatchMethodNotAllowed(HttpMethod.HEAD, uri, processor); 
+    
+    //singleton ref
+    dispatch(HttpMethod.GET, singletonUri, processor);
+    verify(processor, times(2)).readReferenceCollection(any(ODataRequest.class), 
+        any(ODataResponse.class), any(UriInfo.class),
+        any(ContentType.class));
+
+    dispatchMethodNotAllowed(HttpMethod.PATCH, singletonUri, processor);
+    dispatchMethodNotAllowed(HttpMethod.PUT, singletonUri, processor);
+    dispatchMethodNotAllowed(HttpMethod.HEAD, singletonUri, processor);
   }
 
   @Test


[2/2] olingo-odata4 git commit: [OLINGO-917] Fix $entity request handling

Posted by ch...@apache.org.
[OLINGO-917] Fix $entity request handling

This is a contribution from Ramya in
https://issues.apache.org/jira/browse/OLINGO-917


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

Branch: refs/heads/master
Commit: 6a736db10c3ef9d990dda637809a6514f27cb66b
Parents: 84a052d
Author: Christian Amend <ch...@sap.com>
Authored: Tue Nov 22 14:17:59 2016 +0100
Committer: Christian Amend <ch...@sap.com>
Committed: Tue Nov 22 14:17:59 2016 +0100

----------------------------------------------------------------------
 .../olingo/server/core/ServiceDispatcher.java   |   2 +-
 .../olingo/server/core/ServiceRequest.java      |   3 +-
 .../olingo/server/core/ODataDispatcher.java     |   1 +
 .../olingo/server/core/ODataHandlerImpl.java    |   2 +-
 .../olingo/server/core/uri/UriHelperImpl.java   |   2 +-
 .../olingo/server/core/uri/parser/Parser.java   | 117 ++++++++++++++-----
 .../server/core/uri/parser/UriDecoder.java      |   2 +-
 .../uri/parser/UriParserSemanticException.java  |   4 +-
 .../uri/parser/UriParserSyntaxException.java    |   4 +-
 .../server-core-exceptions-i18n.properties      |   2 +
 .../tecsvc/processor/TechnicalProcessor.java    |   2 +-
 .../server/core/PreconditionsValidatorTest.java |   4 +-
 .../server/core/uri/parser/ApplyParserTest.java |   2 +-
 .../core/uri/parser/ExpandParserTest.java       |   4 +-
 .../server/core/uri/parser/UriParserTest.java   |  76 +++++++++++-
 .../core/uri/testutil/FilterValidator.java      |   4 +-
 .../core/uri/testutil/ResourceValidator.java    |   2 +-
 .../core/uri/testutil/TestUriValidator.java     |  21 +++-
 .../core/uri/validator/UriValidatorTest.java    |   4 +-
 19 files changed, 203 insertions(+), 55 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/6a736db1/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceDispatcher.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceDispatcher.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceDispatcher.java
index a6d39b6..877ea70 100644
--- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceDispatcher.java
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceDispatcher.java
@@ -90,7 +90,7 @@ public class ServiceDispatcher extends RequestURLHierarchyVisitor {
         executeIdOption(query, odRequest, odResponse);
       } else {
         UriInfo uriInfo = new Parser(this.metadata.getEdm(), odata)
-          .parseUri(path, query, null);
+          .parseUri(path, query, null, odRequest.getRawBaseUri());
         
         contentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
             odRequest, this.customContentSupport, RepresentationType.ERROR);      

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/6a736db1/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceRequest.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceRequest.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceRequest.java
index 29c7134..c973ba6 100644
--- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceRequest.java
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceRequest.java
@@ -340,7 +340,8 @@ public abstract class ServiceRequest {
       rawPath = rawPath.substring(e+path.length());
     }
 
-    UriInfo uriInfo = new Parser(serviceMetadata.getEdm(), odata).parseUri(rawPath, uri.getQuery(), null);
+    UriInfo uriInfo = new Parser(serviceMetadata.getEdm(), odata).parseUri(rawPath, uri.getQuery(), null, 
+        getODataRequest().getRawBaseUri());
     ServiceDispatcher dispatcher = new ServiceDispatcher(odata, serviceMetadata, null, customContentType);
     dispatcher.visit(uriInfo);
     dispatcher.request.setUriInfo(uriInfo);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/6a736db1/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataDispatcher.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataDispatcher.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataDispatcher.java
index 5d48e34..d460ee7 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataDispatcher.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataDispatcher.java
@@ -109,6 +109,7 @@ public class ODataDispatcher {
       break;
 
     case resource:
+    case entityId:
       handleResourceDispatching(request, response);
       break;
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/6a736db1/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandlerImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandlerImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandlerImpl.java
index 921124c..d1a9cf2 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandlerImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandlerImpl.java
@@ -136,7 +136,7 @@ public class ODataHandlerImpl implements ODataHandler {
     final int measurementUriParser = debugger.startRuntimeMeasurement("Parser", "parseUri");
     try {
       uriInfo = new Parser(serviceMetadata.getEdm(), odata)
-          .parseUri(request.getRawODataPath(), request.getRawQueryPath(), null);
+          .parseUri(request.getRawODataPath(), request.getRawQueryPath(), null, request.getRawBaseUri());
     } catch (final ODataLibraryException e) {
       debugger.stopRuntimeMeasurement(measurementUriParser);
       debugger.stopRuntimeMeasurement(measurementHandle);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/6a736db1/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 f5d4bd0..ee4636b 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
@@ -146,7 +146,7 @@ public class UriHelperImpl implements UriHelper {
 
     try {
       final List<UriResource> uriResourceParts =
-          new Parser(edm, new ODataImpl()).parseUri(oDataPath, null, null).getUriResourceParts();
+          new Parser(edm, new ODataImpl()).parseUri(oDataPath, null, null, rawServiceRoot).getUriResourceParts();
       if (uriResourceParts.size() == 1 && uriResourceParts.get(0).getKind() == UriResourceKind.entitySet) {
         final UriResourceEntitySet entityUriResource = (UriResourceEntitySet) uriResourceParts.get(0);
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/6a736db1/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java
index 82e69eb..0ce8c75 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java
@@ -78,6 +78,8 @@ public class Parser {
   private static final String DOLLAR = "$";
   private static final String AT = "@";
   private static final String NULL = "null";
+  private static final String ENTITY = "$entity";
+  private static final String HTTP = "http";
 
   private final Edm edm;
   private final OData odata;
@@ -87,7 +89,7 @@ public class Parser {
     this.odata = odata;
   }
 
-  public UriInfo parseUri(final String path, final String query, final String fragment)
+  public UriInfo parseUri(final String path, final String query, final String fragment, String baseUri)
       throws UriParserException, UriValidationException {
 
     UriInfoImpl contextUriInfo = new UriInfoImpl();
@@ -149,16 +151,55 @@ public class Parser {
       contextIsCollection = true;
 
     } else if (firstSegment.equals("$entity")) {
-      contextUriInfo.setKind(UriInfoKind.entityId);
-      if (numberOfSegments > 1) {
-        final String typeCastSegment = pathSegmentsDecoded.get(1);
-        ensureLastSegment(typeCastSegment, 2, numberOfSegments);
-        contextType = new ResourcePathParser(edm, contextUriInfo.getAliasMap())
-            .parseDollarEntityTypeCast(typeCastSegment);
-        contextUriInfo.setEntityTypeCast((EdmEntityType) contextType);
+      if (null != contextUriInfo.getIdOption()) {
+        String idOptionText = contextUriInfo.getIdOption().getText();
+        if (idOptionText.startsWith(HTTP)) {
+          baseUri = UriDecoder.decode(baseUri);
+          if (idOptionText.contains(baseUri)) {
+            idOptionText = idOptionText.substring(baseUri.length() + 1);
+          } else {
+            throw new UriParserSemanticException("$id cannot have an absolute path",
+                UriParserSemanticException.MessageKeys.NOT_IMPLEMENTED_SYSTEM_QUERY_OPTION);
+          }
+        }
+        if (numberOfSegments > 1) {
+          /**
+           * If url is of the form 
+           * http://localhost:8080/odata-server-tecsvc/odata.svc/$entity/
+           * olingo.odata.test1.ETAllPrim?$id=ESAllPrim(32767)
+           */
+          final ResourcePathParser resourcePathParser = new ResourcePathParser
+            (edm, contextUriInfo.getAliasMap());
+          String typeCastSegment = pathSegmentsDecoded.get(1);
+          ensureLastSegment(typeCastSegment, 2, numberOfSegments);
+          contextType = resourcePathParser.parseDollarEntityTypeCast(typeCastSegment);
+          contextUriInfo = (UriInfoImpl) new Parser(edm, odata).
+              parseUri("/" + idOptionText, query, fragment, baseUri);
+          contextUriInfo.setEntityTypeCast((EdmEntityType) contextType);
+        } else if (numberOfSegments == 1) {
+          /**
+           * If url is of the form 
+           * http://localhost:8080/odata-server-tecsvc/odata.svc/$entity?$id=ESAllPrim(32527)
+           */
+          contextUriInfo = (UriInfoImpl) new Parser(edm, odata).
+                  parseUri("/" + idOptionText, query, fragment, baseUri);
+        }
+        contextType = contextUriInfo.getEntityTypeCast();
+        contextUriInfo.setKind(UriInfoKind.entityId);
+        contextIsCollection = false;
+      } else {
+        /**
+         * If url is of the form 
+         * http://localhost:8080/odata-server-tecsvc/odata.svc/$entity/olingo.odata.test1.ETKeyNav/$ref
+         */
+        ensureLastSegment(firstSegment, 2, numberOfSegments);
+        /**
+         * If url is of the form 
+         * http://localhost:8080/odata-server-tecsvc/odata.svc/$entity/olingo.odata.test1.ETKeyNav
+         */
+        throw new UriParserSyntaxException("The entity-id MUST be specified using the system query option $id",
+                  UriParserSyntaxException.MessageKeys.ENTITYID_MISSING_SYSTEM_QUERY_OPTION_ID);
       }
-      contextIsCollection = false;
-
     } else if (firstSegment.startsWith("$crossjoin")) {
       ensureLastSegment(firstSegment, 1, numberOfSegments);
       contextUriInfo.setKind(UriInfoKind.crossjoin);
@@ -176,35 +217,49 @@ public class Parser {
       UriResource lastSegment = null;
       for (final String pathSegment : pathSegmentsDecoded) {
         count++;
-        final UriResource segment = resourcePathParser.parsePathSegment(pathSegment, lastSegment);
-        if (segment != null) {
-          if (segment instanceof UriResourceCount
-              || segment instanceof UriResourceRef
-              || segment instanceof UriResourceValue) {
-            ensureLastSegment(pathSegment, count, numberOfSegments);
-          } else if (segment instanceof UriResourceAction
-              || segment instanceof UriResourceFunction
-              && !((UriResourceFunction) segment).getFunction().isComposable()) {
-            if (count < numberOfSegments) {
-              throw new UriValidationException(
-                  "The segment of an action or of a non-composable function must be the last resource-path segment.",
-                  UriValidationException.MessageKeys.UNALLOWED_RESOURCE_PATH,
-                  pathSegmentsDecoded.get(count));
+        if (pathSegment.startsWith(ENTITY)) {
+          /**
+           * If url is of the form 
+           * http://localhost:8080/odata-server-tecsvc/odata.svc/ESAllPrim/$entity
+           */
+          throw new UriParserSyntaxException("The entity-id MUST be specified using the system query option $id",
+                    UriParserSyntaxException.MessageKeys.ENTITYID_MISSING_SYSTEM_QUERY_OPTION_ID);
+        } else {
+          final UriResource segment = resourcePathParser.parsePathSegment(pathSegment, lastSegment);
+          if (segment != null) {
+            if (segment instanceof UriResourceCount
+                || segment instanceof UriResourceRef
+                || segment instanceof UriResourceValue) {
+              ensureLastSegment(pathSegment, count, numberOfSegments);
+            } else if (segment instanceof UriResourceAction
+                || segment instanceof UriResourceFunction
+                && !((UriResourceFunction) segment).getFunction().isComposable()) {
+              if (count < numberOfSegments) {
+                throw new UriValidationException(
+                    "The segment of an action or of a non-composable function must be the last resource-path segment.",
+                    UriValidationException.MessageKeys.UNALLOWED_RESOURCE_PATH,
+                    pathSegmentsDecoded.get(count));
+              }
+              lastSegment = segment;
+            } else if (segment instanceof UriResourceStartingTypeFilterImpl) {
+              throw new UriParserSemanticException("First resource-path segment must not be namespace-qualified.",
+                  UriParserSemanticException.MessageKeys.NAMESPACE_NOT_ALLOWED_AT_FIRST_ELEMENT);
+            } else {
+              lastSegment = segment;
             }
-            lastSegment = segment;
-          } else if (segment instanceof UriResourceStartingTypeFilterImpl) {
-            throw new UriParserSemanticException("First resource-path segment must not be namespace-qualified.",
-                UriParserSemanticException.MessageKeys.NAMESPACE_NOT_ALLOWED_AT_FIRST_ELEMENT);
-          } else {
-            lastSegment = segment;
+            contextUriInfo.addResourcePart(segment);
           }
-          contextUriInfo.addResourcePart(segment);
         }
       }
 
       if (lastSegment instanceof UriResourcePartTyped) {
         final UriResourcePartTyped typed = (UriResourcePartTyped) lastSegment;
         contextType = ParserHelper.getTypeInformation(typed);
+        if (contextUriInfo.getIdOption() != null && contextType != null) {
+          if (contextType instanceof EdmEntityType) {
+            contextUriInfo.setEntityTypeCast((EdmEntityType) contextType);
+          }
+        }
         contextIsCollection = typed.isCollection();
       }
     }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/6a736db1/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriDecoder.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriDecoder.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriDecoder.java
index 4a94e85..65cbd4f 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriDecoder.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriDecoder.java
@@ -78,7 +78,7 @@ public class UriDecoder {
     return list;
   }
 
-  private static String decode(final String encoded) throws UriParserSyntaxException {
+  public static String decode(final String encoded) throws UriParserSyntaxException {
     try {
       return Decoder.decode(encoded);
     } catch (final IllegalArgumentException e) {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/6a736db1/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParserSemanticException.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParserSemanticException.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParserSemanticException.java
index 8260af7..ab24a4f 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParserSemanticException.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParserSemanticException.java
@@ -75,7 +75,9 @@ public class UriParserSemanticException extends UriParserException {
     ONLY_FOR_PRIMITIVE_TYPES,
     /** parameter: function name */
     FUNCTION_MUST_USE_COLLECTIONS,
-    COLLECTION_NOT_ALLOWED;
+    COLLECTION_NOT_ALLOWED,
+    /** parameter: not implemented part for system query option $id */
+    NOT_IMPLEMENTED_SYSTEM_QUERY_OPTION;
 
     @Override
     public String getKey() {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/6a736db1/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParserSyntaxException.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParserSyntaxException.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParserSyntaxException.java
index 895e31e..be989ac 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParserSyntaxException.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParserSyntaxException.java
@@ -37,7 +37,9 @@ public class UriParserSyntaxException extends UriParserException {
     SYSTEM_QUERY_OPTION_LEVELS_NOT_ALLOWED_HERE,
     SYNTAX,
     /** parameter: alias name */
-    DUPLICATED_ALIAS;
+    DUPLICATED_ALIAS,
+    /**Entity id must be followed by system query option id */
+    ENTITYID_MISSING_SYSTEM_QUERY_OPTION_ID;
 
     @Override
     public String getKey() {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/6a736db1/lib/server-core/src/main/resources/server-core-exceptions-i18n.properties
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/resources/server-core-exceptions-i18n.properties b/lib/server-core/src/main/resources/server-core-exceptions-i18n.properties
index 5768565..3b261ac 100644
--- a/lib/server-core/src/main/resources/server-core-exceptions-i18n.properties
+++ b/lib/server-core/src/main/resources/server-core-exceptions-i18n.properties
@@ -36,6 +36,7 @@ UriParserSyntaxException.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION_FORMAT=The system q
 UriParserSyntaxException.SYSTEM_QUERY_OPTION_LEVELS_NOT_ALLOWED_HERE=The system query option '$levels' is not allowed here.
 UriParserSyntaxException.SYNTAX=The URI is malformed.
 UriParserSyntaxException.DUPLICATED_ALIAS=Duplicated alias. An alias '%1$s' was already specified!.
+UriParserSyntaxException.ENTITYID_MISSING_SYSTEM_QUERY_OPTION_ID=The entity-id must be specified using the system query option $id.
 
 SearchParserException.NO_EXPRESSION_FOUND=No expression found.
 SearchParserException.TOKENIZER_EXCEPTION=Exception during tokenizer creation with message '%1$s'.
@@ -77,6 +78,7 @@ UriParserSemanticException.IS_PROPERTY=The identifier '%1$s' is already used as
 UriParserSemanticException.ONLY_FOR_PRIMITIVE_TYPES='%1$s' is only allowed for primitive-type expressions.
 UriParserSemanticException.FUNCTION_MUST_USE_COLLECTIONS=Only bound functions with collections of structural types as binding parameter and as return type are allowed; '%1$s' is not such a function.
 UriParserSemanticException.COLLECTION_NOT_ALLOWED=A collection expression is not allowed.
+UriParserSemanticException.NOT_IMPLEMENTED_SYSTEM_QUERY_OPTION=$id with absolute url different from base url is not implemented!
 
 UriValidationException.UNSUPPORTED_QUERY_OPTION=The query option '%1$s' is not supported.
 UriValidationException.UNSUPPORTED_URI_KIND=The URI kind '%1$s' is not supported.

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/6a736db1/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 47a9a63..fc6991f 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
@@ -250,7 +250,7 @@ public abstract class TechnicalProcessor implements Processor {
   }
 
   protected void validateOptions(final UriInfoResource uriInfo) throws ODataApplicationException {
-    if (uriInfo.getIdOption() != null || uriInfo.getApplyOption() != null) {
+    if (uriInfo.getApplyOption() != null) {
       throw new ODataApplicationException("Not all of the specified options are supported.",
           HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
     }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/6a736db1/lib/server-test/src/test/java/org/apache/olingo/server/core/PreconditionsValidatorTest.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/PreconditionsValidatorTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/PreconditionsValidatorTest.java
index 4d73a4d..154e529 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/PreconditionsValidatorTest.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/PreconditionsValidatorTest.java
@@ -141,7 +141,7 @@ public class PreconditionsValidatorTest {
 
   @Test
   public void simpleEntityValueValidationNotActiveForMedia() throws Exception {
-    final UriInfo uriInfo = new Parser(edm, odata).parseUri("ESMedia(1)/$value", null, null);
+    final UriInfo uriInfo = new Parser(edm, odata).parseUri("ESMedia(1)/$value", null, null, null);
 
     CustomETagSupport support = mock(CustomETagSupport.class);
     when(support.hasETag(any(EdmBindingTarget.class))).thenReturn(true);
@@ -193,7 +193,7 @@ public class PreconditionsValidatorTest {
 
   private boolean mustValidate(final String uri, final String entitySetName)
       throws UriParserException, UriValidationException, PreconditionException {
-    final UriInfo uriInfo = new Parser(edm, odata).parseUri(uri, null, null);
+    final UriInfo uriInfo = new Parser(edm, odata).parseUri(uri, null, null, null);
     final List<UriResource> parts = uriInfo.getUriResourceParts();
     final boolean isMedia = parts.size() >= 2
         && parts.get(parts.size() - 1) instanceof UriResourceValue

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/6a736db1/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/ApplyParserTest.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/ApplyParserTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/ApplyParserTest.java
index 4286672..c22df73 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/ApplyParserTest.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/ApplyParserTest.java
@@ -498,7 +498,7 @@ public class ApplyParserTest {
 
   private ApplyValidator parse(final String path, final String apply)
       throws UriParserException, UriValidationException {
-    final UriInfo uriInfo = new Parser(edm, odata).parseUri(path, "$apply=" + apply, null);
+    final UriInfo uriInfo = new Parser(edm, odata).parseUri(path, "$apply=" + apply, null, null);
     return new ApplyValidator(uriInfo.getApplyOption());
   }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/6a736db1/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/ExpandParserTest.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/ExpandParserTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/ExpandParserTest.java
index e2f129d..97504da 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/ExpandParserTest.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/ExpandParserTest.java
@@ -252,7 +252,7 @@ public class ExpandParserTest {
   @Test
   public void expandNavigationApplyOption() throws Exception {
     UriInfo uriInfo = new Parser(edm, oData).parseUri("ESTwoKeyNav",
-        "$expand=NavPropertyETKeyNavMany($apply=identity),NavPropertyETKeyNavOne", null);
+        "$expand=NavPropertyETKeyNavMany($apply=identity),NavPropertyETKeyNavOne", null, null);
     Assert.assertEquals(ApplyItem.Kind.IDENTITY,
         uriInfo.getExpandOption().getExpandItems().get(0).getApplyOption().getApplyItems().get(0).getKind());
     Assert.assertEquals("NavPropertyETKeyNavOne",
@@ -260,7 +260,7 @@ public class ExpandParserTest {
             .getResourcePath().getUriResourceParts().get(0).getSegmentValue());
 
     uriInfo = new Parser(edm, oData).parseUri("ESTwoKeyNav",
-        "$expand=NavPropertyETKeyNavMany($apply=aggregate(PropertyInt16 with sum as s))", null);
+        "$expand=NavPropertyETKeyNavMany($apply=aggregate(PropertyInt16 with sum as s))", null, null);
     final ApplyItem applyItem =
         uriInfo.getExpandOption().getExpandItems().get(0).getApplyOption().getApplyItems().get(0);
     Assert.assertEquals(ApplyItem.Kind.AGGREGATE, applyItem.getKind());

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/6a736db1/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/UriParserTest.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/UriParserTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/UriParserTest.java
index 693f5b6..e77139a 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/UriParserTest.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/UriParserTest.java
@@ -71,7 +71,9 @@ public class UriParserTest {
     testUri.runEx("$all/$ref").isExSyntax(UriParserSyntaxException.MessageKeys.MUST_BE_LAST_SEGMENT);
     testUri.runEx("$entity/olingo.odata.test1.ETKeyNav/$ref")
         .isExSyntax(UriParserSyntaxException.MessageKeys.MUST_BE_LAST_SEGMENT);
-
+    testUri.runEx("$entity/olingo.odata.test1.ETKeyNav")
+        .isExSyntax(UriParserSyntaxException.MessageKeys.ENTITYID_MISSING_SYSTEM_QUERY_OPTION_ID);
+    
     testUri.runEx("$wrong").isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
     testUri.runEx("", "$wrong").isExSyntax(UriParserSyntaxException.MessageKeys.UNKNOWN_SYSTEM_QUERY_OPTION);
 
@@ -252,6 +254,78 @@ public class UriParserTest {
         .isEntityType(EntityTypeProvider.nameETBase)
         .isIdText("ESTwoPrim(1)")
         .goExpand().first().isSegmentStar();
+    
+    try {
+      testUri.run("$entity/olingo.odata.test1.ETAllNullable")
+      .isKind(UriInfoKind.entityId)
+      .isEntityType(EntityTypeProvider.nameETAllNullable);
+    } catch (UriParserSyntaxException e) {
+      testUri.isExSyntax(UriParserSyntaxException.MessageKeys.ENTITYID_MISSING_SYSTEM_QUERY_OPTION_ID);
+    }
+    testUri.run("$entity/Namespace1_Alias.ETAllPrim", "$id=ESAllPrim(32767)")
+    .isKind(UriInfoKind.entityId)
+    .isEntityType(EntityTypeProvider.nameETAllPrim)
+    .isIdText("ESAllPrim(32767)");
+    try {
+      testUri.run("ESAllPrim/$entity")
+    .isKind(UriInfoKind.resource);
+    } catch (UriParserSyntaxException e) {
+      testUri.isExSyntax(UriParserSyntaxException.MessageKeys.ENTITYID_MISSING_SYSTEM_QUERY_OPTION_ID);
+    }
+    try {
+      testUri.run("ESAllPrim(32767)/NavPropertyETTwoPrimOne/$entity")
+    .isKind(UriInfoKind.resource);
+    } catch(UriParserSyntaxException e) {
+      testUri.isExSyntax(UriParserSyntaxException.MessageKeys.ENTITYID_MISSING_SYSTEM_QUERY_OPTION_ID);
+    }
+    testUri.run("$entity", "$id=ESAllPrim(32767)/NavPropertyETTwoPrimOne")
+      .isKind(UriInfoKind.entityId)
+      .isEntityType(EntityTypeProvider.nameETTwoPrim)
+    .isIdText("ESAllPrim(32767)/NavPropertyETTwoPrimOne");
+    testUri.run("$entity", "$id=ESAllPrim(32767)", "$select=PropertyString", null)
+    .isKind(UriInfoKind.entityId)
+    .isEntityType(EntityTypeProvider.nameETAllPrim)
+      .isIdText("ESAllPrim(32767)");
+    testUri.run("$entity", "$id=ESAllPrim(32767)", "$expand=NavPropertyETTwoPrimOne", null)
+    .isKind(UriInfoKind.entityId)
+    .isEntityType(EntityTypeProvider.nameETAllPrim)
+      .isIdText("ESAllPrim(32767)");  
+    testUri.run("$entity", "$id=http://localhost:8080/odata-server-tecsvc/odata.svc/"
+        + "ESAllPrim(32767)/NavPropertyETTwoPrimOne", null, 
+        "http://localhost:8080/odata-server-tecsvc/odata.svc")
+    .isKind(UriInfoKind.entityId)
+    .isEntityType(EntityTypeProvider.nameETTwoPrim)
+    .isIdText("http://localhost:8080/odata-server-tecsvc/odata.svc/"
+        + "ESAllPrim(32767)/NavPropertyETTwoPrimOne");
+    try {
+      testUri.run("$entity/olingo.odata.test1.ETKeyNav", "$id=http://localhost:90/tecsvc/ESKeyNav(1)",
+            null, "http://localhost:80/tecsvc")
+          .isKind(UriInfoKind.entityId)
+          .isEntityType(EntityTypeProvider.nameETKeyNav)
+          .isIdText("http://localhost:90/tecsvc/ESKeyNav(1)");
+    } catch (UriParserSemanticException e) {
+      testUri.isExSemantic(UriParserSemanticException.MessageKeys.NOT_IMPLEMENTED_SYSTEM_QUERY_OPTION);
+    }
+    try {
+      testUri.run("$entity/olingo.odata.test1.ETKeyNav", "$id=http://localhost:90/tecs%27v; c/ESKeyNav(1)",
+            null, "http://localhost:80/tecs%27v; c")
+          .isKind(UriInfoKind.entityId)
+          .isEntityType(EntityTypeProvider.nameETKeyNav)
+          .isIdText("http://localhost:90/tecs%27v; c/ESKeyNav(1)");
+    } catch (UriParserSemanticException e) {
+      testUri.isExSemantic(UriParserSemanticException.MessageKeys.NOT_IMPLEMENTED_SYSTEM_QUERY_OPTION);
+    }
+    testUri.run("$entity/olingo.odata.test1.ETKeyNav", "$id=http://localhost:90/tecs%27v%20c/ESKeyNav(1)",
+        null, "http://localhost:90/tecs%27v%20c")
+      .isKind(UriInfoKind.entityId)
+      .isEntityType(EntityTypeProvider.nameETKeyNav);
+    String idOption = UriDecoder.decode("http://localhost:90/tecs%27v%20c/ESKeyNav(1)");
+    testUri.isIdText(idOption);
+    testUri.run("$entity/olingo.odata.test1.ETKeyNav", "$id=http://localhost:90/tecs'v c/ESKeyNav(1)",
+        null, "http://localhost:90/tecs'v c")
+      .isKind(UriInfoKind.entityId)
+      .isEntityType(EntityTypeProvider.nameETKeyNav)
+      .isIdText("http://localhost:90/tecs'v c/ESKeyNav(1)");
   }
 
   @Test

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/6a736db1/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/FilterValidator.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/FilterValidator.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/FilterValidator.java
index c7e9e64..246a408 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/FilterValidator.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/FilterValidator.java
@@ -168,7 +168,7 @@ public class FilterValidator implements TestValidator {
 
   public FilterValidator runUri(final String path, final String query)
       throws UriParserException, UriValidationException {
-    final UriInfo uriInfo = new Parser(edm, odata).parseUri(path, query, null);
+    final UriInfo uriInfo = new Parser(edm, odata).parseUri(path, query, null, null);
     assertTrue("Filtervalidator can only be used on resourcePaths", uriInfo.getKind() == UriInfoKind.resource);
     setFilter(uriInfo.getFilterOption());
     curExpression = filter.getExpression();
@@ -181,7 +181,7 @@ public class FilterValidator implements TestValidator {
 
   public FilterValidator runUriOrderBy(final String path, final String query)
       throws UriParserException, UriValidationException {
-    final UriInfo uriInfo = new Parser(edm, odata).parseUri(path, query, null);
+    final UriInfo uriInfo = new Parser(edm, odata).parseUri(path, query, null, null);
     assertTrue("Filtervalidator can only be used on resourcePaths", uriInfo.getKind() == UriInfoKind.resource);
     orderBy = uriInfo.getOrderByOption();
     return this;

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/6a736db1/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/ResourceValidator.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/ResourceValidator.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/ResourceValidator.java
index 658f2c0..147cbd3 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/ResourceValidator.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/ResourceValidator.java
@@ -83,7 +83,7 @@ public class ResourceValidator implements TestValidator {
   public ResourceValidator run(final String path) {
     UriInfo uriInfoTmp = null;
     try {
-      uriInfoTmp = new Parser(edm, odata).parseUri(path, null, null);
+      uriInfoTmp = new Parser(edm, odata).parseUri(path, null, null, null);
     } catch (final ODataLibraryException e) {
       fail("Exception occurred while parsing the URI: " + path + "\n"
           + " Message: " + e.getMessage());

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/6a736db1/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/TestUriValidator.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/TestUriValidator.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/TestUriValidator.java
index 3f1b913..27e2cd4 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/TestUriValidator.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/TestUriValidator.java
@@ -59,17 +59,28 @@ public class TestUriValidator implements TestValidator {
 
   // Execution
   public TestUriValidator run(final String path) throws UriParserException, UriValidationException {
-    return run(path, null, null);
+    return run(path, null, null, null);
   }
 
   public TestUriValidator run(final String path, final String query)
       throws UriParserException, UriValidationException {
-    return run(path, query, null);
+    return run(path, query, null, null);
   }
-
+  public TestUriValidator run(final String path, final String query, final String fragment, final String baseUri)
+      throws UriParserException, UriValidationException {
+    try {
+      uriInfo = new Parser(edm, odata).parseUri(path, query, fragment, baseUri);
+      new UriValidator().validate(uriInfo, HttpMethod.GET);
+      return this;
+    } catch (UriParserException e) {
+      exception = e;
+      throw e;
+    } 
+  }
+  
   public TestUriValidator run(final String path, final String query, final String fragment)
       throws UriParserException, UriValidationException {
-    uriInfo = new Parser(edm, odata).parseUri(path, query, fragment);
+    uriInfo = new Parser(edm, odata).parseUri(path, query, fragment, null);
     new UriValidator().validate(uriInfo, HttpMethod.GET);
     return this;
   }
@@ -81,7 +92,7 @@ public class TestUriValidator implements TestValidator {
   public TestUriValidator runEx(final String path, final String query) {
     uriInfo = null;
     try {
-      run(path, query, null);
+      run(path, query, null, null);
       fail("Exception expected");
     } catch (UriParserException e) {
       exception = e;

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/6a736db1/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/validator/UriValidatorTest.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/validator/UriValidatorTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/validator/UriValidatorTest.java
index 61cc000..3c39c41 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/validator/UriValidatorTest.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/validator/UriValidatorTest.java
@@ -467,7 +467,7 @@ public class UriValidatorTest {
 
   private void validate(final String path, final String query, final HttpMethod method) {
     try {
-      new UriValidator().validate(new Parser(edm, odata).parseUri(path, query, null), method);
+      new UriValidator().validate(new Parser(edm, odata).parseUri(path, query, null, null), method);
     } catch (final UriParserException e) {
       fail("Failed for " + method + " on URI: " + path + '?' + query);
     } catch (final UriValidationException e) {
@@ -478,7 +478,7 @@ public class UriValidatorTest {
   private void validateWrong(final String path, final String query, final HttpMethod method,
       final UriValidationException.MessageKeys expectedMessageKey) {
     try {
-      new UriValidator().validate(new Parser(edm, odata).parseUri(path, query, null), method);
+      new UriValidator().validate(new Parser(edm, odata).parseUri(path, query, null, null), method);
       fail("Validation Exception not thrown: " + method + ' ' + path + '?' + query);
     } catch (final UriParserException e) {
       fail("Wrong Exception thrown: " + method + ' ' + path + '?' + query);