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/01/12 14:08:04 UTC

[03/30] olingo-odata4 git commit: [OLINGO-834] URI resource-path parser in Java

[OLINGO-834] URI resource-path parser in Java

Signed-off-by: Michael Bolz <mi...@sap.com>


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

Branch: refs/heads/master
Commit: 927ecb93e34a8a1d4b5ff1dfefb96882b50a028b
Parents: d88913f
Author: Klaus Straubinger <kl...@sap.com>
Authored: Fri Dec 4 15:47:51 2015 +0100
Committer: Michael Bolz <mi...@sap.com>
Committed: Mon Dec 7 13:17:50 2015 +0100

----------------------------------------------------------------------
 .../olingo/fit/tecsvc/client/BasicITCase.java   |   2 +-
 .../core/edm/primitivetype/EdmBinary.java       |  12 +-
 .../edm/provider/EdmActionImportImplTest.java   |   2 +-
 .../core/edm/provider/EdmProviderImplTest.java  |   4 +-
 .../core/edm/provider/EdmSchemaImplTest.java    |   1 +
 .../apache/olingo/server/core/ErrorHandler.java |   8 +-
 .../olingo/server/core/ServiceDispatcher.java   |   4 +-
 .../olingo/server/core/ServiceRequest.java      |   6 +-
 .../apache/olingo/server/core/ODataHandler.java |   4 +-
 .../olingo/server/core/uri/UriHelperImpl.java   |   9 +-
 .../uri/UriResourceNavigationPropertyImpl.java  |   5 +-
 .../core/uri/UriResourceWithKeysImpl.java       |   3 +-
 .../olingo/server/core/uri/parser/Parser.java   | 202 +++---
 .../core/uri/parser/ResourcePathParser.java     | 692 +++++++++++++++++++
 .../core/uri/parser/UriParseTreeVisitor.java    |   2 +-
 .../server/core/uri/parser/UriTokenizer.java    | 592 ++++++++++++++++
 .../server/core/uri/validator/UriValidator.java |  74 +-
 .../core/uri/parser/UriTokenizerTest.java       | 369 ++++++++++
 .../uri/parser/search/SearchTokenizerTest.java  |   1 -
 .../server/tecsvc/data/DataProviderTest.java    |   4 +-
 .../server/core/PreconditionsValidatorTest.java |  25 +-
 .../serializer/utils/ContextURLHelperTest.java  |   4 +-
 .../olingo/server/core/uri/UriHelperTest.java   |   4 +-
 .../server/core/uri/UriResourceImplTest.java    |  14 +-
 .../core/uri/antlr/TestFullResourcePath.java    | 154 +++--
 .../core/uri/antlr/TestUriParserImpl.java       |  15 +-
 .../server/core/uri/parser/ParserTest.java      |   4 +-
 .../core/uri/testutil/FilterValidator.java      |  62 +-
 .../core/uri/testutil/ParserWithLogging.java    |   5 +-
 .../core/uri/testutil/ResourceValidator.java    |  13 +-
 .../core/uri/testutil/TestUriValidator.java     |  14 +-
 .../core/uri/validator/UriValidatorTest.java    |  17 +-
 32 files changed, 1973 insertions(+), 354 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/927ecb93/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java
index a09cafa..c8e4848 100644
--- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java
@@ -245,7 +245,7 @@ public class BasicITCase extends AbstractParamTecSvcITCase {
     } catch (final ODataClientErrorException e) {
       assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), e.getStatusLine().getStatusCode());
       final ODataError error = e.getODataError();
-      assertThat(error.getMessage(), containsString("key property"));
+      assertThat(error.getMessage(), containsString("key"));
     }
   }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/927ecb93/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmBinary.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmBinary.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmBinary.java
index 735250a..bdbc3fa 100644
--- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmBinary.java
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmBinary.java
@@ -133,19 +133,19 @@ public class EdmBinary extends SingletonPrimitiveType {
       final Boolean isNullable, final Integer maxLength, final Integer precision,
       final Integer scale, final Boolean isUnicode) {
 
-    return value == null
-        ? isNullable == null || isNullable
-        : isBase64(value.getBytes(UTF_8)) && validateMaxLength(value, maxLength);
+    return value == null ?
+        isNullable == null || isNullable :
+        isBase64(value.getBytes(UTF_8)) && validateMaxLength(value, maxLength);
   }
 
   private static boolean validateMaxLength(final String value, final Integer maxLength) {
-    return maxLength == null ? true
-        : // Every three bytes are represented as four base-64 characters.
+    return maxLength == null ? true :
+        // Every three bytes are represented as four base-64 characters.
         // Additionally, there could be up to two padding "=" characters
         // if the number of bytes is not a multiple of three,
         // and there could be line feeds, possibly with carriage returns.
         maxLength >= (value.length() - lineEndingsLength(value)) * 3 / 4
-          - (value.endsWith("==") ? 2 : value.endsWith("=") ? 1 : 0);
+            - (value.endsWith("==") ? 2 : value.endsWith("=") ? 1 : 0);
   }
 
   private static int lineEndingsLength(final String value) {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/927ecb93/lib/commons-core/src/test/java/org/apache/olingo/server/core/edm/provider/EdmActionImportImplTest.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/test/java/org/apache/olingo/server/core/edm/provider/EdmActionImportImplTest.java b/lib/commons-core/src/test/java/org/apache/olingo/server/core/edm/provider/EdmActionImportImplTest.java
index 02824f4..e4cd593 100644
--- a/lib/commons-core/src/test/java/org/apache/olingo/server/core/edm/provider/EdmActionImportImplTest.java
+++ b/lib/commons-core/src/test/java/org/apache/olingo/server/core/edm/provider/EdmActionImportImplTest.java
@@ -96,7 +96,7 @@ public class EdmActionImportImplTest {
     String target = "nonExisting";
     CsdlActionImport providerActionImport = new CsdlActionImport().setName("actionImportName").setEntitySet(target);
     EdmProviderImpl edm = mock(EdmProviderImpl.class);
-    when(edm.getEntityContainer(null)).thenReturn(container);
+    when(edm.getEntityContainer()).thenReturn(container);
     EdmActionImport actionImport = new EdmActionImportImpl(edm, container, providerActionImport);
     actionImport.getReturnedEntitySet();
   }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/927ecb93/lib/commons-core/src/test/java/org/apache/olingo/server/core/edm/provider/EdmProviderImplTest.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/test/java/org/apache/olingo/server/core/edm/provider/EdmProviderImplTest.java b/lib/commons-core/src/test/java/org/apache/olingo/server/core/edm/provider/EdmProviderImplTest.java
index 6ce6ab8..7ba529a 100644
--- a/lib/commons-core/src/test/java/org/apache/olingo/server/core/edm/provider/EdmProviderImplTest.java
+++ b/lib/commons-core/src/test/java/org/apache/olingo/server/core/edm/provider/EdmProviderImplTest.java
@@ -183,7 +183,7 @@ public class EdmProviderImplTest {
     when(localProvider.getAliasInfos()).thenThrow(new ODataException("msg"));
 
     Edm localEdm = new EdmProviderImpl(localProvider);
-    localEdm.getEntityContainer(null);
+    localEdm.getEntityContainer();
   }
 
   @Test
@@ -193,7 +193,7 @@ public class EdmProviderImplTest {
     assertEquals(FQN.getNamespace(), entityContainer.getNamespace());
     assertEquals(FQN.getName(), entityContainer.getName());
 
-    entityContainer = edm.getEntityContainer(null);
+    entityContainer = edm.getEntityContainer();
     assertNotNull(entityContainer);
     assertEquals(FQN.getNamespace(), entityContainer.getNamespace());
     assertEquals(FQN.getName(), entityContainer.getName());

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/927ecb93/lib/commons-core/src/test/java/org/apache/olingo/server/core/edm/provider/EdmSchemaImplTest.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/test/java/org/apache/olingo/server/core/edm/provider/EdmSchemaImplTest.java b/lib/commons-core/src/test/java/org/apache/olingo/server/core/edm/provider/EdmSchemaImplTest.java
index e6502af..2c95ce1 100644
--- a/lib/commons-core/src/test/java/org/apache/olingo/server/core/edm/provider/EdmSchemaImplTest.java
+++ b/lib/commons-core/src/test/java/org/apache/olingo/server/core/edm/provider/EdmSchemaImplTest.java
@@ -229,6 +229,7 @@ public class EdmSchemaImplTest {
 
     assertTrue(container == edm.getEntityContainer(new FullQualifiedName(schema.getNamespace(), container.getName())));
     assertTrue(container == edm.getEntityContainer(null));
+    assertTrue(container == edm.getEntityContainer());
   }
 
   private class LocalProvider implements CsdlEdmProvider {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/927ecb93/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ErrorHandler.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ErrorHandler.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ErrorHandler.java
index 5f425da..33f65cd 100644
--- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ErrorHandler.java
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ErrorHandler.java
@@ -90,13 +90,15 @@ public class ErrorHandler {
       final ODataServerError serverError) {
     ContentType requestedContentType;
     try {
-      UriInfo uriInfo = new Parser().parseUri(request.getRawODataPath(), request.getRawQueryPath(),
-          null, this.metadata.getEdm());
+      final UriInfo uriInfo = new Parser(metadata.getEdm(), odata)
+          .parseUri(request.getRawODataPath(), request.getRawQueryPath(), null);
       requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
           request, this.customContent, RepresentationType.ERROR);
     } catch (final ContentNegotiatorException e) {
       requestedContentType = ContentType.JSON;
-    } catch (UriParserException e) {
+    } catch (final UriParserException e) {
+      requestedContentType = ContentType.JSON;
+    } catch (final UriValidationException e) {
       requestedContentType = ContentType.JSON;
     }
     processError(response, serverError, requestedContentType);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/927ecb93/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 17ec358..45de757 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
@@ -76,8 +76,8 @@ public class ServiceDispatcher extends RequestURLHierarchyVisitor {
   public void execute(ODataRequest odRequest, ODataResponse odResponse)
       throws ODataLibraryException, ODataApplicationException {
 
-    UriInfo uriInfo = new Parser().parseUri(odRequest.getRawODataPath(), odRequest.getRawQueryPath(), null,
-        this.metadata.getEdm());
+    UriInfo uriInfo = new Parser(this.metadata.getEdm(), odata)
+        .parseUri(odRequest.getRawODataPath(), odRequest.getRawQueryPath(), null);
 
     new UriValidator().validate(uriInfo, odRequest.getMethod());
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/927ecb93/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 8195b85..0796144 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
@@ -47,6 +47,7 @@ import org.apache.olingo.server.api.uri.UriInfo;
 import org.apache.olingo.server.core.requests.DataRequest;
 import org.apache.olingo.server.core.uri.parser.Parser;
 import org.apache.olingo.server.core.uri.parser.UriParserException;
+import org.apache.olingo.server.core.uri.validator.UriValidationException;
 
 public abstract class ServiceRequest {
   protected OData odata;
@@ -240,7 +241,7 @@ public abstract class ServiceRequest {
     return null;
   }
 
-  public DataRequest parseLink(URI uri) throws UriParserException, URISyntaxException {
+  public DataRequest parseLink(URI uri) throws UriParserException, UriValidationException, URISyntaxException {
     String path = "/";
     URI servicePath = new URI(getODataRequest().getRawBaseUri());
     path = servicePath.getPath();
@@ -253,8 +254,7 @@ public abstract class ServiceRequest {
       rawPath = rawPath.substring(e+path.length());
     }
 
-    UriInfo uriInfo = new Parser().parseUri(rawPath, uri.getQuery(), null,
-        this.serviceMetadata.getEdm());
+    UriInfo uriInfo = new Parser(serviceMetadata.getEdm(), odata).parseUri(rawPath, uri.getQuery(), null);
     ServiceDispatcher dispatcher = new ServiceDispatcher(odata, serviceMetadata, null, customContentType);
     dispatcher.visit(uriInfo);
     return (DataRequest)dispatcher.request;

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/927ecb93/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java
index 12f2dfd..8c2e286 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java
@@ -129,8 +129,8 @@ public class ODataHandler {
 
     final int measurementUriParser = debugger.startRuntimeMeasurement("UriParser", "parseUri");
     try {
-      uriInfo = new Parser().parseUri(request.getRawODataPath(), request.getRawQueryPath(), null,
-          serviceMetadata.getEdm());
+      uriInfo = new Parser(serviceMetadata.getEdm(), odata)
+          .parseUri(request.getRawODataPath(), request.getRawQueryPath(), null);
     } catch (final ODataLibraryException e) {
       debugger.stopRuntimeMeasurement(measurementUriParser);
       debugger.stopRuntimeMeasurement(measurementHandle);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/927ecb93/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 c463765..3bc5ad0 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
@@ -29,6 +29,7 @@ import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
 import org.apache.olingo.commons.api.edm.EdmProperty;
 import org.apache.olingo.commons.api.edm.EdmStructuredType;
 import org.apache.olingo.commons.core.Encoder;
+import org.apache.olingo.server.api.ODataLibraryException;
 import org.apache.olingo.server.api.deserializer.DeserializerException;
 import org.apache.olingo.server.api.deserializer.DeserializerException.MessageKeys;
 import org.apache.olingo.server.api.serializer.SerializerException;
@@ -39,9 +40,9 @@ 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.core.ODataImpl;
 import org.apache.olingo.server.core.serializer.utils.ContextURLHelper;
 import org.apache.olingo.server.core.uri.parser.Parser;
-import org.apache.olingo.server.core.uri.parser.UriParserException;
 
 public class UriHelperImpl implements UriHelper {
 
@@ -107,8 +108,8 @@ public class UriHelperImpl implements UriHelper {
     oDataPath = oDataPath.startsWith("/") ? oDataPath : "/" + oDataPath;
 
     try {
-      final List<UriResource> uriResourceParts = new Parser().parseUri(oDataPath, null, null, edm)
-          .getUriResourceParts();
+      final List<UriResource> uriResourceParts =
+          new Parser(edm, new ODataImpl()).parseUri(oDataPath, null, null).getUriResourceParts();
       if (uriResourceParts.size() == 1 && uriResourceParts.get(0).getKind() == UriResourceKind.entitySet) {
         final UriResourceEntitySet entityUriResource = (UriResourceEntitySet) uriResourceParts.get(0);
         
@@ -117,7 +118,7 @@ public class UriHelperImpl implements UriHelper {
 
       throw new DeserializerException("Invalid entity binding link", MessageKeys.INVALID_ENTITY_BINDING_LINK,
           entityId);
-    } catch (UriParserException e) {
+    } catch (final ODataLibraryException e) {
       throw new DeserializerException("Invalid entity binding link", e, MessageKeys.INVALID_ENTITY_BINDING_LINK,
           entityId);
     }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/927ecb93/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceNavigationPropertyImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceNavigationPropertyImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceNavigationPropertyImpl.java
index 1a4fa44..f4390b5 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceNavigationPropertyImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceNavigationPropertyImpl.java
@@ -49,10 +49,7 @@ public class UriResourceNavigationPropertyImpl extends UriResourceWithKeysImpl i
 
   @Override
   public boolean isCollection() {
-    if (keyPredicates != null) {
-      return false;
-    }
-    return navigationProperty.isCollection();
+    return navigationProperty.isCollection() && keyPredicates == null;
   }
   
   @Override

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/927ecb93/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceWithKeysImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceWithKeysImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceWithKeysImpl.java
index 54d62a1..c300d78 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceWithKeysImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceWithKeysImpl.java
@@ -18,7 +18,6 @@
  */
 package org.apache.olingo.server.core.uri;
 
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
@@ -48,7 +47,7 @@ public abstract class UriResourceWithKeysImpl extends UriResourceImpl implements
   public List<UriParameter> getKeyPredicates() {
     return keyPredicates == null ?
         Collections.<UriParameter> emptyList() :
-        new ArrayList<UriParameter>(keyPredicates);
+        Collections.unmodifiableList(keyPredicates);
   }
 
   public UriResourceWithKeysImpl setKeyPredicates(final List<UriParameter> list) {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/927ecb93/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 d12b853..5caaaeb 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
@@ -18,7 +18,6 @@
  */
 package org.apache.olingo.server.core.uri.parser;
 
-import java.util.ArrayList;
 import java.util.List;
 
 import org.antlr.v4.runtime.ANTLRInputStream;
@@ -31,11 +30,15 @@ import org.antlr.v4.runtime.Token;
 import org.antlr.v4.runtime.atn.PredictionMode;
 import org.antlr.v4.runtime.misc.ParseCancellationException;
 import org.apache.olingo.commons.api.edm.Edm;
+import org.apache.olingo.commons.api.edm.EdmEntityContainer;
 import org.apache.olingo.commons.api.ex.ODataRuntimeException;
+import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.uri.UriInfo;
 import org.apache.olingo.server.api.uri.UriInfoKind;
 import org.apache.olingo.server.api.uri.UriResource;
+import org.apache.olingo.server.api.uri.UriResourceAction;
 import org.apache.olingo.server.api.uri.UriResourceCount;
+import org.apache.olingo.server.api.uri.UriResourceFunction;
 import org.apache.olingo.server.api.uri.UriResourcePartTyped;
 import org.apache.olingo.server.api.uri.UriResourceRef;
 import org.apache.olingo.server.api.uri.UriResourceValue;
@@ -46,18 +49,14 @@ import org.apache.olingo.server.api.uri.queryoption.SystemQueryOption;
 import org.apache.olingo.server.api.uri.queryoption.SystemQueryOptionKind;
 import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
 import org.apache.olingo.server.core.uri.UriInfoImpl;
+import org.apache.olingo.server.core.uri.UriResourceStartingTypeFilterImpl;
 import org.apache.olingo.server.core.uri.antlr.UriLexer;
 import org.apache.olingo.server.core.uri.antlr.UriParserParser;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.AllEOFContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.BatchEOFContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.CrossjoinEOFContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.EntityEOFContext;
 import org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandItemsEOFContext;
 import org.apache.olingo.server.core.uri.antlr.UriParserParser.FilterExpressionEOFContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.MetadataEOFContext;
 import org.apache.olingo.server.core.uri.antlr.UriParserParser.OrderByEOFContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.PathSegmentEOFContext;
 import org.apache.olingo.server.core.uri.antlr.UriParserParser.SelectEOFContext;
+import org.apache.olingo.server.core.uri.parser.UriTokenizer.TokenKind;
 import org.apache.olingo.server.core.uri.parser.search.SearchParser;
 import org.apache.olingo.server.core.uri.queryoption.AliasQueryOptionImpl;
 import org.apache.olingo.server.core.uri.queryoption.CountOptionImpl;
@@ -71,6 +70,7 @@ import org.apache.olingo.server.core.uri.queryoption.SelectOptionImpl;
 import org.apache.olingo.server.core.uri.queryoption.SkipOptionImpl;
 import org.apache.olingo.server.core.uri.queryoption.SkipTokenOptionImpl;
 import org.apache.olingo.server.core.uri.queryoption.TopOptionImpl;
+import org.apache.olingo.server.core.uri.validator.UriValidationException;
 
 public class Parser {
   private static final String ATOM = "atom";
@@ -78,19 +78,22 @@ public class Parser {
   private static final String XML = "xml";
   private static final String AT = "@";
   private static final String NULL = "null";
+
   int logLevel = 0;
+  private final Edm edm;
+  private final OData odata;
 
   private enum ParserEntryRules {
-    All, Batch, CrossJoin, Entity, ExpandItems, FilterExpression, Metadata, PathSegment, Orderby, Select, Search
+    ExpandItems, FilterExpression, Orderby, Select
   }
 
-  public Parser setLogLevel(final int logLevel) {
-    this.logLevel = logLevel;
-    return this;
+  public Parser(final Edm edm, final OData odata) {
+    this.edm = edm;
+    this.odata = odata;
   }
 
-  public UriInfo parseUri(final String path, final String query, final String fragment, final Edm edm)
-      throws UriParserException {
+  public UriInfo parseUri(final String path, final String query, final String fragment)
+      throws UriParserException, UriValidationException {
 
     UriContext context = new UriContext();
     UriParseTreeVisitor uriParseTreeVisitor = new UriParseTreeVisitor(edm, context);
@@ -104,65 +107,74 @@ public class Parser {
       if (firstSegment.isEmpty()) {
         ensureLastSegment(firstSegment, 0, uri.pathSegmentListDecoded.size());
         context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.service);
-      } else if (firstSegment.startsWith("$batch")) {
-        ensureLastSegment(firstSegment, 1, uri.pathSegmentListDecoded.size());
-        BatchEOFContext ctxBatchEOF =
-            (BatchEOFContext) parseRule(uri.pathSegmentListDecoded.get(0), ParserEntryRules.Batch);
 
-        uriParseTreeVisitor.visitBatchEOF(ctxBatchEOF);
-      } else if (firstSegment.startsWith("$metadata")) {
+      } else if (firstSegment.equals("$batch")) {
         ensureLastSegment(firstSegment, 1, uri.pathSegmentListDecoded.size());
-        MetadataEOFContext ctxMetadataEOF =
-            (MetadataEOFContext) parseRule(uri.pathSegmentListDecoded.get(0), ParserEntryRules.Metadata);
-
-        uriParseTreeVisitor.visitMetadataEOF(ctxMetadataEOF);
+        context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.batch);
 
+      } else if (firstSegment.equals("$metadata")) {
+        ensureLastSegment(firstSegment, 1, uri.pathSegmentListDecoded.size());
+        context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.metadata);
         context.contextUriInfo.setFragment(uri.fragment);
-      } else if (firstSegment.startsWith("$entity")) {
 
-        context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.entityId);
+      } else if (firstSegment.equals("$all")) {
+        ensureLastSegment(firstSegment, 1, uri.pathSegmentListDecoded.size());
+        context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.all);
+
+      } else if (firstSegment.equals("$entity")) {
         if (uri.pathSegmentListDecoded.size() > 1) {
           final String typeCastSegment = uri.pathSegmentListDecoded.get(1);
           ensureLastSegment(typeCastSegment, 2, uri.pathSegmentListDecoded.size());
-          EntityEOFContext ctxEntityEOF =
-              (EntityEOFContext) parseRule(typeCastSegment, ParserEntryRules.Entity);
-          uriParseTreeVisitor.visitEntityEOF(ctxEntityEOF);
+          context.contextUriInfo = new ResourcePathParser(edm, odata).parseDollarEntityTypeCast(typeCastSegment);
+          context.contextTypes.push(
+              uriParseTreeVisitor.new TypeInformation(context.contextUriInfo.getEntityTypeCast(), false));
+        } else {
+          context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.entityId);
         }
 
-      } else if (firstSegment.startsWith("$all")) {
-        ensureLastSegment(firstSegment, 1, uri.pathSegmentListDecoded.size());
-        AllEOFContext ctxResourcePathEOF =
-            (AllEOFContext) parseRule(uri.pathSegmentListDecoded.get(0), ParserEntryRules.All);
-
-        uriParseTreeVisitor.visitAllEOF(ctxResourcePathEOF);
       } else if (firstSegment.startsWith("$crossjoin")) {
         ensureLastSegment(firstSegment, 1, uri.pathSegmentListDecoded.size());
-        CrossjoinEOFContext ctxResourcePathEOF =
-            (CrossjoinEOFContext) parseRule(uri.pathSegmentListDecoded.get(0), ParserEntryRules.CrossJoin);
-
-        uriParseTreeVisitor.visitCrossjoinEOF(ctxResourcePathEOF);
-      } else {
-        List<PathSegmentEOFContext> ctxPathSegments = new ArrayList<PathSegmentEOFContext>();
-        for (String pathSegment : uri.pathSegmentListDecoded) {
-          PathSegmentEOFContext ctxPathSegment =
-              (PathSegmentEOFContext) parseRule(pathSegment, ParserEntryRules.PathSegment);
-          ctxPathSegments.add(ctxPathSegment);
+        context.contextUriInfo = new ResourcePathParser(edm, odata)
+            .parseCrossjoinSegment(uri.pathSegmentListDecoded.get(0));
+        final EdmEntityContainer container = edm.getEntityContainer();
+        for (final String name : context.contextUriInfo.getEntitySetNames()) {
+          context.contextTypes.push(
+              uriParseTreeVisitor.new TypeInformation(container.getEntitySet(name).getEntityType(), true));
         }
 
+      } else {
         context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.resource);
-
-        for (PathSegmentEOFContext ctxPathSegment : ctxPathSegments) {
-          // add checks for batch, entity, metadata, all, crossjoin
-          uriParseTreeVisitor.visitPathSegmentEOF(ctxPathSegment);
+        final ResourcePathParser resourcePathParser = new ResourcePathParser(edm, odata);
+        int count = 0;
+        UriResource lastSegment = null;
+        for (final String pathSegment : uri.pathSegmentListDecoded) {
+          count++;
+          final UriResource segment = resourcePathParser.parsePathSegment(pathSegment, lastSegment);
+          if (segment != null) {
+            if (segment instanceof UriResourceCount
+                || segment instanceof UriResourceRef
+                || segment instanceof UriResourceValue) {
+              ensureLastSegment(pathSegment, count, uri.pathSegmentListDecoded.size());
+            } else if (segment instanceof UriResourceAction
+                || segment instanceof UriResourceFunction
+                && !((UriResourceFunction) segment).getFunction().isComposable()) {
+              if (count < uri.pathSegmentListDecoded.size()) {
+                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,
+                    uri.pathSegmentListDecoded.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;
+            }
+            context.contextUriInfo.addResourcePart(segment);
+          }
         }
 
-        UriResource lastSegment = context.contextUriInfo.getLastResourcePart();
-        if (lastSegment instanceof UriResourceCount
-            || lastSegment instanceof UriResourceRef
-            || lastSegment instanceof UriResourceValue) {
-          final List<UriResource> parts = context.contextUriInfo.getUriResourceParts();
-          lastSegment = parts.get(parts.size() - 2);
-        }
         if (lastSegment instanceof UriResourcePartTyped) {
           UriResourcePartTyped typed = (UriResourcePartTyped) lastSegment;
 
@@ -174,13 +186,12 @@ public class Parser {
       }
 
       // second, read the system query options and the custom query options
-      for (RawUri.QueryOption option : uri.queryOptionListDecoded) {
+      for (final RawUri.QueryOption option : uri.queryOptionListDecoded) {
         if (option.name.startsWith("$")) {
           SystemQueryOption systemOption = null;
           if (option.name.equals(SystemQueryOptionKind.FILTER.toString())) {
             FilterExpressionEOFContext ctxFilterExpression =
                 (FilterExpressionEOFContext) parseRule(option.value, ParserEntryRules.FilterExpression);
-
             systemOption = (FilterOptionImpl) uriParseTreeVisitor.visitFilterExpressionEOF(ctxFilterExpression);
 
           } else if (option.name.equals(SystemQueryOptionKind.FORMAT.toString())) {
@@ -201,7 +212,6 @@ public class Parser {
           } else if (option.name.equals(SystemQueryOptionKind.EXPAND.toString())) {
             ExpandItemsEOFContext ctxExpandItems =
                 (ExpandItemsEOFContext) parseRule(option.value, ParserEntryRules.ExpandItems);
-
             systemOption = (ExpandOptionImpl) uriParseTreeVisitor.visitExpandItemsEOF(ctxExpandItems);
 
           } else if (option.name.equals(SystemQueryOptionKind.ID.toString())) {
@@ -210,22 +220,24 @@ public class Parser {
             idOption.setText(option.value);
             idOption.setValue(option.value);
             systemOption = idOption;
+
           } else if (option.name.equals(SystemQueryOptionKind.LEVELS.toString())) {
             throw new UriParserSyntaxException("System query option '$levels' is allowed only inside '$expand'!",
                 UriParserSyntaxException.MessageKeys.SYSTEM_QUERY_OPTION_LEVELS_NOT_ALLOWED_HERE);
+
           } else if (option.name.equals(SystemQueryOptionKind.ORDERBY.toString())) {
             OrderByEOFContext ctxOrderByExpression =
                 (OrderByEOFContext) parseRule(option.value, ParserEntryRules.Orderby);
-
             systemOption = (OrderByOptionImpl) uriParseTreeVisitor.visitOrderByEOF(ctxOrderByExpression);
+
           } else if (option.name.equals(SystemQueryOptionKind.SEARCH.toString())) {
-            SearchParser searchParser = new SearchParser();
-            systemOption = searchParser.parse(option.value);
+            systemOption = new SearchParser().parse(option.value);
+
           } else if (option.name.equals(SystemQueryOptionKind.SELECT.toString())) {
             SelectEOFContext ctxSelectEOF =
                 (SelectEOFContext) parseRule(option.value, ParserEntryRules.Select);
-
             systemOption = (SelectOptionImpl) uriParseTreeVisitor.visitSelectEOF(ctxSelectEOF);
+
           } else if (option.name.equals(SystemQueryOptionKind.SKIP.toString())) {
             SkipOptionImpl skipOption = new SkipOptionImpl();
             skipOption.setName(option.name);
@@ -238,12 +250,14 @@ public class Parser {
                   option.name, option.value);
             }
             systemOption = skipOption;
+
           } else if (option.name.equals(SystemQueryOptionKind.SKIPTOKEN.toString())) {
             SkipTokenOptionImpl skipTokenOption = new SkipTokenOptionImpl();
             skipTokenOption.setName(option.name);
             skipTokenOption.setText(option.value);
             skipTokenOption.setValue(option.value);
             systemOption = skipTokenOption;
+
           } else if (option.name.equals(SystemQueryOptionKind.TOP.toString())) {
             TopOptionImpl topOption = new TopOptionImpl();
             topOption.setName(option.name);
@@ -256,6 +270,7 @@ public class Parser {
                   option.name, option.value);
             }
             systemOption = topOption;
+
           } else if (option.name.equals(SystemQueryOptionKind.COUNT.toString())) {
             CountOptionImpl inlineCountOption = new CountOptionImpl();
             inlineCountOption.setName(option.name);
@@ -268,6 +283,7 @@ public class Parser {
                   option.name, option.value);
             }
             systemOption = inlineCountOption;
+
           } else {
             throw new UriParserSyntaxException("Unknown system query option!",
                 UriParserSyntaxException.MessageKeys.UNKNOWN_SYSTEM_QUERY_OPTION, option.name);
@@ -278,12 +294,23 @@ public class Parser {
             throw new UriParserSyntaxException("Double system query option!", e,
                 UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION, option.name);
           }
+
         } else if (option.name.startsWith(AT)) {
           if (context.contextUriInfo.getAlias(option.name) == null) {
-            final FilterExpressionEOFContext filterExpCtx =
-                (FilterExpressionEOFContext) parseRule(option.value, ParserEntryRules.FilterExpression);
-            final Expression expression = ((FilterOption) uriParseTreeVisitor.visitFilterExpressionEOF(filterExpCtx))
-                .getExpression();
+            // TODO: Create a proper alias-value parser that can parse also common expressions.
+            Expression expression = null;
+            if (!option.value.isEmpty() && (option.value.charAt(0) == '[' || option.value.charAt(0) == '{')) {
+              UriTokenizer tokenizer = new UriTokenizer(option.value);
+              if (!(tokenizer.next(TokenKind.jsonArrayOrObject) && tokenizer.next(TokenKind.EOF))) {
+                throw new UriParserSyntaxException("Illegal value for alias '" + option.name + "'.",
+                    UriParserSyntaxException.MessageKeys.SYNTAX);
+              }
+            } else {
+              final FilterExpressionEOFContext filterExpCtx =
+                  (FilterExpressionEOFContext) parseRule(option.value, ParserEntryRules.FilterExpression);
+              expression = ((FilterOption) uriParseTreeVisitor.visitFilterExpressionEOF(filterExpCtx))
+                  .getExpression();
+            }
             context.contextUriInfo.addAlias((AliasQueryOption) new AliasQueryOptionImpl()
                 .setAliasValue(expression)
                 .setName(option.name)
@@ -292,6 +319,7 @@ public class Parser {
             throw new UriParserSyntaxException("Alias already specified! Name: " + option.name,
                 UriParserSyntaxException.MessageKeys.DUPLICATED_ALIAS, option.name);
           }
+
         } else {
           context.contextUriInfo.addCustomQueryOption((CustomQueryOption)
               new CustomQueryOptionImpl()
@@ -354,21 +382,6 @@ public class Parser {
 
       // parse
       switch (entryPoint) {
-      case All:
-        ret = parser.allEOF();
-        break;
-      case Batch:
-        ret = parser.batchEOF();
-        break;
-      case CrossJoin:
-        ret = parser.crossjoinEOF();
-        break;
-      case Metadata:
-        ret = parser.metadataEOF();
-        break;
-      case PathSegment:
-        ret = parser.pathSegmentEOF();
-        break;
       case FilterExpression:
         lexer.mode(Lexer.DEFAULT_MODE);
         ret = parser.filterExpressionEOF();
@@ -381,15 +394,9 @@ public class Parser {
         lexer.mode(Lexer.DEFAULT_MODE);
         ret = parser.expandItemsEOF();
         break;
-      case Entity:
-        ret = parser.entityEOF();
-        break;
       case Select:
         ret = parser.selectEOF();
         break;
-      case Search:
-        ret = parser.searchInline();
-        break;
       default:
         break;
 
@@ -414,21 +421,6 @@ public class Parser {
 
         // parse
         switch (entryPoint) {
-        case All:
-          ret = parser.allEOF();
-          break;
-        case Batch:
-          ret = parser.batchEOF();
-          break;
-        case CrossJoin:
-          ret = parser.crossjoinEOF();
-          break;
-        case Metadata:
-          ret = parser.metadataEOF();
-          break;
-        case PathSegment:
-          ret = parser.pathSegmentEOF();
-          break;
         case FilterExpression:
           lexer.mode(Lexer.DEFAULT_MODE);
           ret = parser.filterExpressionEOF();
@@ -441,15 +433,9 @@ public class Parser {
           lexer.mode(Lexer.DEFAULT_MODE);
           ret = parser.expandItemsEOF();
           break;
-        case Entity:
-          ret = parser.entityEOF();
-          break;
         case Select:
           ret = parser.selectEOF();
           break;
-        case Search:
-          ret = parser.searchInline();
-          break;
         default:
           break;
         }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/927ecb93/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ResourcePathParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ResourcePathParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ResourcePathParser.java
new file mode 100644
index 0000000..9852011
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ResourcePathParser.java
@@ -0,0 +1,692 @@
+/*
+ * 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.server.core.uri.parser;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.olingo.commons.api.edm.Edm;
+import org.apache.olingo.commons.api.edm.EdmAction;
+import org.apache.olingo.commons.api.edm.EdmActionImport;
+import org.apache.olingo.commons.api.edm.EdmEntityContainer;
+import org.apache.olingo.commons.api.edm.EdmEntitySet;
+import org.apache.olingo.commons.api.edm.EdmEntityType;
+import org.apache.olingo.commons.api.edm.EdmFunction;
+import org.apache.olingo.commons.api.edm.EdmFunctionImport;
+import org.apache.olingo.commons.api.edm.EdmKeyPropertyRef;
+import org.apache.olingo.commons.api.edm.EdmNavigationProperty;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
+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.EdmSingleton;
+import org.apache.olingo.commons.api.edm.EdmStructuredType;
+import org.apache.olingo.commons.api.edm.EdmType;
+import org.apache.olingo.commons.api.edm.EdmTypeDefinition;
+import org.apache.olingo.commons.api.edm.FullQualifiedName;
+import org.apache.olingo.commons.api.edm.constants.EdmTypeKind;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.uri.UriInfoKind;
+import org.apache.olingo.server.api.uri.UriParameter;
+import org.apache.olingo.server.api.uri.UriResource;
+import org.apache.olingo.server.api.uri.UriResourcePartTyped;
+import org.apache.olingo.server.core.uri.UriInfoImpl;
+import org.apache.olingo.server.core.uri.UriParameterImpl;
+import org.apache.olingo.server.core.uri.UriResourceActionImpl;
+import org.apache.olingo.server.core.uri.UriResourceComplexPropertyImpl;
+import org.apache.olingo.server.core.uri.UriResourceCountImpl;
+import org.apache.olingo.server.core.uri.UriResourceEntitySetImpl;
+import org.apache.olingo.server.core.uri.UriResourceFunctionImpl;
+import org.apache.olingo.server.core.uri.UriResourceNavigationPropertyImpl;
+import org.apache.olingo.server.core.uri.UriResourcePrimitivePropertyImpl;
+import org.apache.olingo.server.core.uri.UriResourceRefImpl;
+import org.apache.olingo.server.core.uri.UriResourceSingletonImpl;
+import org.apache.olingo.server.core.uri.UriResourceTypedImpl;
+import org.apache.olingo.server.core.uri.UriResourceValueImpl;
+import org.apache.olingo.server.core.uri.UriResourceWithKeysImpl;
+import org.apache.olingo.server.core.uri.parser.UriTokenizer.TokenKind;
+import org.apache.olingo.server.core.uri.validator.UriValidationException;
+
+public class ResourcePathParser {
+
+  private final Edm edm;
+  private final EdmEntityContainer edmEntityContainer;
+  private final OData odata;
+  private UriTokenizer tokenizer;
+
+  public ResourcePathParser(final Edm edm, final OData odata) {
+    this.edm = edm;
+    edmEntityContainer = edm.getEntityContainer();
+    this.odata = odata;
+  }
+
+  public UriResource parsePathSegment(final String pathSegment, UriResource previous)
+      throws UriParserException, UriValidationException {
+    tokenizer = new UriTokenizer(pathSegment);
+
+    // The order is important.
+    // A qualified name should not be parsed as identifier and let the tokenizer halt at '.'.
+
+    if (previous == null) {
+      if (tokenizer.next(TokenKind.QualifiedName)) {
+        throw new UriParserSemanticException("The initial segment must not be namespace-qualified.",
+            UriParserSemanticException.MessageKeys.NAMESPACE_NOT_ALLOWED_AT_FIRST_ELEMENT,
+            new FullQualifiedName(tokenizer.getText()).getNamespace());
+      } else if (tokenizer.next(TokenKind.ODataIdentifier)) {
+        return leadingResourcePathSegment();
+      }
+
+    } else {
+      if (tokenizer.next(TokenKind.REF)) {
+        return ref(previous);
+      } else if (tokenizer.next(TokenKind.VALUE)) {
+        return value(previous);
+      } else if (tokenizer.next(TokenKind.COUNT)) {
+        return count(previous);
+      } else if (tokenizer.next(TokenKind.QualifiedName)) {
+        return boundOperationOrTypeCast(previous);
+      } else if (tokenizer.next(TokenKind.ODataIdentifier)) {
+        return navigationOrProperty(previous);
+      }
+    }
+
+    throw new UriParserSyntaxException("Unexpected start of resource-path segment.",
+        UriParserSyntaxException.MessageKeys.SYNTAX);
+  }
+
+  public UriInfoImpl parseDollarEntityTypeCast(final String pathSegment) throws UriParserException {
+    UriInfoImpl uriInfo = new UriInfoImpl().setKind(UriInfoKind.entityId);
+    tokenizer = new UriTokenizer(pathSegment);
+    requireNext(TokenKind.QualifiedName);
+    final String name = tokenizer.getText();
+    requireTokenEnd();
+    final EdmEntityType type = edm.getEntityType(new FullQualifiedName(name));
+    if (type == null) {
+      throw new UriParserSemanticException("Type '" + name + "' not found.",
+          UriParserSemanticException.MessageKeys.UNKNOWN_TYPE, name);
+    } else {
+      uriInfo.setEntityTypeCast(type);
+    }
+    return uriInfo;
+  }
+
+  public UriInfoImpl parseCrossjoinSegment(final String pathSegment) throws UriParserException {
+    UriInfoImpl uriInfo = new UriInfoImpl().setKind(UriInfoKind.crossjoin);
+    tokenizer = new UriTokenizer(pathSegment);
+    requireNext(TokenKind.CROSSJOIN);
+    requireNext(TokenKind.OPEN);
+    // At least one entity-set name is mandatory.  Try to fetch all.
+    do {
+      requireNext(TokenKind.ODataIdentifier);
+      final String name = tokenizer.getText();
+      final EdmEntitySet edmEntitySet = edmEntityContainer.getEntitySet(name);
+      if (edmEntitySet == null) {
+        throw new UriParserSemanticException("Expected Entity Set Name.",
+            UriParserSemanticException.MessageKeys.UNKNOWN_PART, name);
+      } else {
+        uriInfo.addEntitySetName(name);
+      }
+    } while (tokenizer.next(TokenKind.COMMA));
+    requireNext(TokenKind.CLOSE);
+    requireTokenEnd();
+    return uriInfo;
+  }
+
+  private UriResource ref(final UriResource previous) throws UriParserException {
+    requireTokenEnd();
+    requireTyped(previous, "$ref");
+    if (((UriResourcePartTyped) previous).getType() instanceof EdmEntityType) {
+      return new UriResourceRefImpl();
+    } else {
+      throw new UriParserSemanticException("$ref is only allowed on entity types.",
+          UriParserSemanticException.MessageKeys.ONLY_FOR_ENTITY_TYPES, "$ref");
+    }
+  }
+
+  private UriResource value(final UriResource previous) throws UriParserException {
+    requireTokenEnd();
+    requireTyped(previous, "$value");
+    if (!((UriResourcePartTyped) previous).isCollection()) {
+      return new UriResourceValueImpl();
+    } else {
+      throw new UriParserSemanticException("$value is only allowed on typed path segments.",
+          UriParserSemanticException.MessageKeys.ONLY_FOR_TYPED_PARTS, "$value");
+    }
+  }
+
+  private UriResource count(final UriResource previous) throws UriParserException {
+    requireTokenEnd();
+    requireTyped(previous, "$count");
+    if (((UriResourcePartTyped) previous).isCollection()) {
+      return new UriResourceCountImpl();
+    } else {
+      throw new UriParserSemanticException("$count is only allowed on collections.",
+          UriParserSemanticException.MessageKeys.ONLY_FOR_COLLECTIONS, "$count");
+    }
+  }
+
+  private UriResource leadingResourcePathSegment() throws UriParserException, UriValidationException {
+    final String oDataIdentifier = tokenizer.getText();
+
+    final EdmEntitySet edmEntitySet = edmEntityContainer.getEntitySet(oDataIdentifier);
+    if (edmEntitySet != null) {
+      final UriResourceEntitySetImpl entitySetResource = new UriResourceEntitySetImpl().setEntitSet(edmEntitySet);
+
+      if (tokenizer.next(TokenKind.OPEN)) {
+        final List<UriParameter> keyPredicates = keyPredicate(entitySetResource.getEntityType(), null);
+        entitySetResource.setKeyPredicates(keyPredicates);
+      }
+
+      requireTokenEnd();
+      return entitySetResource;
+    }
+
+    final EdmSingleton edmSingleton = edmEntityContainer.getSingleton(oDataIdentifier);
+    if (edmSingleton != null) {
+      requireTokenEnd();
+      return new UriResourceSingletonImpl().setSingleton(edmSingleton);
+    }
+
+    final EdmActionImport edmActionImport = edmEntityContainer.getActionImport(oDataIdentifier);
+    if (edmActionImport != null) {
+      requireTokenEnd();
+      return new UriResourceActionImpl().setActionImport(edmActionImport);
+    }
+
+    final EdmFunctionImport edmFunctionImport = edmEntityContainer.getFunctionImport(oDataIdentifier);
+    if (edmFunctionImport != null) {
+      return functionCall(edmFunctionImport, null, null, false);
+    }
+
+    if (tokenizer.next(TokenKind.OPEN) || tokenizer.next(TokenKind.EOF)) {
+      throw new UriParserSemanticException("Unexpected start of resource-path segment.",
+          UriParserSemanticException.MessageKeys.RESOURCE_NOT_FOUND, oDataIdentifier);
+    } else {
+      throw new UriParserSyntaxException("Unexpected start of resource-path segment.",
+          UriParserSyntaxException.MessageKeys.SYNTAX);
+    }
+  }
+
+  private UriResource navigationOrProperty(final UriResource previous)
+      throws UriParserException, UriValidationException {
+    final String name = tokenizer.getText();
+
+    UriResourcePartTyped previousTyped = null;
+    EdmStructuredType structType = null;
+    requireTyped(previous, name);
+    if (((UriResourcePartTyped) previous).getType() instanceof EdmStructuredType) {
+      previousTyped = (UriResourcePartTyped) previous;
+      final EdmType previousTypeFilter = getPreviousTypeFilter(previousTyped);
+      structType = (EdmStructuredType) (previousTypeFilter == null ? previousTyped.getType() : previousTypeFilter);
+    } else {
+      throw new UriParserSemanticException(
+          "Cannot parse '" + name + "'; previous path segment is not a structural type.",
+          UriParserSemanticException.MessageKeys.RESOURCE_PART_MUST_BE_PRECEDED_BY_STRUCTURAL_TYPE, name);
+    }
+
+    if (previousTyped.isCollection()) {
+      throw new UriParserSemanticException("Property '" + name + "' is not allowed after collection.",
+          UriParserSemanticException.MessageKeys.PROPERTY_AFTER_COLLECTION, name);
+    }
+
+    final EdmProperty property = structType.getStructuralProperty(name);
+    if (property != null) {
+      return property.isPrimitive()
+          || property.getType().getKind() == EdmTypeKind.ENUM
+          || property.getType().getKind() == EdmTypeKind.DEFINITION ?
+          new UriResourcePrimitivePropertyImpl().setProperty(property) :
+          new UriResourceComplexPropertyImpl().setProperty(property);
+    }
+    final EdmNavigationProperty navigationProperty = structType.getNavigationProperty(name);
+    if (navigationProperty == null) {
+      throw new UriParserSemanticException("Property '" + name + "' not found in type '"
+          + structType.getFullQualifiedName().getFullQualifiedNameAsString() + "'",
+          UriParserSemanticException.MessageKeys.PROPERTY_NOT_IN_TYPE,
+          structType.getFullQualifiedName().getFullQualifiedNameAsString(), name);
+    }
+    List<UriParameter> keyPredicate = null;
+    if (tokenizer.next(TokenKind.OPEN)) {
+      if (navigationProperty.isCollection()) {
+        keyPredicate = keyPredicate(navigationProperty.getType(), navigationProperty.getPartner());
+      } else {
+        throw new UriParserSemanticException("A key is not allowed on non-collection navigation properties.",
+            UriParserSemanticException.MessageKeys.KEY_NOT_ALLOWED);
+      }
+    }
+    requireTokenEnd();
+    return new UriResourceNavigationPropertyImpl()
+        .setNavigationProperty(navigationProperty)
+        .setKeyPredicates(keyPredicate);
+  }
+
+  private UriResource boundOperationOrTypeCast(UriResource previous)
+      throws UriParserException, UriValidationException {
+    final FullQualifiedName name = new FullQualifiedName(tokenizer.getText());
+    requireTyped(previous, name.getFullQualifiedNameAsString());
+      final UriResourcePartTyped previousTyped = (UriResourcePartTyped) previous;
+      final EdmType previousTypeFilter = getPreviousTypeFilter(previousTyped);
+      final EdmType previousType = previousTypeFilter == null ? previousTyped.getType() : previousTypeFilter;
+      final EdmAction boundAction = edm.getBoundAction(name,
+          previousType.getFullQualifiedName(),
+          previousTyped.isCollection());
+      if (boundAction != null) {
+        requireTokenEnd();
+        return new UriResourceActionImpl().setAction(boundAction);
+      }
+      EdmStructuredType type = edm.getEntityType(name);
+      if (type == null) {
+        type = edm.getComplexType(name);
+      }
+      if (type != null) {
+        return typeCast(name, type, previousTyped);
+      }
+      if (tokenizer.next(TokenKind.EOF)) {
+        throw new UriParserSemanticException("Type '" + name.getFullQualifiedNameAsString() + "' not found.",
+            UriParserSemanticException.MessageKeys.UNKNOWN_TYPE, name.getFullQualifiedNameAsString());
+      }
+      return functionCall(null, name,
+          previousType.getFullQualifiedName(),
+          previousTyped.isCollection());
+  }
+
+  private void requireTyped(final UriResource previous, final String forWhat) throws UriParserException {
+    if (previous == null || !(previous instanceof UriResourcePartTyped)) {
+      throw new UriParserSemanticException("Path segment before '" + forWhat + "' is not typed.",
+          UriParserSemanticException.MessageKeys.PREVIOUS_PART_NOT_TYPED, forWhat);
+    }
+  }
+
+  private List<UriParameter> keyPredicate(final EdmEntityType edmEntityType, final EdmNavigationProperty partner)
+      throws UriParserException, UriValidationException {
+    final List<EdmKeyPropertyRef> keyPropertyRefs = edmEntityType.getKeyPropertyRefs();
+    if (tokenizer.next(TokenKind.CLOSE)) {
+      throw new UriParserSemanticException(
+          "Expected " + keyPropertyRefs.size() + " key predicates but none.",
+          UriParserSemanticException.MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES,
+          Integer.toString(keyPropertyRefs.size()), "0");
+    }
+    List<UriParameter> keys = new ArrayList<UriParameter>();
+    Map<String, String> referencedNames = new HashMap<String, String>();
+
+    if (partner != null) {
+      // Prepare list of potentially missing keys to be filled from referential constraints.
+      for (final String name : edmEntityType.getKeyPredicateNames()) {
+        final String referencedName = partner.getReferencingPropertyName(name);
+        if (referencedName != null) {
+          referencedNames.put(name, referencedName);
+        }
+      }
+    }
+
+    if (tokenizer.next(TokenKind.ODataIdentifier)) {
+      keys.addAll(compoundKey(edmEntityType));
+    } else if (keyPropertyRefs.size() - referencedNames.size() == 1) {
+      for (final EdmKeyPropertyRef candidate : keyPropertyRefs) {
+        if (referencedNames.get(candidate.getName()) == null) {
+          keys.add(simpleKey(candidate));
+          break;
+        }
+      }
+    } else {
+      throw new UriParserSemanticException(
+          "Expected " + (keyPropertyRefs.size() -referencedNames.size()) + " key predicates but found one.",
+          UriParserSemanticException.MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES,
+          Integer.toString(keyPropertyRefs.size() - referencedNames.size()), "1");
+    }
+
+    if (keys.size() < keyPropertyRefs.size() && partner != null) {
+      // Fill missing keys from referential constraints.
+      for (final String name : edmEntityType.getKeyPredicateNames()) {
+        boolean found = false;
+        for (final UriParameter key : keys) {
+          if (name.equals(key.getName())) {
+            found = true;
+            break;
+          }
+        }
+        if (!found && referencedNames.get(name) != null) {
+          keys.add(0, new UriParameterImpl().setName(name).setReferencedProperty(referencedNames.get(name)));
+        }
+      }
+    }
+
+    // Check that all key predicates are filled from the URI.
+    if (keys.size() < keyPropertyRefs.size()) {
+      throw new UriParserSemanticException(
+          "Expected " + keyPropertyRefs.size() + " key predicates but found " + keys.size() + ".",
+          UriParserSemanticException.MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES,
+          Integer.toString(keyPropertyRefs.size()), Integer.toString(keys.size()));
+    } else {
+      return keys;
+    }
+  }
+
+  private UriParameter simpleKey(final EdmKeyPropertyRef edmKeyPropertyRef)
+      throws UriParserException, UriValidationException {
+    final EdmProperty edmProperty = edmKeyPropertyRef == null ? null : edmKeyPropertyRef.getProperty();
+    if (nextPrimitiveTypeValue(
+        edmProperty == null ? null : (EdmPrimitiveType) edmProperty.getType(),
+        edmProperty == null ? false : edmProperty.isNullable())) {
+      final String literalValue = tokenizer.getText();
+      requireNext(TokenKind.CLOSE);
+      return createUriParameter(edmProperty, edmKeyPropertyRef.getName(), literalValue);
+    } else {
+      throw new UriParserSemanticException("The key value is not valid.",
+          UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE, edmKeyPropertyRef.getName());
+    }
+  }
+
+  private List<UriParameter> compoundKey(final EdmEntityType edmEntityType)
+      throws UriParserException, UriValidationException {
+
+    List<UriParameter> parameters = new ArrayList<UriParameter>();
+    List<String> parameterNames = new ArrayList<String>();
+
+    // To validate that each key predicate is exactly specified once, we use a list to pick from.
+    List<String> remainingKeyNames = new ArrayList<String>(edmEntityType.getKeyPredicateNames());
+
+    // At least one key predicate is mandatory.  Try to fetch all.
+    boolean hasComma = false;
+    do {
+      final String keyPredicateName = tokenizer.getText();
+      if (parameterNames.contains(keyPredicateName)) {
+        throw new UriValidationException("Duplicated key property " + keyPredicateName,
+            UriValidationException.MessageKeys.DOUBLE_KEY_PROPERTY, keyPredicateName);
+      }
+      if (remainingKeyNames.isEmpty()) {
+        throw new UriParserSemanticException("Too many key properties.",
+            UriParserSemanticException.MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES,
+            Integer.toString(parameters.size()), Integer.toString(parameters.size() + 1));
+      }
+      if (!remainingKeyNames.remove(keyPredicateName)) {
+        throw new UriValidationException("Unknown key property " + keyPredicateName,
+            UriValidationException.MessageKeys.INVALID_KEY_PROPERTY, keyPredicateName);
+      }
+      parameters.add(keyValuePair(keyPredicateName, edmEntityType));
+      parameterNames.add(keyPredicateName);
+      hasComma = tokenizer.next(TokenKind.COMMA);
+      if (hasComma) {
+        requireNext(TokenKind.ODataIdentifier);
+      }
+    } while (hasComma);
+    requireNext(TokenKind.CLOSE);
+
+    return parameters;
+  }
+
+  private UriParameter keyValuePair(final String keyPredicateName, final EdmEntityType edmEntityType)
+      throws UriParserException, UriValidationException {
+    final EdmKeyPropertyRef keyPropertyRef = edmEntityType.getKeyPropertyRef(keyPredicateName);
+    final EdmProperty edmProperty = keyPropertyRef == null ? null : keyPropertyRef.getProperty();
+    if (edmProperty == null) {
+      throw new UriValidationException(keyPredicateName + " is not a valid key property name.",
+          UriValidationException.MessageKeys.INVALID_KEY_PROPERTY, keyPredicateName);
+    }
+    requireNext(TokenKind.EQ);
+    if (tokenizer.next(TokenKind.COMMA) || tokenizer.next(TokenKind.CLOSE) || tokenizer.next(TokenKind.EOF)) {
+      throw new UriParserSyntaxException("Key value expected.", UriParserSyntaxException.MessageKeys.SYNTAX);
+    }
+    if (nextPrimitiveTypeValue((EdmPrimitiveType) edmProperty.getType(), edmProperty.isNullable())) {
+      return createUriParameter(edmProperty, keyPredicateName, tokenizer.getText());
+    } else {
+      throw new UriParserSemanticException(keyPredicateName + " has not a valid  key value.",
+          UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE, keyPredicateName);
+    }
+  }
+
+  private UriParameter createUriParameter(final EdmProperty edmProperty, final String parameterName,
+      final String literalValue) throws UriParserException, UriValidationException {
+    if (literalValue.startsWith("@")) {
+      return new UriParameterImpl()
+          .setName(parameterName)
+          .setAlias(literalValue);
+    }
+
+    final EdmPrimitiveType primitiveType = (EdmPrimitiveType) edmProperty.getType();
+    try {
+      if (!(primitiveType.validate(primitiveType.fromUriLiteral(literalValue), edmProperty.isNullable(),
+          edmProperty.getMaxLength(), edmProperty.getPrecision(), edmProperty.getScale(), edmProperty.isUnicode()))) {
+        throw new UriValidationException("Invalid key property",
+            UriValidationException.MessageKeys.INVALID_KEY_PROPERTY, parameterName);
+      }
+    } catch (final EdmPrimitiveTypeException e) {
+      throw new UriValidationException("Invalid key property",
+          UriValidationException.MessageKeys.INVALID_KEY_PROPERTY, parameterName);
+    }
+
+    return new UriParameterImpl()
+        .setName(parameterName)
+        .setText("null".equals(literalValue) ? null : literalValue);
+  }
+
+  private UriResource typeCast(final FullQualifiedName name, final EdmStructuredType type,
+      final UriResourcePartTyped previousTyped) throws UriParserException, UriValidationException {
+    if (type.compatibleTo(previousTyped.getType())) {
+      EdmType previousTypeFilter = null;
+      if (previousTyped instanceof UriResourceWithKeysImpl) {
+        if (previousTyped.isCollection()) {
+          previousTypeFilter = ((UriResourceWithKeysImpl) previousTyped).getTypeFilterOnCollection();
+          if (previousTypeFilter != null) {
+            throw new UriParserSemanticException("Type filters are not chainable.",
+                UriParserSemanticException.MessageKeys.TYPE_FILTER_NOT_CHAINABLE,
+                previousTypeFilter.getName(), type.getName());
+          }
+          ((UriResourceWithKeysImpl) previousTyped).setCollectionTypeFilter(type);
+        } else {
+          previousTypeFilter = ((UriResourceWithKeysImpl) previousTyped).getTypeFilterOnEntry();
+          if (previousTypeFilter != null) {
+            throw new UriParserSemanticException("Type filters are not chainable.",
+                UriParserSemanticException.MessageKeys.TYPE_FILTER_NOT_CHAINABLE,
+                previousTypeFilter.getName(), type.getName());
+          }
+          ((UriResourceWithKeysImpl) previousTyped).setEntryTypeFilter(type);
+        }
+        if (tokenizer.next(TokenKind.OPEN)) {
+          ((UriResourceWithKeysImpl) previousTyped).setKeyPredicates(
+              keyPredicate((EdmEntityType) type, null));
+        }
+      } else {
+        previousTypeFilter = ((UriResourceTypedImpl) previousTyped).getTypeFilter();
+        if (previousTypeFilter != null) {
+          throw new UriParserSemanticException("Type filters are not chainable.",
+              UriParserSemanticException.MessageKeys.TYPE_FILTER_NOT_CHAINABLE,
+              previousTypeFilter.getName(), type.getName());
+        }
+        ((UriResourceTypedImpl) previousTyped).setTypeFilter(type);
+      }
+      requireTokenEnd();
+      return null;
+    } else {
+      throw new UriParserSemanticException(
+          "Type filter not compatible to previous path segment: " + name.getFullQualifiedNameAsString(),
+          UriParserSemanticException.MessageKeys.INCOMPATIBLE_TYPE_FILTER, name.getFullQualifiedNameAsString());
+    }
+  }
+
+  private EdmType getPreviousTypeFilter(final UriResourcePartTyped previousTyped) {
+    if (previousTyped instanceof UriResourceWithKeysImpl) {
+      return ((UriResourceWithKeysImpl) previousTyped).getTypeFilterOnEntry() == null ?
+          ((UriResourceWithKeysImpl) previousTyped).getTypeFilterOnCollection() :
+          ((UriResourceWithKeysImpl) previousTyped).getTypeFilterOnEntry();
+    } else {
+      return ((UriResourceTypedImpl) previousTyped).getTypeFilter();
+    }
+  }
+
+  private UriResource functionCall(final EdmFunctionImport edmFunctionImport,
+      final FullQualifiedName boundFunctionName, final FullQualifiedName bindingParameterTypeName,
+      final boolean isBindingParameterCollection) throws UriParserException, UriValidationException {
+    final List<UriParameter> parameters = functionParameters();
+    List<String> names = new ArrayList<String>();
+    for (final UriParameter parameter : parameters) {
+      names.add(parameter.getName());
+    }
+    EdmFunction function = null;
+    if (edmFunctionImport != null) {
+      function = edmFunctionImport.getUnboundFunction(names);
+      if (function == null) {
+        throw new UriParserSemanticException(
+            "Function of function import '" + edmFunctionImport.getName() + "' "
+                + "with parameters " + names.toString() + " not found.",
+            UriParserSemanticException.MessageKeys.FUNCTION_NOT_FOUND, edmFunctionImport.getName(), names.toString());
+      }
+    } else {
+      function = edm.getBoundFunction(boundFunctionName,
+          bindingParameterTypeName, isBindingParameterCollection, names);
+      if (function == null) {
+        throw new UriParserSemanticException(
+            "Function " + boundFunctionName + " not found.",
+            UriParserSemanticException.MessageKeys.UNKNOWN_PART, boundFunctionName.getFullQualifiedNameAsString());
+      }
+    }
+    UriResourceFunctionImpl resource = new UriResourceFunctionImpl()
+        .setFunctionImport(edmFunctionImport, null)
+        .setFunction(function)
+        .setParameters(parameters);
+    if (tokenizer.next(TokenKind.OPEN)) {
+      if (function.getReturnType() != null
+          && function.getReturnType().getType().getKind() == EdmTypeKind.ENTITY
+          && function.getReturnType().isCollection()) {
+        resource.setKeyPredicates(
+            keyPredicate((EdmEntityType) function.getReturnType().getType(), null));
+      } else {
+        throw new UriParserSemanticException("A key is not allowed.",
+            UriParserSemanticException.MessageKeys.KEY_NOT_ALLOWED);
+      }
+    }
+    requireTokenEnd();
+    return resource;
+  }
+
+  private List<UriParameter> functionParameters() throws UriParserException {
+    List<UriParameter> parameters = new ArrayList<UriParameter>();
+    requireNext(TokenKind.OPEN);
+    if (tokenizer.next(TokenKind.CLOSE)) {
+      return parameters;
+    }
+    do {
+      requireNext(TokenKind.ODataIdentifier);
+      final String name = tokenizer.getText();
+      if (parameters.contains(name)) {
+        throw new UriParserSemanticException("Duplicated function parameter " + name,
+            UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE, name);
+      }
+      requireNext(TokenKind.EQ);
+      if (tokenizer.next(TokenKind.COMMA) || tokenizer.next(TokenKind.CLOSE) || tokenizer.next(TokenKind.EOF)) {
+        throw new UriParserSyntaxException("Parameter value expected.", UriParserSyntaxException.MessageKeys.SYNTAX);
+      }
+      if (nextPrimitiveValue()) {
+        final String literalValue = tokenizer.getText();
+        UriParameterImpl parameter = new UriParameterImpl().setName(name);
+        parameters.add(literalValue.startsWith("@") ?
+            parameter.setAlias(literalValue) :
+            parameter.setText("null".equals(literalValue) ? null : literalValue));
+      } else {
+        throw new UriParserSemanticException("Wrong parameter value.",
+            UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE, "");
+      }
+    } while (tokenizer.next(TokenKind.COMMA));
+    requireNext(TokenKind.CLOSE);
+    return parameters;
+  }
+
+  private void requireNext(final TokenKind kind) throws UriParserException {
+    if (!tokenizer.next(kind)) {
+      throw new UriParserSyntaxException("Expected token '" + kind.toString() + "' not found.",
+          UriParserSyntaxException.MessageKeys.SYNTAX);
+    }
+  }
+
+  private void requireTokenEnd() throws UriParserException {
+    requireNext(TokenKind.EOF);
+  }
+
+  private boolean nextPrimitiveTypeValue(final EdmPrimitiveType primitiveType, final boolean nullable) {
+    final EdmPrimitiveType type = primitiveType instanceof EdmTypeDefinition ?
+        ((EdmTypeDefinition) primitiveType).getUnderlyingType() :
+        primitiveType;
+    if (tokenizer.next(TokenKind.ParameterAliasName)) {
+      return true;
+    } else if (nullable && tokenizer.next(TokenKind.NULL)) {
+      return true;
+
+    } else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Boolean).equals(type)) {
+      return tokenizer.next(TokenKind.PrimitiveBooleanValue);
+    } else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.String).equals(type)) {
+      return tokenizer.next(TokenKind.PrimitiveStringValue);
+    } else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.SByte).equals(type)
+        || odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Byte).equals(type)
+        || odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Int16).equals(type)
+        || odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Int32).equals(type)
+        || odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Int64).equals(type)) {
+      return tokenizer.next(TokenKind.PrimitiveIntegerValue);
+    } else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Guid).equals(type)) {
+      return tokenizer.next(TokenKind.PrimitiveGuidValue);
+    } else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Date).equals(type)) {
+      return tokenizer.next(TokenKind.PrimitiveDateValue);
+    } else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.DateTimeOffset).equals(type)) {
+      return tokenizer.next(TokenKind.PrimitiveDateTimeOffsetValue);
+    } else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.TimeOfDay).equals(type)) {
+      return tokenizer.next(TokenKind.PrimitiveTimeOfDayValue);
+    } else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Decimal).equals(type)) {
+      // The order is important.
+      // A decimal value should not be parsed as integer and let the tokenizer stop at the decimal point.
+      return tokenizer.next(TokenKind.PrimitiveDecimalValue)
+          || tokenizer.next(TokenKind.PrimitiveIntegerValue);
+    } else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Double).equals(type)) {
+      // The order is important.
+      // A floating-point value should not be parsed as decimal and let the tokenizer stop at 'E'.
+      // A decimal value should not be parsed as integer and let the tokenizer stop at the decimal point.
+      return tokenizer.next(TokenKind.PrimitiveDoubleValue)
+          || tokenizer.next(TokenKind.PrimitiveDecimalValue)
+          || tokenizer.next(TokenKind.PrimitiveIntegerValue);
+    } else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Duration).equals(type)) {
+      return tokenizer.next(TokenKind.PrimitiveDurationValue);
+    } else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Binary).equals(type)) {
+      return tokenizer.next(TokenKind.PrimitiveBinaryValue);
+    } else if (type.getKind() == EdmTypeKind.ENUM) {
+      return tokenizer.next(TokenKind.PrimitiveEnumValue);
+    } else {
+      return false;
+    }
+  }
+
+  private boolean nextPrimitiveValue() {
+    return tokenizer.next(TokenKind.ParameterAliasName)
+        || tokenizer.next(TokenKind.NULL)
+        || tokenizer.next(TokenKind.PrimitiveBooleanValue)
+        || tokenizer.next(TokenKind.PrimitiveStringValue)
+
+        // The order of the next seven expressions is important in order to avoid
+        // finding partly parsed tokens (counter-intuitive as it may be, even a GUID may start with digits ...).
+        || tokenizer.next(TokenKind.PrimitiveDoubleValue)
+        || tokenizer.next(TokenKind.PrimitiveDecimalValue)
+        || tokenizer.next(TokenKind.PrimitiveGuidValue)
+        || tokenizer.next(TokenKind.PrimitiveDateTimeOffsetValue)
+        || tokenizer.next(TokenKind.PrimitiveDateValue)
+        || tokenizer.next(TokenKind.PrimitiveTimeOfDayValue)
+        || tokenizer.next(TokenKind.PrimitiveIntegerValue)
+
+        || tokenizer.next(TokenKind.PrimitiveDurationValue)
+        || tokenizer.next(TokenKind.PrimitiveBinaryValue)
+        || tokenizer.next(TokenKind.PrimitiveEnumValue);
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/927ecb93/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParseTreeVisitor.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParseTreeVisitor.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParseTreeVisitor.java
index 1e33a19..8740d66 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParseTreeVisitor.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParseTreeVisitor.java
@@ -250,7 +250,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
   public UriParseTreeVisitor(final Edm edm, final UriContext context) {
     this.edm = edm;
     this.context = context;
-    edmEntityContainer = edm.getEntityContainer(null);
+    edmEntityContainer = edm.getEntityContainer();
   }
 
   @Override