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:02 UTC

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

Repository: olingo-odata4
Updated Branches:
  refs/heads/master 0d6f4821f -> b0866014d


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/927ecb93/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestUriParserImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestUriParserImpl.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestUriParserImpl.java
index 9011bc4..e6612ff 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestUriParserImpl.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestUriParserImpl.java
@@ -28,7 +28,6 @@ import org.apache.olingo.server.api.edmx.EdmxReference;
 import org.apache.olingo.server.api.uri.UriInfoKind;
 import org.apache.olingo.server.api.uri.UriResourceKind;
 import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind;
-import org.apache.olingo.server.core.uri.parser.UriParserException;
 import org.apache.olingo.server.core.uri.parser.UriParserSemanticException;
 import org.apache.olingo.server.core.uri.parser.UriParserSyntaxException;
 import org.apache.olingo.server.core.uri.testutil.FilterValidator;
@@ -186,11 +185,11 @@ public class TestUriParserImpl {
     .isType(EntityTypeProvider.nameETTwoKeyTwoPrim, false);
 
     testUri.runEx(ContainerProvider.AIRT_STRING + "/invalidElement")
-        .isExSemantic(UriParserSemanticException.MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS);
+        .isExValidation(UriValidationException.MessageKeys.UNALLOWED_RESOURCE_PATH);
   }
 
   @Test
-  public void runCount() {
+  public void count() {
 
     // count entity set
     testRes.run("ESAllPrim/$count")
@@ -338,7 +337,7 @@ public class TestUriParserImpl {
     .isKeyPredicate(0, "PropertyInt16", "1");
 
     // with two keys
-    testRes.run("ESTwoKeyTwoPrim(PropertyInt16=1, PropertyString='ABC')")
+    testRes.run("ESTwoKeyTwoPrim(PropertyInt16=1,PropertyString='ABC')")
     .isEntitySet("ESTwoKeyTwoPrim")
     .isKeyPredicate(0, "PropertyInt16", "1")
     .isKeyPredicate(1, "PropertyString", "'ABC'");
@@ -562,14 +561,14 @@ public class TestUriParserImpl {
   }
 
   @Test
-  public void testUnary() throws UriParserException {
+  public void unary() throws Exception {
     testFilter.runOnETAllPrim("not PropertyBoolean").isCompr("<not <PropertyBoolean>>");
     testFilter.runOnETAllPrim("- PropertyInt16 eq PropertyInt16").isCompr("<<- <PropertyInt16>> eq <PropertyInt16>>");
     testFilter.runOnETAllPrim("-PropertyInt16 eq PropertyInt16").isCompr("<<- <PropertyInt16>> eq <PropertyInt16>>");
   }
 
   @Test
-  public void testFilterComplexMixedPriority() throws UriParserException {
+  public void filterComplexMixedPriority() throws Exception {
     testFilter.runOnETAllPrim("PropertyInt16 or PropertyInt32 and PropertyInt64")
         .isCompr("<<PropertyInt16> or <<PropertyInt32> and <PropertyInt64>>>");
     testFilter.runOnETAllPrim("PropertyInt16 or PropertyInt32 and PropertyInt64 eq PropertyByte")
@@ -594,7 +593,7 @@ public class TestUriParserImpl {
   }
 
   @Test
-  public void testFilterSimpleSameBinaryBinaryBinaryPriority() throws UriParserException {
+  public void filterSimpleSameBinaryBinaryBinaryPriority() throws Exception {
     testFilter.runOnETAllPrim("1 add 2 add 3 add 4").isCompr("<<< <1> add   <2>> add  <3>>  add <4>>");
     testFilter.runOnETAllPrim("1 add 2 add 3 div 4").isCompr("<<  <1> add   <2>> add <<3>   div <4>>>");
     testFilter.runOnETAllPrim("1 add 2 div 3 add 4").isCompr("<<  <1> add  <<2>  div  <3>>> add <4>>");
@@ -1101,7 +1100,7 @@ public class TestUriParserImpl {
   }
 
   @Test
-  public void testGeo() throws UriParserException {
+  public void geo() throws Exception {
     testFilter.runOnETAllPrim("geo.distance(PropertySByte,PropertySByte)")
     .is("<geo.distance(<PropertySByte>,<PropertySByte>)>")
     .isMethod(MethodKind.GEODISTANCE, 2);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/927ecb93/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/ParserTest.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/ParserTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/ParserTest.java
index 3d67c48..f54ad04 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/ParserTest.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/ParserTest.java
@@ -55,7 +55,7 @@ public class ParserTest {
     EdmEntityType productsType = Mockito.mock(EdmEntityType.class);
 
     final FullQualifiedName nameProducts = new FullQualifiedName("NS", "Products");
-    Mockito.when(mockEdm.getEntityContainer(null)).thenReturn(container);
+    Mockito.when(mockEdm.getEntityContainer()).thenReturn(container);
     Mockito.when(typeCategory.getName()).thenReturn("Category");
     Mockito.when(typeCategory.getNamespace()).thenReturn("NS");
     Mockito.when(esCategory.getEntityType()).thenReturn(typeCategory);
@@ -97,7 +97,7 @@ public class ParserTest {
     EdmEntityType typeProduct = Mockito.mock(EdmEntityType.class);
     FullQualifiedName fqnProduct = new FullQualifiedName("NS", "Products");
 
-    Mockito.when(mockEdm.getEntityContainer(null)).thenReturn(container);
+    Mockito.when(mockEdm.getEntityContainer()).thenReturn(container);
     Mockito.when(typeCategory.getName()).thenReturn(fqnCategory.getName());
     Mockito.when(typeCategory.getNamespace()).thenReturn(fqnCategory.getNamespace());
     Mockito.when(typeCategory.getFullQualifiedName()).thenReturn(fqnCategory);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/927ecb93/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 309a25f..0800dd0 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
@@ -28,7 +28,9 @@ import java.util.List;
 import org.apache.olingo.commons.api.edm.Edm;
 import org.apache.olingo.commons.api.edm.EdmType;
 import org.apache.olingo.commons.api.edm.FullQualifiedName;
+import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.api.ODataLibraryException;
 import org.apache.olingo.server.api.uri.UriInfo;
 import org.apache.olingo.server.api.uri.UriInfoKind;
 import org.apache.olingo.server.api.uri.UriResource;
@@ -51,8 +53,10 @@ import org.apache.olingo.server.core.uri.parser.UriParserSemanticException;
 import org.apache.olingo.server.core.uri.parser.UriParserSyntaxException;
 import org.apache.olingo.server.core.uri.queryoption.expression.MemberImpl;
 import org.apache.olingo.server.core.uri.queryoption.expression.MethodImpl;
+import org.apache.olingo.server.core.uri.validator.UriValidationException;
 
 public class FilterValidator implements TestValidator {
+  private final OData odata = OData.newInstance();
   private Edm edm;
 
   private TestValidator invokedByValidator;
@@ -62,7 +66,7 @@ public class FilterValidator implements TestValidator {
   private Expression curExpression;
   private Expression rootExpression;
 
-  private UriParserException exception;
+  private ODataLibraryException exception;
 
   // --- Setup ---
   public FilterValidator setUriResourcePathValidator(final ResourceValidator uriResourcePathValidator) {
@@ -107,15 +111,18 @@ public class FilterValidator implements TestValidator {
 
   // --- Execution ---
 
-  public FilterValidator runOrderByOnETAllPrim(final String orderBy) throws UriParserException {
+  public FilterValidator runOrderByOnETAllPrim(final String orderBy)
+      throws UriParserException, UriValidationException {
     return runUriOrderBy("ESAllPrim", "$orderby=" + orderBy.trim());
   }
 
-  public FilterValidator runOrderByOnETTwoKeyNav(final String orderBy) throws UriParserException {
+  public FilterValidator runOrderByOnETTwoKeyNav(final String orderBy)
+      throws UriParserException, UriValidationException {
     return runUriOrderBy("ESTwoKeyNav", "$orderby=" + orderBy.trim());
   }
 
-  public FilterValidator runOrderByOnETMixEnumDefCollComp(final String orderBy) throws UriParserException {
+  public FilterValidator runOrderByOnETMixEnumDefCollComp(final String orderBy)
+      throws UriParserException, UriValidationException {
     return runUriOrderBy("ESMixEnumDefCollComp", "$orderby=" + orderBy.trim());
   }
 
@@ -123,15 +130,17 @@ public class FilterValidator implements TestValidator {
     return runUriOrderByEx("ESTwoKeyNav", "$orderby=" + orderBy.trim());
   }
 
-  public FilterValidator runOnETTwoKeyNav(final String filter) throws UriParserException {
+  public FilterValidator runOnETTwoKeyNav(final String filter) throws UriParserException, UriValidationException {
     return runUri("ESTwoKeyNav", "$filter=" + filter.trim());
   }
 
-  public FilterValidator runOnETMixEnumDefCollComp(final String filter) throws UriParserException {
+  public FilterValidator runOnETMixEnumDefCollComp(final String filter)
+      throws UriParserException, UriValidationException {
     return runUri("ESMixEnumDefCollComp", "$filter=" + filter.trim());
   }
 
-  public FilterValidator runOnETTwoKeyNavSingle(final String filter) throws UriParserException {
+  public FilterValidator runOnETTwoKeyNavSingle(final String filter)
+      throws UriParserException, UriValidationException {
     return runUri("SINav", "$filter=" + filter.trim());
   }
 
@@ -139,11 +148,11 @@ public class FilterValidator implements TestValidator {
     return runUriEx("ESTwoKeyNav", "$filter=" + filter.trim());
   }
 
-  public FilterValidator runOnETAllPrim(final String filter) throws UriParserException {
+  public FilterValidator runOnETAllPrim(final String filter) throws UriParserException, UriValidationException {
     return runUri("ESAllPrim(1)", "$filter=" + filter.trim());
   }
 
-  public FilterValidator runOnETKeyNav(final String filter) throws UriParserException {
+  public FilterValidator runOnETKeyNav(final String filter) throws UriParserException, UriValidationException {
     return runUri("ESKeyNav(1)", "$filter=" + filter.trim());
   }
 
@@ -151,35 +160,36 @@ public class FilterValidator implements TestValidator {
     return runUriEx("ESKeyNav(1)", "$filter=" + filter.trim());
   }
 
-  public FilterValidator runOnCTTwoPrim(final String filter) throws UriParserException {
+  public FilterValidator runOnCTTwoPrim(final String filter) throws UriParserException, UriValidationException {
     return runUri("SINav/PropertyCompTwoPrim", "$filter=" + filter.trim());
   }
 
-  public FilterValidator runOnString(final String filter) throws UriParserException {
+  public FilterValidator runOnString(final String filter) throws UriParserException, UriValidationException {
     return runUri("SINav/PropertyString", "$filter=" + filter.trim());
   }
 
-  public FilterValidator runOnInt32(final String filter) throws UriParserException {
+  public FilterValidator runOnInt32(final String filter) throws UriParserException, UriValidationException {
     return runUri("ESCollAllPrim(1)/CollPropertyInt32", "$filter=" + filter.trim());
   }
 
-  public FilterValidator runOnDateTimeOffset(final String filter) throws UriParserException {
+  public FilterValidator runOnDateTimeOffset(final String filter) throws UriParserException, UriValidationException {
     return runUri("ESCollAllPrim(1)/CollPropertyDateTimeOffset", "$filter=" + filter.trim());
   }
 
-  public FilterValidator runOnDuration(final String filter) throws UriParserException {
+  public FilterValidator runOnDuration(final String filter) throws UriParserException, UriValidationException {
     return runUri("ESCollAllPrim(1)/CollPropertyDuration", "$filter=" + filter.trim());
   }
 
-  public FilterValidator runOnTimeOfDay(final String filter) throws UriParserException {
+  public FilterValidator runOnTimeOfDay(final String filter) throws UriParserException, UriValidationException {
     return runUri("ESCollAllPrim(1)/CollPropertyTimeOfDay", "$filter=" + filter.trim());
   }
 
-  public FilterValidator runUri(final String path, final String query) throws UriParserException {
-    Parser parser = new Parser();
+  public FilterValidator runUri(final String path, final String query)
+      throws UriParserException, UriValidationException {
+    Parser parser = new Parser(edm, odata);
     UriInfo uriInfo = null;
 
-    uriInfo = parser.parseUri(path, query, null, edm);
+    uriInfo = parser.parseUri(path, query, null);
 
     if (uriInfo.getKind() != UriInfoKind.resource) {
       fail("Filtervalidator can only be used on resourcePaths");
@@ -193,19 +203,19 @@ public class FilterValidator implements TestValidator {
   public FilterValidator runUriEx(final String path, final String query) {
     exception = null;
     try {
-      new Parser().parseUri(path, query, null, edm);
+      new Parser(edm, odata).parseUri(path, query, null);
       fail("Expected exception not thrown.");
     } catch (final UriParserException e) {
       exception = e;
+    } catch (final UriValidationException e) {
+      exception = e;
     }
     return this;
   }
 
-  public FilterValidator runUriOrderBy(final String path, final String query) throws UriParserException {
-    Parser parser = new Parser();
-    UriInfo uriInfo = null;
-
-    uriInfo = parser.parseUri(path, query, null, edm);
+  public FilterValidator runUriOrderBy(final String path, final String query)
+      throws UriParserException, UriValidationException {
+    final UriInfo uriInfo = new Parser(edm, odata).parseUri(path, query, null);
 
     if (uriInfo.getKind() != UriInfoKind.resource) {
       fail("Filtervalidator can only be used on resourcePaths");
@@ -218,10 +228,12 @@ public class FilterValidator implements TestValidator {
   public FilterValidator runUriOrderByEx(final String path, final String query) {
     exception = null;
     try {
-      new Parser().parseUri(path, query, null, edm);
+      new Parser(edm, odata).parseUri(path, query, null);
       fail("Expected exception not thrown.");
     } catch (final UriParserException e) {
       exception = e;
+    } catch (final UriValidationException e) {
+      exception = e;
     }
     return this;
   }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/927ecb93/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/ParserWithLogging.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/ParserWithLogging.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/ParserWithLogging.java
index 6b2b0df..5ebc57e 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/ParserWithLogging.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/ParserWithLogging.java
@@ -20,6 +20,8 @@ package org.apache.olingo.server.core.uri.testutil;
 
 import org.antlr.v4.runtime.DefaultErrorStrategy;
 import org.antlr.v4.runtime.DiagnosticErrorListener;
+import org.apache.olingo.commons.api.edm.Edm;
+import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.core.uri.antlr.UriParserParser;
 import org.apache.olingo.server.core.uri.parser.Parser;
 
@@ -27,7 +29,8 @@ public class ParserWithLogging extends Parser {
   TestErrorLogger errorCollector1;
   TestErrorLogger errorCollector2;
 
-  public ParserWithLogging() {
+  public ParserWithLogging(final Edm edm, final OData odata) {
+    super(edm, odata);
     errorCollector1 = new TestErrorLogger("Stage 1", 1);
     errorCollector2 = new TestErrorLogger("Stage 2", 1);
   }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/927ecb93/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 994b6b2..d70b204 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
@@ -30,6 +30,8 @@ import org.apache.olingo.commons.api.edm.EdmElement;
 import org.apache.olingo.commons.api.edm.EdmType;
 import org.apache.olingo.commons.api.edm.FullQualifiedName;
 import org.apache.olingo.commons.api.http.HttpMethod;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.ODataLibraryException;
 import org.apache.olingo.server.api.uri.UriInfo;
 import org.apache.olingo.server.api.uri.UriInfoKind;
 import org.apache.olingo.server.api.uri.UriInfoResource;
@@ -50,11 +52,11 @@ import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
 import org.apache.olingo.server.api.uri.queryoption.SelectItem;
 import org.apache.olingo.server.api.uri.queryoption.SelectOption;
 import org.apache.olingo.server.core.uri.UriResourceWithKeysImpl;
-import org.apache.olingo.server.core.uri.parser.UriParserException;
 import org.apache.olingo.server.core.uri.validator.UriValidationException;
 import org.apache.olingo.server.core.uri.validator.UriValidator;
 
 public class ResourceValidator implements TestValidator {
+  private final OData odata = OData.newInstance();
   private Edm edm;
   private TestValidator invokedBy;
   private UriInfo uriInfo = null;
@@ -83,13 +85,13 @@ public class ResourceValidator implements TestValidator {
   // --- Execution ---
 
   public ResourceValidator run(final String path) {
-    ParserWithLogging testParser = new ParserWithLogging();
+    ParserWithLogging testParser = new ParserWithLogging(edm, odata);
 
     UriInfo uriInfoTmp = null;
     uriPathInfo = null;
     try {
-      uriInfoTmp = testParser.parseUri(path, null, null, edm);
-    } catch (final UriParserException e) {
+      uriInfoTmp = testParser.parseUri(path, null, null);
+    } catch (final ODataLibraryException e) {
       fail("Exception occurred while parsing the URI: " + path + "\n"
           + " Message: " + e.getMessage());
     }
@@ -279,7 +281,8 @@ public class ResourceValidator implements TestValidator {
 
     // input parameter type may be null in order to assert that the collectionTypeFilter is not set
     EdmType actualType = uriPathInfoKeyPred.getTypeFilterOnCollection();
-    assertEquals(expectedType, expectedType == null ? actualType : actualType.getFullQualifiedName());
+    assertEquals(expectedType,
+        expectedType == null || actualType == null ? actualType : actualType.getFullQualifiedName());
 
     return this;
   }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/927ecb93/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 0d5fb4a..1dbe62b 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
@@ -28,6 +28,7 @@ import org.apache.olingo.commons.api.edm.Edm;
 import org.apache.olingo.commons.api.edm.EdmType;
 import org.apache.olingo.commons.api.edm.FullQualifiedName;
 import org.apache.olingo.commons.api.http.HttpMethod;
+import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.ODataLibraryException;
 import org.apache.olingo.server.api.uri.UriInfo;
 import org.apache.olingo.server.api.uri.UriInfoKind;
@@ -44,6 +45,7 @@ import org.apache.olingo.server.core.uri.validator.UriValidationException;
 import org.apache.olingo.server.core.uri.validator.UriValidator;
 
 public class TestUriValidator implements TestValidator {
+  private final OData odata = OData.newInstance();
   private Edm edm;
 
   private UriInfo uriInfo;
@@ -62,17 +64,14 @@ public class TestUriValidator implements TestValidator {
 
   public TestUriValidator run(final String path, final String query)
       throws UriParserException, UriValidationException {
-    Parser parser = new Parser();
-    UriValidator validator = new UriValidator();
-
-    uriInfo = parser.parseUri(path, query, null, edm);
-    validator.validate(uriInfo, HttpMethod.GET);
+    uriInfo = new Parser(edm, odata).parseUri(path, query, null);
+    new UriValidator().validate(uriInfo, HttpMethod.GET);
     return this;
   }
 
   public TestUriValidator run(final String path, final String query, final String fragment)
       throws UriParserException, UriValidationException {
-    uriInfo = new Parser().parseUri(path, query, fragment, edm);
+    uriInfo = new Parser(edm, odata).parseUri(path, query, fragment);
     new UriValidator().validate(uriInfo, HttpMethod.GET);
     return this;
   }
@@ -82,10 +81,9 @@ public class TestUriValidator implements TestValidator {
   }
 
   public TestUriValidator runEx(final String path, final String query) {
-    Parser parser = new Parser();
     uriInfo = null;
     try {
-      uriInfo = parser.parseUri(path, query, null, edm);
+      uriInfo = new Parser(edm, odata).parseUri(path, query, null);
       new UriValidator().validate(uriInfo, HttpMethod.GET);
       fail("Exception expected");
     } catch (UriParserException e) {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/927ecb93/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 0e8b2e6..868f9b8 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
@@ -323,7 +323,8 @@ public class UriValidatorTest {
       { URI_ACTION_ES, QO_ID }
   };
 
-  private static final Edm edm = OData.newInstance().createServiceMetadata(
+  private static final OData odata = OData.newInstance();
+  private static final Edm edm = odata.createServiceMetadata(
       new EdmTechProvider(), Collections.<EdmxReference> emptyList()).getEdm();
 
   @Test
@@ -419,24 +420,24 @@ public class UriValidatorTest {
   public void checkKeys() throws Exception {
     final TestUriValidator testUri = new TestUriValidator().setEdm(edm);
 
-    testUri.run("ESTwoKeyNav(PropertyInt16=1, PropertyString='abc')");
+    testUri.run("ESTwoKeyNav(PropertyInt16=1,PropertyString='abc')");
 
-    testUri.runEx("ESTwoKeyNav(xxx=1, yyy='abc')")
+    testUri.runEx("ESTwoKeyNav(xxx=1,yyy='abc')")
         .isExValidation(UriValidationException.MessageKeys.INVALID_KEY_PROPERTY);
     testUri.runEx("ESCollAllPrim(null)").isExValidation(UriValidationException.MessageKeys.INVALID_KEY_PROPERTY);
     testUri.runEx("ESAllPrim(PropertyInt16='1')")
-        .isExValidation(UriValidationException.MessageKeys.INVALID_KEY_PROPERTY);
+        .isExSemantic(UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE);
     testUri.runEx("ESAllPrim(12345678901234567890)")
         .isExValidation(UriValidationException.MessageKeys.INVALID_KEY_PROPERTY);
     testUri.runEx("ESTwoKeyNav(PropertyInt16=1,PropertyString=1)")
-        .isExValidation(UriValidationException.MessageKeys.INVALID_KEY_PROPERTY);
+        .isExSemantic(UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE);
     testUri.runEx("ESTwoKeyNav(PropertyInt16=1,PropertyInt16=1)")
         .isExValidation(UriValidationException.MessageKeys.DOUBLE_KEY_PROPERTY);
 
     testUri.runEx("ESAllPrim(0)/NavPropertyETTwoPrimMany(xxx=42)")
         .isExValidation(UriValidationException.MessageKeys.INVALID_KEY_PROPERTY);
     testUri.runEx("ESAllPrim(0)/NavPropertyETTwoPrimMany(PropertyInt16='1')")
-        .isExValidation(UriValidationException.MessageKeys.INVALID_KEY_PROPERTY);
+        .isExSemantic(UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE);
   }
 
   @Test
@@ -499,7 +500,7 @@ public class UriValidatorTest {
 
   private void validate(final String path, final String query, final HttpMethod method) {
     try {
-      new UriValidator().validate(new Parser().parseUri(path, query, null, edm), method);
+      new UriValidator().validate(new Parser(edm, odata).parseUri(path, query, null), method);
     } catch (final UriParserException e) {
       fail("Failed for uri: " + path + '?' + query);
     } catch (final UriValidationException e) {
@@ -510,7 +511,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().parseUri(path, query, null, edm), method);
+      new UriValidator().validate(new Parser(edm, odata).parseUri(path, query, null), method);
       fail("Validation Exception not thrown: " + method + ' ' + path + '?' + query);
     } catch (final UriParserException e) {
       fail("Wrong Exception thrown: " + method + ' ' + path + '?' + query);


[18/30] olingo-odata4 git commit: [OLINGO-834] ExpressionParser parses path expressions

Posted by ch...@apache.org.
[OLINGO-834] ExpressionParser parses path expressions

Signed-off-by: Christian Amend <ch...@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/a8091658
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/a8091658
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/a8091658

Branch: refs/heads/master
Commit: a809165896e8315a04b566e11bd1637c26044c7d
Parents: 104ecf4
Author: Klaus Straubinger <kl...@sap.com>
Authored: Fri Dec 18 16:42:51 2015 +0100
Committer: Christian Amend <ch...@sap.com>
Committed: Mon Dec 21 10:10:35 2015 +0100

----------------------------------------------------------------------
 .../deserializer/helper/ExpandTreeBuilder.java  |  14 +-
 .../server/core/uri/UriResourceActionImpl.java  |  44 +-
 .../uri/UriResourceComplexPropertyImpl.java     |  18 +-
 .../server/core/uri/UriResourceCountImpl.java   |  10 +-
 .../core/uri/UriResourceEntitySetImpl.java      |  19 +-
 .../core/uri/UriResourceFunctionImpl.java       |  48 +-
 .../olingo/server/core/uri/UriResourceImpl.java |   6 +-
 .../server/core/uri/UriResourceItImpl.java      |  31 +-
 .../core/uri/UriResourceLambdaAllImpl.java      |  26 +-
 .../core/uri/UriResourceLambdaAnyImpl.java      |  25 +-
 .../core/uri/UriResourceLambdaVarImpl.java      |  32 +-
 .../uri/UriResourceNavigationPropertyImpl.java  |  21 +-
 .../uri/UriResourcePrimitivePropertyImpl.java   |  20 +-
 .../server/core/uri/UriResourceRefImpl.java     |  10 +-
 .../server/core/uri/UriResourceRootImpl.java    |  31 +-
 .../core/uri/UriResourceSingletonImpl.java      |  21 +-
 .../uri/UriResourceStartingTypeFilterImpl.java  |  33 +-
 .../server/core/uri/UriResourceTypedImpl.java   |  11 +-
 .../server/core/uri/UriResourceValueImpl.java   |   9 +-
 .../core/uri/parser/ExpressionParser.java       | 560 ++++++++++-
 .../server/core/uri/parser/FilterParser.java    |  49 +
 .../server/core/uri/parser/OrderByParser.java   |  61 ++
 .../olingo/server/core/uri/parser/Parser.java   | 123 +--
 .../server/core/uri/parser/ParserHelper.java    | 335 ++++++-
 .../core/uri/parser/ResourcePathParser.java     | 323 +-----
 .../server/core/uri/parser/SelectParser.java    |  10 +-
 .../server/core/uri/parser/UriContext.java      |   7 +-
 .../core/uri/parser/UriParseTreeVisitor.java    | 124 +--
 .../server/core/uri/parser/UriTokenizer.java    |  36 +-
 .../uri/queryoption/expression/MemberImpl.java  |   5 +
 .../olingo/server/core/uri/UriInfoImplTest.java |  10 +-
 .../core/uri/parser/ExpressionParserTest.java   |  21 +-
 .../core/uri/parser/UriTokenizerTest.java       |  31 +-
 .../server/core/uri/UriResourceImplTest.java    | 156 ++-
 .../core/uri/antlr/TestFullResourcePath.java    | 979 +++++++++----------
 .../core/uri/antlr/TestUriParserImpl.java       |  36 +-
 .../queryoption/expression/ExpressionTest.java  |  12 +-
 37 files changed, 1816 insertions(+), 1491 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8091658/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/helper/ExpandTreeBuilder.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/helper/ExpandTreeBuilder.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/helper/ExpandTreeBuilder.java
index 549cf33..7577e7b 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/helper/ExpandTreeBuilder.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/helper/ExpandTreeBuilder.java
@@ -27,14 +27,8 @@ public abstract class ExpandTreeBuilder {
   public abstract ExpandTreeBuilder expand(EdmNavigationProperty edmNavigationProperty);
 
   protected ExpandItemImpl buildExpandItem(final EdmNavigationProperty edmNavigationProperty) {
-    final ExpandItemImpl expandItem = new ExpandItemImpl();
-    final UriInfoImpl uriInfo = new UriInfoImpl();
-    final UriResourceNavigationPropertyImpl resourceNavigation = new UriResourceNavigationPropertyImpl();
-
-    resourceNavigation.setNavigationProperty(edmNavigationProperty);
-    uriInfo.addResourcePart(resourceNavigation);
-    expandItem.setResourcePath(uriInfo);
-
-    return expandItem;
+    return new ExpandItemImpl()
+        .setResourcePath(new UriInfoImpl()
+            .addResourcePart(new UriResourceNavigationPropertyImpl(edmNavigationProperty)));
   }
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8091658/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceActionImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceActionImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceActionImpl.java
index 4126110..1853942 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceActionImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceActionImpl.java
@@ -31,11 +31,19 @@ import org.apache.olingo.server.api.uri.UriResourceKind;
  */
 public class UriResourceActionImpl extends UriResourceImpl implements UriResourceAction {
 
-  protected EdmAction action;
-  protected EdmActionImport actionImport;
+  private final EdmActionImport actionImport;
+  private final EdmAction action;
 
-  public UriResourceActionImpl() {
+  public UriResourceActionImpl(final EdmActionImport actionImport) {
     super(UriResourceKind.action);
+    this.actionImport = actionImport;
+    this.action = actionImport.getUnboundAction();
+  }
+
+  public UriResourceActionImpl(final EdmAction action) {
+    super(UriResourceKind.action);
+    this.actionImport = null;
+    this.action = action;
   }
 
   @Override
@@ -43,38 +51,21 @@ public class UriResourceActionImpl extends UriResourceImpl implements UriResourc
     return action;
   }
 
-  public UriResourceActionImpl setAction(final EdmAction action) {
-    this.action = action;
-    return this;
-  }
-
   @Override
   public EdmActionImport getActionImport() {
     return actionImport;
   }
 
-  public UriResourceActionImpl setActionImport(final EdmActionImport actionImport) {
-    this.actionImport = actionImport;
-    setAction(actionImport.getUnboundAction());
-    return this;
-  }
-
   @Override
   public boolean isCollection() {
-    if (action.getReturnType() != null) {
-      return action.getReturnType().isCollection();
-    }
-    return false;
+    return action.getReturnType() != null && action.getReturnType().isCollection();
   }
 
   @Override
   public EdmType getType() {
-    if (action.getReturnType() != null) {
-      return action.getReturnType().getType();
-    }
-    return null;
+    return action.getReturnType() == null ? null : action.getReturnType().getType();
   }
-  
+
   @Override
   public String getSegmentValue(final boolean includeFilters) {
     return actionImport == null ? (action == null ? "" : action.getName()) : actionImport.getName();
@@ -84,14 +75,9 @@ public class UriResourceActionImpl extends UriResourceImpl implements UriResourc
   public String getSegmentValue() {
     return getSegmentValue(false);
   }
-  
+
   @Override
   public String toString(final boolean includeFilters) {
     return getSegmentValue(includeFilters);
   }
-
-  @Override
-  public String toString() {
-    return getSegmentValue();
-  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8091658/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceComplexPropertyImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceComplexPropertyImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceComplexPropertyImpl.java
index 63db69c..9c83f24 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceComplexPropertyImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceComplexPropertyImpl.java
@@ -26,10 +26,11 @@ import org.apache.olingo.server.api.uri.UriResourceKind;
 
 public class UriResourceComplexPropertyImpl extends UriResourceTypedImpl implements UriResourceComplexProperty {
 
-  protected EdmProperty property;
+  private final EdmProperty property;
 
-  public UriResourceComplexPropertyImpl() {
+  public UriResourceComplexPropertyImpl(final EdmProperty property) {
     super(UriResourceKind.complexProperty);
+    this.property = property;
   }
 
   @Override
@@ -37,11 +38,6 @@ public class UriResourceComplexPropertyImpl extends UriResourceTypedImpl impleme
     return property;
   }
 
-  public UriResourceComplexPropertyImpl setProperty(final EdmProperty property) {
-    this.property = property;
-    return this;
-  }
-
   @Override
   public EdmComplexType getComplexType() {
     return (EdmComplexType) getType();
@@ -63,13 +59,7 @@ public class UriResourceComplexPropertyImpl extends UriResourceTypedImpl impleme
   }
 
   @Override
-  public String getSegmentValue(){
+  public String getSegmentValue() {
     return property.getName();
   }
-  
-  @Override
-  public String toString() {
-    return getSegmentValue();
-  }
-
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8091658/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceCountImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceCountImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceCountImpl.java
index e1859a6..90dc4f5 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceCountImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceCountImpl.java
@@ -26,15 +26,9 @@ public class UriResourceCountImpl extends UriResourceImpl implements UriResource
   public UriResourceCountImpl() {
     super(UriResourceKind.count);
   }
-  
-  @Override
-  public String getSegmentValue(){
-    return "$count";
-  }
 
   @Override
-  public String toString() {
-    return getSegmentValue();
+  public String getSegmentValue() {
+    return "$count";
   }
-
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8091658/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceEntitySetImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceEntitySetImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceEntitySetImpl.java
index 4675964..ea21fe5 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceEntitySetImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceEntitySetImpl.java
@@ -25,10 +25,12 @@ import org.apache.olingo.server.api.uri.UriResourceEntitySet;
 import org.apache.olingo.server.api.uri.UriResourceKind;
 
 public class UriResourceEntitySetImpl extends UriResourceWithKeysImpl implements UriResourceEntitySet {
-  protected EdmEntitySet edmEntitySet = null;
 
-  public UriResourceEntitySetImpl() {
+  private final EdmEntitySet edmEntitySet;
+
+  public UriResourceEntitySetImpl(final EdmEntitySet edmEntitySet) {
     super(UriResourceKind.entitySet);
+    this.edmEntitySet = edmEntitySet;
   }
 
   @Override
@@ -36,11 +38,6 @@ public class UriResourceEntitySetImpl extends UriResourceWithKeysImpl implements
     return edmEntitySet;
   }
 
-  public UriResourceEntitySetImpl setEntitSet(final EdmEntitySet edmES) {
-    edmEntitySet = edmES;
-    return this;
-  }
-
   @Override
   public EdmEntityType getEntityType() {
     return edmEntitySet.getEntityType();
@@ -57,13 +54,7 @@ public class UriResourceEntitySetImpl extends UriResourceWithKeysImpl implements
   }
   
   @Override
-  public String getSegmentValue(){
+  public String getSegmentValue() {
     return edmEntitySet.getName();
   }
-  
-
-  @Override
-  public String toString() {
-    return getSegmentValue();
-  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8091658/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceFunctionImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceFunctionImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceFunctionImpl.java
index a47a6ab..7784062 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceFunctionImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceFunctionImpl.java
@@ -33,13 +33,16 @@ import org.apache.olingo.server.api.uri.UriResourceKind;
  */
 public class UriResourceFunctionImpl extends UriResourceWithKeysImpl implements UriResourceFunction {
 
-  protected List<UriParameter> parameters;
-  protected EdmFunction function;
-  protected EdmFunctionImport functionImport;
-  private boolean isParameterListFilled = false;
+  private final EdmFunctionImport functionImport;
+  private final EdmFunction function;
+  private final List<UriParameter> parameters;
 
-  public UriResourceFunctionImpl() {
+  public UriResourceFunctionImpl(final EdmFunctionImport edmFunctionImport, final EdmFunction function,
+      final List<UriParameter> parameters) {
     super(UriResourceKind.function);
+    this.functionImport = edmFunctionImport;
+    this.function = function;
+    this.parameters = parameters;
   }
 
   @Override
@@ -49,34 +52,16 @@ public class UriResourceFunctionImpl extends UriResourceWithKeysImpl implements
         Collections.unmodifiableList(parameters);
   }
 
-  public UriResourceFunctionImpl setParameters(final List<UriParameter> parameters) {
-    isParameterListFilled = true;
-    this.parameters = parameters;
-    return this;
-  }
-
   @Override
   public EdmFunction getFunction() {
     return function;
   }
 
-  public UriResourceFunctionImpl setFunction(final EdmFunction function) {
-    this.function = function;
-    return this;
-  }
-
   @Override
   public EdmFunctionImport getFunctionImport() {
     return functionImport;
   }
 
-  public UriResourceFunctionImpl setFunctionImport(final EdmFunctionImport edmFunctionImport,
-      final List<UriParameter> parameters) {
-    functionImport = edmFunctionImport;
-    setParameters(parameters);
-    return this;
-  }
-
   @Override
   public EdmType getType() {
     return function.getReturnType().getType();
@@ -89,21 +74,6 @@ public class UriResourceFunctionImpl extends UriResourceWithKeysImpl implements
 
   @Override
   public String getSegmentValue() {
-    if (functionImport != null) {
-      return functionImport.getName();
-    } else if (function != null) {
-      return function.getName();
-    }
-    return "";
+    return functionImport == null ? (function == null ? "" : function.getName()) : functionImport.getName();
   }
-
-  @Override
-  public String toString() {
-    return getSegmentValue();
-  }
-
-  public boolean isParameterListFilled() {
-    return isParameterListFilled;
-  }
-
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8091658/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceImpl.java
index 9fbcbd0..db991a8 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceImpl.java
@@ -22,7 +22,7 @@ import org.apache.olingo.server.api.uri.UriResource;
 import org.apache.olingo.server.api.uri.UriResourceKind;
 
 /**
- * Covers Functionimports and BoundFunction in URI
+ * Abstract class for resource-path elements in URI.
  */
 public abstract class UriResourceImpl implements UriResource {
   protected UriResourceKind kind;
@@ -36,4 +36,8 @@ public abstract class UriResourceImpl implements UriResource {
     return kind;
   }
 
+  @Override
+  public String toString() {
+    return getSegmentValue();
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8091658/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceItImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceItImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceItImpl.java
index fc31910..e7db56c 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceItImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceItImpl.java
@@ -27,11 +27,13 @@ import org.apache.olingo.server.api.uri.UriResourceKind;
  */
 public class UriResourceItImpl extends UriResourceWithKeysImpl implements UriResourceIt {
 
-  private EdmType type;
-  private boolean isCollection;
+  private final EdmType type;
+  private final boolean isCollection;
 
-  public UriResourceItImpl() {
+  public UriResourceItImpl(final EdmType type, final boolean isCollection) {
     super(UriResourceKind.it);
+    this.type = type;
+    this.isCollection = isCollection;
   }
 
   @Override
@@ -39,32 +41,13 @@ public class UriResourceItImpl extends UriResourceWithKeysImpl implements UriRes
     return type;
   }
 
-  public UriResourceItImpl setType(final EdmType type) {
-    this.type = type;
-    return this;
-  }
-
   @Override
   public boolean isCollection() {
-    if (keyPredicates != null) {
-      return false;
-    }
-    return isCollection;
+    return keyPredicates == null && isCollection;
   }
 
-  public UriResourceItImpl setCollection(final boolean isCollection) {
-    this.isCollection = isCollection;
-    return this;
-  }
-  
   @Override
-  public String getSegmentValue(){
+  public String getSegmentValue() {
     return "$it";
   }
-
-  @Override
-  public String toString() {
-    return getSegmentValue();
-  }
-
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8091658/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceLambdaAllImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceLambdaAllImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceLambdaAllImpl.java
index d980777..4f5a4fa 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceLambdaAllImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceLambdaAllImpl.java
@@ -19,7 +19,6 @@
 package org.apache.olingo.server.core.uri;
 
 import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
-import org.apache.olingo.commons.api.edm.EdmProperty;
 import org.apache.olingo.commons.api.edm.EdmType;
 import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
 import org.apache.olingo.server.api.uri.UriResourceKind;
@@ -28,12 +27,13 @@ import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
 
 public class UriResourceLambdaAllImpl extends UriResourceTypedImpl implements UriResourceLambdaAll {
 
-  protected EdmProperty property;
-  private String lambdaVariable;
-  private Expression expression;
+  private final String lambdaVariable;
+  private final Expression expression;
 
-  public UriResourceLambdaAllImpl() {
+  public UriResourceLambdaAllImpl(final String lambdaVariable, final Expression expression) {
     super(UriResourceKind.lambdaAll);
+    this.lambdaVariable = lambdaVariable;
+    this.expression = expression;
   }
 
   @Override
@@ -51,29 +51,13 @@ public class UriResourceLambdaAllImpl extends UriResourceTypedImpl implements Ur
     return lambdaVariable;
   }
 
-  public UriResourceLambdaAllImpl setLamdaVariable(final String lambdaVariable) {
-    this.lambdaVariable = lambdaVariable;
-    return this;
-  }
-
   @Override
   public Expression getExpression() {
     return expression;
   }
 
-  public UriResourceLambdaAllImpl setExpression(final Expression expression) {
-    this.expression = expression;
-    return this;
-  }
-
   @Override
   public String getSegmentValue() {
     return "all";
   }
-
-  @Override
-  public String toString() {
-    return getSegmentValue();
-  }
-
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8091658/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceLambdaAnyImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceLambdaAnyImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceLambdaAnyImpl.java
index fe5dfee..b586a09 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceLambdaAnyImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceLambdaAnyImpl.java
@@ -19,7 +19,6 @@
 package org.apache.olingo.server.core.uri;
 
 import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
-import org.apache.olingo.commons.api.edm.EdmProperty;
 import org.apache.olingo.commons.api.edm.EdmType;
 import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
 import org.apache.olingo.server.api.uri.UriResourceKind;
@@ -28,12 +27,13 @@ import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
 
 public class UriResourceLambdaAnyImpl extends UriResourceTypedImpl implements UriResourceLambdaAny {
 
-  protected EdmProperty property;
-  private String lambdaVariable;
-  private Expression expression;
+  private final String lambdaVariable;
+  private final Expression expression;
 
-  public UriResourceLambdaAnyImpl() {
+  public UriResourceLambdaAnyImpl(final String lambdaVariable, final Expression expression) {
     super(UriResourceKind.lambdaAny);
+    this.lambdaVariable = lambdaVariable;
+    this.expression = expression;
   }
 
   @Override
@@ -51,28 +51,13 @@ public class UriResourceLambdaAnyImpl extends UriResourceTypedImpl implements Ur
     return lambdaVariable;
   }
 
-  public UriResourceLambdaAnyImpl setLamdaVariable(final String lambdaVariable) {
-    this.lambdaVariable = lambdaVariable;
-    return this;
-  }
-
   @Override
   public Expression getExpression() {
     return expression;
   }
 
-  public UriResourceLambdaAnyImpl setExpression(final Expression expression) {
-    this.expression = expression;
-    return this;
-  }
-
   @Override
   public String getSegmentValue() {
     return "any";
   }
-
-  @Override
-  public String toString() {
-    return getSegmentValue();
-  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8091658/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceLambdaVarImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceLambdaVarImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceLambdaVarImpl.java
index 2eb7607..306807a 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceLambdaVarImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceLambdaVarImpl.java
@@ -24,12 +24,13 @@ import org.apache.olingo.server.api.uri.UriResourceLambdaVariable;
 
 public class UriResourceLambdaVarImpl extends UriResourceTypedImpl implements UriResourceLambdaVariable {
 
-  private EdmType type;
-  private boolean isCollection;
-  private String variableText;
+  private final String variableText;
+  private final EdmType type;
 
-  public UriResourceLambdaVarImpl() {
+  public UriResourceLambdaVarImpl(final String variableText, final EdmType type) {
     super(UriResourceKind.lambdaVariable);
+    this.variableText = variableText;
+    this.type = type;
   }
 
   @Override
@@ -37,39 +38,18 @@ public class UriResourceLambdaVarImpl extends UriResourceTypedImpl implements Ur
     return variableText;
   }
 
-  public UriResourceLambdaVarImpl setVariableText(final String variableText) {
-    this.variableText = variableText;
-    return this;
-  }
-
   @Override
   public EdmType getType() {
     return type;
   }
 
-  public UriResourceLambdaVarImpl setType(final EdmType type) {
-    this.type = type;
-    return this;
-
-  }
-
   @Override
   public boolean isCollection() {
-    return isCollection;
-  }
-
-  public UriResourceLambdaVarImpl setCollection(final boolean isCollection) {
-    this.isCollection = isCollection;
-    return this;
+    return false;
   }
 
   @Override
   public String getSegmentValue() {
     return variableText;
   }
-
-  @Override
-  public String toString() {
-    return getSegmentValue();
-  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8091658/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 f4390b5..1d8b321 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
@@ -25,10 +25,11 @@ import org.apache.olingo.server.api.uri.UriResourceNavigation;
 
 public class UriResourceNavigationPropertyImpl extends UriResourceWithKeysImpl implements UriResourceNavigation {
 
-  protected EdmNavigationProperty navigationProperty;
+  private final EdmNavigationProperty navigationProperty;
 
-  public UriResourceNavigationPropertyImpl() {
+  public UriResourceNavigationPropertyImpl(final EdmNavigationProperty property) {
     super(UriResourceKind.navigationProperty);
+    navigationProperty = property;
   }
 
   @Override
@@ -36,12 +37,6 @@ public class UriResourceNavigationPropertyImpl extends UriResourceWithKeysImpl i
     return navigationProperty;
   }
 
-  public UriResourceNavigationPropertyImpl setNavigationProperty(final EdmNavigationProperty property) {
-    navigationProperty = property;
-    return this;
-
-  }
-
   @Override
   public EdmType getType() {
     return navigationProperty.getType();
@@ -51,15 +46,9 @@ public class UriResourceNavigationPropertyImpl extends UriResourceWithKeysImpl i
   public boolean isCollection() {
     return navigationProperty.isCollection() && keyPredicates == null;
   }
-  
-  @Override
-  public String getSegmentValue(){
-    return navigationProperty.getName();
-  }
 
   @Override
-  public String toString() {
-    return getSegmentValue();
+  public String getSegmentValue() {
+    return navigationProperty.getName();
   }
-
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8091658/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourcePrimitivePropertyImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourcePrimitivePropertyImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourcePrimitivePropertyImpl.java
index d470ef4..bb04142 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourcePrimitivePropertyImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourcePrimitivePropertyImpl.java
@@ -25,10 +25,11 @@ import org.apache.olingo.server.api.uri.UriResourcePrimitiveProperty;
 
 public class UriResourcePrimitivePropertyImpl extends UriResourceTypedImpl implements UriResourcePrimitiveProperty {
 
-  EdmProperty property;
+  private final EdmProperty property;
 
-  public UriResourcePrimitivePropertyImpl() {
+  public UriResourcePrimitivePropertyImpl(final EdmProperty property) {
     super(UriResourceKind.primitiveProperty);
+    this.property = property;
   }
 
   @Override
@@ -36,11 +37,6 @@ public class UriResourcePrimitivePropertyImpl extends UriResourceTypedImpl imple
     return property;
   }
 
-  public UriResourcePrimitivePropertyImpl setProperty(final EdmProperty property) {
-    this.property = property;
-    return this;
-  }
-
   @Override
   public EdmType getType() {
     return property.getType();
@@ -50,15 +46,9 @@ public class UriResourcePrimitivePropertyImpl extends UriResourceTypedImpl imple
   public boolean isCollection() {
     return property.isCollection();
   }
-  
-  @Override
-  public String getSegmentValue(){
-    return  property.getName();
-  }
 
   @Override
-  public String toString() {
-    return getSegmentValue();
+  public String getSegmentValue() {
+    return property.getName();
   }
-
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8091658/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceRefImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceRefImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceRefImpl.java
index 0c45f9a..6f01936 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceRefImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceRefImpl.java
@@ -25,16 +25,10 @@ public class UriResourceRefImpl extends UriResourceImpl implements UriResourceRe
 
   public UriResourceRefImpl() {
     super(UriResourceKind.ref);
-
-  }
-  @Override
-  public String getSegmentValue(){
-    return "$ref";
   }
 
   @Override
-  public String toString() {
-    return getSegmentValue();
+  public String getSegmentValue() {
+    return "$ref";
   }
-
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8091658/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceRootImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceRootImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceRootImpl.java
index 5d8737f..761899f 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceRootImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceRootImpl.java
@@ -24,11 +24,13 @@ import org.apache.olingo.server.api.uri.UriResourceRoot;
 
 public class UriResourceRootImpl extends UriResourceWithKeysImpl implements UriResourceRoot {
 
-  private EdmType type;
-  private boolean isCollection;
+  private final EdmType type;
+  private final boolean isCollection;
 
-  public UriResourceRootImpl() {
+  public UriResourceRootImpl(final EdmType type, final boolean isCollection) {
     super(UriResourceKind.root);
+    this.type = type;
+    this.isCollection = isCollection;
   }
 
   @Override
@@ -36,32 +38,13 @@ public class UriResourceRootImpl extends UriResourceWithKeysImpl implements UriR
     return type;
   }
 
-  public UriResourceRootImpl setType(final EdmType type) {
-    this.type = type;
-    return this;
-  }
-
   @Override
   public boolean isCollection() {
-    if (keyPredicates != null) {
-      return false;
-    }
-    return isCollection;
+    return keyPredicates == null && isCollection;
   }
 
-  public UriResourceRootImpl setCollection(final boolean isCollection) {
-    this.isCollection = isCollection;
-    return this;
-  }
-  
   @Override
-  public String getSegmentValue(){
+  public String getSegmentValue() {
     return "$root";
   }
-
-  @Override
-  public String toString() {
-    return getSegmentValue();
-  }
-
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8091658/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceSingletonImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceSingletonImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceSingletonImpl.java
index 72289f6..381a518 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceSingletonImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceSingletonImpl.java
@@ -26,10 +26,11 @@ import org.apache.olingo.server.api.uri.UriResourceSingleton;
 
 public class UriResourceSingletonImpl extends UriResourceTypedImpl implements UriResourceSingleton {
 
-  private EdmSingleton singleton;
+  private final EdmSingleton singleton;
 
-  public UriResourceSingletonImpl() {
+  public UriResourceSingletonImpl(final EdmSingleton singleton) {
     super(UriResourceKind.singleton);
+    this.singleton = singleton;
   }
 
   @Override
@@ -37,12 +38,6 @@ public class UriResourceSingletonImpl extends UriResourceTypedImpl implements Ur
     return singleton;
   }
 
-  public UriResourceSingletonImpl setSingleton(final EdmSingleton singleton) {
-
-    this.singleton = singleton;
-    return this;
-  }
-
   @Override
   public EdmEntityType getEntityTypeFilter() {
     return (EdmEntityType) typeFilter;
@@ -62,15 +57,9 @@ public class UriResourceSingletonImpl extends UriResourceTypedImpl implements Ur
   public boolean isCollection() {
     return false;
   }
-  
-  @Override
-  public String getSegmentValue(){
-    return singleton.getName();
-  }
 
   @Override
-  public String toString() {
-    return getSegmentValue();
+  public String getSegmentValue() {
+    return singleton.getName();
   }
-
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8091658/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceStartingTypeFilterImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceStartingTypeFilterImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceStartingTypeFilterImpl.java
index 24d3713..09af068 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceStartingTypeFilterImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceStartingTypeFilterImpl.java
@@ -23,11 +23,13 @@ import org.apache.olingo.server.api.uri.UriResourceKind;
 
 public class UriResourceStartingTypeFilterImpl extends UriResourceWithKeysImpl {
 
-  private EdmType type;
-  private boolean isCollection;
+  private final EdmType type;
+  private final boolean isCollection;
 
-  public UriResourceStartingTypeFilterImpl() {
+  public UriResourceStartingTypeFilterImpl(final EdmType type, final boolean isCollection) {
     super(null);
+    this.type = type;
+    this.isCollection = isCollection;
   }
 
   @Override
@@ -40,32 +42,13 @@ public class UriResourceStartingTypeFilterImpl extends UriResourceWithKeysImpl {
     return type;
   }
 
-  public UriResourceStartingTypeFilterImpl setType(final EdmType type) {
-    this.type = type;
-    return this;
-  }
-
   @Override
   public boolean isCollection() {
-    if (keyPredicates != null) {
-      return false;
-    }
-    return isCollection;
-  }
-
-  public UriResourceStartingTypeFilterImpl setCollection(final boolean isCollection) {
-    this.isCollection = isCollection;
-    return this;
+    return keyPredicates == null && isCollection;
   }
 
   @Override
-  public String getSegmentValue(){
-    return type.getNamespace() + "." + type.getName();
+  public String getSegmentValue() {
+    return type.getFullQualifiedName().getFullQualifiedNameAsString();
   }
-  
-  @Override
-  public String toString() {
-    return getSegmentValue();
-  }
-
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8091658/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceTypedImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceTypedImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceTypedImpl.java
index d6710ad..9930a7e 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceTypedImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceTypedImpl.java
@@ -41,14 +41,9 @@ public abstract class UriResourceTypedImpl extends UriResourceImpl implements Ur
   }
 
   public String getSegmentValue(final boolean includeFilters) {
-    if (includeFilters) {
-      if (typeFilter != null) {
-        return getSegmentValue() + "/" + typeFilter.getFullQualifiedName().toString();
-      } else {
-        return getSegmentValue();
-      }
-    }
-    return getSegmentValue();
+    return includeFilters && typeFilter != null ?
+        getSegmentValue() + "/" + typeFilter.getFullQualifiedName().getFullQualifiedNameAsString() :
+        getSegmentValue();
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8091658/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceValueImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceValueImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceValueImpl.java
index 73f86c4..d2b70d5 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceValueImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceValueImpl.java
@@ -25,17 +25,10 @@ public class UriResourceValueImpl extends UriResourceImpl implements UriResource
 
   public UriResourceValueImpl() {
     super(UriResourceKind.value);
-
   }
 
   @Override
-  public String getSegmentValue(){
+  public String getSegmentValue() {
     return "$value";
   }
-
-  @Override
-  public String toString() {
-    return getSegmentValue();
-  }
-
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8091658/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java
index 61c023d..2f7fdb2 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java
@@ -18,20 +18,41 @@
  */
 package org.apache.olingo.server.core.uri.parser;
 
+import java.util.ArrayDeque;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
+import java.util.Deque;
 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.EdmComplexType;
+import org.apache.olingo.commons.api.edm.EdmElement;
+import org.apache.olingo.commons.api.edm.EdmEntitySet;
+import org.apache.olingo.commons.api.edm.EdmEntityType;
+import org.apache.olingo.commons.api.edm.EdmEnumType;
+import org.apache.olingo.commons.api.edm.EdmFunction;
+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.EdmReturnType;
+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.UriParameter;
+import org.apache.olingo.server.api.uri.UriResourceFunction;
+import org.apache.olingo.server.api.uri.UriResourceLambdaVariable;
+import org.apache.olingo.server.api.uri.UriResourceNavigation;
+import org.apache.olingo.server.api.uri.UriResourcePartTyped;
 import org.apache.olingo.server.api.uri.queryoption.expression.Alias;
 import org.apache.olingo.server.api.uri.queryoption.expression.Binary;
 import org.apache.olingo.server.api.uri.queryoption.expression.BinaryOperatorKind;
@@ -45,12 +66,32 @@ import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind;
 import org.apache.olingo.server.api.uri.queryoption.expression.TypeLiteral;
 import org.apache.olingo.server.api.uri.queryoption.expression.Unary;
 import org.apache.olingo.server.api.uri.queryoption.expression.UnaryOperatorKind;
+import org.apache.olingo.server.core.uri.UriInfoImpl;
+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.UriResourceItImpl;
+import org.apache.olingo.server.core.uri.UriResourceLambdaAllImpl;
+import org.apache.olingo.server.core.uri.UriResourceLambdaAnyImpl;
+import org.apache.olingo.server.core.uri.UriResourceLambdaVarImpl;
+import org.apache.olingo.server.core.uri.UriResourceNavigationPropertyImpl;
+import org.apache.olingo.server.core.uri.UriResourcePrimitivePropertyImpl;
+import org.apache.olingo.server.core.uri.UriResourceRootImpl;
+import org.apache.olingo.server.core.uri.UriResourceSingletonImpl;
+import org.apache.olingo.server.core.uri.UriResourceStartingTypeFilterImpl;
+import org.apache.olingo.server.core.uri.UriResourceTypedImpl;
+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.queryoption.expression.AliasImpl;
 import org.apache.olingo.server.core.uri.queryoption.expression.BinaryImpl;
+import org.apache.olingo.server.core.uri.queryoption.expression.EnumerationImpl;
 import org.apache.olingo.server.core.uri.queryoption.expression.LiteralImpl;
+import org.apache.olingo.server.core.uri.queryoption.expression.MemberImpl;
 import org.apache.olingo.server.core.uri.queryoption.expression.MethodImpl;
+import org.apache.olingo.server.core.uri.queryoption.expression.TypeLiteralImpl;
 import org.apache.olingo.server.core.uri.queryoption.expression.UnaryImpl;
+import org.apache.olingo.server.core.uri.validator.UriValidationException;
 
 public class ExpressionParser {
   private static final Map<TokenKind, BinaryOperatorKind> tokenToBinaryOperator;
@@ -129,7 +170,7 @@ public class ExpressionParser {
     Map<TokenKind, EdmPrimitiveTypeKind> temp = new HashMap<TokenKind, EdmPrimitiveTypeKind>();
     temp.put(TokenKind.BooleanValue, EdmPrimitiveTypeKind.Boolean);
     temp.put(TokenKind.StringValue, EdmPrimitiveTypeKind.String);
-    // TODO:Check if int64 is correct here or if it has to be single instead
+    // TODO: Check if int64 is correct here or if it has to be decimal or single or double instead.
     temp.put(TokenKind.IntegerValue, EdmPrimitiveTypeKind.Int64);
     temp.put(TokenKind.GuidValue, EdmPrimitiveTypeKind.Guid);
     temp.put(TokenKind.DateValue, EdmPrimitiveTypeKind.Date);
@@ -147,20 +188,27 @@ public class ExpressionParser {
   private final OData odata;
 
   private UriTokenizer tokenizer;
+  private Deque<UriResourceLambdaVariable> lambdaVariables = new ArrayDeque<UriResourceLambdaVariable>();
+  private EdmType referringType;
+  private Collection<String> crossjoinEntitySetNames;
 
   public ExpressionParser(final Edm edm, final OData odata) {
     this.edm = edm;
     this.odata = odata;
   }
 
-  public Expression parse(UriTokenizer tokenizer) throws UriParserException {
+  public Expression parse(UriTokenizer tokenizer, final EdmType referringType,
+      final Collection<String> crossjoinEntitySetNames)
+      throws UriParserException, UriValidationException {
     // Initialize tokenizer.
     this.tokenizer = tokenizer;
+    this.referringType = referringType;
+    this.crossjoinEntitySetNames = crossjoinEntitySetNames;
 
     return parseExpression();
   }
 
-  private Expression parseExpression() throws UriParserException {
+  private Expression parseExpression() throws UriParserException, UriValidationException {
     Expression left = parseAnd();
     while (tokenizer.next(TokenKind.OrOperator)) {
       final Expression right = parseAnd();
@@ -172,7 +220,7 @@ public class ExpressionParser {
     return left;
   }
 
-  private Expression parseAnd() throws UriParserException {
+  private Expression parseAnd() throws UriParserException, UriValidationException {
     Expression left = parseExprEquality();
     while (tokenizer.next(TokenKind.AndOperator)) {
       final Expression right = parseExprEquality();
@@ -184,7 +232,7 @@ public class ExpressionParser {
     return left;
   }
 
-  private Expression parseExprEquality() throws UriParserException {
+  private Expression parseExprEquality() throws UriParserException, UriValidationException {
     Expression left = parseExprRel();
     TokenKind operatorTokenKind = ParserHelper.next(tokenizer, TokenKind.EqualsOperator, TokenKind.NotEqualsOperator);
     // Null for everything other than EQ or NE
@@ -199,7 +247,7 @@ public class ExpressionParser {
   }
 
   // TODO: The 'isof' method has relational precedence and should appear here.
-  private Expression parseExprRel() throws UriParserException {
+  private Expression parseExprRel() throws UriParserException, UriValidationException {
     Expression left = parseExprAdd();
     TokenKind operatorTokenKind = ParserHelper.next(tokenizer,
         TokenKind.GreaterThanOperator, TokenKind.GreaterThanOrEqualsOperator,
@@ -217,7 +265,7 @@ public class ExpressionParser {
     return left;
   }
 
-  private Expression parseExprAdd() throws UriParserException {
+  private Expression parseExprAdd() throws UriParserException, UriValidationException {
     Expression left = parseExprMul();
     TokenKind operatorTokenKind = ParserHelper.next(tokenizer, TokenKind.AddOperator, TokenKind.SubOperator);
     // Null for everything other than ADD or SUB
@@ -231,7 +279,7 @@ public class ExpressionParser {
     return left;
   }
 
-  private Expression parseExprMul() throws UriParserException {
+  private Expression parseExprMul() throws UriParserException, UriValidationException {
     Expression left = parseExprUnary();
     TokenKind operatorTokenKind = ParserHelper.next(tokenizer,
         TokenKind.MulOperator, TokenKind.DivOperator, TokenKind.ModOperator);
@@ -255,7 +303,22 @@ public class ExpressionParser {
   }
 
   // TODO: The 'cast' method has unary precedence and should appear here.
-  private Expression parseExprUnary() throws UriParserException {
+  private Expression parseExprUnary() throws UriParserException, UriValidationException {
+    // Negative numbers start with a minus indistinguishable from an unary minus operator.
+    // So we read numbers (and primitive values starting with numbers) right here.
+    // TODO: Find a better idea how to solve this problem.
+    final TokenKind numberTokenKind = ParserHelper.next(tokenizer,
+        TokenKind.DoubleValue, TokenKind.DecimalValue, TokenKind.GuidValue,
+        TokenKind.DateTimeOffsetValue, TokenKind.DateValue, TokenKind.TimeOfDayValue,
+        TokenKind.IntegerValue);
+    if (numberTokenKind != null) {
+      final EdmPrimitiveTypeKind primitiveTypeKind = tokenToPrimitiveType.get(numberTokenKind);
+      final EdmPrimitiveType type = primitiveTypeKind == null ?
+          // Null handling
+          null :
+          odata.createPrimitiveTypeInstance(primitiveTypeKind);
+      return new LiteralImpl(tokenizer.getText(), type);
+    }
     Expression left = null;
     TokenKind operatorTokenKind = ParserHelper.next(tokenizer, TokenKind.MINUS, TokenKind.NotOperator);
     // Null for everything other than - or NOT
@@ -279,13 +342,11 @@ public class ExpressionParser {
     return left;
   }
 
-  private Expression parseExprPrimary() throws UriParserException {
+  private Expression parseExprPrimary() throws UriParserException, UriValidationException {
     final Expression left = parseExprValue();
     if (isEnumType(left) && tokenizer.next(TokenKind.HasOperator)) {
       ParserHelper.requireNext(tokenizer, TokenKind.EnumValue);
-      final String primitiveValueLiteral = tokenizer.getText();
-      final Expression right = new LiteralImpl(primitiveValueLiteral, getEnumType(primitiveValueLiteral));
-      checkEnumLiteral(right);
+      final Expression right = createEnumExpression(tokenizer.getText());
       return new BinaryImpl(left, BinaryOperatorKind.HAS, right,
           odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Boolean));
     } else {
@@ -293,7 +354,7 @@ public class ExpressionParser {
     }
   }
 
-  private Expression parseExprValue() throws UriParserException {
+  private Expression parseExprValue() throws UriParserException, UriValidationException {
     if (tokenizer.next(TokenKind.OPEN)) {
       final Expression expression = parseExpression();
       ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
@@ -310,51 +371,49 @@ public class ExpressionParser {
     }
 
     if (tokenizer.next(TokenKind.ROOT)) {
-      // TODO: Consume $root expression.
+      return parseFirstMemberExpr(TokenKind.ROOT);
     }
 
     if (tokenizer.next(TokenKind.IT)) {
-      // TODO: Consume $it expression.
+      return parseFirstMemberExpr(TokenKind.IT);
     }
 
-    TokenKind nextPrimitive = ParserHelper.nextPrimitive(tokenizer);
+    final TokenKind nextPrimitive = ParserHelper.nextPrimitiveValue(tokenizer);
     if (nextPrimitive != null) {
       final String primitiveValueLiteral = tokenizer.getText();
-      final EdmPrimitiveTypeKind primitiveTypeKind = tokenToPrimitiveType.get(nextPrimitive);
-      EdmPrimitiveType type;
-      if (primitiveTypeKind == null) {
-        if (nextPrimitive == TokenKind.EnumValue) {
-          type = getEnumType(primitiveValueLiteral);
-        } else {
-          // Null handling
-          type = null;
-        }
+      if (nextPrimitive == TokenKind.EnumValue) {
+        return createEnumExpression(primitiveValueLiteral);
       } else {
-        type = odata.createPrimitiveTypeInstance(primitiveTypeKind);
+        final EdmPrimitiveTypeKind primitiveTypeKind = tokenToPrimitiveType.get(nextPrimitive);
+        final EdmPrimitiveType type = primitiveTypeKind == null ?
+            // Null handling
+            null :
+            odata.createPrimitiveTypeInstance(primitiveTypeKind);
+        return new LiteralImpl(primitiveValueLiteral, type);
       }
-      return new LiteralImpl(primitiveValueLiteral, type);
     }
 
     // The method token text includes the opening parenthesis so that method calls can be recognized unambiguously.
     // OData identifiers have to be considered after that.
-    TokenKind nextMethod = nextMethod();
+    final TokenKind nextMethod = nextMethod();
     if (nextMethod != null) {
       MethodKind methodKind = tokenToMethod.get(nextMethod);
       return new MethodImpl(methodKind, parseMethodParameters(methodKind));
     }
 
     if (tokenizer.next(TokenKind.QualifiedName)) {
-      // TODO: Consume typecast or bound-function expression.
+      return parseFirstMemberExpr(TokenKind.QualifiedName);
     }
 
     if (tokenizer.next(TokenKind.ODataIdentifier)) {
-      // TODO: Consume property-path or lambda-variable expression.
+      return parseFirstMemberExpr(TokenKind.ODataIdentifier);
     }
 
-    throw new UriParserSyntaxException("Unexpected token", UriParserSyntaxException.MessageKeys.SYNTAX);
+    throw new UriParserSyntaxException("Unexpected token.", UriParserSyntaxException.MessageKeys.SYNTAX);
   }
 
-  private List<Expression> parseMethodParameters(final MethodKind methodKind) throws UriParserException {
+  private List<Expression> parseMethodParameters(final MethodKind methodKind)
+      throws UriParserException, UriValidationException {
     List<Expression> parameters = new ArrayList<Expression>();
     switch (methodKind) {
     // Must have no parameter.
@@ -477,6 +536,411 @@ public class ExpressionParser {
     return parameters;
   }
 
+  private Expression parseFirstMemberExpr(final TokenKind lastTokenKind)
+      throws UriParserException, UriValidationException {
+
+    final UriInfoImpl uriInfo = new UriInfoImpl();
+    EdmType startTypeFilter = null;
+
+    if (lastTokenKind == TokenKind.ROOT) {
+      parseDollarRoot(uriInfo);
+    } else if (lastTokenKind == TokenKind.IT) {
+      parseDollarIt(uriInfo);
+    } else if (lastTokenKind == TokenKind.ODataIdentifier) {
+      parseFirstMemberODataIdentifier(uriInfo);
+    } else if (lastTokenKind == TokenKind.QualifiedName) {
+      // Special handling for leading type casts and type literals
+      final FullQualifiedName fullQualifiedName = new FullQualifiedName(tokenizer.getText());
+      EdmStructuredType structuredType = edm.getEntityType(fullQualifiedName);
+      if (structuredType == null) {
+        structuredType = edm.getComplexType(fullQualifiedName);
+      }
+
+      if (structuredType != null) {
+        if (tokenizer.next(TokenKind.SLASH)) {
+          // Leading type cast
+          checkStructuredTypeFilter(referringType, structuredType);
+          startTypeFilter = structuredType;
+
+          final TokenKind tokenKind = ParserHelper.next(tokenizer, TokenKind.QualifiedName, TokenKind.ODataIdentifier);
+          parseMemberExpression(tokenKind, uriInfo, new UriResourceStartingTypeFilterImpl(structuredType, false),
+              false);
+        } else {
+          // Type literal
+          checkStructuredTypeFilter(referringType, structuredType);
+          return new TypeLiteralImpl(structuredType);
+        }
+      } else {
+        // Must be bound or unbound function. // TODO: Is unbound function allowed?
+        parseFunction(fullQualifiedName, uriInfo, referringType, true);
+      }
+    }
+
+    return new MemberImpl(uriInfo, startTypeFilter);
+  }
+
+  private void parseDollarRoot(UriInfoImpl uriInfo) throws UriParserException, UriValidationException {
+    UriResourceRootImpl rootResource = new UriResourceRootImpl(referringType, true);
+    uriInfo.addResourcePart(rootResource);
+    ParserHelper.requireNext(tokenizer, TokenKind.SLASH);
+    ParserHelper.requireNext(tokenizer, TokenKind.ODataIdentifier);
+    final String name = tokenizer.getText();
+    UriResourcePartTyped resource = null;
+    final EdmEntitySet entitySet = edm.getEntityContainer().getEntitySet(name);
+    if (entitySet == null) {
+      final EdmSingleton singleton = edm.getEntityContainer().getSingleton(name);
+      if (singleton == null) {
+        throw new UriParserSemanticException("EntitySet or singleton expected.",
+            UriParserSemanticException.MessageKeys.UNKNOWN_PART, name);
+      } else {
+        resource = new UriResourceSingletonImpl(singleton);
+      }
+    } else {
+      ParserHelper.requireNext(tokenizer, TokenKind.OPEN);
+      final List<UriParameter> keyPredicates =
+          ParserHelper.parseKeyPredicate(tokenizer, entitySet.getEntityType(), null);
+      resource = new UriResourceEntitySetImpl(entitySet).setKeyPredicates(keyPredicates);
+    }
+    uriInfo.addResourcePart(resource);
+    parseSingleNavigationExpr(uriInfo, resource);
+  }
+
+  private void parseDollarIt(UriInfoImpl uriInfo) throws UriParserException, UriValidationException {
+    UriResourceItImpl itResource = new UriResourceItImpl(referringType,
+        referringType instanceof EdmEntityType); // TODO: Determine isCollection.
+    uriInfo.addResourcePart(itResource);
+    if (tokenizer.next(TokenKind.SLASH)) {
+      final TokenKind tokenKind = ParserHelper.next(tokenizer, TokenKind.QualifiedName, TokenKind.ODataIdentifier);
+      parseMemberExpression(tokenKind, uriInfo, itResource, true);
+    }
+  }
+
+  private void parseFirstMemberODataIdentifier(UriInfoImpl uriInfo) throws UriParserException, UriValidationException {
+    final String name = tokenizer.getText();
+
+    // For a crossjoin, the identifier must be an entity-set name.
+    if (crossjoinEntitySetNames != null && !crossjoinEntitySetNames.isEmpty()) {
+      if (crossjoinEntitySetNames.contains(name)) {
+        final UriResourceEntitySetImpl resource =
+            new UriResourceEntitySetImpl(edm.getEntityContainer().getEntitySet(name));
+        uriInfo.addResourcePart(resource);
+        if (tokenizer.next(TokenKind.SLASH)) {
+          final TokenKind tokenKind = ParserHelper.next(tokenizer, TokenKind.QualifiedName, TokenKind.ODataIdentifier);
+          parseMemberExpression(tokenKind, uriInfo, resource, true);
+        }
+        return;
+      } else {
+        throw new UriParserSemanticException("Unknown crossjoin entity set.",
+            UriParserSemanticException.MessageKeys.UNKNOWN_PART, name);
+      }
+    }
+
+    // Check if the OData identifier is a lambda variable, otherwise it must be a property.
+    UriResourceLambdaVariable lambdaVariable = null;
+    for (final UriResourceLambdaVariable variable : lambdaVariables) {
+      if (variable.getVariableName().equals(name)) {
+        lambdaVariable = variable;
+        break;
+      }
+    }
+    if (lambdaVariable != null) {
+      // Copy lambda variable into new resource, just in case ...
+      final UriResourceLambdaVariable lambdaResource =
+          new UriResourceLambdaVarImpl(lambdaVariable.getVariableName(), lambdaVariable.getType());
+      uriInfo.addResourcePart(lambdaResource);
+      if (tokenizer.next(TokenKind.SLASH)) {
+        final TokenKind tokenKind = ParserHelper.next(tokenizer, TokenKind.QualifiedName, TokenKind.ODataIdentifier);
+        parseMemberExpression(tokenKind, uriInfo, lambdaResource, true);
+      }
+    } else {
+      // Must be a property.
+      parseMemberExpression(TokenKind.ODataIdentifier, uriInfo, null, true); // TODO: Find last resource.
+    }
+  }
+
+  private void parseMemberExpression(final TokenKind lastTokenKind, UriInfoImpl uriInfo,
+      final UriResourcePartTyped lastResource, final boolean allowTypeFilter)
+          throws UriParserException, UriValidationException {
+
+    if (lastTokenKind == TokenKind.QualifiedName) {
+      // Type cast or bound function
+      final FullQualifiedName fullQualifiedName = new FullQualifiedName(tokenizer.getText());
+      final EdmEntityType edmEntityType = edm.getEntityType(fullQualifiedName);
+
+      if (edmEntityType != null) {
+        if (allowTypeFilter) {
+          setTypeFilter(lastResource, edmEntityType);
+        } else {
+          throw new UriParserSemanticException("Type filters are not chainable.",
+              UriParserSemanticException.MessageKeys.TYPE_FILTER_NOT_CHAINABLE,
+              lastResource.getType().getFullQualifiedName().getFullQualifiedNameAsString(),
+              fullQualifiedName.getFullQualifiedNameAsString());
+        }
+      } else {
+        parseBoundFunction(fullQualifiedName, uriInfo, lastResource);
+      }
+    } else if (lastTokenKind == TokenKind.ODataIdentifier) {
+      parsePropertyPathExpr(uriInfo, lastResource);
+    } else {
+      throw new UriParserSyntaxException("Unexpected token.", UriParserSyntaxException.MessageKeys.SYNTAX);
+    }
+  }
+
+  private void setTypeFilter(UriResourcePartTyped lastResource, final EdmEntityType entityTypeFilter)
+      throws UriParserException {
+    checkStructuredTypeFilter(lastResource.getType(), entityTypeFilter);
+    if (lastResource instanceof UriResourceTypedImpl) {
+      ((UriResourceTypedImpl) lastResource).setTypeFilter(entityTypeFilter);
+    } else if (lastResource instanceof UriResourceWithKeysImpl) {
+      ((UriResourceWithKeysImpl) lastResource).setEntryTypeFilter(entityTypeFilter);
+    }
+  }
+
+  private void parsePropertyPathExpr(UriInfoImpl uriInfo, final UriResourcePartTyped lastResource)
+      throws UriParserException, UriValidationException {
+
+    final String oDataIdentifier = tokenizer.getText();
+
+    final EdmType lastType = lastResource == null ? referringType : ParserHelper.getTypeInformation(lastResource);
+    if (!(lastType instanceof EdmStructuredType)) {
+      throw new UriParserSemanticException("Property paths must follow a structured type.",
+          UriParserSemanticException.MessageKeys.ONLY_FOR_STRUCTURAL_TYPES, oDataIdentifier);
+    }
+
+    final EdmStructuredType structuredType = (EdmStructuredType) lastType;
+    final EdmElement property = structuredType.getProperty(oDataIdentifier);
+
+    if (property == null) {
+      throw new UriParserSemanticException("Unknown property.",
+          UriParserSemanticException.MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE, oDataIdentifier);
+    }
+
+    if (property.getType() instanceof EdmComplexType) {
+      final UriResourceComplexPropertyImpl complexResource =
+          new UriResourceComplexPropertyImpl((EdmProperty) property);
+      uriInfo.addResourcePart(complexResource);
+
+      if (property.isCollection()) {
+        parseCollectionPathExpr(uriInfo, complexResource);
+      } else {
+        parseComplexPathExpr(uriInfo, complexResource);
+      }
+    } else if (property instanceof EdmNavigationProperty) {
+      // Nav. property; maybe a collection
+      final UriResourceNavigationPropertyImpl navigationResource =
+          new UriResourceNavigationPropertyImpl((EdmNavigationProperty) property);
+      navigationResource.setKeyPredicates(
+          ParserHelper.parseNavigationKeyPredicate(tokenizer, (EdmNavigationProperty) property));
+      uriInfo.addResourcePart(navigationResource);
+
+      if (navigationResource.isCollection()) {
+        parseCollectionNavigationExpr(uriInfo, navigationResource);
+      } else {
+        parseSingleNavigationExpr(uriInfo, navigationResource);
+      }
+    } else {
+      // Primitive type or Enum type
+      final UriResourcePrimitivePropertyImpl primitiveResource =
+          new UriResourcePrimitivePropertyImpl((EdmProperty) property);
+      uriInfo.addResourcePart(primitiveResource);
+
+      if (property.isCollection()) {
+        parseCollectionPathExpr(uriInfo, primitiveResource);
+      } else {
+        parseSinglePathExpr(uriInfo, primitiveResource);
+      }
+    }
+  }
+
+  private void parseSingleNavigationExpr(UriInfoImpl uriInfo, final UriResourcePartTyped lastResource)
+      throws UriParserException, UriValidationException {
+    // TODO: Is that correct?
+    if (tokenizer.next(TokenKind.SLASH)) {
+      final TokenKind tokenKind = ParserHelper.next(tokenizer, TokenKind.QualifiedName, TokenKind.ODataIdentifier);
+      parseMemberExpression(tokenKind, uriInfo, lastResource, true);
+    }
+  }
+
+  private void parseCollectionNavigationExpr(UriInfoImpl uriInfo, UriResourcePartTyped lastResource)
+      throws UriParserException, UriValidationException {
+    // TODO: Is type cast missing?
+    if (tokenizer.next(TokenKind.OPEN)) {
+      if (lastResource instanceof UriResourceNavigation) {
+        ((UriResourceNavigationPropertyImpl) lastResource).setKeyPredicates(
+              ParserHelper.parseNavigationKeyPredicate(tokenizer,
+                  ((UriResourceNavigationPropertyImpl) lastResource).getProperty()));
+      } else if (lastResource instanceof UriResourceFunction
+          && ((UriResourceFunction) lastResource).getType() instanceof EdmEntityType) {
+        ((UriResourceFunctionImpl) lastResource).setKeyPredicates(
+            ParserHelper.parseKeyPredicate(tokenizer,
+                (EdmEntityType) ((UriResourceFunction) lastResource).getType(),
+                null));
+      } else {
+        throw new UriParserSemanticException("Unknown or wrong resource type.",
+            UriParserSemanticException.MessageKeys.NOT_IMPLEMENTED, lastResource.toString());
+      }
+      parseSingleNavigationExpr(uriInfo, lastResource);
+    }
+    parseCollectionPathExpr(uriInfo, lastResource);
+  }
+
+  private void parseSinglePathExpr(UriInfoImpl uriInfo, final UriResourcePartTyped lastResource)
+      throws UriParserException, UriValidationException {
+    if (tokenizer.next(TokenKind.SLASH)) {
+      ParserHelper.requireNext(tokenizer, TokenKind.QualifiedName);
+      parseBoundFunction(new FullQualifiedName(tokenizer.getText()), uriInfo, lastResource);
+    }
+  }
+
+  private void parseComplexPathExpr(UriInfoImpl uriInfo, final UriResourcePartTyped lastResource)
+      throws UriParserException, UriValidationException {
+
+    if (tokenizer.next(TokenKind.SLASH)) {
+      if (tokenizer.next(TokenKind.QualifiedName)) {
+        final FullQualifiedName fullQualifiedName = new FullQualifiedName(tokenizer.getText());
+        final EdmEntityType edmEntityType = edm.getEntityType(fullQualifiedName);
+
+        if (edmEntityType != null) {
+          setTypeFilter(lastResource, edmEntityType);
+          if (tokenizer.next(TokenKind.SLASH)) {
+            parseComplexPathRestExpr(uriInfo, lastResource);
+          }
+        } else {
+          // Must be a bound function.
+          parseBoundFunction(fullQualifiedName, uriInfo, lastResource);
+        }
+      } else {
+        parseComplexPathRestExpr(uriInfo, lastResource);
+      }
+    }
+  }
+
+  private void parseComplexPathRestExpr(UriInfoImpl uriInfo, final UriResourcePartTyped lastResource)
+      throws UriParserException, UriValidationException {
+    if (tokenizer.next(TokenKind.QualifiedName)) {
+      final FullQualifiedName fullQualifiedName = new FullQualifiedName(tokenizer.getText());
+      // Must be a bound function.
+      parseBoundFunction(fullQualifiedName, uriInfo, lastResource);
+    } else if (tokenizer.next(TokenKind.ODataIdentifier)) {
+      parsePropertyPathExpr(uriInfo, lastResource);
+    } else {
+      throw new UriParserSyntaxException("Unexpected token.", UriParserSyntaxException.MessageKeys.SYNTAX);
+    }
+  }
+
+  private void parseCollectionPathExpr(UriInfoImpl uriInfo, final UriResourcePartTyped lastResource)
+      throws UriParserException, UriValidationException {
+
+    if (tokenizer.next(TokenKind.SLASH)) {
+      if (tokenizer.next(TokenKind.COUNT)) {
+        uriInfo.addResourcePart(new UriResourceCountImpl());
+      } else if (tokenizer.next(TokenKind.ANY)) {
+        uriInfo.addResourcePart(parseLambdaRest(TokenKind.ANY, lastResource));
+      } else if (tokenizer.next(TokenKind.ALL)) {
+        uriInfo.addResourcePart(parseLambdaRest(TokenKind.ALL, lastResource));
+      } else if (tokenizer.next(TokenKind.QualifiedName)) {
+        final FullQualifiedName fullQualifiedName = new FullQualifiedName(tokenizer.getText());
+        parseBoundFunction(fullQualifiedName, uriInfo, lastResource);
+      }
+    }
+  }
+
+  private void parseFunction(final FullQualifiedName fullQualifiedName, UriInfoImpl uriInfo,
+      final EdmType lastType, final boolean lastIsCollection) throws UriParserException, UriValidationException {
+
+    final List<UriParameter> parameters = ParserHelper.parseFunctionParameters(tokenizer, true);
+    final List<String> parameterNames = ParserHelper.getParameterNames(parameters);
+    final EdmFunction boundFunction = edm.getBoundFunction(fullQualifiedName,
+        lastType.getFullQualifiedName(), lastIsCollection, parameterNames);
+
+    if (boundFunction != null) {
+      parseFunctionRest(uriInfo, boundFunction, parameters);
+      return;
+    }
+
+    final EdmFunction unboundFunction = edm.getUnboundFunction(fullQualifiedName, parameterNames);
+    if (unboundFunction != null) {
+      parseFunctionRest(uriInfo, unboundFunction, parameters);
+      return;
+    }
+
+    throw new UriParserSemanticException("No function found.",
+        UriParserSemanticException.MessageKeys.FUNCTION_NOT_FOUND, fullQualifiedName.getFullQualifiedNameAsString());
+  }
+
+  private void parseBoundFunction(final FullQualifiedName fullQualifiedName, UriInfoImpl uriInfo,
+      final UriResourcePartTyped lastResource) throws UriParserException, UriValidationException {
+    final List<UriParameter> parameters = ParserHelper.parseFunctionParameters(tokenizer, true);
+    final List<String> parameterNames = ParserHelper.getParameterNames(parameters);
+    final EdmFunction boundFunction = edm.getBoundFunction(fullQualifiedName,
+        lastResource.getType().getFullQualifiedName(), lastResource.isCollection(), parameterNames);
+    if (boundFunction == null) {
+      throw new UriParserSemanticException("Bound function not found.",
+          UriParserSemanticException.MessageKeys.FUNCTION_NOT_FOUND, fullQualifiedName.getFullQualifiedNameAsString());
+    }
+    parseFunctionRest(uriInfo, boundFunction, parameters);
+  }
+
+  private void parseFunctionRest(UriInfoImpl uriInfo, final EdmFunction function,
+      final List<UriParameter> parameters) throws UriParserException, UriValidationException {
+    final UriResourceFunction functionResource = new UriResourceFunctionImpl(null, function, parameters);
+    uriInfo.addResourcePart(functionResource);
+
+    final EdmReturnType edmReturnType = function.getReturnType();
+    final EdmType edmType = edmReturnType.getType();
+    final boolean isCollection = edmReturnType.isCollection();
+
+    if (function.isComposable()) {
+      if (edmType instanceof EdmEntityType ) {
+        if (isCollection) {
+          parseCollectionNavigationExpr(uriInfo, null); // TODO: Get navigation property.
+        } else {
+          parseSingleNavigationExpr(uriInfo, null); // TODO: Get navigation property.
+        }
+      } else if (edmType instanceof EdmComplexType) {
+        if (isCollection) {
+          parseCollectionPathExpr(uriInfo, functionResource);
+        } else {
+          parseComplexPathExpr(uriInfo, functionResource);
+        }
+      } else if (edmType instanceof EdmPrimitiveType) {
+        if (isCollection) {
+          parseCollectionPathExpr(uriInfo, functionResource);
+        } else {
+          parseSinglePathExpr(uriInfo, functionResource);
+        }
+      }
+    } else if (tokenizer.next(TokenKind.SLASH)) {
+      throw new UriValidationException("Function is not composable.",
+          UriValidationException.MessageKeys.UNALLOWED_RESOURCE_PATH, "");
+    }
+  }
+
+  private UriResourcePartTyped parseLambdaRest(final TokenKind lastTokenKind, final UriResourcePartTyped lastResource)
+      throws UriParserException, UriValidationException {
+
+    ParserHelper.requireNext(tokenizer, TokenKind.OPEN);
+    if (lastTokenKind == TokenKind.ANY && tokenizer.next(TokenKind.CLOSE)) {
+      return new UriResourceLambdaAnyImpl(null, null);
+    }
+    ParserHelper.requireNext(tokenizer, TokenKind.ODataIdentifier);
+    final String lambbdaVariable = tokenizer.getText();
+    ParserHelper.requireNext(tokenizer, TokenKind.COLON);
+    lambdaVariables.addFirst(new UriResourceLambdaVarImpl(lambbdaVariable,
+        lastResource == null ? referringType : lastResource.getType()));
+    final Expression lambdaPredicateExpr = parseExpression();
+    lambdaVariables.removeFirst();
+    // TODO: The ABNF suggests that the "lambaPredicateExpr" must contain at least one lambdaVariable.
+    ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
+    if (lastTokenKind == TokenKind.ALL) {
+      return new UriResourceLambdaAllImpl(lambbdaVariable, lambdaPredicateExpr);
+    } else if (lastTokenKind == TokenKind.ANY) {
+      return new UriResourceLambdaAnyImpl(lambbdaVariable, lambdaPredicateExpr);
+    } else {
+      throw new UriParserSyntaxException("Unexpected token.", UriParserSyntaxException.MessageKeys.SYNTAX);
+    }
+  }
+
   private TokenKind nextMethod() {
     return ParserHelper.next(tokenizer,
         TokenKind.CeilingMethod,
@@ -580,9 +1044,9 @@ public class ExpressionParser {
     }
   }
 
-  private EdmPrimitiveType getEnumType(final String primitiveValueLiteral) throws UriParserException {
+  private EdmEnumType getEnumType(final String primitiveValueLiteral) throws UriParserException {
     final String enumTypeName = primitiveValueLiteral.substring(0, primitiveValueLiteral.indexOf('\''));
-    final EdmPrimitiveType type = edm.getEnumType(new FullQualifiedName(enumTypeName));
+    final EdmEnumType type = edm.getEnumType(new FullQualifiedName(enumTypeName));
     if (type == null) {
       throw new UriParserSemanticException("Unknown Enum type '" + enumTypeName + "'.",
           UriParserSemanticException.MessageKeys.UNKNOWN_TYPE, enumTypeName);
@@ -599,13 +1063,16 @@ public class ExpressionParser {
             EdmPrimitiveTypeKind.Byte, EdmPrimitiveTypeKind.SByte);
   }
 
-  private void checkEnumLiteral(final Expression expression) throws UriParserException {
-    if (expression == null
-        || !(expression instanceof Literal)
-        || ((Literal) expression).getType() == null
-        || ((Literal) expression).getType().getKind() != EdmTypeKind.ENUM) {
-      throw new UriParserSemanticException("Enum literal expected.",
-          UriParserSemanticException.MessageKeys.UNKNOWN_TYPE, ""); // TODO: better message
+  private Enumeration createEnumExpression(final String primitiveValueLiteral) throws UriParserException {
+    final EdmEnumType enumType = getEnumType(primitiveValueLiteral);
+    // TODO: Can the Enumeration interface be changed to handle the value as a whole?
+    try {
+      return new EnumerationImpl(enumType,
+          Arrays.asList(enumType.fromUriLiteral(primitiveValueLiteral).split(",")));
+    } catch (final EdmPrimitiveTypeException e) {
+      // TODO: Better error message.
+      throw new UriParserSemanticException("Wrong enumeration value.", e,
+          UriParserSemanticException.MessageKeys.UNKNOWN_PART, primitiveValueLiteral);
     }
   }
 
@@ -664,4 +1131,13 @@ public class ExpressionParser {
     throw new UriParserSemanticException("Incompatible types.",
         UriParserSemanticException.MessageKeys.UNKNOWN_TYPE, ""); // TODO: better message
   }
+
+  private void checkStructuredTypeFilter(final EdmType type, final EdmStructuredType filterType)
+      throws UriParserException {
+    if (!filterType.compatibleTo(type)) {
+      throw new UriParserSemanticException("Incompatible type filter.",
+          UriParserSemanticException.MessageKeys.INCOMPATIBLE_TYPE_FILTER,
+          filterType.getFullQualifiedName().getFullQualifiedNameAsString());
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8091658/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/FilterParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/FilterParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/FilterParser.java
new file mode 100644
index 0000000..a3376e0
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/FilterParser.java
@@ -0,0 +1,49 @@
+/*
+ * 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.Collection;
+
+import org.apache.olingo.commons.api.edm.Edm;
+import org.apache.olingo.commons.api.edm.EdmStructuredType;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.uri.queryoption.FilterOption;
+import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
+import org.apache.olingo.server.core.uri.queryoption.FilterOptionImpl;
+import org.apache.olingo.server.core.uri.validator.UriValidationException;
+
+public class FilterParser {
+
+  private final Edm edm;
+  private final OData odata;
+
+  public FilterParser(final Edm edm, final OData odata) {
+    this.edm = edm;
+    this.odata = odata;
+  }
+
+  public FilterOption parse(UriTokenizer tokenizer, final EdmStructuredType referencedType,
+      final Collection<String> crossjoinEntitySetNames)
+      throws UriParserException, UriValidationException {
+    final Expression filterExpression = new ExpressionParser(edm, odata)
+        .parse(tokenizer, referencedType, crossjoinEntitySetNames);
+    // TODO: Check that the expression is boolean.
+    return new FilterOptionImpl().setExpression(filterExpression);
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8091658/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/OrderByParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/OrderByParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/OrderByParser.java
new file mode 100644
index 0000000..5ea8cb7
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/OrderByParser.java
@@ -0,0 +1,61 @@
+/*
+ * 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.Collection;
+
+import org.apache.olingo.commons.api.edm.Edm;
+import org.apache.olingo.commons.api.edm.EdmStructuredType;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.uri.queryoption.OrderByOption;
+import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
+import org.apache.olingo.server.core.uri.parser.UriTokenizer.TokenKind;
+import org.apache.olingo.server.core.uri.queryoption.OrderByItemImpl;
+import org.apache.olingo.server.core.uri.queryoption.OrderByOptionImpl;
+import org.apache.olingo.server.core.uri.validator.UriValidationException;
+
+public class OrderByParser {
+
+  private final Edm edm;
+  private final OData odata;
+
+  public OrderByParser(final Edm edm, final OData odata) {
+    this.edm = edm;
+    this.odata = odata;
+  }
+
+  public OrderByOption parse(UriTokenizer tokenizer, final EdmStructuredType referencedType,
+      final Collection<String> crossjoinEntitySetNames)
+      throws UriParserException, UriValidationException {
+    OrderByOptionImpl orderByOption = new OrderByOptionImpl();
+    do {
+      final Expression orderByExpression = new ExpressionParser(edm, odata)
+          .parse(tokenizer, referencedType, crossjoinEntitySetNames);
+      OrderByItemImpl item = new OrderByItemImpl();
+      item.setExpression(orderByExpression);
+      if (tokenizer.next(TokenKind.AscSuffix)) {
+        item.setDescending(false);
+      } else if (tokenizer.next(TokenKind.DescSuffix)) {
+        item.setDescending(true);
+      }
+      orderByOption.addOrder(item);
+    } while (tokenizer.next(TokenKind.COMMA));
+    return orderByOption;
+  }
+}


[15/30] olingo-odata4 git commit: [OLINGO-834] ExpressionParser parses path expressions

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8091658/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java
index e9f1c07..ec9cc22 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java
@@ -82,13 +82,8 @@ public class TestFullResourcePath {
         .isKeyPredicate(0, "PropertyEnumString", "olingo.odata.test1.ENString'String1'")
         .isKeyPredicate(1, "PropertyDefString", "'abc'");
 
-    testUri
-        .run("ESMixEnumDefCollComp", "$filter=PropertyEnumString has Namespace1_Alias.ENString'String1'")
-        .goPath()
-        .at(0)
-        .isEntitySet("ESMixEnumDefCollComp")
-        .goUpUriValidator()
-        .goFilter().is("<<PropertyEnumString> has <olingo.odata.test1.ENString<String1>>>");
+    testFilter.runOnETMixEnumDefCollComp("PropertyEnumString has Namespace1_Alias.ENString'String1'")
+        .is("<<PropertyEnumString> has <olingo.odata.test1.ENString<String1>>>");
 
     testUri
         .run("ESMixEnumDefCollComp(PropertyEnumString=Namespace1_Alias.ENString'String1',PropertyDefString='abc')")
@@ -100,7 +95,7 @@ public class TestFullResourcePath {
   }
 
   @Test
-  public void testFunctionBound_varOverloading() throws Exception {
+  public void functionBound_varOverloading() throws Exception {
     // on ESTwoKeyNav
     testUri.run("ESTwoKeyNav/olingo.odata.test1.BFCESTwoKeyNavRTESTwoKeyNav()").goPath()
         .at(0)
@@ -941,7 +936,10 @@ public class TestFullResourcePath {
     testUri.run("$crossjoin(ESKeyNav,ESTwoKeyNav)")
         .isKind(UriInfoKind.crossjoin)
         .isCrossJoinEntityList(Arrays.asList("ESKeyNav", "ESTwoKeyNav"));
+  }
 
+  @Test
+  public void crossjoinFilter() throws Exception {
     testUri.run("$crossjoin(ESTwoPrim,ESMixPrimCollComp)",
         "$filter=ESTwoPrim/PropertyString eq ESMixPrimCollComp/PropertyComp/PropertyString")
         .goFilter()
@@ -950,7 +948,7 @@ public class TestFullResourcePath {
   }
 
   @Test
-  public void runCrossjoinError() throws Exception {
+  public void crossjoinError() throws Exception {
     testUri.runEx("$crossjoin").isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
     testUri.runEx("$crossjoin/error").isExSyntax(UriParserSyntaxException.MessageKeys.MUST_BE_LAST_SEGMENT);
     testUri.runEx("$crossjoin()").isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
@@ -1031,20 +1029,20 @@ public class TestFullResourcePath {
   }
 
   @Test
-  public void resourcePathWithApostrophe() {
+  public void resourcePathWithApostrophe() throws Exception {
     testUri.runEx("ESAllPrim'").isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
     testUri.runEx("ESAllPrim'InvalidStuff").isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
 
-    testUri.runEx("ESAllPrim", "$filter=PropertyInt16' eq 0")
-        .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
+    testFilter.runOnETKeyNavEx("PropertyInt16' eq 0")
+        .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION);
 
-    testUri.runEx("ESAllPrim", "$filter=PropertyInt16 eq' 0")
-        .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
+    testFilter.runOnETKeyNavEx("PropertyInt16 eq' 0")
+        .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION);
 
-    testUri.runEx("ESAllPrim", "$filter=PropertyInt16 eq 0'")
-        .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
+    testFilter.runOnETKeyNavEx("PropertyInt16 eq 0'")
+        .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION);
 
-    testUri.runEx("ESAllPrim", "$filter=PropertyInt16 eq 'dsd''")
+    testFilter.runOnETKeyNavEx("PropertyInt16 eq 'dsd''")
         .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
   }
 
@@ -1334,14 +1332,6 @@ public class TestFullResourcePath {
 
   @Test
   public void runEsNameKeyCast() throws Exception {
-    // testUri.runEx("ESTwoPrim(1)/olingo.odata.test1.ETBase(1)")
-    // .isExSemantic(MessageKeys.xxx);
-
-    // testUri.runEx("ESTwoPrim/olingo.odata.test1.ETBase(1)/olingo.odata.test1.ETTwoBase(1)")
-    // .isExSemantic(MessageKeys.xxx);
-
-    testUri.runEx("ESBase/olingo.odata.test1.ETTwoPrim(1)").isExSemantic(MessageKeys.INCOMPATIBLE_TYPE_FILTER);
-
     testUri.run("ESTwoPrim(1)/olingo.odata.test1.ETBase")
         .isKind(UriInfoKind.resource).goPath()
         .first()
@@ -1388,6 +1378,15 @@ public class TestFullResourcePath {
         .isEntitySet("ESTwoPrim")
         .isType(EntityTypeProvider.nameETTwoPrim)
         .isTypeFilterOnCollection(EntityTypeProvider.nameETTwoBase);
+
+    // TODO: Keys cannot be specified twice.
+    //testUri.runEx("ESTwoPrim(1)/olingo.odata.test1.ETBase(1)")
+    //    .isExSemantic(MessageKeys.INCOMPATIBLE_TYPE_FILTER);
+
+    //testUri.runEx("ESTwoPrim/olingo.odata.test1.ETBase(1)/olingo.odata.test1.ETTwoBase(1)")
+    //    .isExSemantic(MessageKeys.TYPE_FILTER_NOT_CHAINABLE);
+
+    testUri.runEx("ESBase/olingo.odata.test1.ETTwoPrim(1)").isExSemantic(MessageKeys.INCOMPATIBLE_TYPE_FILTER);
   }
 
   @Test
@@ -2620,9 +2619,7 @@ public class TestFullResourcePath {
         .goExpand().first()
         .isExpandStartType(EntityTypeProvider.nameETBaseTwoKeyNav)
         .goPath().first()
-        // .isType(EntityTypeProvider.nameETTwoKeyNav)
-        // .isTypeFilterOnEntry(EntityTypeProvider.nameETBaseTwoKeyNav)
-        // .n()
+        .isType(EntityTypeProvider.nameETKeyNav)
         .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true);
 
     testUri.run("ESTwoKeyNav(PropertyInt16=1,PropertyString='2')",
@@ -2633,9 +2630,7 @@ public class TestFullResourcePath {
         .goExpand().first()
         .isExpandStartType(EntityTypeProvider.nameETBaseTwoKeyNav)
         .goPath().first()
-        // .isType(EntityTypeProvider.nameETTwoKeyNav)
-        // .isTypeFilterOnEntry(EntityTypeProvider.nameETBaseTwoKeyNav)
-        // .n()
+        .isType(EntityTypeProvider.nameETTwoKeyNav)
         .isNavProperty("NavPropertyETTwoKeyNavMany", EntityTypeProvider.nameETTwoKeyNav, true);
 
     testUri.run("ESTwoKeyNav(PropertyInt16=1,PropertyString='2')",
@@ -2647,9 +2642,7 @@ public class TestFullResourcePath {
         .goExpand().first()
         .isExpandStartType(EntityTypeProvider.nameETBaseTwoKeyNav)
         .goPath().first()
-        // .isType(EntityTypeProvider.nameETTwoKeyNav)
-        // .isTypeFilterOnEntry(EntityTypeProvider.nameETBaseTwoKeyNav)
-        // .n()
+        .isType(EntityTypeProvider.nameETTwoKeyNav)
         .isNavProperty("NavPropertyETTwoKeyNavMany", EntityTypeProvider.nameETTwoKeyNav, true)
         .isTypeFilterOnCollection(EntityTypeProvider.nameETTwoBaseTwoKeyNav);
 
@@ -2658,11 +2651,7 @@ public class TestFullResourcePath {
         .goExpand().first()
         .isExpandStartType(EntityTypeProvider.nameETBaseTwoKeyNav)
         .goPath().first()
-        // .isType(EntityTypeProvider.nameETTwoKeyNav)
-        // .isTypeFilterOnCollection(EntityTypeProvider.nameETBaseTwoKeyNav)
-        // .n()
-        .isComplex("PropertyCompNav")
-        .isType(ComplexTypeProvider.nameCTBasePrimCompNav)
+        .isComplexProperty("PropertyCompNav", ComplexTypeProvider.nameCTBasePrimCompNav, false)
         .n()
         .isNavProperty("NavPropertyETTwoKeyNavOne", EntityTypeProvider.nameETTwoKeyNav, false);
 
@@ -2672,11 +2661,8 @@ public class TestFullResourcePath {
         .goExpand().first()
         .isExpandStartType(EntityTypeProvider.nameETBaseTwoKeyNav)
         .goPath().first()
-        // .isType(EntityTypeProvider.nameETTwoKeyNav)
-        // .isTypeFilterOnCollection(EntityTypeProvider.nameETBaseTwoKeyNav)
-        // .n()
-        .isComplex("PropertyCompNav")
-        .isType(ComplexTypeProvider.nameCTBasePrimCompNav)
+        .isComplexProperty("PropertyCompNav", ComplexTypeProvider.nameCTBasePrimCompNav, false)
+        .isTypeFilter(ComplexTypeProvider.nameCTTwoBasePrimCompNav)
         .n()
         .isNavProperty("NavPropertyETTwoKeyNavOne", EntityTypeProvider.nameETTwoKeyNav, false);
 
@@ -2704,10 +2690,7 @@ public class TestFullResourcePath {
         .goExpand().first()
         .isExpandStartType(EntityTypeProvider.nameETBaseTwoKeyNav)
         .goPath().first()
-        // .isUriPathInfoKind(UriResourceKind.startingTypeFilter)
-        // .isType(EntityTypeProvider.nameETTwoKeyNav)
-        // .isTypeFilterOnEntry(EntityTypeProvider.nameETBaseTwoKeyNav)
-        // .n().isNavProperty("NavPropertyETTwoKeyNavMany", EntityTypeProvider.nameETTwoKeyNav, true)
+        .isNavProperty("NavPropertyETTwoKeyNavMany", EntityTypeProvider.nameETTwoKeyNav, true)
         .isType(EntityTypeProvider.nameETTwoKeyNav)
         .isTypeFilterOnCollection(EntityTypeProvider.nameETTwoBaseTwoKeyNav)
         .goUpExpandValidator()
@@ -3246,7 +3229,9 @@ public class TestFullResourcePath {
 
   }
 
+  // TODO
   @Test
+  @Ignore
   public void filter() throws Exception {
 
     testFilter.runOnETTwoKeyNav("PropertyString")
@@ -3311,9 +3296,6 @@ public class TestFullResourcePath {
         .root().left()
         .isType(PropertyProvider.nameDate)
         .isMember().isMemberStartType(EntityTypeProvider.nameETBaseTwoKeyNav).goPath()
-        // .first().isUriPathInfoKind(UriResourceKind.startingTypeFilter)
-        // .isType(EntityTypeProvider.nameETTwoKeyNav).isTypeFilterOnCollection(EntityTypeProvider.nameETBaseTwoKeyNav)
-        // .n().isPrimitiveProperty("PropertyDate", PropertyProvider.nameDate, false)
         .first().isPrimitiveProperty("PropertyDate", PropertyProvider.nameDate, false)
         .goUpFilterValidator()
         .root().right()
@@ -3324,9 +3306,6 @@ public class TestFullResourcePath {
         .root().left()
         .isType(PropertyProvider.nameString)
         .isMember().isMemberStartType(ComplexTypeProvider.nameCTBase).goPath()
-        // .first().isUriPathInfoKind(UriResourceKind.startingTypeFilter)
-        // .isType(EntityTypeProvider.nameCTTwoPrim).isTypeFilterOnEntry(ComplexTypeProvider.nameCTBase)
-        // .n().isPrimitiveProperty("AdditionalPropString", PropertyProvider.nameString, false)
         .first().isPrimitiveProperty("AdditionalPropString", PropertyProvider.nameString, false)
         .goUpFilterValidator()
         .root().right()
@@ -3352,19 +3331,18 @@ public class TestFullResourcePath {
         .isExSemantic(MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
     // TODO: This should throw an exception because the top node of the filter tree must be boolean.
     // testFilter.runOnETTwoKeyNavEx("PropertyComp")
-    // .isExSemantic(MessageKeys.XYZ);
+    //     .isExSemantic(MessageKeys.UNKNOWN_TYPE);
     testFilter.runOnETTwoKeyNavEx("PropertyComp/invalid")
         .isExSemantic(MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
     testFilter.runOnETTwoKeyNavEx("concat('a','b')/invalid").isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
     testFilter.runOnETTwoKeyNavEx("PropertyComp/concat('a','b')")
         .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
-    // TODO: These should throw exceptions because the types are incompatible.
-    // testFilter.runOnETTwoKeyNavEx("PropertyComp/PropertyInt16 eq '1'")
-    // .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
-    // testFilter.runOnETTwoKeyNavEx("PropertyComp/PropertyComp/PropertyDate eq 1")
-    // .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
-    // testFilter.runOnETTwoKeyNavEx("PropertyComp/PropertyComp/PropertyString eq 1")
-    // .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
+    testFilter.runOnETTwoKeyNavEx("PropertyComp/PropertyInt16 eq '1'")
+        .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
+    testFilter.runOnETTwoKeyNavEx("PropertyComp/PropertyComp/PropertyDate eq 1")
+        .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
+    testFilter.runOnETTwoKeyNavEx("PropertyComp/PropertyComp/PropertyString eq 1")
+        .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
     testFilter.runOnETTwoKeyNavEx("PropertyComp/PropertyInt64 eq 1")
         .isExSemantic(MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
     testFilter.runOnETTwoKeyNavEx("NavPropertyETKeyNavMany/PropertyInt16 gt 42")
@@ -3788,8 +3766,155 @@ public class TestFullResourcePath {
         .right().isLiteral("INF").isType(PropertyProvider.nameDecimal);
   }
 
+  // TODO
   @Test
+  @Ignore
   public void filterProperties() throws Exception {
+    testFilter.runOnETAllPrim("PropertyBoolean eq true")
+        .is("<<PropertyBoolean> eq <true>>")
+        .isBinary(BinaryOperatorKind.EQ)
+        .root().left().goPath().isPrimitiveProperty("PropertyBoolean", PropertyProvider.nameBoolean, false)
+        .goUpFilterValidator()
+        .root().right().isTrue();
+
+    testFilter.runOnETAllPrim("PropertyDecimal eq 1.25")
+        .is("<<PropertyDecimal> eq <1.25>>")
+        .isBinary(BinaryOperatorKind.EQ)
+        .root().left().goPath().isPrimitiveProperty("PropertyDecimal", PropertyProvider.nameDecimal, false)
+        .goUpFilterValidator()
+        .root().right().isLiteral("1.25");
+
+    testFilter.runOnETAllPrim("PropertyDouble eq 1.5")
+        .is("<<PropertyDouble> eq <1.5>>")
+        .isBinary(BinaryOperatorKind.EQ)
+        .root().left().goPath().isPrimitiveProperty("PropertyDouble", PropertyProvider.nameDouble, false)
+        .goUpFilterValidator()
+        .root().right().isLiteral("1.5");
+
+    testFilter.runOnETAllPrim("PropertySingle eq 1.5")
+        .is("<<PropertySingle> eq <1.5>>")
+        .isBinary(BinaryOperatorKind.EQ)
+        .root().left().goPath().isPrimitiveProperty("PropertySingle", PropertyProvider.nameSingle, false)
+        .goUpFilterValidator()
+        .root().right().isLiteral("1.5");
+
+    testFilter.runOnETAllPrim("PropertySByte eq -128")
+        .is("<<PropertySByte> eq <-128>>")
+        .isBinary(BinaryOperatorKind.EQ)
+        .root().left().goPath().isPrimitiveProperty("PropertySByte", PropertyProvider.nameSByte, false)
+        .goUpFilterValidator()
+        .root().right().isLiteral("-128");
+
+    testFilter.runOnETAllPrim("PropertyByte eq 255")
+        .is("<<PropertyByte> eq <255>>")
+        .isBinary(BinaryOperatorKind.EQ)
+        .root().left().goPath().isPrimitiveProperty("PropertyByte",
+            PropertyProvider.nameByte, false).goUpFilterValidator()
+        .root().right().isLiteral("255");
+
+    testFilter.runOnETAllPrim("PropertyInt16 eq 32767")
+        .is("<<PropertyInt16> eq <32767>>")
+        .isBinary(BinaryOperatorKind.EQ)
+        .root().left().goPath().isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false)
+        .goUpFilterValidator()
+        .root().right().isLiteral("32767");
+
+    testFilter.runOnETAllPrim("PropertyInt32 eq 2147483647")
+        .is("<<PropertyInt32> eq <2147483647>>")
+        .isBinary(BinaryOperatorKind.EQ)
+        .root().left().goPath().isPrimitiveProperty("PropertyInt32", PropertyProvider.nameInt32, false)
+        .goUpFilterValidator()
+        .root().right().isLiteral("2147483647");
+
+    testFilter.runOnETAllPrim("PropertyInt64 eq 9223372036854775807")
+        .is("<<PropertyInt64> eq <9223372036854775807>>")
+        .isBinary(BinaryOperatorKind.EQ)
+        .root().left().goPath().isPrimitiveProperty("PropertyInt64", PropertyProvider.nameInt64, false)
+        .goUpFilterValidator()
+        .root().right().isLiteral("9223372036854775807");
+
+    testFilter.runOnETAllPrim("PropertyDate eq 2013-09-25")
+        .is("<<PropertyDate> eq <2013-09-25>>")
+        .isBinary(BinaryOperatorKind.EQ)
+        .root().left().goPath().isPrimitiveProperty("PropertyDate", PropertyProvider.nameDate, false)
+        .goUpFilterValidator()
+        .root().right().isLiteral("2013-09-25");
+
+    testFilter.runOnETAllPrim("PropertyDateTimeOffset eq 2013-09-25T12:34:56.123456789012-10:24")
+        .is("<<PropertyDateTimeOffset> eq <2013-09-25T12:34:56.123456789012-10:24>>")
+        .isBinary(BinaryOperatorKind.EQ)
+        .root().left().goPath()
+        .isPrimitiveProperty("PropertyDateTimeOffset", PropertyProvider.nameDateTimeOffset, false)
+        .goUpFilterValidator()
+        .root().right().isLiteral("2013-09-25T12:34:56.123456789012-10:24");
+
+    testFilter.runOnETAllPrim("PropertyDuration eq duration'P10DT5H34M21.123456789012S'")
+        .is("<<PropertyDuration> eq <duration'P10DT5H34M21.123456789012S'>>")
+        .isBinary(BinaryOperatorKind.EQ)
+        .root().left().goPath().isPrimitiveProperty("PropertyDuration", PropertyProvider.nameDuration, false)
+        .goUpFilterValidator()
+        .root().right().isLiteral("duration'P10DT5H34M21.123456789012S'");
+
+    testFilter.runOnETAllPrim("PropertyGuid eq 005056A5-09B1-1ED3-89BD-FB81372CCB33")
+        .is("<<PropertyGuid> eq <005056A5-09B1-1ED3-89BD-FB81372CCB33>>")
+        .isBinary(BinaryOperatorKind.EQ)
+        .root().left().goPath().isPrimitiveProperty("PropertyGuid", PropertyProvider.nameGuid, false)
+        .goUpFilterValidator()
+        .root().right().isLiteral("005056A5-09B1-1ED3-89BD-FB81372CCB33");
+
+    testFilter.runOnETAllPrim("PropertyString eq 'somestring'")
+        .is("<<PropertyString> eq <'somestring'>>")
+        .isBinary(BinaryOperatorKind.EQ)
+        .root().left().goPath().isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false)
+        .goUpFilterValidator()
+        .root().right().isLiteral("'somestring'");
+
+    testFilter.runOnETAllPrim("PropertyTimeOfDay eq 12:34:55.12345678901")
+        .is("<<PropertyTimeOfDay> eq <12:34:55.12345678901>>")
+        .isBinary(BinaryOperatorKind.EQ)
+        .root().left().goPath().isPrimitiveProperty("PropertyTimeOfDay", PropertyProvider.nameTimeOfDay, false)
+        .goUpFilterValidator()
+        .root().right().isLiteral("12:34:55.12345678901");
+
+    testFilter.runOnETMixEnumDefCollComp("PropertyEnumString eq olingo.odata.test1.ENString'String1'")
+        .is("<<PropertyEnumString> eq <olingo.odata.test1.ENString<String1>>>")
+        .isBinary(BinaryOperatorKind.EQ)
+        .root().left().goPath().isPrimitiveProperty("PropertyEnumString", EnumTypeProvider.nameENString, false)
+        .goUpFilterValidator()
+        .root().right().isEnum(EnumTypeProvider.nameENString, Arrays.asList("String1"));
+
+    testFilter.runOnETMixEnumDefCollComp("PropertyEnumString eq olingo.odata.test1.ENString'String2'")
+        .is("<<PropertyEnumString> eq <olingo.odata.test1.ENString<String2>>>")
+        .isBinary(BinaryOperatorKind.EQ)
+        .root().left().goPath().isPrimitiveProperty("PropertyEnumString", EnumTypeProvider.nameENString, false)
+        .goUpFilterValidator()
+        .root().right().isEnum(EnumTypeProvider.nameENString, Arrays.asList("String2"));
+
+    testFilter.runOnETMixEnumDefCollComp(
+        "PropertyCompMixedEnumDef/PropertyEnumString eq olingo.odata.test1.ENString'String3'")
+        .is("<<PropertyCompMixedEnumDef/PropertyEnumString> eq <olingo.odata.test1.ENString<String3>>>")
+        .isBinary(BinaryOperatorKind.EQ)
+        .root().left().goPath()
+        .first().isComplex("PropertyCompMixedEnumDef")
+        .n().isPrimitiveProperty("PropertyEnumString", EnumTypeProvider.nameENString, false)
+        .goUpFilterValidator()
+        .root().right().isEnum(EnumTypeProvider.nameENString, Arrays.asList("String3"));
+
+    testFilter
+        .runOnETMixEnumDefCollComp(
+            "PropertyCompMixedEnumDef/PropertyEnumString eq " +
+                "PropertyCompMixedEnumDef/PropertyEnumString")
+        .is("<<PropertyCompMixedEnumDef/PropertyEnumString> eq " +
+            "<PropertyCompMixedEnumDef/PropertyEnumString>>")
+        .isBinary(BinaryOperatorKind.EQ)
+        .root().left().goPath()
+        .first().isComplex("PropertyCompMixedEnumDef")
+        .n().isPrimitiveProperty("PropertyEnumString", EnumTypeProvider.nameENString, false)
+        .goUpFilterValidator()
+        .root().right().goPath()
+        .first().isComplex("PropertyCompMixedEnumDef")
+        .n().isPrimitiveProperty("PropertyEnumString", EnumTypeProvider.nameENString, false);
+
     testFilter.runOnETAllPrim("PropertyByte mod 0")
         .is("<<PropertyByte> mod <0>>");
 
@@ -3953,9 +4078,10 @@ public class TestFullResourcePath {
         .isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
   }
 
+  // TODO: $it on primitive types?
   @Test
-  public void filterPMethods() throws Exception {
-
+  @Ignore
+  public void methods() throws Exception {
     testFilter.runOnETKeyNav("indexof(PropertyString,'47') eq 5")
         .is("<<indexof(<PropertyString>,<'47'>)> eq <5>>")
         .root().left()
@@ -4024,16 +4150,6 @@ public class TestFullResourcePath {
         .isParameterText(0, "<PropertyString>")
         .isParameterText(1, "<'bar'>");
 
-    testFilter.runOnETKeyNav("concat(PropertyString, cast(PropertyCompAllPrim/PropertyInt16,Edm.String))")
-        .is("<concat(<PropertyString>,<cast(<PropertyCompAllPrim/PropertyInt16>,<Edm.String>)>)>")
-        .isMethod(MethodKind.CONCAT, 2)
-        .isParameterText(0, "<PropertyString>")
-        .isParameterText(1, "<cast(<PropertyCompAllPrim/PropertyInt16>,<Edm.String>)>")
-        .goParameter(1)
-        .isMethod(MethodKind.CAST, 2)
-        .isParameterText(0, "<PropertyCompAllPrim/PropertyInt16>")
-        .isParameterText(1, "<Edm.String>");
-
     testFilter.runOnETKeyNav("length(PropertyString) eq 32")
         .is("<<length(<PropertyString>)> eq <32>>")
         .root().left()
@@ -4416,59 +4532,167 @@ public class TestFullResourcePath {
         .isType(EntityTypeProvider.nameETTwoKeyNav, true)
         .n().isPrimitiveProperty("CollPropertyString", PropertyProvider.nameString, true);
 
-    testFilter.runOnETTwoKeyNav("PropertyComp/PropertyComp/PropertyInt16 eq $root"
-        + "/ESTwoKeyNav(PropertyInt16=1,PropertyString='2')/PropertyInt16")
-        .is("<<PropertyComp/PropertyComp/PropertyInt16> eq <$root/ESTwoKeyNav/PropertyInt16>>")
-        .root().left()
-        .goPath()
-        .first().isComplex("PropertyComp").isType(ComplexTypeProvider.nameCTPrimComp, false)
-        .n().isComplex("PropertyComp").isType(ComplexTypeProvider.nameCTAllPrim, false)
-        .n().isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false)
-        .goUpFilterValidator()
-        .root().right()
-        .goPath()
-        .first().isUriPathInfoKind(UriResourceKind.root)
-        .n().isEntitySet("ESTwoKeyNav")
-        .isKeyPredicate(0, "PropertyInt16", "1")
-        .isKeyPredicate(1, "PropertyString", "'2'")
-        .n().isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
-
-    testFilter.runOnETKeyNav("cast(olingo.odata.test1.ETBaseTwoKeyNav)")
-        .is("<cast(<olingo.odata.test1.ETBaseTwoKeyNav>)>")
-        .root()
-        .isMethod(MethodKind.CAST, 1)
-        .isParameterText(0, "<olingo.odata.test1.ETBaseTwoKeyNav>")
-        .goParameter(0)
-        .isTypedLiteral(EntityTypeProvider.nameETBaseTwoKeyNav);
+    testFilter.runOnETTwoKeyNav("endswith(PropertyComp/PropertyComp/PropertyString,'dorf')")
+        .is("<endswith(<PropertyComp/PropertyComp/PropertyString>,<'dorf'>)>")
+        .isMethod(MethodKind.ENDSWITH, 2)
+        .goParameter(0).goPath()
+        .first().isComplex("PropertyComp")
+        .n().isComplex("PropertyComp")
+        .n().isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false).goUpFilterValidator()
+        .root().goParameter(1).isLiteral("'dorf'");
 
-    testFilter.runOnETKeyNav("cast(PropertyCompTwoPrim,olingo.odata.test1.CTBase)")
-        .is("<cast(<PropertyCompTwoPrim>,<olingo.odata.test1.CTBase>)>")
-        .root()
-        .isMethod(MethodKind.CAST, 2)
-        .isParameterText(0, "<PropertyCompTwoPrim>")
-        .isParameterText(1, "<olingo.odata.test1.CTBase>")
-        .goParameter(0).goPath().first()
-        .isComplex("PropertyCompTwoPrim").isType(ComplexTypeProvider.nameCTTwoPrim, false)
-        .goUpFilterValidator()
-        .root()
-        .goParameter(1)
-        .isTypedLiteral(ComplexTypeProvider.nameCTBase);
+    testFilter.runOnETTwoKeyNav("endswith(PropertyComp/PropertyComp/PropertyString,'dorf') eq true")
+        .is("<<endswith(<PropertyComp/PropertyComp/PropertyString>,<'dorf'>)> eq <true>>")
+        .isBinary(BinaryOperatorKind.EQ)
+        .left().isMethod(MethodKind.ENDSWITH, 2)
+        .goParameter(0).goPath()
+        .first().isComplex("PropertyComp")
+        .n().isComplex("PropertyComp")
+        .n().isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false).goUpFilterValidator()
+        .root().left().goParameter(1).isLiteral("'dorf'");
 
-    testFilter.runOnETKeyNav("cast($it,olingo.odata.test1.CTBase)")
-        .is("<cast(<$it>,<olingo.odata.test1.CTBase>)>")
-        .root()
-        .isMethod(MethodKind.CAST, 2)
-        .isParameterText(0, "<$it>")
-        .isParameterText(1, "<olingo.odata.test1.CTBase>")
-        .goParameter(0).goPath().first()
-        .isIt().isType(EntityTypeProvider.nameETKeyNav, false)
-        .goUpFilterValidator()
-        .root()
-        .goParameter(1).isTypedLiteral(ComplexTypeProvider.nameCTBase);
+    testFilter.runOnETTwoKeyNav("endswith('Walldorf','dorf')")
+        .is("<endswith(<'Walldorf'>,<'dorf'>)>")
+        .isMethod(MethodKind.ENDSWITH, 2)
+        .goParameter(0).isLiteral("'Walldorf'")
+        .root().goParameter(1).isLiteral("'dorf'");
 
-    testFilter.runOnETKeyNav("cast($it,olingo.odata.test1.CTBase) eq cast($it,olingo.odata.test1.CTBase)"
-        )
-        .is("<<cast(<$it>,<olingo.odata.test1.CTBase>)> eq <cast(<$it>,<olingo.odata.test1.CTBase>)>>")
+    testFilter.runOnETTwoKeyNav("endswith('Walldorf','dorf') eq true")
+        .is("<<endswith(<'Walldorf'>,<'dorf'>)> eq <true>>")
+        .isBinary(BinaryOperatorKind.EQ)
+        .left().isMethod(MethodKind.ENDSWITH, 2)
+        .goParameter(0).isLiteral("'Walldorf'")
+        .root().left().goParameter(1).isLiteral("'dorf'");
+
+    testFilter.runOnETKeyNav("startswith(PropertyCompAllPrim/PropertyString,'Wall')")
+        .is("<startswith(<PropertyCompAllPrim/PropertyString>,<'Wall'>)>")
+        .isMethod(MethodKind.STARTSWITH, 2)
+        .goParameter(0).goPath()
+        .first().isComplex("PropertyCompAllPrim")
+        .n().isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false).goUpFilterValidator()
+        .root().goParameter(1).isLiteral("'Wall'");
+
+    testFilter.runOnETKeyNav("startswith(PropertyCompAllPrim/PropertyString,'Wall') eq true")
+        .is("<<startswith(<PropertyCompAllPrim/PropertyString>,<'Wall'>)> eq <true>>")
+        .isBinary(BinaryOperatorKind.EQ)
+        .left().isMethod(MethodKind.STARTSWITH, 2)
+        .goParameter(0).goPath()
+        .first().isComplex("PropertyCompAllPrim")
+        .n().isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false).goUpFilterValidator()
+        .root().left().goParameter(1).isLiteral("'Wall'");
+
+    testFilter.runOnETKeyNav("startswith('Walldorf','Wall')")
+        .is("<startswith(<'Walldorf'>,<'Wall'>)>")
+        .isMethod(MethodKind.STARTSWITH, 2)
+        .goParameter(0).isLiteral("'Walldorf'")
+        .root().goParameter(1).isLiteral("'Wall'");
+
+    testFilter.runOnETKeyNav("startswith('Walldorf','Wall') eq true")
+        .is("<<startswith(<'Walldorf'>,<'Wall'>)> eq <true>>")
+        .isBinary(BinaryOperatorKind.EQ)
+        .left().isMethod(MethodKind.STARTSWITH, 2)
+        .goParameter(0).isLiteral("'Walldorf'")
+        .root().left().goParameter(1).isLiteral("'Wall'");
+
+    testFilter.runOnETTwoKeyNav("contains(PropertyComp/PropertyComp/PropertyString,'Wall')")
+        .is("<contains(<PropertyComp/PropertyComp/PropertyString>,<'Wall'>)>")
+        .isMethod(MethodKind.CONTAINS, 2)
+        .goParameter(0).goPath()
+        .first().isComplex("PropertyComp")
+        .n().isComplex("PropertyComp")
+        .n().isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false).goUpFilterValidator()
+        .root().goParameter(1).isLiteral("'Wall'");
+
+    testFilter.runOnETTwoKeyNav("contains(PropertyComp/PropertyComp/PropertyString,'Wall') eq true")
+        .is("<<contains(<PropertyComp/PropertyComp/PropertyString>,<'Wall'>)> eq <true>>")
+        .isBinary(BinaryOperatorKind.EQ)
+        .left().isMethod(MethodKind.CONTAINS, 2)
+        .goParameter(0).goPath()
+        .first().isComplex("PropertyComp")
+        .n().isComplex("PropertyComp")
+        .n().isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false).goUpFilterValidator()
+        .root().left().goParameter(1).isLiteral("'Wall'");
+
+    testFilter.runOnETTwoKeyNav("contains('Walldorf','Wall')")
+        .is("<contains(<'Walldorf'>,<'Wall'>)>")
+        .isMethod(MethodKind.CONTAINS, 2)
+        .goParameter(0).isLiteral("'Walldorf'")
+        .root().goParameter(1).isLiteral("'Wall'");
+
+    testFilter.runOnETTwoKeyNav("contains('Walldorf','Wall') eq true")
+        .is("<<contains(<'Walldorf'>,<'Wall'>)> eq <true>>")
+        .isBinary(BinaryOperatorKind.EQ)
+        .left().isMethod(MethodKind.CONTAINS, 2)
+        .goParameter(0).isLiteral("'Walldorf'")
+        .root().left().goParameter(1).isLiteral("'Wall'");
+
+    testFilter.runOnETTwoKeyNav("PropertyComp/PropertyComp/PropertyInt16 eq "
+        + "$root/ESTwoKeyNav(PropertyInt16=1,PropertyString='2')/PropertyInt16")
+        .is("<<PropertyComp/PropertyComp/PropertyInt16> eq <$root/ESTwoKeyNav/PropertyInt16>>")
+        .root().left()
+        .goPath()
+        .first().isComplex("PropertyComp").isType(ComplexTypeProvider.nameCTPrimComp, false)
+        .n().isComplex("PropertyComp").isType(ComplexTypeProvider.nameCTAllPrim, false)
+        .n().isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false)
+        .goUpFilterValidator()
+        .root().right()
+        .goPath()
+        .first().isUriPathInfoKind(UriResourceKind.root)
+        .n().isEntitySet("ESTwoKeyNav")
+        .isKeyPredicate(0, "PropertyInt16", "1")
+        .isKeyPredicate(1, "PropertyString", "'2'")
+        .n().isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
+  }
+
+  // TODO: Implement cast method.
+  @Test
+  @Ignore
+  public void castMethod() throws Exception {
+    testFilter.runOnETKeyNav("cast(olingo.odata.test1.ETBaseTwoKeyNav)")
+        .is("<cast(<olingo.odata.test1.ETBaseTwoKeyNav>)>")
+        .root()
+        .isMethod(MethodKind.CAST, 1)
+        .isParameterText(0, "<olingo.odata.test1.ETBaseTwoKeyNav>")
+        .goParameter(0)
+        .isTypedLiteral(EntityTypeProvider.nameETBaseTwoKeyNav);
+
+    testFilter.runOnETKeyNav("cast(PropertyCompTwoPrim,olingo.odata.test1.CTBase)")
+        .is("<cast(<PropertyCompTwoPrim>,<olingo.odata.test1.CTBase>)>")
+        .root()
+        .isMethod(MethodKind.CAST, 2)
+        .isParameterText(0, "<PropertyCompTwoPrim>")
+        .isParameterText(1, "<olingo.odata.test1.CTBase>")
+        .goParameter(0).goPath().first()
+        .isComplex("PropertyCompTwoPrim").isType(ComplexTypeProvider.nameCTTwoPrim, false)
+        .goUpFilterValidator()
+        .root()
+        .goParameter(1)
+        .isTypedLiteral(ComplexTypeProvider.nameCTBase);
+
+    testFilter.runOnETKeyNav("cast($it,olingo.odata.test1.CTBase)")
+        .is("<cast(<$it>,<olingo.odata.test1.CTBase>)>")
+        .root()
+        .isMethod(MethodKind.CAST, 2)
+        .isParameterText(0, "<$it>")
+        .isParameterText(1, "<olingo.odata.test1.CTBase>")
+        .goParameter(0).goPath().first()
+        .isIt().isType(EntityTypeProvider.nameETKeyNav, false)
+        .goUpFilterValidator()
+        .root()
+        .goParameter(1).isTypedLiteral(ComplexTypeProvider.nameCTBase);
+
+    testFilter.runOnETKeyNav("concat(PropertyString,cast(PropertyCompAllPrim/PropertyInt16,Edm.String))")
+        .is("<concat(<PropertyString>,<cast(<PropertyCompAllPrim/PropertyInt16>,<Edm.String>)>)>")
+        .isMethod(MethodKind.CONCAT, 2)
+        .isParameterText(0, "<PropertyString>")
+        .isParameterText(1, "<cast(<PropertyCompAllPrim/PropertyInt16>,<Edm.String>)>")
+        .goParameter(1)
+        .isMethod(MethodKind.CAST, 2)
+        .isParameterText(0, "<PropertyCompAllPrim/PropertyInt16>")
+        .isParameterText(1, "<Edm.String>");
+
+    testFilter.runOnETKeyNav("cast($it,olingo.odata.test1.CTBase) eq cast($it,olingo.odata.test1.CTBase)")
+        .is("<<cast(<$it>,<olingo.odata.test1.CTBase>)> eq <cast(<$it>,<olingo.odata.test1.CTBase>)>>")
         .root().left()
         .isMethod(MethodKind.CAST, 2)
         .isParameterText(0, "<$it>")
@@ -4563,26 +4787,22 @@ public class TestFullResourcePath {
         .goUpFilterValidator().root()
         .goParameter(1).isTypedLiteral(EntityTypeProvider.nameETKeyPrimNav);
 
+    testFilter.runOnETAllPrim("olingo.odata.test1.UFCRTCTTwoPrimTwoParam(ParameterInt16=null,ParameterString=null)")
+        .goPath()
+        .isFunction("UFCRTCTTwoPrimTwoParam")
+        .isParameter(0, "ParameterInt16", null)
+        .isParameter(1, "ParameterString", null);
+
     testFilter.runOnETKeyNavEx("cast(NavPropertyETKeyPrimNavOne,olingo.odata.test1.ETKeyNav)")
         .isExSemantic(MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
     testFilter.runOnETKeyNav("any()")
         .isMember().goPath().first().isUriPathInfoKind(UriResourceKind.lambdaAny);
   }
 
+  // TODO: Check whether lambda expressions really are allowed on complex collections.
   @Test
+  @Ignore
   public void lambdaFunctions() throws Exception {
-
-    testFilter.runOnETKeyNav("any(d:d/PropertyInt16 eq 1)")
-        .is("<<ANY;<<d/PropertyInt16> eq <1>>>>")
-        .root().goPath()
-        .first().isUriPathInfoKind(UriResourceKind.lambdaAny)
-        .goLambdaExpression()
-        .isBinary(BinaryOperatorKind.EQ)
-        .left().goPath()
-        .first().isUriPathInfoKind(UriResourceKind.lambdaVariable)
-        .isType(EntityTypeProvider.nameETKeyNav, false)
-        .n().isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
-
     testFilter.runOnETKeyNav("NavPropertyETTwoKeyNavMany/any(d:d/PropertyString eq 'SomeString')")
         .is("<NavPropertyETTwoKeyNavMany/<ANY;<<d/PropertyString> eq <'SomeString'>>>>")
         .root().goPath()
@@ -4610,7 +4830,7 @@ public class TestFullResourcePath {
         .first().isUriPathInfoKind(UriResourceKind.lambdaVariable)
         .isType(PropertyProvider.nameString, false);
 
-    testFilter.runOnETKeyNav(" NavPropertyETTwoKeyNavOne/olingo.odata.test1.BFCETTwoKeyNavRTESTwoKeyNav()"
+    testFilter.runOnETKeyNav("NavPropertyETTwoKeyNavOne/olingo.odata.test1.BFCETTwoKeyNavRTESTwoKeyNav()"
         + "/any(d:d/PropertyComp/PropertyInt16 eq 6)")
         .is("<NavPropertyETTwoKeyNavOne/BFCETTwoKeyNavRTESTwoKeyNav/<ANY;<<d/PropertyComp/PropertyInt16> eq <6>>>>")
         .root().goPath()
@@ -4625,8 +4845,8 @@ public class TestFullResourcePath {
         .n().isComplex("PropertyComp")
         .n().isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
 
-    testFilter.runOnETKeyNav("NavPropertyETTwoKeyNavMany/any(d:d/PropertyInt16 eq 1 or d/any"
-        + "(e:e/CollPropertyString eq 'SomeString'))")
+    testFilter.runOnETKeyNav("NavPropertyETTwoKeyNavMany/any(d:d/PropertyInt16 eq 1 or "
+        + "d/any(e:e/CollPropertyString eq 'SomeString'))")
         .is("<NavPropertyETTwoKeyNavMany/<ANY;<<<d/PropertyInt16> eq <1>> or "
             + "<d/<ANY;<<e/CollPropertyString> eq <'SomeString'>>>>>>>")
         .root().goPath()
@@ -4653,8 +4873,8 @@ public class TestFullResourcePath {
         .isType(EntityTypeProvider.nameETTwoKeyNav, false)
         .n().isPrimitiveProperty("CollPropertyString", PropertyProvider.nameString, true);
 
-    testFilter.runOnETKeyNav("NavPropertyETTwoKeyNavMany/any(d:d/PropertyInt16 eq 1 or d/CollPropertyString/any"
-        + "(e:e eq 'SomeString'))")
+    testFilter.runOnETKeyNav("NavPropertyETTwoKeyNavMany/any(d:d/PropertyInt16 eq 1 or "
+        + "d/CollPropertyString/any(e:e eq 'SomeString'))")
         .is("<NavPropertyETTwoKeyNavMany/<ANY;<<<d/PropertyInt16> eq <1>> or "
             + "<d/CollPropertyString/<ANY;<<e> eq <'SomeString'>>>>>>>")
         .root().goPath()
@@ -4681,9 +4901,8 @@ public class TestFullResourcePath {
         .first().isUriPathInfoKind(UriResourceKind.lambdaVariable)
         .isType(PropertyProvider.nameString, false);
 
-    testFilter
-        .runOnETKeyNav("NavPropertyETTwoKeyNavMany/any(d:d/PropertyString eq 'SomeString' and d/CollPropertyString/any"
-            + "(e:e eq d/PropertyString))")
+    testFilter.runOnETKeyNav("NavPropertyETTwoKeyNavMany/any(d:d/PropertyString eq 'SomeString' and "
+            + "d/CollPropertyString/any(e:e eq d/PropertyString))")
         .is("<NavPropertyETTwoKeyNavMany/<ANY;<<<d/PropertyString> eq <'SomeString'>> and "
             + "<d/CollPropertyString/<ANY;<<e> eq <d/PropertyString>>>>>>>")
         .root().goPath()
@@ -4714,11 +4933,14 @@ public class TestFullResourcePath {
         .first().isUriPathInfoKind(UriResourceKind.lambdaVariable)
         .n().isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
 
+    testFilter.runOnETKeyNavEx("any(d:d/PropertyInt16 eq 1)")
+        .isExSemantic(MessageKeys.PROPERTY_NOT_IN_TYPE);
   }
 
+  // TODO: Implement isof method.
   @Test
-  public void runIsOf() throws Exception {
-
+  @Ignore
+  public void isOfMethod() throws Exception {
     testFilter.runOnETKeyNav("isof(olingo.odata.test1.ETTwoKeyNav)")
         .is("<isof(<olingo.odata.test1.ETTwoKeyNav>)>")
         .root()
@@ -4903,271 +5125,16 @@ public class TestFullResourcePath {
         .goUpFilterValidator()
         .root().right().isEnum(EnumTypeProvider.nameENString, Arrays.asList("String3"));
 
-    testFilter.runOnETMixEnumDefCollComp("PropertyEnumString has olingo.odata.test1.ENString'String,String3'")
-        .is("<<PropertyEnumString> has <olingo.odata.test1.ENString<String,String3>>>")
-        .isBinary(BinaryOperatorKind.HAS)
-        .root().left().goPath()
-        .first().isPrimitiveProperty("PropertyEnumString", EnumTypeProvider.nameENString, false)
-        .goUpFilterValidator()
-        .root().right().isEnum(EnumTypeProvider.nameENString, Arrays.asList("String", "String3"));
-
-    testFilter.runOnETMixEnumDefCollComp("PropertyEnumString has null")
-        .is("<<PropertyEnumString> has <null>>")
-        .root()
+    testFilter.runOnETMixEnumDefCollComp("PropertyEnumString has olingo.odata.test1.ENString'String1,String3'")
+        .is("<<PropertyEnumString> has <olingo.odata.test1.ENString<String1,String3>>>")
         .isBinary(BinaryOperatorKind.HAS)
         .root().left().goPath()
         .first().isPrimitiveProperty("PropertyEnumString", EnumTypeProvider.nameENString, false)
         .goUpFilterValidator()
-        .root().right().isNull();
-
-    testFilter.runOnETTwoKeyNav("endswith(PropertyComp/PropertyComp/PropertyString,'dorf')")
-        .is("<endswith(<PropertyComp/PropertyComp/PropertyString>,<'dorf'>)>")
-        .isMethod(MethodKind.ENDSWITH, 2)
-        .goParameter(0).goPath()
-        .first().isComplex("PropertyComp")
-        .n().isComplex("PropertyComp")
-        .n().isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false).goUpFilterValidator()
-        .root().goParameter(1).isLiteral("'dorf'");
-
-    testFilter.runOnETTwoKeyNav("endswith(PropertyComp/PropertyComp/PropertyString,'dorf') eq true")
-        .is("<<endswith(<PropertyComp/PropertyComp/PropertyString>,<'dorf'>)> eq <true>>")
-        .isBinary(BinaryOperatorKind.EQ)
-        .left().isMethod(MethodKind.ENDSWITH, 2)
-        .goParameter(0).goPath()
-        .first().isComplex("PropertyComp")
-        .n().isComplex("PropertyComp")
-        .n().isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false).goUpFilterValidator()
-        .root().left().goParameter(1).isLiteral("'dorf'");
-
-    testFilter.runOnETTwoKeyNav("endswith('Walldorf','dorf')")
-        .is("<endswith(<'Walldorf'>,<'dorf'>)>")
-        .isMethod(MethodKind.ENDSWITH, 2)
-        .goParameter(0).isLiteral("'Walldorf'")
-        .root().goParameter(1).isLiteral("'dorf'");
-
-    testFilter.runOnETTwoKeyNav("endswith('Walldorf','dorf') eq true")
-        .is("<<endswith(<'Walldorf'>,<'dorf'>)> eq <true>>")
-        .isBinary(BinaryOperatorKind.EQ)
-        .left().isMethod(MethodKind.ENDSWITH, 2)
-        .goParameter(0).isLiteral("'Walldorf'")
-        .root().left().goParameter(1).isLiteral("'dorf'");
-
-    testFilter.runOnETKeyNav("startswith(PropertyCompAllPrim/PropertyString,'Wall')")
-        .is("<startswith(<PropertyCompAllPrim/PropertyString>,<'Wall'>)>")
-        .isMethod(MethodKind.STARTSWITH, 2)
-        .goParameter(0).goPath()
-        .first().isComplex("PropertyCompAllPrim")
-        .n().isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false).goUpFilterValidator()
-        .root().goParameter(1).isLiteral("'Wall'");
-
-    testFilter.runOnETKeyNav("startswith(PropertyCompAllPrim/PropertyString,'Wall') eq true")
-        .is("<<startswith(<PropertyCompAllPrim/PropertyString>,<'Wall'>)> eq <true>>")
-        .isBinary(BinaryOperatorKind.EQ)
-        .left().isMethod(MethodKind.STARTSWITH, 2)
-        .goParameter(0).goPath()
-        .first().isComplex("PropertyCompAllPrim")
-        .n().isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false).goUpFilterValidator()
-        .root().left().goParameter(1).isLiteral("'Wall'");
-
-    testFilter.runOnETKeyNav("startswith('Walldorf','Wall')")
-        .is("<startswith(<'Walldorf'>,<'Wall'>)>")
-        .isMethod(MethodKind.STARTSWITH, 2)
-        .goParameter(0).isLiteral("'Walldorf'")
-        .root().goParameter(1).isLiteral("'Wall'");
-
-    testFilter.runOnETKeyNav("startswith('Walldorf','Wall') eq true")
-        .is("<<startswith(<'Walldorf'>,<'Wall'>)> eq <true>>")
-        .isBinary(BinaryOperatorKind.EQ)
-        .left().isMethod(MethodKind.STARTSWITH, 2)
-        .goParameter(0).isLiteral("'Walldorf'")
-        .root().left().goParameter(1).isLiteral("'Wall'");
-
-    testFilter.runOnETTwoKeyNav("contains(PropertyComp/PropertyComp/PropertyString,'Wall')")
-        .is("<contains(<PropertyComp/PropertyComp/PropertyString>,<'Wall'>)>")
-        .isMethod(MethodKind.CONTAINS, 2)
-        .goParameter(0).goPath()
-        .first().isComplex("PropertyComp")
-        .n().isComplex("PropertyComp")
-        .n().isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false).goUpFilterValidator()
-        .root().goParameter(1).isLiteral("'Wall'");
-
-    testFilter.runOnETTwoKeyNav("contains(PropertyComp/PropertyComp/PropertyString,'Wall') eq true")
-        .is("<<contains(<PropertyComp/PropertyComp/PropertyString>,<'Wall'>)> eq <true>>")
-        .isBinary(BinaryOperatorKind.EQ)
-        .left().isMethod(MethodKind.CONTAINS, 2)
-        .goParameter(0).goPath()
-        .first().isComplex("PropertyComp")
-        .n().isComplex("PropertyComp")
-        .n().isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false).goUpFilterValidator()
-        .root().left().goParameter(1).isLiteral("'Wall'");
-
-    testFilter.runOnETTwoKeyNav("contains('Walldorf','Wall')")
-        .is("<contains(<'Walldorf'>,<'Wall'>)>")
-        .isMethod(MethodKind.CONTAINS, 2)
-        .goParameter(0).isLiteral("'Walldorf'")
-        .root().goParameter(1).isLiteral("'Wall'");
-
-    testFilter.runOnETTwoKeyNav("contains('Walldorf','Wall') eq true")
-        .is("<<contains(<'Walldorf'>,<'Wall'>)> eq <true>>")
-        .isBinary(BinaryOperatorKind.EQ)
-        .left().isMethod(MethodKind.CONTAINS, 2)
-        .goParameter(0).isLiteral("'Walldorf'")
-        .root().left().goParameter(1).isLiteral("'Wall'");
-
-    testFilter.runOnETAllPrim("olingo.odata.test1.UFCRTCTTwoPrimTwoParam(ParameterInt16=null,ParameterString=null)")
-        .goPath()
-        .isFunction("UFCRTCTTwoPrimTwoParam")
-        .isParameter(0, "ParameterInt16", null)
-        .isParameter(1, "ParameterString", null);
-
-    testFilter.runOnETAllPrim("PropertyBoolean eq true")
-        .is("<<PropertyBoolean> eq <true>>")
-        .isBinary(BinaryOperatorKind.EQ)
-        .root().left().goPath().isPrimitiveProperty("PropertyBoolean", PropertyProvider.nameBoolean, false)
-        .goUpFilterValidator()
-        .root().right().isTrue();
-
-    testFilter.runOnETAllPrim("PropertyBoolean eq 2")
-        .is("<<PropertyBoolean> eq <2>>");
-
-    testFilter.runOnETAllPrim("PropertyDecimal eq 1.25")
-        .is("<<PropertyDecimal> eq <1.25>>")
-        .isBinary(BinaryOperatorKind.EQ)
-        .root().left().goPath().isPrimitiveProperty("PropertyDecimal", PropertyProvider.nameDecimal, false)
-        .goUpFilterValidator()
-        .root().right().isLiteral("1.25");
-
-    testFilter.runOnETAllPrim("PropertyDouble eq 1.5")
-        .is("<<PropertyDouble> eq <1.5>>")
-        .isBinary(BinaryOperatorKind.EQ)
-        .root().left().goPath().isPrimitiveProperty("PropertyDouble", PropertyProvider.nameDouble, false)
-        .goUpFilterValidator()
-        .root().right().isLiteral("1.5");
-
-    testFilter.runOnETAllPrim("PropertySingle eq 1.5")
-        .is("<<PropertySingle> eq <1.5>>")
-        .isBinary(BinaryOperatorKind.EQ)
-        .root().left().goPath().isPrimitiveProperty("PropertySingle", PropertyProvider.nameSingle, false)
-        .goUpFilterValidator()
-        .root().right().isLiteral("1.5");
-
-    testFilter.runOnETAllPrim("PropertySByte eq -128")
-        .is("<<PropertySByte> eq <-128>>")
-        .isBinary(BinaryOperatorKind.EQ)
-        .root().left().goPath().isPrimitiveProperty("PropertySByte", PropertyProvider.nameSByte, false)
-        .goUpFilterValidator()
-        .root().right().isLiteral("-128");
-
-    testFilter.runOnETAllPrim("PropertyByte eq 255")
-        .is("<<PropertyByte> eq <255>>")
-        .isBinary(BinaryOperatorKind.EQ)
-        .root().left().goPath().isPrimitiveProperty("PropertyByte",
-            PropertyProvider.nameByte, false).goUpFilterValidator()
-        .root().right().isLiteral("255");
-
-    testFilter.runOnETAllPrim("PropertyInt16 eq 32767")
-        .is("<<PropertyInt16> eq <32767>>")
-        .isBinary(BinaryOperatorKind.EQ)
-        .root().left().goPath().isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false)
-        .goUpFilterValidator()
-        .root().right().isLiteral("32767");
-
-    testFilter.runOnETAllPrim("PropertyInt32 eq 2147483647")
-        .is("<<PropertyInt32> eq <2147483647>>")
-        .isBinary(BinaryOperatorKind.EQ)
-        .root().left().goPath().isPrimitiveProperty("PropertyInt32", PropertyProvider.nameInt32, false)
-        .goUpFilterValidator()
-        .root().right().isLiteral("2147483647");
-
-    testFilter.runOnETAllPrim("PropertyInt64 eq 9223372036854775807")
-        .is("<<PropertyInt64> eq <9223372036854775807>>")
-        .isBinary(BinaryOperatorKind.EQ)
-        .root().left().goPath().isPrimitiveProperty("PropertyInt64", PropertyProvider.nameInt64, false)
-        .goUpFilterValidator()
-        .root().right().isLiteral("9223372036854775807");
-
-    testFilter.runOnETAllPrim("PropertyDate eq 2013-09-25")
-        .is("<<PropertyDate> eq <2013-09-25>>")
-        .isBinary(BinaryOperatorKind.EQ)
-        .root().left().goPath().isPrimitiveProperty("PropertyDate", PropertyProvider.nameDate, false)
-        .goUpFilterValidator()
-        .root().right().isLiteral("2013-09-25");
-
-    testFilter.runOnETAllPrim("PropertyDateTimeOffset eq 2013-09-25T12:34:56.123456789012-10:24")
-        .is("<<PropertyDateTimeOffset> eq <2013-09-25T12:34:56.123456789012-10:24>>")
-        .isBinary(BinaryOperatorKind.EQ)
-        .root().left().goPath()
-        .isPrimitiveProperty("PropertyDateTimeOffset", PropertyProvider.nameDateTimeOffset, false)
-        .goUpFilterValidator()
-        .root().right().isLiteral("2013-09-25T12:34:56.123456789012-10:24");
-
-    testFilter.runOnETAllPrim("PropertyDuration eq duration'P10DT5H34M21.123456789012S'")
-        .is("<<PropertyDuration> eq <duration'P10DT5H34M21.123456789012S'>>")
-        .isBinary(BinaryOperatorKind.EQ)
-        .root().left().goPath().isPrimitiveProperty("PropertyDuration", PropertyProvider.nameDuration, false)
-        .goUpFilterValidator()
-        .root().right().isLiteral("duration'P10DT5H34M21.123456789012S'");
-
-    testFilter.runOnETAllPrim("PropertyGuid eq 005056A5-09B1-1ED3-89BD-FB81372CCB33")
-        .is("<<PropertyGuid> eq <005056A5-09B1-1ED3-89BD-FB81372CCB33>>")
-        .isBinary(BinaryOperatorKind.EQ)
-        .root().left().goPath().isPrimitiveProperty("PropertyGuid", PropertyProvider.nameGuid, false)
-        .goUpFilterValidator()
-        .root().right().isLiteral("005056A5-09B1-1ED3-89BD-FB81372CCB33");
-
-    testFilter.runOnETAllPrim("PropertyString eq 'somestring'")
-        .is("<<PropertyString> eq <'somestring'>>")
-        .isBinary(BinaryOperatorKind.EQ)
-        .root().left().goPath().isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false)
-        .goUpFilterValidator()
-        .root().right().isLiteral("'somestring'");
-
-    testFilter.runOnETAllPrim("PropertyTimeOfDay eq 12:34:55.12345678901")
-        .is("<<PropertyTimeOfDay> eq <12:34:55.12345678901>>")
-        .isBinary(BinaryOperatorKind.EQ)
-        .root().left().goPath().isPrimitiveProperty("PropertyTimeOfDay", PropertyProvider.nameTimeOfDay, false)
-        .goUpFilterValidator()
-        .root().right().isLiteral("12:34:55.12345678901");
-
-    testFilter.runOnETMixEnumDefCollComp("PropertyEnumString eq olingo.odata.test1.ENString'String1'")
-        .is("<<PropertyEnumString> eq <olingo.odata.test1.ENString<String1>>>")
-        .isBinary(BinaryOperatorKind.EQ)
-        .root().left().goPath().isPrimitiveProperty("PropertyEnumString", EnumTypeProvider.nameENString, false)
-        .goUpFilterValidator()
-        .root().right().isEnum(EnumTypeProvider.nameENString, Arrays.asList("String1"));
-
-    testFilter.runOnETMixEnumDefCollComp("PropertyEnumString eq olingo.odata.test1.ENString'String2'")
-        .is("<<PropertyEnumString> eq <olingo.odata.test1.ENString<String2>>>")
-        .isBinary(BinaryOperatorKind.EQ)
-        .root().left().goPath().isPrimitiveProperty("PropertyEnumString", EnumTypeProvider.nameENString, false)
-        .goUpFilterValidator()
-        .root().right().isEnum(EnumTypeProvider.nameENString, Arrays.asList("String2"));
-
-    testFilter.runOnETMixEnumDefCollComp(
-        "PropertyCompMixedEnumDef/PropertyEnumString eq olingo.odata.test1.ENString'String3'")
-        .is("<<PropertyCompMixedEnumDef/PropertyEnumString> eq <olingo.odata.test1.ENString<String3>>>")
-        .isBinary(BinaryOperatorKind.EQ)
-        .root().left().goPath()
-        .first().isComplex("PropertyCompMixedEnumDef")
-        .n().isPrimitiveProperty("PropertyEnumString", EnumTypeProvider.nameENString, false)
-        .goUpFilterValidator()
-        .root().right().isEnum(EnumTypeProvider.nameENString, Arrays.asList("String3"));
-
-    testFilter
-        .runOnETMixEnumDefCollComp(
-            "PropertyCompMixedEnumDef/PropertyEnumString eq " +
-                "PropertyCompMixedEnumDef/PropertyEnumString")
-        .is("<<PropertyCompMixedEnumDef/PropertyEnumString> eq " +
-            "<PropertyCompMixedEnumDef/PropertyEnumString>>")
-        .isBinary(BinaryOperatorKind.EQ)
-        .root().left().goPath()
-        .first().isComplex("PropertyCompMixedEnumDef")
-        .n().isPrimitiveProperty("PropertyEnumString", EnumTypeProvider.nameENString, false)
-        .goUpFilterValidator()
-        .root().right().goPath()
-        .first().isComplex("PropertyCompMixedEnumDef")
-        .n().isPrimitiveProperty("PropertyEnumString", EnumTypeProvider.nameENString, false);
+        .root().right().isEnum(EnumTypeProvider.nameENString, Arrays.asList("String1", "String3"));
 
+    testFilter.runUriEx("ESMixEnumDefCollComp", "$filter=PropertyEnumString has null")
+        .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
     testFilter.runUriEx("ESMixEnumDefCollComp", "$filter=PropertyEnumString has ENString'String1'")
         .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
     testFilter.runUriEx("ESMixEnumDefCollComp", "$filter=PropertyEnumString has wrongNamespace.ENString'String1'")
@@ -5192,6 +5159,28 @@ public class TestFullResourcePath {
 
   @Test
   public void orderby() throws Exception {
+    testFilter.runOrderByOnETTwoKeyNav("PropertyString")
+        .isSortOrder(0, false)
+        .goOrder(0).goPath()
+        .first().isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
+
+    testFilter.runOrderByOnETTwoKeyNav("PropertyComp")
+        .isSortOrder(0, false)
+        .goOrder(0).goPath()
+        .first().isComplex("PropertyComp");
+
+    testFilter.runOrderByOnETTwoKeyNav("PropertyComp/PropertyComp")
+        .isSortOrder(0, false)
+        .goOrder(0).goPath()
+        .first().isComplex("PropertyComp")
+        .n().isComplex("PropertyComp");
+
+    testFilter.runOrderByOnETTwoKeyNav("PropertyComp/PropertyComp/PropertyDate")
+        .isSortOrder(0, false)
+        .goOrder(0).goPath()
+        .first().isComplex("PropertyComp")
+        .n().isComplex("PropertyComp")
+        .n().isPrimitiveProperty("PropertyDate", PropertyProvider.nameDate, false);
 
     testFilter.runOrderByOnETTwoKeyNav("olingo.odata.test1.UFCRTETAllPrimTwoParam("
         + "ParameterString=@ParamStringAlias,ParameterInt16=@ParamInt16Alias)/PropertyString eq 'SomeString'")
@@ -5215,8 +5204,8 @@ public class TestFullResourcePath {
         .goOrder(0).right().isLiteral("'SomeString'");
 
     testFilter.runOrderByOnETTwoKeyNav("olingo.odata.test1.UFCRTETAllPrimTwoParam("
-        + "ParameterString=@ParamStringAlias,ParameterInt16=@ParamInt16Alias)/PropertyString eq 'SomeString' desc"
-        + ", PropertyString eq '1'")
+        + "ParameterString=@ParamStringAlias,ParameterInt16=@ParamInt16Alias)/PropertyString eq 'SomeString' desc,"
+        + "PropertyString eq '1'")
         .isSortOrder(0, true)
         .goOrder(0).isBinary(BinaryOperatorKind.EQ).left().goPath()
         .first().isFunction("UFCRTETAllPrimTwoParam").goUpFilterValidator()
@@ -5241,20 +5230,8 @@ public class TestFullResourcePath {
         .n().isComplex("PropertyComp")
         .n().isPrimitiveProperty("PropertyDate", PropertyProvider.nameDate, false);
 
-    testFilter.runOrderByOnETTwoKeyNav("PropertyString")
-        .isSortOrder(0, false)
-        .goOrder(0).goPath()
-        .first().isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
-
-    testFilter.runOrderByOnETTwoKeyNav("PropertyComp/PropertyComp/PropertyDate")
-        .isSortOrder(0, false)
-        .goOrder(0).goPath()
-        .first().isComplex("PropertyComp")
-        .n().isComplex("PropertyComp")
-        .n().isPrimitiveProperty("PropertyDate", PropertyProvider.nameDate, false);
-
-    testFilter.runOrderByOnETTwoKeyNav("PropertyComp/PropertyComp/PropertyDate "
-        + "eq 2013-11-12 desc, PropertyString eq 'SomeString' desc")
+    testFilter.runOrderByOnETTwoKeyNav("PropertyComp/PropertyComp/PropertyDate eq 2013-11-12 desc,"
+        + "PropertyString eq 'SomeString' desc")
         .isSortOrder(0, true)
         .goOrder(0).isBinary(BinaryOperatorKind.EQ)
         .left().goPath()
@@ -5267,17 +5244,7 @@ public class TestFullResourcePath {
         .goUpFilterValidator()
         .goOrder(1).right().isLiteral("'SomeString'");
 
-    testFilter.runOrderByOnETTwoKeyNav("PropertyComp")
-        .isSortOrder(0, false)
-        .goOrder(0).goPath()
-        .first().isComplex("PropertyComp");
-    testFilter.runOrderByOnETTwoKeyNav("PropertyComp/PropertyComp")
-        .isSortOrder(0, false)
-        .goOrder(0).goPath()
-        .first().isComplex("PropertyComp")
-        .n().isComplex("PropertyComp");
-
-    testFilter.runOrderByOnETTwoKeyNav("PropertyComp desc, PropertyComp/PropertyInt16 eq 1")
+    testFilter.runOrderByOnETTwoKeyNav("PropertyComp desc,PropertyComp/PropertyInt16 eq 1")
         .isSortOrder(0, true)
         .goOrder(0).goPath()
         .first().isComplex("PropertyComp").goUpFilterValidator()
@@ -5419,17 +5386,17 @@ public class TestFullResourcePath {
         .goUpFilterValidator()
         .goOrder(0).right().isLiteral("9223372036854775807");
 
-    testFilter.runOrderByOnETAllPrim("PropertyBinary eq binary'0FAB7B'")
+    testFilter.runOrderByOnETAllPrim("PropertyBinary eq binary'VGVzdA=='")
         .isSortOrder(0, false)
         .goOrder(0).left().goPath().isPrimitiveProperty("PropertyBinary", PropertyProvider.nameBinary, false)
         .goUpFilterValidator()
-        .goOrder(0).right().isLiteral("binary'0FAB7B'");
+        .goOrder(0).right().isLiteral("binary'VGVzdA=='");
 
-    testFilter.runOrderByOnETAllPrim("PropertyBinary eq binary'0FAB7B' desc")
+    testFilter.runOrderByOnETAllPrim("PropertyBinary eq binary'VGVzdA==' desc")
         .isSortOrder(0, true)
         .goOrder(0).left().goPath().isPrimitiveProperty("PropertyBinary", PropertyProvider.nameBinary, false)
         .goUpFilterValidator()
-        .goOrder(0).right().isLiteral("binary'0FAB7B'");
+        .goOrder(0).right().isLiteral("binary'VGVzdA=='");
 
     testFilter.runOrderByOnETAllPrim("PropertyDate eq 2013-09-25")
         .isSortOrder(0, false)
@@ -5518,15 +5485,15 @@ public class TestFullResourcePath {
         .goOrder(0).right().isEnum(EnumTypeProvider.nameENString, Arrays.asList("String1"));
 
     testFilter.runOrderByOnETTwoKeyNavEx("PropertyInt16 1")
-        .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
+        .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION);
     testFilter.runOrderByOnETTwoKeyNavEx("PropertyInt16, PropertyInt32 PropertyDuration")
         .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
     testFilter.runOrderByOnETTwoKeyNavEx("PropertyInt16 PropertyInt32, PropertyDuration desc")
-        .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
+        .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION);
     testFilter.runOrderByOnETTwoKeyNavEx("PropertyInt16 asc, PropertyInt32 PropertyDuration desc")
         .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
     testFilter.runOrderByOnETTwoKeyNavEx("PropertyInt16 asc desc")
-        .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
+        .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION);
     testFilter.runOrderByOnETTwoKeyNavEx("undefined")
         .isExSemantic(MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
     testFilter.runOrderByOnETTwoKeyNavEx("PropertyComp/undefined")
@@ -5779,7 +5746,7 @@ public class TestFullResourcePath {
   }
 
   @Test
-  public void KeyPredicatesInDoubleExpandedFilter() throws Exception {
+  public void keyPredicatesInDoubleExpandedFilter() throws Exception {
     testUri.run("ESKeyNav(0)", "$expand=NavPropertyETTwoKeyNavMany($expand=NavPropertyETTwoKeyNavMany"
         + "($filter=NavPropertyETTwoKeyNavMany(PropertyInt16=1,PropertyString='2')/PropertyInt16 eq 1))")
         .goPath().goExpand()
@@ -5791,15 +5758,15 @@ public class TestFullResourcePath {
   }
 
   @Test
-  public void filterSystemQueryOptionAnyWithKeyAny() throws Exception {
-    testUri.runEx("ESAllPrim", "$filter=NavPropertyETTwoPrimMany(1)/any(d:d/PropertyInt16 eq 0)")
-        .isExSemantic(MessageKeys.KEY_NOT_ALLOWED);
+  public void filterSystemQueryOptionManyWithKeyAny() throws Exception {
+    testFilter.runUriEx("ESAllPrim", "$filter=NavPropertyETTwoPrimMany(1)/any(d:d/PropertyInt16 eq 0)")
+        .isExSemantic(MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
   }
 
   @Test
-  public void filterSystemQueryOptionAnyWithKeyAll() throws Exception {
-    testUri.runEx("ESAllPrim", "$filter=NavPropertyETTwoPrimMany(1)/all(d:d/PropertyInt16 eq 0)")
-        .isExSemantic(MessageKeys.KEY_NOT_ALLOWED);
+  public void filterSystemQueryOptionManyWithKeyAll() throws Exception {
+    testFilter.runUriEx("ESAllPrim", "$filter=NavPropertyETTwoPrimMany(1)/all(d:d/PropertyInt16 eq 0)")
+        .isExSemantic(MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
   }
 
   @Test
@@ -5896,87 +5863,103 @@ public class TestFullResourcePath {
         .at(3).isNavProperty(entitySetName, nameETNavProp, true);
   }
 
+  // TODO: Better type determination for literal numbers.
   @Test
+  @Ignore
   public void filterLiteralTypes() throws Exception {
-    testUri.run("ESAllPrim", "$filter='1' eq 42")
-        .goFilter().isBinary(BinaryOperatorKind.EQ)
-        .left().isLiteral("'1'").isLiteralType(oData.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.String))
+    testFilter.runOnETAllPrim("-1000 eq 42")
+        .isBinary(BinaryOperatorKind.EQ)
+        .left().isLiteral("-1000").isLiteralType(oData.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Int16))
         .root()
         .right().isLiteral("42").isLiteralType(oData.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.SByte));
 
-    testUri.run("ESAllPrim", "$filter=127 eq 128")
-        .goFilter().isBinary(BinaryOperatorKind.EQ)
+    testFilter.runOnETAllPrim("127 eq 128")
+        .isBinary(BinaryOperatorKind.EQ)
         .left().isLiteral("127").isLiteralType(oData.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.SByte))
         .root()
         .right().isLiteral("128").isLiteralType(oData.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Byte));
 
-    testUri.run("ESAllPrim", "$filter=null eq 42.1")
-        .goFilter().isBinary(BinaryOperatorKind.EQ)
+    testFilter.runOnETAllPrim("null eq 42.1")
+        .isBinary(BinaryOperatorKind.EQ)
         .left().isLiteral("null").isNullLiteralType()
         .root()
         .right().isLiteral("42.1").isLiteralType(oData.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Decimal));
 
-    testUri.run("ESAllPrim", "$filter=15.6E300 eq 3.4E37")
-        .goFilter().isBinary(BinaryOperatorKind.EQ)
+    testFilter.runOnETAllPrim("15.6E300 eq 3.4E37")
+        .isBinary(BinaryOperatorKind.EQ)
         .left().isLiteral("15.6E300")
         .isLiteralType(oData.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Double))
         .root()
         .right().isLiteral("3.4E37").isLiteralType(oData.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Double));
 
-    testUri.run("ESAllPrim", "$filter=15.55555555555555555555555555555555555555555555 eq 3.1")
-        .goFilter().isBinary(BinaryOperatorKind.EQ)
+    testFilter.runOnETAllPrim("15.55555555555555555555555555555555555555555555 eq 3.1")
+        .isBinary(BinaryOperatorKind.EQ)
         .left().isLiteral("15.55555555555555555555555555555555555555555555")
         .isLiteralType(oData.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Decimal))
         .root()
         .right().isLiteral("3.1").isLiteralType(oData.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Decimal));
 
-    testUri.run("ESAllPrim", "$filter=duration'PT1H2S' eq 2012-12-03")
-        .goFilter().isBinary(BinaryOperatorKind.EQ)
+    testFilter.runOnETAllPrim("duration'PT1H2S' eq duration'PT3602S'")
+        .isBinary(BinaryOperatorKind.EQ)
         .left().isLiteral("duration'PT1H2S'")
         .isLiteralType(oData.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Duration))
         .root()
+        .right().isLiteral("duration'PT3602S'")
+        .isLiteralType(oData.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Duration));
+
+    testFilter.runOnETAllPrim("2013-11-02 ne 2012-12-03")
+        .isBinary(BinaryOperatorKind.NE)
+        .left().isLiteral("2013-11-02").isLiteralType(oData.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Date))
+        .root()
         .right().isLiteral("2012-12-03").isLiteralType(oData.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Date));
 
-    testUri.run("ESAllPrim", "$filter=true eq 2012-12-03T07:16:23Z")
-        .goFilter().isBinary(BinaryOperatorKind.EQ)
-        .left().isLiteral("true").isLiteralType(oData.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Boolean))
+    testFilter.runOnETAllPrim("null eq 2012-12-03T07:16:23Z")
+        .isBinary(BinaryOperatorKind.EQ)
+        .left().isLiteral("null")
+        .isNullLiteralType()
         .root()
         .right().isLiteral("2012-12-03T07:16:23Z")
         .isLiteralType(oData.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.DateTimeOffset));
 
-    testUri.run("ESAllPrim", "$filter=07:59:59.999 eq 01234567-89ab-cdef-0123-456789abcdef")
-        .goFilter().isBinary(BinaryOperatorKind.EQ)
+    testFilter.runOnETAllPrim("07:59:59.999 eq null")
+        .isBinary(BinaryOperatorKind.EQ)
         .left().isLiteral("07:59:59.999")
         .isLiteralType(oData.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.TimeOfDay))
         .root()
+        .right().isLiteral("null").isNullLiteralType();
+
+    testFilter.runOnETAllPrim("null eq 01234567-89ab-cdef-0123-456789abcdef")
+        .isBinary(BinaryOperatorKind.EQ)
+        .left().isLiteral("null").isNullLiteralType()
+        .root()
         .right().isLiteral("01234567-89ab-cdef-0123-456789abcdef")
         .isLiteralType(oData.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Guid));
 
-    testUri.run("ESAllPrim", "$filter=binary'0FAB7B' eq true")
-        .goFilter().isBinary(BinaryOperatorKind.EQ)
-        .left().isLiteral("binary'0FAB7B'").isLiteralType(
+    testFilter.runOnETAllPrim("binary'VGVzdA==' eq null")
+        .isBinary(BinaryOperatorKind.EQ)
+        .left().isLiteral("binary'VGVzdA=='").isLiteralType(
             oData.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Binary))
         .root()
-        .right().isLiteral("true").isLiteralType(oData.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Boolean));
+        .right().isLiteral("null").isNullLiteralType();
 
-    testUri.run("ESAllPrim", "$filter=" + Short.MIN_VALUE + " eq " + Short.MAX_VALUE)
-        .goFilter().isBinary(BinaryOperatorKind.EQ)
+    testFilter.runOnETAllPrim(Short.MIN_VALUE + " eq " + Short.MAX_VALUE)
+        .isBinary(BinaryOperatorKind.EQ)
         .left().isLiteral(Short.toString(Short.MIN_VALUE))
         .isLiteralType(oData.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Int16))
         .root()
         .right().isLiteral(Short.toString(Short.MAX_VALUE))
         .isLiteralType(oData.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Int16));
 
-    testUri.run("ESAllPrim", "$filter=" + Integer.MIN_VALUE + " eq " + Integer.MAX_VALUE)
-        .goFilter().isBinary(BinaryOperatorKind.EQ)
+    testFilter.runOnETAllPrim(Integer.MIN_VALUE + " eq " + Integer.MAX_VALUE)
+        .isBinary(BinaryOperatorKind.EQ)
         .left().isLiteral(Integer.toString(Integer.MIN_VALUE))
         .isLiteralType(oData.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Int32))
         .root()
         .right().isLiteral(Integer.toString(Integer.MAX_VALUE))
         .isLiteralType(oData.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Int32));
 
-    testUri.run("ESAllPrim", "$filter=" + Long.MIN_VALUE + " eq " + Long.MAX_VALUE)
-        .goFilter().isBinary(BinaryOperatorKind.EQ)
+    testFilter.runOnETAllPrim(Long.MIN_VALUE + " eq " + Long.MAX_VALUE)
+        .isBinary(BinaryOperatorKind.EQ)
         .left().isLiteral(Long.toString(Long.MIN_VALUE))
         .isLiteralType(oData.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Int64))
         .root()
@@ -6016,34 +5999,35 @@ public class TestFullResourcePath {
         .at(1).isFunction("BFCESTwoKeyNavRTStringParam").isParameterAlias(0, "ParameterComp", "@p1")
         .isInAliasToValueMap("@p1", "{\"PropertyInt16\":1,\"PropertyString\":\"" + stringValueDecoded + "\"}");
 
-    testUri.run("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
+    testFilter.runOnETTwoKeyNav("olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
         + "(ParameterComp={\"PropertyString\":\"Test\",\"PropertyInt16\":1}) eq 'Test'")
-        .goFilter().left().is("<<BFCESTwoKeyNavRTStringParam> eq <'Test'>>")
-        .isParameterText(0, "{\"PropertyString\":\"Test\",\"PropertyInt16\":1}");
+        .is("<<BFCESTwoKeyNavRTStringParam> eq <'Test'>>")
+        .isBinary(BinaryOperatorKind.EQ)
+        .left().isParameterText(0, "{\"PropertyString\":\"Test\",\"PropertyInt16\":1}");
 
-    testUri.run("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
+    testFilter.runOnETTwoKeyNav("olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
         + "(ParameterComp={\"PropertyString\":\"" + stringValueEncoded + "\",\"PropertyInt16\":1}) eq 'Test'")
-        .goFilter().left().is("<<BFCESTwoKeyNavRTStringParam> eq <'Test'>>")
-        .isParameterText(0, "{\"PropertyString\":\"" + stringValueDecoded + "\",\"PropertyInt16\":1}");
+        .is("<<BFCESTwoKeyNavRTStringParam> eq <'Test'>>")
+        .left().isParameterText(0, "{\"PropertyString\":\"" + stringValueDecoded + "\",\"PropertyInt16\":1}");
 
     testUri.run("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
-        + "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":1,\"PropertyString\":\"1\"}");
+        + "(ParameterComp=@p1) eq '0'&@p1={\"PropertyInt16\":1,\"PropertyString\":\"1\"}");
 
     testUri.run("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
-        + "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":1,\"PropertyString\":null}")
+        + "(ParameterComp=@p1) eq '0'&@p1={\"PropertyInt16\":1,\"PropertyString\":null}")
         .goFilter().left().isParameterText(0, null);
 
     testUri.run("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
-        + "(ParameterComp=@p1) eq 0&@p1={}");
+        + "(ParameterComp=@p1) eq '0'&@p1={}");
 
     testUri.run("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
-        + "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":[1,2,3],\"PropertyString\":\"1\"}");
+        + "(ParameterComp=@p1) eq '0'&@p1={\"PropertyInt16\":[1,2,3],\"PropertyString\":\"1\"}");
 
     testUri.run("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
-        + "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":[\"1\",\"2\",\"3\"],\"PropertyString\":\"1\"}");
+        + "(ParameterComp=@p1) eq '0'&@p1={\"PropertyInt16\":[\"1\",\"2\",\"3\"],\"PropertyString\":\"1\"}");
 
     testUri.run("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
-        + "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":[{\"Prop1\":123,\"Prop2\":\"Test\",\"Prop3\":[1,2,3]},"
+        + "(ParameterComp=@p1) eq '0'&@p1={\"PropertyInt16\":[{\"Prop1\":123,\"Prop2\":\"Test\",\"Prop3\":[1,2,3]},"
         + "{\"Prop1\":{\"Prop1\":[\"Prop\\\":{]\"]}}],\"PropertyString\":\"1\"}");
 
     testUri.run("FINRTByteNineParam(ParameterEnum=null,ParameterDef='x',ParameterComp=@c,"
@@ -6057,7 +6041,7 @@ public class TestFullResourcePath {
 
     testUri.runEx("ESTwoKeyNav/olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
         + "(ParameterComp={\"PropertyInt16\":1,\"PropertyString\":\"Test\"})")
-        .isExSemantic(MessageKeys.INVALID_KEY_VALUE);
+        .isExSemantic(MessageKeys.COMPLEX_PARAMETER_IN_RESOURCE_PATH);
 
     testUri.runEx("FICRTCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=null)")
         .isExValidation(UriValidationException.MessageKeys.MISSING_PARAMETER);
@@ -6081,34 +6065,33 @@ public class TestFullResourcePath {
     testUri.runEx("FICRTCollCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test)", "@test=null&@test='1'")
         .isExSyntax(UriParserSyntaxException.MessageKeys.DUPLICATED_ALIAS);
 
-    testUri.runEx("ESAllPrim", "$filter=FINRTInt16() eq 0")
-        .isExSemantic(MessageKeys.FUNCTION_IMPORT_NOT_ALLOWED);
+    testFilter.runOnETKeyNavEx("FINRTInt16() eq 0")
+        .isExSemantic(MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
 
     testUri.runEx("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
-        + "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":1,\"PropertyString\":\"1\"")
+        + "(ParameterComp=@p1) eq '0'&@p1={\"PropertyInt16\":1,\"PropertyString\":\"1\"")
         .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
 
     testUri.runEx("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
-        + "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":1,\"PropertyString\":\"1\"}}")
+        + "(ParameterComp=@p1) eq '0'&@p1={\"PropertyInt16\":1,\"PropertyString\":\"1\"}}")
         .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
 
     testUri.runEx("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
-        + "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":[1,2,3]],\"PropertyString\":\"1\"}")
+        + "(ParameterComp=@p1) eq '0'&@p1={\"PropertyInt16\":[1,2,3]],\"PropertyString\":\"1\"}")
         .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
 
     testUri.runEx("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
-        + "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":[1,2,3,\"PropertyString\":\"1\"}")
+        + "(ParameterComp=@p1) eq '0'&@p1={\"PropertyInt16\":[1,2,3,\"PropertyString\":\"1\"}")
         .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
 
     testUri.runEx("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
-        + "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":[1,2,3},\"PropertyString\":\"1\"}")
+        + "(ParameterComp=@p1) eq '0'&@p1={\"PropertyInt16\":[1,2,3},\"PropertyString\":\"1\"}")
         .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
   }
 
   @Test
-  @Ignore("Key predicates in filter/orderby expression are not validated currently")
-  public void testKeyPredicatesInExpressions() throws Exception {
-    testUri.run("ESTwoKeyNav", "$filter=NavPropertyETTwoKeyNavMany(PropertyString='1',PropertyInt16=1)"
+  public void keyPredicatesInExpressions() throws Exception {
+    testFilter.runOnETTwoKeyNav("NavPropertyETTwoKeyNavMany(PropertyString='1',PropertyInt16=1)"
         + "/PropertyInt16 eq 1");
     testUri.runEx("ESTwoKeyNav", "$filter=NavPropertyETTwoKeyNavMany(Prop='22',P=2)/PropertyInt16 eq 0")
         .isExValidation(UriValidationException.MessageKeys.INVALID_KEY_PROPERTY);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8091658/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestUriParserImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestUriParserImpl.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestUriParserImpl.java
index 19f5946..8790766 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestUriParserImpl.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestUriParserImpl.java
@@ -38,6 +38,7 @@ import org.apache.olingo.server.tecsvc.provider.ContainerProvider;
 import org.apache.olingo.server.tecsvc.provider.EdmTechProvider;
 import org.apache.olingo.server.tecsvc.provider.EntityTypeProvider;
 import org.apache.olingo.server.tecsvc.provider.PropertyProvider;
+import org.junit.Ignore;
 import org.junit.Test;
 
 public class TestUriParserImpl {
@@ -561,11 +562,12 @@ public class TestUriParserImpl {
   @Test
   public void unary() throws Exception {
     testFilter.runOnETAllPrim("not PropertyBoolean").isCompr("<not <PropertyBoolean>>");
-    testFilter.runOnETAllPrim("- PropertyInt16 eq PropertyInt16").isCompr("<<- <PropertyInt16>> eq <PropertyInt16>>");
     testFilter.runOnETAllPrim("-PropertyInt16 eq PropertyInt16").isCompr("<<- <PropertyInt16>> eq <PropertyInt16>>");
   }
 
+  // TODO: Use correct types.
   @Test
+  @Ignore
   public void filterComplexMixedPriority() throws Exception {
     testFilter.runOnETAllPrim("PropertyInt16 or PropertyInt32 and PropertyInt64")
         .isCompr("<<PropertyInt16> or <<PropertyInt32> and <PropertyInt64>>>");
@@ -1069,28 +1071,21 @@ public class TestUriParserImpl {
   }
 
   @Test
-  public void testLambda() throws Exception {
-    testUri.run("ESTwoKeyNav", "$filter=CollPropertyComp/all( l : true )")
-    .goFilter().is("<CollPropertyComp/<ALL;<true>>>");
-
-    testUri.run("ESTwoKeyNav", "$filter=CollPropertyComp/all( x : x/PropertyInt16 eq 2)")
-        .goFilter().is("<CollPropertyComp/<ALL;<<x/PropertyInt16> eq <2>>>>");
-
-    testUri.run("ESTwoKeyNav", "$filter=CollPropertyComp/any( l : true )")
-    .goFilter().is("<CollPropertyComp/<ANY;<true>>>");
-    testUri.run("ESTwoKeyNav", "$filter=CollPropertyComp/any( )")
-    .goFilter().is("<CollPropertyComp/<ANY;>>");
-
-    testUri.run("ESTwoKeyNav", "$filter=all( l : true )")
-    .goFilter().is("<<ALL;<true>>>");
-    testUri.run("ESTwoKeyNav", "$filter=any( l : true )")
-    .goFilter().is("<<ANY;<true>>>");
-    testUri.run("ESTwoKeyNav", "$filter=any( )")
-    .goFilter().is("<<ANY;>>");
+  public void lambda() throws Exception {
+    testFilter.runOnETTwoKeyNav("CollPropertyComp/all(l:true)")
+        .is("<CollPropertyComp/<ALL;<true>>>");
+
+    testFilter.runOnETTwoKeyNav("CollPropertyComp/all(x:x/PropertyInt16 eq 2)")
+        .is("<CollPropertyComp/<ALL;<<x/PropertyInt16> eq <2>>>>");
+
+    testFilter.runOnETTwoKeyNav("CollPropertyComp/any(l:true)")
+        .is("<CollPropertyComp/<ANY;<true>>>");
+    testFilter.runOnETTwoKeyNav("CollPropertyComp/any()")
+        .is("<CollPropertyComp/<ANY;>>");
   }
 
   @Test
-  public void testCustomQueryOption() throws Exception {
+  public void customQueryOption() throws Exception {
     testUri.run("ESTwoKeyNav", "custom")
     .isCustomParameter(0, "custom", "");
     testUri.run("ESTwoKeyNav", "custom=ABC")
@@ -1098,6 +1093,7 @@ public class TestUriParserImpl {
   }
 
   @Test
+  @Ignore("Geo types are not supported yet.")
   public void geo() throws Exception {
     testFilter.runOnETAllPrim("geo.distance(PropertySByte,PropertySByte)")
     .is("<geo.distance(<PropertySByte>,<PropertySByte>)>")

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8091658/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/queryoption/expression/ExpressionTest.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/queryoption/expression/ExpressionTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/queryoption/expression/ExpressionTest.java
index 864b17a..fad718b 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/queryoption/expression/ExpressionTest.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/queryoption/expression/ExpressionTest.java
@@ -128,7 +128,7 @@ public class ExpressionTest {
     // UriResourceImpl
     EdmAction action = edm.getUnboundAction(ActionProvider.nameUARTString);
     UriInfoResource uriInfo = new UriInfoImpl().setKind(UriInfoKind.resource).addResourcePart(
-        new UriResourceActionImpl().setAction(action)).asUriInfoResource();
+        new UriResourceActionImpl(action)).asUriInfoResource();
     MemberImpl expression = new MemberImpl(uriInfo, null);
     assertEquals(action.getReturnType().getType(), expression.getType());
 
@@ -142,7 +142,7 @@ public class ExpressionTest {
     // UriResourceImplTyped check collection = true case
     action = edm.getUnboundAction(ActionProvider.nameUARTCollStringTwoParam);
     expression = new MemberImpl(new UriInfoImpl().setKind(UriInfoKind.resource)
-        .addResourcePart(new UriResourceActionImpl().setAction(action))
+        .addResourcePart(new UriResourceActionImpl(action))
         .asUriInfoResource(),
         null);
     assertTrue(expression.isCollection());
@@ -150,7 +150,7 @@ public class ExpressionTest {
     // UriResourceImplTyped with filter
     EdmFunction function = edm.getUnboundFunction(FunctionProvider.nameUFCRTETKeyNav, null);
     expression = new MemberImpl(new UriInfoImpl().setKind(UriInfoKind.resource).addResourcePart(
-        new UriResourceFunctionImpl().setFunction(function).setEntryTypeFilter(entityType))
+        new UriResourceFunctionImpl(null, function, null).setEntryTypeFilter(entityType))
         .asUriInfoResource(),
         null);
     assertEquals(entityType, expression.getType());
@@ -158,7 +158,7 @@ public class ExpressionTest {
     // UriResourceImplKeyPred
     function = edm.getUnboundFunction(FunctionProvider.nameUFCRTETKeyNav, null);
     expression = new MemberImpl(new UriInfoImpl().setKind(UriInfoKind.resource).addResourcePart(
-        new UriResourceFunctionImpl().setFunction(function))
+        new UriResourceFunctionImpl(null, function, null))
         .asUriInfoResource(),
         null);
     assertEquals(function.getReturnType().getType(), expression.getType());
@@ -167,7 +167,7 @@ public class ExpressionTest {
     EdmEntityType entityBaseType = edm.getEntityType(EntityTypeProvider.nameETBaseTwoKeyNav);
     function = edm.getUnboundFunction(FunctionProvider.nameUFCRTCollETTwoKeyNavParam, Arrays.asList("ParameterInt16"));
     expression = new MemberImpl(new UriInfoImpl().setKind(UriInfoKind.resource).addResourcePart(
-        new UriResourceFunctionImpl().setFunction(function).setEntryTypeFilter(entityBaseType))
+        new UriResourceFunctionImpl(null, function, null).setEntryTypeFilter(entityBaseType))
         .asUriInfoResource(),
         null);
     assertEquals(entityBaseType, expression.getType());
@@ -176,7 +176,7 @@ public class ExpressionTest {
     entityBaseType = edm.getEntityType(EntityTypeProvider.nameETBaseTwoKeyNav);
     function = edm.getUnboundFunction(FunctionProvider.nameUFCRTCollETTwoKeyNavParam, Arrays.asList("ParameterInt16"));
     expression = new MemberImpl(new UriInfoImpl().setKind(UriInfoKind.resource).addResourcePart(
-        new UriResourceFunctionImpl().setFunction(function).setCollectionTypeFilter(entityBaseType))
+        new UriResourceFunctionImpl(null, function, null).setCollectionTypeFilter(entityBaseType))
         .asUriInfoResource(),
         null);
     assertEquals(entityBaseType, expression.getType());


[06/30] olingo-odata4 git commit: Merge branch 'master' into refactorUriParsing

Posted by ch...@apache.org.
Merge branch 'master' into refactorUriParsing


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

Branch: refs/heads/master
Commit: 7bc932aae980251776ff014712b0a1f7de679b46
Parents: 83f11b9 a47e9f6
Author: Christian Amend <ch...@sap.com>
Authored: Thu Dec 10 15:32:44 2015 +0100
Committer: Christian Amend <ch...@sap.com>
Committed: Thu Dec 10 15:32:44 2015 +0100

----------------------------------------------------------------------
 .../edm/primitivetype/EdmDateTimeOffset.java    |  8 +++++-
 .../primitivetype/EdmDateTimeOffsetTest.java    | 16 ++++++++++--
 .../edm/primitivetype/EdmTimeOfDayTest.java     | 26 +++++++++++++++++++-
 3 files changed, 46 insertions(+), 4 deletions(-)
----------------------------------------------------------------------



[09/30] olingo-odata4 git commit: [OLINGO-834] $select parser in Java + clean-up

Posted by ch...@apache.org.
[OLINGO-834] $select parser in Java + clean-up

Signed-off-by: Christian Amend <ch...@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/d7e23bf8
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/d7e23bf8
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/d7e23bf8

Branch: refs/heads/master
Commit: d7e23bf89a61df8fdbe53728f201a2686c7f79fc
Parents: ef19c9b
Author: Klaus Straubinger <kl...@sap.com>
Authored: Thu Dec 10 14:56:58 2015 +0100
Committer: Christian Amend <ch...@sap.com>
Committed: Thu Dec 10 15:51:45 2015 +0100

----------------------------------------------------------------------
 .../uri/parser/CheckFullContextListener.java    |  60 ---
 .../olingo/server/core/uri/parser/Parser.java   | 507 ++++++++++---------
 .../olingo/server/core/uri/parser/RawUri.java   |  46 --
 .../server/core/uri/parser/SelectParser.java    | 241 +++++++++
 .../server/core/uri/parser/UriContext.java      |  17 +-
 .../server/core/uri/parser/UriDecoder.java      |  74 +--
 .../core/uri/parser/UriParseTreeVisitor.java    | 176 ++-----
 .../server/core/uri/parser/UriTokenizer.java    | 166 ++++--
 .../olingo/server/core/uri/UriInfoImplTest.java | 204 ++++++++
 .../server/core/uri/parser/UriDecoderTest.java  |  94 ++++
 .../core/uri/parser/UriTokenizerTest.java       |  13 +-
 .../olingo/server/core/uri/UriInfoImplTest.java | 212 --------
 .../core/uri/antlr/TestFullResourcePath.java    | 159 +++++-
 .../core/uri/antlr/TestUriParserImpl.java       |  60 ---
 .../server/core/uri/parser/RawUriTest.java      | 150 ------
 .../core/uri/testutil/ParserWithLogging.java    |  59 ---
 .../core/uri/testutil/ResourceValidator.java    |   3 +-
 .../core/uri/testutil/TestErrorLogger.java      | 105 ----
 .../core/uri/testutil/TokenValidator.java       |  70 +--
 .../core/uri/testutil/UriLexerWithTrace.java    |  85 ----
 20 files changed, 1164 insertions(+), 1337 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d7e23bf8/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/CheckFullContextListener.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/CheckFullContextListener.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/CheckFullContextListener.java
deleted file mode 100644
index 86efdca..0000000
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/CheckFullContextListener.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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.BitSet;
-
-import org.antlr.v4.runtime.DiagnosticErrorListener;
-import org.antlr.v4.runtime.Parser;
-import org.antlr.v4.runtime.RecognitionException;
-import org.antlr.v4.runtime.Recognizer;
-import org.antlr.v4.runtime.atn.ATNConfigSet;
-import org.antlr.v4.runtime.dfa.DFA;
-
-class CheckFullContextListener extends DiagnosticErrorListener {
-
-  @Override
-  public void syntaxError(final Recognizer<?, ?> recognizer, final Object offendingSymbol, final int line,
-      final int charPositionInLine,
-      final String msg, final RecognitionException e) {
-    // System.err.println("syntaxError detected");
-  }
-
-  @Override
-  public void reportAmbiguity(final Parser recognizer, final DFA dfa, final int startIndex, final int stopIndex,
-      final boolean exact,
-      final BitSet ambigAlts, final ATNConfigSet configs) {
-    // System.err.println("reportAmbiguity detected");
-  }
-
-  @Override
-  public void reportAttemptingFullContext(final Parser recognizer, final DFA dfa, final int startIndex,
-      final int stopIndex,
-      final BitSet conflictingAlts, final ATNConfigSet configs) {
-    // System.err.println("reportAttemptingFullContext detected");
-  }
-
-  @Override
-  public void reportContextSensitivity(final Parser recognizer, final DFA dfa, final int startIndex,
-      final int stopIndex, final int prediction,
-      final ATNConfigSet configs) {
-    // System.err.println("reportContextSensitivity detected");
-  }
-
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d7e23bf8/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 5caaaeb..0b53e69 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
@@ -26,11 +26,13 @@ import org.antlr.v4.runtime.CommonTokenStream;
 import org.antlr.v4.runtime.Lexer;
 import org.antlr.v4.runtime.ParserRuleContext;
 import org.antlr.v4.runtime.RecognitionException;
-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.edm.EdmEntitySet;
+import org.apache.olingo.commons.api.edm.EdmStructuredType;
+import org.apache.olingo.commons.api.edm.EdmType;
 import org.apache.olingo.commons.api.ex.ODataRuntimeException;
 import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.uri.UriInfo;
@@ -45,28 +47,28 @@ import org.apache.olingo.server.api.uri.UriResourceValue;
 import org.apache.olingo.server.api.uri.queryoption.AliasQueryOption;
 import org.apache.olingo.server.api.uri.queryoption.CustomQueryOption;
 import org.apache.olingo.server.api.uri.queryoption.FilterOption;
+import org.apache.olingo.server.api.uri.queryoption.QueryOption;
 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.UriResourceTypedImpl;
+import org.apache.olingo.server.core.uri.UriResourceWithKeysImpl;
 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.ExpandItemsEOFContext;
 import org.apache.olingo.server.core.uri.antlr.UriParserParser.FilterExpressionEOFContext;
 import org.apache.olingo.server.core.uri.antlr.UriParserParser.OrderByEOFContext;
-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;
-import org.apache.olingo.server.core.uri.queryoption.CustomQueryOptionImpl;
 import org.apache.olingo.server.core.uri.queryoption.ExpandOptionImpl;
 import org.apache.olingo.server.core.uri.queryoption.FilterOptionImpl;
 import org.apache.olingo.server.core.uri.queryoption.FormatOptionImpl;
 import org.apache.olingo.server.core.uri.queryoption.IdOptionImpl;
 import org.apache.olingo.server.core.uri.queryoption.OrderByOptionImpl;
-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;
@@ -79,12 +81,11 @@ public class Parser {
   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 {
-    ExpandItems, FilterExpression, Orderby, Select
+    ExpandItems, FilterExpression, Orderby
   }
 
   public Parser(final Edm edm, final OData odata) {
@@ -98,242 +99,268 @@ public class Parser {
     UriContext context = new UriContext();
     UriParseTreeVisitor uriParseTreeVisitor = new UriParseTreeVisitor(edm, context);
 
-    try {
-      final RawUri uri = UriDecoder.decodeUri(path, query, fragment, 0); // -> 0 segments are before the service url
-
-      // first, read the decoded path segments
-      final String firstSegment = uri.pathSegmentListDecoded.isEmpty() ? "" : uri.pathSegmentListDecoded.get(0);
-
-      if (firstSegment.isEmpty()) {
-        ensureLastSegment(firstSegment, 0, uri.pathSegmentListDecoded.size());
-        context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.service);
-
-      } else if (firstSegment.equals("$batch")) {
-        ensureLastSegment(firstSegment, 1, uri.pathSegmentListDecoded.size());
-        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.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());
-          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);
-        }
+    final List<String> pathSegmentsDecoded = UriDecoder.splitAndDecodePath(path);
+    final int numberOfSegments = pathSegmentsDecoded.size();
 
-      } else if (firstSegment.startsWith("$crossjoin")) {
-        ensureLastSegment(firstSegment, 1, uri.pathSegmentListDecoded.size());
-        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));
-        }
+    // first, read the decoded path segments
+    final String firstSegment = numberOfSegments == 0 ? "" : pathSegmentsDecoded.get(0);
+
+    if (firstSegment.isEmpty()) {
+      ensureLastSegment(firstSegment, 0, numberOfSegments);
+      context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.service);
 
+    } else if (firstSegment.equals("$batch")) {
+      ensureLastSegment(firstSegment, 1, numberOfSegments);
+      context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.batch);
+
+    } else if (firstSegment.equals("$metadata")) {
+      ensureLastSegment(firstSegment, 1, numberOfSegments);
+      context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.metadata);
+      context.contextUriInfo.setFragment(fragment);
+
+    } else if (firstSegment.equals("$all")) {
+      ensureLastSegment(firstSegment, 1, numberOfSegments);
+      context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.all);
+      // This loads nearly the whole schema, but sooner or later '$all' needs all entity sets anyway.
+      for (final EdmEntitySet entitySet : edm.getEntityContainer().getEntitySets()) {
+        context.contextTypes.push(entitySet.getEntityType());
+      }
+      context.isCollection = true;
+
+    } else if (firstSegment.equals("$entity")) {
+      if (numberOfSegments > 1) {
+        final String typeCastSegment = pathSegmentsDecoded.get(1);
+        ensureLastSegment(typeCastSegment, 2, numberOfSegments);
+        context.contextUriInfo = new ResourcePathParser(edm, odata).parseDollarEntityTypeCast(typeCastSegment);
+        context.contextTypes.push(context.contextUriInfo.getEntityTypeCast());
       } else {
-        context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.resource);
-        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 = new UriInfoImpl().setKind(UriInfoKind.entityId);
+        // The type of the entity is not known until the $id query option has been parsed.
+      }
+      context.isCollection = false;
+
+    } else if (firstSegment.startsWith("$crossjoin")) {
+      ensureLastSegment(firstSegment, 1, numberOfSegments);
+      context.contextUriInfo = new ResourcePathParser(edm, odata).parseCrossjoinSegment(firstSegment);
+      final EdmEntityContainer container = edm.getEntityContainer();
+      for (final String name : context.contextUriInfo.getEntitySetNames()) {
+        context.contextTypes.push(container.getEntitySet(name).getEntityType());
+      }
+      context.isCollection = true;
+
+    } else {
+      context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.resource);
+      final ResourcePathParser resourcePathParser = new ResourcePathParser(edm, odata);
+      int count = 0;
+      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));
             }
-            context.contextUriInfo.addResourcePart(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;
           }
+          context.contextUriInfo.addResourcePart(segment);
         }
+      }
 
-        if (lastSegment instanceof UriResourcePartTyped) {
-          UriResourcePartTyped typed = (UriResourcePartTyped) lastSegment;
-
-          UriParseTreeVisitor.TypeInformation myType = uriParseTreeVisitor.getTypeInformation(typed);
-          UriParseTreeVisitor.TypeInformation typeInfo =
-              uriParseTreeVisitor.new TypeInformation(myType.type, typed.isCollection());
-          context.contextTypes.push(typeInfo);
+      if (lastSegment instanceof UriResourcePartTyped) {
+        final UriResourcePartTyped typed = (UriResourcePartTyped) lastSegment;
+        final EdmType type = getTypeInformation(typed);
+        if (type != null) { // could be null for, e.g., actions without return type
+          context.contextTypes.push(type);
         }
+        context.isCollection = typed.isCollection();
       }
+    }
 
-      // second, read the system query options and the custom query options
-      for (final RawUri.QueryOption option : uri.queryOptionListDecoded) {
-        if (option.name.startsWith("$")) {
-          SystemQueryOption systemOption = null;
-          if (option.name.equals(SystemQueryOptionKind.FILTER.toString())) {
+    // second, read the system query options and the custom query options
+    final List<QueryOption> options = UriDecoder.splitAndDecodeOptions(query);
+    for (final QueryOption option : options) {
+      final String optionName = option.getName();
+      final String optionValue = option.getText();
+      if (optionName.startsWith("$")) {
+        SystemQueryOption systemOption = null;
+        if (optionName.equals(SystemQueryOptionKind.FILTER.toString())) {
+          try {
             FilterExpressionEOFContext ctxFilterExpression =
-                (FilterExpressionEOFContext) parseRule(option.value, ParserEntryRules.FilterExpression);
+                (FilterExpressionEOFContext) parseRule(optionValue, ParserEntryRules.FilterExpression);
             systemOption = (FilterOptionImpl) uriParseTreeVisitor.visitFilterExpressionEOF(ctxFilterExpression);
+          } catch (final ParseCancellationException e) {
+            throw e.getCause() instanceof UriParserException ?
+                (UriParserException) e.getCause() :
+                new UriParserSyntaxException("Syntax error", e, UriParserSyntaxException.MessageKeys.SYNTAX);
+          }
 
-          } else if (option.name.equals(SystemQueryOptionKind.FORMAT.toString())) {
-            FormatOptionImpl formatOption = new FormatOptionImpl();
-            formatOption.setName(option.name);
-            formatOption.setText(option.value);
-            if (option.value.equalsIgnoreCase(JSON)
-                || option.value.equalsIgnoreCase(XML)
-                || option.value.equalsIgnoreCase(ATOM)
-                || isFormatSyntaxValid(option.value)) {
-              formatOption.setFormat(option.value);
-            } else {
-              throw new UriParserSyntaxException("Illegal value of $format option!",
-                  UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION_FORMAT, option.value);
-            }
-            systemOption = formatOption;
+        } else if (optionName.equals(SystemQueryOptionKind.FORMAT.toString())) {
+          FormatOptionImpl formatOption = new FormatOptionImpl();
+          formatOption.setText(optionValue);
+          if (optionValue.equalsIgnoreCase(JSON)
+              || optionValue.equalsIgnoreCase(XML)
+              || optionValue.equalsIgnoreCase(ATOM)
+              || isFormatSyntaxValid(optionValue)) {
+            formatOption.setFormat(optionValue);
+          } else {
+            throw new UriParserSyntaxException("Illegal value of $format option!",
+                UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION_FORMAT, optionValue);
+          }
+          systemOption = formatOption;
 
-          } else if (option.name.equals(SystemQueryOptionKind.EXPAND.toString())) {
+        } else if (optionName.equals(SystemQueryOptionKind.EXPAND.toString())) {
+          try {
             ExpandItemsEOFContext ctxExpandItems =
-                (ExpandItemsEOFContext) parseRule(option.value, ParserEntryRules.ExpandItems);
+                (ExpandItemsEOFContext) parseRule(optionValue, ParserEntryRules.ExpandItems);
             systemOption = (ExpandOptionImpl) uriParseTreeVisitor.visitExpandItemsEOF(ctxExpandItems);
+          } catch (final ParseCancellationException e) {
+            throw e.getCause() instanceof UriParserException ?
+                (UriParserException) e.getCause() :
+                new UriParserSyntaxException("Syntax error", e, UriParserSyntaxException.MessageKeys.SYNTAX);
+          }
 
-          } else if (option.name.equals(SystemQueryOptionKind.ID.toString())) {
-            IdOptionImpl idOption = new IdOptionImpl();
-            idOption.setName(option.name);
-            idOption.setText(option.value);
-            idOption.setValue(option.value);
-            systemOption = idOption;
+        } else if (optionName.equals(SystemQueryOptionKind.ID.toString())) {
+          IdOptionImpl idOption = new IdOptionImpl();
+          idOption.setText(optionValue);
+          idOption.setValue(optionValue);
+          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 (optionName.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())) {
+        } else if (optionName.equals(SystemQueryOptionKind.ORDERBY.toString())) {
+          try {
             OrderByEOFContext ctxOrderByExpression =
-                (OrderByEOFContext) parseRule(option.value, ParserEntryRules.Orderby);
+                (OrderByEOFContext) parseRule(optionValue, ParserEntryRules.Orderby);
             systemOption = (OrderByOptionImpl) uriParseTreeVisitor.visitOrderByEOF(ctxOrderByExpression);
+          } catch (final ParseCancellationException e) {
+            throw e.getCause() instanceof UriParserException ?
+                (UriParserException) e.getCause() :
+                new UriParserSyntaxException("Syntax error", e, UriParserSyntaxException.MessageKeys.SYNTAX);
+          }
 
-          } else if (option.name.equals(SystemQueryOptionKind.SEARCH.toString())) {
-            systemOption = new SearchParser().parse(option.value);
+        } else if (optionName.equals(SystemQueryOptionKind.SEARCH.toString())) {
+          systemOption = new SearchParser().parse(optionValue);
+
+        } else if (optionName.equals(SystemQueryOptionKind.SELECT.toString())) {
+          UriTokenizer selectTokenizer = new UriTokenizer(optionValue);
+          systemOption = new SelectParser(edm).parse(selectTokenizer,
+              context.contextTypes.peek() instanceof EdmStructuredType ?
+                  (EdmStructuredType) context.contextTypes.peek() :
+                  null,
+              context.isCollection);
+          if (!selectTokenizer.next(TokenKind.EOF)) {
+            throw new UriParserSyntaxException("Illegal value of $select option!",
+                UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION,
+                optionName, optionValue);
+          }
 
-          } else if (option.name.equals(SystemQueryOptionKind.SELECT.toString())) {
-            SelectEOFContext ctxSelectEOF =
-                (SelectEOFContext) parseRule(option.value, ParserEntryRules.Select);
-            systemOption = (SelectOptionImpl) uriParseTreeVisitor.visitSelectEOF(ctxSelectEOF);
+        } else if (optionName.equals(SystemQueryOptionKind.SKIP.toString())) {
+          SkipOptionImpl skipOption = new SkipOptionImpl();
+          skipOption.setText(optionValue);
+          try {
+            skipOption.setValue(Integer.parseInt(optionValue));
+          } catch (final NumberFormatException e) {
+            throw new UriParserSyntaxException("Illegal value of $skip option!", e,
+                UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION,
+                optionName, optionValue);
+          }
+          systemOption = skipOption;
 
-          } else if (option.name.equals(SystemQueryOptionKind.SKIP.toString())) {
-            SkipOptionImpl skipOption = new SkipOptionImpl();
-            skipOption.setName(option.name);
-            skipOption.setText(option.value);
-            try {
-              skipOption.setValue(Integer.parseInt(option.value));
-            } catch (final NumberFormatException e) {
-              throw new UriParserSyntaxException("Illegal value of $skip option!", e,
-                  UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION,
-                  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);
-            topOption.setText(option.value);
-            try {
-              topOption.setValue(Integer.parseInt(option.value));
-            } catch (final NumberFormatException e) {
-              throw new UriParserSyntaxException("Illegal value of $top option!", e,
-                  UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION,
-                  option.name, option.value);
-            }
-            systemOption = topOption;
-
-          } else if (option.name.equals(SystemQueryOptionKind.COUNT.toString())) {
-            CountOptionImpl inlineCountOption = new CountOptionImpl();
-            inlineCountOption.setName(option.name);
-            inlineCountOption.setText(option.value);
-            if (option.value.equals("true") || option.value.equals("false")) {
-              inlineCountOption.setValue(Boolean.parseBoolean(option.value));
-            } else {
-              throw new UriParserSyntaxException("Illegal value of $count option!",
-                  UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION,
-                  option.name, option.value);
-            }
-            systemOption = inlineCountOption;
+        } else if (optionName.equals(SystemQueryOptionKind.SKIPTOKEN.toString())) {
+          SkipTokenOptionImpl skipTokenOption = new SkipTokenOptionImpl();
+          skipTokenOption.setText(optionValue);
+          skipTokenOption.setValue(optionValue);
+          systemOption = skipTokenOption;
 
-          } else {
-            throw new UriParserSyntaxException("Unknown system query option!",
-                UriParserSyntaxException.MessageKeys.UNKNOWN_SYSTEM_QUERY_OPTION, option.name);
-          }
+        } else if (optionName.equals(SystemQueryOptionKind.TOP.toString())) {
+          TopOptionImpl topOption = new TopOptionImpl();
+          topOption.setText(optionValue);
           try {
-            context.contextUriInfo.setSystemQueryOption(systemOption);
-          } catch (final ODataRuntimeException e) {
-            throw new UriParserSyntaxException("Double system query option!", e,
-                UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION, option.name);
+            topOption.setValue(Integer.parseInt(optionValue));
+          } catch (final NumberFormatException e) {
+            throw new UriParserSyntaxException("Illegal value of $top option!", e,
+                UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION,
+                optionName, optionValue);
           }
+          systemOption = topOption;
 
-        } else if (option.name.startsWith(AT)) {
-          if (context.contextUriInfo.getAlias(option.name) == null) {
-            // 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 {
+        } else if (optionName.equals(SystemQueryOptionKind.COUNT.toString())) {
+          CountOptionImpl inlineCountOption = new CountOptionImpl();
+          inlineCountOption.setText(optionValue);
+          if (optionValue.equals("true") || optionValue.equals("false")) {
+            inlineCountOption.setValue(Boolean.parseBoolean(optionValue));
+          } else {
+            throw new UriParserSyntaxException("Illegal value of $count option!",
+                UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION,
+                optionName, optionValue);
+          }
+          systemOption = inlineCountOption;
+
+        } else {
+          throw new UriParserSyntaxException("Unknown system query option!",
+              UriParserSyntaxException.MessageKeys.UNKNOWN_SYSTEM_QUERY_OPTION, optionName);
+        }
+        try {
+          context.contextUriInfo.setSystemQueryOption(systemOption);
+        } catch (final ODataRuntimeException e) {
+          throw new UriParserSyntaxException("Double system query option!", e,
+              UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION, optionName);
+        }
+
+      } else if (optionName.startsWith(AT)) {
+        if (context.contextUriInfo.getAlias(optionName) == null) {
+          // TODO: Create a proper alias-value parser that can parse also common expressions.
+          Expression expression = null;
+          UriTokenizer aliasTokenizer = new UriTokenizer(optionValue);
+          if (aliasTokenizer.next(TokenKind.jsonArrayOrObject)) {
+            if (!aliasTokenizer.next(TokenKind.EOF)) {
+              throw new UriParserSyntaxException("Illegal value for alias '" + optionName + "'.",
+                  UriParserSyntaxException.MessageKeys.SYNTAX);
+            }
+          } else {
+            try {
               final FilterExpressionEOFContext filterExpCtx =
-                  (FilterExpressionEOFContext) parseRule(option.value, ParserEntryRules.FilterExpression);
+                  (FilterExpressionEOFContext) parseRule(optionValue, ParserEntryRules.FilterExpression);
               expression = ((FilterOption) uriParseTreeVisitor.visitFilterExpressionEOF(filterExpCtx))
                   .getExpression();
+            } catch (final ParseCancellationException e) {
+              throw e.getCause() instanceof UriParserException ?
+                  (UriParserException) e.getCause() :
+                  new UriParserSyntaxException("Syntax error", e, UriParserSyntaxException.MessageKeys.SYNTAX);
             }
-            context.contextUriInfo.addAlias((AliasQueryOption) new AliasQueryOptionImpl()
-                .setAliasValue(expression)
-                .setName(option.name)
-                .setText(NULL.equals(option.value) ? null : option.value));
-          } else {
-            throw new UriParserSyntaxException("Alias already specified! Name: " + option.name,
-                UriParserSyntaxException.MessageKeys.DUPLICATED_ALIAS, option.name);
           }
-
+          context.contextUriInfo.addAlias((AliasQueryOption) new AliasQueryOptionImpl()
+              .setAliasValue(expression)
+              .setName(optionName)
+              .setText(NULL.equals(optionValue) ? null : optionValue));
         } else {
-          context.contextUriInfo.addCustomQueryOption((CustomQueryOption)
-              new CustomQueryOptionImpl()
-                  .setName(option.name)
-                  .setText(option.value));
+          throw new UriParserSyntaxException("Alias already specified! Name: " + optionName,
+              UriParserSyntaxException.MessageKeys.DUPLICATED_ALIAS, optionName);
         }
-      }
 
-      return context.contextUriInfo;
-    } catch (ParseCancellationException e) {
-      throw e.getCause() instanceof UriParserException ?
-          (UriParserException) e.getCause() :
-          new UriParserSyntaxException("Syntax error", e, UriParserSyntaxException.MessageKeys.SYNTAX);
+      } else {
+        context.contextUriInfo.addCustomQueryOption((CustomQueryOption) option);
+      }
     }
+
+    return context.contextUriInfo;
   }
 
   private void ensureLastSegment(final String segment, final int pos, final int size)
@@ -349,6 +376,30 @@ public class Parser {
     return index > 0 && index < value.length() - 1 && index == value.lastIndexOf('/');
   }
 
+  protected static EdmType getTypeInformation(final UriResourcePartTyped resourcePart) {
+    EdmType type = null;
+    if (resourcePart instanceof UriResourceWithKeysImpl) {
+      final UriResourceWithKeysImpl lastPartWithKeys = (UriResourceWithKeysImpl) resourcePart;
+      if (lastPartWithKeys.getTypeFilterOnEntry() != null) {
+        type = lastPartWithKeys.getTypeFilterOnEntry();
+      } else if (lastPartWithKeys.getTypeFilterOnCollection() != null) {
+        type = lastPartWithKeys.getTypeFilterOnCollection();
+      } else {
+        type = lastPartWithKeys.getType();
+      }
+
+    } else if (resourcePart instanceof UriResourceTypedImpl) {
+      final UriResourceTypedImpl lastPartTyped = (UriResourceTypedImpl) resourcePart;
+      type = lastPartTyped.getTypeFilter() == null ?
+          lastPartTyped.getType() :
+          lastPartTyped.getTypeFilter();
+    } else {
+      type = resourcePart.getType();
+    }
+
+    return type;
+  }
+
   private ParserRuleContext parseRule(final String input, final ParserEntryRules entryPoint)
       throws UriParserSyntaxException {
     UriParserParser parser = null;
@@ -362,17 +413,11 @@ public class Parser {
     try {
 
       // create parser
-      if (logLevel > 0) {
-        //TODO: Discuss if we should keep this code
-        lexer = new UriLexer(new ANTLRInputStream(input));
-        showTokens(input, lexer.getAllTokens());
-      }
-
       lexer = new UriLexer(new ANTLRInputStream(input));
       parser = new UriParserParser(new CommonTokenStream(lexer));
 
       // Set error strategy
-      addStage1ErrorStategy(parser);
+      addStage1ErrorStrategy(parser);
 
       // Set error collector
       addStage1ErrorListener(parser);
@@ -394,9 +439,6 @@ public class Parser {
         lexer.mode(Lexer.DEFAULT_MODE);
         ret = parser.expandItemsEOF();
         break;
-      case Select:
-        ret = parser.selectEOF();
-        break;
       default:
         break;
 
@@ -411,7 +453,7 @@ public class Parser {
         parser = new UriParserParser(new CommonTokenStream(lexer));
 
         // Set error strategy
-        addStage2ErrorStategy(parser);
+        addStage2ErrorStrategy(parser);
 
         // Set error collector
         addStage2ErrorListener(parser);
@@ -433,9 +475,6 @@ public class Parser {
           lexer.mode(Lexer.DEFAULT_MODE);
           ret = parser.expandItemsEOF();
           break;
-        case Select:
-          ret = parser.selectEOF();
-          break;
         default:
           break;
         }
@@ -454,13 +493,13 @@ public class Parser {
     return ret;
   }
 
-  protected void addStage1ErrorStategy(final UriParserParser parser) {
+  protected void addStage1ErrorStrategy(final UriParserParser parser) {
     // Throw exception at first syntax error
     parser.setErrorHandler(new BailErrorStrategy());
 
   }
 
-  protected void addStage2ErrorStategy(final UriParserParser parser) {
+  protected void addStage2ErrorStrategy(final UriParserParser parser) {
     // Throw exception at first syntax error
     parser.setErrorHandler(new BailErrorStrategy());
   }
@@ -468,36 +507,10 @@ public class Parser {
   protected void addStage1ErrorListener(final UriParserParser parser) {
     // No error logging to System.out or System.err, only exceptions used (depending on ErrorStrategy)
     parser.removeErrorListeners();
-    parser.addErrorListener(new CheckFullContextListener());
-
   }
 
   protected void addStage2ErrorListener(final UriParserParser parser) {
     // No error logging to System.out or System.err, only exceptions used (depending on ErrorStrategy)
     parser.removeErrorListeners();
   }
-
-  public void showTokens(final String input, final List<? extends Token> list) {
-    boolean first = true;
-    System.out.println("input: " + input);
-    String nL = "\n";
-    StringBuilder out = new StringBuilder("[").append(nL);
-    for (Token token : list) {
-      if (!first) {
-        out.append(",");
-        first = false;
-      }
-      int index = token.getType();
-      out.append("\"").append(token.getText()).append("\"").append("     ");
-      if (index != -1) {
-        out.append(UriLexer.VOCABULARY.getDisplayName(index));
-      } else {
-        out.append(index);
-      }
-      out.append(nL);
-    }
-    out.append(']');
-    System.out.println("tokens: " + out.toString());
-  }
-
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d7e23bf8/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/RawUri.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/RawUri.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/RawUri.java
deleted file mode 100644
index 42e0a0f..0000000
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/RawUri.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.List;
-
-public class RawUri {
-  public String uri;
-  public String scheme;
-  public String authority;
-  public String path;
-  public String queryOptionString;
-  public String fragment;
-  public List<QueryOption> queryOptionList;
-  public List<QueryOption> queryOptionListDecoded;
-
-  public List<String> pathSegmentList;
-  public List<String> pathSegmentListDecoded;
-
-  public static class QueryOption {
-    public String name;
-    public String value;
-
-    QueryOption(final String name, final String value) {
-      this.name = name;
-      this.value = value;
-    }
-
-  }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d7e23bf8/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/SelectParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/SelectParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/SelectParser.java
new file mode 100644
index 0000000..3d933d2
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/SelectParser.java
@@ -0,0 +1,241 @@
+/*
+ * 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.List;
+
+import org.apache.olingo.commons.api.edm.Edm;
+import org.apache.olingo.commons.api.edm.EdmAction;
+import org.apache.olingo.commons.api.edm.EdmComplexType;
+import org.apache.olingo.commons.api.edm.EdmFunction;
+import org.apache.olingo.commons.api.edm.EdmNavigationProperty;
+import org.apache.olingo.commons.api.edm.EdmProperty;
+import org.apache.olingo.commons.api.edm.EdmStructuredType;
+import org.apache.olingo.commons.api.edm.FullQualifiedName;
+import org.apache.olingo.commons.api.edm.constants.EdmTypeKind;
+import org.apache.olingo.server.api.uri.UriInfoKind;
+import org.apache.olingo.server.api.uri.UriResourcePartTyped;
+import org.apache.olingo.server.api.uri.queryoption.SelectItem;
+import org.apache.olingo.server.api.uri.queryoption.SelectOption;
+import org.apache.olingo.server.core.uri.UriInfoImpl;
+import org.apache.olingo.server.core.uri.UriResourceActionImpl;
+import org.apache.olingo.server.core.uri.UriResourceComplexPropertyImpl;
+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.parser.UriTokenizer.TokenKind;
+import org.apache.olingo.server.core.uri.queryoption.SelectItemImpl;
+import org.apache.olingo.server.core.uri.queryoption.SelectOptionImpl;
+import org.apache.olingo.server.core.uri.validator.UriValidationException;
+
+public class SelectParser {
+
+  private final Edm edm;
+
+  public SelectParser(final Edm edm) {
+    this.edm = edm;
+  }
+
+  public SelectOption parse(UriTokenizer tokenizer, final EdmStructuredType referencedType,
+      final boolean referencedIsCollection) throws UriParserException, UriValidationException {
+    List<SelectItem> selectItems = new ArrayList<SelectItem>();
+    SelectItem item;
+    do {
+      item = parseItem(tokenizer, referencedType, referencedIsCollection);
+      selectItems.add(item);
+    } while (tokenizer.next(TokenKind.COMMA));
+
+    return new SelectOptionImpl().setSelectItems(selectItems);
+  }
+
+  private SelectItem parseItem(UriTokenizer tokenizer,
+      final EdmStructuredType referencedType, final boolean referencedIsCollection) throws UriParserException {
+    SelectItemImpl item = new SelectItemImpl();
+    if (tokenizer.next(TokenKind.STAR)) {
+      item.setStar(true);
+
+    } else if (tokenizer.next(TokenKind.QualifiedName)) {
+      // The namespace or its alias could consist of dot-separated OData identifiers.
+      final FullQualifiedName allOperationsInSchema = parseAllOperationsInSchema(tokenizer);
+      if (allOperationsInSchema != null) {
+        item.addAllOperationsInSchema(allOperationsInSchema);
+
+      } else {
+        ensureReferencedTypeNotNull(referencedType);
+        final FullQualifiedName qualifiedName = new FullQualifiedName(tokenizer.getText());
+        EdmStructuredType type = edm.getEntityType(qualifiedName);
+        if (type == null) {
+          type = edm.getComplexType(qualifiedName);
+        }
+        if (type == null) {
+          item.setResourcePath(new UriInfoImpl().setKind(UriInfoKind.resource).addResourcePart(
+              parseBoundOperation(tokenizer, qualifiedName, referencedType, referencedIsCollection)));
+
+        } else {
+          if (type.compatibleTo(referencedType)) {
+            item.setTypeFilter(type);
+            if (tokenizer.next(TokenKind.SLASH)) {
+              requireNext(tokenizer, TokenKind.ODataIdentifier);
+              UriInfoImpl resource = new UriInfoImpl().setKind(UriInfoKind.resource);
+              addSelectPath(tokenizer, type, resource);
+              item.setResourcePath(resource);
+            }
+          } else {
+            throw new UriParserSemanticException("The type cast is not compatible.",
+                UriParserSemanticException.MessageKeys.INCOMPATIBLE_TYPE_FILTER, type.getName());
+          }
+        }
+      }
+
+    } else {
+      requireNext(tokenizer, TokenKind.ODataIdentifier);
+      // The namespace or its alias could be a single OData identifier.
+      final FullQualifiedName allOperationsInSchema = parseAllOperationsInSchema(tokenizer);
+      if (allOperationsInSchema != null) {
+        item.addAllOperationsInSchema(allOperationsInSchema);
+
+      } else {
+        ensureReferencedTypeNotNull(referencedType);
+        UriInfoImpl resource = new UriInfoImpl().setKind(UriInfoKind.resource);
+        addSelectPath(tokenizer, referencedType, resource);
+        item.setResourcePath(resource);
+      }
+    }
+
+    return item;
+  }
+
+  private FullQualifiedName parseAllOperationsInSchema(UriTokenizer tokenizer) throws UriParserException {
+    final String name = tokenizer.getText();
+    if (tokenizer.next(TokenKind.DOT)) {
+      if (tokenizer.next(TokenKind.STAR)) {
+        // TODO: Validate the namespace without loading the whole schema.
+        return new FullQualifiedName(name, tokenizer.getText());
+      } else {
+        throw new UriParserSemanticException("Expected star after dot.",
+            UriParserSemanticException.MessageKeys.UNKNOWN_PART, "");
+      }
+    }
+    return null;
+  }
+
+  private void ensureReferencedTypeNotNull(final EdmStructuredType referencedType) throws UriParserException {
+    if (referencedType == null) {
+      throw new UriParserSemanticException("The referenced part is not typed.",
+          UriParserSemanticException.MessageKeys.ONLY_FOR_TYPED_PARTS, "select");
+    }
+  }
+
+  private UriResourcePartTyped parseBoundOperation(UriTokenizer tokenizer, final FullQualifiedName qualifiedName,
+      final EdmStructuredType referencedType, final boolean referencedIsCollection) throws UriParserException {
+    final EdmAction boundAction = edm.getBoundAction(qualifiedName,
+        referencedType.getFullQualifiedName(),
+        referencedIsCollection);
+    if (boundAction == null) {
+      final List<String> parameterNames = parseFunctionParameterNames(tokenizer);
+      final EdmFunction boundFunction = edm.getBoundFunction(qualifiedName,
+          referencedType.getFullQualifiedName(), referencedIsCollection, parameterNames);
+      if (boundFunction == null) {
+        throw new UriParserSemanticException("Function not found.",
+            UriParserSemanticException.MessageKeys.UNKNOWN_PART, qualifiedName.getFullQualifiedNameAsString());
+      } else {
+        return new UriResourceFunctionImpl().setFunction(boundFunction);
+      }
+    } else {
+      return new UriResourceActionImpl().setAction(boundAction);
+    }
+  }
+
+  private List<String> parseFunctionParameterNames(UriTokenizer tokenizer) throws UriParserException {
+    List<String> names = new ArrayList<String>();
+    if (tokenizer.next(TokenKind.OPEN)) {
+      do {
+        requireNext(tokenizer, TokenKind.ODataIdentifier);
+        names.add(tokenizer.getText());
+      } while (tokenizer.next(TokenKind.COMMA));
+      requireNext(tokenizer, TokenKind.CLOSE);
+    }
+    return names;
+  }
+
+  private void addSelectPath(UriTokenizer tokenizer, final EdmStructuredType referencedType, UriInfoImpl resource)
+      throws UriParserException {
+    final String name = tokenizer.getText();
+    final EdmProperty property = referencedType.getStructuralProperty(name);
+
+    if (property == null) {
+      final EdmNavigationProperty navigationProperty = referencedType.getNavigationProperty(name);
+      if (navigationProperty == null) {
+        throw new UriParserSemanticException("Selected property not found.",
+            UriParserSemanticException.MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE,
+            referencedType.getName(), name);
+      } else {
+        resource.addResourcePart(new UriResourceNavigationPropertyImpl().setNavigationProperty(navigationProperty));
+      }
+
+    } else if (property.isPrimitive()
+        || property.getType().getKind() == EdmTypeKind.ENUM
+        || property.getType().getKind() == EdmTypeKind.DEFINITION) {
+      resource.addResourcePart(new UriResourcePrimitivePropertyImpl().setProperty(property));
+
+    } else {
+      UriResourceComplexPropertyImpl complexPart = new UriResourceComplexPropertyImpl().setProperty(property);
+      resource.addResourcePart(complexPart);
+      if (tokenizer.next(TokenKind.SLASH)) {
+        if (tokenizer.next(TokenKind.QualifiedName)) {
+          final FullQualifiedName qualifiedName = new FullQualifiedName(tokenizer.getText());
+          final EdmComplexType type = edm.getComplexType(qualifiedName);
+          if (type == null) {
+            throw new UriParserSemanticException("Type not found.",
+                UriParserSemanticException.MessageKeys.UNKNOWN_TYPE, qualifiedName.getFullQualifiedNameAsString());
+          } else if (type.compatibleTo(property.getType())) {
+            complexPart.setTypeFilter(type);
+            if (tokenizer.next(TokenKind.SLASH)) {
+              if (tokenizer.next(TokenKind.ODataIdentifier)) {
+                addSelectPath(tokenizer, type, resource);
+              } else {
+                throw new UriParserSemanticException("Unknown part after '/'.",
+                    UriParserSemanticException.MessageKeys.UNKNOWN_PART, "");
+              }
+            }
+          } else {
+            throw new UriParserSemanticException("The type cast is not compatible.",
+                UriParserSemanticException.MessageKeys.INCOMPATIBLE_TYPE_FILTER, type.getName());
+          }
+        } else if (tokenizer.next(TokenKind.ODataIdentifier)) {
+          addSelectPath(tokenizer, (EdmStructuredType) property.getType(), resource);
+        } else if (tokenizer.next(TokenKind.SLASH)) {
+          throw new UriParserSyntaxException("Illegal $select expression.",
+              UriParserSyntaxException.MessageKeys.SYNTAX);
+        } else {
+          throw new UriParserSemanticException("Unknown part after '/'.",
+              UriParserSemanticException.MessageKeys.UNKNOWN_PART, "");
+        }
+      }
+    }
+  }
+
+  private void requireNext(UriTokenizer tokenizer, final TokenKind kind) throws UriParserSyntaxException {
+    if (!tokenizer.next(kind)) {
+      throw new UriParserSyntaxException("Illegal $select expression.",
+          UriParserSyntaxException.MessageKeys.SYNTAX);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d7e23bf8/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriContext.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriContext.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriContext.java
index b6b6fda..c0db85b 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriContext.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriContext.java
@@ -18,11 +18,11 @@
  */
 package org.apache.olingo.server.core.uri.parser;
 
-import java.util.Stack;
+import java.util.ArrayDeque;
+import java.util.Deque;
 
 import org.apache.olingo.commons.api.edm.EdmType;
 import org.apache.olingo.server.core.uri.UriInfoImpl;
-import org.apache.olingo.server.core.uri.parser.UriParseTreeVisitor.TypeInformation;
 import org.apache.olingo.server.core.uri.queryoption.ExpandItemImpl;
 import org.apache.olingo.server.core.uri.queryoption.SelectItemImpl;
 
@@ -33,9 +33,9 @@ import org.apache.olingo.server.core.uri.queryoption.SelectItemImpl;
 public class UriContext {
 
   public static class LambdaVariables {
-    public boolean isCollection;
     public String name;
     public EdmType type;
+    public boolean isCollection;
   }
 
   /**
@@ -43,11 +43,14 @@ public class UriContext {
    * As lambda functions can be nested there may be more than one allowed lambda variables at a time while parsing a
    * $filter or $orderby expressions.
    */
-  public Stack<LambdaVariables> allowedLambdaVariables;
+  public Deque<LambdaVariables> allowedLambdaVariables;
   /**
    * Used to stack type information for nested $expand, $filter query options and other cases.
    */
-  public Stack<TypeInformation> contextTypes;
+  public Deque<EdmType> contextTypes;
+
+  /** Whether the context types are collections. */
+  public boolean isCollection;
 
   // CHECKSTYLE:OFF (Maven checkstyle)
   /**
@@ -106,8 +109,8 @@ public class UriContext {
     contextExpandItemPath = null;
     contextReadingFunctionParameters = false;
     contextSelectItem = null;
-    contextTypes = new Stack<UriParseTreeVisitor.TypeInformation>();
-    allowedLambdaVariables = new Stack<UriContext.LambdaVariables>();
+    contextTypes = new ArrayDeque<EdmType>();
+    allowedLambdaVariables = new ArrayDeque<UriContext.LambdaVariables>();
 
   }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d7e23bf8/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 4649ac5..4dd7e1c 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
@@ -25,53 +25,42 @@ import java.util.LinkedList;
 import java.util.List;
 
 import org.apache.olingo.commons.core.Decoder;
+import org.apache.olingo.server.api.uri.queryoption.QueryOption;
+import org.apache.olingo.server.core.uri.queryoption.CustomQueryOptionImpl;
 
 public class UriDecoder {
 
-  public static RawUri decodeUri(final String path, final String query, final String fragment,
-      final int skipSegments) throws UriParserSyntaxException {
-    RawUri rawUri = new RawUri();
-
-    rawUri.path = path;
-    rawUri.queryOptionString = query;
-    rawUri.fragment = fragment;
-
-    rawUri.pathSegmentList = splitPath(path, skipSegments);
-    rawUri.queryOptionList = splitOptions(query);
-    decode(rawUri);
-
-    return rawUri;
-  }
-
-  private static void decode(final RawUri rawUri) throws UriParserSyntaxException {
-    rawUri.pathSegmentListDecoded = new ArrayList<String>();
-    for (String segment : rawUri.pathSegmentList) {
-      rawUri.pathSegmentListDecoded.add(decode(segment));
-    }
-
-    rawUri.queryOptionListDecoded = new ArrayList<RawUri.QueryOption>();
-    for (RawUri.QueryOption optionPair : rawUri.queryOptionList) {
-      rawUri.queryOptionListDecoded.add(new RawUri.QueryOption(
-          decode(optionPair.name),
-          decode(optionPair.value)));
+  /** Splits the path string at '/' characters and percent-decodes the resulting path segments. */
+  protected static List<String> splitAndDecodePath(final String path) throws UriParserSyntaxException {
+    List<String> pathSegmentsDecoded = new ArrayList<String>();
+    for (final String segment : splitSkipEmpty(path, '/')) {
+      pathSegmentsDecoded.add(decode(segment));
     }
+    return pathSegmentsDecoded;
   }
 
-  private static List<RawUri.QueryOption> splitOptions(final String queryOptionString) {
-    if (queryOptionString == null) {
+  /**
+   * Splits the query-option string at '&' characters, the resulting parts at '=' characters,
+   * and separately percent-decodes names and values of the resulting name-value pairs.
+   */
+  protected static List<QueryOption> splitAndDecodeOptions(final String queryOptionString)
+      throws UriParserSyntaxException {
+    if (queryOptionString == null || queryOptionString.isEmpty()) {
       return Collections.emptyList();
     }
 
-    List<RawUri.QueryOption> queryOptionList = new ArrayList<RawUri.QueryOption>();
-    for (String option : splitSkipEmpty(queryOptionString, '&')) {
+    List<QueryOption> queryOptions = new ArrayList<QueryOption>();
+    for (final String option : splitSkipEmpty(queryOptionString, '&')) {
       final List<String> pair = splitFirst(option, '=');
-      queryOptionList.add(new RawUri.QueryOption(pair.get(0), pair.get(1)));
+      queryOptions.add(new CustomQueryOptionImpl()
+          .setName(decode(pair.get(0)))
+          .setText(decode(pair.get(1))));
     }
-    return queryOptionList;
+    return queryOptions;
   }
 
   private static List<String> splitFirst(final String input, final char c) {
-    int pos = input.indexOf(c, 0);
+    int pos = input.indexOf(c);
     if (pos >= 0) {
       return Arrays.asList(input.substring(0, pos), input.substring(pos + 1));
     } else {
@@ -79,21 +68,14 @@ public class UriDecoder {
     }
   }
 
-  private static List<String> splitPath(final String path, final int skipSegments) {
-    List<String> list = splitSkipEmpty(path, '/');
-
-    return skipSegments > 0 ? list.subList(skipSegments, list.size()) : list;
-  }
-
   /**
-   * Split the input string at given character and drop all empty elements.
-   *
+   * Splits the input string at the given character and drops all empty elements.
    * @param input string to split
    * @param c character at which to split
    * @return list of elements (can be empty)
    */
-  static List<String> splitSkipEmpty(final String input, final char c) {
-    if(input.isEmpty() || input.length() == 1 && input.charAt(0) == c) {
+  private static List<String> splitSkipEmpty(final String input, final char c) {
+    if (input.isEmpty() || input.length() == 1 && input.charAt(0) == c) {
       return Collections.emptyList();
     }
 
@@ -103,20 +85,20 @@ public class UriDecoder {
     int end;
 
     while ((end = input.indexOf(c, start)) >= 0) {
-      if(start != end) {
+      if (start != end) {
         list.add(input.substring(start, end));
       }
       start = end + 1;
     }
 
-    if(input.charAt(input.length()-1) != c) {
+    if (input.charAt(input.length() - 1) != c) {
       list.add(input.substring(start));
     }
 
     return list;
   }
 
-  public static String decode(final String encoded) throws UriParserSyntaxException {
+  private 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/d7e23bf8/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 8740d66..c58327b 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
@@ -82,9 +82,7 @@ import org.apache.olingo.server.core.uri.UriResourceStartingTypeFilterImpl;
 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.antlr.UriLexer;
-import org.apache.olingo.server.core.uri.antlr.UriParserBaseVisitor;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser;
+import org.apache.olingo.server.core.uri.antlr.*;
 import org.apache.olingo.server.core.uri.antlr.UriParserParser.AllEOFContext;
 import org.apache.olingo.server.core.uri.antlr.UriParserParser.AllExprContext;
 import org.apache.olingo.server.core.uri.antlr.UriParserParser.AltAddContext;
@@ -106,7 +104,6 @@ import org.apache.olingo.server.core.uri.antlr.UriParserParser.CeilingMethodCall
 import org.apache.olingo.server.core.uri.antlr.UriParserParser.ConcatMethodCallExprContext;
 import org.apache.olingo.server.core.uri.antlr.UriParserParser.ConstSegmentContext;
 import org.apache.olingo.server.core.uri.antlr.UriParserParser.ContainsMethodCallExprContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.CrossjoinEOFContext;
 import org.apache.olingo.server.core.uri.antlr.UriParserParser.DateLiteralContext;
 import org.apache.olingo.server.core.uri.antlr.UriParserParser.DateMethodCallExprContext;
 import org.apache.olingo.server.core.uri.antlr.UriParserParser.DatetimeoffsetLiteralContext;
@@ -151,7 +148,6 @@ import org.apache.olingo.server.core.uri.antlr.UriParserParser.NamespaceContext;
 import org.apache.olingo.server.core.uri.antlr.UriParserParser.NaninfinityLiteralContext;
 import org.apache.olingo.server.core.uri.antlr.UriParserParser.NowMethodCallExprContext;
 import org.apache.olingo.server.core.uri.antlr.UriParserParser.NullruleLiteralContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.OdataIdentifierContext;
 import org.apache.olingo.server.core.uri.antlr.UriParserParser.OrderByContext;
 import org.apache.olingo.server.core.uri.antlr.UriParserParser.OrderByEOFContext;
 import org.apache.olingo.server.core.uri.antlr.UriParserParser.OrderByItemContext;
@@ -226,20 +222,6 @@ import org.apache.olingo.server.core.uri.queryoption.expression.UnaryImpl;
  */
 public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
 
-  public class TypeInformation {
-
-    boolean isCollection;
-
-    EdmType type;
-
-    TypeInformation(final EdmType type, final boolean isCollection) {
-      this.type = type;
-      this.isCollection = isCollection;
-    }
-
-    public TypeInformation() {}
-  }
-
   public UriContext context = null;
 
   public Edm edm;
@@ -277,36 +259,6 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
     return null;
   }
 
-  TypeInformation getTypeInformation(final UriResource lastResourcePart) {
-
-    TypeInformation typeInformation = new TypeInformation();
-    if (lastResourcePart instanceof UriResourceWithKeysImpl) {
-      UriResourceWithKeysImpl lastPartWithKeys = (UriResourceWithKeysImpl) lastResourcePart;
-
-      if (lastPartWithKeys.getTypeFilterOnEntry() != null) {
-        typeInformation.type = lastPartWithKeys.getTypeFilterOnEntry();
-      } else if (lastPartWithKeys.getTypeFilterOnCollection() != null) {
-        typeInformation.type = lastPartWithKeys.getTypeFilterOnCollection();
-      } else {
-        typeInformation.type = lastPartWithKeys.getType();
-      }
-      typeInformation.isCollection = lastPartWithKeys.isCollection();
-
-    } else if (lastResourcePart instanceof UriResourceTypedImpl) {
-      UriResourceTypedImpl lastPartTyped = (UriResourceTypedImpl) lastResourcePart;
-
-      if (lastPartTyped.getTypeFilter() != null) {
-        typeInformation.type = lastPartTyped.getTypeFilter();
-      } else {
-        typeInformation.type = lastPartTyped.getType();
-      }
-
-      typeInformation.isCollection = lastPartTyped.isCollection();
-    }
-
-    return typeInformation;
-  }
-
   public UriResourceTypedImpl readResourcePathSegment(final PathSegmentContext ctx) {
 
     final boolean checkFirst =
@@ -318,10 +270,10 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
     boolean searchInContainer = true;
     // validate if context type and according property is available
     // otherwise search in container for first element
-    if (checkFirst && ctx.vNS == null && !context.contextTypes.empty()) {
-      TypeInformation source = context.contextTypes.peek();
-      if (source.type instanceof EdmStructuredType) {
-        EdmStructuredType str = (EdmStructuredType) source.type;
+    if (checkFirst && ctx.vNS == null && !context.contextTypes.isEmpty()) {
+      EdmType sourceType = context.contextTypes.peek();
+      if (sourceType instanceof EdmStructuredType) {
+        EdmStructuredType str = (EdmStructuredType) sourceType;
         EdmElement property = str.getProperty(odi);
         if (property != null) {
           searchInContainer = false;
@@ -418,11 +370,12 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
       }
     }
 
-    final TypeInformation source;
+    EdmType sourceType;
+    boolean sourceIsCollection = false;
     final UriResource lastResourcePart = context.contextUriInfo.getLastResourcePart();
 
     if (lastResourcePart == null) {
-      if (context.contextTypes.empty()) {
+      if (context.contextTypes.isEmpty()) {
         if (checkFirst && ctx.vNS == null) {
           throw wrap(new UriParserSemanticException(
               "Cannot find EntitySet, Singleton, ActionImport or FunctionImport with name '" + odi + "'.",
@@ -432,15 +385,15 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
             "Resource part '" + odi + "' can only applied on typed resource parts",
             UriParserSemanticException.MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS, odi));
       }
-      source = context.contextTypes.peek();
+      sourceType = context.contextTypes.peek();
+      sourceIsCollection = context.isCollection;
+    } else if (lastResourcePart instanceof UriResourcePartTyped) {
+      sourceType = Parser.getTypeInformation((UriResourcePartTyped) lastResourcePart);
+      sourceIsCollection = ((UriResourcePartTyped) lastResourcePart).isCollection();
     } else {
-      source = getTypeInformation(lastResourcePart);
-
-      if (source.type == null) {
-        throw wrap(new UriParserSemanticException(
-            "Resource part '" + odi + "' can only be applied on typed resource parts.",
-            UriParserSemanticException.MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS, odi));
-      }
+      throw wrap(new UriParserSemanticException(
+          "Resource part '" + odi + "' can only be applied on typed resource parts.",
+          UriParserSemanticException.MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS, odi));
     }
 
     if (ctx.vNS == null) { // without namespace
@@ -456,7 +409,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
         return null;
       }
 
-      if (!(source.type instanceof EdmStructuredType)) {
+      if (!(sourceType instanceof EdmStructuredType)) {
         throw wrap(new UriParserSemanticException(
             "Cannot parse '" + odi + "'; previous path segment is not a structural type.",
             UriParserSemanticException.MessageKeys.RESOURCE_PART_MUST_BE_PRECEDED_BY_STRUCTURAL_TYPE, odi));
@@ -465,12 +418,12 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
       if ((ctx.depth() <= 2 // path evaluation for the resource path
           || lastResourcePart instanceof UriResourceTypedImpl
           || lastResourcePart instanceof UriResourceNavigationPropertyImpl)
-          && source.isCollection) {
+          && sourceIsCollection) {
         throw wrap(new UriParserSemanticException("Property '" + odi + "' is not allowed after collection.",
             UriParserSemanticException.MessageKeys.PROPERTY_AFTER_COLLECTION, odi));
       }
 
-      EdmStructuredType structType = (EdmStructuredType) source.type;
+      EdmStructuredType structType = (EdmStructuredType) sourceType;
 
       EdmElement property = structType.getProperty(odi);
       if (property == null) {
@@ -520,12 +473,12 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
       FullQualifiedName fullFilterName = getFullNameFromContext(ctx.vNS, odi);
 
       // EdmType lastType = getLastType(lastTyped);
-      if (source.type instanceof EdmEntityType) {
+      if (sourceType instanceof EdmEntityType) {
 
         EdmEntityType filterEntityType = edm.getEntityType(fullFilterName);
         if (filterEntityType != null) {
           // is entity type cast
-          if (!(filterEntityType.compatibleTo(source.type))) {
+          if (!(filterEntityType.compatibleTo(sourceType))) {
             throw wrap(new UriParserSemanticException(
                 "Entity typefilter not compatible to previous path segment: " + fullFilterName.toString(),
                 UriParserSemanticException.MessageKeys.INCOMPATIBLE_TYPE_FILTER, fullFilterName.toString()));
@@ -535,8 +488,8 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
             // this may be the case if a member expression within a filter starts with a typeCast
             UriResourceStartingTypeFilterImpl uriResource = new UriResourceStartingTypeFilterImpl()
                 .setType(filterEntityType)
-                .setCollection(source.isCollection);
-            if (source.isCollection) {
+                .setCollection(sourceIsCollection);
+            if (sourceIsCollection) {
               uriResource.setCollectionTypeFilter(filterEntityType);
             } else {
               uriResource.setEntryTypeFilter(filterEntityType);
@@ -590,18 +543,18 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
           }
         }
 
-      } else if (source.type instanceof EdmComplexType) {
+      } else if (sourceType instanceof EdmComplexType) {
 
         EdmComplexType filterComplexType = edm.getComplexType(fullFilterName);
 
         if (filterComplexType != null) {
 
           // is complex type cast
-          if (!(filterComplexType.compatibleTo(source.type))) {
+          if (!(filterComplexType.compatibleTo(sourceType))) {
             throw wrap(new UriParserSemanticException(
-                "Complex typefilter '" + getName(source.type) + "'not compatible type of previous path segment '"
+                "Complex typefilter '" + getName(sourceType) + "'not compatible type of previous path segment '"
                     + getName(filterComplexType) + "'",
-                UriParserSemanticException.MessageKeys.INCOMPATIBLE_TYPE_FILTER, getName(source.type)));
+                UriParserSemanticException.MessageKeys.INCOMPATIBLE_TYPE_FILTER, getName(sourceType)));
           }
 
           // is simple complex type cast
@@ -609,9 +562,9 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
             // this may be the case if a member expression within a filter starts with a typeCast
             UriResourceStartingTypeFilterImpl uriResource = new UriResourceStartingTypeFilterImpl()
                 .setType(filterComplexType)
-                .setCollection(source.isCollection);
+                .setCollection(sourceIsCollection);
 
-            if (source.isCollection) {
+            if (sourceIsCollection) {
               uriResource.setCollectionTypeFilter(filterComplexType);
             } else {
               uriResource.setEntryTypeFilter(filterComplexType);
@@ -666,10 +619,10 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
         }
       }
 
-      FullQualifiedName fullBindingTypeName = new FullQualifiedName(source.type.getNamespace(), source.type.getName());
+      FullQualifiedName fullBindingTypeName = sourceType.getFullQualifiedName();
 
       // check for action
-      EdmAction action = edm.getBoundAction(fullFilterName, fullBindingTypeName, source.isCollection);
+      EdmAction action = edm.getBoundAction(fullFilterName, fullBindingTypeName, sourceIsCollection);
       if (action != null) {
         UriResourceActionImpl pathInfoAction = new UriResourceActionImpl();
         pathInfoAction.setAction(action);
@@ -694,7 +647,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
         names.add(item.getName());
       }
 
-      EdmFunction function = edm.getBoundFunction(fullFilterName, fullBindingTypeName, source.isCollection, names);
+      EdmFunction function = edm.getBoundFunction(fullFilterName, fullBindingTypeName, sourceIsCollection, names);
 
       if (function != null) {
         UriResourceFunctionImpl pathInfoFunction = new UriResourceFunctionImpl()
@@ -767,7 +720,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
 
     UriContext.LambdaVariables var = new UriContext.LambdaVariables();
     var.name = ctx.vLV.getText();
-    var.type = getTypeInformation(obj).type;
+    var.type = Parser.getTypeInformation((UriResourcePartTyped) obj);
     var.isCollection = false;
 
     all.setLamdaVariable(ctx.vLV.getText());
@@ -907,11 +860,9 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
     context.contextUriInfo.setEntityTypeCast(type);
 
     // contextUriInfo = uriInfo;
-    context.contextTypes.push(new TypeInformation(context.contextUriInfo.getEntityTypeCast(), true));
+    context.contextTypes.push(context.contextUriInfo.getEntityTypeCast());
+    context.isCollection = true;  // TODO: check!
 
-    // @SuppressWarnings("unchecked")
-    // List<QueryOptionImpl> list = (List<QueryOptionImpl>) ctx.vEO.accept(this);
-    // uriInfo.setQueryOptions(list);
     return null;
   }
 
@@ -998,7 +949,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
 
       UriContext.LambdaVariables var = new UriContext.LambdaVariables();
       var.name = ctx.vLV.getText();
-      var.type = getTypeInformation(lastResourcePart).type;
+      var.type = Parser.getTypeInformation((UriResourcePartTyped) lastResourcePart);
       var.isCollection = false;
 
       any.setLamdaVariable(ctx.vLV.getText());
@@ -1147,33 +1098,6 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
   }
 
   @Override
-  public Object visitCrossjoinEOF(final CrossjoinEOFContext ctx) {
-    UriInfoImpl crossJoin = new UriInfoImpl().setKind(UriInfoKind.crossjoin);
-
-    for (OdataIdentifierContext obj : ctx.vlODI) {
-      String odi = obj.getText();
-      crossJoin.addEntitySetName(odi);
-
-      EdmEntitySet edmEntitySet = edmEntityContainer.getEntitySet(odi);
-      if (edmEntitySet == null) {
-        throw wrap(new UriParserSemanticException("Expected EntityTypeName",
-            UriParserSemanticException.MessageKeys.UNKNOWN_PART, odi));
-      }
-
-      EdmEntityType type = edmEntitySet.getEntityType();
-      if (type == null) {
-        throw wrap(new UriParserSemanticException("Expected EntityTypeName",
-            UriParserSemanticException.MessageKeys.UNKNOWN_ENTITY_TYPE, odi));
-      }
-      // contextUriInfo = uriInfo;
-      context.contextTypes.push(new TypeInformation(type, true));
-    }
-
-    context.contextUriInfo = crossJoin;
-    return null;
-  }
-
-  @Override
   public Object visitDateMethodCallExpr(final DateMethodCallExprContext ctx) {
     return new MethodImpl()
         .setMethod(MethodKind.DATE)
@@ -1372,23 +1296,24 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
     if (context.contextExpandItemPath == null) {
       // use the type of the last resource path segement
       UriResourceTypedImpl lastSegment = (UriResourceTypedImpl) context.contextUriInfo.getLastResourcePart();
-      targetType = getTypeInformation(lastSegment).type;
+      targetType = Parser.getTypeInformation(lastSegment);
       isColl = lastSegment.isCollection();
     } else {
       if (context.contextExpandItemPath.getResourcePath() == null) {
         // use the type of the last resource path segement
         UriResourceTypedImpl lastSegment = (UriResourceTypedImpl) context.contextUriInfo.getLastResourcePart();
-        targetType = getTypeInformation(lastSegment).type;
+        targetType = Parser.getTypeInformation(lastSegment);
         isColl = lastSegment.isCollection();
       } else {
         // use the type of the last ''expand'' path segement
         UriInfoImpl info = (UriInfoImpl) context.contextExpandItemPath.getResourcePath();
-        targetType = getTypeInformation(info.getLastResourcePart()).type;
+        targetType = Parser.getTypeInformation((UriResourcePartTyped) info.getLastResourcePart());
         isColl = ((UriResourcePartTyped) info.getLastResourcePart()).isCollection();
       }
     }
 
-    context.contextTypes.push(new TypeInformation(targetType, isColl));
+    context.contextTypes.push(targetType);
+    context.isCollection = isColl;
 
     if (ctx.vC != null) {
       UriInfoImpl resourcePath = (UriInfoImpl) context.contextExpandItemPath.getResourcePath();
@@ -1546,12 +1471,11 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
       throw wrap(new UriParserSemanticException("Expression '" + ctx.getText() + "' is not allowed as key value.",
           UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE, ctx.getText()));
     }
-    TypeInformation lastTypeInfo = context.contextTypes.peek();
 
     if (ctx.vIt != null || ctx.vIts != null) {
       UriResourceItImpl pathInfoIT = new UriResourceItImpl();
-      pathInfoIT.setType(lastTypeInfo.type);
-      pathInfoIT.setCollection(lastTypeInfo.isCollection);
+      pathInfoIT.setType(context.contextTypes.peek());
+      pathInfoIT.setCollection(context.isCollection);
       uriInfoImplpath.addResourcePart(pathInfoIT);
     }
 
@@ -2101,7 +2025,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
 
     UriResourceRootImpl pathInfoRoot = new UriResourceRootImpl();
     pathInfoRoot.setCollection(lastType.isCollection());
-    pathInfoRoot.setType(getTypeInformation(lastType).type);
+    pathInfoRoot.setType(Parser.getTypeInformation(lastType));
 
     UriInfoImpl uriInfoImplpath = new UriInfoImpl().setKind(UriInfoKind.resource);
     uriInfoImplpath.addResourcePart(pathInfoRoot);
@@ -2194,12 +2118,12 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
 
       EdmType prevType = null;
       if (context.contextSelectItem.getResourcePath() == null) {
-        prevType = context.contextTypes.peek().type;
+        prevType = context.contextTypes.peek();
       } else {
         UriInfoImpl uriInfo = (UriInfoImpl) context.contextSelectItem.getResourcePath();
         UriResource last = uriInfo.getLastResourcePart();
 
-        prevType = getTypeInformation(last).type;
+        prevType = Parser.getTypeInformation((UriResourcePartTyped) last);
         if (prevType == null) {
           throw wrap(new UriParserSemanticException("prev segment not typed",
               UriParserSemanticException.MessageKeys.ONLY_FOR_TYPED_PARTS, "select"));
@@ -2278,7 +2202,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
       // contextSelectItem.addQualifiedThing(fullName);
 
       if (context.contextSelectItem.getResourcePath() == null) {
-        EdmType prevType = context.contextTypes.peek().type;
+        EdmType prevType = context.contextTypes.peek();
 
         // check for complex type cast
         if (prevType instanceof EdmComplexType) {
@@ -2331,7 +2255,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
           throw wrap(new UriParserSemanticException("prev segment typed",
               UriParserSemanticException.MessageKeys.ONLY_FOR_TYPED_PARTS, "select"));
         }
-        EdmType prevType = getTypeInformation(last).type;
+        EdmType prevType = Parser.getTypeInformation((UriResourcePartTyped) last);
 
         if (prevType instanceof EdmComplexType) {
           EdmComplexType ct = edm.getComplexType(fullName);
@@ -2367,7 +2291,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
 
       EdmType prevType = null;
       if (context.contextSelectItem.getResourcePath() == null) {
-        prevType = context.contextTypes.peek().type;
+        prevType = context.contextTypes.peek();
       } else {
         UriInfoImpl uriInfo = (UriInfoImpl) context.contextSelectItem.getResourcePath();
         UriResource last = uriInfo.getLastResourcePart();
@@ -2375,7 +2299,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
           throw wrap(new UriParserSemanticException("prev segment typed",
               UriParserSemanticException.MessageKeys.PREVIOUS_PART_TYPED));
         }
-        prevType = getTypeInformation(last).type;
+        prevType = Parser.getTypeInformation((UriResourcePartTyped) last);
       }
 
       final FullQualifiedName finalTypeName = prevType.getFullQualifiedName();


[10/30] olingo-odata4 git commit: [OLINGO-834] clean-up Expression implementations

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/208f26c7/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/BinaryImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/BinaryImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/BinaryImpl.java
index c3530c0..3f2e8f2 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/BinaryImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/BinaryImpl.java
@@ -25,21 +25,16 @@ import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
 import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitException;
 import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitor;
 
-public class BinaryImpl extends ExpressionImpl implements Binary {
+public class BinaryImpl implements Binary {
 
-  private BinaryOperatorKind operator;
-  private ExpressionImpl left;
-  private ExpressionImpl right;
+  private final Expression left;
+  private final BinaryOperatorKind operator;
+  private final Expression right;
 
-  public BinaryImpl() {
-    // TODO: Delete
-  }
-
-  public BinaryImpl(Expression left, BinaryOperatorKind operator, Expression right) {
-    // TODO:DeleteCast
-    this.left = (ExpressionImpl) left;
+  public BinaryImpl(final Expression left, final BinaryOperatorKind operator, final Expression right) {
+    this.left = left;
     this.operator = operator;
-    this.right = (ExpressionImpl) right;
+    this.right = right;
   }
 
   @Override
@@ -47,30 +42,16 @@ public class BinaryImpl extends ExpressionImpl implements Binary {
     return operator;
   }
 
-  public Binary setOperator(final BinaryOperatorKind operator) {
-    this.operator = operator;
-    return this;
-  }
-
   @Override
   public Expression getLeftOperand() {
     return left;
   }
 
-  public void setLeftOperand(final ExpressionImpl operand) {
-    left = operand;
-  }
-
   @Override
   public Expression getRightOperand() {
     return right;
   }
 
-  public void setRightOperand(final ExpressionImpl operand) {
-    right = operand;
-
-  }
-
   @Override
   public <T> T accept(final ExpressionVisitor<T> visitor) throws ExpressionVisitException, ODataApplicationException {
     T left = this.left.accept(visitor);
@@ -82,5 +63,4 @@ public class BinaryImpl extends ExpressionImpl implements Binary {
   public String toString() {
     return "{" + left + " " + operator.name() + " " + right + '}';
   }
-
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/208f26c7/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/EnumerationImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/EnumerationImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/EnumerationImpl.java
index 8f7df3a..256b8d1 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/EnumerationImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/EnumerationImpl.java
@@ -18,7 +18,7 @@
  */
 package org.apache.olingo.server.core.uri.queryoption.expression;
 
-import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 import org.apache.olingo.commons.api.edm.EdmEnumType;
@@ -27,19 +27,14 @@ import org.apache.olingo.server.api.uri.queryoption.expression.Enumeration;
 import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitException;
 import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitor;
 
-public class EnumerationImpl extends ExpressionImpl implements Enumeration {
+public class EnumerationImpl implements Enumeration {
 
-  private EdmEnumType type;
-  private List<String> values = new ArrayList<String>();
+  private final EdmEnumType type;
+  private final List<String> values;
 
-  @Override
-  public List<String> getValues() {
-    return values;
-  }
-
-  public EnumerationImpl addValue(final String enumValue) {
-    values.add(enumValue);
-    return this;
+  public EnumerationImpl(final EdmEnumType type, final List<String> values) {
+    this.type = type;
+    this.values = values;
   }
 
   @Override
@@ -47,14 +42,15 @@ public class EnumerationImpl extends ExpressionImpl implements Enumeration {
     return type;
   }
 
-  public EnumerationImpl setType(final EdmEnumType type) {
-    this.type = type;
-    return this;
+  @Override
+  public List<String> getValues() {
+    return values == null ?
+        Collections.<String> emptyList() :
+        Collections.unmodifiableList(values);
   }
 
   @Override
   public <T> T accept(final ExpressionVisitor<T> visitor) throws ExpressionVisitException, ODataApplicationException {
     return visitor.visitEnum(type, values);
   }
-
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/208f26c7/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/ExpressionImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/ExpressionImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/ExpressionImpl.java
deleted file mode 100644
index c9cc707..0000000
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/ExpressionImpl.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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.queryoption.expression;
-
-import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
-
-public abstract class ExpressionImpl implements Expression {
-  // No additional methods needed for now.
-}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/208f26c7/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/LambdaRefImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/LambdaRefImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/LambdaRefImpl.java
index 8198204..824943a 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/LambdaRefImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/LambdaRefImpl.java
@@ -23,23 +23,21 @@ import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitEx
 import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitor;
 import org.apache.olingo.server.api.uri.queryoption.expression.LambdaRef;
 
-public class LambdaRefImpl extends ExpressionImpl implements LambdaRef {
+public class LambdaRefImpl implements LambdaRef {
 
-  private String variableText;
+  private final String variableText;
+
+  public LambdaRefImpl(final String text) {
+    variableText = text;
+  }
 
   @Override
   public String getVariableName() {
     return variableText;
   }
 
-  public LambdaRefImpl setVariableText(final String text) {
-    variableText = text;
-    return this;
-  }
-
   @Override
   public <T> T accept(final ExpressionVisitor<T> visitor) throws ExpressionVisitException, ODataApplicationException {
     return visitor.visitLambdaReference(variableText);
   }
-
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/208f26c7/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/LiteralImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/LiteralImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/LiteralImpl.java
index e275fdd..8a3cc8a 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/LiteralImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/LiteralImpl.java
@@ -24,16 +24,12 @@ import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitEx
 import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitor;
 import org.apache.olingo.server.api.uri.queryoption.expression.Literal;
 
-public class LiteralImpl extends ExpressionImpl implements Literal {
+public class LiteralImpl implements Literal {
 
-  private String text;
-  private EdmType type;
+  private final String text;
+  private final EdmType type;
 
-  public LiteralImpl() {
-
-  }
-
-  public LiteralImpl(String text, EdmType type) {
+  public LiteralImpl(final String text, final EdmType type) {
     this.text = text;
     this.type = type;
   }
@@ -43,21 +39,11 @@ public class LiteralImpl extends ExpressionImpl implements Literal {
     return text;
   }
 
-  public LiteralImpl setText(final String text) {
-    this.text = text;
-    return this;
-  }
-
   @Override
   public EdmType getType() {
     return type;
   }
 
-  public LiteralImpl setType(final EdmType type) {
-    this.type = type;
-    return this;
-  }
-
   @Override
   public <T> T accept(final ExpressionVisitor<T> visitor) throws ExpressionVisitException, ODataApplicationException {
     return visitor.visitLiteral(this);
@@ -65,7 +51,6 @@ public class LiteralImpl extends ExpressionImpl implements Literal {
 
   @Override
   public String toString() {
-    return "" + text;
+    return text == null ? "" : text;
   }
-
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/208f26c7/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MemberImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MemberImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MemberImpl.java
index 5f6162f..a71e382 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MemberImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MemberImpl.java
@@ -30,19 +30,24 @@ import org.apache.olingo.server.core.uri.UriResourceImpl;
 import org.apache.olingo.server.core.uri.UriResourceTypedImpl;
 import org.apache.olingo.server.core.uri.UriResourceWithKeysImpl;
 
-public class MemberImpl extends ExpressionImpl implements Member {
+public class MemberImpl implements Member {
 
-  private UriInfoResource path;
-  private EdmType startTypeFilter;
+  private final UriInfoResource path;
+  private final EdmType startTypeFilter;
+
+  public MemberImpl(final UriInfoResource path, final EdmType startTypeFilter) {
+    this.path = path;
+    this.startTypeFilter = startTypeFilter;
+  }
 
   @Override
   public UriInfoResource getResourcePath() {
     return path;
   }
 
-  public Member setResourcePath(final UriInfoResource pathSegments) {
-    path = pathSegments;
-    return this;
+  @Override
+  public EdmType getStartTypeFilter() {
+    return startTypeFilter;
   }
 
   @Override
@@ -89,15 +94,4 @@ public class MemberImpl extends ExpressionImpl implements Member {
     }
     return false;
   }
-
-  @Override
-  public EdmType getStartTypeFilter() {
-    return startTypeFilter;
-  }
-
-  public MemberImpl setTypeFilter(final EdmType startTypeFilter) {
-    this.startTypeFilter = startTypeFilter;
-    return this;
-  }
-
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/208f26c7/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MethodImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MethodImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MethodImpl.java
index 8175c85..1c8ce64 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MethodImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MethodImpl.java
@@ -19,6 +19,7 @@
 package org.apache.olingo.server.core.uri.queryoption.expression;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 import org.apache.olingo.server.api.ODataApplicationException;
@@ -28,17 +29,14 @@ import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitor
 import org.apache.olingo.server.api.uri.queryoption.expression.Method;
 import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind;
 
-public class MethodImpl extends ExpressionImpl implements Method {
+public class MethodImpl implements Method {
 
-  private MethodKind method;
-  private List<ExpressionImpl> parameters = new ArrayList<ExpressionImpl>();
+  private final MethodKind method;
+  private final List<Expression> parameters;
 
-  public MethodImpl() {
-    // TODO: Delete constructor
-  }
-
-  public MethodImpl(MethodKind method) {
+  public MethodImpl(final MethodKind method, final List<Expression> parameters) {
     this.method = method;
+    this.parameters = parameters;
   }
 
   @Override
@@ -46,48 +44,26 @@ public class MethodImpl extends ExpressionImpl implements Method {
     return method;
   }
 
-  public MethodImpl setMethod(final MethodKind methodCalls) {
-    method = methodCalls;
-    return this;
-  }
-
   @Override
   public List<Expression> getParameters() {
-    List<Expression> list = new ArrayList<Expression>();
-    for (ExpressionImpl item : parameters) {
-      list.add(item);
-    }
-    return list;
-  }
-
-  public MethodImpl addParameter(final ExpressionImpl readCommonExpression) {
-    parameters.add(readCommonExpression);
-    return this;
+    return parameters == null ?
+        Collections.<Expression> emptyList() :
+        Collections.unmodifiableList(parameters);
   }
 
   @Override
   public <T> T accept(final ExpressionVisitor<T> visitor) throws ExpressionVisitException, ODataApplicationException {
     List<T> userParameters = new ArrayList<T>();
-    for (ExpressionImpl parameter : parameters) {
-      userParameters.add(parameter.accept(visitor));
+    if (parameters != null) {
+      for (final Expression parameter : parameters) {
+        userParameters.add(parameter.accept(visitor));
+      }
     }
     return visitor.visitMethodCall(method, userParameters);
   }
 
   @Override
   public String toString() {
-    String parametersString = "[";
-    boolean first = true;
-    for (Expression exp : parameters) {
-      if(first){
-        first = false;
-        parametersString = parametersString + exp.toString();
-      }else {
-        parametersString = parametersString + ", " + exp.toString();
-      }
-    }
-    parametersString = parametersString + "]";
-    return "{" + method + " " + parametersString + "}";
+    return "{" + method + " " + parameters + "}";
   }
-
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/208f26c7/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/TypeLiteralImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/TypeLiteralImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/TypeLiteralImpl.java
index f5f6f06..336c203 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/TypeLiteralImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/TypeLiteralImpl.java
@@ -24,23 +24,21 @@ import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitEx
 import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitor;
 import org.apache.olingo.server.api.uri.queryoption.expression.TypeLiteral;
 
-public class TypeLiteralImpl extends ExpressionImpl implements TypeLiteral {
+public class TypeLiteralImpl implements TypeLiteral {
 
-  private EdmType type;
+  private final EdmType type;
+
+  public TypeLiteralImpl(final EdmType type) {
+    this.type = type;
+  }
 
   @Override
   public EdmType getType() {
     return type;
   }
 
-  public TypeLiteralImpl setType(final EdmType type) {
-    this.type = type;
-    return this;
-  }
-
   @Override
   public <T> T accept(final ExpressionVisitor<T> visitor) throws ExpressionVisitException, ODataApplicationException {
     return visitor.visitTypeLiteral(type);
   }
-
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/208f26c7/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/UnaryImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/UnaryImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/UnaryImpl.java
index f1edf91..2438d27 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/UnaryImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/UnaryImpl.java
@@ -25,18 +25,14 @@ import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitor
 import org.apache.olingo.server.api.uri.queryoption.expression.Unary;
 import org.apache.olingo.server.api.uri.queryoption.expression.UnaryOperatorKind;
 
-public class UnaryImpl extends ExpressionImpl implements Unary {
+public class UnaryImpl implements Unary {
 
-  private UnaryOperatorKind operator;
-  private ExpressionImpl expression;
+  private final UnaryOperatorKind operator;
+  private final Expression expression;
 
-  public UnaryImpl() {
-
-  }
-
-  public UnaryImpl(UnaryOperatorKind operator, Expression expression) {
+  public UnaryImpl(final UnaryOperatorKind operator, final Expression expression) {
     this.operator = operator;
-    this.expression = (ExpressionImpl) expression;
+    this.expression = expression;
   }
 
   @Override
@@ -44,19 +40,11 @@ public class UnaryImpl extends ExpressionImpl implements Unary {
     return operator;
   }
 
-  public void setOperator(final UnaryOperatorKind operator) {
-    this.operator = operator;
-  }
-
   @Override
   public Expression getOperand() {
     return expression;
   }
 
-  public void setOperand(final ExpressionImpl expression) {
-    this.expression = expression;
-  }
-
   @Override
   public <T> T accept(final ExpressionVisitor<T> visitor) throws ExpressionVisitException, ODataApplicationException {
     T operand = expression.accept(visitor);
@@ -67,5 +55,4 @@ public class UnaryImpl extends ExpressionImpl implements Unary {
   public String toString() {
     return "{" + operator + " " + expression + '}';
   }
-
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/208f26c7/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/expression/FilterParserTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/expression/FilterParserTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/expression/FilterParserTest.java
deleted file mode 100644
index 7bfc369..0000000
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/expression/FilterParserTest.java
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * 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.expression;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-import java.util.ArrayList;
-
-import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
-import org.apache.olingo.server.core.uri.expression.FilterParser.TokenKind;
-import org.apache.olingo.server.core.uri.expression.FilterParser.Tokenizer;
-import org.apache.olingo.server.core.uri.expression.FilterParser.Token;
-import org.junit.Test;
-
-public class FilterParserTest {
-
-  @Test
-  public void equality() {
-    Expression expression = parseExpression(TokenKind.EQ_OP);
-    assertEquals("{5 EQ 5}", expression.toString());
-
-    expression = parseExpression(TokenKind.NE_OP);
-    assertEquals("{5 NE 5}", expression.toString());
-  }
-
-  @Test
-  public void relational() {
-    Expression expression = parseExpression(TokenKind.GT_OP);
-    assertEquals("{5 GT 5}", expression.toString());
-
-    expression = parseExpression(TokenKind.GE_OP);
-    assertEquals("{5 GE 5}", expression.toString());
-
-    expression = parseExpression(TokenKind.LT_OP);
-    assertEquals("{5 LT 5}", expression.toString());
-
-    expression = parseExpression(TokenKind.LE_OP);
-    assertEquals("{5 LE 5}", expression.toString());
-  }
-
-  @Test
-  public void additive() {
-    Expression expression = parseExpression(TokenKind.ADD_OP);
-    assertEquals("{5 ADD 5}", expression.toString());
-
-    expression = parseExpression(TokenKind.SUB_OP);
-    assertEquals("{5 SUB 5}", expression.toString());
-  }
-
-  @Test
-  public void multiplicative() {
-    Expression expression = parseExpression(TokenKind.MUL_OP);
-    assertEquals("{5 MUL 5}", expression.toString());
-
-    expression = parseExpression(TokenKind.DIV_OP);
-    assertEquals("{5 DIV 5}", expression.toString());
-
-    expression = parseExpression(TokenKind.MOD_OP);
-    assertEquals("{5 MOD 5}", expression.toString());
-  }
-
-  @Test
-  public void unary() {
-    ArrayList<Token> tokens = new ArrayList<Token>();
-    tokens.add(new Token(TokenKind.MINUS, ""));
-    tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
-    Tokenizer tokenizer = new Tokenizer(tokens);
-    Expression expression = new FilterParser().parse(tokenizer);
-    assertEquals("{- 5}", expression.toString());
-
-    tokens = new ArrayList<Token>();
-    tokens.add(new Token(TokenKind.NOT, ""));
-    tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
-    tokenizer = new Tokenizer(tokens);
-    expression = new FilterParser().parse(tokenizer);
-    assertEquals("{not 5}", expression.toString());
-  }
-
-  @Test
-  public void grouping() {
-    ArrayList<Token> tokens = new ArrayList<Token>();
-    tokens.add(new Token(TokenKind.MINUS, ""));
-    tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
-    tokens.add(new Token(TokenKind.ADD_OP, ""));
-    tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
-    Tokenizer tokenizer = new Tokenizer(tokens);
-    Expression expression = new FilterParser().parse(tokenizer);
-    assertEquals("{{- 5} ADD 5}", expression.toString());
-
-    tokens = new ArrayList<Token>();
-    tokens.add(new Token(TokenKind.MINUS, ""));
-    tokens.add(new Token(TokenKind.OPEN, ""));
-    tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
-    tokens.add(new Token(TokenKind.ADD_OP, ""));
-    tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
-    tokens.add(new Token(TokenKind.CLOSE, ""));
-    tokenizer = new Tokenizer(tokens);
-    expression = new FilterParser().parse(tokenizer);
-    assertEquals("{- {5 ADD 5}}", expression.toString());
-  }
-
-  @Test
-  public void noParameterMethods() {
-    Expression expression = parseMethod(TokenKind.Now);
-    assertEquals("{now []}", expression.toString());
-
-    expression = parseMethod(TokenKind.Maxdatetime);
-    assertEquals("{maxdatetime []}", expression.toString());
-
-    expression = parseMethod(TokenKind.Mindatetime);
-    assertEquals("{mindatetime []}", expression.toString());
-  }
-
-  @Test
-  public void oneParameterMethods() {
-    Expression expression = parseMethod(TokenKind.Length, TokenKind.PrimitiveStringValue);
-    assertEquals("{length [String1]}", expression.toString());
-
-    expression = parseMethod(TokenKind.Tolower, TokenKind.PrimitiveStringValue);
-    assertEquals("{tolower [String1]}", expression.toString());
-
-    expression = parseMethod(TokenKind.Toupper, TokenKind.PrimitiveStringValue);
-    assertEquals("{toupper [String1]}", expression.toString());
-
-    expression = parseMethod(TokenKind.Trim, TokenKind.PrimitiveStringValue);
-    assertEquals("{trim [String1]}", expression.toString());
-
-    expression = parseMethod(TokenKind.Year, TokenKind.PrimitiveDateValue);
-    assertEquals("{year [Date1]}", expression.toString());
-
-    expression = parseMethod(TokenKind.Month, TokenKind.PrimitiveDateValue);
-    assertEquals("{month [Date1]}", expression.toString());
-
-    expression = parseMethod(TokenKind.Day, TokenKind.PrimitiveDateValue);
-    assertEquals("{day [Date1]}", expression.toString());
-
-    expression = parseMethod(TokenKind.Hour, TokenKind.PrimitiveDateTimeOffsetValue);
-    assertEquals("{hour [DateTimeOffset1]}", expression.toString());
-
-    expression = parseMethod(TokenKind.Minute, TokenKind.PrimitiveDateTimeOffsetValue);
-    assertEquals("{minute [DateTimeOffset1]}", expression.toString());
-
-    expression = parseMethod(TokenKind.Second, TokenKind.PrimitiveDateTimeOffsetValue);
-    assertEquals("{second [DateTimeOffset1]}", expression.toString());
-  }
-
-  @Test
-  public void twoParameterMethods() {
-
-  }
-
-  private Expression parseMethod(TokenKind... kind) {
-    ArrayList<Token> tokens = new ArrayList<Token>();
-    tokens.add(new Token(kind[0], ""));
-
-    for (int i = 1; i < kind.length; i++) {
-      String text = null;
-      switch (kind[i]) {
-      case PrimitiveStringValue:
-        text = "String" + i;
-        break;
-      case PrimitiveDateValue:
-        text = "Date" + i;
-        break;
-      case PrimitiveDateTimeOffsetValue:
-        text = "DateTimeOffset" + i;
-        break;
-      default:
-        text = "" + i;
-        break;
-      }
-      tokens.add(new Token(kind[i], text));
-    }
-
-    tokens.add(new Token(TokenKind.CLOSE, ""));
-    Tokenizer tokenizer = new Tokenizer(tokens);
-    Expression expression = new FilterParser().parse(tokenizer);
-    assertNotNull(expression);
-    return expression;
-  }
-
-  private Expression parseExpression(TokenKind operator) {
-    ArrayList<Token> tokens = new ArrayList<Token>();
-    tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
-    tokens.add(new Token(operator, ""));
-    tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
-    Tokenizer tokenizer = new Tokenizer(tokens);
-
-    Expression expression = new FilterParser().parse(tokenizer);
-    assertNotNull(expression);
-    return expression;
-  }
-}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/208f26c7/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java
new file mode 100644
index 0000000..7da823e
--- /dev/null
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java
@@ -0,0 +1,210 @@
+/*
+ * 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 static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.ArrayList;
+
+import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
+import org.apache.olingo.server.core.uri.parser.ExpressionParser.Token;
+import org.apache.olingo.server.core.uri.parser.ExpressionParser.TokenKind;
+import org.apache.olingo.server.core.uri.parser.ExpressionParser.Tokenizer;
+import org.junit.Test;
+
+public class ExpressionParserTest {
+
+  @Test
+  public void equality() throws Exception {
+    Expression expression = parseExpression(TokenKind.EQ_OP);
+    assertEquals("{5 EQ 5}", expression.toString());
+
+    expression = parseExpression(TokenKind.NE_OP);
+    assertEquals("{5 NE 5}", expression.toString());
+  }
+
+  @Test
+  public void relational() throws Exception {
+    Expression expression = parseExpression(TokenKind.GT_OP);
+    assertEquals("{5 GT 5}", expression.toString());
+
+    expression = parseExpression(TokenKind.GE_OP);
+    assertEquals("{5 GE 5}", expression.toString());
+
+    expression = parseExpression(TokenKind.LT_OP);
+    assertEquals("{5 LT 5}", expression.toString());
+
+    expression = parseExpression(TokenKind.LE_OP);
+    assertEquals("{5 LE 5}", expression.toString());
+  }
+
+  @Test
+  public void additive() throws Exception {
+    Expression expression = parseExpression(TokenKind.ADD_OP);
+    assertEquals("{5 ADD 5}", expression.toString());
+
+    expression = parseExpression(TokenKind.SUB_OP);
+    assertEquals("{5 SUB 5}", expression.toString());
+  }
+
+  @Test
+  public void multiplicative() throws Exception {
+    Expression expression = parseExpression(TokenKind.MUL_OP);
+    assertEquals("{5 MUL 5}", expression.toString());
+
+    expression = parseExpression(TokenKind.DIV_OP);
+    assertEquals("{5 DIV 5}", expression.toString());
+
+    expression = parseExpression(TokenKind.MOD_OP);
+    assertEquals("{5 MOD 5}", expression.toString());
+  }
+
+  @Test
+  public void unary() throws Exception {
+    ArrayList<Token> tokens = new ArrayList<Token>();
+    tokens.add(new Token(TokenKind.MINUS, ""));
+    tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
+    Tokenizer tokenizer = new Tokenizer(tokens);
+    Expression expression = new ExpressionParser().parse(tokenizer);
+    assertEquals("{- 5}", expression.toString());
+
+    tokens = new ArrayList<Token>();
+    tokens.add(new Token(TokenKind.NOT, ""));
+    tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
+    tokenizer = new Tokenizer(tokens);
+    expression = new ExpressionParser().parse(tokenizer);
+    assertEquals("{not 5}", expression.toString());
+  }
+
+  @Test
+  public void grouping() throws Exception {
+    ArrayList<Token> tokens = new ArrayList<Token>();
+    tokens.add(new Token(TokenKind.MINUS, ""));
+    tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
+    tokens.add(new Token(TokenKind.ADD_OP, ""));
+    tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
+    Tokenizer tokenizer = new Tokenizer(tokens);
+    Expression expression = new ExpressionParser().parse(tokenizer);
+    assertEquals("{{- 5} ADD 5}", expression.toString());
+
+    tokens = new ArrayList<Token>();
+    tokens.add(new Token(TokenKind.MINUS, ""));
+    tokens.add(new Token(TokenKind.OPEN, ""));
+    tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
+    tokens.add(new Token(TokenKind.ADD_OP, ""));
+    tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
+    tokens.add(new Token(TokenKind.CLOSE, ""));
+    tokenizer = new Tokenizer(tokens);
+    expression = new ExpressionParser().parse(tokenizer);
+    assertEquals("{- {5 ADD 5}}", expression.toString());
+  }
+
+  @Test
+  public void noParameterMethods() throws Exception {
+    Expression expression = parseMethod(TokenKind.Now);
+    assertEquals("{now []}", expression.toString());
+
+    expression = parseMethod(TokenKind.Maxdatetime);
+    assertEquals("{maxdatetime []}", expression.toString());
+
+    expression = parseMethod(TokenKind.Mindatetime);
+    assertEquals("{mindatetime []}", expression.toString());
+  }
+
+  @Test
+  public void oneParameterMethods() throws Exception {
+    Expression expression = parseMethod(TokenKind.Length, TokenKind.PrimitiveStringValue);
+    assertEquals("{length [String1]}", expression.toString());
+
+    expression = parseMethod(TokenKind.Tolower, TokenKind.PrimitiveStringValue);
+    assertEquals("{tolower [String1]}", expression.toString());
+
+    expression = parseMethod(TokenKind.Toupper, TokenKind.PrimitiveStringValue);
+    assertEquals("{toupper [String1]}", expression.toString());
+
+    expression = parseMethod(TokenKind.Trim, TokenKind.PrimitiveStringValue);
+    assertEquals("{trim [String1]}", expression.toString());
+
+    expression = parseMethod(TokenKind.Year, TokenKind.PrimitiveDateValue);
+    assertEquals("{year [Date1]}", expression.toString());
+
+    expression = parseMethod(TokenKind.Month, TokenKind.PrimitiveDateValue);
+    assertEquals("{month [Date1]}", expression.toString());
+
+    expression = parseMethod(TokenKind.Day, TokenKind.PrimitiveDateValue);
+    assertEquals("{day [Date1]}", expression.toString());
+
+    expression = parseMethod(TokenKind.Hour, TokenKind.PrimitiveDateTimeOffsetValue);
+    assertEquals("{hour [DateTimeOffset1]}", expression.toString());
+
+    expression = parseMethod(TokenKind.Minute, TokenKind.PrimitiveDateTimeOffsetValue);
+    assertEquals("{minute [DateTimeOffset1]}", expression.toString());
+
+    expression = parseMethod(TokenKind.Second, TokenKind.PrimitiveDateTimeOffsetValue);
+    assertEquals("{second [DateTimeOffset1]}", expression.toString());
+  }
+
+  @Test
+  public void twoParameterMethods() {
+
+  }
+
+  private Expression parseMethod(TokenKind... kind) throws UriParserException {
+    ArrayList<Token> tokens = new ArrayList<Token>();
+    tokens.add(new Token(kind[0], ""));
+
+    for (int i = 1; i < kind.length; i++) {
+      String text = null;
+      switch (kind[i]) {
+      case PrimitiveStringValue:
+        text = "String" + i;
+        break;
+      case PrimitiveDateValue:
+        text = "Date" + i;
+        break;
+      case PrimitiveDateTimeOffsetValue:
+        text = "DateTimeOffset" + i;
+        break;
+      default:
+        text = "" + i;
+        break;
+      }
+      tokens.add(new Token(kind[i], text));
+    }
+
+    tokens.add(new Token(TokenKind.CLOSE, ""));
+    Tokenizer tokenizer = new Tokenizer(tokens);
+    Expression expression = new ExpressionParser().parse(tokenizer);
+    assertNotNull(expression);
+    return expression;
+  }
+
+  private Expression parseExpression(TokenKind operator) throws UriParserException {
+    ArrayList<Token> tokens = new ArrayList<Token>();
+    tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
+    tokens.add(new Token(operator, ""));
+    tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
+    Tokenizer tokenizer = new Tokenizer(tokens);
+
+    Expression expression = new ExpressionParser().parse(tokenizer);
+    assertNotNull(expression);
+    return expression;
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/208f26c7/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/UriResourceImplTest.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/UriResourceImplTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/UriResourceImplTest.java
index a5d0ea3..a945d11 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/UriResourceImplTest.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/UriResourceImplTest.java
@@ -43,7 +43,7 @@ import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.edmx.EdmxReference;
 import org.apache.olingo.server.api.uri.UriParameter;
 import org.apache.olingo.server.api.uri.UriResourceKind;
-import org.apache.olingo.server.core.uri.queryoption.expression.ExpressionImpl;
+import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
 import org.apache.olingo.server.core.uri.queryoption.expression.LiteralImpl;
 import org.apache.olingo.server.tecsvc.provider.ActionProvider;
 import org.apache.olingo.server.tecsvc.provider.ComplexTypeProvider;
@@ -59,7 +59,7 @@ public class UriResourceImplTest {
   @Test
   public void testUriParameterImpl() {
     UriParameterImpl impl = new UriParameterImpl();
-    ExpressionImpl expression = new LiteralImpl().setText("Expression");
+    Expression expression = new LiteralImpl("Expression", null);
 
     impl.setText("Text");
     impl.setName("A");
@@ -105,7 +105,7 @@ public class UriResourceImplTest {
     UriResourceLambdaAllImpl impl = new UriResourceLambdaAllImpl();
     assertEquals(UriResourceKind.lambdaAll, impl.getKind());
 
-    ExpressionImpl expression = new LiteralImpl().setText("Expression");
+    Expression expression = new LiteralImpl("Expression", null);
     impl.setExpression(expression);
     impl.setLamdaVariable("A");
 
@@ -121,7 +121,7 @@ public class UriResourceImplTest {
     UriResourceLambdaAnyImpl impl = new UriResourceLambdaAnyImpl();
     assertEquals(UriResourceKind.lambdaAny, impl.getKind());
 
-    ExpressionImpl expression = new LiteralImpl().setText("Expression");
+    Expression expression = new LiteralImpl("Expression", null);
     impl.setExpression(expression);
     impl.setLamdaVariable("A");
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/208f26c7/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/queryoption/QueryOptionTest.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/queryoption/QueryOptionTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/queryoption/QueryOptionTest.java
index 93cdf86..db9f5be 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/queryoption/QueryOptionTest.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/queryoption/QueryOptionTest.java
@@ -44,7 +44,7 @@ public class QueryOptionTest {
   public void testAliasQueryOption() {
     AliasQueryOptionImpl option = new AliasQueryOptionImpl();
 
-    Expression expression = new LiteralImpl();
+    Expression expression = new LiteralImpl(null, null);
 
     option.setAliasValue(expression);
     assertEquals(expression, option.getValue());
@@ -132,7 +132,7 @@ public class QueryOptionTest {
     FilterOptionImpl option = new FilterOptionImpl();
     assertEquals(SystemQueryOptionKind.FILTER, option.getKind());
 
-    AliasImpl expression = new AliasImpl();
+    AliasImpl expression = new AliasImpl(null);
 
     option.setExpression(expression);
     assertEquals(expression, option.getExpression());
@@ -184,7 +184,7 @@ public class QueryOptionTest {
   public void testOrderByItemImpl() {
     OrderByItemImpl option = new OrderByItemImpl();
 
-    AliasImpl expression = new AliasImpl();
+    AliasImpl expression = new AliasImpl(null);
     option.setExpression(expression);
     assertEquals(expression, option.getExpression());
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/208f26c7/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/queryoption/expression/ExpressionTest.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/queryoption/expression/ExpressionTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/queryoption/expression/ExpressionTest.java
index e8a9b38..ec5ce6e 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/queryoption/expression/ExpressionTest.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/queryoption/expression/ExpressionTest.java
@@ -37,6 +37,7 @@ import org.apache.olingo.server.api.edmx.EdmxReference;
 import org.apache.olingo.server.api.uri.UriInfoKind;
 import org.apache.olingo.server.api.uri.UriInfoResource;
 import org.apache.olingo.server.api.uri.queryoption.expression.BinaryOperatorKind;
+import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
 import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitException;
 import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind;
 import org.apache.olingo.server.api.uri.queryoption.expression.UnaryOperatorKind;
@@ -56,7 +57,7 @@ public class ExpressionTest {
       new EdmTechProvider(), Collections.<EdmxReference> emptyList()).getEdm();
 
   @Test
-  public void testSupportedOperators() {
+  public void supportedOperators() {
     assertEquals(UnaryOperatorKind.MINUS, UnaryOperatorKind.get("-"));
     assertEquals(null, UnaryOperatorKind.get("XXX"));
 
@@ -68,28 +69,21 @@ public class ExpressionTest {
   }
 
   @Test
-  public void testAliasExpression() throws ExpressionVisitException, ODataApplicationException {
-    AliasImpl expression = new AliasImpl();
-
-    expression.setParameter("Test");
+  public void aliasExpression() throws ExpressionVisitException, ODataApplicationException {
+    AliasImpl expression = new AliasImpl("Test");
 
     assertEquals("Test", expression.getParameterName());
 
     String output = expression.accept(new FilterTreeToText());
     assertEquals("<Test>", output);
-
   }
 
   @Test
-  public void testBinaryExpression() throws ExpressionVisitException, ODataApplicationException {
-    BinaryImpl expression = new BinaryImpl();
-
-    ExpressionImpl expressionLeft = new LiteralImpl().setText("A");
-    ExpressionImpl expressionRight = new LiteralImpl().setText("B");
+  public void binaryExpression() throws ExpressionVisitException, ODataApplicationException {
+    Expression expressionLeft = new LiteralImpl("A", null);
+    Expression expressionRight = new LiteralImpl("B", null);
 
-    expression.setLeftOperand(expressionLeft);
-    expression.setRightOperand(expressionRight);
-    expression.setOperator(BinaryOperatorKind.SUB);
+    BinaryImpl expression = new BinaryImpl(expressionLeft, BinaryOperatorKind.SUB, expressionRight);
 
     assertEquals(expressionLeft, expression.getLeftOperand());
     assertEquals(expressionRight, expression.getRightOperand());
@@ -100,50 +94,39 @@ public class ExpressionTest {
   }
 
   @Test
-  public void testEnumerationExpression() throws ExpressionVisitException, ODataApplicationException {
-    EnumerationImpl expression = new EnumerationImpl();
+  public void enumerationExpression() throws ExpressionVisitException, ODataApplicationException {
     EdmEnumType type = edm.getEnumType(EnumTypeProvider.nameENString);
     assertNotNull(type);
-    expression.setType(type);
-
+    EnumerationImpl expression = new EnumerationImpl(type, Arrays.asList("A", "B"));
     assertEquals(type, expression.getType());
-
-    expression.addValue("A");
-    expression.addValue("B");
     assertEquals("A", expression.getValues().get(0));
     assertEquals("B", expression.getValues().get(1));
     assertEquals("<olingo.odata.test1.ENString<A,B>>", expression.accept(new FilterTreeToText()));
   }
 
   @Test
-  public void testLambdaRefExpression() throws ExpressionVisitException, ODataApplicationException {
-    LambdaRefImpl expression = new LambdaRefImpl();
-    expression.setVariableText("A");
+  public void lambdaRefExpression() throws ExpressionVisitException, ODataApplicationException {
+    LambdaRefImpl expression = new LambdaRefImpl("A");
     assertEquals("A", expression.getVariableName());
-
     assertEquals("<A>", expression.accept(new FilterTreeToText()));
-
   }
 
   @Test
-  public void testLiteralExpresion() throws ExpressionVisitException, ODataApplicationException {
-    LiteralImpl expression = new LiteralImpl();
-    expression.setText("A");
+  public void literalExpression() throws ExpressionVisitException, ODataApplicationException {
+    LiteralImpl expression = new LiteralImpl("A", null);
     assertEquals("A", expression.getText());
-
     assertEquals("<A>", expression.accept(new FilterTreeToText()));
   }
 
   @Test
-  public void testMemberExpression() throws ExpressionVisitException, ODataApplicationException {
-    MemberImpl expression = new MemberImpl();
+  public void memberExpression() throws ExpressionVisitException, ODataApplicationException {
     EdmEntityType entityType = edm.getEntityType(EntityTypeProvider.nameETKeyNav);
 
     // UriResourceImpl
     EdmAction action = edm.getUnboundAction(ActionProvider.nameUARTString);
     UriInfoResource uriInfo = new UriInfoImpl().setKind(UriInfoKind.resource).addResourcePart(
         new UriResourceActionImpl().setAction(action)).asUriInfoResource();
-    expression.setResourcePath(uriInfo);
+    MemberImpl expression = new MemberImpl(uriInfo, null);
     assertEquals(action.getReturnType().getType(), expression.getType());
 
     // check accept and path
@@ -155,45 +138,50 @@ public class ExpressionTest {
 
     // UriResourceImplTyped check collection = true case
     action = edm.getUnboundAction(ActionProvider.nameUARTCollStringTwoParam);
-    expression.setResourcePath(new UriInfoImpl().setKind(UriInfoKind.resource)
+    expression = new MemberImpl(new UriInfoImpl().setKind(UriInfoKind.resource)
         .addResourcePart(new UriResourceActionImpl().setAction(action))
-        .asUriInfoResource());
+        .asUriInfoResource(),
+        null);
     assertTrue(expression.isCollection());
 
     // UriResourceImplTyped with filter
     EdmFunction function = edm.getUnboundFunction(FunctionProvider.nameUFCRTETKeyNav, null);
-    expression.setResourcePath(new UriInfoImpl().setKind(UriInfoKind.resource).addResourcePart(
+    expression = new MemberImpl(new UriInfoImpl().setKind(UriInfoKind.resource).addResourcePart(
         new UriResourceFunctionImpl().setFunction(function).setEntryTypeFilter(entityType))
-        .asUriInfoResource());
+        .asUriInfoResource(),
+        null);
     assertEquals(entityType, expression.getType());
 
     // UriResourceImplKeyPred
     function = edm.getUnboundFunction(FunctionProvider.nameUFCRTETKeyNav, null);
-    expression.setResourcePath(new UriInfoImpl().setKind(UriInfoKind.resource).addResourcePart(
+    expression = new MemberImpl(new UriInfoImpl().setKind(UriInfoKind.resource).addResourcePart(
         new UriResourceFunctionImpl().setFunction(function))
-        .asUriInfoResource());
+        .asUriInfoResource(),
+        null);
     assertEquals(function.getReturnType().getType(), expression.getType());
 
     // UriResourceImplKeyPred typeFilter on entry
     EdmEntityType entityBaseType = edm.getEntityType(EntityTypeProvider.nameETBaseTwoKeyNav);
     function = edm.getUnboundFunction(FunctionProvider.nameUFCRTCollETTwoKeyNavParam, Arrays.asList("ParameterInt16"));
-    expression.setResourcePath(new UriInfoImpl().setKind(UriInfoKind.resource).addResourcePart(
+    expression = new MemberImpl(new UriInfoImpl().setKind(UriInfoKind.resource).addResourcePart(
         new UriResourceFunctionImpl().setFunction(function).setEntryTypeFilter(entityBaseType))
-        .asUriInfoResource());
+        .asUriInfoResource(),
+        null);
     assertEquals(entityBaseType, expression.getType());
 
     // UriResourceImplKeyPred typeFilter on entry
     entityBaseType = edm.getEntityType(EntityTypeProvider.nameETBaseTwoKeyNav);
     function = edm.getUnboundFunction(FunctionProvider.nameUFCRTCollETTwoKeyNavParam, Arrays.asList("ParameterInt16"));
-    expression.setResourcePath(new UriInfoImpl().setKind(UriInfoKind.resource).addResourcePart(
+    expression = new MemberImpl(new UriInfoImpl().setKind(UriInfoKind.resource).addResourcePart(
         new UriResourceFunctionImpl().setFunction(function).setCollectionTypeFilter(entityBaseType))
-        .asUriInfoResource());
+        .asUriInfoResource(),
+        null);
     assertEquals(entityBaseType, expression.getType());
 
     // no typed
     entityBaseType = edm.getEntityType(EntityTypeProvider.nameETBaseTwoKeyNav);
     function = edm.getUnboundFunction(FunctionProvider.nameUFCRTCollETTwoKeyNavParam, Arrays.asList("ParameterInt16"));
-    expression.setResourcePath(new UriInfoImpl().setKind(UriInfoKind.all));
+    expression = new MemberImpl(new UriInfoImpl().setKind(UriInfoKind.all), null);
     assertEquals(null, expression.getType());
 
     // no typed collection else case
@@ -201,14 +189,10 @@ public class ExpressionTest {
   }
 
   @Test
-  public void testMethodCallExpression() throws ExpressionVisitException, ODataApplicationException {
-    MethodImpl expression = new MethodImpl();
-    expression.setMethod(MethodKind.CONCAT);
-
-    ExpressionImpl p0 = new LiteralImpl().setText("A");
-    ExpressionImpl p1 = new LiteralImpl().setText("B");
-    expression.addParameter(p0);
-    expression.addParameter(p1);
+  public void methodCallExpression() throws ExpressionVisitException, ODataApplicationException {
+    Expression p0 = new LiteralImpl("A", null);
+    Expression p1 = new LiteralImpl("B", null);
+    MethodImpl expression = new MethodImpl(MethodKind.CONCAT, Arrays.asList(p0, p1));
 
     assertEquals(MethodKind.CONCAT, expression.getMethod());
     assertEquals("<concat(<A>,<B>)>", expression.accept(new FilterTreeToText()));
@@ -218,27 +202,22 @@ public class ExpressionTest {
   }
 
   @Test
-  public void testTypeLiteralExpression() throws ExpressionVisitException, ODataApplicationException {
-    TypeLiteralImpl expression = new TypeLiteralImpl();
+  public void typeLiteralExpression() throws ExpressionVisitException, ODataApplicationException {
     EdmEntityType entityBaseType = edm.getEntityType(EntityTypeProvider.nameETBaseTwoKeyNav);
-    expression.setType(entityBaseType);
+    TypeLiteralImpl expression = new TypeLiteralImpl(entityBaseType);
 
     assertEquals(entityBaseType, expression.getType());
     assertEquals("<olingo.odata.test1.ETBaseTwoKeyNav>", expression.accept(new FilterTreeToText()));
   }
 
   @Test
-  public void testUnaryExpression() throws ExpressionVisitException, ODataApplicationException {
-    UnaryImpl expression = new UnaryImpl();
-    expression.setOperator(UnaryOperatorKind.MINUS);
-
-    ExpressionImpl operand = new LiteralImpl().setText("A");
-    expression.setOperand(operand);
+  public void unaryExpression() throws ExpressionVisitException, ODataApplicationException {
+    Expression operand = new LiteralImpl("A", null);
+    UnaryImpl expression = new UnaryImpl(UnaryOperatorKind.MINUS, operand);
 
     assertEquals(UnaryOperatorKind.MINUS, expression.getOperator());
     assertEquals(operand, expression.getOperand());
 
     assertEquals("<- <A>>", expression.accept(new FilterTreeToText()));
   }
-
 }


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

Posted by ch...@apache.org.
[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


[29/30] olingo-odata4 git commit: [OLINGO-834] Adjust LICENSE file

Posted by ch...@apache.org.
[OLINGO-834] Adjust LICENSE file

I removed the Antlr and treelayout bsd license.


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

Branch: refs/heads/master
Commit: 53d2e8bb8c81433a96a235b8a0f8a485278cd0b6
Parents: 40be3e4
Author: Christian Amend <ch...@sap.com>
Authored: Fri Jan 8 10:03:04 2016 +0100
Committer: Christian Amend <ch...@sap.com>
Committed: Fri Jan 8 10:03:04 2016 +0100

----------------------------------------------------------------------
 dist/server-lib/src/main/resources/LICENSE      | 67 --------------------
 dist/server-lib/src/main/resources/NOTICE       | 31 +--------
 fit/pom.xml                                     |  1 -
 .../olingo/server/core/uri/parser/RawUri.java   | 46 --------------
 .../queryoption/expression/ExpressionImpl.java  | 25 --------
 5 files changed, 1 insertion(+), 169 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/53d2e8bb/dist/server-lib/src/main/resources/LICENSE
----------------------------------------------------------------------
diff --git a/dist/server-lib/src/main/resources/LICENSE b/dist/server-lib/src/main/resources/LICENSE
index f858fe4..1685307 100644
--- a/dist/server-lib/src/main/resources/LICENSE
+++ b/dist/server-lib/src/main/resources/LICENSE
@@ -205,73 +205,6 @@ See the License for the specific language governing permissions and
 limitations under the License.
 
 
-From: 'abego Software GmbH, Germany' (http://abego-software.de) - abego
-TreeLayout Core (http://code.google.com/p/treelayout/)
-org.abego.treelayout:org.abego.treelayout.core:jar:1.0.1 License: BSD 3-Clause
-"New" or "Revised" License (BSD-3-Clause)
-(http://treelayout.googlecode.com/files/LICENSE.TXT)
-
-[The "BSD license"]
-Copyright (c) 2011, abego Software GmbH, Germany (http://www.abego.org)
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without 
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, 
-   this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice, 
-   this list of conditions and the following disclaimer in the documentation 
-   and/or other materials provided with the distribution.
-3. Neither the name of the abego Software GmbH nor the names of its 
-   contributors may be used to endorse or promote products derived from this 
-   software without specific prior written permission.
-   
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
-POSSIBILITY OF SUCH DAMAGE.
-
-
-
-
-From: 'ANTLR' (http://www.antlr.org) - ANTLR 4 Runtime
-(http://www.antlr.org/antlr4-runtime) org.antlr:antlr4-runtime:jar:4.1 License:
-The BSD License (http://www.antlr.org/license.html)
-
-[The BSD License]
-Copyright (c) 2012 Terence Parr and Sam Harwell
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-    Redistributions of source code must retain the above copyright notice, this
-    list of conditions and the following disclaimer. Redistributions in binary
-    form must reproduce the above copyright notice, this list of conditions and
-    the following disclaimer in the documentation and/or other materials
-    provided with the distribution. Neither the name of the author nor the
-    names of its contributors may be used to endorse or promote products
-    derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
 From: 'fasterxml.com' (http://fasterxml.com) - Stax2 API
 (http://wiki.fasterxml.com/WoodstoxStax2)
 org.codehaus.woodstox:stax2-api:bundle:3.1.4 License: The BSD License

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/53d2e8bb/dist/server-lib/src/main/resources/NOTICE
----------------------------------------------------------------------
diff --git a/dist/server-lib/src/main/resources/NOTICE b/dist/server-lib/src/main/resources/NOTICE
index 5a87ef7..bb34cf8 100644
--- a/dist/server-lib/src/main/resources/NOTICE
+++ b/dist/server-lib/src/main/resources/NOTICE
@@ -18,33 +18,4 @@ FasterXML.com (http://fasterxml.com).
 ## Credits
 A list of contributors may be found from CREDITS file, which is included
 in some artifacts (usually source distributions); but is always available
-from the source code management (SCM) system project uses.
-
-This distribution includes TreeLayout Core (http://code.google.com/p/treelayout/)
-Copyright (c) 2011, abego Software GmbH, Germany (http://www.abego.org)
-All rights reserved.
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-1. Redistributions of source code must retain the above copyright notice,
-   this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice,
-   this list of conditions and the following disclaimer in the documentation
-   and/or other materials provided with the distribution.
-3. Neither the name of the abego Software GmbH nor the names of its
-   contributors may be used to endorse or promote products derived from this
-   software without specific prior written permission.
-(http://treelayout.googlecode.com/files/LICENSE.TXT)
-
-This distribution includes  ANTLR 4 Runtime (http://www.antlr.org/antlr4-runtime)
-Copyright (c) 2012 Terence Parr and Sam Harwell
-All rights reserved.
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-Redistributions of source code must retain the above copyright notice,
-this list of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice,
-this list of conditions and the following disclaimer in the documentation
-and/or other materials provided with the distribution.
-Neither the name of the author nor the names of its contributors may be used to
-endorse or promote products derived from this software without specific prior written permission.
-(http://www.antlr.org/license.html)
+from the source code management (SCM) system project uses.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/53d2e8bb/fit/pom.xml
----------------------------------------------------------------------
diff --git a/fit/pom.xml b/fit/pom.xml
index 34eff39..08dd7fc 100644
--- a/fit/pom.xml
+++ b/fit/pom.xml
@@ -239,7 +239,6 @@
               <exclude>org/apache/olingo/**/tecsvc/**/*.class</exclude>
               <exclude>org/apache/olingo/**/fit/**/*.class</exclude>
               <exclude>org/apache/olingo/**/testutil/**/*.class</exclude>
-              <exclude>org/apache/olingo/**/antlr/**/*.class</exclude>
             </excludes>
           </instrumentation>
           <check/>

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/53d2e8bb/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/RawUri.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/RawUri.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/RawUri.java
deleted file mode 100644
index 231317f..0000000
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/RawUri.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.List;
-
-public class RawUri {
-  public String uri;
-  public String scheme;
-  public String authority;
-  public String path;
-  public String queryOptionString;
-  public String fragment;
-  public List<QueryOption> queryOptionList;
-  public List<QueryOption> queryOptionListDecoded;
-
-  public List<String> pathSegmentList;
-  public List<String> pathSegmentListDecoded;
-
-  public static class QueryOption {
-    public String name;
-    public String value;
-
-    QueryOption(final String name, final String value) {
-      this.name = name;
-      this.value = value;
-    }
-
-  }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/53d2e8bb/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/ExpressionImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/ExpressionImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/ExpressionImpl.java
deleted file mode 100644
index e64a363..0000000
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/ExpressionImpl.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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.queryoption.expression;
-
-import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
-
-public abstract class ExpressionImpl implements Expression {
-  // No additional methods needed for now.
-}


[26/30] olingo-odata4 git commit: Merge branch 'master' into OLINGO-834_Filter_Parser

Posted by ch...@apache.org.
Merge branch 'master' into OLINGO-834_Filter_Parser

Conflicts:
	lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceComplexPropertyImpl.java
	lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceCountImpl.java
	lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceEntitySetImpl.java
	lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceItImpl.java
	lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceLambdaAllImpl.java
	lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceLambdaAnyImpl.java
	lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceLambdaVarImpl.java
	lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceNavigationPropertyImpl.java
	lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourcePrimitivePropertyImpl.java
	lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceRefImpl.java
	lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceRootImpl.java
	lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceSingletonImpl.java
	lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceStartingTypeFilterImpl.java
	lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceWithKeysImpl.java
	lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/CheckFullContextListener.java
	lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java
	lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/RawUri.java
	lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriContext.java
	lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriDecoder.java
	lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParseTreeVisitor.java
	lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParserSemanticException.java
	lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/ExpressionImpl.java
	lib/server-core/src/main/java/org/apache/olingo/server/core/uri/validator/UriValidator.java
	lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java


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

Branch: refs/heads/master
Commit: 010642c506d593c83cfb136cd9f5ddb815bf8ba7
Parents: 8925274 0d6f482
Author: Christian Amend <ch...@sap.com>
Authored: Thu Jan 7 14:27:27 2016 +0100
Committer: Christian Amend <ch...@sap.com>
Committed: Thu Jan 7 14:27:27 2016 +0100

----------------------------------------------------------------------
 dist/android-lib/pom.xml                        |   2 +-
 dist/client-lib/pom.xml                         |   2 +-
 dist/javadoc/pom.xml                            |   2 +-
 dist/pom.xml                                    |   2 +-
 dist/server-lib/pom.xml                         |   2 +-
 ext/client-android/pom.xml                      |   2 +-
 ext/client-proxy/pom.xml                        |   2 +-
 ext/karaf/karaf-features/pom.xml                |   2 +-
 ext/karaf/karaf-fit/pom.xml                     |   2 +-
 ext/karaf/pom.xml                               |   2 +-
 ext/pojogen-maven-plugin/pom.xml                |   2 +-
 ext/pom.xml                                     |   2 +-
 fit/pom.xml                                     |   2 +-
 lib/client-api/pom.xml                          |   2 +-
 lib/client-core/pom.xml                         |   2 +-
 .../olingo/client/core/uri/URIBuilderImpl.java  |   4 +-
 .../olingo/client/core/uri/URIBuilderTest.java  |  15 +-
 lib/commons-api/pom.xml                         |   2 +-
 lib/commons-core/pom.xml                        |   2 +-
 lib/pom.xml                                     |   2 +-
 lib/server-api/pom.xml                          |   2 +-
 .../apache/olingo/server/api/HttpHeaders.java   |   4 +-
 .../org/apache/olingo/server/api/OData.java     |   6 +-
 .../server/api/ODataApplicationException.java   |   4 +-
 .../olingo/server/api/ODataHttpHandler.java     |   4 +-
 .../server/api/ODataLibraryException.java       |   4 +-
 .../apache/olingo/server/api/ODataRequest.java  |   6 +-
 .../apache/olingo/server/api/ODataResponse.java |   5 +-
 .../olingo/server/api/ODataServerError.java     |   4 +-
 .../olingo/server/api/ServiceMetadata.java      |   4 +-
 .../olingo/server/api/batch/BatchFacade.java    | 106 +++++-----
 .../olingo/server/api/batch/package-info.java   |   4 +-
 .../server/api/debug/DebugInformation.java      |  16 +-
 .../server/api/debug/DebugResponseHelper.java   |   4 +-
 .../olingo/server/api/debug/DebugSupport.java   |   9 +-
 .../server/api/debug/DefaultDebugSupport.java   |   8 +-
 .../server/api/debug/RuntimeMeasurement.java    |  12 +-
 .../olingo/server/api/debug/package-info.java   |   4 +-
 .../api/deserializer/DeserializerException.java |   4 +-
 .../api/deserializer/DeserializerResult.java    |   4 +-
 .../deserializer/FixedFormatDeserializer.java   |  12 +-
 .../api/deserializer/ODataDeserializer.java     |  10 +-
 .../batch/BatchDeserializerException.java       |  14 +-
 .../api/deserializer/batch/BatchOptions.java    |   8 +-
 .../deserializer/batch/BatchRequestPart.java    |   4 +-
 .../deserializer/batch/ODataResponsePart.java   |   8 +-
 .../api/deserializer/batch/package-info.java    |   4 +-
 .../server/api/deserializer/package-info.java   |   4 +-
 .../server/api/etag/CustomETagSupport.java      |   4 +-
 .../olingo/server/api/etag/ETagHelper.java      |  22 +-
 .../server/api/etag/PreconditionException.java  |   4 +-
 .../api/etag/ServiceMetadataETagSupport.java    |   6 +-
 .../olingo/server/api/etag/package-info.java    |   4 +-
 .../apache/olingo/server/api/package-info.java  |   4 +-
 .../olingo/server/api/prefer/Preferences.java   |  13 +-
 .../server/api/prefer/PreferencesApplied.java   |  16 +-
 .../olingo/server/api/prefer/package-info.java  |   4 +-
 .../ActionComplexCollectionProcessor.java       |   4 +-
 .../api/processor/ActionComplexProcessor.java   |   4 +-
 .../ActionEntityCollectionProcessor.java        |   4 +-
 .../api/processor/ActionEntityProcessor.java    |   4 +-
 .../ActionPrimitiveCollectionProcessor.java     |   4 +-
 .../api/processor/ActionPrimitiveProcessor.java |   4 +-
 .../api/processor/ActionVoidProcessor.java      |   4 +-
 .../server/api/processor/BatchProcessor.java    |   4 +-
 .../processor/ComplexCollectionProcessor.java   |   4 +-
 .../server/api/processor/ComplexProcessor.java  |   4 +-
 .../CountComplexCollectionProcessor.java        |   4 +-
 .../CountEntityCollectionProcessor.java         |   4 +-
 .../CountPrimitiveCollectionProcessor.java      |   4 +-
 .../server/api/processor/DefaultProcessor.java  |   4 +-
 .../server/api/processor/DeltaProcessor.java    |  30 +--
 .../processor/EntityCollectionProcessor.java    |   4 +-
 .../server/api/processor/EntityProcessor.java   |   6 +-
 .../server/api/processor/ErrorProcessor.java    |   6 +-
 .../api/processor/MediaEntityProcessor.java     |   4 +-
 .../server/api/processor/MetadataProcessor.java |   4 +-
 .../processor/PrimitiveCollectionProcessor.java |   4 +-
 .../api/processor/PrimitiveProcessor.java       |   6 +-
 .../api/processor/PrimitiveValueProcessor.java  |   6 +-
 .../olingo/server/api/processor/Processor.java  |   4 +-
 .../processor/ReferenceCollectionProcessor.java |   4 +-
 .../api/processor/ReferenceProcessor.java       |   4 +-
 .../api/processor/ServiceDocumentProcessor.java |   4 +-
 .../server/api/processor/package-info.java      |   5 +-
 .../serializer/BatchSerializerException.java    |   7 +-
 .../serializer/ComplexSerializerOptions.java    |  10 +-
 .../serializer/CustomContentTypeSupport.java    |   4 +-
 .../EntityCollectionSerializerOptions.java      |   8 +-
 .../api/serializer/EntitySerializerOptions.java |   8 +-
 .../api/serializer/FixedFormatSerializer.java   |   6 +-
 .../server/api/serializer/ODataSerializer.java  |  52 ++---
 .../serializer/PrimitiveSerializerOptions.java  |  10 +-
 .../PrimitiveValueSerializerOptions.java        |   4 +-
 .../ReferenceCollectionSerializerOptions.java   |  12 +-
 .../serializer/ReferenceSerializerOptions.java  |   4 +-
 .../api/serializer/RepresentationType.java      |   4 +-
 .../api/serializer/SerializerException.java     |   4 +-
 .../server/api/serializer/SerializerResult.java |   4 +-
 .../server/api/serializer/package-info.java     |   4 +-
 .../apache/olingo/server/api/uri/UriHelper.java |  10 +-
 .../apache/olingo/server/api/uri/UriInfo.java   |   6 +-
 .../olingo/server/api/uri/UriInfoAll.java       |   6 +-
 .../olingo/server/api/uri/UriInfoBatch.java     |   6 +-
 .../olingo/server/api/uri/UriInfoCrossjoin.java |   8 +-
 .../olingo/server/api/uri/UriInfoEntityId.java  |   4 +-
 .../olingo/server/api/uri/UriInfoKind.java      |   4 +-
 .../olingo/server/api/uri/UriInfoMetadata.java  |   4 +-
 .../olingo/server/api/uri/UriInfoResource.java  |   4 +-
 .../olingo/server/api/uri/UriInfoService.java   |   6 +-
 .../olingo/server/api/uri/UriParameter.java     |   4 +-
 .../olingo/server/api/uri/UriResource.java      |   4 +-
 .../server/api/uri/UriResourceAction.java       |   4 +-
 .../api/uri/UriResourceComplexProperty.java     |   4 +-
 .../olingo/server/api/uri/UriResourceCount.java |   6 +-
 .../server/api/uri/UriResourceEntitySet.java    |   4 +-
 .../server/api/uri/UriResourceFunction.java     |   4 +-
 .../olingo/server/api/uri/UriResourceIt.java    |   4 +-
 .../olingo/server/api/uri/UriResourceKind.java  |   4 +-
 .../server/api/uri/UriResourceLambdaAll.java    |   4 +-
 .../server/api/uri/UriResourceLambdaAny.java    |   4 +-
 .../api/uri/UriResourceLambdaVariable.java      |   4 +-
 .../server/api/uri/UriResourceNavigation.java   |   4 +-
 .../server/api/uri/UriResourcePartTyped.java    |   6 +-
 .../api/uri/UriResourcePrimitiveProperty.java   |   6 +-
 .../server/api/uri/UriResourceProperty.java     |   4 +-
 .../olingo/server/api/uri/UriResourceRef.java   |   6 +-
 .../olingo/server/api/uri/UriResourceRoot.java  |   6 +-
 .../server/api/uri/UriResourceSingleton.java    |   4 +-
 .../olingo/server/api/uri/UriResourceValue.java |   6 +-
 .../olingo/server/api/uri/package-info.java     |   6 +-
 .../api/uri/queryoption/AliasQueryOption.java   |   4 +-
 .../server/api/uri/queryoption/CountOption.java |   4 +-
 .../api/uri/queryoption/CustomQueryOption.java  |   6 +-
 .../server/api/uri/queryoption/ExpandItem.java  |   4 +-
 .../api/uri/queryoption/ExpandOption.java       |   4 +-
 .../api/uri/queryoption/FilterOption.java       |   4 +-
 .../api/uri/queryoption/FormatOption.java       |   4 +-
 .../server/api/uri/queryoption/IdOption.java    |   4 +-
 .../api/uri/queryoption/LevelsExpandOption.java |   4 +-
 .../server/api/uri/queryoption/OrderByItem.java |   4 +-
 .../api/uri/queryoption/OrderByOption.java      |   4 +-
 .../server/api/uri/queryoption/QueryOption.java |   4 +-
 .../api/uri/queryoption/SearchOption.java       |   4 +-
 .../server/api/uri/queryoption/SelectItem.java  |   4 +-
 .../api/uri/queryoption/SelectOption.java       |   4 +-
 .../server/api/uri/queryoption/SkipOption.java  |   4 +-
 .../api/uri/queryoption/SkipTokenOption.java    |   4 +-
 .../api/uri/queryoption/SystemQueryOption.java  |   4 +-
 .../uri/queryoption/SystemQueryOptionKind.java  |   4 +-
 .../server/api/uri/queryoption/TopOption.java   |   4 +-
 .../api/uri/queryoption/expression/Alias.java   |   4 +-
 .../api/uri/queryoption/expression/Binary.java  |   4 +-
 .../expression/BinaryOperatorKind.java          |   4 +-
 .../uri/queryoption/expression/Enumeration.java |   4 +-
 .../uri/queryoption/expression/Expression.java  |   6 +-
 .../expression/ExpressionVisitException.java    |   4 +-
 .../expression/ExpressionVisitor.java           |   4 +-
 .../uri/queryoption/expression/LambdaRef.java   |   4 +-
 .../api/uri/queryoption/expression/Literal.java |  10 +-
 .../api/uri/queryoption/expression/Member.java  |   4 +-
 .../api/uri/queryoption/expression/Method.java  |   4 +-
 .../uri/queryoption/expression/MethodKind.java  |   4 +-
 .../uri/queryoption/expression/TypeLiteral.java |   4 +-
 .../api/uri/queryoption/expression/Unary.java   |   4 +-
 .../expression/UnaryOperatorKind.java           |   4 +-
 .../expression/VisitableExpression.java         |   4 +-
 .../queryoption/expression/package-info.java    |   4 +-
 .../api/uri/queryoption/package-info.java       |   4 +-
 .../uri/queryoption/search/SearchBinary.java    |   4 +-
 .../search/SearchBinaryOperatorKind.java        |   4 +-
 .../queryoption/search/SearchExpression.java    |  18 +-
 .../api/uri/queryoption/search/SearchTerm.java  |   4 +-
 .../api/uri/queryoption/search/SearchUnary.java |   5 +-
 .../search/SearchUnaryOperatorKind.java         |   4 +-
 .../uri/queryoption/search/package-info.java    |   4 +-
 .../olingo/server/api/ODataRequestTest.java     |   4 +-
 .../server/api/TranslatedExceptionsTest.java    |   4 +-
 .../api/prefer/PreferencesAppliedTest.java      |  22 +-
 lib/server-core-ext/pom.xml                     |   2 +-
 lib/server-core/pom.xml                         |   2 +-
 .../olingo/server/core/ContentNegotiator.java   |  18 +-
 .../server/core/ContentNegotiatorException.java |   4 +-
 .../server/core/DefaultRedirectProcessor.java   |   4 +-
 .../olingo/server/core/ODataDispatcher.java     | 132 ++++++------
 .../server/core/ODataExceptionHelper.java       |  14 +-
 .../apache/olingo/server/core/ODataHandler.java |  18 +-
 .../server/core/ODataHandlerException.java      |   6 +-
 .../server/core/ODataHttpHandlerImpl.java       |   8 +-
 .../apache/olingo/server/core/ODataImpl.java    |  10 +-
 .../olingo/server/core/RedirectProcessor.java   |   4 +-
 .../olingo/server/core/ServiceMetadataImpl.java |   8 +-
 .../core/batchhandler/BatchFacadeImpl.java      |   8 +-
 .../server/core/batchhandler/BatchHandler.java  |   4 +-
 .../core/batchhandler/BatchPartHandler.java     |   6 +-
 .../BatchReferenceRewriter.java                 |   4 +-
 .../core/debug/DebugResponseHelperImpl.java     | 118 +++++------
 .../olingo/server/core/debug/DebugTab.java      |   5 +-
 .../olingo/server/core/debug/DebugTabBody.java  |  12 +-
 .../server/core/debug/DebugTabRequest.java      |  28 +--
 .../server/core/debug/DebugTabResponse.java     |  14 +-
 .../server/core/debug/DebugTabRuntime.java      |  34 +--
 .../server/core/debug/DebugTabServer.java       |  14 +-
 .../server/core/debug/DebugTabStacktrace.java   |  24 +--
 .../olingo/server/core/debug/DebugTabUri.java   |  49 +++--
 .../core/debug/ExpressionJsonVisitor.java       |  12 +-
 .../server/core/debug/ServerCoreDebugger.java   |  12 +-
 .../deserializer/DeserializerResultImpl.java    |   4 +-
 .../FixedFormatDeserializerImpl.java            |  10 +-
 .../core/deserializer/batch/BatchBodyPart.java  |   8 +-
 .../deserializer/batch/BatchChangeSetPart.java  |   4 +-
 .../deserializer/batch/BatchLineReader.java     |  44 ++--
 .../core/deserializer/batch/BatchParser.java    |  10 +-
 .../deserializer/batch/BatchParserCommon.java   |  14 +-
 .../core/deserializer/batch/BatchPart.java      |   4 +-
 .../deserializer/batch/BatchQueryOperation.java |   4 +-
 .../batch/BatchRequestTransformator.java        |  20 +-
 .../batch/BatchTransformatorCommon.java         |   8 +-
 .../server/core/deserializer/batch/Header.java  |   4 +-
 .../core/deserializer/batch/HeaderField.java    |   4 +-
 .../batch/HttpRequestStatusLine.java            |   6 +-
 .../server/core/deserializer/batch/Line.java    |   4 +-
 .../deserializer/helper/ExpandTreeBuilder.java  |   4 +-
 .../helper/ExpandTreeBuilderImpl.java           |   4 +-
 .../json/ODataJsonDeserializer.java             | 113 +++++-----
 .../deserializer/xml/ODataXmlDeserializer.java  |  34 +--
 .../olingo/server/core/etag/ETagHelperImpl.java |   8 +-
 .../server/core/etag/ETagInformation.java       |   4 +-
 .../olingo/server/core/etag/ETagParser.java     |  22 +-
 .../core/etag/PreconditionsValidator.java       |  14 +-
 .../olingo/server/core/prefer/PreferParser.java |  40 ++--
 .../server/core/prefer/PreferencesImpl.java     |  13 +-
 .../serializer/AbstractODataSerializer.java     |   7 +-
 .../serializer/AsyncResponseSerializer.java     |  18 +-
 .../serializer/BatchResponseSerializer.java     |  45 ++--
 .../serializer/FixedFormatSerializerImpl.java   |   6 +-
 .../core/serializer/SerializerResultImpl.java   |   4 +-
 .../serializer/json/ODataErrorSerializer.java   |   4 +-
 .../serializer/json/ODataJsonSerializer.java    |  94 ++++-----
 .../json/ServiceDocumentJsonSerializer.java     |  12 +-
 .../serializer/utils/CircleStreamBuffer.java    |   4 +-
 .../serializer/utils/ContentTypeHelper.java     |  16 +-
 .../serializer/utils/ContextURLBuilder.java     |  22 +-
 .../core/serializer/utils/ContextURLHelper.java |  17 +-
 .../serializer/utils/ExpandSelectHelper.java    |   4 +-
 .../xml/MetadataDocumentXmlSerializer.java      |  38 ++--
 .../core/serializer/xml/ODataXmlSerializer.java |  27 +--
 .../xml/ServiceDocumentXmlSerializer.java       |  12 +-
 .../olingo/server/core/uri/UriHelperImpl.java   |   8 +-
 .../olingo/server/core/uri/UriInfoImpl.java     |   4 +-
 .../server/core/uri/UriParameterImpl.java       |   4 +-
 .../server/core/uri/UriResourceActionImpl.java  |   8 +-
 .../uri/UriResourceComplexPropertyImpl.java     |   4 +-
 .../server/core/uri/UriResourceCountImpl.java   |   4 +-
 .../core/uri/UriResourceEntitySetImpl.java      |   6 +-
 .../core/uri/UriResourceFunctionImpl.java       |   6 +-
 .../olingo/server/core/uri/UriResourceImpl.java |   4 +-
 .../server/core/uri/UriResourceItImpl.java      |   4 +-
 .../core/uri/UriResourceLambdaAllImpl.java      |   4 +-
 .../core/uri/UriResourceLambdaAnyImpl.java      |   4 +-
 .../core/uri/UriResourceLambdaVarImpl.java      |   4 +-
 .../uri/UriResourceNavigationPropertyImpl.java  |   4 +-
 .../uri/UriResourcePrimitivePropertyImpl.java   |   4 +-
 .../server/core/uri/UriResourceRefImpl.java     |   4 +-
 .../server/core/uri/UriResourceRootImpl.java    |   4 +-
 .../core/uri/UriResourceSingletonImpl.java      |   4 +-
 .../uri/UriResourceStartingTypeFilterImpl.java  |   4 +-
 .../server/core/uri/UriResourceTypedImpl.java   |   5 +-
 .../server/core/uri/UriResourceValueImpl.java   |   4 +-
 .../core/uri/UriResourceWithKeysImpl.java       |   4 +-
 .../uri/parser/CheckFullContextListener.java    |  60 ++++++
 .../olingo/server/core/uri/parser/Parser.java   |   4 +-
 .../olingo/server/core/uri/parser/RawUri.java   |  46 +++++
 .../server/core/uri/parser/UriDecoder.java      |   4 +-
 .../core/uri/parser/UriParserException.java     |   4 +-
 .../uri/parser/UriParserSemanticException.java  |   8 +-
 .../uri/parser/UriParserSyntaxException.java    |   6 +-
 .../uri/parser/search/SearchBinaryImpl.java     |   7 +-
 .../uri/parser/search/SearchExpressionImpl.java |   4 +-
 .../core/uri/parser/search/SearchParser.java    |  60 +++---
 .../parser/search/SearchParserException.java    |   6 +-
 .../uri/parser/search/SearchQueryToken.java     |   9 +-
 .../core/uri/parser/search/SearchTermImpl.java  |   6 +-
 .../core/uri/parser/search/SearchTokenizer.java | 129 ++++++------
 .../parser/search/SearchTokenizerException.java |   6 +-
 .../core/uri/parser/search/SearchUnaryImpl.java |   6 +-
 .../uri/queryoption/AliasQueryOptionImpl.java   |   4 +-
 .../core/uri/queryoption/CountOptionImpl.java   |   4 +-
 .../uri/queryoption/CustomQueryOptionImpl.java  |   4 +-
 .../core/uri/queryoption/ExpandItemImpl.java    |   8 +-
 .../core/uri/queryoption/ExpandOptionImpl.java  |   4 +-
 .../core/uri/queryoption/FilterOptionImpl.java  |   4 +-
 .../core/uri/queryoption/FormatOptionImpl.java  |   4 +-
 .../core/uri/queryoption/IdOptionImpl.java      |   4 +-
 .../core/uri/queryoption/LevelsOptionImpl.java  |   4 +-
 .../core/uri/queryoption/OrderByItemImpl.java   |   4 +-
 .../core/uri/queryoption/OrderByOptionImpl.java |   4 +-
 .../core/uri/queryoption/QueryOptionImpl.java   |   4 +-
 .../core/uri/queryoption/SearchOptionImpl.java  |   6 +-
 .../core/uri/queryoption/SelectItemImpl.java    |   4 +-
 .../core/uri/queryoption/SelectOptionImpl.java  |   4 +-
 .../core/uri/queryoption/SkipOptionImpl.java    |   4 +-
 .../uri/queryoption/SkipTokenOptionImpl.java    |   4 +-
 .../uri/queryoption/SystemQueryOptionImpl.java  |   4 +-
 .../core/uri/queryoption/TopOptionImpl.java     |   4 +-
 .../uri/queryoption/expression/AliasImpl.java   |   4 +-
 .../uri/queryoption/expression/BinaryImpl.java  |   4 +-
 .../queryoption/expression/EnumerationImpl.java |   4 +-
 .../queryoption/expression/ExpressionImpl.java  |  25 +++
 .../queryoption/expression/LambdaRefImpl.java   |   4 +-
 .../uri/queryoption/expression/LiteralImpl.java |   4 +-
 .../uri/queryoption/expression/MemberImpl.java  |   4 +-
 .../uri/queryoption/expression/MethodImpl.java  |   4 +-
 .../queryoption/expression/TypeLiteralImpl.java |   4 +-
 .../uri/queryoption/expression/UnaryImpl.java   |   4 +-
 .../uri/validator/UriValidationException.java   |   7 +-
 .../server/core/uri/validator/UriValidator.java | 161 ++++++++-------
 .../server/core/ContentNegotiatorTest.java      |   8 +-
 .../olingo/server/core/ExceptionHelperTest.java |   6 +-
 .../server/core/ODataHttpHandlerImplTest.java   |   6 +-
 .../olingo/server/core/ODataImplTest.java       |   4 +-
 .../core/TranslatedExceptionSubclassesTest.java |   4 +-
 .../batchhandler/MockedBatchHandlerTest.java    |   4 +-
 .../server/core/debug/AbstractDebugTabTest.java |   8 +-
 .../server/core/debug/DebugTabBodyTest.java     |   4 +-
 .../server/core/debug/DebugTabRequestTest.java  |   4 +-
 .../server/core/debug/DebugTabResponseTest.java |   4 +-
 .../server/core/debug/DebugTabServerTest.java   |   6 +-
 .../core/debug/ServerCoreDebuggerTest.java      |   6 +-
 .../FixedFormatDeserializerTest.java            |   4 +-
 .../deserializer/batch/BatchLineReaderTest.java |   4 +-
 .../batch/BatchParserCommonTest.java            |   4 +-
 .../batch/BatchRequestParserTest.java           |  16 +-
 .../core/deserializer/batch/HeaderTest.java     |   4 +-
 .../batch/HttpRequestStatusLineTest.java        |   4 +-
 .../json/ODataJsonDeserializerBasicTest.java    |   4 +-
 .../olingo/server/core/etag/ETagHelperTest.java |   4 +-
 .../olingo/server/core/etag/ETagParserTest.java |   4 +-
 .../server/core/prefer/PreferencesTest.java     |   8 +-
 .../serializer/AsyncResponseSerializerTest.java |  18 +-
 .../serializer/BatchResponseSerializerTest.java |  20 +-
 .../serializer/FixedFormatSerializerTest.java   |   4 +-
 .../json/ServerErrorSerializerTest.java         |   8 +-
 .../utils/CircleStreamBufferTest.java           |   5 +-
 .../serializer/utils/ContextURLBuilderTest.java |   4 +-
 .../xml/MetadataDocumentXmlSerializerTest.java  | 205 ++++++++++---------
 .../xml/ServerErrorXmlSerializerTest.java       |  18 +-
 .../xml/ServiceDocumentXmlSerializerTest.java   |  24 +--
 .../search/SearchParserAndTokenizerTest.java    |  88 ++++----
 .../uri/parser/search/SearchParserTest.java     |  17 +-
 .../uri/parser/search/SearchTokenizerTest.java  | 112 +++++-----
 lib/server-tecsvc/pom.xml                       |   2 +-
 lib/server-test/pom.xml                         |   2 +-
 pom.xml                                         |   2 +-
 samples/client/pom.xml                          |   2 +-
 samples/osgi/server/pom.xml                     |   2 +-
 samples/pom.xml                                 |   2 +-
 samples/server/pom.xml                          |   2 +-
 samples/tutorials/p0_all/pom.xml                |   4 +-
 samples/tutorials/p10_media/pom.xml             |   4 +-
 samples/tutorials/p11_batch/pom.xml             |   4 +-
 samples/tutorials/p12_deep_insert/pom.xml       |   4 +-
 .../p12_deep_insert_preparation/pom.xml         |   4 +-
 samples/tutorials/p1_read/pom.xml               |   4 +-
 samples/tutorials/p2_readep/pom.xml             |   4 +-
 samples/tutorials/p3_write/pom.xml              |   4 +-
 samples/tutorials/p4_navigation/pom.xml         |   4 +-
 samples/tutorials/p5_queryoptions-tcs/pom.xml   |   4 +-
 samples/tutorials/p6_queryoptions-es/pom.xml    |   4 +-
 samples/tutorials/p7_queryoptions-o/pom.xml     |   4 +-
 samples/tutorials/p8_queryoptions-f/pom.xml     |   4 +-
 samples/tutorials/p9_action/pom.xml             |   4 +-
 samples/tutorials/p9_action_preparation/pom.xml |   4 +-
 samples/tutorials/pom.xml                       |   2 +-
 374 files changed, 2042 insertions(+), 1851 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010642c5/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/ExpandItem.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010642c5/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010642c5/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/helper/ExpandTreeBuilder.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010642c5/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriHelperImpl.java
----------------------------------------------------------------------
diff --cc lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriHelperImpl.java
index 3bc5ad0,f1bd75e..b2917f4
--- 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
@@@ -108,11 -107,11 +108,11 @@@ public class UriHelperImpl implements U
      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);
-         
+ 
          return entityUriResource;
        }
  

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010642c5/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceActionImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010642c5/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceComplexPropertyImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010642c5/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceCountImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010642c5/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceEntitySetImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010642c5/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceFunctionImpl.java
----------------------------------------------------------------------
diff --cc lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceFunctionImpl.java
index 7784062,42361e0..433ebb5
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceFunctionImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceFunctionImpl.java
@@@ -49,9 -46,15 +49,9 @@@ public class UriResourceFunctionImpl ex
    public List<UriParameter> getParameters() {
      return parameters == null ?
          Collections.<UriParameter> emptyList() :
-         Collections.unmodifiableList(parameters);
+           Collections.unmodifiableList(parameters);
    }
  
 -  public UriResourceFunctionImpl setParameters(final List<UriParameter> parameters) {
 -    isParameterListFilled = true;
 -    this.parameters = parameters;
 -    return this;
 -  }
 -
    @Override
    public EdmFunction getFunction() {
      return function;

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010642c5/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010642c5/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceItImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010642c5/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceLambdaAllImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010642c5/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceLambdaAnyImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010642c5/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceLambdaVarImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010642c5/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceNavigationPropertyImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010642c5/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourcePrimitivePropertyImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010642c5/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceRefImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010642c5/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceRootImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010642c5/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceSingletonImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010642c5/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceStartingTypeFilterImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010642c5/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceTypedImpl.java
----------------------------------------------------------------------
diff --cc lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceTypedImpl.java
index 9930a7e,cdfa013..d44b9e6
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceTypedImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceTypedImpl.java
@@@ -40,10 -40,16 +40,11 @@@ public abstract class UriResourceTypedI
      return this;
    }
  
+   @Override
    public String getSegmentValue(final boolean includeFilters) {
 -    if (includeFilters) {
 -      if (typeFilter != null) {
 -        return getSegmentValue() + "/" + typeFilter.getFullQualifiedName().toString();
 -      } else {
 -        return getSegmentValue();
 -      }
 -    }
 -    return getSegmentValue();
 +    return includeFilters && typeFilter != null ?
 +        getSegmentValue() + "/" + typeFilter.getFullQualifiedName().getFullQualifiedNameAsString() :
 +        getSegmentValue();
    }
  
    @Override

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010642c5/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceValueImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010642c5/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceWithKeysImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010642c5/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010642c5/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriDecoder.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010642c5/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParserSemanticException.java
----------------------------------------------------------------------
diff --cc lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParserSemanticException.java
index cc31e34,33dd321..8f5aa67
--- 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
@@@ -79,14 -79,12 +79,14 @@@ public class UriParserSemanticExceptio
      /** parameter: not implemented part */
      NOT_IMPLEMENTED,
      /** parameter: namespace **/
-     NAMESPACE_NOT_ALLOWED_AT_FIRST_ELEMENT, 
+     NAMESPACE_NOT_ALLOWED_AT_FIRST_ELEMENT,
      /** parameter: complex parameter value */
-     COMPLEX_PARAMETER_IN_RESOURCE_PATH, 
+     COMPLEX_PARAMETER_IN_RESOURCE_PATH,
      /** parameter: function import name */
 -    FUNCTION_IMPORT_NOT_ALLOWED;
 -
 +    FUNCTION_IMPORT_NOT_ALLOWED, 
 +    /** parameters: left type, right type */
 +    TYPES_NOT_COMPATIBLE;
 +    
      @Override
      public String getKey() {
        return name();

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010642c5/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/OrderByItemImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010642c5/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/AliasImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010642c5/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/BinaryImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010642c5/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/EnumerationImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010642c5/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/LambdaRefImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010642c5/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/LiteralImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010642c5/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MemberImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010642c5/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MethodImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010642c5/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/TypeLiteralImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010642c5/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/UnaryImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010642c5/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/validator/UriValidator.java
----------------------------------------------------------------------
diff --cc lib/server-core/src/main/java/org/apache/olingo/server/core/uri/validator/UriValidator.java
index 3ccd97a,9ffe696..149d1fc
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/validator/UriValidator.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/validator/UriValidator.java
@@@ -222,7 -223,14 +222,6 @@@ public class UriValidator 
  
    private RowIndexForUriType rowIndexForResourceKind(final UriInfo uriInfo) throws UriValidationException {
      RowIndexForUriType idx;
 -
 -    final int nonComposableFunctionIndex = getIndexOfLastNonComposableFunction(uriInfo);
 -    if (nonComposableFunctionIndex != -1 && (uriInfo.getUriResourceParts().size() - 1) > nonComposableFunctionIndex) {
 -      throw new UriValidationException("Non composable functions followed by further resource parts are not allowed",
 -          UriValidationException.MessageKeys.UNALLOWED_RESOURCE_PATH,
 -          uriInfo.getUriResourceParts().get(nonComposableFunctionIndex + 1).getSegmentValue());
 -    }
--
      int lastPathSegmentIndex = uriInfo.getUriResourceParts().size() - 1;
      UriResource lastPathSegment = uriInfo.getUriResourceParts().get(lastPathSegmentIndex);
  

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010642c5/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
----------------------------------------------------------------------
diff --cc lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
index f3e50a2,40c6200..9bb7d6f
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
@@@ -119,71 -119,71 +119,71 @@@ public class SearchParserAndTokenizerTe
     */
    @Test
    public void searchQueryPhraseAbnfTestcases() throws Exception {
-     //    <TestCase Name="5.1.7 Search - simple phrase" Rule="queryOptions">
+     // <TestCase Name="5.1.7 Search - simple phrase" Rule="queryOptions">
      assertQuery("\"blue green\"").resultsIn("'blue green'");
-     //    <TestCase Name="5.1.7 Search - simple phrase" Rule="queryOptions">
+     // <TestCase Name="5.1.7 Search - simple phrase" Rule="queryOptions">
      assertQuery("\"blue green\"").resultsIn("'blue green'");
-     //    <TestCase Name="5.1.7 Search - phrase with escaped double-quote" Rule="queryOptions">
-     //    <Input>$search="blue\"green"</Input>
+     // <TestCase Name="5.1.7 Search - phrase with escaped double-quote" Rule="queryOptions">
+     // <Input>$search="blue\"green"</Input>
      assertQuery("\"blue\\\"green\"").resultsIn("'blue\"green'");
  
-     //    <TestCase Name="5.1.7 Search - phrase with escaped backslash" Rule="queryOptions">
-     //    <Input>$search="blue\\green"</Input>
+     // <TestCase Name="5.1.7 Search - phrase with escaped backslash" Rule="queryOptions">
+     // <Input>$search="blue\\green"</Input>
      assertQuery("\"blue\\\\green\"").resultsIn("'blue\\green'");
-     //    <TestCase Name="5.1.7 Search - phrase with unescaped double-quote" Rule="queryOptions" FailAt="14">
+     // <TestCase Name="5.1.7 Search - phrase with unescaped double-quote" Rule="queryOptions" FailAt="14">
      assertQuery("\"blue\"green\"").resultsIn(SearchParserException.MessageKeys.TOKENIZER_EXCEPTION);
-     //    <TestCase Name="5.1.7 Search - phrase with unescaped double-quote" Rule="queryOptions" FailAt="16">
+     // <TestCase Name="5.1.7 Search - phrase with unescaped double-quote" Rule="queryOptions" FailAt="16">
      assertQuery("\"blue\"green\"").resultsIn(SearchParserException.MessageKeys.TOKENIZER_EXCEPTION);
  
-     //    <TestCase Name="5.1.7 Search - implicit AND" Rule="queryOptions">
-     //    <Input>$search=blue green</Input>
+     // <TestCase Name="5.1.7 Search - implicit AND" Rule="queryOptions">
+     // <Input>$search=blue green</Input>
      assertQuery("blue green").resultsIn("{'blue' AND 'green'}");
-     //    <TestCase Name="5.1.7 Search - implicit AND, encoced" Rule="queryOptions">
+     // <TestCase Name="5.1.7 Search - implicit AND, encoced" Rule="queryOptions">
      assertQuery("blue green").resultsIn("{'blue' AND 'green'}");
  
-     //    <TestCase Name="5.1.7 Search - AND" Rule="queryOptions">
-     //    <Input>$search=blue AND green</Input>
+     // <TestCase Name="5.1.7 Search - AND" Rule="queryOptions">
+     // <Input>$search=blue AND green</Input>
      assertQuery("blue AND green").resultsIn("{'blue' AND 'green'}");
  
-     //    <TestCase Name="5.1.7 Search - OR" Rule="queryOptions">
-     //    <Input>$search=blue OR green</Input>
+     // <TestCase Name="5.1.7 Search - OR" Rule="queryOptions">
+     // <Input>$search=blue OR green</Input>
      assertQuery("blue OR green").resultsIn("{'blue' OR 'green'}");
  
-     //    <TestCase Name="5.1.7 Search - NOT" Rule="queryOptions">
-     //    <Input>$search=blue NOT green</Input>
+     // <TestCase Name="5.1.7 Search - NOT" Rule="queryOptions">
+     // <Input>$search=blue NOT green</Input>
      assertQuery("blue NOT green").resultsIn("{'blue' AND {NOT 'green'}}");
  
-     //    <TestCase Name="5.1.7 Search - only NOT" Rule="queryOptions">
-     //    <Input>$search=NOT blue</Input>
+     // <TestCase Name="5.1.7 Search - only NOT" Rule="queryOptions">
+     // <Input>$search=NOT blue</Input>
      assertQuery("NOT blue").resultsIn("{NOT 'blue'}");
  
-     //    <TestCase Name="5.1.7 Search - multiple" Rule="queryOptions">
-     //    <Input>$search=foo AND bar OR foo AND baz OR that AND bar OR that AND baz</Input>
+     // <TestCase Name="5.1.7 Search - multiple" Rule="queryOptions">
+     // <Input>$search=foo AND bar OR foo AND baz OR that AND bar OR that AND baz</Input>
      assertQuery("foo AND bar OR foo AND baz OR that AND bar OR that AND baz")
 -    .resultsIn("{{{{'foo' AND 'bar'} OR {'foo' AND 'baz'}} OR {'that' AND 'bar'}} OR {'that' AND 'baz'}}");
 +        .resultsIn("{{{{'foo' AND 'bar'} OR {'foo' AND 'baz'}} OR {'that' AND 'bar'}} OR {'that' AND 'baz'}}");
  
-     //    <TestCase Name="5.1.7 Search - multiple" Rule="queryOptions">
-     //    <Input>$search=(foo OR that) AND (bar OR baz)</Input>
+     // <TestCase Name="5.1.7 Search - multiple" Rule="queryOptions">
+     // <Input>$search=(foo OR that) AND (bar OR baz)</Input>
      assertQuery("(foo OR that) AND (bar OR baz)").resultsIn("{{'foo' OR 'that'} AND {'bar' OR 'baz'}}");
  
-     //    <TestCase Name="5.1.7 Search - grouping" Rule="queryOptions">
-     //    <Input>$search=foo AND (bar OR baz)</Input>
+     // <TestCase Name="5.1.7 Search - grouping" Rule="queryOptions">
+     // <Input>$search=foo AND (bar OR baz)</Input>
      assertQuery("foo AND (bar OR baz)").resultsIn("{'foo' AND {'bar' OR 'baz'}}");
  
-     //    <TestCase Name="5.1.7 Search - grouping" Rule="queryOptions">
-     //    <Input>$search=(foo AND bar) OR baz</Input>
+     // <TestCase Name="5.1.7 Search - grouping" Rule="queryOptions">
+     // <Input>$search=(foo AND bar) OR baz</Input>
      assertQuery("(foo AND bar) OR baz").resultsIn("{{'foo' AND 'bar'} OR 'baz'}");
  
-     //    <TestCase Name="5.1.7 Search - grouping" Rule="queryOptions">
-     //    <Input>$search=(NOT foo) OR baz</Input>
+     // <TestCase Name="5.1.7 Search - grouping" Rule="queryOptions">
+     // <Input>$search=(NOT foo) OR baz</Input>
      assertQuery("(NOT foo) OR baz").resultsIn("{{NOT 'foo'} OR 'baz'}");
  
-     //    <TestCase Name="5.1.7 Search - grouping" Rule="queryOptions">
-     //    <Input>$search=(NOT foo)</Input>
+     // <TestCase Name="5.1.7 Search - grouping" Rule="queryOptions">
+     // <Input>$search=(NOT foo)</Input>
      assertQuery("(NOT foo)").resultsIn("{NOT 'foo'}");
  
-     //    <TestCase Name="5.1.7 Search - on entity set" Rule="odataUri">
-     //    <Input>http://serviceRoot/Products?$search=blue</Input>
+     // <TestCase Name="5.1.7 Search - on entity set" Rule="odataUri">
+     // <Input>http://serviceRoot/Products?$search=blue</Input>
      assertQuery("blue").resultsIn("'blue'");
  
      // below cases can not be tested here
@@@ -198,13 -198,19 +198,19 @@@
    }
  
    private static class Validator {
 -    private boolean log;
      private final String searchQuery;
  
-     private Validator(String searchQuery) {
+     private Validator(final String searchQuery) {
        this.searchQuery = searchQuery;
      }
  
-     private void resultsIn(SearchParserException.MessageKey key) throws SearchTokenizerException {
+     private static Validator init(final String searchQuery) {
+       return new Validator(searchQuery);
+     }
+ 
+     private void resultsIn(final SearchParserException.MessageKey key)
+         throws SearchTokenizerException {
++
        try {
          resultsIn(searchQuery);
        } catch (SearchParserException e) {


[22/30] olingo-odata4 git commit: [OLINGO-834] $expand parser in Java + clean-up

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8925274c/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java
index f505a21..3b673a6 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java
@@ -40,6 +40,15 @@ public class UriTokenizer {
     ROOT,
     IT,
 
+    EXPAND,
+    FILTER,
+    LEVELS,
+    ORDERBY,
+    SEARCH,
+    SELECT,
+    SKIP,
+    TOP,
+
     ANY,
     ALL,
 
@@ -53,8 +62,9 @@ public class UriTokenizer {
     EQ,
     STAR,
     PLUS,
-    MINUS,
+
     NULL,
+    MAX,
 
     // variable-value tokens (convention: mixed case)
     ODataIdentifier,
@@ -76,6 +86,13 @@ public class UriTokenizer {
 
     jsonArrayOrObject,
 
+    Word,
+    Phrase,
+
+    OrOperatorSearch,
+    AndOperatorSearch,
+    NotOperatorSearch,
+
     OrOperator,
     AndOperator,
     EqualsOperator,
@@ -90,6 +107,7 @@ public class UriTokenizer {
     MulOperator,
     DivOperator,
     ModOperator,
+    MinusOperator,
     NotOperator,
 
     CastMethod,
@@ -161,6 +179,10 @@ public class UriTokenizer {
     boolean found = false;
     final int previousIndex = index;
     switch (allowedTokenKind) {
+    case EOF:
+      found = index >= parseString.length();
+      break;
+
     // Constants
     case REF:
       found = nextConstant("$ref");
@@ -181,6 +203,31 @@ public class UriTokenizer {
       found = nextConstant("$it");
       break;
 
+    case EXPAND:
+      found = nextConstant("$expand");
+      break;
+    case FILTER:
+      found = nextConstant("$filter");
+      break;
+    case LEVELS:
+      found = nextConstant("$levels");
+      break;
+    case ORDERBY:
+      found = nextConstant("$orderby");
+      break;
+    case SEARCH:
+      found = nextConstant("$search");
+      break;
+    case SELECT:
+      found = nextConstant("$select");
+      break;
+    case SKIP:
+      found = nextConstant("$skip");
+      break;
+    case TOP:
+      found = nextConstant("$top");
+      break;
+
     case ANY:
       found = nextConstant("any");
       break;
@@ -218,14 +265,12 @@ public class UriTokenizer {
     case PLUS:
       found = nextCharacter('+');
       break;
-    case MINUS:
-      found = nextMinus();
-      break;
+
     case NULL:
       found = nextConstant("null");
       break;
-    case EOF:
-      found = index >= parseString.length();
+    case MAX:
+      found = nextConstant("max");
       break;
 
     // Identifiers
@@ -282,6 +327,25 @@ public class UriTokenizer {
       found = nextJsonArrayOrObject();
       break;
 
+    // Search
+    case Word:
+      found = nextWord();
+      break;
+    case Phrase:
+      found = nextPhrase();
+      break;
+
+    // Operators in Search Expressions
+    case OrOperatorSearch:
+      found = nextBinaryOperator("OR");
+      break;
+    case AndOperatorSearch:
+      found = nextAndOperatorSearch();
+      break;
+    case NotOperatorSearch:
+      found = nextUnaryOperator("NOT");
+      break;
+
     // Operators
     case OrOperator:
       found = nextBinaryOperator("or");
@@ -325,8 +389,12 @@ public class UriTokenizer {
     case ModOperator:
       found = nextBinaryOperator("mod");
       break;
+    case MinusOperator:
+      // To avoid unnecessary minus operators for negative numbers, we have to check what follows the minus sign.
+      found = nextCharacter('-') && !nextDigit() && !nextConstant("INF");
+      break;
     case NotOperator:
-      found = nextConstant("not") && nextWhitespace();
+      found = nextUnaryOperator("not");
       break;
 
     // Methods
@@ -444,27 +512,6 @@ public class UriTokenizer {
     return found;
   }
 
-  private boolean nextMinus() {
-    if(parseString.startsWith("-", index)) {
-      final int lastGoodIndex = index;
-      
-      if(nextDoubleValue()) {
-        index = lastGoodIndex;
-        return false;
-      } else if(nextDecimalValue()) {
-        index = lastGoodIndex;
-        return false;
-      } else if(nextIntegerValue(true)) {
-        index = lastGoodIndex;
-        return false;
-      } else {
-        index++;
-        return true;
-      }
-    }
-    return false;
-  }
-
   /**
    * Moves past the given string constant if found; otherwise leaves the index unchanged.
    * @return whether the constant has been found at the current index
@@ -569,34 +616,6 @@ public class UriTokenizer {
     }
     return count > 0;
   }
-
-  /**
-   * Moves past the given whitespace-surrounded operator constant if found;
-   * otherwise leaves the index unchanged.
-   * @return whether the operator has been found at the current index
-   */
-  private boolean nextBinaryOperator(final String operator) {
-    return nextWhitespace() && nextConstant(operator) && nextWhitespace();
-  }
-
-  /**
-   * Moves past the given method name and its immediately following opening parenthesis if found;
-   * otherwise leaves the index unchanged.
-   * @return whether the method has been found at the current index
-   */
-  private boolean nextMethod(final String methodName) {
-    return nextConstant(methodName) && nextCharacter('(');
-  }
-
-  /**
-   * Moves past (required) whitespace and the given suffix name if found;
-   * otherwise leaves the index unchanged.
-   * @return whether the suffix has been found at the current index
-   */
-  private boolean nextSuffix(final String suffixName) {
-    return nextWhitespace() && nextConstant(suffixName);
-  }
-
   /**
    * Moves past an OData identifier if found; otherwise leaves the index unchanged.
    * @return whether an OData identifier has been found at the current index
@@ -650,6 +669,38 @@ public class UriTokenizer {
     }
   }
 
+  /**
+   * Moves past the given whitespace-surrounded operator constant if found.
+   * @return whether the operator has been found at the current index
+   */
+  private boolean nextBinaryOperator(final String operator) {
+    return nextWhitespace() && nextConstant(operator) && nextWhitespace();
+  }
+
+  /**
+   * Moves past the given whitespace-suffixed operator constant if found.
+   * @return whether the operator has been found at the current index
+   */
+  private boolean nextUnaryOperator(final String operator) {
+    return nextConstant(operator) && nextWhitespace();
+  }
+
+  /**
+   * Moves past the given method name and its immediately following opening parenthesis if found.
+   * @return whether the method has been found at the current index
+   */
+  private boolean nextMethod(final String methodName) {
+    return nextConstant(methodName) && nextCharacter('(');
+  }
+
+  /**
+   * Moves past (required) whitespace and the given suffix name if found.
+   * @return whether the suffix has been found at the current index
+   */
+  private boolean nextSuffix(final String suffixName) {
+    return nextWhitespace() && nextConstant(suffixName);
+  }
+
   private boolean nextParameterAliasName() {
     return nextCharacter('@') && nextODataIdentifier();
   }
@@ -978,4 +1029,52 @@ public class UriTokenizer {
       return false;
     }
   }
+
+  private boolean nextAndOperatorSearch() {
+    if (nextWhitespace()) {
+      final int lastGoodIndex = index;
+      if (nextUnaryOperator("OR")) {
+        return false;
+      } else if (!(nextUnaryOperator("AND"))) {
+        index = lastGoodIndex;
+      }
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  private boolean nextWord() {
+    int count = 0;
+    while (index < parseString.length()) {
+      final int code = parseString.codePointAt(index);
+      if (Character.isUnicodeIdentifierStart(code)) {
+        count++;
+        // Unicode characters outside of the Basic Multilingual Plane are represented as two Java characters.
+        index += Character.isSupplementaryCodePoint(code) ? 2 : 1;
+      } else {
+        break;
+      }
+    }
+    final String word = parseString.substring(index - count, index);
+    return count > 0 && !("OR".equals(word) || "AND".equals(word) || "NOT".equals(word));
+  }
+
+  private boolean nextPhrase() {
+    if (nextCharacter('"')) {
+      do {
+        if (nextCharacter('\\')) {
+          if (!(nextCharacter('\\') || nextCharacter('"'))) {
+            return false;
+          }
+        } else if (nextCharacter('"')) {
+          return true;
+        } else {
+          index++;
+        }
+      } while (index < parseString.length());
+      return false;
+    }
+    return false;
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8925274c/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/AliasImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/AliasImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/AliasImpl.java
index c7d7c20..8c8dab9 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/AliasImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/AliasImpl.java
@@ -41,4 +41,8 @@ public class AliasImpl implements Alias {
     return visitor.visitAlias(parameterName);
   }
 
+  @Override
+  public String toString() {
+    return parameterName;
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8925274c/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/EnumerationImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/EnumerationImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/EnumerationImpl.java
index 256b8d1..a238104 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/EnumerationImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/EnumerationImpl.java
@@ -53,4 +53,10 @@ public class EnumerationImpl implements Enumeration {
   public <T> T accept(final ExpressionVisitor<T> visitor) throws ExpressionVisitException, ODataApplicationException {
     return visitor.visitEnum(type, values);
   }
+
+  @Override
+  public String toString() {
+    return type == null ? null :
+      type.getFullQualifiedName().getFullQualifiedNameAsString() + getValues();
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8925274c/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/LambdaRefImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/LambdaRefImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/LambdaRefImpl.java
index 824943a..16232b8 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/LambdaRefImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/LambdaRefImpl.java
@@ -40,4 +40,9 @@ public class LambdaRefImpl implements LambdaRef {
   public <T> T accept(final ExpressionVisitor<T> visitor) throws ExpressionVisitException, ODataApplicationException {
     return visitor.visitLambdaReference(variableText);
   }
+
+  @Override
+  public String toString() {
+    return variableText;
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8925274c/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/TypeLiteralImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/TypeLiteralImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/TypeLiteralImpl.java
index 336c203..6a2a1c6 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/TypeLiteralImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/TypeLiteralImpl.java
@@ -41,4 +41,9 @@ public class TypeLiteralImpl implements TypeLiteral {
   public <T> T accept(final ExpressionVisitor<T> visitor) throws ExpressionVisitException, ODataApplicationException {
     return visitor.visitTypeLiteral(type);
   }
+
+  @Override
+  public String toString() {
+    return type == null ? null : type.getFullQualifiedName().getFullQualifiedNameAsString();
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8925274c/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 0b43f70..e178fed 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
@@ -81,11 +81,11 @@ UriParserSemanticException.COMPLEX_PROPERTY_OF_ENTITY_TYPE_EXPECTED=A complex pr
 UriParserSemanticException.NOT_FOR_ENTITY_TYPE=Not allowed for entity type.
 UriParserSemanticException.PREVIOUS_PART_TYPED=The previous part is typed.
 UriParserSemanticException.RESOURCE_NOT_FOUND=Cannot find EntitySet, Singleton, ActionImport or FunctionImport with name '%1$s'.
-UriParserSemanticException.NOT_IMPLEMENTED=%1$s is not implemented!
-UriParserSemanticException.NAMESPACE_NOT_ALLOWED_AT_FIRST_ELEMENT=Namespace is not allowed for Entity Sets, Singeltons, Action Imports and Function Imports. Found '%1$s'.
-UriParserSemanticException.COMPLEX_PARAMETER_IN_RESOURCE_PATH=Complex parameters must not appear in resource path segments. Found: '%1$s'.
+UriParserSemanticException.NOT_IMPLEMENTED='%1$s' is not implemented!
+UriParserSemanticException.NAMESPACE_NOT_ALLOWED_AT_FIRST_ELEMENT=Namespace is not allowed for Entity Sets, Singletons, Action Imports and Function Imports; found '%1$s'.
+UriParserSemanticException.COMPLEX_PARAMETER_IN_RESOURCE_PATH=Complex parameters must not appear in resource path segments; found: '%1$s'.
 UriParserSemanticException.FUNCTION_IMPORT_NOT_ALLOWED=Function Imports are not allowed in $filter or $orderby. Found: '%1$s'.
-UriParserSemanticException.TYPES_NOT_COMPATIBLE=Types are not compatible. Left type: '%1$s', right type: '%1$s'.
+UriParserSemanticException.TYPES_NOT_COMPATIBLE=The types '%1$s' and '%2$s' are not compatible.
 
 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/8925274c/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java
index 4ab7fce..94d5373 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java
@@ -22,9 +22,11 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
 
 import java.util.Locale;
 
+import org.apache.olingo.commons.api.edm.Edm;
 import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
 import org.apache.olingo.server.core.uri.parser.UriTokenizer.TokenKind;
@@ -260,9 +262,17 @@ public class ExpressionParserTest {
     expression = parseMethod(TokenKind.SubstringMethod, "'abc'", "1");
     assertEquals("{substring ['abc', 1]}", expression.toString());
 
+    assertEquals("{cast [Edm.SByte]}", parseMethod(TokenKind.CastMethod, "Edm.SByte").toString());
+    assertEquals("{cast [42, Edm.SByte]}", parseMethod(TokenKind.CastMethod, "42", "Edm.SByte").toString());
+
+    assertEquals("{isof [Edm.SByte]}", parseMethod(TokenKind.IsofMethod, "Edm.SByte").toString());
+    assertEquals("{isof [42, Edm.SByte]}", parseMethod(TokenKind.IsofMethod, "42", "Edm.SByte").toString());
+
     wrongExpression("substring('abc')");
     wrongExpression("substring('abc',1,2,3)");
     wrongExpression("substring(1,2)");
+    wrongExpression("cast(1,2)");
+    wrongExpression("isof(Edm.Int16,2)");
   }
 
   private Expression parseMethod(TokenKind kind, String... parameters)
@@ -288,7 +298,7 @@ public class ExpressionParserTest {
   private Expression parseExpression(final String expressionString)
       throws UriParserException, UriValidationException {
     UriTokenizer tokenizer = new UriTokenizer(expressionString);
-    Expression expression = new ExpressionParser(null, odata).parse(tokenizer, null, null);
+    Expression expression = new ExpressionParser(mock(Edm.class), odata).parse(tokenizer, null, null);
     assertNotNull(expression);
     assertTrue(tokenizer.next(TokenKind.EOF));
     return expression;
@@ -296,7 +306,7 @@ public class ExpressionParserTest {
 
   private void wrongExpression(final String expressionString) {
     try {
-      new ExpressionParser(null, odata).parse(new UriTokenizer(expressionString), null, null);
+      new ExpressionParser(mock(Edm.class), odata).parse(new UriTokenizer(expressionString), null, null);
       fail("Expected exception not thrown.");
     } catch (final UriParserException e) {
       assertNotNull(e);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8925274c/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java
index af45e80..e130457 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java
@@ -76,7 +76,7 @@ public class UriTokenizerTest {
     assertTrue(tokenizer.next(TokenKind.STAR));
     assertTrue(tokenizer.next(TokenKind.SLASH));
     assertTrue(tokenizer.next(TokenKind.PLUS));
-    assertTrue(tokenizer.next(TokenKind.MINUS));
+    assertTrue(tokenizer.next(TokenKind.MinusOperator));
     assertTrue(tokenizer.next(TokenKind.EOF));
 
     tokenizer = new UriTokenizer("any(a:true) or all(b:false)");
@@ -97,6 +97,45 @@ public class UriTokenizerTest {
   }
 
   @Test
+  public void systemQueryOptions() {
+    UriTokenizer tokenizer = new UriTokenizer("$expand=*;$filter=true;$levels=max;$orderby=false");
+    assertTrue(tokenizer.next(TokenKind.EXPAND));
+    assertTrue(tokenizer.next(TokenKind.EQ));
+    assertTrue(tokenizer.next(TokenKind.STAR));
+    assertTrue(tokenizer.next(TokenKind.SEMI));
+    assertTrue(tokenizer.next(TokenKind.FILTER));
+    assertTrue(tokenizer.next(TokenKind.EQ));
+    assertTrue(tokenizer.next(TokenKind.BooleanValue));
+    assertTrue(tokenizer.next(TokenKind.SEMI));
+    assertTrue(tokenizer.next(TokenKind.LEVELS));
+    assertTrue(tokenizer.next(TokenKind.EQ));
+    assertTrue(tokenizer.next(TokenKind.MAX));
+    assertTrue(tokenizer.next(TokenKind.SEMI));
+    assertTrue(tokenizer.next(TokenKind.ORDERBY));
+    assertTrue(tokenizer.next(TokenKind.EQ));
+    assertTrue(tokenizer.next(TokenKind.BooleanValue));
+    assertTrue(tokenizer.next(TokenKind.EOF));
+
+    tokenizer = new UriTokenizer("$search=A;$select=*;$skip=1;$top=2");
+    assertTrue(tokenizer.next(TokenKind.SEARCH));
+    assertTrue(tokenizer.next(TokenKind.EQ));
+    assertTrue(tokenizer.next(TokenKind.ODataIdentifier));
+    assertTrue(tokenizer.next(TokenKind.SEMI));
+    assertTrue(tokenizer.next(TokenKind.SELECT));
+    assertTrue(tokenizer.next(TokenKind.EQ));
+    assertTrue(tokenizer.next(TokenKind.STAR));
+    assertTrue(tokenizer.next(TokenKind.SEMI));
+    assertTrue(tokenizer.next(TokenKind.SKIP));
+    assertTrue(tokenizer.next(TokenKind.EQ));
+    assertTrue(tokenizer.next(TokenKind.IntegerValue));
+    assertTrue(tokenizer.next(TokenKind.SEMI));
+    assertTrue(tokenizer.next(TokenKind.TOP));
+    assertTrue(tokenizer.next(TokenKind.EQ));
+    assertTrue(tokenizer.next(TokenKind.IntegerValue));
+    assertTrue(tokenizer.next(TokenKind.EOF));
+  }
+
+  @Test
   public void identifier() {
     assertTrue(new UriTokenizer("name").next(TokenKind.ODataIdentifier));
     assertTrue(new UriTokenizer("_name").next(TokenKind.ODataIdentifier));
@@ -390,11 +429,11 @@ public class UriTokenizerTest {
     assertTrue(tokenizer.next(TokenKind.IntegerValue));
     assertTrue(tokenizer.next(TokenKind.EOF));
 
-    tokenizer = new UriTokenizer("1ne 2");
+    tokenizer = new UriTokenizer("-1ne 2");
     assertTrue(tokenizer.next(TokenKind.IntegerValue));
     assertFalse(tokenizer.next(TokenKind.NotEqualsOperator));
 
-    tokenizer = new UriTokenizer("1 ne2");
+    tokenizer = new UriTokenizer("1 ne-2");
     assertTrue(tokenizer.next(TokenKind.IntegerValue));
     assertFalse(tokenizer.next(TokenKind.NotEqualsOperator));
 
@@ -404,6 +443,11 @@ public class UriTokenizerTest {
     assertTrue(tokenizer.next(TokenKind.IntegerValue));
     assertTrue(tokenizer.next(TokenKind.EOF));
 
+    assertTrue(new UriTokenizer("-x").next(TokenKind.MinusOperator));
+    assertFalse(new UriTokenizer("-1").next(TokenKind.MinusOperator));
+    assertFalse(new UriTokenizer("-INF").next(TokenKind.MinusOperator));
+    assertFalse(new UriTokenizer("+").next(TokenKind.MinusOperator));
+
     assertFalse(new UriTokenizer("nottrue").next(TokenKind.NotOperator));
     assertFalse(new UriTokenizer("no true").next(TokenKind.NotOperator));
 
@@ -484,6 +528,38 @@ public class UriTokenizerTest {
     wrongToken(TokenKind.DescSuffix, " desc", 'D');
   }
 
+  @Test
+  public void search() {
+    UriTokenizer tokenizer = new UriTokenizer("a AND b OR NOT \"c\" d");
+    assertTrue(tokenizer.next(TokenKind.Word));
+    assertTrue(tokenizer.next(TokenKind.AndOperatorSearch));
+    assertTrue(tokenizer.next(TokenKind.Word));
+    assertFalse(tokenizer.next(TokenKind.AndOperatorSearch));
+    assertTrue(tokenizer.next(TokenKind.OrOperatorSearch));
+    assertTrue(tokenizer.next(TokenKind.NotOperatorSearch));
+    assertTrue(tokenizer.next(TokenKind.Phrase));
+    assertTrue(tokenizer.next(TokenKind.AndOperatorSearch));
+    assertTrue(tokenizer.next(TokenKind.Word));
+    assertFalse(tokenizer.next(TokenKind.AndOperatorSearch));
+    assertFalse(tokenizer.next(TokenKind.Word));
+    assertFalse(tokenizer.next(TokenKind.Phrase));
+    assertTrue(tokenizer.next(TokenKind.EOF));
+
+    assertTrue(new UriTokenizer("\"a\\\\x\\\"\"").next(TokenKind.Phrase));
+    assertFalse(new UriTokenizer("\"a\\\"").next(TokenKind.Phrase));
+    assertFalse(new UriTokenizer("\"a\\x\"").next(TokenKind.Phrase));
+    wrongToken(TokenKind.Phrase, "\"a\"", '\\');
+
+    final String outsideBmpLetter = String.valueOf(Character.toChars(0x10330));
+    assertTrue(new UriTokenizer("\"" + outsideBmpLetter + "\"").next(TokenKind.Phrase));
+
+    assertTrue(new UriTokenizer(outsideBmpLetter).next(TokenKind.Word));
+    assertFalse(new UriTokenizer("1").next(TokenKind.Word));
+    assertFalse(new UriTokenizer("AND").next(TokenKind.Word));
+    assertFalse(new UriTokenizer("OR").next(TokenKind.Word));
+    assertFalse(new UriTokenizer("NOT").next(TokenKind.Word));
+  }
+
   private void wrongToken(final TokenKind kind, final String value, final char disturbCharacter) {
     assertFalse(new UriTokenizer(disturbCharacter + value).next(kind));
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8925274c/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
index e028cfe..f3e50a2 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
@@ -35,7 +35,7 @@ public class SearchParserAndTokenizerTest {
     assertQuery("a AND b AND c").resultsIn("{{'a' AND 'b'} AND 'c'}");
     assertQuery("a OR b").resultsIn("{'a' OR 'b'}");
     assertQuery("a OR b OR c").resultsIn("{{'a' OR 'b'} OR 'c'}");
-    
+
     assertQuery("NOT a NOT b").resultsIn("{{NOT 'a'} AND {NOT 'b'}}");
     assertQuery("NOT a AND NOT b").resultsIn("{{NOT 'a'} AND {NOT 'b'}}");
     assertQuery("NOT a OR NOT b").resultsIn("{{NOT 'a'} OR {NOT 'b'}}");
@@ -59,16 +59,16 @@ public class SearchParserAndTokenizerTest {
     assertQuery("a AND (b OR c)").resultsIn("{'a' AND {'b' OR 'c'}}");
     assertQuery("(a OR b) AND NOT c").resultsIn("{{'a' OR 'b'} AND {NOT 'c'}}");
     assertQuery("(a OR B) AND (c OR d AND NOT e OR (f))")
-            .resultsIn("{{'a' OR 'B'} AND {{'c' OR {'d' AND {NOT 'e'}}} OR 'f'}}");
+        .resultsIn("{{'a' OR 'B'} AND {{'c' OR {'d' AND {NOT 'e'}}} OR 'f'}}");
     assertQuery("(a OR B) (c OR d NOT e OR (f))")
-      .resultsIn("{{'a' OR 'B'} AND {{'c' OR {'d' AND {NOT 'e'}}} OR 'f'}}");
+        .resultsIn("{{'a' OR 'B'} AND {{'c' OR {'d' AND {NOT 'e'}}} OR 'f'}}");
     assertQuery("((((a))))").resultsIn("'a'");
     assertQuery("((((a)))) ((((a))))").resultsIn("{'a' AND 'a'}");
     assertQuery("((((a)))) OR ((((a))))").resultsIn("{'a' OR 'a'}");
     assertQuery("((((((a)))) ((((c))) OR (((C)))) ((((a))))))").resultsIn("{{'a' AND {'c' OR 'C'}} AND 'a'}");
     assertQuery("((((\"a\")))) OR ((((\"a\"))))").resultsIn("{'a' OR 'a'}");
   }
-  
+
   @Test
   public void parseImplicitAnd() throws Exception {
     assertQuery("a b").resultsIn("{'a' AND 'b'}");
@@ -103,7 +103,7 @@ public class SearchParserAndTokenizerTest {
     assertQuery("((a AND b OR c)").resultsIn(SearchParserException.MessageKeys.MISSING_CLOSE);
     assertQuery("a AND (b OR c").resultsIn(SearchParserException.MessageKeys.MISSING_CLOSE);
     assertQuery("(a AND ((b OR c)").resultsIn(SearchParserException.MessageKeys.MISSING_CLOSE);
-    
+
     assertQuery("NOT NOT a").resultsIn(SearchParserException.MessageKeys.INVALID_NOT_OPERAND);
     assertQuery("NOT (a)").resultsIn(SearchParserException.MessageKeys.TOKENIZER_EXCEPTION);
   }
@@ -186,7 +186,6 @@ public class SearchParserAndTokenizerTest {
     //    <Input>http://serviceRoot/Products?$search=blue</Input>
     assertQuery("blue").resultsIn("'blue'");
 
-
     // below cases can not be tested here
     //    <TestCase Name="5.1.7 Search - on entity container" Rule="odataUri">
     //    <Input>http://serviceRoot/Model.Container/$all?$search=blue</Input>
@@ -194,68 +193,47 @@ public class SearchParserAndTokenizerTest {
     //    <Input>http://serviceRoot/$all?$search=blue</Input>
   }
 
-
   private static Validator assertQuery(String searchQuery) {
-    return Validator.init(searchQuery);
+    return new Validator(searchQuery);
   }
 
   private static class Validator {
-    private boolean log;
     private final String searchQuery;
 
     private Validator(String searchQuery) {
       this.searchQuery = searchQuery;
     }
 
-    private static Validator init(String searchQuery) {
-      return new Validator(searchQuery);
-    }
-
-    @SuppressWarnings("unused")
-    private Validator withLogging() {
-      log = true;
-      return this;
-    }
-
-    private void resultsIn(SearchParserException.MessageKey key)
-            throws SearchTokenizerException {
+    private void resultsIn(SearchParserException.MessageKey key) throws SearchTokenizerException {
       try {
         resultsIn(searchQuery);
       } catch (SearchParserException e) {
         Assert.assertEquals("SearchParserException with unexpected message '" + e.getMessage() +
             "' was thrown.", key, e.getMessageKey());
-        if(log) {
-          System.out.println("Caught SearchParserException with message key " +
-              e.getMessageKey() + " and message " + e.getMessage());
-        }
         return;
       }
       Assert.fail("SearchParserException with message key " + key.getKey() + " was not thrown.");
     }
-    
+
     public void resultsInExpectedTerm(final String actualToken) throws SearchTokenizerException {
       try {
         resultsIn(searchQuery);
-      } catch(SearchParserException e) {
+      } catch (SearchParserException e) {
         Assert.assertEquals(SearchParserException.MessageKeys.EXPECTED_DIFFERENT_TOKEN, e.getMessageKey());
         Assert.assertEquals("Expected PHRASE||WORD found: " + actualToken, e.getMessage());
       }
     }
-    
+
     private void resultsIn(String expectedSearchExpression) throws SearchTokenizerException, SearchParserException {
       final SearchExpression searchExpression = getSearchExpression();
       Assert.assertEquals(expectedSearchExpression, searchExpression.toString());
     }
 
     private SearchExpression getSearchExpression() throws SearchParserException, SearchTokenizerException {
-      SearchParser tokenizer = new SearchParser();
-      SearchOption result = tokenizer.parse(searchQuery);
+      SearchOption result = new SearchParser().parse(searchQuery);
       Assert.assertNotNull(result);
       final SearchExpression searchExpression = result.getSearchExpression();
       Assert.assertNotNull(searchExpression);
-      if (log) {
-        System.out.println(searchExpression);
-      }
       return searchExpression;
     }
   }


[24/30] olingo-odata4 git commit: [OLINGO-834] $expand parser in Java + clean-up

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8925274c/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriContext.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriContext.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriContext.java
deleted file mode 100644
index 36a0887..0000000
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriContext.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * 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.ArrayDeque;
-import java.util.Deque;
-
-import org.apache.olingo.commons.api.edm.EdmType;
-import org.apache.olingo.server.core.uri.UriInfoImpl;
-import org.apache.olingo.server.core.uri.queryoption.ExpandItemImpl;
-import org.apache.olingo.server.core.uri.queryoption.SelectItemImpl;
-
-/**
- * UriContext object used for holding information for URI parsing.
- *
- */
-public class UriContext {
-
-  public static class LambdaVariable {
-    public String name;
-    public EdmType type;
-  }
-
-  /**
-   * Hold all currently allowed lambda variables
-   * As lambda functions can be nested there may be more than one allowed lambda variables at a time while parsing a
-   * $filter or $orderby expressions.
-   */
-  public Deque<LambdaVariable> allowedLambdaVariables;
-  /**
-   * Used to stack type information for nested $expand, $filter query options and other cases.
-   */
-  public Deque<EdmType> contextTypes;
-
-  /** Whether the context types are collections. */
-  public boolean isCollection;
-
-  // CHECKSTYLE:OFF (Maven checkstyle)
-  /**
-   * Set within method
-   * {@link org.apache.olingo.server.core.uri.antlr.UriParserBaseVisitor#visitExpandItem(org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandItemContext ctx)}
-   * and
-   * {@link org.apache.olingo.server.core.uri.antlr.UriParserBaseVisitor#visitExpandPathExtension(org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandPathExtensionContext ctx)}
-   * to allow nodes
-   * deeper in the expand tree at
-   * {@link org.apache.olingo.server.core.uri.antlr.UriParserBaseVisitor#visitExpandPathExtension(org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandPathExtensionContext ctx)}
-   * appending path
-   * segments to the currently processed {@link ExpandItemImpl}.
-   */
-  public ExpandItemImpl contextExpandItemPath;
-  // CHECKSTYLE:ON (Maven checkstyle)
-  
-  //CHECKSTYLE:OFF (Maven checkstyle)
-  /**
-   * Set to true in method {@link UriParseTreeVisitor#visitExpandPath} right before 
-   * calling {@link  org.apache.olingo.server.core.uri.parser.UriParseTreeVisitor#readResourcePathSegment}
-   * After reading the path the variable is set back to false
-   * 
-   * readResourcePathSegment handles all navigation properties, it depends on the context if key predicates are allowed or not.
-   * In case of expand 
-   */
-  public boolean contextVisitExpandResourcePath;
-  //CHECKSTYLE:ON (Maven checkstyle)
-  
-  // CHECKSTYLE:OFF (Maven checkstyle)
-  /**
-   * Set within method
-   * {@link org.apache.olingo.server.core.uri.antlr.UriParserBaseVisitor#visitSelectItem(org.apache.olingo.server.core.uri.antlr.UriParserParser.SelectItemContext ctx)}
-   * to allow
-   * nodes
-   * deeper in the expand tree at
-   * {@link org.apache.olingo.server.core.uri.antlr.UriParserBaseVisitor#visitSelectSegment(org.apache.olingo.server.core.uri.antlr.UriParserParser.SelectSegmentContext ctx)}
-   * appending path segments to the
-   * currently processed {@link SelectItemImpl}.
-   */
-  public SelectItemImpl contextSelectItem;
-  // CHECKSTYLE:ON (Maven checkstyle)
-  /**
-   * Stores the currently processed UriInfo objects. There is one URI Info object for the resource path
-   * and one for each new first member access within $filter and $orderBy options.
-   */
-  public UriInfoImpl contextUriInfo;
-  public boolean contextReadingFunctionParameters;
-  
-  /**
-   * Set to true if the parser operates on query part.
-   */
-  public boolean contextReadingQueryPart;
-  
-  public UriContext() {
-
-    contextExpandItemPath = null;
-    contextReadingFunctionParameters = false;
-    contextSelectItem = null;
-    contextTypes = new ArrayDeque<EdmType>();
-    allowedLambdaVariables = new ArrayDeque<UriContext.LambdaVariable>();
-
-  }
-}
\ No newline at end of file


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

Posted by ch...@apache.org.
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/UriTokenizer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java
new file mode 100644
index 0000000..87e09ad
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java
@@ -0,0 +1,592 @@
+/*
+ * 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;
+
+/**
+ * <p>Simple OData URI tokenizer that works on a given string by keeping an index.</p>
+ * <p>As far as feasible, it tries to work on character basis, assuming this to be faster than string operations.
+ * Since only the index is "moved", backing out while parsing a token is easy and used throughout.
+ * There is intentionally no method to push back tokens (although it would be easy to add such a method)
+ * because this tokenizer should behave like a classical token-consuming tokenizer.</p>
+ */
+public class UriTokenizer {
+
+  public enum TokenKind {
+    EOF, // signals the end of the string to be parsed
+
+    // constant-value tokens (convention: uppercase)
+    REF,
+    VALUE,
+    COUNT,
+    CROSSJOIN,
+    OPEN,
+    CLOSE,
+    COMMA,
+    SEMI,
+    EQ,
+    NULL,
+
+    // variable-value tokens (convention: mixed case)
+    ODataIdentifier,
+    QualifiedName,
+    ParameterAliasName,
+
+    PrimitiveBooleanValue,
+    PrimitiveStringValue,
+    PrimitiveIntegerValue,
+    PrimitiveGuidValue,
+    PrimitiveDateValue,
+    PrimitiveDateTimeOffsetValue,
+    PrimitiveTimeOfDayValue,
+    PrimitiveDecimalValue,
+    PrimitiveDoubleValue,
+    PrimitiveDurationValue,
+    PrimitiveBinaryValue,
+    PrimitiveEnumValue,
+
+    jsonArrayOrObject
+  }
+
+  private final String pathSegment;
+
+  private int startIndex = 0;
+  private int index = 0;
+
+  public UriTokenizer(final String pathSegment) {
+    this.pathSegment = pathSegment == null ? "" : pathSegment;
+  }
+
+  /** Returns the string value corresponding to the last successful {@link #next(TokenKind)} call. */
+  public String getText() {
+    return pathSegment.substring(startIndex, index);
+  }
+
+  /**
+   * Tries to find a token of the given token kind at the current index.
+   * The order in which this method is called with different token kinds is important,
+   * not only for performance reasons but also if tokens can start with the same characters
+   * (e.g., a qualified name starts with an OData identifier).
+   * @param allowedTokenKind the kind of token to expect
+   * @return <code>true</code> if the token is found; <code>false</code> otherwise
+   * @see #getText()
+   */
+  public boolean next(final TokenKind allowedTokenKind) {
+    if (allowedTokenKind == null) {
+      return false;
+    }
+
+    boolean found = false;
+    final int previousIndex = index;
+    switch (allowedTokenKind) {
+    // Constants
+    case REF:
+      found = nextConstant("$ref");
+      break;
+    case VALUE:
+      found = nextConstant("$value");
+      break;
+    case COUNT:
+      found = nextConstant("$count");
+      break;
+    case CROSSJOIN:
+      found = nextConstant("$crossjoin");
+      break;
+    case OPEN:
+      found = nextCharacter('(');
+      break;
+    case CLOSE:
+      found = nextCharacter(')');
+      break;
+    case COMMA:
+      found = nextCharacter(',');
+      break;
+    case SEMI:
+      found = nextCharacter(';');
+      break;
+    case EQ:
+      found = nextCharacter('=');
+      break;
+    case NULL:
+      found = nextConstant("null");
+      break;
+    case EOF:
+      found = index >= pathSegment.length();
+      break;
+
+    // Identifiers
+    case ODataIdentifier:
+      found = nextODataIdentifier();
+      break;
+    case QualifiedName:
+      found = nextQualifiedName();
+      break;
+    case ParameterAliasName:
+      found = nextParameterAliasName();
+      break;
+
+    // Primitive Values
+    case PrimitiveBooleanValue:
+      found = nextBooleanValue();
+      break;
+    case PrimitiveStringValue:
+      found = nextStringValue();
+      break;
+    case PrimitiveIntegerValue:
+      found = nextIntegerValue(true);
+      break;
+    case PrimitiveGuidValue:
+      found = nextGuidValue();
+      break;
+    case PrimitiveDateValue:
+      found = nextDateValue();
+      break;
+    case PrimitiveDateTimeOffsetValue:
+      found = nextDateTimeOffsetValue();
+      break;
+    case PrimitiveTimeOfDayValue:
+      found = nextTimeOfDayValue();
+      break;
+    case PrimitiveDecimalValue:
+      found = nextDecimalValue();
+      break;
+    case PrimitiveDoubleValue:
+      found = nextDoubleValue();
+      break;
+    case PrimitiveDurationValue:
+      found = nextDurationValue();
+      break;
+    case PrimitiveBinaryValue:
+      found = nextBinaryValue();
+      break;
+    case PrimitiveEnumValue:
+      found = nextEnumValue();
+      break;
+
+    // Primitive Values
+    case jsonArrayOrObject:
+      found = nextJsonArrayOrObject();
+      break;
+    }
+
+    if (found) {
+      startIndex = previousIndex;
+    } else {
+      index = previousIndex;
+    }
+    return found;
+  }
+
+  private boolean nextConstant(final String constant) {
+    if (pathSegment.startsWith(constant, index)) {
+      index += constant.length();
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  private boolean nextConstantIgnoreCase(final String constant) {
+    final int length = constant.length();
+    if (index + length <= pathSegment.length()
+        && constant.equalsIgnoreCase(pathSegment.substring(index, index + length))) {
+      index += length;
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  /**
+   * Moves past the given character if found; otherwise leaves the index unchanged.
+   * @return whether the given character has been found at the current index
+   */
+  private boolean nextCharacter(final char character) {
+    if (index < pathSegment.length() && pathSegment.charAt(index) == character) {
+      index++;
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  /**
+   * Moves past the next character if it is in the given character range;
+   * otherwise leaves the index unchanged.
+   * @return whether the given character has been found at the current index
+   */
+  private boolean nextCharacterRange(final char from, final char to) {
+    if (index < pathSegment.length()) {
+      final char code = pathSegment.charAt(index);
+      if (code >= from && code <= to) {
+        index++;
+        return true;
+      }
+    }
+    return false;
+  }
+
+  /**
+   * Moves past a digit character ('0' to '9') if found; otherwise leaves the index unchanged.
+   * @return whether a digit character has been found at the current index
+   */
+  private boolean nextDigit() {
+    return nextCharacterRange('0', '9');
+  }
+
+  /**
+   * Moves past a hexadecimal digit character ('0' to '9', 'A' to 'F', or 'a' to 'f') if found;
+   * otherwise leaves the index unchanged.
+   * @return whether a hexadecimal digit character has been found at the current index
+   */
+  private boolean nextHexDigit() {
+    return nextCharacterRange('0', '9') || nextCharacterRange('A', 'F') || nextCharacterRange('a', 'f');
+  }
+
+  /**
+   * Moves past a base64 character ('0' to '9', 'A' to 'Z', 'a' to 'z', '-', or '_') if found;
+   * otherwise leaves the index unchanged.
+   * @return whether a base64 character has been found at the current index
+   */
+  private boolean nextBase64() {
+    return nextCharacterRange('0', '9') || nextCharacterRange('A', 'Z') || nextCharacterRange('a', 'z')
+        || nextCharacter('-') || nextCharacter('_');
+  }
+
+  /**
+   * Moves past a sign character ('+' or '-') if found; otherwise leaves the index unchanged.
+   * @return whether a sign character has been found at the current index
+   */
+  private boolean nextSign() {
+    return nextCharacter('+') || nextCharacter('-');
+  }
+
+  private boolean nextODataIdentifier() {
+    int count = 0;
+    if (index < pathSegment.length()) {
+      int code = pathSegment.codePointAt(index);
+      if (Character.isUnicodeIdentifierStart(code) || code == '_') {
+        count++;
+        // Unicode characters outside of the Basic Multilingual Plane are represented as two Java characters.
+        index += Character.isSupplementaryCodePoint(code) ? 2 : 1;
+        while (index < pathSegment.length() && count < 128) {
+          code = pathSegment.codePointAt(index);
+          if (Character.isUnicodeIdentifierPart(code) && !Character.isISOControl(code)) {
+            count++;
+            // Unicode characters outside of the Basic Multilingual Plane are represented as two Java characters.
+            index += Character.isSupplementaryCodePoint(code) ? 2 : 1;
+          } else {
+            break;
+          }
+        }
+      }
+    }
+    return count > 0;
+  }
+
+  private boolean nextQualifiedName() {
+    int count = 0;
+    do {
+      if (nextODataIdentifier()) {
+        count++;
+      } else {
+        return false;
+      }
+    } while (nextCharacter('.'));
+    return count >= 2;
+  }
+
+  private boolean nextParameterAliasName() {
+    return nextCharacter('@') && nextODataIdentifier();
+  }
+
+  private boolean nextBooleanValue() {
+    return nextConstantIgnoreCase("true") || nextConstantIgnoreCase("false");
+  }
+
+  private boolean nextStringValue() {
+    if (!nextCharacter('\'')) {
+      return false;
+    }
+    while (index < pathSegment.length()) {
+      if (pathSegment.charAt(index) == '\'') {
+        // If a single quote is followed by another single quote,
+        // it represents one single quote within the string literal,
+        // otherwise it marks the end of the string literal.
+        if (index + 1 < pathSegment.length() && pathSegment.charAt(index + 1) == '\'') {
+          index++;
+        } else {
+          break;
+        }
+      }
+      index++;
+    }
+    return nextCharacter('\'');
+  }
+
+  private boolean nextIntegerValue(final boolean signed) {
+    if (signed) {
+      nextSign();
+    }
+    boolean hasDigits = false;
+    while (nextDigit()) {
+      hasDigits = true;
+    }
+    return hasDigits;
+  }
+
+  /** Finds and returns only decimal-number tokens with a fractional part.
+   *  Whole numbers must be found with {@link #nextIntegerValue()}.
+   */
+  private boolean nextDecimalValue() {
+    return nextIntegerValue(true) && nextCharacter('.') && nextIntegerValue(false);
+  }
+
+  /**
+   * Finds and returns only floating-point-number tokens with an exponential part
+   * and the special three constants "NaN", "-INF", and "INF".
+   *  Whole numbers must be found with {@link #nextIntegerValue()}.
+   *  Decimal numbers must be found with {@link #nextDecimalValue()}.
+   */
+  private boolean nextDoubleValue() {
+    if (nextConstant("NaN") || nextConstant("-INF") || nextConstant("INF")) {
+      return true;
+    } else {
+      if (!nextIntegerValue(true)) {
+        return false;
+      }
+      if (nextCharacter('.') && !nextIntegerValue(false)) {
+        return false;
+      }
+      return (nextCharacter('E') || nextCharacter('e')) && nextIntegerValue(true);
+    }
+  }
+
+  private boolean nextGuidValue() {
+    return nextHexDigit() && nextHexDigit() && nextHexDigit() && nextHexDigit()
+        && nextHexDigit() && nextHexDigit() && nextHexDigit() && nextHexDigit()
+        && nextCharacter('-')
+        && nextHexDigit() && nextHexDigit() && nextHexDigit() && nextHexDigit()
+        && nextCharacter('-')
+        && nextHexDigit() && nextHexDigit() && nextHexDigit() && nextHexDigit()
+        && nextCharacter('-')
+        && nextHexDigit() && nextHexDigit() && nextHexDigit() && nextHexDigit()
+        && nextCharacter('-')
+        && nextHexDigit() && nextHexDigit() && nextHexDigit() && nextHexDigit()
+        && nextHexDigit() && nextHexDigit() && nextHexDigit() && nextHexDigit()
+        && nextHexDigit() && nextHexDigit() && nextHexDigit() && nextHexDigit();
+  }
+
+  private boolean nextYear() {
+    nextCharacter('-');
+    if (nextCharacter('0')) {
+      return nextDigit() && nextDigit() && nextDigit();
+    } else if (nextCharacterRange('1', '9')) {
+      int count = 0;
+      while (nextDigit()) {
+        count++;
+      }
+      return count >= 3;
+    } else {
+      return false;
+    }
+  }
+
+  private boolean nextDateValue() {
+    return nextYear()
+        && nextCharacter('-')
+        && (nextCharacter('0') && nextCharacterRange('1', '9')
+        || nextCharacter('1') && nextCharacterRange('0', '2'))
+        && nextCharacter('-')
+        && (nextCharacter('0') && nextCharacterRange('1', '9')
+            || nextCharacterRange('1', '2') && nextDigit()
+            || nextCharacter('3') && nextCharacterRange('0', '1'));
+  }
+
+  private boolean nextHours() {
+    return nextCharacterRange('0', '1') && nextDigit()
+        || nextCharacter('2') && nextCharacterRange('0', '3');
+  }
+
+  private boolean nextMinutesOrSeconds() {
+    return nextCharacterRange('0', '5') && nextDigit();
+  }
+
+  private boolean nextDateTimeOffsetValue() {
+    return nextDateValue()
+        && (nextCharacter('T') || nextCharacter('t'))
+        && nextTimeOfDayValue()
+        && (nextCharacter('Z')
+            || nextCharacter('z')
+            || nextSign() && nextHours() && nextCharacter(':') && nextMinutesOrSeconds());
+  }
+
+  private boolean nextTimeOfDayValue() {
+    if (nextHours() && nextCharacter(':') && nextMinutesOrSeconds()) {
+      if (nextCharacter(':')) {
+        if (nextMinutesOrSeconds()) {
+          if (nextCharacter('.') && !nextIntegerValue(false)) {
+            return false;
+          }
+        } else {
+          return false;
+        }
+      }
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  private boolean nextDurationValue() {
+    if (nextConstantIgnoreCase("duration") && nextCharacter('\'')) {
+      nextSign();
+      if (nextCharacter('P') || nextCharacter('p')) {
+        if (nextIntegerValue(false)) {
+          if (!(nextCharacter('D') || nextCharacter('d'))) {
+            return false;
+          }
+        }
+        if (nextCharacter('T') || nextCharacter('t')) {
+          boolean hasNumber = false;
+          if (nextIntegerValue(false)) {
+            hasNumber = true;
+            if (nextCharacter('H') || nextCharacter('h')) {
+              hasNumber = false;
+            }
+          }
+          if (hasNumber || nextIntegerValue(false)) {
+            hasNumber = true;
+            if (nextCharacter('M') || nextCharacter('m')) {
+              hasNumber = false;
+            }
+          }
+          if (hasNumber || nextIntegerValue(false)) {
+            if (nextCharacter('.')) {
+              if (!nextIntegerValue(false)) {
+                return false;
+              }
+            }
+            if (!(nextCharacter('S') || nextCharacter('s'))) {
+              return false;
+            }
+          }
+        }
+        return nextCharacter('\'');
+      }
+    }
+    return false;
+  }
+
+  private boolean nextBinaryValue() {
+    if (nextConstantIgnoreCase("binary") && nextCharacter('\'')) {
+      int lastGoodIndex = index;
+      while (nextBase64() && nextBase64() && nextBase64() && nextBase64()) {
+        lastGoodIndex += 4;
+      }
+      index = lastGoodIndex;
+      if (nextBase64() && nextBase64()
+          && (nextCharacter('A') || nextCharacter('E') || nextCharacter('I') || nextCharacter('M')
+              || nextCharacter('Q') || nextCharacter('U') || nextCharacter('Y') || nextCharacter('c')
+              || nextCharacter('g') || nextCharacter('k') || nextCharacter('o') || nextCharacter('s')
+              || nextCharacter('w') || nextCharacter('0') || nextCharacter('4') || nextCharacter('8'))) {
+        nextCharacter('=');
+      } else {
+        index = lastGoodIndex;
+        if (nextBase64()) {
+          if (nextCharacter('A') || nextCharacter('Q') || nextCharacter('g') || nextCharacter('w')) {
+            nextConstant("==");
+          } else {
+            return false;
+          }
+        }
+      }
+      return nextCharacter('\'');
+    }
+    return false;
+  }
+
+  private boolean nextEnumValue() {
+    if (nextQualifiedName() && nextCharacter('\'')) {
+      do {
+        if (!(nextODataIdentifier() || nextIntegerValue(true))) {
+          return false;
+        }
+      } while (nextCharacter(','));
+      return nextCharacter('\'');
+    }
+    return false;
+  }
+
+  private boolean nextJsonString() {
+    if (nextCharacter('"')) {
+      do {
+        if (nextCharacter('\\')) {
+          if (!(nextCharacter('b') || nextCharacter('t')
+              || nextCharacter('n') || nextCharacter('f') || nextCharacter('r')
+              || nextCharacter('"') || nextCharacter('/') || nextCharacter('\\')
+              || nextCharacter('u') && nextHexDigit() && nextHexDigit() && nextHexDigit() && nextHexDigit())) {
+            return false;
+          }
+        } else if (nextCharacter('"')) {
+          return true;
+        } else {
+          index++;
+        }
+      } while (index < pathSegment.length());
+      return false;
+    }
+    return false;
+  }
+
+  private boolean nextJsonValue() {
+    return nextConstant("null") || nextConstant("true") || nextConstant("false")
+        // If a double or decimal number is not found, the index must be reset; the internal methods don't do that.
+        || next(TokenKind.PrimitiveDoubleValue) || next(TokenKind.PrimitiveDecimalValue) || nextIntegerValue(true)
+        || nextJsonString()
+        || nextJsonArrayOrObject();
+  }
+
+  private boolean nextJsonMember() {
+    return nextJsonString() && nextCharacter(':') && nextJsonValue();
+  }
+
+  private boolean nextJsonArrayOrObject() {
+    if (nextCharacter('[')) {
+      if (nextJsonValue()) {
+        while (nextCharacter(',')) {
+          if (!nextJsonValue()) {
+            return false;
+          }
+        }
+      }
+      return nextCharacter(']');
+    } else if (nextCharacter('{')) {
+      if (nextJsonMember()) {
+        while (nextCharacter(',')) {
+          if (!nextJsonMember()) {
+            return false;
+          }
+        }
+      }
+      return nextCharacter('}');
+    } else {
+      return false;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/927ecb93/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/validator/UriValidator.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/validator/UriValidator.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/validator/UriValidator.java
index f840e8e..3ccd97a 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/validator/UriValidator.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/validator/UriValidator.java
@@ -24,7 +24,6 @@ import java.util.Map;
 
 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.EdmPrimitiveType;
 import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
@@ -223,14 +222,7 @@ public class UriValidator {
 
   private RowIndexForUriType rowIndexForResourceKind(final UriInfo uriInfo) throws UriValidationException {
     RowIndexForUriType idx;
-    
-    final int nonComposableFunctionIndex = getIndexOfLastNonComposableFunction(uriInfo);
-    if(nonComposableFunctionIndex != -1 && (uriInfo.getUriResourceParts().size() - 1) > nonComposableFunctionIndex) {
-      throw new UriValidationException("Non composable functions followed by further resource parts are not allowed", 
-          UriValidationException.MessageKeys.UNALLOWED_RESOURCE_PATH, 
-          uriInfo.getUriResourceParts().get(nonComposableFunctionIndex + 1).getSegmentValue());
-    }
-    
+
     int lastPathSegmentIndex = uriInfo.getUriResourceParts().size() - 1;
     UriResource lastPathSegment = uriInfo.getUriResourceParts().get(lastPathSegmentIndex);
 
@@ -249,11 +241,7 @@ public class UriValidator {
       idx = rowIndexForEntitySet(lastPathSegment);
       break;
     case function:
-      if(nonComposableFunctionIndex == -1) {
-        idx = rowIndexForFunction(lastPathSegment);
-      } else {
-        idx = RowIndexForUriType.none;
-      }
+      idx = rowIndexForFunction(lastPathSegment);
       break;
     case primitiveProperty:
       idx = rowIndexForPrimitiveProperty(lastPathSegment);
@@ -278,21 +266,6 @@ public class UriValidator {
     return idx;
   }
 
-  private int getIndexOfLastNonComposableFunction(final UriInfo uriInfo) {
-    for(int i = 0; i < uriInfo.getUriResourceParts().size(); i++) {
-      final UriResource resourcePath = uriInfo.getUriResourceParts().get(i);
-      
-      if(resourcePath instanceof UriResourceFunction) {
-        final UriResourceFunction resourceFuntion = (UriResourceFunction) resourcePath;
-        if(!resourceFuntion.getFunction().isComposable()) {
-          return i;
-        }
-      }
-    }
-    
-    return -1;
-  }
-
   private RowIndexForUriType rowIndexForValue(final UriInfo uriInfo) throws UriValidationException {
     RowIndexForUriType idx;
     int secondLastPathSegmentIndex = uriInfo.getUriResourceParts().size() - 2;
@@ -309,9 +282,7 @@ public class UriValidator {
       break;
     case function:
       UriResourceFunction uriFunction = (UriResourceFunction) secondLastPathSegment;
-      final EdmFunctionImport functionImport = uriFunction.getFunctionImport();
-      final EdmFunction function = functionImport == null ?
-          uriFunction.getFunction() : functionImport.getUnboundFunctions().get(0);
+      final EdmFunction function = uriFunction.getFunction();
       idx = function.getReturnType().getType().getKind() == EdmTypeKind.ENTITY ?
           RowIndexForUriType.mediaStream : RowIndexForUriType.propertyPrimitiveValue;
       break;
@@ -351,32 +322,33 @@ public class UriValidator {
   }
 
   private RowIndexForUriType rowIndexForFunction(final UriResource lastPathSegment) throws UriValidationException {
-    RowIndexForUriType idx;
-    UriResourceFunction urf = (UriResourceFunction) lastPathSegment;
-    EdmReturnType rt = urf.getFunction().getReturnType();
+    final UriResourceFunction uriFunction = (UriResourceFunction) lastPathSegment;
+    final EdmReturnType returnType = uriFunction.getFunction().getReturnType();
 
-    if(!urf.getFunction().isComposable()) {
+    if (!uriFunction.getFunction().isComposable()) {
       return RowIndexForUriType.none;
     }
-    
-    
-    switch (rt.getType().getKind()) {
+
+    RowIndexForUriType idx;
+    switch (returnType.getType().getKind()) {
     case ENTITY:
-      idx = rt.isCollection() && urf.getKeyPredicates().isEmpty() ?
+      idx = returnType.isCollection() && uriFunction.getKeyPredicates().isEmpty() ?
           RowIndexForUriType.entitySet : RowIndexForUriType.entity;
       break;
     case PRIMITIVE:
     case ENUM:
     case DEFINITION:
-      idx = rt.isCollection() ? RowIndexForUriType.propertyPrimitiveCollection : RowIndexForUriType.propertyPrimitive;
+      idx = returnType.isCollection() ? RowIndexForUriType.propertyPrimitiveCollection :
+                                        RowIndexForUriType.propertyPrimitive;
       break;
     case COMPLEX:
-      idx = rt.isCollection() ? RowIndexForUriType.propertyComplexCollection : RowIndexForUriType.propertyComplex;
+      idx = returnType.isCollection() ? RowIndexForUriType.propertyComplexCollection :
+                                        RowIndexForUriType.propertyComplex;
       break;
     default:
-      throw new UriValidationException("Unsupported function return type: " + rt.getType().getKind(),
+      throw new UriValidationException("Unsupported function return type: " + returnType.getType().getKind(),
           UriValidationException.MessageKeys.UNSUPPORTED_FUNCTION_RETURN_TYPE,
-          rt.getType().getKind().toString());
+          returnType.getType().getKind().toString());
     }
 
     return idx;
@@ -447,9 +419,7 @@ public class UriValidator {
       break;
     case function:
       final UriResourceFunction uriFunction = (UriResourceFunction) secondLastPathSegment;
-      final EdmFunctionImport functionImport = uriFunction.getFunctionImport();
-      final EdmFunction function = functionImport == null ?
-          uriFunction.getFunction() : functionImport.getUnboundFunctions().get(0);
+      final EdmFunction function = uriFunction.getFunction();
       final EdmType returnType = function.getReturnType().getType();
       switch (returnType.getKind()) {
       case ENTITY:
@@ -560,8 +530,8 @@ public class UriValidator {
   private void validateParameters(final UriInfo uriInfo) throws UriValidationException {
     for (UriResource pathSegment : uriInfo.getUriResourceParts()) {
       final boolean isFunction = pathSegment.getKind() == UriResourceKind.function;
-      
-      if(isFunction) {
+
+      if (isFunction) {
         final UriResourceFunction functionPathSegement = (UriResourceFunction) pathSegment;
         final EdmFunction edmFuntion = functionPathSegement.getFunction();
         
@@ -613,7 +583,7 @@ public class UriValidator {
     for (UriResource pathSegment : uriInfo.getUriResourceParts()) {
       final boolean isEntitySet = pathSegment.getKind() == UriResourceKind.entitySet;
       final boolean isEntityColFunction = isEntityColFunction(pathSegment);
-      
+
       if (isEntitySet || pathSegment.getKind() == UriResourceKind.navigationProperty || isEntityColFunction) {
         final List<UriParameter> keyPredicates = isEntitySet ?
             ((UriResourceEntitySet) pathSegment).getKeyPredicates() :
@@ -680,7 +650,7 @@ public class UriValidator {
   }
 
   private boolean isEntityColFunction(final UriResource pathSegment) {
-    if(pathSegment.getKind() == UriResourceKind.function) {
+    if (pathSegment.getKind() == UriResourceKind.function) {
       final UriResourceFunction resourceFunction = (UriResourceFunction) pathSegment;
       final EdmReturnType returnType = resourceFunction.getFunction().getReturnType();
       
@@ -689,7 +659,7 @@ public class UriValidator {
       return false;
     }
   }
-  
+
   private void validatePropertyOperations(final UriInfo uriInfo, final HttpMethod method)
       throws UriValidationException {
     final List<UriResource> parts = uriInfo.getUriResourceParts();

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/927ecb93/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java
new file mode 100644
index 0000000..a9e97ce
--- /dev/null
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java
@@ -0,0 +1,369 @@
+/*
+ * 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 static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.olingo.server.core.uri.parser.UriTokenizer.TokenKind;
+import org.junit.Test;
+
+public class UriTokenizerTest {
+
+  @Test
+  public void nullOK() {
+    assertFalse(new UriTokenizer(null).next(null));
+    assertTrue(new UriTokenizer(null).next(TokenKind.EOF));
+  }
+
+  @Test
+  public void constants() {
+    final UriTokenizer tokenizer = new UriTokenizer("$ref");
+    assertTrue(tokenizer.next(TokenKind.REF));
+    assertEquals("$ref", tokenizer.getText());
+    assertTrue(tokenizer.next(TokenKind.EOF));
+    assertTrue(tokenizer.next(TokenKind.EOF));
+
+    assertTrue(new UriTokenizer("$value").next(TokenKind.VALUE));
+    assertTrue(new UriTokenizer("$count").next(TokenKind.COUNT));
+    assertTrue(new UriTokenizer("$crossjoin").next(TokenKind.CROSSJOIN));
+    assertTrue(new UriTokenizer("null").next(TokenKind.NULL));
+
+    wrongToken(TokenKind.REF, "$ref", 'x');
+  }
+
+  @Test
+  public void sequence() {
+    final UriTokenizer tokenizer = new UriTokenizer("(A=1,B=2);");
+    assertTrue(tokenizer.next(TokenKind.OPEN));
+    assertFalse(tokenizer.next(TokenKind.OPEN));
+    assertTrue(tokenizer.next(TokenKind.ODataIdentifier));
+    assertEquals("A", tokenizer.getText());
+    assertTrue(tokenizer.next(TokenKind.EQ));
+    assertTrue(tokenizer.next(TokenKind.PrimitiveIntegerValue));
+    assertEquals("1", tokenizer.getText());
+    assertTrue(tokenizer.next(TokenKind.COMMA));
+    assertTrue(tokenizer.next(TokenKind.ODataIdentifier));
+    assertEquals("B", tokenizer.getText());
+    assertTrue(tokenizer.next(TokenKind.EQ));
+    assertTrue(tokenizer.next(TokenKind.PrimitiveIntegerValue));
+    assertEquals("2", tokenizer.getText());
+    assertFalse(tokenizer.next(TokenKind.EOF));
+    assertTrue(tokenizer.next(TokenKind.CLOSE));
+    assertTrue(tokenizer.next(TokenKind.SEMI));
+    assertTrue(tokenizer.next(TokenKind.EOF));
+  }
+
+  @Test
+  public void identifier() {
+    assertTrue(new UriTokenizer("name").next(TokenKind.ODataIdentifier));
+    assertTrue(new UriTokenizer("_name").next(TokenKind.ODataIdentifier));
+    assertFalse(new UriTokenizer("1name").next(TokenKind.ODataIdentifier));
+    assertFalse(new UriTokenizer("").next(TokenKind.ODataIdentifier));
+
+    final String outsideBmpLetter = String.valueOf(Character.toChars(0x10330));
+    UriTokenizer tokenizer = new UriTokenizer(
+        outsideBmpLetter + "name1\u0300a\u0600b\uFE4F" + outsideBmpLetter + "end\b");
+    assertTrue(tokenizer.next(TokenKind.ODataIdentifier));
+    assertEquals(outsideBmpLetter + "name1\u0300a\u0600b\uFE4F" + outsideBmpLetter + "end", tokenizer.getText());
+
+    // Identifiers consist of up to 128 characters.  Check that the identifier does not have more characters.
+    final String name = "Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch"; // Do you know this village?
+    tokenizer = new UriTokenizer(name + '_' + name + "_0123456789X");
+    assertTrue(tokenizer.next(TokenKind.ODataIdentifier));
+    assertEquals(name + '_' + name + "_0123456789", tokenizer.getText());
+    tokenizer.next(TokenKind.ODataIdentifier);
+    assertEquals("X", tokenizer.getText());
+
+    wrongToken(TokenKind.ODataIdentifier, "_", '.');
+    wrongToken(TokenKind.ODataIdentifier, "_", ',');
+  }
+
+  @Test
+  public void qualifiedName() {
+    assertTrue(new UriTokenizer("namespace.name").next(TokenKind.QualifiedName));
+
+    final UriTokenizer tokenizer = new UriTokenizer("multi.part.namespace.name");
+    assertTrue(tokenizer.next(TokenKind.QualifiedName));
+    assertTrue(tokenizer.next(TokenKind.EOF));
+
+    assertFalse(new UriTokenizer("name").next(TokenKind.QualifiedName));
+    assertFalse(new UriTokenizer("namespace..name").next(TokenKind.QualifiedName));
+    assertFalse(new UriTokenizer("").next(TokenKind.QualifiedName));
+    wrongToken(TokenKind.QualifiedName, "namespace._", ',');
+  }
+
+  @Test
+  public void alias() {
+    assertTrue(new UriTokenizer("@name").next(TokenKind.ParameterAliasName));
+    assertTrue(new UriTokenizer("@_name").next(TokenKind.ParameterAliasName));
+    assertFalse(new UriTokenizer("name").next(TokenKind.ParameterAliasName));
+    assertFalse(new UriTokenizer("@").next(TokenKind.ParameterAliasName));
+    assertFalse(new UriTokenizer("@1").next(TokenKind.ParameterAliasName));
+  }
+
+  @Test
+  public void booleanValue() {
+    assertTrue(new UriTokenizer("true").next(TokenKind.PrimitiveBooleanValue));
+    assertTrue(new UriTokenizer("tRuE").next(TokenKind.PrimitiveBooleanValue));
+    assertTrue(new UriTokenizer("false").next(TokenKind.PrimitiveBooleanValue));
+    assertTrue(new UriTokenizer("False").next(TokenKind.PrimitiveBooleanValue));
+
+    wrongToken(TokenKind.PrimitiveBooleanValue, "true", 'x');
+  }
+
+  @Test
+  public void string() {
+    assertTrue(new UriTokenizer("'ABC'").next(TokenKind.PrimitiveStringValue));
+    assertTrue(new UriTokenizer("'€\uFDFC'").next(TokenKind.PrimitiveStringValue));
+    assertTrue(new UriTokenizer('\'' + String.valueOf(Character.toChars(0x1F603)) + '\'')
+        .next(TokenKind.PrimitiveStringValue));
+
+    final UriTokenizer tokenizer = new UriTokenizer("'AB''''C'''D");
+    assertTrue(tokenizer.next(TokenKind.PrimitiveStringValue));
+    assertEquals("'AB''''C'''", tokenizer.getText());
+    assertTrue(tokenizer.next(TokenKind.ODataIdentifier));
+    assertEquals("D", tokenizer.getText());
+
+    assertFalse(new UriTokenizer("A").next(TokenKind.PrimitiveStringValue));
+    assertFalse(new UriTokenizer("'A").next(TokenKind.PrimitiveStringValue));
+  }
+
+  @Test
+  public void integer() {
+    assertTrue(new UriTokenizer("1").next(TokenKind.PrimitiveIntegerValue));
+    assertTrue(new UriTokenizer("1.").next(TokenKind.PrimitiveIntegerValue));
+    assertFalse(new UriTokenizer(".1").next(TokenKind.PrimitiveIntegerValue));
+    assertTrue(new UriTokenizer("-1").next(TokenKind.PrimitiveIntegerValue));
+    assertTrue(new UriTokenizer("1234567890").next(TokenKind.PrimitiveIntegerValue));
+  }
+
+  @Test
+  public void guid() {
+    assertTrue(new UriTokenizer("12345678-abcd-ef12-1234-567890ABCDEF").next(TokenKind.PrimitiveGuidValue));
+    wrongToken(TokenKind.PrimitiveGuidValue, "12345678-1234-1234-1234-123456789ABC", 'G');
+  }
+
+  @Test
+  public void date() {
+    assertTrue(new UriTokenizer("12345-12-25").next(TokenKind.PrimitiveDateValue));
+    assertTrue(new UriTokenizer("-0001-12-24").next(TokenKind.PrimitiveDateValue));
+    assertFalse(new UriTokenizer("1234-13-01").next(TokenKind.PrimitiveDateValue));
+    assertFalse(new UriTokenizer("1234-12-32").next(TokenKind.PrimitiveDateValue));
+    assertFalse(new UriTokenizer("123-01-01").next(TokenKind.PrimitiveDateValue));
+    assertFalse(new UriTokenizer("1234-00-01").next(TokenKind.PrimitiveDateValue));
+    assertFalse(new UriTokenizer("1234-01-00").next(TokenKind.PrimitiveDateValue));
+    wrongToken(TokenKind.PrimitiveDateValue, "2000-12-29", 'A');
+    wrongToken(TokenKind.PrimitiveDateValue, "0001-01-01", 'A');
+    wrongToken(TokenKind.PrimitiveDateValue, "-12345-01-31", 'A');
+  }
+
+  @Test
+  public void dateTimeOffset() {
+    assertTrue(new UriTokenizer("1234-12-25T11:12:13.456Z").next(TokenKind.PrimitiveDateTimeOffsetValue));
+    assertTrue(new UriTokenizer("-1234-12-25t01:12z").next(TokenKind.PrimitiveDateTimeOffsetValue));
+    assertTrue(new UriTokenizer("-1234-12-25T21:22:23+01:00").next(TokenKind.PrimitiveDateTimeOffsetValue));
+    assertTrue(new UriTokenizer("1234-12-25T11:12:13-00:30").next(TokenKind.PrimitiveDateTimeOffsetValue));
+    assertFalse(new UriTokenizer("1234-10-01").next(TokenKind.PrimitiveDateTimeOffsetValue));
+    wrongToken(TokenKind.PrimitiveDateTimeOffsetValue, "-1234-12-25T11:12:13.456+01:00", 'P');
+  }
+
+  @Test
+  public void timeOfDay() {
+    assertTrue(new UriTokenizer("11:12:13").next(TokenKind.PrimitiveTimeOfDayValue));
+    assertTrue(new UriTokenizer("11:12:13.456").next(TokenKind.PrimitiveTimeOfDayValue));
+    assertFalse(new UriTokenizer("24:00:00").next(TokenKind.PrimitiveTimeOfDayValue));
+    assertFalse(new UriTokenizer("01:60:00").next(TokenKind.PrimitiveTimeOfDayValue));
+    assertFalse(new UriTokenizer("01:00:60").next(TokenKind.PrimitiveTimeOfDayValue));
+    assertFalse(new UriTokenizer("01:00:00.").next(TokenKind.PrimitiveTimeOfDayValue));
+    assertFalse(new UriTokenizer("0:02:03").next(TokenKind.PrimitiveTimeOfDayValue));
+    assertFalse(new UriTokenizer("01:0:03").next(TokenKind.PrimitiveTimeOfDayValue));
+    assertFalse(new UriTokenizer("01:02:0").next(TokenKind.PrimitiveTimeOfDayValue));
+    wrongToken(TokenKind.PrimitiveTimeOfDayValue, "11:12", '-');
+  }
+
+  @Test
+  public void decimal() {
+    assertTrue(new UriTokenizer("1.2").next(TokenKind.PrimitiveDecimalValue));
+    assertFalse(new UriTokenizer(".1").next(TokenKind.PrimitiveDecimalValue));
+    assertTrue(new UriTokenizer("-12.34").next(TokenKind.PrimitiveDecimalValue));
+    assertTrue(new UriTokenizer("1234567890.0123456789").next(TokenKind.PrimitiveDecimalValue));
+    assertFalse(new UriTokenizer("0,1").next(TokenKind.PrimitiveDecimalValue));
+    assertFalse(new UriTokenizer("0..1").next(TokenKind.PrimitiveDecimalValue));
+  }
+
+  @Test
+  public void doubleValue() {
+    assertTrue(new UriTokenizer("NaN").next(TokenKind.PrimitiveDoubleValue));
+    assertTrue(new UriTokenizer("-INF").next(TokenKind.PrimitiveDoubleValue));
+    assertTrue(new UriTokenizer("INF").next(TokenKind.PrimitiveDoubleValue));
+    assertFalse(new UriTokenizer("inf").next(TokenKind.PrimitiveDoubleValue));
+    assertTrue(new UriTokenizer("1.2E3").next(TokenKind.PrimitiveDoubleValue));
+    assertTrue(new UriTokenizer("-12.34e-05").next(TokenKind.PrimitiveDoubleValue));
+    assertTrue(new UriTokenizer("1E2").next(TokenKind.PrimitiveDoubleValue));
+    assertFalse(new UriTokenizer("1.E2").next(TokenKind.PrimitiveDoubleValue));
+    wrongToken(TokenKind.PrimitiveDoubleValue, "-12.34E+5", 'i');
+  }
+
+  @Test
+  public void duration() {
+    assertTrue(new UriTokenizer("duration'P'").next(TokenKind.PrimitiveDurationValue));
+    assertTrue(new UriTokenizer("DURATION'P1D'").next(TokenKind.PrimitiveDurationValue));
+    assertTrue(new UriTokenizer("duration'PT'").next(TokenKind.PrimitiveDurationValue));
+    assertTrue(new UriTokenizer("duration'PT1H'").next(TokenKind.PrimitiveDurationValue));
+    assertTrue(new UriTokenizer("duration'pt1M'").next(TokenKind.PrimitiveDurationValue));
+    assertTrue(new UriTokenizer("duration'PT1S'").next(TokenKind.PrimitiveDurationValue));
+    assertTrue(new UriTokenizer("duration'PT1.2s'").next(TokenKind.PrimitiveDurationValue));
+    assertTrue(new UriTokenizer("duration'-p1dt2h3m4.5s'").next(TokenKind.PrimitiveDurationValue));
+    assertFalse(new UriTokenizer("-p1dt2h3m4.5s").next(TokenKind.PrimitiveDurationValue));
+    assertFalse(new UriTokenizer("duration'-p1dt2h3m4.5s").next(TokenKind.PrimitiveDurationValue));
+    assertFalse(new UriTokenizer("duration'2h3m4s'").next(TokenKind.PrimitiveDurationValue));
+    wrongToken(TokenKind.PrimitiveDurationValue, "duration'P1DT2H3M4.5S'", ':');
+  }
+
+  @Test
+  public void binary() {
+    assertTrue(new UriTokenizer("binary''").next(TokenKind.PrimitiveBinaryValue));
+    assertTrue(new UriTokenizer("Binary'bm93'").next(TokenKind.PrimitiveBinaryValue));
+
+    // all cases with three base64 characters (and one fill character) at the end
+    assertTrue(new UriTokenizer("binary'QUA='").next(TokenKind.PrimitiveBinaryValue));
+    assertTrue(new UriTokenizer("binary'QUE='").next(TokenKind.PrimitiveBinaryValue));
+    assertTrue(new UriTokenizer("binary'QUI='").next(TokenKind.PrimitiveBinaryValue));
+    assertTrue(new UriTokenizer("binary'QUM='").next(TokenKind.PrimitiveBinaryValue));
+    assertTrue(new UriTokenizer("binary'QUQ='").next(TokenKind.PrimitiveBinaryValue));
+    assertTrue(new UriTokenizer("binary'QUU='").next(TokenKind.PrimitiveBinaryValue));
+    assertTrue(new UriTokenizer("binary'QUY='").next(TokenKind.PrimitiveBinaryValue));
+    assertTrue(new UriTokenizer("binary'QUc='").next(TokenKind.PrimitiveBinaryValue));
+    assertTrue(new UriTokenizer("binary'QUg='").next(TokenKind.PrimitiveBinaryValue));
+    assertTrue(new UriTokenizer("binary'QUk='").next(TokenKind.PrimitiveBinaryValue));
+    assertTrue(new UriTokenizer("binary'QUo='").next(TokenKind.PrimitiveBinaryValue));
+    assertTrue(new UriTokenizer("binary'QUs='").next(TokenKind.PrimitiveBinaryValue));
+    assertTrue(new UriTokenizer("binary'QUw='").next(TokenKind.PrimitiveBinaryValue));
+    assertTrue(new UriTokenizer("binary'QU0='").next(TokenKind.PrimitiveBinaryValue));
+    assertTrue(new UriTokenizer("binary'QU4='").next(TokenKind.PrimitiveBinaryValue));
+    assertTrue(new UriTokenizer("binary'QU8='").next(TokenKind.PrimitiveBinaryValue));
+    assertFalse(new UriTokenizer("binary'QUB='").next(TokenKind.PrimitiveBinaryValue));
+
+    // all cases with two base64 characters (and two fill characters) at the end
+    assertTrue(new UriTokenizer("BINARY'VGVzdA=='").next(TokenKind.PrimitiveBinaryValue));
+    assertTrue(new UriTokenizer("binary'U-RnZQ=='").next(TokenKind.PrimitiveBinaryValue));
+    assertTrue(new UriTokenizer("binary'Yg=='").next(TokenKind.PrimitiveBinaryValue));
+    assertTrue(new UriTokenizer("binary'Yw=='").next(TokenKind.PrimitiveBinaryValue));
+
+    // without optional fill character
+    assertTrue(new UriTokenizer("binary'T0RhdGE'").next(TokenKind.PrimitiveBinaryValue));
+
+    // special character '_' (the other, '-', already has been used above)
+    assertTrue(new UriTokenizer("binary'V_ZydGVy'").next(TokenKind.PrimitiveBinaryValue));
+
+    wrongToken(TokenKind.PrimitiveBinaryValue, "binary'VGVzdA=='", '+');
+  }
+
+  @Test
+  public void enumValue() {
+    assertTrue(new UriTokenizer("namespace.name'value'").next(TokenKind.PrimitiveEnumValue));
+    assertTrue(new UriTokenizer("namespace.name'flag1,flag2,-3'").next(TokenKind.PrimitiveEnumValue));
+    assertFalse(new UriTokenizer("namespace.name'1flag'").next(TokenKind.PrimitiveEnumValue));
+    assertFalse(new UriTokenizer("namespace.name'flag1,,flag2'").next(TokenKind.PrimitiveEnumValue));
+    assertFalse(new UriTokenizer("namespace.name',value'").next(TokenKind.PrimitiveEnumValue));
+    assertFalse(new UriTokenizer("namespace.name'value,'").next(TokenKind.PrimitiveEnumValue));
+    assertFalse(new UriTokenizer("namespace.name''").next(TokenKind.PrimitiveEnumValue));
+    assertFalse(new UriTokenizer("'1'").next(TokenKind.PrimitiveEnumValue));
+    assertFalse(new UriTokenizer("1").next(TokenKind.PrimitiveEnumValue));
+    wrongToken(TokenKind.PrimitiveEnumValue, "namespace.name'_1,_2,3'", ';');
+  }
+
+  @Test
+  public void json() {
+    // Empty string or JSON values are not allowed.
+    assertFalse(new UriTokenizer("").next(TokenKind.jsonArrayOrObject));
+    assertFalse(new UriTokenizer("1").next(TokenKind.jsonArrayOrObject));
+
+    // object with values
+    assertTrue(new UriTokenizer("{}").next(TokenKind.jsonArrayOrObject));
+    assertTrue(new UriTokenizer("{\"name\":0}").next(TokenKind.jsonArrayOrObject));
+    assertTrue(new UriTokenizer("{\"name\":true}").next(TokenKind.jsonArrayOrObject));
+    assertTrue(new UriTokenizer("{\"name\":false}").next(TokenKind.jsonArrayOrObject));
+    assertTrue(new UriTokenizer("{\"name\":null}").next(TokenKind.jsonArrayOrObject));
+    assertTrue(new UriTokenizer("{\"name\":\"value\"}").next(TokenKind.jsonArrayOrObject));
+    assertTrue(new UriTokenizer("{\"name\":\"value\",\"name2\":null}").next(TokenKind.jsonArrayOrObject));
+
+    // array with values
+    assertTrue(new UriTokenizer("[]").next(TokenKind.jsonArrayOrObject));
+    assertTrue(new UriTokenizer("[1]").next(TokenKind.jsonArrayOrObject));
+    assertTrue(new UriTokenizer("[true]").next(TokenKind.jsonArrayOrObject));
+    assertTrue(new UriTokenizer("[false]").next(TokenKind.jsonArrayOrObject));
+    assertTrue(new UriTokenizer("[null]").next(TokenKind.jsonArrayOrObject));
+    assertTrue(new UriTokenizer("[\"value\"]").next(TokenKind.jsonArrayOrObject));
+    assertTrue(new UriTokenizer("[\"\"]").next(TokenKind.jsonArrayOrObject));
+    assertTrue(new UriTokenizer("[\"\\b\\t\\f\\r\\nn\\/\\\\x\\uFE4Fu\\\"\"]").next(TokenKind.jsonArrayOrObject));
+    assertTrue(new UriTokenizer("[1,2.0,3.4E5]").next(TokenKind.jsonArrayOrObject));
+    assertTrue(new UriTokenizer("[\"value\",null]").next(TokenKind.jsonArrayOrObject));
+
+    // nesting
+    assertTrue(new UriTokenizer("[{\"name\":\"value\"},{\"name\":\"value2\"}]").next(TokenKind.jsonArrayOrObject));
+    assertTrue(new UriTokenizer("{\"name\":{\"name2\":\"value\"}}").next(TokenKind.jsonArrayOrObject));
+
+    // unbalanced opening and closing
+    assertFalse(new UriTokenizer("{").next(TokenKind.jsonArrayOrObject));
+    assertFalse(new UriTokenizer("}").next(TokenKind.jsonArrayOrObject));
+    assertFalse(new UriTokenizer("[").next(TokenKind.jsonArrayOrObject));
+    assertFalse(new UriTokenizer("]").next(TokenKind.jsonArrayOrObject));
+    assertFalse(new UriTokenizer("{]").next(TokenKind.jsonArrayOrObject));
+
+    // missing values
+    assertFalse(new UriTokenizer("[1,]").next(TokenKind.jsonArrayOrObject));
+    assertFalse(new UriTokenizer("[,1]").next(TokenKind.jsonArrayOrObject));
+    assertFalse(new UriTokenizer("[1,,2]").next(TokenKind.jsonArrayOrObject));
+    assertFalse(new UriTokenizer("[1,x]").next(TokenKind.jsonArrayOrObject));
+    assertFalse(new UriTokenizer("{\"name\":1,}").next(TokenKind.jsonArrayOrObject));
+    assertFalse(new UriTokenizer("{,\"name\":1}").next(TokenKind.jsonArrayOrObject));
+    assertFalse(new UriTokenizer("{\"name\":1,,\"name2\":2}").next(TokenKind.jsonArrayOrObject));
+    assertFalse(new UriTokenizer("{\"name\":1,x}").next(TokenKind.jsonArrayOrObject));
+    assertFalse(new UriTokenizer("{\"name\":1,\"name2\"}").next(TokenKind.jsonArrayOrObject));
+    assertFalse(new UriTokenizer("{\"name\":1,\"name2\":}").next(TokenKind.jsonArrayOrObject));
+
+    // wrong JSON strings
+    assertFalse(new UriTokenizer("[\"a").next(TokenKind.jsonArrayOrObject));
+    assertFalse(new UriTokenizer("[\"a]").next(TokenKind.jsonArrayOrObject));
+    assertFalse(new UriTokenizer("[\"a\"\"]").next(TokenKind.jsonArrayOrObject));
+    assertFalse(new UriTokenizer("[\"\\x\"]").next(TokenKind.jsonArrayOrObject));
+    assertFalse(new UriTokenizer("[\"\\ux\"]").next(TokenKind.jsonArrayOrObject));
+    assertFalse(new UriTokenizer("[\"\\u1\"]").next(TokenKind.jsonArrayOrObject));
+    assertFalse(new UriTokenizer("[\"\\u12x\"]").next(TokenKind.jsonArrayOrObject));
+    assertFalse(new UriTokenizer("[\"\\u123x\"]").next(TokenKind.jsonArrayOrObject));
+  }
+
+  private void wrongToken(final TokenKind kind, final String value, final char disturbCharacter) {
+    assertFalse(new UriTokenizer(disturbCharacter + value).next(kind));
+
+    final UriTokenizer tokenizer = new UriTokenizer(value + disturbCharacter);
+    assertTrue(tokenizer.next(kind));
+    assertEquals(value, tokenizer.getText());
+
+    // Place the disturbing character at every position in the value string
+    // and check that this leads to a failed token recognition.
+    for (int index = 0; index < value.length(); index++) {
+      assertFalse("Error at index " + index,
+          new UriTokenizer(value.substring(0, index) + disturbCharacter + value.substring(index + 1)).next(kind));
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/927ecb93/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
index c2a390a..7547687 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
@@ -31,7 +31,6 @@ import java.util.Iterator;
 import java.util.List;
 
 import org.junit.Assert;
-import org.junit.Ignore;
 import org.junit.Test;
 
 public class SearchTokenizerTest {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/927ecb93/lib/server-tecsvc/src/test/java/org/apache/olingo/server/tecsvc/data/DataProviderTest.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/test/java/org/apache/olingo/server/tecsvc/data/DataProviderTest.java b/lib/server-tecsvc/src/test/java/org/apache/olingo/server/tecsvc/data/DataProviderTest.java
index 93c3c9a..6bd6463 100644
--- a/lib/server-tecsvc/src/test/java/org/apache/olingo/server/tecsvc/data/DataProviderTest.java
+++ b/lib/server-tecsvc/src/test/java/org/apache/olingo/server/tecsvc/data/DataProviderTest.java
@@ -29,7 +29,6 @@ import org.apache.olingo.commons.api.data.Property;
 import org.apache.olingo.commons.api.edm.Edm;
 import org.apache.olingo.commons.api.edm.EdmEntityContainer;
 import org.apache.olingo.commons.api.edm.EdmEntitySet;
-import org.apache.olingo.commons.api.edm.FullQualifiedName;
 import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.edmx.EdmxReference;
 import org.apache.olingo.server.api.uri.UriParameter;
@@ -44,8 +43,7 @@ public class DataProviderTest {
   private final Edm edm =
       oData.createServiceMetadata(new EdmTechProvider(), Collections.<EdmxReference> emptyList())
       .getEdm();
-  private final EdmEntityContainer entityContainer = edm.getEntityContainer(
-      new FullQualifiedName("olingo.odata.test1", "Container"));
+  private final EdmEntityContainer entityContainer = edm.getEntityContainer();
 
   private final EdmEntitySet esAllPrim = entityContainer.getEntitySet("ESAllPrim");
   private final EdmEntitySet esAllKey = entityContainer.getEntitySet("ESAllKey");

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/927ecb93/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 5e3499c..bf68fb3 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
@@ -41,7 +41,7 @@ import org.apache.olingo.server.api.uri.UriResourceValue;
 import org.apache.olingo.server.core.etag.PreconditionsValidator;
 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.parser.UriParserSemanticException;
+import org.apache.olingo.server.core.uri.validator.UriValidationException;
 import org.apache.olingo.server.tecsvc.provider.EdmTechProvider;
 import org.junit.Test;
 import org.mockito.invocation.InvocationOnMock;
@@ -49,7 +49,8 @@ import org.mockito.stubbing.Answer;
 
 public class PreconditionsValidatorTest {
 
-  private static final Edm edm = OData.newInstance().createServiceMetadata(
+  private static final OData odata = OData.newInstance();
+  private static final Edm edm = odata.createServiceMetadata(
       new EdmTechProvider(), Collections.<EdmxReference> emptyList()).getEdm();
 
   // -------------- POSITIVE TESTS --------------------------------------------------------------------------------
@@ -140,7 +141,7 @@ public class PreconditionsValidatorTest {
 
   @Test
   public void simpleEntityValueValidationNotActiveForMedia() throws Exception {
-    final UriInfo uriInfo = new Parser().parseUri("ESMedia(1)/$value", null, null, edm);
+    final UriInfo uriInfo = new Parser(edm, odata).parseUri("ESMedia(1)/$value", null, null);
 
     CustomETagSupport support = mock(CustomETagSupport.class);
     when(support.hasETag(any(EdmBindingTarget.class))).thenReturn(true);
@@ -185,21 +186,17 @@ public class PreconditionsValidatorTest {
     assertFalse(mustValidate("SINav/NavPropertyETKeyNavOne/$ref", "ESKeyNav"));
   }
 
-  @Test(expected = UriParserSemanticException.class)
-  public void resourceSegmentAfterActionMustLeadToUriParserException() throws Exception {
-    mustValidate("ESKeyNav(1)/Namespace1_Alias.BAETTwoKeyNavRTETTwoKeyNav/PropertyInt16", "ESKeyNav");
-  }
-
-  @Test(expected = UriParserSemanticException.class)
-  public void valueMustBeLastSegment() throws Exception {
-    mustValidate("ESMedia(1)/$value/PropertyInt16", "ESMedia");
+  @Test
+  public void nonResourceMustBeIgnored() throws Exception {
+    assertFalse(mustValidate("$all", null));
   }
 
   private boolean mustValidate(final String uri, final String entitySetName)
-      throws UriParserException, PreconditionException {
-    final UriInfo uriInfo = new Parser().parseUri(uri, null, null, edm);
+      throws UriParserException, UriValidationException, PreconditionException {
+    final UriInfo uriInfo = new Parser(edm, odata).parseUri(uri, null, null);
     final List<UriResource> parts = uriInfo.getUriResourceParts();
-    final boolean isMedia = parts.get(parts.size() - 1) instanceof UriResourceValue
+    final boolean isMedia = parts.size() >= 2
+        && parts.get(parts.size() - 1) instanceof UriResourceValue
         && parts.get(parts.size() - 2) instanceof UriResourceEntitySet;
 
     CustomETagSupport support = mock(CustomETagSupport.class);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/927ecb93/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/utils/ContextURLHelperTest.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/utils/ContextURLHelperTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/utils/ContextURLHelperTest.java
index fe86896..92b069d 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/utils/ContextURLHelperTest.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/utils/ContextURLHelperTest.java
@@ -28,7 +28,6 @@ import org.apache.olingo.commons.api.edm.Edm;
 import org.apache.olingo.commons.api.edm.EdmEntityContainer;
 import org.apache.olingo.commons.api.edm.EdmEntitySet;
 import org.apache.olingo.commons.api.edm.EdmProperty;
-import org.apache.olingo.commons.api.edm.FullQualifiedName;
 import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.edmx.EdmxReference;
 import org.apache.olingo.server.api.uri.UriParameter;
@@ -45,8 +44,7 @@ public class ContextURLHelperTest {
 
   private static final Edm edm = OData.newInstance().createServiceMetadata(
       new EdmTechProvider(), Collections.<EdmxReference> emptyList()).getEdm();
-  private static final EdmEntityContainer entityContainer = edm.getEntityContainer(
-      new FullQualifiedName("olingo.odata.test1", "Container"));
+  private static final EdmEntityContainer entityContainer = edm.getEntityContainer();
 
   @Test
   public void buildSelect() throws Exception {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/927ecb93/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/UriHelperTest.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/UriHelperTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/UriHelperTest.java
index 781f48d..d3dba46 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/UriHelperTest.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/UriHelperTest.java
@@ -25,7 +25,6 @@ import org.apache.olingo.commons.api.data.ValueType;
 import org.apache.olingo.commons.api.edm.Edm;
 import org.apache.olingo.commons.api.edm.EdmEntityContainer;
 import org.apache.olingo.commons.api.edm.EdmEntitySet;
-import org.apache.olingo.commons.api.edm.FullQualifiedName;
 import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.edmx.EdmxReference;
 import org.apache.olingo.server.api.serializer.SerializerException;
@@ -40,8 +39,7 @@ public class UriHelperTest {
   private static final OData odata = OData.newInstance();
   private static final Edm edm = odata.createServiceMetadata(
       new EdmTechProvider(), Collections.<EdmxReference> emptyList()).getEdm();
-  private static final EdmEntityContainer container = edm.getEntityContainer(
-      new FullQualifiedName("olingo.odata.test1", "Container"));
+  private static final EdmEntityContainer container = edm.getEntityContainer();
   private static final UriHelper helper = odata.createUriHelper();
   private final DataProvider data = new DataProvider(odata, edm);
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/927ecb93/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/UriResourceImplTest.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/UriResourceImplTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/UriResourceImplTest.java
index 27b879d..a5d0ea3 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/UriResourceImplTest.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/UriResourceImplTest.java
@@ -86,7 +86,7 @@ public class UriResourceImplTest {
 
     // action import
     impl = new UriResourceActionImpl();
-    EdmActionImport actionImport = edm.getEntityContainer(null).getActionImport("AIRTCTTwoPrimParam");
+    EdmActionImport actionImport = edm.getEntityContainer().getActionImport("AIRTCTTwoPrimParam");
     impl.setActionImport(actionImport);
     assertEquals(actionImport, impl.getActionImport());
     assertEquals(actionImport.getUnboundAction(), impl.getAction());
@@ -94,7 +94,7 @@ public class UriResourceImplTest {
     assertEquals("AIRTCTTwoPrimParam", impl.toString());
     assertEquals(actionImport.getUnboundAction().getReturnType().getType(), impl.getType());
 
-    actionImport = edm.getEntityContainer(null).getActionImport("AIRT");
+    actionImport = edm.getEntityContainer().getActionImport("AIRT");
     impl.setActionImport(actionImport);
     assertFalse(impl.isCollection());
     assertNull(impl.getType());
@@ -184,7 +184,7 @@ public class UriResourceImplTest {
     UriResourceEntitySetImpl impl = new UriResourceEntitySetImpl();
     assertEquals(UriResourceKind.entitySet, impl.getKind());
 
-    EdmEntitySet entitySet = edm.getEntityContainer(null).getEntitySet("ESAllPrim");
+    EdmEntitySet entitySet = edm.getEntityContainer().getEntitySet("ESAllPrim");
     impl.setEntitSet(entitySet);
 
     assertEquals("ESAllPrim", impl.toString());
@@ -207,7 +207,7 @@ public class UriResourceImplTest {
     assertEquals("", impl.toString());
 
     // function
-    EdmFunction function = edm.getEntityContainer(null).getFunctionImport("FINRTInt16")
+    EdmFunction function = edm.getEntityContainer().getFunctionImport("FINRTInt16")
         .getUnboundFunction(Collections.<String> emptyList());
     assertNotNull(function);
     impl.setFunction(function);
@@ -219,14 +219,14 @@ public class UriResourceImplTest {
 
     // function import
     impl = new UriResourceFunctionImpl();
-    EdmFunctionImport functionImport = edm.getEntityContainer(null).getFunctionImport("FINRTInt16");
+    EdmFunctionImport functionImport = edm.getEntityContainer().getFunctionImport("FINRTInt16");
     impl.setFunctionImport(functionImport, Collections.<UriParameter> emptyList());
     assertEquals(functionImport, impl.getFunctionImport());
     assertEquals("FINRTInt16", impl.toString());
 
     // function collection
     impl = new UriResourceFunctionImpl();
-    functionImport = edm.getEntityContainer(null).getFunctionImport("FICRTCollESTwoKeyNavParam");
+    functionImport = edm.getEntityContainer().getFunctionImport("FICRTCollESTwoKeyNavParam");
     assertNotNull(function);
     UriParameter parameter = new UriParameterImpl().setName("ParameterInt16");
     impl.setFunctionImport(functionImport, Collections.singletonList(parameter));
@@ -414,7 +414,7 @@ public class UriResourceImplTest {
     UriResourceSingletonImpl impl = new UriResourceSingletonImpl();
     assertEquals(UriResourceKind.singleton, impl.getKind());
 
-    EdmSingleton singleton = edm.getEntityContainer(null).getSingleton("SINav");
+    EdmSingleton singleton = edm.getEntityContainer().getSingleton("SINav");
     EdmEntityType entityTypeBaseColl = edm.getEntityType(EntityTypeProvider.nameETBaseTwoKeyNav);
     impl.setSingleton(singleton);
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/927ecb93/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java
index 379345e..11acede 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java
@@ -34,12 +34,10 @@ import org.apache.olingo.commons.api.edm.FullQualifiedName;
 import org.apache.olingo.commons.api.format.ContentType;
 import org.apache.olingo.commons.core.Encoder;
 import org.apache.olingo.server.api.OData;
-import org.apache.olingo.server.api.ODataApplicationException;
 import org.apache.olingo.server.api.edmx.EdmxReference;
 import org.apache.olingo.server.api.uri.UriInfoKind;
 import org.apache.olingo.server.api.uri.UriResourceKind;
 import org.apache.olingo.server.api.uri.queryoption.expression.BinaryOperatorKind;
-import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitException;
 import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind;
 import org.apache.olingo.server.core.uri.parser.UriParserException;
 import org.apache.olingo.server.core.uri.parser.UriParserSemanticException;
@@ -934,14 +932,20 @@ public class TestFullResourcePath {
   }
 
   @Test
-  public void runCrossjoin() throws Exception {
+  public void crossjoin() throws Exception {
     testUri.run("$crossjoin(ESKeyNav)")
         .isKind(UriInfoKind.crossjoin)
         .isCrossJoinEntityList(Arrays.asList("ESKeyNav"));
 
-    testUri.run("$crossjoin(ESKeyNav, ESTwoKeyNav)")
+    testUri.run("$crossjoin(ESKeyNav,ESTwoKeyNav)")
         .isKind(UriInfoKind.crossjoin)
         .isCrossJoinEntityList(Arrays.asList("ESKeyNav", "ESTwoKeyNav"));
+
+    testUri.run("$crossjoin(ESTwoPrim,ESMixPrimCollComp)",
+        "$filter=ESTwoPrim/PropertyString eq ESMixPrimCollComp/PropertyComp/PropertyString")
+        .goFilter()
+        .isBinary(BinaryOperatorKind.EQ)
+        .is("<<ESTwoPrim/PropertyString> eq <ESMixPrimCollComp/PropertyComp/PropertyString>>");
   }
 
   @Test
@@ -951,6 +955,8 @@ public class TestFullResourcePath {
     testUri.runEx("$crossjoin()").isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
     testUri.runEx("$crossjoin(ESKeyNav, ESTwoKeyNav)/invalid")
         .isExSyntax(UriParserSyntaxException.MessageKeys.MUST_BE_LAST_SEGMENT);
+    testUri.runEx("$crossjoin(ESKeyNav)/$ref")
+        .isExSyntax(UriParserSyntaxException.MessageKeys.MUST_BE_LAST_SEGMENT);
   }
 
   @Test
@@ -982,15 +988,16 @@ public class TestFullResourcePath {
   }
 
   @Test
-  public void runEsNameError() {
+  public void esNameError() {
 
-    testUri.runEx("ESAllPrim/$count/$ref").isExSemantic(MessageKeys.ONLY_FOR_TYPED_PROPERTIES);
-    testUri.runEx("ESAllPrim/$ref/$count").isExSemantic(MessageKeys.ONLY_FOR_TYPED_PARTS);
-    testUri.runEx("ESAllPrim/$ref/invalid").isExSemantic(MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS);
-    testUri.runEx("ESAllPrim/$count/invalid").isExSemantic(MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS);
+    testUri.runEx("ESAllPrim/$count/$ref").isExSyntax(UriParserSyntaxException.MessageKeys.MUST_BE_LAST_SEGMENT);
+    testUri.runEx("ESAllPrim/$ref/$count").isExSyntax(UriParserSyntaxException.MessageKeys.MUST_BE_LAST_SEGMENT);
+    testUri.runEx("ESAllPrim/$ref/invalid").isExSyntax(UriParserSyntaxException.MessageKeys.MUST_BE_LAST_SEGMENT);
+    testUri.runEx("ESAllPrim/$count/invalid").isExSyntax(UriParserSyntaxException.MessageKeys.MUST_BE_LAST_SEGMENT);
     testUri.runEx("ESAllPrim/PropertyString").isExSemantic(MessageKeys.PROPERTY_AFTER_COLLECTION);
     testUri.runEx("ESAllPrim(1)/whatever").isExSemantic(MessageKeys.PROPERTY_NOT_IN_TYPE);
-    testUri.runEx("ESAllPrim(PropertyInt16)").isExSemantic(MessageKeys.INVALID_KEY_VALUE);
+    testUri.runEx("ESAllPrim('1')").isExSemantic(MessageKeys.INVALID_KEY_VALUE);
+    testUri.runEx("ESAllPrim(PropertyInt16)").isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
     testUri.runEx("ESAllPrim(PropertyInt16=)").isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
     testUri.runEx("ESAllPrim(PropertyInt16=1,Invalid='1')").isExSemantic(MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES);
 
@@ -1023,8 +1030,7 @@ public class TestFullResourcePath {
   }
 
   @Test
-  public void runResourcePathWithApostrophe() {
-    // TODO Currently "'" is not allowed in OData identifiers, but the specification allows this character (Unicode Cf)
+  public void resourcePathWithApostrophe() {
     testUri.runEx("ESAllPrim'").isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
     testUri.runEx("ESAllPrim'InvalidStuff").isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
 
@@ -1070,7 +1076,7 @@ public class TestFullResourcePath {
         .isKeyPredicate(0, "PropertyInt16", "0");
 
     testUri.runEx("FICRTCollETMixPrimCollCompTwoParam(ParameterString='1',ParameterInt16=1)(PropertyInt16 eq 0)")
-        .isExSemantic(MessageKeys.INVALID_KEY_VALUE);
+        .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
 
     // PropertyInt32 does not exist
     testUri.runEx("FICRTCollETMixPrimCollCompTwoParam(ParameterString='1',ParameterInt16=1)(PropertyInt32=0)")
@@ -1078,7 +1084,7 @@ public class TestFullResourcePath {
 
     testUri.runEx("FICRTCollETMixPrimCollCompTwoParam(ParameterString='1',ParameterInt16=1)"
         + "(PropertyInt16=0,PropertyInt16=1)")
-        .isExSemantic(MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES);
+        .isExValidation(UriValidationException.MessageKeys.DOUBLE_KEY_PROPERTY);
 
     testUri.run("FICRTCollCTTwoPrimTwoParam(ParameterString='1',ParameterInt16=1)")
         .isKind(UriInfoKind.resource)
@@ -1117,13 +1123,13 @@ public class TestFullResourcePath {
         .isKeyPredicate(1, "PropertyString", "'1'");
 
     testUri.runEx("FICRTCollESTwoKeyNavParam(ParameterInt16=1)(PropertyInt16 eq 1)")
-        .isExSemantic(MessageKeys.INVALID_KEY_VALUE);
+        .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
 
     testUri.runEx("FICRTCollESTwoKeyNavParam(ParameterInt16=1)(PropertyInt16=1)")
         .isExSemantic(MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES);
 
     testUri.runEx("FICRTCollESTwoKeyNavParam(ParameterInt16=1)(PropertyInt16=1,PropertyInt32=1,PropertyString='1')")
-        .isExSemantic(MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES);
+        .isExValidation(UriValidationException.MessageKeys.INVALID_KEY_PROPERTY);
 
     testUri.runEx("FICRTCollESTwoKeyNavParam(ParameterInt16=1)()")
         .isExSemantic(MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES);
@@ -1193,11 +1199,9 @@ public class TestFullResourcePath {
     testUri.runEx("FICRTCollETMixPrimCollCompTwoParam(ParameterInt16=1,ParameterString='1')", "$skiptoken=5")
         .isExValidation(UriValidationException.MessageKeys.SYSTEM_QUERY_OPTION_NOT_ALLOWED);
 
-    // $search is currently not implemented. Please change this exception if the implementation is done.
-    // FIXME (151106:mibo): check after finish of OLINGO-568
-//    testUri.runEx("FICRTCollETMixPrimCollCompTwoParam(ParameterInt16=1,ParameterString='1')", "$search=test")
-//      .isExSemantic(MessageKeys.NOT_IMPLEMENTED);
-    
+    testUri.runEx("FICRTCollETMixPrimCollCompTwoParam(ParameterInt16=1,ParameterString='1')", "$search=test")
+        .isExValidation(UriValidationException.MessageKeys.SYSTEM_QUERY_OPTION_NOT_ALLOWED);
+
     testUri.run("ESAllPrim/olingo.odata.test1.BFNESAllPrimRTCTAllPrim()")
         .isKind(UriInfoKind.resource)
         .goPath().first()
@@ -1296,8 +1300,8 @@ public class TestFullResourcePath {
         .isKeyPredicate(2, "KeyAlias2", "'3'")
         .isKeyPredicate(3, "KeyAlias3", "'4'");
 
-    testUri.runEx("ESTwoPrim(wrong)").isExSemantic(MessageKeys.INVALID_KEY_VALUE);
-    testUri.runEx("ESTwoPrim(PropertyInt16=wrong)").isExSemantic(MessageKeys.INVALID_KEY_VALUE);
+    testUri.runEx("ESTwoPrim('wrong')").isExSemantic(MessageKeys.INVALID_KEY_VALUE);
+    testUri.runEx("ESTwoPrim(PropertyInt16='wrong')").isExSemantic(MessageKeys.INVALID_KEY_VALUE);
   }
 
   @Test
@@ -1794,7 +1798,7 @@ public class TestFullResourcePath {
 
   @Test
   public void runEsNamePpNpRc() throws Exception {
-    // checks for using referential constrains to fill missing keys
+    // checks for using referential constraints to fill missing keys
     testUri.run("ESKeyNav(1)/NavPropertyETTwoKeyNavMany('2')").goPath()
         .first()
         .isEntitySet("ESKeyNav")
@@ -2037,7 +2041,6 @@ public class TestFullResourcePath {
 
   @Test
   public void runFunctionImpEs() throws Exception {
-    /**/
     testUri.run("FICRTESMixPrimCollCompTwoParam(ParameterInt16=1,ParameterString='2')")
         .isKind(UriInfoKind.resource).goPath()
         .first()
@@ -2805,8 +2808,8 @@ public class TestFullResourcePath {
   }
 
   @Test
-  @Ignore("$search currently not implemented")
-  public void runDuplicatedSearchExpand() throws UriParserException, UriValidationException {
+  @Ignore("$search in expand currently not implemented")
+  public void duplicatedSearchExpand() throws Exception {
     testUri.runEx("ESKeyNav", "$expand=NavPropertyETKeyNavOne($search=Test;$search=Test)")
         .isExSyntax(UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION);
   }
@@ -2931,13 +2934,8 @@ public class TestFullResourcePath {
     testUri.run("$batch")
         .isKind(UriInfoKind.batch);
 
-    testUri.run("$crossjoin(ESKeyNav)")
-        .isKind(UriInfoKind.crossjoin)
-        .isCrossJoinEntityList(Arrays.asList("ESKeyNav"));
-
     testUri.runEx("$metadata/$ref").isExSyntax(UriParserSyntaxException.MessageKeys.MUST_BE_LAST_SEGMENT);
     testUri.runEx("$batch/$ref").isExSyntax(UriParserSyntaxException.MessageKeys.MUST_BE_LAST_SEGMENT);
-    testUri.runEx("$crossjoin(ESKeyNav)/$ref").isExSyntax(UriParserSyntaxException.MessageKeys.MUST_BE_LAST_SEGMENT);
     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);
@@ -3142,7 +3140,7 @@ public class TestFullResourcePath {
   }
 
   @Test
-  public void testFilter() throws UriParserException {
+  public void filter() throws Exception {
 
     testFilter.runOnETTwoKeyNav("PropertyString")
         .is("<PropertyString>")
@@ -3684,7 +3682,7 @@ public class TestFullResourcePath {
   }
 
   @Test
-  public void testFilterProperties() throws UriParserException {
+  public void filterProperties() throws Exception {
     testFilter.runOnETAllPrim("PropertyByte mod 0")
         .is("<<PropertyByte> mod <0>>");
 
@@ -3849,7 +3847,7 @@ public class TestFullResourcePath {
   }
 
   @Test
-  public void testFilterPMethods() throws ExpressionVisitException, ODataApplicationException, UriParserException {
+  public void filterPMethods() throws Exception {
 
     testFilter.runOnETKeyNav("indexof(PropertyString,'47') eq 5")
         .is("<<indexof(<PropertyString>,<'47'>)> eq <5>>")
@@ -4465,7 +4463,7 @@ public class TestFullResourcePath {
   }
 
   @Test
-  public void runLamdbaFunctions() throws ExpressionVisitException, ODataApplicationException, UriParserException {
+  public void lambdaFunctions() throws Exception {
 
     testFilter.runOnETKeyNav("any(d:d/PropertyInt16 eq 1)")
         .is("<<ANY;<<d/PropertyInt16> eq <1>>>>")
@@ -4612,7 +4610,7 @@ public class TestFullResourcePath {
   }
 
   @Test
-  public void runIsOf() throws ExpressionVisitException, ODataApplicationException, UriParserException {
+  public void runIsOf() throws Exception {
 
     testFilter.runOnETKeyNav("isof(olingo.odata.test1.ETTwoKeyNav)")
         .is("<isof(<olingo.odata.test1.ETTwoKeyNav>)>")
@@ -4757,7 +4755,7 @@ public class TestFullResourcePath {
   }
 
   @Test
-  public void testHas() throws ExpressionVisitException, ODataApplicationException, UriParserException {
+  public void has() throws Exception {
 
     testFilter.runOnETMixEnumDefCollComp("PropertyEnumString has olingo.odata.test1.ENString'String1'")
         .is("<<PropertyEnumString> has <olingo.odata.test1.ENString<String1>>>")
@@ -5086,7 +5084,7 @@ public class TestFullResourcePath {
   }
 
   @Test
-  public void testOrderby() throws UriParserException, UnsupportedEncodingException {
+  public void orderby() throws Exception {
 
     testFilter.runOrderByOnETTwoKeyNav("olingo.odata.test1.UFCRTETAllPrimTwoParam("
         + "ParameterString=@ParamStringAlias,ParameterInt16=@ParamInt16Alias)/PropertyString eq 'SomeString'")
@@ -5429,7 +5427,7 @@ public class TestFullResourcePath {
   }
 
   @Test
-  public void testSearch() throws Exception {
+  public void search() throws Exception {
     testUri.run("ESTwoKeyNav", "$search=abc");
     testUri.run("ESTwoKeyNav", "$search=NOT abc");
 
@@ -5462,6 +5460,9 @@ public class TestFullResourcePath {
     testUri.run("ESTwoKeyNav", "$search=abc AND (def    OR  ghi)");
     testUri.run("ESTwoKeyNav", "$search=abc AND (def        ghi)");
 
+    // search in function-import return value
+    testUri.run("FICRTCollESTwoKeyNavParam(ParameterInt16=1)", "$search=test");
+
     // percent encoded characters
     testUri.run("ESTwoKeyNav", "$search=%41%42%43");
     testUri.run("ESTwoKeyNav", "$search=\"100%25\"");
@@ -5484,7 +5485,6 @@ public class TestFullResourcePath {
 
   /**
    * https://tools.oasis-open.org/version-control/browse/wsvn/odata/trunk/spec/ABNF/odata-abnf-testcases.xml
-   * @throws Exception
    */
   @Test
   public void searchQueryPhraseAbnfTestcases() throws Exception {
@@ -5568,10 +5568,10 @@ public class TestFullResourcePath {
   }
 
   @Test
-  public void testErrors() {
+  public void errors() {
     testUri.runEx("FICRTString(wrong1='ABC')/olingo.odata.test1.BFCStringRTESTwoKeyNav()")
         .isExSemantic(MessageKeys.FUNCTION_NOT_FOUND);
-    testUri.runEx("FICRTString(wrong1='ABC', wrong2=1)/olingo.odata.test1.BFCStringRTESTwoKeyNav()")
+    testUri.runEx("FICRTString(wrong1='ABC',wrong2=1)/olingo.odata.test1.BFCStringRTESTwoKeyNav()")
         .isExSemantic(MessageKeys.FUNCTION_NOT_FOUND);
 
     // type filter for entity incompatible
@@ -5620,14 +5620,14 @@ public class TestFullResourcePath {
 
     // Actions must not be followed by anything.
     testUri.runEx(ContainerProvider.AIRT_STRING + "/$value")
-        .isExValidation(UriValidationException.MessageKeys.UNALLOWED_KIND_BEFORE_VALUE);
+        .isExValidation(UriValidationException.MessageKeys.UNALLOWED_RESOURCE_PATH);
     testUri.runEx(ContainerProvider.AIRTCT_TWO_PRIM_PARAM + "/PropertyInt16")
-        .isExSemantic(MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS);
+        .isExValidation(UriValidationException.MessageKeys.UNALLOWED_RESOURCE_PATH);
     testUri.runEx("ESTwoKeyNav(PropertyInt16=1,PropertyString='2')/"
         + "olingo.odata.test1.BAETTwoKeyNavRTETTwoKeyNav/olingo.odata.test1.ETTwoKeyNav")
-        .isExSemantic(MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS);
+        .isExValidation(UriValidationException.MessageKeys.UNALLOWED_RESOURCE_PATH);
     testUri.runEx("ESTwoKeyNav/olingo.odata.test1.BAESTwoKeyNavRTESTwoKeyNav/$count")
-        .isExValidation(UriValidationException.MessageKeys.UNALLOWED_KIND_BEFORE_COUNT);
+        .isExValidation(UriValidationException.MessageKeys.UNALLOWED_RESOURCE_PATH);
   }
 
   @Test
@@ -5646,7 +5646,7 @@ public class TestFullResourcePath {
   @Test
   public void multipleKeysInResourcePath() throws Exception {
     // See OLINGO-730
-    testUri.runEx("ESAllPrim(32767)(1)(2)").isExSemantic(MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES);
+    testUri.runEx("ESAllPrim(32767)(1)(2)").isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
   }
 
   @Test
@@ -5705,9 +5705,9 @@ public class TestFullResourcePath {
 
   @Test
   public void navigationWithMoreThanOneKey() throws Exception {
-    testUri.runEx("ESKeyNav(1)/NavPropertyETTwoKeyNavMany(PropertyInt=1,PropertyString='2')"
-        + "(PropertyInt=1,PropertyString='2')")
-        .isExSemantic(MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES);
+    testUri.runEx("ESKeyNav(1)/NavPropertyETTwoKeyNavMany(PropertyInt16=1,PropertyString='2')"
+        + "(PropertyInt16=1,PropertyString='2')")
+        .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
   }
 
   @Test
@@ -5724,10 +5724,14 @@ public class TestFullResourcePath {
     testUri.runEx("FICRTETKeyNav()/SINav").isExSemantic(MessageKeys.PROPERTY_NOT_IN_TYPE);
     testUri.runEx("FICRTETKeyNav()/FICRTString()").isExSemantic(MessageKeys.PROPERTY_NOT_IN_TYPE);
     testUri.runEx("FICRTETKeyNav()/AIRTString").isExSemantic(MessageKeys.PROPERTY_NOT_IN_TYPE);
-    testUri.runEx("AIRTESAllPrimParam/ESAllPrim(0)").isExSemantic(MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS);
-    testUri.runEx("AIRTESAllPrimParam/SINav").isExSemantic(MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS);
-    testUri.runEx("AIRTESAllPrimParam/FICRTString()").isExSemantic(MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS);
-    testUri.runEx("AIRTESAllPrimParam/AIRTString").isExSemantic(MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS);
+    testUri.runEx("AIRTESAllPrimParam/ESAllPrim(0)")
+        .isExValidation(UriValidationException.MessageKeys.UNALLOWED_RESOURCE_PATH);
+    testUri.runEx("AIRTESAllPrimParam/SINav")
+        .isExValidation(UriValidationException.MessageKeys.UNALLOWED_RESOURCE_PATH);
+    testUri.runEx("AIRTESAllPrimParam/FICRTString()")
+        .isExValidation(UriValidationException.MessageKeys.UNALLOWED_RESOURCE_PATH);
+    testUri.runEx("AIRTESAllPrimParam/AIRTString")
+        .isExValidation(UriValidationException.MessageKeys.UNALLOWED_RESOURCE_PATH);
   }
 
   @Test
@@ -5737,7 +5741,7 @@ public class TestFullResourcePath {
   }
 
   @Test
-  public void testFirstResourcePathWithNamespace() {
+  public void firstResourcePathWithNamespace() {
     testUri.runEx("olingo.odata.test1.ESAllPrim").isExSemantic(MessageKeys.NAMESPACE_NOT_ALLOWED_AT_FIRST_ELEMENT);
     testUri.runEx("olingo.odata.test1.ESAllPrim(0)").isExSemantic(MessageKeys.NAMESPACE_NOT_ALLOWED_AT_FIRST_ELEMENT);
     testUri.runEx("olingo.odata.test1.FINRTInt16()").isExSemantic(MessageKeys.NAMESPACE_NOT_ALLOWED_AT_FIRST_ELEMENT);
@@ -5764,7 +5768,7 @@ public class TestFullResourcePath {
     Mockito.when(entityType.getFullQualifiedName()).thenReturn(nameETNavProp);
     Mockito.when(entityType.getKeyPredicateNames()).thenReturn(Collections.singletonList(keyPropertyName));
     Mockito.when(entityType.getKeyPropertyRefs()).thenReturn(Collections.singletonList(keyPropertyRef));
-    Mockito.when(entityType.getProperty(entitySetName)).thenReturn(navProperty);
+    Mockito.when(entityType.getNavigationProperty(entitySetName)).thenReturn(navProperty);
     Mockito.when(navProperty.getType()).thenReturn(entityType);
     EdmEntitySet entitySet = Mockito.mock(EdmEntitySet.class);
     Mockito.when(entitySet.getName()).thenReturn(entitySetName);
@@ -5772,7 +5776,7 @@ public class TestFullResourcePath {
     EdmEntityContainer container = Mockito.mock(EdmEntityContainer.class);
     Mockito.when(container.getEntitySet(entitySetName)).thenReturn(entitySet);
     Edm mockedEdm = Mockito.mock(Edm.class);
-    Mockito.when(mockedEdm.getEntityContainer(null)).thenReturn(container);
+    Mockito.when(mockedEdm.getEntityContainer()).thenReturn(container);
     new TestUriValidator().setEdm(mockedEdm)
         .run("ESNavProp(1)/ESNavProp(2)/ESNavProp(3)/ESNavProp")
         .goPath()
@@ -5886,11 +5890,11 @@ public class TestFullResourcePath {
   @Test
   public void functionsWithComplexParameters() throws Exception {
     testUri.run("ESTwoKeyNav/olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
-        + "(ParameterComp=@p1)", "@p1={\"PropertyInt16\":1,\"ProperyString\":\"1\"}")
+        + "(ParameterComp=@p1)", "@p1={\"PropertyInt16\":1,\"PropertyString\":\"1\"}")
         .goPath()
         .at(0).isEntitySet("ESTwoKeyNav")
         .at(1).isFunction("BFCESTwoKeyNavRTStringParam").isParameterAlias(0, "ParameterComp", "@p1")
-        .isInAliasToValueMap("@p1", "{\"PropertyInt16\":1,\"ProperyString\":\"1\"}");
+        .isInAliasToValueMap("@p1", "{\"PropertyInt16\":1,\"PropertyString\":\"1\"}");
 
     // Test JSON String lexer rule =\"3,Int16=abc},\\\nabc&test%test\b\f\r\t\u0022\\}\\{\\)\\(\\]\\[}
     final String stringValueEncoded = "=\\\"3,Int16=abc},\\\\\\nabc%26test%25test\\b\\f\\r\\t\\u0022\\\\}\\\\{\\\\)"
@@ -5899,11 +5903,11 @@ public class TestFullResourcePath {
         + "\\\\(\\\\]\\\\[}";
 
     testUri.run("ESTwoKeyNav/olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
-        + "(ParameterComp=@p1)", "@p1={\"PropertyInt16\":1,\"ProperyString\":\"" + stringValueEncoded + "\"}")
+        + "(ParameterComp=@p1)", "@p1={\"PropertyInt16\":1,\"PropertyString\":\"" + stringValueEncoded + "\"}")
         .goPath()
         .at(0).isEntitySet("ESTwoKeyNav")
         .at(1).isFunction("BFCESTwoKeyNavRTStringParam").isParameterAlias(0, "ParameterComp", "@p1")
-        .isInAliasToValueMap("@p1", "{\"PropertyInt16\":1,\"ProperyString\":\"" + stringValueDecoded + "\"}");
+        .isInAliasToValueMap("@p1", "{\"PropertyInt16\":1,\"PropertyString\":\"" + stringValueDecoded + "\"}");
 
     testUri.run("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
         + "(ParameterComp={\"PropertyString\":\"Test\",\"PropertyInt16\":1}) eq 'Test'")
@@ -5916,24 +5920,24 @@ public class TestFullResourcePath {
         .isParameterText(0, "{\"PropertyString\":\"" + stringValueDecoded + "\",\"PropertyInt16\":1}");
 
     testUri.run("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
-        + "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":1,\"ProperyString\":\"1\"}");
+        + "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":1,\"PropertyString\":\"1\"}");
 
     testUri.run("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
-        + "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":1,\"ProperyString\":null}")
+        + "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":1,\"PropertyString\":null}")
         .goFilter().left().isParameterText(0, null);
 
     testUri.run("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
         + "(ParameterComp=@p1) eq 0&@p1={}");
 
     testUri.run("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
-        + "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":[1,2,3],\"ProperyString\":\"1\"}");
+        + "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":[1,2,3],\"PropertyString\":\"1\"}");
 
     testUri.run("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
-        + "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":[\"1\",\"2\",\"3\"],\"ProperyString\":\"1\"}");
+        + "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":[\"1\",\"2\",\"3\"],\"PropertyString\":\"1\"}");
 
     testUri.run("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
         + "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":[{\"Prop1\":123,\"Prop2\":\"Test\",\"Prop3\":[1,2,3]},"
-        + "{\"Prop1\":{\"Prop1\":[\"Prop\\\":{]\"]}}],\"ProperyString\":\"1\"}");
+        + "{\"Prop1\":{\"Prop1\":[\"Prop\\\":{]\"]}}],\"PropertyString\":\"1\"}");
 
     testUri.run("FINRTByteNineParam(ParameterEnum=null,ParameterDef='x',ParameterComp=@c,"
         + "ParameterETTwoPrim=@c,CollParameterByte=@e,CollParameterEnum=@e,CollParameterDef=@e,"
@@ -5941,12 +5945,12 @@ public class TestFullResourcePath {
         "@c={}&@e=[]");
 
     testUri.runEx("ESTwoKeyNav/olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
-        + "(ParameterComp=@p1)", "@p1={\"PropertyInt16\":1,\"ProperyString\":'1'}")
+        + "(ParameterComp=@p1)", "@p1={\"PropertyInt16\":1,\"PropertyString\":'1'}")
         .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
 
     testUri.runEx("ESTwoKeyNav/olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
         + "(ParameterComp={\"PropertyInt16\":1,\"PropertyString\":\"Test\"})")
-        .isExSemantic(UriParserSemanticException.MessageKeys.COMPLEX_PARAMETER_IN_RESOURCE_PATH);
+        .isExSemantic(UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE);
 
     testUri.runEx("FICRTCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=null)")
         .isExValidation(UriValidationException.MessageKeys.MISSING_PARAMETER);
@@ -5959,7 +5963,7 @@ public class TestFullResourcePath {
 
     testUri.run("FICRTCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test)", "@test='null'");
 
-    testUri.runEx("FICRTCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test, UnknownParam=1)", "@test='null'")
+    testUri.runEx("FICRTCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test,UnknownParam=1)", "@test='null'")
         .isExSemantic(UriParserSemanticException.MessageKeys.FUNCTION_NOT_FOUND);
 
     testUri.run("FICRTCollCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test)", "@test='null'");
@@ -5974,23 +5978,23 @@ public class TestFullResourcePath {
         .isExSemantic(UriParserSemanticException.MessageKeys.FUNCTION_IMPORT_NOT_ALLOWED);
 
     testUri.runEx("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
-        + "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":1,\"ProperyString\":\"1\"")
+        + "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":1,\"PropertyString\":\"1\"")
         .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
 
     testUri.runEx("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
-        + "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":1,\"ProperyString\":\"1\"}}")
+        + "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":1,\"PropertyString\":\"1\"}}")
         .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
 
     testUri.runEx("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
-        + "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":[1,2,3]],\"ProperyString\":\"1\"}")
+        + "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":[1,2,3]],\"PropertyString\":\"1\"}")
         .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
 
     testUri.runEx("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
-        + "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":[1,2,3,\"ProperyString\":\"1\"}")
+        + "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":[1,2,3,\"PropertyString\":\"1\"}")
         .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
 
     testUri.runEx("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
-        + "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":[1,2,3},\"ProperyString\":\"1\"}")
+        + "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":[1,2,3},\"PropertyString\":\"1\"}")
         .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
   }
 


[13/30] olingo-odata4 git commit: [OLINGO-834] ExpressionParser uses UriTokenizer

Posted by ch...@apache.org.
[OLINGO-834] ExpressionParser uses UriTokenizer

Signed-off-by: Christian Amend <ch...@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/2f3bc286
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/2f3bc286
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/2f3bc286

Branch: refs/heads/master
Commit: 2f3bc2866befb2f8f75a81ecb4952950dc3913df
Parents: 208f26c
Author: Klaus Straubinger <kl...@sap.com>
Authored: Fri Dec 11 16:48:38 2015 +0100
Committer: Christian Amend <ch...@sap.com>
Committed: Mon Dec 14 10:12:22 2015 +0100

----------------------------------------------------------------------
 .../core/uri/parser/ExpressionParser.java       | 499 +++++++------------
 .../olingo/server/core/uri/parser/Parser.java   |   8 +
 .../server/core/uri/parser/ParserHelper.java    |  65 +++
 .../core/uri/parser/ResourcePathParser.java     | 130 +++--
 .../server/core/uri/parser/SelectParser.java    |  15 +-
 .../server/core/uri/parser/UriTokenizer.java    | 291 ++++++++++-
 .../uri/queryoption/expression/UnaryImpl.java   |   2 +-
 .../core/uri/parser/ExpressionParserTest.java   | 174 +++----
 .../core/uri/parser/UriTokenizerTest.java       | 313 +++++++-----
 9 files changed, 841 insertions(+), 656 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2f3bc286/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java
index 854536d..3b04089 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java
@@ -32,6 +32,7 @@ import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
 import org.apache.olingo.server.api.uri.queryoption.expression.Method;
 import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind;
 import org.apache.olingo.server.api.uri.queryoption.expression.UnaryOperatorKind;
+import org.apache.olingo.server.core.uri.parser.UriTokenizer.TokenKind;
 import org.apache.olingo.server.core.uri.queryoption.expression.AliasImpl;
 import org.apache.olingo.server.core.uri.queryoption.expression.BinaryImpl;
 import org.apache.olingo.server.core.uri.queryoption.expression.LiteralImpl;
@@ -39,75 +40,73 @@ import org.apache.olingo.server.core.uri.queryoption.expression.MethodImpl;
 import org.apache.olingo.server.core.uri.queryoption.expression.UnaryImpl;
 
 public class ExpressionParser {
-  private Tokenizer tokenizer;
-
   private static final Map<TokenKind, BinaryOperatorKind> tokenToBinaryOperator;
   static {
-    Map<TokenKind, BinaryOperatorKind> temp = new HashMap<ExpressionParser.TokenKind, BinaryOperatorKind>();
-    temp.put(TokenKind.OR_OP, BinaryOperatorKind.OR);
-    temp.put(TokenKind.AND_OP, BinaryOperatorKind.AND);
+    Map<TokenKind, BinaryOperatorKind> temp = new HashMap<TokenKind, BinaryOperatorKind>();
+    temp.put(TokenKind.OrOperator, BinaryOperatorKind.OR);
+    temp.put(TokenKind.AndOperator, BinaryOperatorKind.AND);
 
-    temp.put(TokenKind.EQ_OP, BinaryOperatorKind.EQ);
-    temp.put(TokenKind.NE_OP, BinaryOperatorKind.NE);
+    temp.put(TokenKind.EqualsOperator, BinaryOperatorKind.EQ);
+    temp.put(TokenKind.NotEqualsOperator, BinaryOperatorKind.NE);
 
-    temp.put(TokenKind.GT_OP, BinaryOperatorKind.GT);
-    temp.put(TokenKind.GE_OP, BinaryOperatorKind.GE);
-    temp.put(TokenKind.LT_OP, BinaryOperatorKind.LT);
-    temp.put(TokenKind.LE_OP, BinaryOperatorKind.LE);
+    temp.put(TokenKind.GreaterThanOperator, BinaryOperatorKind.GT);
+    temp.put(TokenKind.GreaterThanOrEqualsOperator, BinaryOperatorKind.GE);
+    temp.put(TokenKind.LessThanOperator, BinaryOperatorKind.LT);
+    temp.put(TokenKind.LessThanOrEqualsOperator, BinaryOperatorKind.LE);
 
-    temp.put(TokenKind.ADD_OP, BinaryOperatorKind.ADD);
-    temp.put(TokenKind.SUB_OP, BinaryOperatorKind.SUB);
+    temp.put(TokenKind.AddOperator, BinaryOperatorKind.ADD);
+    temp.put(TokenKind.SubOperator, BinaryOperatorKind.SUB);
 
-    temp.put(TokenKind.MUL_OP, BinaryOperatorKind.MUL);
-    temp.put(TokenKind.DIV_OP, BinaryOperatorKind.DIV);
-    temp.put(TokenKind.MOD_OP, BinaryOperatorKind.MOD);
+    temp.put(TokenKind.MulOperator, BinaryOperatorKind.MUL);
+    temp.put(TokenKind.DivOperator, BinaryOperatorKind.DIV);
+    temp.put(TokenKind.ModOperator, BinaryOperatorKind.MOD);
 
     tokenToBinaryOperator = Collections.unmodifiableMap(temp);
   }
 
   private static final Map<TokenKind, UnaryOperatorKind> tokenToUnaryOperator;
   static {
-    Map<TokenKind, UnaryOperatorKind> temp = new HashMap<ExpressionParser.TokenKind, UnaryOperatorKind>();
+    Map<TokenKind, UnaryOperatorKind> temp = new HashMap<TokenKind, UnaryOperatorKind>();
     temp.put(TokenKind.MINUS, UnaryOperatorKind.MINUS);
-    temp.put(TokenKind.NOT, UnaryOperatorKind.NOT);
+    temp.put(TokenKind.NotOperator, UnaryOperatorKind.NOT);
     tokenToUnaryOperator = Collections.unmodifiableMap(temp);
   }
 
   private static final Map<TokenKind, MethodKind> tokenToMethod;
   static {
-    Map<TokenKind, MethodKind> temp = new HashMap<ExpressionParser.TokenKind, MethodKind>();
-    temp.put(TokenKind.Cast, MethodKind.CAST);
-    temp.put(TokenKind.Ceiling, MethodKind.CEILING);
-    temp.put(TokenKind.Concat, MethodKind.CONCAT);
-    temp.put(TokenKind.Contains, MethodKind.CONTAINS);
-    temp.put(TokenKind.Date, MethodKind.DATE);
-    temp.put(TokenKind.Day, MethodKind.DAY);
-    temp.put(TokenKind.Endswith, MethodKind.ENDSWITH);
-    temp.put(TokenKind.Floor, MethodKind.FLOOR);
-    temp.put(TokenKind.Fractionalseconds, MethodKind.FRACTIONALSECONDS);
-    temp.put(TokenKind.GeoDistance, MethodKind.GEODISTANCE);
-    temp.put(TokenKind.GeoIntersects, MethodKind.GEOINTERSECTS);
-    temp.put(TokenKind.GeoLength, MethodKind.GEOLENGTH);
-    temp.put(TokenKind.Hour, MethodKind.HOUR);
-    temp.put(TokenKind.Indexof, MethodKind.INDEXOF);
-    temp.put(TokenKind.Isof, MethodKind.ISOF);
-    temp.put(TokenKind.Length, MethodKind.LENGTH);
-    temp.put(TokenKind.Maxdatetime, MethodKind.MAXDATETIME);
-    temp.put(TokenKind.Mindatetime, MethodKind.MINDATETIME);
-    temp.put(TokenKind.Minute, MethodKind.MINUTE);
-    temp.put(TokenKind.Month, MethodKind.MONTH);
-    temp.put(TokenKind.Now, MethodKind.NOW);
-    temp.put(TokenKind.Round, MethodKind.ROUND);
-    temp.put(TokenKind.Second, MethodKind.SECOND);
-    temp.put(TokenKind.Startswith, MethodKind.STARTSWITH);
-    temp.put(TokenKind.Substring, MethodKind.SUBSTRING);
-    temp.put(TokenKind.Time, MethodKind.TIME);
-    temp.put(TokenKind.Tolower, MethodKind.TOLOWER);
-    temp.put(TokenKind.Totaloffsetminutes, MethodKind.TOTALOFFSETMINUTES);
-    temp.put(TokenKind.Totalseconds, MethodKind.TOTALSECONDS);
-    temp.put(TokenKind.Toupper, MethodKind.TOUPPER);
-    temp.put(TokenKind.Trim, MethodKind.TRIM);
-    temp.put(TokenKind.Year, MethodKind.YEAR);
+    Map<TokenKind, MethodKind> temp = new HashMap<TokenKind, MethodKind>();
+    temp.put(TokenKind.CastMethod, MethodKind.CAST);
+    temp.put(TokenKind.CeilingMethod, MethodKind.CEILING);
+    temp.put(TokenKind.ConcatMethod, MethodKind.CONCAT);
+    temp.put(TokenKind.ContainsMethod, MethodKind.CONTAINS);
+    temp.put(TokenKind.DateMethod, MethodKind.DATE);
+    temp.put(TokenKind.DayMethod, MethodKind.DAY);
+    temp.put(TokenKind.EndswithMethod, MethodKind.ENDSWITH);
+    temp.put(TokenKind.FloorMethod, MethodKind.FLOOR);
+    temp.put(TokenKind.FractionalsecondsMethod, MethodKind.FRACTIONALSECONDS);
+    temp.put(TokenKind.GeoDistanceMethod, MethodKind.GEODISTANCE);
+    temp.put(TokenKind.GeoIntersectsMethod, MethodKind.GEOINTERSECTS);
+    temp.put(TokenKind.GeoLengthMethod, MethodKind.GEOLENGTH);
+    temp.put(TokenKind.HourMethod, MethodKind.HOUR);
+    temp.put(TokenKind.IndexofMethod, MethodKind.INDEXOF);
+    temp.put(TokenKind.IsofMethod, MethodKind.ISOF);
+    temp.put(TokenKind.LengthMethod, MethodKind.LENGTH);
+    temp.put(TokenKind.MaxdatetimeMethod, MethodKind.MAXDATETIME);
+    temp.put(TokenKind.MindatetimeMethod, MethodKind.MINDATETIME);
+    temp.put(TokenKind.MinuteMethod, MethodKind.MINUTE);
+    temp.put(TokenKind.MonthMethod, MethodKind.MONTH);
+    temp.put(TokenKind.NowMethod, MethodKind.NOW);
+    temp.put(TokenKind.RoundMethod, MethodKind.ROUND);
+    temp.put(TokenKind.SecondMethod, MethodKind.SECOND);
+    temp.put(TokenKind.StartswithMethod, MethodKind.STARTSWITH);
+    temp.put(TokenKind.SubstringMethod, MethodKind.SUBSTRING);
+    temp.put(TokenKind.TimeMethod, MethodKind.TIME);
+    temp.put(TokenKind.TolowerMethod, MethodKind.TOLOWER);
+    temp.put(TokenKind.TotaloffsetminutesMethod, MethodKind.TOTALOFFSETMINUTES);
+    temp.put(TokenKind.TotalsecondsMethod, MethodKind.TOTALSECONDS);
+    temp.put(TokenKind.ToupperMethod, MethodKind.TOUPPER);
+    temp.put(TokenKind.TrimMethod, MethodKind.TRIM);
+    temp.put(TokenKind.YearMethod, MethodKind.YEAR);
 
     tokenToMethod = Collections.unmodifiableMap(temp);
   }
@@ -115,24 +114,26 @@ public class ExpressionParser {
   private static final Map<TokenKind, EdmPrimitiveTypeKind> tokenToPrimitiveType;
   static {
     /* Enum and null are not present in the map. These have to be handled differently */
-    Map<TokenKind, EdmPrimitiveTypeKind> temp = new HashMap<ExpressionParser.TokenKind, EdmPrimitiveTypeKind>();
-    temp.put(TokenKind.PrimitiveBooleanValue, EdmPrimitiveTypeKind.Boolean);
-    temp.put(TokenKind.PrimitiveStringValue, EdmPrimitiveTypeKind.String);
+    Map<TokenKind, EdmPrimitiveTypeKind> temp = new HashMap<TokenKind, EdmPrimitiveTypeKind>();
+    temp.put(TokenKind.BooleanValue, EdmPrimitiveTypeKind.Boolean);
+    temp.put(TokenKind.StringValue, EdmPrimitiveTypeKind.String);
     // TODO:Check if int64 is correct here or if it has to be single instead
-    temp.put(TokenKind.PrimitiveIntegerValue, EdmPrimitiveTypeKind.Int64);
-    temp.put(TokenKind.PrimitiveGuidValue, EdmPrimitiveTypeKind.Guid);
-    temp.put(TokenKind.PrimitiveDateValue, EdmPrimitiveTypeKind.Date);
-    temp.put(TokenKind.PrimitiveDateTimeOffsetValue, EdmPrimitiveTypeKind.DateTimeOffset);
-    temp.put(TokenKind.PrimitiveTimeOfDayValue, EdmPrimitiveTypeKind.TimeOfDay);
-    temp.put(TokenKind.PrimitiveDecimalValue, EdmPrimitiveTypeKind.Decimal);
-    temp.put(TokenKind.PrimitiveDoubleValue, EdmPrimitiveTypeKind.Double);
-    temp.put(TokenKind.PrimitiveDurationValue, EdmPrimitiveTypeKind.Duration);
-    temp.put(TokenKind.PrimitiveBinaryValue, EdmPrimitiveTypeKind.Binary);
+    temp.put(TokenKind.IntegerValue, EdmPrimitiveTypeKind.Int64);
+    temp.put(TokenKind.GuidValue, EdmPrimitiveTypeKind.Guid);
+    temp.put(TokenKind.DateValue, EdmPrimitiveTypeKind.Date);
+    temp.put(TokenKind.DateTimeOffsetValue, EdmPrimitiveTypeKind.DateTimeOffset);
+    temp.put(TokenKind.TimeOfDayValue, EdmPrimitiveTypeKind.TimeOfDay);
+    temp.put(TokenKind.DecimalValue, EdmPrimitiveTypeKind.Decimal);
+    temp.put(TokenKind.DoubleValue, EdmPrimitiveTypeKind.Double);
+    temp.put(TokenKind.DurationValue, EdmPrimitiveTypeKind.Duration);
+    temp.put(TokenKind.BinaryValue, EdmPrimitiveTypeKind.Binary);
 
     tokenToPrimitiveType = Collections.unmodifiableMap(temp);
   }
 
-  public Expression parse(Tokenizer tokenizer) throws UriParserException {
+  private UriTokenizer tokenizer;
+
+  public Expression parse(UriTokenizer tokenizer) throws UriParserException {
     // Initialize tokenizer.
     this.tokenizer = tokenizer;
 
@@ -141,23 +142,17 @@ public class ExpressionParser {
 
   private Expression parseExpression() throws UriParserException {
     Expression left = parseAnd();
-
-    while (is(TokenKind.OR_OP) != null) {
-      tokenizer.getText();
-
-      Expression right = parseAnd();
+    while (tokenizer.next(TokenKind.OrOperator)) {
+      final Expression right = parseAnd();
       left = new BinaryImpl(left, BinaryOperatorKind.OR, right);
     }
-
     return left;
   }
 
   private Expression parseAnd() throws UriParserException {
     Expression left = parseExprEquality();
-    while (is(TokenKind.AND_OP) != null) {
-      tokenizer.getText();
-
-      Expression right = parseExprEquality();
+    while (tokenizer.next(TokenKind.AndOperator)) {
+      final Expression right = parseExprEquality();
       left = new BinaryImpl(left, BinaryOperatorKind.AND, right);
     }
     return left;
@@ -165,110 +160,107 @@ public class ExpressionParser {
 
   private Expression parseExprEquality() throws UriParserException {
     Expression left = parseExprRel();
-
-    TokenKind nextTokenKind = is(TokenKind.EQ_OP, TokenKind.NE_OP);
+    TokenKind operatorTokenKind = ParserHelper.next(tokenizer, TokenKind.EqualsOperator, TokenKind.NotEqualsOperator);
     // Null for everything other than EQ or NE
-    while (nextTokenKind != null) {
-      tokenizer.getText();
-
-      Expression right = parseExprEquality();
-      left = new BinaryImpl(left, tokenToBinaryOperator.get(nextTokenKind), right);
-      nextTokenKind = is(TokenKind.EQ_OP, TokenKind.NE_OP);
+    while (operatorTokenKind != null) {
+      final Expression right = parseExprEquality();
+      left = new BinaryImpl(left, tokenToBinaryOperator.get(operatorTokenKind), right);
+      operatorTokenKind = ParserHelper.next(tokenizer, TokenKind.EqualsOperator, TokenKind.NotEqualsOperator);
     }
-
     return left;
   }
 
   private Expression parseExprRel() throws UriParserException {
     Expression left = parseExprAdd();
-
-    TokenKind nextTokenKind = is(TokenKind.GT_OP, TokenKind.GE_OP, TokenKind.LT_OP, TokenKind.LE_OP);
+    TokenKind operatorTokenKind = ParserHelper.next(tokenizer,
+        TokenKind.GreaterThanOperator, TokenKind.GreaterThanOrEqualsOperator,
+        TokenKind.LessThanOperator, TokenKind.LessThanOrEqualsOperator);
     // Null for everything other than GT or GE or LT or LE
-    while (nextTokenKind != null) {
-      tokenizer.getText();
-
-      Expression right = parseExprAdd();
-      left = new BinaryImpl(left, tokenToBinaryOperator.get(nextTokenKind), right);
-      nextTokenKind = is(TokenKind.GT_OP, TokenKind.GE_OP, TokenKind.LT_OP, TokenKind.LE_OP);
+    while (operatorTokenKind != null) {
+      final Expression right = parseExprAdd();
+      left = new BinaryImpl(left, tokenToBinaryOperator.get(operatorTokenKind), right);
+      operatorTokenKind = ParserHelper.next(tokenizer,
+          TokenKind.GreaterThanOperator, TokenKind.GreaterThanOrEqualsOperator,
+          TokenKind.LessThanOperator, TokenKind.LessThanOrEqualsOperator);
     }
-
     return left;
   }
 
   private Expression parseExprAdd() throws UriParserException {
     Expression left = parseExprMul();
-
-    TokenKind nextTokenKind = is(TokenKind.ADD_OP, TokenKind.SUB_OP);
+    TokenKind operatorTokenKind = ParserHelper.next(tokenizer, TokenKind.AddOperator, TokenKind.SubOperator);
     // Null for everything other than ADD or SUB
-    while (nextTokenKind != null) {
-      tokenizer.getText();
-
-      Expression right = parseExprMul();
-      left = new BinaryImpl(left, tokenToBinaryOperator.get(nextTokenKind), right);
-      nextTokenKind = is(TokenKind.ADD_OP, TokenKind.SUB_OP);
+    while (operatorTokenKind != null) {
+      final Expression right = parseExprMul();
+      left = new BinaryImpl(left, tokenToBinaryOperator.get(operatorTokenKind), right);
+      operatorTokenKind = ParserHelper.next(tokenizer, TokenKind.AddOperator, TokenKind.SubOperator);
     }
-
     return left;
   }
 
   private Expression parseExprMul() throws UriParserException {
     Expression left = parseExprUnary();
-
-    TokenKind nextTokenKind = is(TokenKind.MUL_OP, TokenKind.DIV_OP, TokenKind.MOD_OP);
+    TokenKind operatorTokenKind = ParserHelper.next(tokenizer,
+        TokenKind.MulOperator, TokenKind.DivOperator, TokenKind.ModOperator);
     // Null for everything other than MUL or DIV or MOD
-    while (nextTokenKind != null) {
-      tokenizer.getText();
-
-      Expression right = parseExprUnary();
-      left = new BinaryImpl(left, tokenToBinaryOperator.get(nextTokenKind), right);
-      nextTokenKind = is(TokenKind.MUL_OP, TokenKind.DIV_OP, TokenKind.MOD_OP);
+    while (operatorTokenKind != null) {
+      final Expression right = parseExprUnary();
+      left = new BinaryImpl(left, tokenToBinaryOperator.get(operatorTokenKind), right);
+      operatorTokenKind = ParserHelper.next(tokenizer,
+          TokenKind.MulOperator, TokenKind.DivOperator, TokenKind.ModOperator);
     }
-
     return left;
   }
 
   private Expression parseExprUnary() throws UriParserException {
     Expression left = null;
-    TokenKind nextTokenKind = is(TokenKind.MINUS, TokenKind.NOT);
+    TokenKind operatorTokenKind = ParserHelper.next(tokenizer, TokenKind.MINUS, TokenKind.NotOperator);
     // Null for everything other than - or NOT
-    while (nextTokenKind != null) {
-      tokenizer.getText();
-
-      Expression exp = parseExprValue();
-      left = new UnaryImpl(tokenToUnaryOperator.get(nextTokenKind), exp);
-      nextTokenKind = is(TokenKind.MINUS, TokenKind.NOT);
+    while (operatorTokenKind != null) {
+      final Expression expression = parseExprValue();
+      left = new UnaryImpl(tokenToUnaryOperator.get(operatorTokenKind), expression);
+      operatorTokenKind = ParserHelper.next(tokenizer, TokenKind.MINUS, TokenKind.NotOperator);
     }
-
     if (left == null) {
       left = parseExprValue();
     }
-
     return left;
   }
 
   private Expression parseExprValue() throws UriParserException {
-    if (is(TokenKind.OPEN) != null) {
-      tokenizer.getText();
-      Expression exp = parseExpression();
-      require(TokenKind.CLOSE);
-      return exp;
+    if (tokenizer.next(TokenKind.OPEN)) {
+      final Expression expression = parseExpression();
+      ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
+      return expression;
     }
 
-    if (is(TokenKind.ParameterAlias) != null) {
+    if (tokenizer.next(TokenKind.ParameterAliasName)) {
       return new AliasImpl(tokenizer.getText());
     }
 
-    if (is(TokenKind.RootExpr) != null) {
-      tokenizer.getText();
-      // TODO: Consume $root Expression.
+    if (tokenizer.next(TokenKind.jsonArrayOrObject)) {
+      // TODO: Can the type be determined?
+      return new LiteralImpl(tokenizer.getText(), null);
     }
 
-    TokenKind nextPrimitive = isPrimitive();
+    if (tokenizer.next(TokenKind.ROOT)) {
+      // TODO: Consume $root expression.
+    }
+
+    if (tokenizer.next(TokenKind.IT)) {
+      // TODO: Consume $it expression.
+    }
+
+    if (tokenizer.next(TokenKind.QualifiedName)) {
+      // TODO: Consume typecast or bound-function expression.
+    }
+
+    TokenKind nextPrimitive = ParserHelper.nextPrimitive(tokenizer);
     if (nextPrimitive != null) {
-      EdmPrimitiveTypeKind primitiveTypeKind = tokenToPrimitiveType.get(nextPrimitive);
+      final EdmPrimitiveTypeKind primitiveTypeKind = tokenToPrimitiveType.get(nextPrimitive);
       EdmPrimitiveType type;
       if (primitiveTypeKind == null) {
-        if (nextPrimitive == TokenKind.PrimitiveEnumValue) {
+        if (nextPrimitive == TokenKind.EnumValue) {
           // TODO: Get enum type.
           type = null;
         } else {
@@ -281,22 +273,16 @@ public class ExpressionParser {
       return new LiteralImpl(tokenizer.getText(), type);
     }
 
-    TokenKind nextMethod = isMethod();
+    TokenKind nextMethod = nextMethod();
     if (nextMethod != null) {
       MethodKind methodKind = tokenToMethod.get(nextMethod);
       List<Expression> parameters = new ArrayList<Expression>();
-      // Consume Method name.
-      tokenizer.getText();
-      if (is(TokenKind.CLOSE) != null) {
-        // Consume closing parenthesis.
-        tokenizer.getText();
-      } else {
-        parameters.add(parseExpression());
-        while (is(TokenKind.COMMA) != null) {
-          tokenizer.getText();
+      // The method token text includes the opening parenthesis!
+      if (!tokenizer.next(TokenKind.CLOSE)) {
+        do {
           parameters.add(parseExpression());
-        }
-        require(TokenKind.CLOSE);
+        } while (tokenizer.next(TokenKind.COMMA));
+        ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
       }
 
       MethodImpl methodImpl = new MethodImpl(methodKind, parameters);
@@ -305,6 +291,10 @@ public class ExpressionParser {
       return methodImpl;
     }
 
+    if (tokenizer.next(TokenKind.ODataIdentifier)) {
+      // TODO: Consume property-path or lambda-variable expression.
+    }
+
     throw new UriParserSyntaxException("Unexpected token", UriParserSyntaxException.MessageKeys.SYNTAX);
   }
 
@@ -356,7 +346,7 @@ public class ExpressionParser {
     case NOW:
     case MAXDATETIME:
     case MINDATETIME:
-      if (size != 0) {
+      if (size > 0) {
         throw new UriParserSemanticException("The method '" + method.getMethod() + "' must have no parameters.",
             null); // TODO: message key
       }
@@ -384,192 +374,39 @@ public class ExpressionParser {
     }
   }
 
-  private String require(TokenKind required) throws UriParserException {
-    if (is(required) == null) {
-      throw new UriParserSyntaxException("Required token: " + required,
-          UriParserSyntaxException.MessageKeys.SYNTAX);
-    }
-    return tokenizer.getText();
-  }
-
-  private TokenKind is(TokenKind... kind) {
-    for (int i = 0; i < kind.length; i++) {
-      if (tokenizer.next(kind[i])) {
-        return kind[i];
-      }
-    }
-    return null;
-  }
-
-  private TokenKind isMethod() {
-    return is(TokenKind.Cast,
-        TokenKind.Ceiling,
-        TokenKind.Concat,
-        TokenKind.Contains,
-        TokenKind.Date,
-        TokenKind.Day,
-        TokenKind.Endswith,
-        TokenKind.Floor,
-        TokenKind.Fractionalseconds,
-        TokenKind.GeoDistance,
-        TokenKind.GeoIntersects,
-        TokenKind.GeoLength,
-        TokenKind.Hour,
-        TokenKind.Indexof,
-        TokenKind.Isof,
-        TokenKind.Length,
-        TokenKind.Maxdatetime,
-        TokenKind.Mindatetime,
-        TokenKind.Minute,
-        TokenKind.Month,
-        TokenKind.Now,
-        TokenKind.Round,
-        TokenKind.Second,
-        TokenKind.Startswith,
-        TokenKind.Substring,
-        TokenKind.Time,
-        TokenKind.Tolower,
-        TokenKind.Totaloffsetminutes,
-        TokenKind.Totalseconds,
-        TokenKind.Toupper,
-        TokenKind.Trim,
-        TokenKind.Year);
-  }
-
-  private TokenKind isPrimitive() {
-    return is(TokenKind.PrimitiveNullValue,
-        TokenKind.PrimitiveBooleanValue,
-        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 ...).
-        TokenKind.PrimitiveDoubleValue,
-        TokenKind.PrimitiveDecimalValue,
-        TokenKind.PrimitiveGuidValue,
-        TokenKind.PrimitiveDateTimeOffsetValue,
-        TokenKind.PrimitiveDateValue,
-        TokenKind.PrimitiveTimeOfDayValue,
-        TokenKind.PrimitiveIntegerValue,
-        TokenKind.PrimitiveDurationValue,
-        TokenKind.PrimitiveBinaryValue,
-        TokenKind.PrimitiveEnumValue);
-  }
-
-  public enum TokenKind {
-    // BINARY
-    OR_OP,
-    AND_OP,
-
-    EQ_OP,
-    NE_OP,
-
-    GT_OP,
-    GE_OP,
-    LT_OP,
-    LE_OP,
-
-    ADD_OP,
-    SUB_OP,
-
-    MUL_OP,
-    DIV_OP,
-    MOD_OP,
-
-    MINUS,
-    NOT,
-
-    // Grouping
-    OPEN,
-    CLOSE,
-
-    // PrimitiveValues
-    PrimitiveNullValue,
-    PrimitiveBooleanValue,
-
-    PrimitiveStringValue,
-    PrimitiveIntegerValue,
-    PrimitiveGuidValue,
-    PrimitiveDateValue,
-    PrimitiveDateTimeOffsetValue,
-    PrimitiveTimeOfDayValue,
-    PrimitiveDecimalValue,
-    PrimitiveDoubleValue,
-    PrimitiveDurationValue,
-    PrimitiveBinaryValue,
-    PrimitiveEnumValue,
-
-    // ExpressionValues
-    ParameterAlias,
-    ArrayOrObject,
-    RootExpr,
-    IT,
-
-    // BuiltInMethods
-    Cast,
-    Ceiling,
-    Concat,
-    Contains,
-    Date,
-    Day,
-    Endswith,
-    Floor,
-    Fractionalseconds,
-    GeoDistance,
-    GeoIntersects,
-    GeoLength,
-    Hour,
-    Indexof,
-    Isof,
-    Length,
-    Maxdatetime,
-    Mindatetime,
-    Minute,
-    Month,
-    Now,
-    Round,
-    Second,
-    Startswith,
-    Substring,
-    Time,
-    Tolower,
-    Totaloffsetminutes,
-    Totalseconds,
-    Toupper,
-    Trim,
-    Year,
-    COMMA
-  }
-
-  public static class Token {
-    TokenKind kind;
-    String text;
-
-    public Token(TokenKind kind, String text) {
-      this.kind = kind;
-      this.text = text;
-    }
-  }
-
-  public static class Tokenizer {
-    private List<Token> tokens;
-    int counter = 0;
-
-    public Tokenizer(List<Token> tokens) {
-      this.tokens = tokens;
-    }
-
-    public boolean next(TokenKind expectedKind) {
-      if (counter < tokens.size() && expectedKind == tokens.get(counter).kind) {
-        return true;
-      }
-      return false;
-    }
-
-    public String getText() {
-      String text = tokens.get(counter).text;
-      counter++;
-      return text;
-    }
+  private TokenKind nextMethod() {
+    return ParserHelper.next(tokenizer,
+        TokenKind.CastMethod,
+        TokenKind.CeilingMethod,
+        TokenKind.ConcatMethod,
+        TokenKind.ContainsMethod,
+        TokenKind.DateMethod,
+        TokenKind.DayMethod,
+        TokenKind.EndswithMethod,
+        TokenKind.FloorMethod,
+        TokenKind.FractionalsecondsMethod,
+        TokenKind.GeoDistanceMethod,
+        TokenKind.GeoIntersectsMethod,
+        TokenKind.GeoLengthMethod,
+        TokenKind.HourMethod,
+        TokenKind.IndexofMethod,
+        TokenKind.IsofMethod,
+        TokenKind.LengthMethod,
+        TokenKind.MaxdatetimeMethod,
+        TokenKind.MindatetimeMethod,
+        TokenKind.MinuteMethod,
+        TokenKind.MonthMethod,
+        TokenKind.NowMethod,
+        TokenKind.RoundMethod,
+        TokenKind.SecondMethod,
+        TokenKind.StartswithMethod,
+        TokenKind.SubstringMethod,
+        TokenKind.TimeMethod,
+        TokenKind.TolowerMethod,
+        TokenKind.TotaloffsetminutesMethod,
+        TokenKind.TotalsecondsMethod,
+        TokenKind.ToupperMethod,
+        TokenKind.TrimMethod,
+        TokenKind.YearMethod);
   }
-
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2f3bc286/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 0b53e69..2a994d3 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
@@ -208,6 +208,14 @@ public class Parser {
                 (UriParserException) e.getCause() :
                 new UriParserSyntaxException("Syntax error", e, UriParserSyntaxException.MessageKeys.SYNTAX);
           }
+//          UriTokenizer filterTokenizer = new UriTokenizer(optionValue);
+//          systemOption = new FilterOptionImpl().setExpression(
+//              new ExpressionParser().parse(filterTokenizer));
+//          if (!filterTokenizer.next(TokenKind.EOF)) {
+//            throw new UriParserSyntaxException("Illegal value of $filter option!",
+//                UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION,
+//                optionName, optionValue);
+//          }
 
         } else if (optionName.equals(SystemQueryOptionKind.FORMAT.toString())) {
           FormatOptionImpl formatOption = new FormatOptionImpl();

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2f3bc286/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ParserHelper.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ParserHelper.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ParserHelper.java
new file mode 100644
index 0000000..e811575
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ParserHelper.java
@@ -0,0 +1,65 @@
+/*
+ * 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 org.apache.olingo.server.core.uri.parser.UriTokenizer.TokenKind;
+
+public class ParserHelper {
+
+  public static void requireNext(UriTokenizer tokenizer, final TokenKind required) throws UriParserException {
+    if (!tokenizer.next(required)) {
+      throw new UriParserSyntaxException("Expected token '" + required.toString() + "' not found.",
+          UriParserSyntaxException.MessageKeys.SYNTAX);
+    }
+  }
+
+  public static void requireTokenEnd(UriTokenizer tokenizer) throws UriParserException {
+    requireNext(tokenizer, TokenKind.EOF);
+  }
+
+  public static TokenKind next(UriTokenizer tokenizer, final TokenKind... kind) {
+    for (int i = 0; i < kind.length; i++) {
+      if (tokenizer.next(kind[i])) {
+        return kind[i];
+      }
+    }
+    return null;
+  }
+
+  public static TokenKind nextPrimitive(UriTokenizer tokenizer) {
+    return next(tokenizer,
+        TokenKind.NULL,
+        TokenKind.BooleanValue,
+        TokenKind.StringValue,
+
+        // 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 ...).
+        TokenKind.DoubleValue,
+        TokenKind.DecimalValue,
+        TokenKind.GuidValue,
+        TokenKind.DateTimeOffsetValue,
+        TokenKind.DateValue,
+        TokenKind.TimeOfDayValue,
+        TokenKind.IntegerValue,
+
+        TokenKind.DurationValue,
+        TokenKind.BinaryValue,
+        TokenKind.EnumValue);
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2f3bc286/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
index 9852011..5d2fbde 100644
--- 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
@@ -115,9 +115,9 @@ public class ResourcePathParser {
   public UriInfoImpl parseDollarEntityTypeCast(final String pathSegment) throws UriParserException {
     UriInfoImpl uriInfo = new UriInfoImpl().setKind(UriInfoKind.entityId);
     tokenizer = new UriTokenizer(pathSegment);
-    requireNext(TokenKind.QualifiedName);
+    ParserHelper.requireNext(tokenizer, TokenKind.QualifiedName);
     final String name = tokenizer.getText();
-    requireTokenEnd();
+    ParserHelper.requireTokenEnd(tokenizer);
     final EdmEntityType type = edm.getEntityType(new FullQualifiedName(name));
     if (type == null) {
       throw new UriParserSemanticException("Type '" + name + "' not found.",
@@ -131,11 +131,11 @@ public class ResourcePathParser {
   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);
+    ParserHelper.requireNext(tokenizer, TokenKind.CROSSJOIN);
+    ParserHelper.requireNext(tokenizer, TokenKind.OPEN);
     // At least one entity-set name is mandatory.  Try to fetch all.
     do {
-      requireNext(TokenKind.ODataIdentifier);
+      ParserHelper.requireNext(tokenizer, TokenKind.ODataIdentifier);
       final String name = tokenizer.getText();
       final EdmEntitySet edmEntitySet = edmEntityContainer.getEntitySet(name);
       if (edmEntitySet == null) {
@@ -145,13 +145,13 @@ public class ResourcePathParser {
         uriInfo.addEntitySetName(name);
       }
     } while (tokenizer.next(TokenKind.COMMA));
-    requireNext(TokenKind.CLOSE);
-    requireTokenEnd();
+    ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
+    ParserHelper.requireTokenEnd(tokenizer);
     return uriInfo;
   }
 
   private UriResource ref(final UriResource previous) throws UriParserException {
-    requireTokenEnd();
+    ParserHelper.requireTokenEnd(tokenizer);
     requireTyped(previous, "$ref");
     if (((UriResourcePartTyped) previous).getType() instanceof EdmEntityType) {
       return new UriResourceRefImpl();
@@ -162,7 +162,7 @@ public class ResourcePathParser {
   }
 
   private UriResource value(final UriResource previous) throws UriParserException {
-    requireTokenEnd();
+    ParserHelper.requireTokenEnd(tokenizer);
     requireTyped(previous, "$value");
     if (!((UriResourcePartTyped) previous).isCollection()) {
       return new UriResourceValueImpl();
@@ -173,7 +173,7 @@ public class ResourcePathParser {
   }
 
   private UriResource count(final UriResource previous) throws UriParserException {
-    requireTokenEnd();
+    ParserHelper.requireTokenEnd(tokenizer);
     requireTyped(previous, "$count");
     if (((UriResourcePartTyped) previous).isCollection()) {
       return new UriResourceCountImpl();
@@ -195,19 +195,19 @@ public class ResourcePathParser {
         entitySetResource.setKeyPredicates(keyPredicates);
       }
 
-      requireTokenEnd();
+      ParserHelper.requireTokenEnd(tokenizer);
       return entitySetResource;
     }
 
     final EdmSingleton edmSingleton = edmEntityContainer.getSingleton(oDataIdentifier);
     if (edmSingleton != null) {
-      requireTokenEnd();
+      ParserHelper.requireTokenEnd(tokenizer);
       return new UriResourceSingletonImpl().setSingleton(edmSingleton);
     }
 
     final EdmActionImport edmActionImport = edmEntityContainer.getActionImport(oDataIdentifier);
     if (edmActionImport != null) {
-      requireTokenEnd();
+      ParserHelper.requireTokenEnd(tokenizer);
       return new UriResourceActionImpl().setActionImport(edmActionImport);
     }
 
@@ -271,7 +271,7 @@ public class ResourcePathParser {
             UriParserSemanticException.MessageKeys.KEY_NOT_ALLOWED);
       }
     }
-    requireTokenEnd();
+    ParserHelper.requireTokenEnd(tokenizer);
     return new UriResourceNavigationPropertyImpl()
         .setNavigationProperty(navigationProperty)
         .setKeyPredicates(keyPredicate);
@@ -288,7 +288,7 @@ public class ResourcePathParser {
           previousType.getFullQualifiedName(),
           previousTyped.isCollection());
       if (boundAction != null) {
-        requireTokenEnd();
+        ParserHelper.requireTokenEnd(tokenizer);
         return new UriResourceActionImpl().setAction(boundAction);
       }
       EdmStructuredType type = edm.getEntityType(name);
@@ -386,7 +386,7 @@ public class ResourcePathParser {
         edmProperty == null ? null : (EdmPrimitiveType) edmProperty.getType(),
         edmProperty == null ? false : edmProperty.isNullable())) {
       final String literalValue = tokenizer.getText();
-      requireNext(TokenKind.CLOSE);
+      ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
       return createUriParameter(edmProperty, edmKeyPropertyRef.getName(), literalValue);
     } else {
       throw new UriParserSemanticException("The key value is not valid.",
@@ -424,10 +424,10 @@ public class ResourcePathParser {
       parameterNames.add(keyPredicateName);
       hasComma = tokenizer.next(TokenKind.COMMA);
       if (hasComma) {
-        requireNext(TokenKind.ODataIdentifier);
+        ParserHelper.requireNext(tokenizer, TokenKind.ODataIdentifier);
       }
     } while (hasComma);
-    requireNext(TokenKind.CLOSE);
+    ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
 
     return parameters;
   }
@@ -440,7 +440,7 @@ public class ResourcePathParser {
       throw new UriValidationException(keyPredicateName + " is not a valid key property name.",
           UriValidationException.MessageKeys.INVALID_KEY_PROPERTY, keyPredicateName);
     }
-    requireNext(TokenKind.EQ);
+    ParserHelper.requireNext(tokenizer, TokenKind.EQ);
     if (tokenizer.next(TokenKind.COMMA) || tokenizer.next(TokenKind.CLOSE) || tokenizer.next(TokenKind.EOF)) {
       throw new UriParserSyntaxException("Key value expected.", UriParserSyntaxException.MessageKeys.SYNTAX);
     }
@@ -512,7 +512,7 @@ public class ResourcePathParser {
         }
         ((UriResourceTypedImpl) previousTyped).setTypeFilter(type);
       }
-      requireTokenEnd();
+      ParserHelper.requireTokenEnd(tokenizer);
       return null;
     } else {
       throw new UriParserSemanticException(
@@ -572,53 +572,42 @@ public class ResourcePathParser {
             UriParserSemanticException.MessageKeys.KEY_NOT_ALLOWED);
       }
     }
-    requireTokenEnd();
+    ParserHelper.requireTokenEnd(tokenizer);
     return resource;
   }
 
   private List<UriParameter> functionParameters() throws UriParserException {
     List<UriParameter> parameters = new ArrayList<UriParameter>();
-    requireNext(TokenKind.OPEN);
+    ParserHelper.requireNext(tokenizer, TokenKind.OPEN);
     if (tokenizer.next(TokenKind.CLOSE)) {
       return parameters;
     }
     do {
-      requireNext(TokenKind.ODataIdentifier);
+      ParserHelper.requireNext(tokenizer, 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);
+      ParserHelper.requireNext(tokenizer, 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()) {
+      if (tokenizer.next(TokenKind.ParameterAliasName)) {
+        parameters.add(new UriParameterImpl().setName(name).setAlias(tokenizer.getText()));
+      } else 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));
+        parameters.add(new UriParameterImpl().setName(name)
+            .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);
+    ParserHelper.requireNext(tokenizer, 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() :
@@ -629,64 +618,63 @@ public class ResourcePathParser {
       return true;
 
     } else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Boolean).equals(type)) {
-      return tokenizer.next(TokenKind.PrimitiveBooleanValue);
+      return tokenizer.next(TokenKind.BooleanValue);
     } else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.String).equals(type)) {
-      return tokenizer.next(TokenKind.PrimitiveStringValue);
+      return tokenizer.next(TokenKind.StringValue);
     } 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);
+      return tokenizer.next(TokenKind.IntegerValue);
     } else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Guid).equals(type)) {
-      return tokenizer.next(TokenKind.PrimitiveGuidValue);
+      return tokenizer.next(TokenKind.GuidValue);
     } else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Date).equals(type)) {
-      return tokenizer.next(TokenKind.PrimitiveDateValue);
+      return tokenizer.next(TokenKind.DateValue);
     } else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.DateTimeOffset).equals(type)) {
-      return tokenizer.next(TokenKind.PrimitiveDateTimeOffsetValue);
+      return tokenizer.next(TokenKind.DateTimeOffsetValue);
     } else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.TimeOfDay).equals(type)) {
-      return tokenizer.next(TokenKind.PrimitiveTimeOfDayValue);
+      return tokenizer.next(TokenKind.TimeOfDayValue);
     } 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);
+      return tokenizer.next(TokenKind.DecimalValue)
+          || tokenizer.next(TokenKind.IntegerValue);
     } 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);
+      return tokenizer.next(TokenKind.DoubleValue)
+          || tokenizer.next(TokenKind.DecimalValue)
+          || tokenizer.next(TokenKind.IntegerValue);
     } else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Duration).equals(type)) {
-      return tokenizer.next(TokenKind.PrimitiveDurationValue);
+      return tokenizer.next(TokenKind.DurationValue);
     } else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Binary).equals(type)) {
-      return tokenizer.next(TokenKind.PrimitiveBinaryValue);
+      return tokenizer.next(TokenKind.BinaryValue);
     } else if (type.getKind() == EdmTypeKind.ENUM) {
-      return tokenizer.next(TokenKind.PrimitiveEnumValue);
+      return tokenizer.next(TokenKind.EnumValue);
     } else {
       return false;
     }
   }
 
   private boolean nextPrimitiveValue() {
-    return tokenizer.next(TokenKind.ParameterAliasName)
-        || tokenizer.next(TokenKind.NULL)
-        || tokenizer.next(TokenKind.PrimitiveBooleanValue)
-        || tokenizer.next(TokenKind.PrimitiveStringValue)
+    return tokenizer.next(TokenKind.NULL)
+        || tokenizer.next(TokenKind.BooleanValue)
+        || tokenizer.next(TokenKind.StringValue)
 
         // 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);
+        || tokenizer.next(TokenKind.DoubleValue)
+        || tokenizer.next(TokenKind.DecimalValue)
+        || tokenizer.next(TokenKind.GuidValue)
+        || tokenizer.next(TokenKind.DateTimeOffsetValue)
+        || tokenizer.next(TokenKind.DateValue)
+        || tokenizer.next(TokenKind.TimeOfDayValue)
+        || tokenizer.next(TokenKind.IntegerValue)
+
+        || tokenizer.next(TokenKind.DurationValue)
+        || tokenizer.next(TokenKind.BinaryValue)
+        || tokenizer.next(TokenKind.EnumValue);
   }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2f3bc286/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/SelectParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/SelectParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/SelectParser.java
index 3d933d2..b257e68 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/SelectParser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/SelectParser.java
@@ -92,7 +92,7 @@ public class SelectParser {
           if (type.compatibleTo(referencedType)) {
             item.setTypeFilter(type);
             if (tokenizer.next(TokenKind.SLASH)) {
-              requireNext(tokenizer, TokenKind.ODataIdentifier);
+              ParserHelper.requireNext(tokenizer, TokenKind.ODataIdentifier);
               UriInfoImpl resource = new UriInfoImpl().setKind(UriInfoKind.resource);
               addSelectPath(tokenizer, type, resource);
               item.setResourcePath(resource);
@@ -105,7 +105,7 @@ public class SelectParser {
       }
 
     } else {
-      requireNext(tokenizer, TokenKind.ODataIdentifier);
+      ParserHelper.requireNext(tokenizer, TokenKind.ODataIdentifier);
       // The namespace or its alias could be a single OData identifier.
       final FullQualifiedName allOperationsInSchema = parseAllOperationsInSchema(tokenizer);
       if (allOperationsInSchema != null) {
@@ -167,10 +167,10 @@ public class SelectParser {
     List<String> names = new ArrayList<String>();
     if (tokenizer.next(TokenKind.OPEN)) {
       do {
-        requireNext(tokenizer, TokenKind.ODataIdentifier);
+        ParserHelper.requireNext(tokenizer, TokenKind.ODataIdentifier);
         names.add(tokenizer.getText());
       } while (tokenizer.next(TokenKind.COMMA));
-      requireNext(tokenizer, TokenKind.CLOSE);
+      ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
     }
     return names;
   }
@@ -231,11 +231,4 @@ public class SelectParser {
       }
     }
   }
-
-  private void requireNext(UriTokenizer tokenizer, final TokenKind kind) throws UriParserSyntaxException {
-    if (!tokenizer.next(kind)) {
-      throw new UriParserSyntaxException("Illegal $select expression.",
-          UriParserSyntaxException.MessageKeys.SYNTAX);
-    }
-  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2f3bc286/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java
index 8051573..a40f4ec 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java
@@ -24,6 +24,8 @@ package org.apache.olingo.server.core.uri.parser;
  * Since only the index is "moved", backing out while parsing a token is easy and used throughout.
  * There is intentionally no method to push back tokens (although it would be easy to add such a method)
  * because this tokenizer should behave like a classical token-consuming tokenizer.</p>
+ * <p>Whitespace is not an extra token but consumed with the tokens that require whitespace.
+ * Optional whitespace is not supported.</p>
  */
 public class UriTokenizer {
 
@@ -35,6 +37,9 @@ public class UriTokenizer {
     VALUE,
     COUNT,
     CROSSJOIN,
+    ROOT,
+    IT,
+
     OPEN,
     CLOSE,
     COMMA,
@@ -44,6 +49,7 @@ public class UriTokenizer {
     EQ,
     STAR,
     PLUS,
+    MINUS,
     NULL,
 
     // variable-value tokens (convention: mixed case)
@@ -51,20 +57,68 @@ public class UriTokenizer {
     QualifiedName,
     ParameterAliasName,
 
-    PrimitiveBooleanValue,
-    PrimitiveStringValue,
-    PrimitiveIntegerValue,
-    PrimitiveGuidValue,
-    PrimitiveDateValue,
-    PrimitiveDateTimeOffsetValue,
-    PrimitiveTimeOfDayValue,
-    PrimitiveDecimalValue,
-    PrimitiveDoubleValue,
-    PrimitiveDurationValue,
-    PrimitiveBinaryValue,
-    PrimitiveEnumValue,
-
-    jsonArrayOrObject
+    BooleanValue,
+    StringValue,
+    IntegerValue,
+    GuidValue,
+    DateValue,
+    DateTimeOffsetValue,
+    TimeOfDayValue,
+    DecimalValue,
+    DoubleValue,
+    DurationValue,
+    BinaryValue,
+    EnumValue,
+
+    jsonArrayOrObject,
+
+    OrOperator,
+    AndOperator,
+    EqualsOperator,
+    NotEqualsOperator,
+    GreaterThanOperator,
+    GreaterThanOrEqualsOperator,
+    LessThanOperator,
+    LessThanOrEqualsOperator,
+    AddOperator,
+    SubOperator,
+    MulOperator,
+    DivOperator,
+    ModOperator,
+    NotOperator,
+
+    CastMethod,
+    CeilingMethod,
+    ConcatMethod,
+    ContainsMethod,
+    DateMethod,
+    DayMethod,
+    EndswithMethod,
+    FloorMethod,
+    FractionalsecondsMethod,
+    GeoDistanceMethod,
+    GeoIntersectsMethod,
+    GeoLengthMethod,
+    HourMethod,
+    IndexofMethod,
+    IsofMethod,
+    LengthMethod,
+    MaxdatetimeMethod,
+    MindatetimeMethod,
+    MinuteMethod,
+    MonthMethod,
+    NowMethod,
+    RoundMethod,
+    SecondMethod,
+    StartswithMethod,
+    SubstringMethod,
+    TimeMethod,
+    TolowerMethod,
+    TotaloffsetminutesMethod,
+    TotalsecondsMethod,
+    ToupperMethod,
+    TrimMethod,
+    YearMethod
   }
 
   private final String parseString;
@@ -111,6 +165,13 @@ public class UriTokenizer {
     case CROSSJOIN:
       found = nextConstant("$crossjoin");
       break;
+    case ROOT:
+      found = nextConstant("$root");
+      break;
+    case IT:
+      found = nextConstant("$it");
+      break;
+
     case OPEN:
       found = nextCharacter('(');
       break;
@@ -138,6 +199,9 @@ public class UriTokenizer {
     case PLUS:
       found = nextCharacter('+');
       break;
+    case MINUS:
+      found = nextCharacter('-');
+      break;
     case NULL:
       found = nextConstant("null");
       break;
@@ -157,47 +221,189 @@ public class UriTokenizer {
       break;
 
     // Primitive Values
-    case PrimitiveBooleanValue:
+    case BooleanValue:
       found = nextBooleanValue();
       break;
-    case PrimitiveStringValue:
+    case StringValue:
       found = nextStringValue();
       break;
-    case PrimitiveIntegerValue:
+    case IntegerValue:
       found = nextIntegerValue(true);
       break;
-    case PrimitiveGuidValue:
+    case GuidValue:
       found = nextGuidValue();
       break;
-    case PrimitiveDateValue:
+    case DateValue:
       found = nextDateValue();
       break;
-    case PrimitiveDateTimeOffsetValue:
+    case DateTimeOffsetValue:
       found = nextDateTimeOffsetValue();
       break;
-    case PrimitiveTimeOfDayValue:
+    case TimeOfDayValue:
       found = nextTimeOfDayValue();
       break;
-    case PrimitiveDecimalValue:
+    case DecimalValue:
       found = nextDecimalValue();
       break;
-    case PrimitiveDoubleValue:
+    case DoubleValue:
       found = nextDoubleValue();
       break;
-    case PrimitiveDurationValue:
+    case DurationValue:
       found = nextDurationValue();
       break;
-    case PrimitiveBinaryValue:
+    case BinaryValue:
       found = nextBinaryValue();
       break;
-    case PrimitiveEnumValue:
+    case EnumValue:
       found = nextEnumValue();
       break;
 
-    // Primitive Values
+    // Complex or Collection Value
     case jsonArrayOrObject:
       found = nextJsonArrayOrObject();
       break;
+
+    // Operators
+    case OrOperator:
+      found = nextBinaryOperator("or");
+      break;
+    case AndOperator:
+      found = nextBinaryOperator("and");
+      break;
+    case EqualsOperator:
+      found = nextBinaryOperator("eq");
+      break;
+    case NotEqualsOperator:
+      found = nextBinaryOperator("ne");
+      break;
+    case GreaterThanOperator:
+      found = nextBinaryOperator("gt");
+      break;
+    case GreaterThanOrEqualsOperator:
+      found = nextBinaryOperator("ge");
+      break;
+    case LessThanOperator:
+      found = nextBinaryOperator("lt");
+      break;
+    case LessThanOrEqualsOperator:
+      found = nextBinaryOperator("le");
+      break;
+    case AddOperator:
+      found = nextBinaryOperator("add");
+      break;
+    case SubOperator:
+      found = nextBinaryOperator("sub");
+      break;
+    case MulOperator:
+      found = nextBinaryOperator("mul");
+      break;
+    case DivOperator:
+      found = nextBinaryOperator("div");
+      break;
+    case ModOperator:
+      found = nextBinaryOperator("mod");
+      break;
+    case NotOperator:
+      found = nextConstant("not") && nextWhitespace();
+      break;
+
+    // Methods
+    case CastMethod:
+      found = nextMethod("cast");
+      break;
+    case CeilingMethod:
+      found = nextMethod("ceiling");
+      break;
+    case ConcatMethod:
+      found = nextMethod("concat");
+      break;
+    case ContainsMethod:
+      found = nextMethod("contains");
+      break;
+    case DateMethod:
+      found = nextMethod("date");
+      break;
+    case DayMethod:
+      found = nextMethod("day");
+      break;
+    case EndswithMethod:
+      found = nextMethod("endswith");
+      break;
+    case FloorMethod:
+      found = nextMethod("floor");
+      break;
+    case FractionalsecondsMethod:
+      found = nextMethod("fractionalseconds");
+      break;
+    case GeoDistanceMethod:
+      found = nextMethod("geo.distance");
+      break;
+    case GeoIntersectsMethod:
+      found = nextMethod("geo.intersects");
+      break;
+    case GeoLengthMethod:
+      found = nextMethod("geo.length");
+      break;
+    case HourMethod:
+      found = nextMethod("hour");
+      break;
+    case IndexofMethod:
+      found = nextMethod("indexof");
+      break;
+    case IsofMethod:
+      found = nextMethod("isof");
+      break;
+    case LengthMethod:
+      found = nextMethod("length");
+      break;
+    case MaxdatetimeMethod:
+      found = nextMethod("maxdatetime");
+      break;
+    case MindatetimeMethod:
+      found = nextMethod("mindatetime");
+      break;
+    case MinuteMethod:
+      found = nextMethod("minute");
+      break;
+    case MonthMethod:
+      found = nextMethod("month");
+      break;
+    case NowMethod:
+      found = nextMethod("now");
+      break;
+    case RoundMethod:
+      found = nextMethod("round");
+      break;
+    case SecondMethod:
+      found = nextMethod("second");
+      break;
+    case StartswithMethod:
+      found = nextMethod("startswith");
+      break;
+    case SubstringMethod:
+      found = nextMethod("substring");
+      break;
+    case TimeMethod:
+      found = nextMethod("time");
+      break;
+    case TolowerMethod:
+      found = nextMethod("tolower");
+      break;
+    case TotaloffsetminutesMethod:
+      found = nextMethod("totaloffsetminutes");
+      break;
+    case TotalsecondsMethod:
+      found = nextMethod("totalseconds");
+      break;
+    case ToupperMethod:
+      found = nextMethod("toupper");
+      break;
+    case TrimMethod:
+      found = nextMethod("trim");
+      break;
+    case YearMethod:
+      found = nextMethod("year");
+      break;
     }
 
     if (found) {
@@ -301,6 +507,37 @@ public class UriTokenizer {
   }
 
   /**
+   * Moves past whitespace (space or horizontal tabulator) characters if found;
+   * otherwise leaves the index unchanged.
+   * @return whether whitespace characters have been found at the current index
+   */
+  private boolean nextWhitespace() {
+    int count = 0;
+    while (nextCharacter(' ') || nextCharacter('\t')) {
+      count++;
+    }
+    return count > 0;
+  }
+
+  /**
+   * Moves past the given whitespace-surrounded operator constant if found;
+   * otherwise leaves the index unchanged.
+   * @return whether the operator has been found at the current index
+   */
+  private boolean nextBinaryOperator(final String operator) {
+    return nextWhitespace() && nextConstant(operator) && nextWhitespace();
+  }
+
+  /**
+   * Moves past the given method name and its immediately following opening parenthesis if found;
+   * otherwise leaves the index unchanged.
+   * @return whether the method has been found at the current index
+   */
+  private boolean nextMethod(final String methodName) {
+    return nextConstant(methodName) && nextCharacter('(');
+  }
+
+  /**
    * Moves past an OData identifier if found; otherwise leaves the index unchanged.
    * @return whether an OData identifier has been found at the current index
    */

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2f3bc286/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/UnaryImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/UnaryImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/UnaryImpl.java
index 2438d27..910997e 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/UnaryImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/UnaryImpl.java
@@ -53,6 +53,6 @@ public class UnaryImpl implements Unary {
 
   @Override
   public String toString() {
-    return "{" + operator + " " + expression + '}';
+    return "{" + operator.name() + " " + expression + '}';
   }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2f3bc286/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java
index 7da823e..58f2a1f 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java
@@ -20,191 +20,157 @@ package org.apache.olingo.server.core.uri.parser;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
-import java.util.ArrayList;
+import java.util.Locale;
 
 import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
-import org.apache.olingo.server.core.uri.parser.ExpressionParser.Token;
-import org.apache.olingo.server.core.uri.parser.ExpressionParser.TokenKind;
-import org.apache.olingo.server.core.uri.parser.ExpressionParser.Tokenizer;
+import org.apache.olingo.server.core.uri.parser.UriTokenizer.TokenKind;
 import org.junit.Test;
 
 public class ExpressionParserTest {
 
   @Test
   public void equality() throws Exception {
-    Expression expression = parseExpression(TokenKind.EQ_OP);
+    Expression expression = parseExpression("5 eq 5");
     assertEquals("{5 EQ 5}", expression.toString());
 
-    expression = parseExpression(TokenKind.NE_OP);
+    expression = parseExpression("5 ne 5");
     assertEquals("{5 NE 5}", expression.toString());
   }
 
   @Test
   public void relational() throws Exception {
-    Expression expression = parseExpression(TokenKind.GT_OP);
+    Expression expression = parseExpression("5 gt 5");
     assertEquals("{5 GT 5}", expression.toString());
 
-    expression = parseExpression(TokenKind.GE_OP);
+    expression = parseExpression("5 ge 5");
     assertEquals("{5 GE 5}", expression.toString());
 
-    expression = parseExpression(TokenKind.LT_OP);
+    expression = parseExpression("5 lt 5");
     assertEquals("{5 LT 5}", expression.toString());
 
-    expression = parseExpression(TokenKind.LE_OP);
+    expression = parseExpression("5 le 5");
     assertEquals("{5 LE 5}", expression.toString());
   }
 
   @Test
   public void additive() throws Exception {
-    Expression expression = parseExpression(TokenKind.ADD_OP);
+    Expression expression = parseExpression("5 add 5");
     assertEquals("{5 ADD 5}", expression.toString());
 
-    expression = parseExpression(TokenKind.SUB_OP);
+    expression = parseExpression("5 sub 5");
     assertEquals("{5 SUB 5}", expression.toString());
   }
 
   @Test
   public void multiplicative() throws Exception {
-    Expression expression = parseExpression(TokenKind.MUL_OP);
+    Expression expression = parseExpression("5 mul 5");
     assertEquals("{5 MUL 5}", expression.toString());
 
-    expression = parseExpression(TokenKind.DIV_OP);
+    expression = parseExpression("5 div 5");
     assertEquals("{5 DIV 5}", expression.toString());
 
-    expression = parseExpression(TokenKind.MOD_OP);
+    expression = parseExpression("5 mod 5");
     assertEquals("{5 MOD 5}", expression.toString());
   }
 
   @Test
   public void unary() throws Exception {
-    ArrayList<Token> tokens = new ArrayList<Token>();
-    tokens.add(new Token(TokenKind.MINUS, ""));
-    tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
-    Tokenizer tokenizer = new Tokenizer(tokens);
-    Expression expression = new ExpressionParser().parse(tokenizer);
-    assertEquals("{- 5}", expression.toString());
-
-    tokens = new ArrayList<Token>();
-    tokens.add(new Token(TokenKind.NOT, ""));
-    tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
-    tokenizer = new Tokenizer(tokens);
-    expression = new ExpressionParser().parse(tokenizer);
-    assertEquals("{not 5}", expression.toString());
+    Expression expression = parseExpression("-5");
+    assertEquals("{MINUS 5}", expression.toString());
+
+    assertEquals("{MINUS -1}", parseExpression("--1").toString());
+
+    expression = parseExpression("not 5");
+    assertEquals("{NOT 5}", expression.toString());
   }
 
   @Test
   public void grouping() throws Exception {
-    ArrayList<Token> tokens = new ArrayList<Token>();
-    tokens.add(new Token(TokenKind.MINUS, ""));
-    tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
-    tokens.add(new Token(TokenKind.ADD_OP, ""));
-    tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
-    Tokenizer tokenizer = new Tokenizer(tokens);
-    Expression expression = new ExpressionParser().parse(tokenizer);
-    assertEquals("{{- 5} ADD 5}", expression.toString());
-
-    tokens = new ArrayList<Token>();
-    tokens.add(new Token(TokenKind.MINUS, ""));
-    tokens.add(new Token(TokenKind.OPEN, ""));
-    tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
-    tokens.add(new Token(TokenKind.ADD_OP, ""));
-    tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
-    tokens.add(new Token(TokenKind.CLOSE, ""));
-    tokenizer = new Tokenizer(tokens);
-    expression = new ExpressionParser().parse(tokenizer);
-    assertEquals("{- {5 ADD 5}}", expression.toString());
+    Expression expression = parseExpression("-5 add 5");
+    assertEquals("{{MINUS 5} ADD 5}", expression.toString());
+
+    expression = parseExpression("-(5 add 5)");
+    assertEquals("{MINUS {5 ADD 5}}", expression.toString());
+  }
+
+  @Test
+  public void precedence() throws Exception {
+    assertEquals("{{MINUS 1} ADD {2 DIV 3}}", parseExpression("-1 add 2 div 3").toString());
+    assertEquals("{true OR {{NOT false} AND true}}", parseExpression("true or not false and true").toString());
   }
 
   @Test
   public void noParameterMethods() throws Exception {
-    Expression expression = parseMethod(TokenKind.Now);
+    Expression expression = parseMethod(TokenKind.NowMethod);
     assertEquals("{now []}", expression.toString());
 
-    expression = parseMethod(TokenKind.Maxdatetime);
+    expression = parseMethod(TokenKind.MaxdatetimeMethod);
     assertEquals("{maxdatetime []}", expression.toString());
 
-    expression = parseMethod(TokenKind.Mindatetime);
+    expression = parseMethod(TokenKind.MindatetimeMethod);
     assertEquals("{mindatetime []}", expression.toString());
   }
 
   @Test
   public void oneParameterMethods() throws Exception {
-    Expression expression = parseMethod(TokenKind.Length, TokenKind.PrimitiveStringValue);
-    assertEquals("{length [String1]}", expression.toString());
-
-    expression = parseMethod(TokenKind.Tolower, TokenKind.PrimitiveStringValue);
-    assertEquals("{tolower [String1]}", expression.toString());
+    final String stringValue = "'abc'";
+    final String dateValue = "1234-12-25";
+    final String dateTimeOffsetValue = "1234-12-25T11:12:13.456Z";
 
-    expression = parseMethod(TokenKind.Toupper, TokenKind.PrimitiveStringValue);
-    assertEquals("{toupper [String1]}", expression.toString());
+    Expression expression = parseMethod(TokenKind.LengthMethod, stringValue);
+    assertEquals("{length [" + stringValue + "]}", expression.toString());
 
-    expression = parseMethod(TokenKind.Trim, TokenKind.PrimitiveStringValue);
-    assertEquals("{trim [String1]}", expression.toString());
+    expression = parseMethod(TokenKind.TolowerMethod, stringValue);
+    assertEquals("{tolower [" + stringValue + "]}", expression.toString());
 
-    expression = parseMethod(TokenKind.Year, TokenKind.PrimitiveDateValue);
-    assertEquals("{year [Date1]}", expression.toString());
+    expression = parseMethod(TokenKind.ToupperMethod, stringValue);
+    assertEquals("{toupper [" + stringValue + "]}", expression.toString());
 
-    expression = parseMethod(TokenKind.Month, TokenKind.PrimitiveDateValue);
-    assertEquals("{month [Date1]}", expression.toString());
+    expression = parseMethod(TokenKind.TrimMethod, stringValue);
+    assertEquals("{trim [" + stringValue + "]}", expression.toString());
 
-    expression = parseMethod(TokenKind.Day, TokenKind.PrimitiveDateValue);
-    assertEquals("{day [Date1]}", expression.toString());
+    expression = parseMethod(TokenKind.YearMethod, dateValue);
+    assertEquals("{year [" + dateValue + "]}", expression.toString());
 
-    expression = parseMethod(TokenKind.Hour, TokenKind.PrimitiveDateTimeOffsetValue);
-    assertEquals("{hour [DateTimeOffset1]}", expression.toString());
+    expression = parseMethod(TokenKind.MonthMethod, dateValue);
+    assertEquals("{month [" + dateValue + "]}", expression.toString());
 
-    expression = parseMethod(TokenKind.Minute, TokenKind.PrimitiveDateTimeOffsetValue);
-    assertEquals("{minute [DateTimeOffset1]}", expression.toString());
+    expression = parseMethod(TokenKind.DayMethod, dateValue);
+    assertEquals("{day [" + dateValue + "]}", expression.toString());
 
-    expression = parseMethod(TokenKind.Second, TokenKind.PrimitiveDateTimeOffsetValue);
-    assertEquals("{second [DateTimeOffset1]}", expression.toString());
-  }
+    expression = parseMethod(TokenKind.HourMethod, dateTimeOffsetValue);
+    assertEquals("{hour [" + dateTimeOffsetValue + "]}", expression.toString());
 
-  @Test
-  public void twoParameterMethods() {
+    expression = parseMethod(TokenKind.MinuteMethod, dateTimeOffsetValue);
+    assertEquals("{minute [" + dateTimeOffsetValue + "]}", expression.toString());
 
+    expression = parseMethod(TokenKind.SecondMethod, dateTimeOffsetValue);
+    assertEquals("{second [" + dateTimeOffsetValue + "]}", expression.toString());
   }
 
-  private Expression parseMethod(TokenKind... kind) throws UriParserException {
-    ArrayList<Token> tokens = new ArrayList<Token>();
-    tokens.add(new Token(kind[0], ""));
-
-    for (int i = 1; i < kind.length; i++) {
-      String text = null;
-      switch (kind[i]) {
-      case PrimitiveStringValue:
-        text = "String" + i;
-        break;
-      case PrimitiveDateValue:
-        text = "Date" + i;
-        break;
-      case PrimitiveDateTimeOffsetValue:
-        text = "DateTimeOffset" + i;
-        break;
-      default:
-        text = "" + i;
-        break;
+  private Expression parseMethod(TokenKind kind, String... parameters) throws UriParserException {
+    String expressionString = kind.name().substring(0, kind.name().indexOf("Method"))
+        .toLowerCase(Locale.ROOT).replace("geo", "geo.") + '(';
+    for (int i = 0; i < parameters.length; i++) {
+      if (i > 0) {
+        expressionString += ',';
       }
-      tokens.add(new Token(kind[i], text));
+      expressionString += parameters[i];
     }
+    expressionString += ')';
 
-    tokens.add(new Token(TokenKind.CLOSE, ""));
-    Tokenizer tokenizer = new Tokenizer(tokens);
-    Expression expression = new ExpressionParser().parse(tokenizer);
+    Expression expression = parseExpression(expressionString);
     assertNotNull(expression);
     return expression;
   }
 
-  private Expression parseExpression(TokenKind operator) throws UriParserException {
-    ArrayList<Token> tokens = new ArrayList<Token>();
-    tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
-    tokens.add(new Token(operator, ""));
-    tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
-    Tokenizer tokenizer = new Tokenizer(tokens);
-
+  private Expression parseExpression(final String expressionString) throws UriParserException {
+    UriTokenizer tokenizer = new UriTokenizer(expressionString);
     Expression expression = new ExpressionParser().parse(tokenizer);
     assertNotNull(expression);
+    assertTrue(tokenizer.next(TokenKind.EOF));
     return expression;
   }
 }


[17/30] olingo-odata4 git commit: [OLINGO-834] ExpressionParser parses path expressions

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8091658/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 2a994d3..118c649 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
@@ -46,29 +46,22 @@ import org.apache.olingo.server.api.uri.UriResourceRef;
 import org.apache.olingo.server.api.uri.UriResourceValue;
 import org.apache.olingo.server.api.uri.queryoption.AliasQueryOption;
 import org.apache.olingo.server.api.uri.queryoption.CustomQueryOption;
-import org.apache.olingo.server.api.uri.queryoption.FilterOption;
 import org.apache.olingo.server.api.uri.queryoption.QueryOption;
 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.UriResourceTypedImpl;
-import org.apache.olingo.server.core.uri.UriResourceWithKeysImpl;
 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.ExpandItemsEOFContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.FilterExpressionEOFContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.OrderByEOFContext;
 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;
 import org.apache.olingo.server.core.uri.queryoption.ExpandOptionImpl;
-import org.apache.olingo.server.core.uri.queryoption.FilterOptionImpl;
 import org.apache.olingo.server.core.uri.queryoption.FormatOptionImpl;
 import org.apache.olingo.server.core.uri.queryoption.IdOptionImpl;
-import org.apache.olingo.server.core.uri.queryoption.OrderByOptionImpl;
 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;
@@ -84,9 +77,7 @@ public class Parser {
   private final Edm edm;
   private final OData odata;
 
-  private enum ParserEntryRules {
-    ExpandItems, FilterExpression, Orderby
-  }
+  private enum ParserEntryRules { ExpandItems }
 
   public Parser(final Edm edm, final OData odata) {
     this.edm = edm;
@@ -131,7 +122,7 @@ public class Parser {
       if (numberOfSegments > 1) {
         final String typeCastSegment = pathSegmentsDecoded.get(1);
         ensureLastSegment(typeCastSegment, 2, numberOfSegments);
-        context.contextUriInfo = new ResourcePathParser(edm, odata).parseDollarEntityTypeCast(typeCastSegment);
+        context.contextUriInfo = new ResourcePathParser(edm).parseDollarEntityTypeCast(typeCastSegment);
         context.contextTypes.push(context.contextUriInfo.getEntityTypeCast());
       } else {
         context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.entityId);
@@ -141,7 +132,7 @@ public class Parser {
 
     } else if (firstSegment.startsWith("$crossjoin")) {
       ensureLastSegment(firstSegment, 1, numberOfSegments);
-      context.contextUriInfo = new ResourcePathParser(edm, odata).parseCrossjoinSegment(firstSegment);
+      context.contextUriInfo = new ResourcePathParser(edm).parseCrossjoinSegment(firstSegment);
       final EdmEntityContainer container = edm.getEntityContainer();
       for (final String name : context.contextUriInfo.getEntitySetNames()) {
         context.contextTypes.push(container.getEntitySet(name).getEntityType());
@@ -150,7 +141,7 @@ public class Parser {
 
     } else {
       context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.resource);
-      final ResourcePathParser resourcePathParser = new ResourcePathParser(edm, odata);
+      final ResourcePathParser resourcePathParser = new ResourcePathParser(edm);
       int count = 0;
       UriResource lastSegment = null;
       for (final String pathSegment : pathSegmentsDecoded) {
@@ -183,7 +174,7 @@ public class Parser {
 
       if (lastSegment instanceof UriResourcePartTyped) {
         final UriResourcePartTyped typed = (UriResourcePartTyped) lastSegment;
-        final EdmType type = getTypeInformation(typed);
+        final EdmType type = ParserHelper.getTypeInformation(typed);
         if (type != null) { // could be null for, e.g., actions without return type
           context.contextTypes.push(type);
         }
@@ -199,23 +190,13 @@ public class Parser {
       if (optionName.startsWith("$")) {
         SystemQueryOption systemOption = null;
         if (optionName.equals(SystemQueryOptionKind.FILTER.toString())) {
-          try {
-            FilterExpressionEOFContext ctxFilterExpression =
-                (FilterExpressionEOFContext) parseRule(optionValue, ParserEntryRules.FilterExpression);
-            systemOption = (FilterOptionImpl) uriParseTreeVisitor.visitFilterExpressionEOF(ctxFilterExpression);
-          } catch (final ParseCancellationException e) {
-            throw e.getCause() instanceof UriParserException ?
-                (UriParserException) e.getCause() :
-                new UriParserSyntaxException("Syntax error", e, UriParserSyntaxException.MessageKeys.SYNTAX);
-          }
-//          UriTokenizer filterTokenizer = new UriTokenizer(optionValue);
-//          systemOption = new FilterOptionImpl().setExpression(
-//              new ExpressionParser().parse(filterTokenizer));
-//          if (!filterTokenizer.next(TokenKind.EOF)) {
-//            throw new UriParserSyntaxException("Illegal value of $filter option!",
-//                UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION,
-//                optionName, optionValue);
-//          }
+          UriTokenizer filterTokenizer = new UriTokenizer(optionValue);
+          systemOption = new FilterParser(edm, odata).parse(filterTokenizer,
+              context.contextTypes.peek() instanceof EdmStructuredType ?
+                  (EdmStructuredType) context.contextTypes.peek() :
+                  null,
+                  context.contextUriInfo.getEntitySetNames());
+          checkOptionEOF(filterTokenizer, optionName, optionValue);
 
         } else if (optionName.equals(SystemQueryOptionKind.FORMAT.toString())) {
           FormatOptionImpl formatOption = new FormatOptionImpl();
@@ -253,15 +234,13 @@ public class Parser {
               UriParserSyntaxException.MessageKeys.SYSTEM_QUERY_OPTION_LEVELS_NOT_ALLOWED_HERE);
 
         } else if (optionName.equals(SystemQueryOptionKind.ORDERBY.toString())) {
-          try {
-            OrderByEOFContext ctxOrderByExpression =
-                (OrderByEOFContext) parseRule(optionValue, ParserEntryRules.Orderby);
-            systemOption = (OrderByOptionImpl) uriParseTreeVisitor.visitOrderByEOF(ctxOrderByExpression);
-          } catch (final ParseCancellationException e) {
-            throw e.getCause() instanceof UriParserException ?
-                (UriParserException) e.getCause() :
-                new UriParserSyntaxException("Syntax error", e, UriParserSyntaxException.MessageKeys.SYNTAX);
-          }
+          UriTokenizer orderByTokenizer = new UriTokenizer(optionValue);
+          systemOption = new OrderByParser(edm, odata).parse(orderByTokenizer,
+              context.contextTypes.peek() instanceof EdmStructuredType ?
+                  (EdmStructuredType) context.contextTypes.peek() :
+                  null,
+                  context.contextUriInfo.getEntitySetNames());
+          checkOptionEOF(orderByTokenizer, optionName, optionValue);
 
         } else if (optionName.equals(SystemQueryOptionKind.SEARCH.toString())) {
           systemOption = new SearchParser().parse(optionValue);
@@ -273,11 +252,7 @@ public class Parser {
                   (EdmStructuredType) context.contextTypes.peek() :
                   null,
               context.isCollection);
-          if (!selectTokenizer.next(TokenKind.EOF)) {
-            throw new UriParserSyntaxException("Illegal value of $select option!",
-                UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION,
-                optionName, optionValue);
-          }
+          checkOptionEOF(selectTokenizer, optionName, optionValue);
 
         } else if (optionName.equals(SystemQueryOptionKind.SKIP.toString())) {
           SkipOptionImpl skipOption = new SkipOptionImpl();
@@ -343,15 +318,12 @@ public class Parser {
                   UriParserSyntaxException.MessageKeys.SYNTAX);
             }
           } else {
-            try {
-              final FilterExpressionEOFContext filterExpCtx =
-                  (FilterExpressionEOFContext) parseRule(optionValue, ParserEntryRules.FilterExpression);
-              expression = ((FilterOption) uriParseTreeVisitor.visitFilterExpressionEOF(filterExpCtx))
-                  .getExpression();
-            } catch (final ParseCancellationException e) {
-              throw e.getCause() instanceof UriParserException ?
-                  (UriParserException) e.getCause() :
-                  new UriParserSyntaxException("Syntax error", e, UriParserSyntaxException.MessageKeys.SYNTAX);
+            UriTokenizer aliasValueTokenizer = new UriTokenizer(optionValue);
+            expression = new ExpressionParser(edm, odata).parse(aliasValueTokenizer, null,
+                context.contextUriInfo.getEntitySetNames());
+            if (!aliasValueTokenizer.next(TokenKind.EOF)) {
+              throw new UriParserSyntaxException("Illegal value for alias '" + optionName + "'.",
+                  UriParserSyntaxException.MessageKeys.SYNTAX);
             }
           }
           context.contextUriInfo.addAlias((AliasQueryOption) new AliasQueryOptionImpl()
@@ -384,28 +356,13 @@ public class Parser {
     return index > 0 && index < value.length() - 1 && index == value.lastIndexOf('/');
   }
 
-  protected static EdmType getTypeInformation(final UriResourcePartTyped resourcePart) {
-    EdmType type = null;
-    if (resourcePart instanceof UriResourceWithKeysImpl) {
-      final UriResourceWithKeysImpl lastPartWithKeys = (UriResourceWithKeysImpl) resourcePart;
-      if (lastPartWithKeys.getTypeFilterOnEntry() != null) {
-        type = lastPartWithKeys.getTypeFilterOnEntry();
-      } else if (lastPartWithKeys.getTypeFilterOnCollection() != null) {
-        type = lastPartWithKeys.getTypeFilterOnCollection();
-      } else {
-        type = lastPartWithKeys.getType();
-      }
-
-    } else if (resourcePart instanceof UriResourceTypedImpl) {
-      final UriResourceTypedImpl lastPartTyped = (UriResourceTypedImpl) resourcePart;
-      type = lastPartTyped.getTypeFilter() == null ?
-          lastPartTyped.getType() :
-          lastPartTyped.getTypeFilter();
-    } else {
-      type = resourcePart.getType();
+  private void checkOptionEOF(UriTokenizer tokenizer, final String optionName, final String optionValue)
+      throws UriParserException {
+    if (!tokenizer.next(TokenKind.EOF)) {
+      throw new UriParserSyntaxException("Illegal value of '" + optionName + "' option!",
+          UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION,
+          optionName, optionValue);
     }
-
-    return type;
   }
 
   private ParserRuleContext parseRule(final String input, final ParserEntryRules entryPoint)
@@ -435,14 +392,6 @@ public class Parser {
 
       // parse
       switch (entryPoint) {
-      case FilterExpression:
-        lexer.mode(Lexer.DEFAULT_MODE);
-        ret = parser.filterExpressionEOF();
-        break;
-      case Orderby:
-        lexer.mode(Lexer.DEFAULT_MODE);
-        ret = parser.orderByEOF();
-        break;
       case ExpandItems:
         lexer.mode(Lexer.DEFAULT_MODE);
         ret = parser.expandItemsEOF();
@@ -471,14 +420,6 @@ public class Parser {
 
         // parse
         switch (entryPoint) {
-        case FilterExpression:
-          lexer.mode(Lexer.DEFAULT_MODE);
-          ret = parser.filterExpressionEOF();
-          break;
-        case Orderby:
-          lexer.mode(Lexer.DEFAULT_MODE);
-          ret = parser.orderByEOF();
-          break;
         case ExpandItems:
           lexer.mode(Lexer.DEFAULT_MODE);
           ret = parser.expandItemsEOF();

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8091658/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ParserHelper.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ParserHelper.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ParserHelper.java
index e811575..65ee461 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ParserHelper.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ParserHelper.java
@@ -18,10 +18,35 @@
  */
 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.EdmEntityType;
+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.EdmType;
+import org.apache.olingo.commons.api.edm.EdmTypeDefinition;
+import org.apache.olingo.commons.api.edm.constants.EdmTypeKind;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.uri.UriParameter;
+import org.apache.olingo.server.api.uri.UriResourcePartTyped;
+import org.apache.olingo.server.core.ODataImpl;
+import org.apache.olingo.server.core.uri.UriParameterImpl;
+import org.apache.olingo.server.core.uri.UriResourceTypedImpl;
+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 ParserHelper {
 
+  private static final OData odata = new ODataImpl();
+
   public static void requireNext(UriTokenizer tokenizer, final TokenKind required) throws UriParserException {
     if (!tokenizer.next(required)) {
       throw new UriParserSyntaxException("Expected token '" + required.toString() + "' not found.",
@@ -33,16 +58,16 @@ public class ParserHelper {
     requireNext(tokenizer, TokenKind.EOF);
   }
 
-  public static TokenKind next(UriTokenizer tokenizer, final TokenKind... kind) {
-    for (int i = 0; i < kind.length; i++) {
-      if (tokenizer.next(kind[i])) {
-        return kind[i];
+  public static TokenKind next(UriTokenizer tokenizer, final TokenKind... kinds) {
+    for (final TokenKind kind : kinds) {
+      if (tokenizer.next(kind)) {
+        return kind;
       }
     }
     return null;
   }
 
-  public static TokenKind nextPrimitive(UriTokenizer tokenizer) {
+  public static TokenKind nextPrimitiveValue(UriTokenizer tokenizer) {
     return next(tokenizer,
         TokenKind.NULL,
         TokenKind.BooleanValue,
@@ -62,4 +87,304 @@ public class ParserHelper {
         TokenKind.BinaryValue,
         TokenKind.EnumValue);
   }
+
+  protected static List<UriParameter> parseFunctionParameters(UriTokenizer tokenizer, final boolean withComplex)
+      throws UriParserException {
+    List<UriParameter> parameters = new ArrayList<UriParameter>();
+    ParserHelper.requireNext(tokenizer, TokenKind.OPEN);
+    if (tokenizer.next(TokenKind.CLOSE)) {
+      return parameters;
+    }
+    do {
+      ParserHelper.requireNext(tokenizer, TokenKind.ODataIdentifier);
+      final String name = tokenizer.getText();
+      if (parameters.contains(name)) {
+        throw new UriParserSemanticException("Duplicated function parameter " + name,
+            UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE, name);
+      }
+      ParserHelper.requireNext(tokenizer, 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 (tokenizer.next(TokenKind.ParameterAliasName)) {
+        parameters.add(new UriParameterImpl().setName(name).setAlias(tokenizer.getText()));
+      } else if (tokenizer.next(TokenKind.jsonArrayOrObject)) {
+        if (withComplex) {
+          parameters.add(new UriParameterImpl().setName(name).setText(tokenizer.getText()));
+        } else {
+          throw new UriParserSemanticException("A JSON array or object is not allowed as parameter value.",
+              UriParserSemanticException.MessageKeys.COMPLEX_PARAMETER_IN_RESOURCE_PATH, tokenizer.getText());
+        }
+      } else if (nextPrimitiveValue(tokenizer) == null) {
+        throw new UriParserSemanticException("Wrong parameter value.",
+            UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE, "");
+      } else {
+        final String literalValue = tokenizer.getText();
+        parameters.add(new UriParameterImpl().setName(name)
+            .setText("null".equals(literalValue) ? null : literalValue));
+      }
+    } while (tokenizer.next(TokenKind.COMMA));
+    ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
+    return parameters;
+  }
+
+  protected static List<UriParameter> parseNavigationKeyPredicate(UriTokenizer tokenizer,
+      final EdmNavigationProperty navigationProperty) throws UriParserException, UriValidationException {
+    if (tokenizer.next(TokenKind.OPEN)) {
+      if (navigationProperty.isCollection()) {
+        return parseKeyPredicate(tokenizer, navigationProperty.getType(), navigationProperty.getPartner());
+      } else {
+        throw new UriParserSemanticException("A key is not allowed on non-collection navigation properties.",
+            UriParserSemanticException.MessageKeys.KEY_NOT_ALLOWED);
+      }
+    }
+    return null;
+  }
+
+  protected static List<UriParameter> parseKeyPredicate(UriTokenizer tokenizer, 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(tokenizer, edmEntityType));
+    } else if (keyPropertyRefs.size() - referencedNames.size() == 1) {
+      for (final EdmKeyPropertyRef candidate : keyPropertyRefs) {
+        if (referencedNames.get(candidate.getName()) == null) {
+          keys.add(simpleKey(tokenizer, 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 static UriParameter simpleKey(UriTokenizer tokenizer, final EdmKeyPropertyRef edmKeyPropertyRef)
+      throws UriParserException, UriValidationException {
+    final EdmProperty edmProperty = edmKeyPropertyRef == null ? null : edmKeyPropertyRef.getProperty();
+    if (nextPrimitiveTypeValue(tokenizer,
+        edmProperty == null ? null : (EdmPrimitiveType) edmProperty.getType(),
+        edmProperty == null ? false : edmProperty.isNullable())) {
+      final String literalValue = tokenizer.getText();
+      ParserHelper.requireNext(tokenizer, 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 static List<UriParameter> compoundKey(UriTokenizer tokenizer, 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(tokenizer, keyPredicateName, edmEntityType));
+      parameterNames.add(keyPredicateName);
+      hasComma = tokenizer.next(TokenKind.COMMA);
+      if (hasComma) {
+        ParserHelper.requireNext(tokenizer, TokenKind.ODataIdentifier);
+      }
+    } while (hasComma);
+    ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
+
+    return parameters;
+  }
+
+  protected static UriParameter keyValuePair(UriTokenizer tokenizer,
+      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);
+    }
+    ParserHelper.requireNext(tokenizer, 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(tokenizer, (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 static 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 static boolean nextPrimitiveTypeValue(UriTokenizer tokenizer,
+      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.BooleanValue);
+    } else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.String).equals(type)) {
+      return tokenizer.next(TokenKind.StringValue);
+    } 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.IntegerValue);
+    } else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Guid).equals(type)) {
+      return tokenizer.next(TokenKind.GuidValue);
+    } else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Date).equals(type)) {
+      return tokenizer.next(TokenKind.DateValue);
+    } else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.DateTimeOffset).equals(type)) {
+      return tokenizer.next(TokenKind.DateTimeOffsetValue);
+    } else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.TimeOfDay).equals(type)) {
+      return tokenizer.next(TokenKind.TimeOfDayValue);
+    } 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.DecimalValue)
+          || tokenizer.next(TokenKind.IntegerValue);
+    } 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.DoubleValue)
+          || tokenizer.next(TokenKind.DecimalValue)
+          || tokenizer.next(TokenKind.IntegerValue);
+    } else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Duration).equals(type)) {
+      return tokenizer.next(TokenKind.DurationValue);
+    } else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Binary).equals(type)) {
+      return tokenizer.next(TokenKind.BinaryValue);
+    } else if (type.getKind() == EdmTypeKind.ENUM) {
+      return tokenizer.next(TokenKind.EnumValue);
+    } else {
+      return false;
+    }
+  }
+
+  protected static List<String> getParameterNames(final List<UriParameter> parameters) {
+    List<String> names = new ArrayList<String>();
+    for (final UriParameter parameter : parameters) {
+      names.add(parameter.getName());
+    }
+    return names;
+  }
+
+  protected static EdmType getTypeInformation(final UriResourcePartTyped resourcePart) {
+    EdmType type = null;
+    if (resourcePart instanceof UriResourceWithKeysImpl) {
+      final UriResourceWithKeysImpl lastPartWithKeys = (UriResourceWithKeysImpl) resourcePart;
+      if (lastPartWithKeys.getTypeFilterOnEntry() != null) {
+        type = lastPartWithKeys.getTypeFilterOnEntry();
+      } else if (lastPartWithKeys.getTypeFilterOnCollection() != null) {
+        type = lastPartWithKeys.getTypeFilterOnCollection();
+      } else {
+        type = lastPartWithKeys.getType();
+      }
+
+    } else if (resourcePart instanceof UriResourceTypedImpl) {
+      final UriResourceTypedImpl lastPartTyped = (UriResourceTypedImpl) resourcePart;
+      type = lastPartTyped.getTypeFilter() == null ?
+          lastPartTyped.getType() :
+          lastPartTyped.getTypeFilter();
+    } else {
+      type = resourcePart.getType();
+    }
+
+    return type;
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8091658/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
index 5d2fbde..1cd4d7a 100644
--- 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
@@ -18,10 +18,7 @@
  */
 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;
@@ -31,25 +28,18 @@ 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;
@@ -69,13 +59,11 @@ 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) {
+  public ResourcePathParser(final Edm edm) {
     this.edm = edm;
     edmEntityContainer = edm.getEntityContainer();
-    this.odata = odata;
   }
 
   public UriResource parsePathSegment(final String pathSegment, UriResource previous)
@@ -188,10 +176,11 @@ public class ResourcePathParser {
 
     final EdmEntitySet edmEntitySet = edmEntityContainer.getEntitySet(oDataIdentifier);
     if (edmEntitySet != null) {
-      final UriResourceEntitySetImpl entitySetResource = new UriResourceEntitySetImpl().setEntitSet(edmEntitySet);
+      final UriResourceEntitySetImpl entitySetResource = new UriResourceEntitySetImpl(edmEntitySet);
 
       if (tokenizer.next(TokenKind.OPEN)) {
-        final List<UriParameter> keyPredicates = keyPredicate(entitySetResource.getEntityType(), null);
+        final List<UriParameter> keyPredicates =
+            ParserHelper.parseKeyPredicate(tokenizer, entitySetResource.getEntityType(), null);
         entitySetResource.setKeyPredicates(keyPredicates);
       }
 
@@ -202,13 +191,13 @@ public class ResourcePathParser {
     final EdmSingleton edmSingleton = edmEntityContainer.getSingleton(oDataIdentifier);
     if (edmSingleton != null) {
       ParserHelper.requireTokenEnd(tokenizer);
-      return new UriResourceSingletonImpl().setSingleton(edmSingleton);
+      return new UriResourceSingletonImpl(edmSingleton);
     }
 
     final EdmActionImport edmActionImport = edmEntityContainer.getActionImport(oDataIdentifier);
     if (edmActionImport != null) {
       ParserHelper.requireTokenEnd(tokenizer);
-      return new UriResourceActionImpl().setActionImport(edmActionImport);
+      return new UriResourceActionImpl(edmActionImport);
     }
 
     final EdmFunctionImport edmFunctionImport = edmEntityContainer.getFunctionImport(oDataIdentifier);
@@ -252,8 +241,8 @@ public class ResourcePathParser {
       return property.isPrimitive()
           || property.getType().getKind() == EdmTypeKind.ENUM
           || property.getType().getKind() == EdmTypeKind.DEFINITION ?
-          new UriResourcePrimitivePropertyImpl().setProperty(property) :
-          new UriResourceComplexPropertyImpl().setProperty(property);
+          new UriResourcePrimitivePropertyImpl(property) :
+          new UriResourceComplexPropertyImpl(property);
     }
     final EdmNavigationProperty navigationProperty = structType.getNavigationProperty(name);
     if (navigationProperty == null) {
@@ -262,18 +251,9 @@ public class ResourcePathParser {
           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);
-      }
-    }
+    List<UriParameter> keyPredicate = ParserHelper.parseNavigationKeyPredicate(tokenizer, navigationProperty);
     ParserHelper.requireTokenEnd(tokenizer);
-    return new UriResourceNavigationPropertyImpl()
-        .setNavigationProperty(navigationProperty)
+    return new UriResourceNavigationPropertyImpl(navigationProperty)
         .setKeyPredicates(keyPredicate);
   }
 
@@ -289,7 +269,7 @@ public class ResourcePathParser {
           previousTyped.isCollection());
       if (boundAction != null) {
         ParserHelper.requireTokenEnd(tokenizer);
-        return new UriResourceActionImpl().setAction(boundAction);
+        return new UriResourceActionImpl(boundAction);
       }
       EdmStructuredType type = edm.getEntityType(name);
       if (type == null) {
@@ -314,169 +294,6 @@ public class ResourcePathParser {
     }
   }
 
-  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();
-      ParserHelper.requireNext(tokenizer, 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) {
-        ParserHelper.requireNext(tokenizer, TokenKind.ODataIdentifier);
-      }
-    } while (hasComma);
-    ParserHelper.requireNext(tokenizer, 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);
-    }
-    ParserHelper.requireNext(tokenizer, 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())) {
@@ -501,7 +318,7 @@ public class ResourcePathParser {
         }
         if (tokenizer.next(TokenKind.OPEN)) {
           ((UriResourceWithKeysImpl) previousTyped).setKeyPredicates(
-              keyPredicate((EdmEntityType) type, null));
+              ParserHelper.parseKeyPredicate(tokenizer, (EdmEntityType) type, null));
         }
       } else {
         previousTypeFilter = ((UriResourceTypedImpl) previousTyped).getTypeFilter();
@@ -534,11 +351,8 @@ public class ResourcePathParser {
   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());
-    }
+    final List<UriParameter> parameters = ParserHelper.parseFunctionParameters(tokenizer, false);
+    final List<String> names = ParserHelper.getParameterNames(parameters);
     EdmFunction function = null;
     if (edmFunctionImport != null) {
       function = edmFunctionImport.getUnboundFunction(names);
@@ -557,16 +371,13 @@ public class ResourcePathParser {
             UriParserSemanticException.MessageKeys.UNKNOWN_PART, boundFunctionName.getFullQualifiedNameAsString());
       }
     }
-    UriResourceFunctionImpl resource = new UriResourceFunctionImpl()
-        .setFunctionImport(edmFunctionImport, null)
-        .setFunction(function)
-        .setParameters(parameters);
+    UriResourceFunctionImpl resource = new UriResourceFunctionImpl(edmFunctionImport, function, 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));
+            ParserHelper.parseKeyPredicate(tokenizer, (EdmEntityType) function.getReturnType().getType(), null));
       } else {
         throw new UriParserSemanticException("A key is not allowed.",
             UriParserSemanticException.MessageKeys.KEY_NOT_ALLOWED);
@@ -575,106 +386,4 @@ public class ResourcePathParser {
     ParserHelper.requireTokenEnd(tokenizer);
     return resource;
   }
-
-  private List<UriParameter> functionParameters() throws UriParserException {
-    List<UriParameter> parameters = new ArrayList<UriParameter>();
-    ParserHelper.requireNext(tokenizer, TokenKind.OPEN);
-    if (tokenizer.next(TokenKind.CLOSE)) {
-      return parameters;
-    }
-    do {
-      ParserHelper.requireNext(tokenizer, TokenKind.ODataIdentifier);
-      final String name = tokenizer.getText();
-      if (parameters.contains(name)) {
-        throw new UriParserSemanticException("Duplicated function parameter " + name,
-            UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE, name);
-      }
-      ParserHelper.requireNext(tokenizer, 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 (tokenizer.next(TokenKind.ParameterAliasName)) {
-        parameters.add(new UriParameterImpl().setName(name).setAlias(tokenizer.getText()));
-      } else if (nextPrimitiveValue()) {
-        final String literalValue = tokenizer.getText();
-        parameters.add(new UriParameterImpl().setName(name)
-            .setText("null".equals(literalValue) ? null : literalValue));
-      } else {
-        throw new UriParserSemanticException("Wrong parameter value.",
-            UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE, "");
-      }
-    } while (tokenizer.next(TokenKind.COMMA));
-    ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
-    return parameters;
-  }
-
-  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.BooleanValue);
-    } else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.String).equals(type)) {
-      return tokenizer.next(TokenKind.StringValue);
-    } 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.IntegerValue);
-    } else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Guid).equals(type)) {
-      return tokenizer.next(TokenKind.GuidValue);
-    } else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Date).equals(type)) {
-      return tokenizer.next(TokenKind.DateValue);
-    } else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.DateTimeOffset).equals(type)) {
-      return tokenizer.next(TokenKind.DateTimeOffsetValue);
-    } else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.TimeOfDay).equals(type)) {
-      return tokenizer.next(TokenKind.TimeOfDayValue);
-    } 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.DecimalValue)
-          || tokenizer.next(TokenKind.IntegerValue);
-    } 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.DoubleValue)
-          || tokenizer.next(TokenKind.DecimalValue)
-          || tokenizer.next(TokenKind.IntegerValue);
-    } else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Duration).equals(type)) {
-      return tokenizer.next(TokenKind.DurationValue);
-    } else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Binary).equals(type)) {
-      return tokenizer.next(TokenKind.BinaryValue);
-    } else if (type.getKind() == EdmTypeKind.ENUM) {
-      return tokenizer.next(TokenKind.EnumValue);
-    } else {
-      return false;
-    }
-  }
-
-  private boolean nextPrimitiveValue() {
-    return tokenizer.next(TokenKind.NULL)
-        || tokenizer.next(TokenKind.BooleanValue)
-        || tokenizer.next(TokenKind.StringValue)
-
-        // 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.DoubleValue)
-        || tokenizer.next(TokenKind.DecimalValue)
-        || tokenizer.next(TokenKind.GuidValue)
-        || tokenizer.next(TokenKind.DateTimeOffsetValue)
-        || tokenizer.next(TokenKind.DateValue)
-        || tokenizer.next(TokenKind.TimeOfDayValue)
-        || tokenizer.next(TokenKind.IntegerValue)
-
-        || tokenizer.next(TokenKind.DurationValue)
-        || tokenizer.next(TokenKind.BinaryValue)
-        || tokenizer.next(TokenKind.EnumValue);
-  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8091658/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/SelectParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/SelectParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/SelectParser.java
index b257e68..00f3673 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/SelectParser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/SelectParser.java
@@ -156,10 +156,10 @@ public class SelectParser {
         throw new UriParserSemanticException("Function not found.",
             UriParserSemanticException.MessageKeys.UNKNOWN_PART, qualifiedName.getFullQualifiedNameAsString());
       } else {
-        return new UriResourceFunctionImpl().setFunction(boundFunction);
+        return new UriResourceFunctionImpl(null, boundFunction, null);
       }
     } else {
-      return new UriResourceActionImpl().setAction(boundAction);
+      return new UriResourceActionImpl(boundAction);
     }
   }
 
@@ -187,16 +187,16 @@ public class SelectParser {
             UriParserSemanticException.MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE,
             referencedType.getName(), name);
       } else {
-        resource.addResourcePart(new UriResourceNavigationPropertyImpl().setNavigationProperty(navigationProperty));
+        resource.addResourcePart(new UriResourceNavigationPropertyImpl(navigationProperty));
       }
 
     } else if (property.isPrimitive()
         || property.getType().getKind() == EdmTypeKind.ENUM
         || property.getType().getKind() == EdmTypeKind.DEFINITION) {
-      resource.addResourcePart(new UriResourcePrimitivePropertyImpl().setProperty(property));
+      resource.addResourcePart(new UriResourcePrimitivePropertyImpl(property));
 
     } else {
-      UriResourceComplexPropertyImpl complexPart = new UriResourceComplexPropertyImpl().setProperty(property);
+      UriResourceComplexPropertyImpl complexPart = new UriResourceComplexPropertyImpl(property);
       resource.addResourcePart(complexPart);
       if (tokenizer.next(TokenKind.SLASH)) {
         if (tokenizer.next(TokenKind.QualifiedName)) {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8091658/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriContext.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriContext.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriContext.java
index c0db85b..36a0887 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriContext.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriContext.java
@@ -32,10 +32,9 @@ import org.apache.olingo.server.core.uri.queryoption.SelectItemImpl;
  */
 public class UriContext {
 
-  public static class LambdaVariables {
+  public static class LambdaVariable {
     public String name;
     public EdmType type;
-    public boolean isCollection;
   }
 
   /**
@@ -43,7 +42,7 @@ public class UriContext {
    * As lambda functions can be nested there may be more than one allowed lambda variables at a time while parsing a
    * $filter or $orderby expressions.
    */
-  public Deque<LambdaVariables> allowedLambdaVariables;
+  public Deque<LambdaVariable> allowedLambdaVariables;
   /**
    * Used to stack type information for nested $expand, $filter query options and other cases.
    */
@@ -110,7 +109,7 @@ public class UriContext {
     contextReadingFunctionParameters = false;
     contextSelectItem = null;
     contextTypes = new ArrayDeque<EdmType>();
-    allowedLambdaVariables = new ArrayDeque<UriContext.LambdaVariables>();
+    allowedLambdaVariables = new ArrayDeque<UriContext.LambdaVariable>();
 
   }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8091658/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 9d29ab2..1bab218 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
@@ -252,8 +252,8 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
     return new FullQualifiedName(namespace, odi);
   }
 
-  private UriContext.LambdaVariables getLambdaVar(final String odi) {
-    for (UriContext.LambdaVariables item : context.allowedLambdaVariables) {
+  private UriContext.LambdaVariable getLambdaVar(final String odi) {
+    for (UriContext.LambdaVariable item : context.allowedLambdaVariables) {
       if (item.name.equals(odi)) {
         return item;
       }
@@ -292,7 +292,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
               || parts.get(0) instanceof UriResourceRoot)) {
         ensureNamespaceIsNull(ctx.vNS);
         context.contextUriInfo.addResourcePart(
-            new UriResourceEntitySetImpl().setEntitSet(edmEntitySet));
+            new UriResourceEntitySetImpl(edmEntitySet));
         return null;
       }
 
@@ -303,7 +303,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
               || parts.get(0) instanceof UriResourceRoot)) {
         ensureNamespaceIsNull(ctx.vNS);
         context.contextUriInfo.addResourcePart(
-            new UriResourceSingletonImpl().setSingleton(edmSingleton));
+            new UriResourceSingletonImpl(edmSingleton));
         return null;
       }
 
@@ -314,7 +314,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
               || parts.get(0) instanceof UriResourceRoot)) {
         ensureNamespaceIsNull(ctx.vNS);
         context.contextUriInfo.addResourcePart(
-            new UriResourceActionImpl().setActionImport(edmActionImport));
+            new UriResourceActionImpl(edmActionImport));
         return null;
       }
 
@@ -344,9 +344,6 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
         // mark parameters as consumed
         ctx.vlNVO.remove(0);
 
-        UriResourceFunctionImpl uriResource = new UriResourceFunctionImpl()
-            .setFunctionImport(edmFunctionImport, parameters);
-
         // collect parameter names
         List<String> names = new ArrayList<String>();
         for (UriParameter item : parameters) {
@@ -366,7 +363,9 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
         }
 
         ensureNamespaceIsNull(ctx.vNS);
-        uriResource.setFunction(edmFunctionImport.getUnboundFunction(names));
+        UriResourceFunctionImpl uriResource = new UriResourceFunctionImpl(edmFunctionImport,
+            edmFunctionImport.getUnboundFunction(names),
+            parameters);
         context.contextUriInfo.addResourcePart(uriResource);
         return null;
       }
@@ -390,7 +389,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
       sourceType = context.contextTypes.peek();
       sourceIsCollection = context.isCollection;
     } else if (lastResourcePart instanceof UriResourcePartTyped) {
-      sourceType = Parser.getTypeInformation((UriResourcePartTyped) lastResourcePart);
+      sourceType = ParserHelper.getTypeInformation((UriResourcePartTyped) lastResourcePart);
       sourceIsCollection = ((UriResourcePartTyped) lastResourcePart).isCollection();
     } else {
       throw wrap(new UriParserSemanticException(
@@ -401,12 +400,9 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
     if (ctx.vNS == null) { // without namespace
 
       // first check for lambda variable because a newly add property should not shadow a long used lambda variable
-      UriContext.LambdaVariables lVar = getLambdaVar(odi);
+      UriContext.LambdaVariable lVar = getLambdaVar(odi);
       if (lVar != null) {
-        UriResourceLambdaVarImpl lambdaResource = new UriResourceLambdaVarImpl();
-        lambdaResource.setVariableText(lVar.name);
-        lambdaResource.setType(lVar.type);
-        lambdaResource.setCollection(lVar.isCollection);
+        UriResourceLambdaVarImpl lambdaResource = new UriResourceLambdaVarImpl(lVar.name, lVar.type);
         context.contextUriInfo.addResourcePart(lambdaResource);
         return null;
       }
@@ -442,14 +438,13 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
             || property.getType().getKind() == EdmTypeKind.ENUM
             || property.getType().getKind() == EdmTypeKind.DEFINITION) {
           // create simple property
-          UriResourcePrimitivePropertyImpl simpleResource = new UriResourcePrimitivePropertyImpl()
-              .setProperty((EdmProperty) property);
+          UriResourcePrimitivePropertyImpl simpleResource =
+              new UriResourcePrimitivePropertyImpl((EdmProperty) property);
           context.contextUriInfo.addResourcePart(simpleResource);
           return null;
         } else {
           // create complex property
-          UriResourceComplexPropertyImpl complexResource = new UriResourceComplexPropertyImpl()
-              .setProperty((EdmProperty) property);
+          UriResourceComplexPropertyImpl complexResource = new UriResourceComplexPropertyImpl((EdmProperty) property);
           context.contextUriInfo.addResourcePart(complexResource);
           return null;
         }
@@ -461,8 +456,8 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
               UriParserSemanticException.MessageKeys.KEY_NOT_ALLOWED));
         }
 
-        UriResourceNavigationPropertyImpl navigationResource = new UriResourceNavigationPropertyImpl()
-            .setNavigationProperty((EdmNavigationProperty) property);
+        UriResourceNavigationPropertyImpl navigationResource =
+            new UriResourceNavigationPropertyImpl((EdmNavigationProperty) property);
         context.contextUriInfo.addResourcePart(navigationResource);
         return null;
       } else {
@@ -488,9 +483,9 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
 
           if (lastResourcePart == null) {
             // this may be the case if a member expression within a filter starts with a typeCast
-            UriResourceStartingTypeFilterImpl uriResource = new UriResourceStartingTypeFilterImpl()
-                .setType(filterEntityType)
-                .setCollection(sourceIsCollection);
+            UriResourceStartingTypeFilterImpl uriResource = new UriResourceStartingTypeFilterImpl(
+                filterEntityType,
+                sourceIsCollection);
             if (sourceIsCollection) {
               uriResource.setCollectionTypeFilter(filterEntityType);
             } else {
@@ -562,9 +557,8 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
           // is simple complex type cast
           if (lastResourcePart == null) {
             // this may be the case if a member expression within a filter starts with a typeCast
-            UriResourceStartingTypeFilterImpl uriResource = new UriResourceStartingTypeFilterImpl()
-                .setType(filterComplexType)
-                .setCollection(sourceIsCollection);
+            UriResourceStartingTypeFilterImpl uriResource =
+                new UriResourceStartingTypeFilterImpl(filterComplexType, sourceIsCollection);
 
             if (sourceIsCollection) {
               uriResource.setCollectionTypeFilter(filterComplexType);
@@ -626,8 +620,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
       // check for action
       EdmAction action = edm.getBoundAction(fullFilterName, fullBindingTypeName, sourceIsCollection);
       if (action != null) {
-        UriResourceActionImpl pathInfoAction = new UriResourceActionImpl();
-        pathInfoAction.setAction(action);
+        UriResourceActionImpl pathInfoAction = new UriResourceActionImpl(action);
         context.contextUriInfo.addResourcePart(pathInfoAction);
         return null;
       }
@@ -652,9 +645,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
       EdmFunction function = edm.getBoundFunction(fullFilterName, fullBindingTypeName, sourceIsCollection, names);
 
       if (function != null) {
-        UriResourceFunctionImpl pathInfoFunction = new UriResourceFunctionImpl()
-            .setFunction(function)
-            .setParameters(parameters);
+        UriResourceFunctionImpl pathInfoFunction = new UriResourceFunctionImpl(null, function, parameters);
         context.contextUriInfo.addResourcePart(pathInfoFunction);
 
         // mark parameters as consumed
@@ -666,9 +657,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
       function = edm.getUnboundFunction(fullFilterName, names);
 
       if (function != null) {
-        UriResourceFunctionImpl pathInfoFunction = new UriResourceFunctionImpl()
-            .setFunction(function)
-            .setParameters(parameters);
+        UriResourceFunctionImpl pathInfoFunction = new UriResourceFunctionImpl(null, function, parameters);
         context.contextUriInfo.addResourcePart(pathInfoFunction);
 
         // mark parameters as consumed
@@ -706,8 +695,6 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
 
   @Override
   public Object visitAllExpr(final AllExprContext ctx) {
-    UriResourceLambdaAllImpl all = new UriResourceLambdaAllImpl();
-
     UriResource obj = context.contextUriInfo.getLastResourcePart();
     if (!(obj instanceof UriResourcePartTyped)) {
       throw wrap(new UriParserSemanticException("all only allowed on typed path segments",
@@ -720,16 +707,14 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
       }
     }
 
-    UriContext.LambdaVariables var = new UriContext.LambdaVariables();
+    UriContext.LambdaVariable var = new UriContext.LambdaVariable();
     var.name = ctx.vLV.getText();
-    var.type = Parser.getTypeInformation((UriResourcePartTyped) obj);
-    var.isCollection = false;
+    var.type = ParserHelper.getTypeInformation((UriResourcePartTyped) obj);
 
-    all.setLamdaVariable(ctx.vLV.getText());
     context.allowedLambdaVariables.push(var);
-    all.setExpression((Expression) ctx.vLE.accept(this));
+    Expression expression = (Expression) ctx.vLE.accept(this);
     context.allowedLambdaVariables.pop();
-    return all;
+    return new UriResourceLambdaAllImpl(var.name, expression);
   }
 
   @Override
@@ -895,7 +880,6 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
 
   @Override
   public Object visitAnyExpr(final AnyExprContext ctx) {
-    UriResourceLambdaAnyImpl any = new UriResourceLambdaAnyImpl();
     if (ctx.vLV != null) {
       UriResourceImpl lastResourcePart = (UriResourceImpl) context.contextUriInfo.getLastResourcePart();
       if (!(lastResourcePart instanceof UriResourcePartTyped)) {
@@ -909,17 +893,16 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
         }
       }
 
-      UriContext.LambdaVariables var = new UriContext.LambdaVariables();
+      UriContext.LambdaVariable var = new UriContext.LambdaVariable();
       var.name = ctx.vLV.getText();
-      var.type = Parser.getTypeInformation((UriResourcePartTyped) lastResourcePart);
-      var.isCollection = false;
+      var.type = ParserHelper.getTypeInformation((UriResourcePartTyped) lastResourcePart);
 
-      any.setLamdaVariable(ctx.vLV.getText());
       context.allowedLambdaVariables.push(var);
-      any.setExpression((Expression) ctx.vLE.accept(this));
+      Expression expression = (Expression) ctx.vLE.accept(this);
       context.allowedLambdaVariables.pop();
+      return new UriResourceLambdaAnyImpl(var.name, expression);
     }
-    return any;
+    return null;
   }
 
   @Override
@@ -1238,18 +1221,18 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
     if (context.contextExpandItemPath == null) {
       // use the type of the last resource path segement
       UriResourceTypedImpl lastSegment = (UriResourceTypedImpl) context.contextUriInfo.getLastResourcePart();
-      targetType = Parser.getTypeInformation(lastSegment);
+      targetType = ParserHelper.getTypeInformation(lastSegment);
       isColl = lastSegment.isCollection();
     } else {
       if (context.contextExpandItemPath.getResourcePath() == null) {
         // use the type of the last resource path segement
         UriResourceTypedImpl lastSegment = (UriResourceTypedImpl) context.contextUriInfo.getLastResourcePart();
-        targetType = Parser.getTypeInformation(lastSegment);
+        targetType = ParserHelper.getTypeInformation(lastSegment);
         isColl = lastSegment.isCollection();
       } else {
         // use the type of the last ''expand'' path segement
         UriInfoImpl info = (UriInfoImpl) context.contextExpandItemPath.getResourcePath();
-        targetType = Parser.getTypeInformation((UriResourcePartTyped) info.getLastResourcePart());
+        targetType = ParserHelper.getTypeInformation((UriResourcePartTyped) info.getLastResourcePart());
         isColl = ((UriResourcePartTyped) info.getLastResourcePart()).isCollection();
       }
     }
@@ -1400,10 +1383,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
     }
 
     if (ctx.vIt != null || ctx.vIts != null) {
-      UriResourceItImpl pathInfoIT = new UriResourceItImpl();
-      pathInfoIT.setType(context.contextTypes.peek());
-      pathInfoIT.setCollection(context.isCollection);
-      uriInfoImplpath.addResourcePart(pathInfoIT);
+      uriInfoImplpath.addResourcePart(new UriResourceItImpl(context.contextTypes.peek(), context.isCollection));
     }
 
     if (ctx.vPs != null) {
@@ -1915,9 +1895,9 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
 
     UriResourcePartTyped lastType = (UriResourcePartTyped) lastResource;
 
-    UriResourceRootImpl pathInfoRoot = new UriResourceRootImpl();
-    pathInfoRoot.setCollection(lastType.isCollection());
-    pathInfoRoot.setType(Parser.getTypeInformation(lastType));
+    UriResourceRootImpl pathInfoRoot = new UriResourceRootImpl(
+        ParserHelper.getTypeInformation(lastType),
+        lastType.isCollection());
 
     UriInfoImpl uriInfoImplpath = new UriInfoImpl().setKind(UriInfoKind.resource);
     uriInfoImplpath.addResourcePart(pathInfoRoot);
@@ -2010,7 +1990,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
         UriInfoImpl uriInfo = (UriInfoImpl) context.contextSelectItem.getResourcePath();
         UriResource last = uriInfo.getLastResourcePart();
 
-        prevType = Parser.getTypeInformation((UriResourcePartTyped) last);
+        prevType = ParserHelper.getTypeInformation((UriResourcePartTyped) last);
         if (prevType == null) {
           throw wrap(new UriParserSemanticException("prev segment not typed",
               UriParserSemanticException.MessageKeys.ONLY_FOR_TYPED_PARTS, "select"));
@@ -2038,8 +2018,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
             || property.getType().getKind() == EdmTypeKind.ENUM
             || property.getType().getKind() == EdmTypeKind.DEFINITION) {
 
-          UriResourcePrimitivePropertyImpl simple = new UriResourcePrimitivePropertyImpl();
-          simple.setProperty(property);
+          UriResourcePrimitivePropertyImpl simple = new UriResourcePrimitivePropertyImpl(property);
 
           UriInfoImpl uriInfo = (UriInfoImpl) context.contextSelectItem.getResourcePath();
           if (uriInfo == null) {
@@ -2059,8 +2038,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
         } else {
           UriInfoImpl uriInfo = (UriInfoImpl) context.contextSelectItem.getResourcePath();
 
-          UriResourceComplexPropertyImpl complex = new UriResourceComplexPropertyImpl();
-          complex.setProperty(property);
+          UriResourceComplexPropertyImpl complex = new UriResourceComplexPropertyImpl(property);
 
           if (uriInfo == null) {
             uriInfo = new UriInfoImpl().setKind(UriInfoKind.resource);
@@ -2096,7 +2074,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
           EdmComplexType ct = edm.getComplexType(fullName);
           if (ct != null) {
             if ((ct.compatibleTo(prevType))) {
-              UriResourceStartingTypeFilterImpl resourcePart = new UriResourceStartingTypeFilterImpl();
+              UriResourceStartingTypeFilterImpl resourcePart = new UriResourceStartingTypeFilterImpl(null, false);
               resourcePart.setCollectionTypeFilter(ct);
 
               UriInfoImpl uriInfo = new UriInfoImpl().setKind(UriInfoKind.resource);
@@ -2115,7 +2093,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
           EdmEntityType et = edm.getEntityType(fullName);
           if (et != null) {
             if ((et.compatibleTo(prevType))) {
-              UriResourceStartingTypeFilterImpl resourcePart = new UriResourceStartingTypeFilterImpl();
+              UriResourceStartingTypeFilterImpl resourcePart = new UriResourceStartingTypeFilterImpl(null, false);
               resourcePart.setCollectionTypeFilter(et);
 
               UriInfoImpl uriInfo = new UriInfoImpl().setKind(UriInfoKind.resource);
@@ -2142,13 +2120,13 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
           throw wrap(new UriParserSemanticException("prev segment typed",
               UriParserSemanticException.MessageKeys.ONLY_FOR_TYPED_PARTS, "select"));
         }
-        EdmType prevType = Parser.getTypeInformation((UriResourcePartTyped) last);
+        EdmType prevType = ParserHelper.getTypeInformation((UriResourcePartTyped) last);
 
         if (prevType instanceof EdmComplexType) {
           EdmComplexType ct = edm.getComplexType(fullName);
           if (ct != null) {
             if ((ct.compatibleTo(prevType))) {
-              UriResourceStartingTypeFilterImpl resourcePart = new UriResourceStartingTypeFilterImpl();
+              UriResourceStartingTypeFilterImpl resourcePart = new UriResourceStartingTypeFilterImpl(null, false);
               resourcePart.setCollectionTypeFilter(ct);
 
               uriInfo.addResourcePart(resourcePart);
@@ -2186,7 +2164,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
           throw wrap(new UriParserSemanticException("prev segment typed",
               UriParserSemanticException.MessageKeys.PREVIOUS_PART_TYPED));
         }
-        prevType = Parser.getTypeInformation((UriResourcePartTyped) last);
+        prevType = ParserHelper.getTypeInformation((UriResourcePartTyped) last);
       }
 
       final FullQualifiedName finalTypeName = prevType.getFullQualifiedName();
@@ -2195,8 +2173,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
       EdmAction action = edm.getBoundAction(fullName, finalTypeName, null);
 
       if (action != null) {
-        UriResourceActionImpl uriAction = new UriResourceActionImpl();
-        uriAction.setAction(action);
+        UriResourceActionImpl uriAction = new UriResourceActionImpl(action);
 
         UriInfoImpl resourcePath = (UriInfoImpl) context.contextSelectItem.getResourcePath();
         resourcePath.addResourcePart(uriAction);
@@ -2206,8 +2183,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
       EdmFunction function = edm.getBoundFunction(fullName, finalTypeName, null, null);
 
       if (function != null) {
-        UriResourceFunctionImpl uriFunction = new UriResourceFunctionImpl();
-        uriFunction.setFunction(function);
+        UriResourceFunctionImpl uriFunction = new UriResourceFunctionImpl(null, function, null);
 
         UriInfoImpl resourcePath = (UriInfoImpl) context.contextSelectItem.getResourcePath();
         resourcePath.addResourcePart(uriFunction);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8091658/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java
index 4b43cd9..37f1b76 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java
@@ -40,10 +40,14 @@ public class UriTokenizer {
     ROOT,
     IT,
 
+    ANY,
+    ALL,
+
     OPEN,
     CLOSE,
     COMMA,
     SEMI,
+    COLON,
     DOT,
     SLASH,
     EQ,
@@ -119,7 +123,10 @@ public class UriTokenizer {
     TotalsecondsMethod,
     ToupperMethod,
     TrimMethod,
-    YearMethod
+    YearMethod,
+
+    AscSuffix,
+    DescSuffix
   }
 
   private final String parseString;
@@ -174,6 +181,13 @@ public class UriTokenizer {
       found = nextConstant("$it");
       break;
 
+    case ANY:
+      found = nextConstant("any");
+      break;
+    case ALL:
+      found = nextConstant("all");
+      break;
+
     case OPEN:
       found = nextCharacter('(');
       break;
@@ -186,6 +200,9 @@ public class UriTokenizer {
     case SEMI:
       found = nextCharacter(';');
       break;
+    case COLON:
+      found = nextCharacter(':');
+      break;
     case DOT:
       found = nextCharacter('.');
       break;
@@ -409,6 +426,14 @@ public class UriTokenizer {
     case YearMethod:
       found = nextMethod("year");
       break;
+
+    // Suffixes
+    case AscSuffix:
+      found = nextSuffix("asc");
+      break;
+    case DescSuffix:
+      found = nextSuffix("desc");
+      break;
     }
 
     if (found) {
@@ -543,6 +568,15 @@ public class UriTokenizer {
   }
 
   /**
+   * Moves past (required) whitespace and the given suffix name if found;
+   * otherwise leaves the index unchanged.
+   * @return whether the suffix has been found at the current index
+   */
+  private boolean nextSuffix(final String suffixName) {
+    return nextWhitespace() && nextConstant(suffixName);
+  }
+
+  /**
    * Moves past an OData identifier if found; otherwise leaves the index unchanged.
    * @return whether an OData identifier has been found at the current index
    */

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8091658/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MemberImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MemberImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MemberImpl.java
index a71e382..6ef37e4 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MemberImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MemberImpl.java
@@ -94,4 +94,9 @@ public class MemberImpl implements Member {
     }
     return false;
   }
+
+  @Override
+  public String toString() {
+    return path.getUriResourceParts().toString() + (startTypeFilter == null ? "" : startTypeFilter);
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8091658/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/UriInfoImplTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/UriInfoImplTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/UriInfoImplTest.java
index 4c76e96..68e6637 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/UriInfoImplTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/UriInfoImplTest.java
@@ -25,6 +25,7 @@ import static org.junit.Assert.assertTrue;
 
 import java.util.Arrays;
 
+import org.apache.olingo.commons.api.edm.EdmAction;
 import org.apache.olingo.commons.api.edm.EdmEntityType;
 import org.apache.olingo.commons.api.ex.ODataRuntimeException;
 import org.apache.olingo.server.api.uri.UriInfo;
@@ -33,9 +34,6 @@ import org.apache.olingo.server.api.uri.UriResourceAction;
 import org.apache.olingo.server.api.uri.UriResourceEntitySet;
 import org.apache.olingo.server.api.uri.queryoption.AliasQueryOption;
 import org.apache.olingo.server.api.uri.queryoption.QueryOption;
-import org.apache.olingo.server.core.uri.UriInfoImpl;
-import org.apache.olingo.server.core.uri.UriResourceActionImpl;
-import org.apache.olingo.server.core.uri.UriResourceEntitySetImpl;
 import org.apache.olingo.server.core.uri.queryoption.AliasQueryOptionImpl;
 import org.apache.olingo.server.core.uri.queryoption.CountOptionImpl;
 import org.apache.olingo.server.core.uri.queryoption.CustomQueryOptionImpl;
@@ -86,9 +84,9 @@ public class UriInfoImplTest {
   public void resourceParts() {
     UriInfoImpl uriInfo = new UriInfoImpl();
 
-    final UriResourceAction action = new UriResourceActionImpl();
-    final UriResourceEntitySet entitySet0 = new UriResourceEntitySetImpl();
-    final UriResourceEntitySet entitySet1 = new UriResourceEntitySetImpl();
+    final UriResourceAction action = new UriResourceActionImpl((EdmAction) null);
+    final UriResourceEntitySet entitySet0 = new UriResourceEntitySetImpl(null);
+    final UriResourceEntitySet entitySet1 = new UriResourceEntitySetImpl(null);
 
     uriInfo.addResourcePart(action);
     uriInfo.addResourcePart(entitySet0);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8091658/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java
index 183ff22..4ab7fce 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java
@@ -28,6 +28,7 @@ import java.util.Locale;
 import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
 import org.apache.olingo.server.core.uri.parser.UriTokenizer.TokenKind;
+import org.apache.olingo.server.core.uri.validator.UriValidationException;
 import org.junit.Test;
 
 public class ExpressionParserTest {
@@ -127,7 +128,7 @@ public class ExpressionParserTest {
   @Test
   public void unary() throws Exception {
     Expression expression = parseExpression("-5");
-    assertEquals("{MINUS 5}", expression.toString());
+    assertEquals("-5", expression.toString());
 
     assertEquals("{MINUS -1}", parseExpression("--1").toString());
     assertEquals("{MINUS duration'PT1M'}", parseExpression("-duration'PT1M'").toString());
@@ -135,13 +136,13 @@ public class ExpressionParserTest {
     expression = parseExpression("not false");
     assertEquals("{NOT false}", expression.toString());
 
-    wrongExpression("-11:12:13");
+    wrongExpression("not 11:12:13");
   }
 
   @Test
   public void grouping() throws Exception {
     Expression expression = parseExpression("-5 add 5");
-    assertEquals("{{MINUS 5} ADD 5}", expression.toString());
+    assertEquals("{-5 ADD 5}", expression.toString());
 
     expression = parseExpression("-(5 add 5)");
     assertEquals("{MINUS {5 ADD 5}}", expression.toString());
@@ -149,7 +150,7 @@ public class ExpressionParserTest {
 
   @Test
   public void precedence() throws Exception {
-    assertEquals("{{MINUS 1} ADD {2 DIV 3}}", parseExpression("-1 add 2 div 3").toString());
+    assertEquals("{-1 ADD {2 DIV 3}}", parseExpression("-1 add 2 div 3").toString());
     assertEquals("{true OR {{NOT false} AND true}}", parseExpression("true or not false and true").toString());
   }
 
@@ -264,7 +265,8 @@ public class ExpressionParserTest {
     wrongExpression("substring(1,2)");
   }
 
-  private Expression parseMethod(TokenKind kind, String... parameters) throws UriParserException {
+  private Expression parseMethod(TokenKind kind, String... parameters)
+      throws UriParserException, UriValidationException {
     String expressionString = kind.name().substring(0, kind.name().indexOf("Method"))
         .toLowerCase(Locale.ROOT).replace("geo", "geo.") + '(';
     boolean first = true;
@@ -283,9 +285,10 @@ public class ExpressionParserTest {
     return expression;
   }
 
-  private Expression parseExpression(final String expressionString) throws UriParserException {
+  private Expression parseExpression(final String expressionString)
+      throws UriParserException, UriValidationException {
     UriTokenizer tokenizer = new UriTokenizer(expressionString);
-    Expression expression = new ExpressionParser(null, odata).parse(tokenizer);
+    Expression expression = new ExpressionParser(null, odata).parse(tokenizer, null, null);
     assertNotNull(expression);
     assertTrue(tokenizer.next(TokenKind.EOF));
     return expression;
@@ -293,10 +296,12 @@ public class ExpressionParserTest {
 
   private void wrongExpression(final String expressionString) {
     try {
-      new ExpressionParser(null, odata).parse(new UriTokenizer(expressionString));
+      new ExpressionParser(null, odata).parse(new UriTokenizer(expressionString), null, null);
       fail("Expected exception not thrown.");
     } catch (final UriParserException e) {
       assertNotNull(e);
+    } catch (final UriValidationException e) {
+      assertNotNull(e);
     }
   }
 }


[28/30] olingo-odata4 git commit: [OLINGO-834] Fix fit maven pom

Posted by ch...@apache.org.
[OLINGO-834] Fix fit maven pom


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

Branch: refs/heads/master
Commit: 40be3e4a29e72bf5c224c5003a87de25e5ef8d24
Parents: 26080f4
Author: Christian Amend <ch...@sap.com>
Authored: Thu Jan 7 16:16:12 2016 +0100
Committer: Christian Amend <ch...@sap.com>
Committed: Thu Jan 7 16:16:12 2016 +0100

----------------------------------------------------------------------
 fit/pom.xml | 7 -------
 1 file changed, 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/40be3e4a/fit/pom.xml
----------------------------------------------------------------------
diff --git a/fit/pom.xml b/fit/pom.xml
index 516c5f5..34eff39 100644
--- a/fit/pom.xml
+++ b/fit/pom.xml
@@ -208,13 +208,6 @@
       </plugin>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-deploy-plugin</artifactId>
-        <configuration>
-          <skip>true</skip>
-        </configuration>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-dependency-plugin</artifactId>
         <version>2.8</version>
         <executions>


[21/30] olingo-odata4 git commit: [OLINGO-834] $expand parser in Java + clean-up

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8925274c/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java
index c27c960..a94026f 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java
@@ -18,29 +18,19 @@
  */
 package org.apache.olingo.server.core.uri.antlr;
 
-import java.io.UnsupportedEncodingException;
 import java.util.Arrays;
 import java.util.Collections;
 
 import org.apache.olingo.commons.api.edm.Edm;
-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.EdmKeyPropertyRef;
-import org.apache.olingo.commons.api.edm.EdmNavigationProperty;
 import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
-import org.apache.olingo.commons.api.edm.EdmProperty;
 import org.apache.olingo.commons.api.edm.FullQualifiedName;
 import org.apache.olingo.commons.api.format.ContentType;
-import org.apache.olingo.commons.core.Encoder;
-import org.apache.olingo.commons.core.edm.primitivetype.EdmString;
 import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.edmx.EdmxReference;
 import org.apache.olingo.server.api.uri.UriInfoKind;
 import org.apache.olingo.server.api.uri.UriResourceKind;
 import org.apache.olingo.server.api.uri.queryoption.expression.BinaryOperatorKind;
 import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind;
-import org.apache.olingo.server.core.uri.parser.UriParserException;
 import org.apache.olingo.server.core.uri.parser.UriParserSemanticException.MessageKeys;
 import org.apache.olingo.server.core.uri.parser.UriParserSyntaxException;
 import org.apache.olingo.server.core.uri.parser.search.SearchParserException;
@@ -56,19 +46,17 @@ import org.apache.olingo.server.tecsvc.provider.EnumTypeProvider;
 import org.apache.olingo.server.tecsvc.provider.FunctionProvider;
 import org.apache.olingo.server.tecsvc.provider.PropertyProvider;
 import org.apache.olingo.server.tecsvc.provider.TypeDefinitionProvider;
-import org.junit.Ignore;
 import org.junit.Test;
-import org.mockito.Mockito;
 
 public class TestFullResourcePath {
 
   private static final OData oData = OData.newInstance();
+  private static final Edm edm = oData.createServiceMetadata(
+      new EdmTechProvider(), Collections.<EdmxReference> emptyList()).getEdm();
   private final TestUriValidator testUri;
   private final FilterValidator testFilter;
 
   public TestFullResourcePath() {
-    final Edm edm = oData.createServiceMetadata(new EdmTechProvider(), Collections.<EdmxReference> emptyList())
-        .getEdm();
     testUri = new TestUriValidator().setEdm(edm);
     testFilter = new FilterValidator().setEdm(edm);
   }
@@ -1033,16 +1021,10 @@ public class TestFullResourcePath {
   public void resourcePathWithApostrophe() throws Exception {
     testUri.runEx("ESAllPrim'").isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
     testUri.runEx("ESAllPrim'InvalidStuff").isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
-
-    testFilter.runOnETKeyNavEx("PropertyInt16' eq 0")
-        .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION);
-
-    testFilter.runOnETKeyNavEx("PropertyInt16 eq' 0")
-        .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION);
-
+    testFilter.runOnETKeyNavEx("PropertyInt16' eq 0").isExSemantic(MessageKeys.TYPES_NOT_COMPATIBLE);
+    testFilter.runOnETKeyNavEx("PropertyInt16 eq' 0").isExSemantic(MessageKeys.TYPES_NOT_COMPATIBLE);
     testFilter.runOnETKeyNavEx("PropertyInt16 eq 0'")
         .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION);
-
     testFilter.runOnETKeyNavEx("PropertyInt16 eq 'dsd''")
         .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
   }
@@ -1306,13 +1288,13 @@ public class TestFullResourcePath {
 
   @Test
   public void runEsNameParaKeys() throws Exception {
-    testUri.run(encode("ESAllKey(PropertyString='O''Neil',PropertyBoolean=true,PropertyByte=255,"
+    testUri.run("ESAllKey(PropertyString='O''Neil',PropertyBoolean=true,PropertyByte=255,"
         + "PropertySByte=-128,PropertyInt16=-32768,PropertyInt32=-2147483648,"
         + "PropertyInt64=-9223372036854775808,PropertyDecimal=1,PropertyDate=2013-09-25,"
         + "PropertyDateTimeOffset=2002-10-10T12:00:00-05:00,"
         + "PropertyDuration=duration'P50903316DT2H25M4S',"
         + "PropertyGuid=12345678-1234-1234-1234-123456789012,"
-        + "PropertyTimeOfDay=12:34:55)"))
+        + "PropertyTimeOfDay=12:34:55)")
         .isKind(UriInfoKind.resource).goPath()
         .first()
         .isEntitySet("ESAllKey")
@@ -1380,12 +1362,11 @@ public class TestFullResourcePath {
         .isType(EntityTypeProvider.nameETTwoPrim)
         .isTypeFilterOnCollection(EntityTypeProvider.nameETTwoBase);
 
-    // TODO: Keys cannot be specified twice.
-    //testUri.runEx("ESTwoPrim(1)/olingo.odata.test1.ETBase(1)")
-    //    .isExSemantic(MessageKeys.INCOMPATIBLE_TYPE_FILTER);
-
-    //testUri.runEx("ESTwoPrim/olingo.odata.test1.ETBase(1)/olingo.odata.test1.ETTwoBase(1)")
-    //    .isExSemantic(MessageKeys.TYPE_FILTER_NOT_CHAINABLE);
+    // Keys cannot be specified twice.
+    testUri.runEx("ESTwoPrim(1)/olingo.odata.test1.ETBase(1)")
+        .isExSemantic(MessageKeys.KEY_NOT_ALLOWED);
+    testUri.runEx("ESTwoPrim/olingo.odata.test1.ETBase(1)/olingo.odata.test1.ETTwoBase(1)")
+        .isExSemantic(MessageKeys.KEY_NOT_ALLOWED);
 
     testUri.runEx("ESBase/olingo.odata.test1.ETTwoPrim(1)").isExSemantic(MessageKeys.INCOMPATIBLE_TYPE_FILTER);
   }
@@ -2321,8 +2302,7 @@ public class TestFullResourcePath {
   }
 
   @Test
-  public void runExpand() throws Exception {
-
+  public void expandStar() throws Exception {
     testUri.run("ESKeyNav(1)", "$expand=*")
         .isKind(UriInfoKind.resource).goPath().goExpand()
         .first()
@@ -2353,7 +2333,10 @@ public class TestFullResourcePath {
         .first()
         .isSegmentStar()
         .isLevelText("max");
+  }
 
+  @Test
+  public void expandNavigationRef() throws Exception {
     testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany/$ref")
         .isKind(UriInfoKind.resource).goPath().goExpand()
         .first()
@@ -2441,7 +2424,10 @@ public class TestFullResourcePath {
         .goUpExpandValidator()
         .isSkipText("1")
         .isTopText("3");
+  }
 
+  @Test
+  public void expandNavigationCount() throws Exception {
     testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany/$count")
         .isKind(UriInfoKind.resource).goPath().goExpand()
         .first()
@@ -2467,7 +2453,10 @@ public class TestFullResourcePath {
         .n().isCount()
         .goUpExpandValidator()
         .isFilterSerialized("<<PropertyInt16> gt <1>>");
+  }
 
+  @Test
+  public void expandNavigationOptions() throws Exception {
     testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany($filter=PropertyInt16 eq 1)")
         .isKind(UriInfoKind.resource).goPath().goExpand()
         .first()
@@ -2521,7 +2510,6 @@ public class TestFullResourcePath {
         .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true)
         .isType(EntityTypeProvider.nameETKeyNav, true)
         .goUpExpandValidator()
-        .isSelectText("PropertyString")
         .goSelectItem(0).isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
 
     testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany($expand=NavPropertyETTwoKeyNavOne)")
@@ -2562,7 +2550,6 @@ public class TestFullResourcePath {
         .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true)
         .isType(EntityTypeProvider.nameETKeyNav, true)
         .goUpExpandValidator()
-        .isSelectText("PropertyString")
         .goSelectItem(0).isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
 
     testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavOne($levels=max)")
@@ -2594,6 +2581,12 @@ public class TestFullResourcePath {
         .isSkipText("1")
         .isTopText("2");
 
+    testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany($search=Country AND Western)")
+        .isKind(UriInfoKind.resource).goPath().goExpand()
+        .first().goPath().first().isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true)
+        .goUpExpandValidator()
+        .isSearchSerialized("{'Country' AND 'Western'}");
+
     testUri.run("ESTwoKeyNav(PropertyInt16=1,PropertyString='Hugo')", "$expand=NavPropertyETKeyNavMany")
         .isKind(UriInfoKind.resource).goPath()
         .first()
@@ -2604,7 +2597,10 @@ public class TestFullResourcePath {
         .goPath().first()
         .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true)
         .isType(EntityTypeProvider.nameETKeyNav, true);
+  }
 
+  @Test
+  public void expandTypeCasts() throws Exception {
     testUri.run("ESTwoKeyNav", "$expand=olingo.odata.test1.ETBaseTwoKeyNav/NavPropertyETKeyNavMany")
         .isKind(UriInfoKind.resource).goPath().first()
         .goExpand().first()
@@ -2635,15 +2631,13 @@ public class TestFullResourcePath {
         .isNavProperty("NavPropertyETTwoKeyNavMany", EntityTypeProvider.nameETTwoKeyNav, true);
 
     testUri.run("ESTwoKeyNav(PropertyInt16=1,PropertyString='2')",
-        "$expand=olingo.odata.test1.ETBaseTwoKeyNav"
-            + "/NavPropertyETTwoKeyNavMany/olingo.odata.test1.ETTwoBaseTwoKeyNav")
+        "$expand=olingo.odata.test1.ETBaseTwoKeyNav/NavPropertyETTwoKeyNavMany/olingo.odata.test1.ETTwoBaseTwoKeyNav")
         .isKind(UriInfoKind.resource).goPath().first()
         .isKeyPredicate(0, "PropertyInt16", "1")
         .isKeyPredicate(1, "PropertyString", "'2'")
         .goExpand().first()
         .isExpandStartType(EntityTypeProvider.nameETBaseTwoKeyNav)
         .goPath().first()
-        .isType(EntityTypeProvider.nameETTwoKeyNav)
         .isNavProperty("NavPropertyETTwoKeyNavMany", EntityTypeProvider.nameETTwoKeyNav, true)
         .isTypeFilterOnCollection(EntityTypeProvider.nameETTwoBaseTwoKeyNav);
 
@@ -2724,7 +2718,6 @@ public class TestFullResourcePath {
         .isNavProperty("NavPropertyETKeyNavOne", EntityTypeProvider.nameETKeyNav, false)
         .isType(EntityTypeProvider.nameETKeyNav)
         .goUpExpandValidator()
-        .isSelectText("PropertyInt16")
         .goSelectItem(0).isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
 
     testUri.run("ESKeyNav", "$expand=NavPropertyETKeyNavOne($select=PropertyCompNav/PropertyInt16)")
@@ -2735,7 +2728,9 @@ public class TestFullResourcePath {
         .isNavProperty("NavPropertyETKeyNavOne", EntityTypeProvider.nameETKeyNav, false)
         .isType(EntityTypeProvider.nameETKeyNav)
         .goUpExpandValidator()
-        .isSelectText("PropertyCompNav/PropertyInt16");
+        .goSelectItem(0)
+        .first().isComplexProperty("PropertyCompNav", ComplexTypeProvider.nameCTNavFiveProp, false)
+        .n().isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
 
     testUri.runEx("ESKeyNav", "$expand=undefined")
         .isExSemantic(MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
@@ -2744,7 +2739,7 @@ public class TestFullResourcePath {
   }
 
   @Test
-  public void runDuplicatedSystemQueryOptionsInExpand() throws UriParserException, UriValidationException {
+  public void duplicatedSystemQueryOptionsInExpand() throws Exception {
     testUri.runEx("ESKeyNav", "$expand=NavPropertyETKeyNavOne($select=PropertyInt16;$select=PropertyInt16)")
         .isExSyntax(UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION);
 
@@ -2768,11 +2763,7 @@ public class TestFullResourcePath {
 
     testUri.runEx("ESKeyNav", "$expand=NavPropertyETKeyNavOne($skip=2;$skip=2)")
         .isExSyntax(UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION);
-  }
 
-  @Test
-  @Ignore("$search in expand currently not implemented")
-  public void duplicatedSearchExpand() throws Exception {
     testUri.runEx("ESKeyNav", "$expand=NavPropertyETKeyNavOne($search=Test;$search=Test)")
         .isExSyntax(UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION);
   }
@@ -2906,8 +2897,7 @@ public class TestFullResourcePath {
   }
 
   @Test
-  public void runTop() throws Exception {
-    // top
+  public void top() throws Exception {
     testUri.run("ESKeyNav", "$top=1")
         .isKind(UriInfoKind.resource).goPath()
         .isEntitySet("ESKeyNav")
@@ -2918,20 +2908,16 @@ public class TestFullResourcePath {
         .isEntitySet("ESKeyNav")
         .isTopText("0");
 
-    testUri.run("ESKeyNav", "$top=-3")
-        .isKind(UriInfoKind.resource).goPath()
-        .isEntitySet("ESKeyNav")
-        .isTopText("-3");
-
     testUri.runEx("ESKeyNav", "$top=undefined")
         .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION);
     testUri.runEx("ESKeyNav", "$top=")
         .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION);
+    testUri.runEx("ESKeyNav", "$top=-3")
+        .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION);
   }
 
   @Test
-  public void runFormat() throws Exception {
-    // format
+  public void format() throws Exception {
     testUri.run("ESKeyNav(1)", "$format=atom")
         .isKind(UriInfoKind.resource).goPath()
         .isFormatText("atom");
@@ -2963,8 +2949,7 @@ public class TestFullResourcePath {
   }
 
   @Test
-  public void runCount() throws Exception {
-    // count
+  public void count() throws Exception {
     testUri.run("ESAllPrim", "$count=true")
         .isKind(UriInfoKind.resource).goPath()
         .isInlineCountText("true");
@@ -2979,20 +2964,19 @@ public class TestFullResourcePath {
 
   @Test
   public void skip() throws Exception {
-    // skip
     testUri.run("ESAllPrim", "$skip=3")
         .isKind(UriInfoKind.resource).goPath()
         .isSkipText("3");
     testUri.run("ESAllPrim", "$skip=0")
         .isKind(UriInfoKind.resource).goPath()
         .isSkipText("0");
-    testUri.run("ESAllPrim", "$skip=-3")
-        .isKind(UriInfoKind.resource).goPath()
-        .isSkipText("-3");
+
     testUri.runEx("ESAllPrim", "$skip=F")
         .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION);
     testUri.runEx("ESAllPrim", "$skip=")
         .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION);
+    testUri.runEx("ESAllPrim", "$skip=-3")
+        .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION);
   }
 
   @Test
@@ -3000,6 +2984,9 @@ public class TestFullResourcePath {
     testUri.run("ESAllPrim", "$skiptoken=foo")
         .isKind(UriInfoKind.resource).goPath()
         .isSkipTokenText("foo");
+
+    testUri.runEx("ESAllPrim", "$skiptoken=")
+        .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION);
   }
 
   @Test
@@ -3010,7 +2997,6 @@ public class TestFullResourcePath {
 
   @Test
   public void misc() throws Exception {
-
     testUri.run("")
         .isKind(UriInfoKind.service);
     testUri.run("/")
@@ -3227,56 +3213,47 @@ public class TestFullResourcePath {
         .isType(EntityTypeProvider.nameETTwoKeyNav)
         .isTypeFilterOnEntry(EntityTypeProvider.nameETBaseTwoKeyNav)
         .n().isValue();
-
   }
 
-  // TODO
   @Test
   public void filter() throws Exception {
+    testFilter.runOnETAllPrim("PropertyBoolean")
+        .is("<PropertyBoolean>")
+        .isType(PropertyProvider.nameBoolean);
 
-    testFilter.runOnETTwoKeyNav("PropertyString")
-        .is("<PropertyString>")
-        .isType(PropertyProvider.nameString);
-
-    testFilter.runOnETTwoKeyNav("PropertyComp/PropertyInt16")
-        .is("<PropertyComp/PropertyInt16>")
-        .isType(PropertyProvider.nameInt16);
+    testFilter.runOnETTwoKeyNav("PropertyComp/PropertyInt16 gt 0")
+        .is("<<PropertyComp/PropertyInt16> gt <0>>")
+        .left().isType(PropertyProvider.nameInt16);
 
-    testFilter.runOnETTwoKeyNav("PropertyComp/PropertyComp/PropertyDate")
-        .is("<PropertyComp/PropertyComp/PropertyDate>")
-        .isType(PropertyProvider.nameDate);
+    testFilter.runOnETTwoKeyNav("PropertyComp/PropertyComp/PropertyDate ne null")
+        .is("<<PropertyComp/PropertyComp/PropertyDate> ne <null>>")
+        .left().isType(PropertyProvider.nameDate);
 
-    testFilter.runOnETTwoKeyNav("NavPropertyETTwoKeyNavOne")
-        .is("<NavPropertyETTwoKeyNavOne>")
-        .isType(EntityTypeProvider.nameETTwoKeyNav);
+    testFilter.runOnETTwoKeyNav("NavPropertyETTwoKeyNavOne eq null")
+        .is("<<NavPropertyETTwoKeyNavOne> eq <null>>")
+        .left().isType(EntityTypeProvider.nameETTwoKeyNav);
 
-    testFilter.runOnETTwoKeyNav("NavPropertyETTwoKeyNavOne/PropertyString")
-        .is("<NavPropertyETTwoKeyNavOne/PropertyString>")
-        .isType(PropertyProvider.nameString);
-
-    testFilter.runOnETTwoKeyNav("NavPropertyETTwoKeyNavOne/PropertyComp")
-        .is("<NavPropertyETTwoKeyNavOne/PropertyComp>")
-        .isType(ComplexTypeProvider.nameCTPrimComp);
+    testFilter.runOnETTwoKeyNav("NavPropertyETTwoKeyNavOne/PropertyString eq ''")
+        .is("<<NavPropertyETTwoKeyNavOne/PropertyString> eq <''>>")
+        .left().isType(PropertyProvider.nameString);
 
-    testFilter.runOnETTwoKeyNav("NavPropertyETTwoKeyNavOne/PropertyComp/PropertyComp")
-        .is("<NavPropertyETTwoKeyNavOne/PropertyComp/PropertyComp>")
-        .isType(ComplexTypeProvider.nameCTAllPrim);
+    testFilter.runOnETTwoKeyNav("NavPropertyETTwoKeyNavOne/PropertyComp eq null")
+        .is("<<NavPropertyETTwoKeyNavOne/PropertyComp> eq <null>>")
+        .left().isType(ComplexTypeProvider.nameCTPrimComp);
 
-    testFilter.runOnETTwoKeyNav("NavPropertyETTwoKeyNavOne/PropertyComp/PropertyInt16")
-        .is("<NavPropertyETTwoKeyNavOne/PropertyComp/PropertyInt16>")
-        .isType(PropertyProvider.nameInt16);
+    testFilter.runOnETTwoKeyNav("NavPropertyETTwoKeyNavOne/PropertyComp/PropertyComp eq null")
+        .is("<<NavPropertyETTwoKeyNavOne/PropertyComp/PropertyComp> eq <null>>")
+        .left().isType(ComplexTypeProvider.nameCTAllPrim);
 
     testFilter.runOnETTwoKeyNav("NavPropertyETTwoKeyNavOne/PropertyComp/PropertyInt16 eq 1")
         .is("<<NavPropertyETTwoKeyNavOne/PropertyComp/PropertyInt16> eq <1>>")
-        .root().left()
-        .isType(PropertyProvider.nameInt16)
-        .root().right()
-        .isLiteral("1");
+        .left().isType(PropertyProvider.nameInt16)
+        .root().right().isLiteral("1");
 
     testFilter.runOnETTwoKeyNav("NavPropertyETKeyNavMany(1)/NavPropertyETTwoKeyNavMany(PropertyString='2')/"
         + "PropertyString eq 'SomeString'")
         .is("<<NavPropertyETKeyNavMany/NavPropertyETTwoKeyNavMany/PropertyString> eq <'SomeString'>>")
-        .root().left()
+        .left()
         .isType(PropertyProvider.nameString)
         .isMember().goPath()
         .first()
@@ -3293,7 +3270,7 @@ public class TestFullResourcePath {
 
     testFilter.runOnETTwoKeyNav("olingo.odata.test1.ETBaseTwoKeyNav/PropertyDate eq 2013-11-12")
         .is("<<PropertyDate> eq <2013-11-12>>")
-        .root().left()
+        .left()
         .isType(PropertyProvider.nameDate)
         .isMember().isMemberStartType(EntityTypeProvider.nameETBaseTwoKeyNav).goPath()
         .first().isPrimitiveProperty("PropertyDate", PropertyProvider.nameDate, false)
@@ -3303,7 +3280,7 @@ public class TestFullResourcePath {
 
     testFilter.runOnCTTwoPrim("olingo.odata.test1.CTBase/AdditionalPropString eq 'SomeString'")
         .is("<<AdditionalPropString> eq <'SomeString'>>")
-        .root().left()
+        .left()
         .isType(PropertyProvider.nameString)
         .isMember().isMemberStartType(ComplexTypeProvider.nameCTBase).goPath()
         .first().isPrimitiveProperty("AdditionalPropString", PropertyProvider.nameString, false)
@@ -3314,7 +3291,7 @@ public class TestFullResourcePath {
     testFilter
         .runOnETTwoKeyNav("NavPropertyETTwoKeyNavOne/olingo.odata.test1.ETBaseTwoKeyNav/PropertyDate eq 2013-11-12")
         .is("<<NavPropertyETTwoKeyNavOne/olingo.odata.test1.ETBaseTwoKeyNav/PropertyDate> eq <2013-11-12>>")
-        .root().left()
+        .left()
         .isType(PropertyProvider.nameDate)
         .root().right()
         .isLiteral("2013-11-12");
@@ -3322,20 +3299,15 @@ public class TestFullResourcePath {
     testFilter
         .runOnETTwoKeyNav("PropertyCompTwoPrim/olingo.odata.test1.CTTwoBase/AdditionalPropString eq 'SomeString'")
         .is("<<PropertyCompTwoPrim/olingo.odata.test1.CTTwoBase/AdditionalPropString> eq <'SomeString'>>")
-        .root().left()
+        .left()
         .isType(PropertyProvider.nameString)
         .root().right()
         .isLiteral("'SomeString'");
 
-    testFilter.runOnETTwoKeyNavEx("invalid")
-        .isExSemantic(MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
-    // TODO: This should throw an exception because the top node of the filter tree must be boolean.
-    // testFilter.runOnETTwoKeyNavEx("PropertyComp")
-    //     .isExSemantic(MessageKeys.UNKNOWN_TYPE);
-    testFilter.runOnETTwoKeyNavEx("PropertyComp/invalid")
-        .isExSemantic(MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
-    testFilter.runOnETTwoKeyNavEx("concat('a','b')/invalid")
-        .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION);
+    testFilter.runOnETTwoKeyNavEx("invalid").isExSemantic(MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
+    testFilter.runOnETTwoKeyNavEx("PropertyComp").isExSemantic(MessageKeys.TYPES_NOT_COMPATIBLE);
+    testFilter.runOnETTwoKeyNavEx("PropertyComp/invalid").isExSemantic(MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
+    testFilter.runOnETTwoKeyNavEx("concat('a','b')/invalid").isExSemantic(MessageKeys.TYPES_NOT_COMPATIBLE);
     testFilter.runOnETTwoKeyNavEx("PropertyComp/concat('a','b')")
         .isExSemantic(MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
     testFilter.runOnETTwoKeyNavEx("PropertyComp/PropertyInt16 eq '1'")
@@ -3347,437 +3319,307 @@ public class TestFullResourcePath {
     testFilter.runOnETTwoKeyNavEx("PropertyComp/PropertyInt64 eq 1")
         .isExSemantic(MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
     testFilter.runOnETTwoKeyNavEx("NavPropertyETKeyNavMany/PropertyInt16 gt 42")
-        .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION);
+        .isExSemantic(MessageKeys.TYPES_NOT_COMPATIBLE);
     testFilter.runOnETTwoKeyNavEx("NavPropertyETKeyNavMany/NavPropertyETTwoKeyNavOne eq null")
-        .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION);
+        .isExSemantic(MessageKeys.TYPES_NOT_COMPATIBLE);
+  }
 
+  @Test
+  public void filterBinaryOperators() throws Exception {
     testFilter.runOnETAllPrim("PropertySByte eq PropertySByte")
         .is("<<PropertySByte> eq <PropertySByte>>")
         .isBinary(BinaryOperatorKind.EQ)
-        .root().left()
-        .isType(PropertyProvider.nameSByte)
-        .root().right()
-        .isType(PropertyProvider.nameSByte);
+        .left().isType(PropertyProvider.nameSByte)
+        .root().right().isType(PropertyProvider.nameSByte);
 
     testFilter.runOnETAllPrim("PropertySByte ne PropertySByte")
         .is("<<PropertySByte> ne <PropertySByte>>")
         .isBinary(BinaryOperatorKind.NE)
-        .root().left()
-        .isType(PropertyProvider.nameSByte)
-        .root().right()
-        .isType(PropertyProvider.nameSByte);
-
-    testFilter.runOnETAllPrim("PropertySByte add PropertySByte")
-        .is("<<PropertySByte> add <PropertySByte>>")
-        .root().left()
-        .isType(PropertyProvider.nameSByte)
-        .root().right()
-        .isType(PropertyProvider.nameSByte);
-
-    testFilter.runOnETAllPrim("PropertyByte add PropertyByte")
-        .is("<<PropertyByte> add <PropertyByte>>")
-        .root().left()
-        .isType(PropertyProvider.nameByte)
-        .root().right()
-        .isType(PropertyProvider.nameByte);
-    testFilter.runOnETAllPrim("PropertyInt16 add PropertyInt16")
-        .is("<<PropertyInt16> add <PropertyInt16>>")
-        .root().left()
-        .isType(PropertyProvider.nameInt16)
-        .root().right()
-        .isType(PropertyProvider.nameInt16);
-    testFilter.runOnETAllPrim("PropertyInt32 add PropertyInt32")
-        .is("<<PropertyInt32> add <PropertyInt32>>")
-        .root().left()
-        .isType(PropertyProvider.nameInt32)
-        .root().right()
-        .isType(PropertyProvider.nameInt32);
-
-    testFilter.runOnETAllPrim("PropertyInt64 add PropertyInt64")
-        .is("<<PropertyInt64> add <PropertyInt64>>")
-        .root().left()
-        .isType(PropertyProvider.nameInt64)
-        .root().right()
-        .isType(PropertyProvider.nameInt64);
-    testFilter.runOnETAllPrim("PropertySingle add PropertySingle")
-        .is("<<PropertySingle> add <PropertySingle>>")
-        .root().left()
-        .isType(PropertyProvider.nameSingle)
-        .root().right()
-        .isType(PropertyProvider.nameSingle);
-    testFilter.runOnETAllPrim("PropertyDouble add PropertyDouble")
-        .is("<<PropertyDouble> add <PropertyDouble>>")
-        .root().left()
-        .isType(PropertyProvider.nameDouble)
-        .root().right()
-        .isType(PropertyProvider.nameDouble);
-    testFilter.runOnETAllPrim("PropertyDecimal add PropertyDecimal")
-        .is("<<PropertyDecimal> add <PropertyDecimal>>")
-        .root().left()
-        .isType(PropertyProvider.nameDecimal)
-        .root().right()
-        .isType(PropertyProvider.nameDecimal);
-    testFilter.runOnETAllPrim("PropertySByte add PropertyDecimal")
-        .is("<<PropertySByte> add <PropertyDecimal>>")
-        .root().left()
-        .isType(PropertyProvider.nameSByte)
-        .root().right()
-        .isType(PropertyProvider.nameDecimal);
-    testFilter.runOnETAllPrim("PropertySByte add PropertyInt32")
-        .is("<<PropertySByte> add <PropertyInt32>>")
-        .root().left()
-        .isType(PropertyProvider.nameSByte)
-        .root().right()
-        .isType(PropertyProvider.nameInt32);
-    testFilter.runOnETAllPrim("PropertySByte add PropertyInt64")
-        .is("<<PropertySByte> add <PropertyInt64>>")
-        .root().left()
-        .isType(PropertyProvider.nameSByte)
-        .root().right()
-        .isType(PropertyProvider.nameInt64);
-    testFilter.runOnETAllPrim("PropertyDateTimeOffset add PropertyDuration")
-        .is("<<PropertyDateTimeOffset> add <PropertyDuration>>")
-        .root().left()
-        .isType(PropertyProvider.nameDateTimeOffset)
-        .root().right()
-        .isType(PropertyProvider.nameDuration);
-    testFilter.runOnETAllPrim("PropertyDuration add PropertyDuration")
-        .is("<<PropertyDuration> add <PropertyDuration>>")
-        .root().left()
-        .isType(PropertyProvider.nameDuration)
-        .root().right()
-        .isType(PropertyProvider.nameDuration);
-    testFilter.runOnETAllPrim("PropertyDate add PropertyDuration")
-        .is("<<PropertyDate> add <PropertyDuration>>")
-        .root().left()
-        .isType(PropertyProvider.nameDate)
-        .root().right()
-        .isType(PropertyProvider.nameDuration);
-    testFilter.runOnETAllPrim("PropertySByte sub PropertySByte")
-        .is("<<PropertySByte> sub <PropertySByte>>")
-        .root().left()
-        .isType(PropertyProvider.nameSByte)
-        .root().right()
-        .isType(PropertyProvider.nameSByte);
-    testFilter.runOnETAllPrim("PropertyByte sub PropertyByte")
-        .is("<<PropertyByte> sub <PropertyByte>>")
-        .root().left()
-        .isType(PropertyProvider.nameByte)
-        .root().right()
-        .isType(PropertyProvider.nameByte);
-    testFilter.runOnETAllPrim("PropertyInt16 sub PropertyInt16")
-        .is("<<PropertyInt16> sub <PropertyInt16>>")
-        .root().left()
-        .isType(PropertyProvider.nameInt16)
-        .root().right()
-        .isType(PropertyProvider.nameInt16);
-    testFilter.runOnETAllPrim("PropertyInt32 sub PropertyInt32")
-        .is("<<PropertyInt32> sub <PropertyInt32>>")
-        .root().left()
-        .isType(PropertyProvider.nameInt32)
-        .root().right()
-        .isType(PropertyProvider.nameInt32);
-    testFilter.runOnETAllPrim("PropertyInt64 sub PropertyInt64")
-        .is("<<PropertyInt64> sub <PropertyInt64>>")
-        .root().left()
-        .isType(PropertyProvider.nameInt64)
-        .root().right()
-        .isType(PropertyProvider.nameInt64);
-    testFilter.runOnETAllPrim("PropertySingle sub PropertySingle")
-        .is("<<PropertySingle> sub <PropertySingle>>")
-        .root().left()
-        .isType(PropertyProvider.nameSingle)
-        .root().right()
-        .isType(PropertyProvider.nameSingle);
-    testFilter.runOnETAllPrim("PropertyDouble sub PropertyDouble")
-        .is("<<PropertyDouble> sub <PropertyDouble>>")
-        .root().left()
-        .isType(PropertyProvider.nameDouble)
-        .root().right()
-        .isType(PropertyProvider.nameDouble);
-    testFilter.runOnETAllPrim("PropertyDecimal sub PropertyDecimal")
-        .is("<<PropertyDecimal> sub <PropertyDecimal>>")
-        .root().left()
-        .isType(PropertyProvider.nameDecimal)
-        .root().right()
-        .isType(PropertyProvider.nameDecimal);
-    testFilter.runOnETAllPrim("PropertyDecimal sub PropertyInt32")
-        .is("<<PropertyDecimal> sub <PropertyInt32>>")
-        .root().left()
-        .isType(PropertyProvider.nameDecimal)
-        .root().right()
-        .isType(PropertyProvider.nameInt32);
-    testFilter.runOnETAllPrim("PropertyDecimal sub PropertyInt64")
-        .is("<<PropertyDecimal> sub <PropertyInt64>>")
-        .root().left()
-        .isType(PropertyProvider.nameDecimal)
-        .root().right()
-        .isType(PropertyProvider.nameInt64);
-    testFilter.runOnETAllPrim("PropertyDecimal sub PropertyByte")
-        .is("<<PropertyDecimal> sub <PropertyByte>>")
-        .root().left()
-        .isType(PropertyProvider.nameDecimal)
-        .root().right()
-        .isType(PropertyProvider.nameByte);
-    testFilter.runOnETAllPrim("PropertyDateTimeOffset sub PropertyDuration")
-        .is("<<PropertyDateTimeOffset> sub <PropertyDuration>>")
-        .root().left()
-        .isType(PropertyProvider.nameDateTimeOffset)
-        .root().right()
-        .isType(PropertyProvider.nameDuration);
-    testFilter.runOnETAllPrim("PropertyDuration sub PropertyDuration")
-        .is("<<PropertyDuration> sub <PropertyDuration>>")
-        .root().left()
-        .isType(PropertyProvider.nameDuration)
-        .root().right()
-        .isType(PropertyProvider.nameDuration);
-    testFilter.runOnETAllPrim("PropertyDateTimeOffset sub PropertyDateTimeOffset")
-        .is("<<PropertyDateTimeOffset> sub <PropertyDateTimeOffset>>")
-        .root().left()
-        .isType(PropertyProvider.nameDateTimeOffset)
-        .root().right()
-        .isType(PropertyProvider.nameDateTimeOffset);
-    testFilter.runOnETAllPrim("PropertyDate sub PropertyDuration")
-        .is("<<PropertyDate> sub <PropertyDuration>>")
-        .root().left()
-        .isType(PropertyProvider.nameDate)
-        .root().right()
-        .isType(PropertyProvider.nameDuration);
-    testFilter.runOnETAllPrim("PropertyDate sub PropertyDate")
-        .is("<<PropertyDate> sub <PropertyDate>>")
-        .root().left()
-        .isType(PropertyProvider.nameDate)
-        .root().right()
-        .isType(PropertyProvider.nameDate);
-    testFilter.runOnETAllPrim("PropertySByte mul PropertySByte")
-        .is("<<PropertySByte> mul <PropertySByte>>")
-        .root().left()
-        .isType(PropertyProvider.nameSByte)
-        .root().right()
-        .isType(PropertyProvider.nameSByte);
-    testFilter.runOnETAllPrim("PropertyByte mul PropertyByte")
-        .is("<<PropertyByte> mul <PropertyByte>>")
-        .root().left()
-        .isType(PropertyProvider.nameByte)
-        .root().right()
-        .isType(PropertyProvider.nameByte);
-    testFilter.runOnETAllPrim("PropertyInt16 mul PropertyInt16")
-        .is("<<PropertyInt16> mul <PropertyInt16>>")
-        .root().left()
-        .isType(PropertyProvider.nameInt16)
-        .root().right()
-        .isType(PropertyProvider.nameInt16);
-    testFilter.runOnETAllPrim("PropertyInt32 mul PropertyInt32")
-        .is("<<PropertyInt32> mul <PropertyInt32>>")
-        .root().left()
-        .isType(PropertyProvider.nameInt32)
-        .root().right()
-        .isType(PropertyProvider.nameInt32);
-    testFilter.runOnETAllPrim("PropertyInt64 mul PropertyInt64")
-        .is("<<PropertyInt64> mul <PropertyInt64>>")
-        .root().left()
-        .isType(PropertyProvider.nameInt64)
-        .root().right()
-        .isType(PropertyProvider.nameInt64);
-    testFilter.runOnETAllPrim("PropertySingle mul PropertySingle")
-        .is("<<PropertySingle> mul <PropertySingle>>")
-        .root().left()
-        .isType(PropertyProvider.nameSingle)
-        .root().right()
-        .isType(PropertyProvider.nameSingle);
-    testFilter.runOnETAllPrim("PropertyDouble mul PropertyDouble")
-        .is("<<PropertyDouble> mul <PropertyDouble>>")
-        .root().left()
-        .isType(PropertyProvider.nameDouble)
-        .root().right()
-        .isType(PropertyProvider.nameDouble);
-    testFilter.runOnETAllPrim("PropertyDecimal mul PropertyDecimal")
-        .is("<<PropertyDecimal> mul <PropertyDecimal>>")
-        .root().left()
-        .isType(PropertyProvider.nameDecimal)
-        .root().right()
-        .isType(PropertyProvider.nameDecimal);
-    testFilter.runOnETAllPrim("PropertyInt64 mul PropertyInt32")
-        .is("<<PropertyInt64> mul <PropertyInt32>>")
-        .root().left()
-        .isType(PropertyProvider.nameInt64)
-        .root().right()
-        .isType(PropertyProvider.nameInt32);
-    testFilter.runOnETAllPrim("PropertyInt64 mul PropertySByte")
-        .is("<<PropertyInt64> mul <PropertySByte>>")
-        .root().left()
-        .isType(PropertyProvider.nameInt64)
-        .root().right()
-        .isType(PropertyProvider.nameSByte);
-    testFilter.runOnETAllPrim("PropertyInt64 mul PropertyDecimal")
-        .is("<<PropertyInt64> mul <PropertyDecimal>>")
-        .root().left()
-        .isType(PropertyProvider.nameInt64)
-        .root().right()
-        .isType(PropertyProvider.nameDecimal);
-    testFilter.runOnETAllPrim("PropertySByte div PropertySByte")
-        .is("<<PropertySByte> div <PropertySByte>>")
-        .root().left()
-        .isType(PropertyProvider.nameSByte)
-        .root().right()
-        .isType(PropertyProvider.nameSByte);
-    testFilter.runOnETAllPrim("PropertyByte div PropertyByte")
-        .is("<<PropertyByte> div <PropertyByte>>")
-        .root().left()
-        .isType(PropertyProvider.nameByte)
-        .root().right()
-        .isType(PropertyProvider.nameByte);
-    testFilter.runOnETAllPrim("PropertyInt16 div PropertyInt16")
-        .is("<<PropertyInt16> div <PropertyInt16>>")
-        .root().left()
-        .isType(PropertyProvider.nameInt16)
-        .root().right()
-        .isType(PropertyProvider.nameInt16);
-    testFilter.runOnETAllPrim("PropertyInt32 div PropertyInt32")
-        .is("<<PropertyInt32> div <PropertyInt32>>")
-        .root().left()
-        .isType(PropertyProvider.nameInt32)
-        .root().right()
-        .isType(PropertyProvider.nameInt32);
-    testFilter.runOnETAllPrim("PropertyInt64 div PropertyInt64")
-        .is("<<PropertyInt64> div <PropertyInt64>>")
-        .root().left()
-        .isType(PropertyProvider.nameInt64)
-        .root().right()
-        .isType(PropertyProvider.nameInt64);
-    testFilter.runOnETAllPrim("PropertySingle div PropertySingle")
-        .is("<<PropertySingle> div <PropertySingle>>")
-        .root().left()
-        .isType(PropertyProvider.nameSingle)
-        .root().right()
-        .isType(PropertyProvider.nameSingle);
-    testFilter.runOnETAllPrim("PropertyDouble div PropertyDouble")
-        .is("<<PropertyDouble> div <PropertyDouble>>")
-        .root().left()
-        .isType(PropertyProvider.nameDouble)
-        .root().right()
-        .isType(PropertyProvider.nameDouble);
-    testFilter.runOnETAllPrim("PropertyDecimal div PropertyDecimal")
-        .is("<<PropertyDecimal> div <PropertyDecimal>>")
-        .root().left()
-        .isType(PropertyProvider.nameDecimal)
-        .root().right()
-        .isType(PropertyProvider.nameDecimal);
-    testFilter.runOnETAllPrim("PropertyByte div PropertyInt32")
-        .is("<<PropertyByte> div <PropertyInt32>>")
-        .root().left()
-        .isType(PropertyProvider.nameByte)
-        .root().right()
-        .isType(PropertyProvider.nameInt32);
-    testFilter.runOnETAllPrim("PropertyByte div PropertyDecimal")
-        .is("<<PropertyByte> div <PropertyDecimal>>")
-        .root().left()
-        .isType(PropertyProvider.nameByte)
-        .root().right()
-        .isType(PropertyProvider.nameDecimal);
-    testFilter.runOnETAllPrim("PropertyByte div PropertySByte")
-        .is("<<PropertyByte> div <PropertySByte>>")
-        .root().left()
-        .isType(PropertyProvider.nameByte)
-        .root().right()
-        .isType(PropertyProvider.nameSByte);
-
-    testFilter.runOnETAllPrim("PropertyByte div 0")
-        .is("<<PropertyByte> div <0>>");
-
-    testFilter.runOnETAllPrim("0 div 0")
-        .is("<<0> div <0>>");
-
-    testFilter.runOnETAllPrim("PropertySByte mod PropertySByte")
-        .is("<<PropertySByte> mod <PropertySByte>>")
-        .root().left()
-        .isType(PropertyProvider.nameSByte)
-        .root().right()
-        .isType(PropertyProvider.nameSByte);
-    testFilter.runOnETAllPrim("PropertyByte mod PropertyByte")
-        .is("<<PropertyByte> mod <PropertyByte>>")
-        .root().left()
-        .isType(PropertyProvider.nameByte)
-        .root().right()
-        .isType(PropertyProvider.nameByte);
-    testFilter.runOnETAllPrim("PropertyInt16 mod PropertyInt16")
-        .is("<<PropertyInt16> mod <PropertyInt16>>")
-        .root().left()
-        .isType(PropertyProvider.nameInt16)
-        .root().right()
-        .isType(PropertyProvider.nameInt16);
-    testFilter.runOnETAllPrim("PropertyInt32 mod PropertyInt32")
-        .is("<<PropertyInt32> mod <PropertyInt32>>")
-        .root().left()
-        .isType(PropertyProvider.nameInt32)
-        .root().right()
-        .isType(PropertyProvider.nameInt32);
-    testFilter.runOnETAllPrim("PropertyInt64 mod PropertyInt64")
-        .is("<<PropertyInt64> mod <PropertyInt64>>")
-        .root().left()
-        .isType(PropertyProvider.nameInt64)
-        .root().right()
-        .isType(PropertyProvider.nameInt64);
-    testFilter.runOnETAllPrim("PropertySingle mod PropertySingle")
-        .is("<<PropertySingle> mod <PropertySingle>>")
-        .root().left()
-        .isType(PropertyProvider.nameSingle)
-        .root().right()
-        .isType(PropertyProvider.nameSingle);
-    testFilter.runOnETAllPrim("PropertyDouble mod PropertyDouble")
-        .is("<<PropertyDouble> mod <PropertyDouble>>")
-        .root().left()
-        .isType(PropertyProvider.nameDouble)
-        .root().right()
-        .isType(PropertyProvider.nameDouble);
-    testFilter.runOnETAllPrim("PropertyDecimal mod PropertyDecimal")
-        .is("<<PropertyDecimal> mod <PropertyDecimal>>")
-        .root().left()
-        .isType(PropertyProvider.nameDecimal)
-        .root().right()
-        .isType(PropertyProvider.nameDecimal);
+        .left().isType(PropertyProvider.nameSByte)
+        .root().right().isType(PropertyProvider.nameSByte);
+
+    testFilter.runOnETAllPrim("PropertySByte add PropertySByte gt 0")
+        .is("<<<PropertySByte> add <PropertySByte>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameSByte)
+        .root().left().right().isType(PropertyProvider.nameSByte);
+
+    testFilter.runOnETAllPrim("PropertyByte add PropertyByte gt 0")
+        .is("<<<PropertyByte> add <PropertyByte>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameByte)
+        .root().left().right().isType(PropertyProvider.nameByte);
+    testFilter.runOnETAllPrim("PropertyInt16 add PropertyInt16 gt 0")
+        .is("<<<PropertyInt16> add <PropertyInt16>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameInt16)
+        .root().left().right().isType(PropertyProvider.nameInt16);
+    testFilter.runOnETAllPrim("PropertyInt32 add PropertyInt32 gt 0")
+        .is("<<<PropertyInt32> add <PropertyInt32>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameInt32)
+        .root().left().right().isType(PropertyProvider.nameInt32);
+    testFilter.runOnETAllPrim("PropertyInt64 add PropertyInt64 gt 0")
+        .is("<<<PropertyInt64> add <PropertyInt64>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameInt64)
+        .root().left().right().isType(PropertyProvider.nameInt64);
+    testFilter.runOnETAllPrim("PropertySingle add PropertySingle gt 0")
+        .is("<<<PropertySingle> add <PropertySingle>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameSingle)
+        .root().left().right().isType(PropertyProvider.nameSingle);
+    testFilter.runOnETAllPrim("PropertyDouble add PropertyDouble gt 0")
+        .is("<<<PropertyDouble> add <PropertyDouble>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameDouble)
+        .root().left().right().isType(PropertyProvider.nameDouble);
+    testFilter.runOnETAllPrim("PropertyDecimal add PropertyDecimal gt 0")
+        .is("<<<PropertyDecimal> add <PropertyDecimal>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameDecimal)
+        .root().left().right().isType(PropertyProvider.nameDecimal);
+    testFilter.runOnETAllPrim("PropertySByte add PropertyDecimal gt 0")
+        .is("<<<PropertySByte> add <PropertyDecimal>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameSByte)
+        .root().left().right().isType(PropertyProvider.nameDecimal);
+    testFilter.runOnETAllPrim("PropertySByte add PropertyInt32 gt 0")
+        .is("<<<PropertySByte> add <PropertyInt32>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameSByte)
+        .root().left().right().isType(PropertyProvider.nameInt32);
+    testFilter.runOnETAllPrim("PropertySByte add PropertyInt64 gt 0")
+        .is("<<<PropertySByte> add <PropertyInt64>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameSByte)
+        .root().left().right().isType(PropertyProvider.nameInt64);
+    testFilter.runOnETAllPrim("PropertyDateTimeOffset add PropertyDuration ne null")
+        .is("<<<PropertyDateTimeOffset> add <PropertyDuration>> ne <null>>")
+        .left().left().isType(PropertyProvider.nameDateTimeOffset)
+        .root().left().right().isType(PropertyProvider.nameDuration);
+    testFilter.runOnETAllPrim("PropertyDuration add PropertyDuration ne null")
+        .is("<<<PropertyDuration> add <PropertyDuration>> ne <null>>")
+        .left().left().isType(PropertyProvider.nameDuration)
+        .root().left().right().isType(PropertyProvider.nameDuration);
+    testFilter.runOnETAllPrim("PropertyDate add PropertyDuration ne null")
+        .is("<<<PropertyDate> add <PropertyDuration>> ne <null>>")
+        .left().left().isType(PropertyProvider.nameDate)
+        .root().left().right().isType(PropertyProvider.nameDuration);
+    testFilter.runOnETAllPrim("PropertySByte sub PropertySByte gt 0")
+        .is("<<<PropertySByte> sub <PropertySByte>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameSByte)
+        .root().left().right().isType(PropertyProvider.nameSByte);
+    testFilter.runOnETAllPrim("PropertyByte sub PropertyByte gt 0")
+        .is("<<<PropertyByte> sub <PropertyByte>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameByte)
+        .root().left().right().isType(PropertyProvider.nameByte);
+    testFilter.runOnETAllPrim("PropertyInt16 sub PropertyInt16 gt 0")
+        .is("<<<PropertyInt16> sub <PropertyInt16>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameInt16)
+        .root().left().right().isType(PropertyProvider.nameInt16);
+    testFilter.runOnETAllPrim("PropertyInt32 sub PropertyInt32 gt 0")
+        .is("<<<PropertyInt32> sub <PropertyInt32>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameInt32)
+        .root().left().right().isType(PropertyProvider.nameInt32);
+    testFilter.runOnETAllPrim("PropertyInt64 sub PropertyInt64 gt 0")
+        .is("<<<PropertyInt64> sub <PropertyInt64>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameInt64)
+        .root().left().right().isType(PropertyProvider.nameInt64);
+    testFilter.runOnETAllPrim("PropertySingle sub PropertySingle gt 0")
+        .is("<<<PropertySingle> sub <PropertySingle>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameSingle)
+        .root().left().right().isType(PropertyProvider.nameSingle);
+    testFilter.runOnETAllPrim("PropertyDouble sub PropertyDouble gt 0")
+        .is("<<<PropertyDouble> sub <PropertyDouble>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameDouble)
+        .root().left().right().isType(PropertyProvider.nameDouble);
+    testFilter.runOnETAllPrim("PropertyDecimal sub PropertyDecimal gt 0")
+        .is("<<<PropertyDecimal> sub <PropertyDecimal>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameDecimal)
+        .root().left().right().isType(PropertyProvider.nameDecimal);
+    testFilter.runOnETAllPrim("PropertyDecimal sub PropertyInt32 gt 0")
+        .is("<<<PropertyDecimal> sub <PropertyInt32>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameDecimal)
+        .root().left().right().isType(PropertyProvider.nameInt32);
+    testFilter.runOnETAllPrim("PropertyDecimal sub PropertyInt64 gt 0")
+        .is("<<<PropertyDecimal> sub <PropertyInt64>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameDecimal)
+        .root().left().right().isType(PropertyProvider.nameInt64);
+    testFilter.runOnETAllPrim("PropertyDecimal sub PropertyByte gt 0")
+        .is("<<<PropertyDecimal> sub <PropertyByte>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameDecimal)
+        .root().left().right().isType(PropertyProvider.nameByte);
+    testFilter.runOnETAllPrim("PropertyDateTimeOffset sub PropertyDuration ne null")
+        .is("<<<PropertyDateTimeOffset> sub <PropertyDuration>> ne <null>>")
+        .left().left().isType(PropertyProvider.nameDateTimeOffset)
+        .root().left().right().isType(PropertyProvider.nameDuration);
+    testFilter.runOnETAllPrim("PropertyDuration sub PropertyDuration ne null")
+        .is("<<<PropertyDuration> sub <PropertyDuration>> ne <null>>")
+        .left().left().isType(PropertyProvider.nameDuration)
+        .root().left().right().isType(PropertyProvider.nameDuration);
+    testFilter.runOnETAllPrim("PropertyDateTimeOffset sub PropertyDateTimeOffset ne null")
+        .is("<<<PropertyDateTimeOffset> sub <PropertyDateTimeOffset>> ne <null>>")
+        .left().left().isType(PropertyProvider.nameDateTimeOffset)
+        .root().left().right().isType(PropertyProvider.nameDateTimeOffset);
+    testFilter.runOnETAllPrim("PropertyDate sub PropertyDuration ne null")
+        .is("<<<PropertyDate> sub <PropertyDuration>> ne <null>>")
+        .left().left().isType(PropertyProvider.nameDate)
+        .root().left().right().isType(PropertyProvider.nameDuration);
+    testFilter.runOnETAllPrim("PropertyDate sub PropertyDate ne null")
+        .is("<<<PropertyDate> sub <PropertyDate>> ne <null>>")
+        .left().left().isType(PropertyProvider.nameDate)
+        .root().left().right().isType(PropertyProvider.nameDate);
+    testFilter.runOnETAllPrim("PropertySByte mul PropertySByte gt 0")
+        .is("<<<PropertySByte> mul <PropertySByte>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameSByte)
+        .root().left().right().isType(PropertyProvider.nameSByte);
+    testFilter.runOnETAllPrim("PropertyByte mul PropertyByte gt 0")
+        .is("<<<PropertyByte> mul <PropertyByte>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameByte)
+        .root().left().right().isType(PropertyProvider.nameByte);
+    testFilter.runOnETAllPrim("PropertyInt16 mul PropertyInt16 gt 0")
+        .is("<<<PropertyInt16> mul <PropertyInt16>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameInt16)
+        .root().left().right().isType(PropertyProvider.nameInt16);
+    testFilter.runOnETAllPrim("PropertyInt32 mul PropertyInt32 gt 0")
+        .is("<<<PropertyInt32> mul <PropertyInt32>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameInt32)
+        .root().left().right().isType(PropertyProvider.nameInt32);
+    testFilter.runOnETAllPrim("PropertyInt64 mul PropertyInt64 gt 0")
+        .is("<<<PropertyInt64> mul <PropertyInt64>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameInt64)
+        .root().left().right().isType(PropertyProvider.nameInt64);
+    testFilter.runOnETAllPrim("PropertySingle mul PropertySingle gt 0")
+        .is("<<<PropertySingle> mul <PropertySingle>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameSingle)
+        .root().left().right().isType(PropertyProvider.nameSingle);
+    testFilter.runOnETAllPrim("PropertyDouble mul PropertyDouble gt 0")
+        .is("<<<PropertyDouble> mul <PropertyDouble>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameDouble)
+        .root().left().right().isType(PropertyProvider.nameDouble);
+    testFilter.runOnETAllPrim("PropertyDecimal mul PropertyDecimal gt 0")
+        .is("<<<PropertyDecimal> mul <PropertyDecimal>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameDecimal)
+        .root().left().right().isType(PropertyProvider.nameDecimal);
+    testFilter.runOnETAllPrim("PropertyInt64 mul PropertyInt32 gt 0")
+        .is("<<<PropertyInt64> mul <PropertyInt32>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameInt64)
+        .root().left().right().isType(PropertyProvider.nameInt32);
+    testFilter.runOnETAllPrim("PropertyInt64 mul PropertySByte gt 0")
+        .is("<<<PropertyInt64> mul <PropertySByte>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameInt64)
+        .root().left().right().isType(PropertyProvider.nameSByte);
+    testFilter.runOnETAllPrim("PropertyInt64 mul PropertyDecimal gt 0")
+        .is("<<<PropertyInt64> mul <PropertyDecimal>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameInt64)
+        .root().left().right().isType(PropertyProvider.nameDecimal);
+    testFilter.runOnETAllPrim("PropertySByte div PropertySByte gt 0")
+        .is("<<<PropertySByte> div <PropertySByte>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameSByte)
+        .root().left().right().isType(PropertyProvider.nameSByte);
+    testFilter.runOnETAllPrim("PropertyByte div PropertyByte gt 0")
+        .is("<<<PropertyByte> div <PropertyByte>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameByte)
+        .root().left().right().isType(PropertyProvider.nameByte);
+    testFilter.runOnETAllPrim("PropertyInt16 div PropertyInt16 gt 0")
+        .is("<<<PropertyInt16> div <PropertyInt16>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameInt16)
+        .root().left().right().isType(PropertyProvider.nameInt16);
+    testFilter.runOnETAllPrim("PropertyInt32 div PropertyInt32 gt 0")
+        .is("<<<PropertyInt32> div <PropertyInt32>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameInt32)
+        .root().left().right().isType(PropertyProvider.nameInt32);
+    testFilter.runOnETAllPrim("PropertyInt64 div PropertyInt64 gt 0")
+        .is("<<<PropertyInt64> div <PropertyInt64>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameInt64)
+        .root().left().right().isType(PropertyProvider.nameInt64);
+    testFilter.runOnETAllPrim("PropertySingle div PropertySingle gt 0")
+        .is("<<<PropertySingle> div <PropertySingle>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameSingle)
+        .root().left().right().isType(PropertyProvider.nameSingle);
+    testFilter.runOnETAllPrim("PropertyDouble div PropertyDouble gt 0")
+        .is("<<<PropertyDouble> div <PropertyDouble>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameDouble)
+        .root().left().right().isType(PropertyProvider.nameDouble);
+    testFilter.runOnETAllPrim("PropertyDecimal div PropertyDecimal gt 0")
+        .is("<<<PropertyDecimal> div <PropertyDecimal>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameDecimal)
+        .root().left().right().isType(PropertyProvider.nameDecimal);
+    testFilter.runOnETAllPrim("PropertyByte div PropertyInt32 gt 0")
+        .is("<<<PropertyByte> div <PropertyInt32>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameByte)
+        .root().left().right().isType(PropertyProvider.nameInt32);
+    testFilter.runOnETAllPrim("PropertyByte div PropertyDecimal gt 0")
+        .is("<<<PropertyByte> div <PropertyDecimal>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameByte)
+        .root().left().right().isType(PropertyProvider.nameDecimal);
+    testFilter.runOnETAllPrim("PropertyByte div PropertySByte gt 0")
+        .is("<<<PropertyByte> div <PropertySByte>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameByte)
+        .root().left().right().isType(PropertyProvider.nameSByte);
+
+    testFilter.runOnETAllPrim("PropertyByte div 0 gt 0")
+        .is("<<<PropertyByte> div <0>> gt <0>>");
+
+    testFilter.runOnETAllPrim("0 div 0 gt 0")
+        .is("<<<0> div <0>> gt <0>>");
+
+    testFilter.runOnETAllPrim("PropertySByte mod PropertySByte gt 0")
+        .is("<<<PropertySByte> mod <PropertySByte>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameSByte)
+        .root().left().right().isType(PropertyProvider.nameSByte);
+    testFilter.runOnETAllPrim("PropertyByte mod PropertyByte gt 0")
+        .is("<<<PropertyByte> mod <PropertyByte>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameByte)
+        .root().left().right().isType(PropertyProvider.nameByte);
+    testFilter.runOnETAllPrim("PropertyInt16 mod PropertyInt16 gt 0")
+        .is("<<<PropertyInt16> mod <PropertyInt16>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameInt16)
+        .root().left().right().isType(PropertyProvider.nameInt16);
+    testFilter.runOnETAllPrim("PropertyInt32 mod PropertyInt32 gt 0")
+        .is("<<<PropertyInt32> mod <PropertyInt32>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameInt32)
+        .root().left().right().isType(PropertyProvider.nameInt32);
+    testFilter.runOnETAllPrim("PropertyInt64 mod PropertyInt64 gt 0")
+        .is("<<<PropertyInt64> mod <PropertyInt64>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameInt64)
+        .root().left().right().isType(PropertyProvider.nameInt64);
+    testFilter.runOnETAllPrim("PropertySingle mod PropertySingle gt 0")
+        .is("<<<PropertySingle> mod <PropertySingle>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameSingle)
+        .root().left().right().isType(PropertyProvider.nameSingle);
+    testFilter.runOnETAllPrim("PropertyDouble mod PropertyDouble gt 0")
+        .is("<<<PropertyDouble> mod <PropertyDouble>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameDouble)
+        .root().left().right().isType(PropertyProvider.nameDouble);
+    testFilter.runOnETAllPrim("PropertyDecimal mod PropertyDecimal gt 0")
+        .is("<<<PropertyDecimal> mod <PropertyDecimal>> gt <0>>")
+        .left().left().isType(PropertyProvider.nameDecimal)
+        .root().left().right().isType(PropertyProvider.nameDecimal);
 
     testFilter.runOnETAllPrim("PropertyDecimal ge PropertyDecimal")
         .is("<<PropertyDecimal> ge <PropertyDecimal>>")
         .isBinary(BinaryOperatorKind.GE)
-        .root().left()
-        .isType(PropertyProvider.nameDecimal)
-        .root().right()
-        .isType(PropertyProvider.nameDecimal);
+        .left().isType(PropertyProvider.nameDecimal)
+        .root().right().isType(PropertyProvider.nameDecimal);
     testFilter.runOnETAllPrim("PropertyDecimal lt PropertyDecimal")
         .is("<<PropertyDecimal> lt <PropertyDecimal>>")
         .isBinary(BinaryOperatorKind.LT)
-        .root().left()
-        .isType(PropertyProvider.nameDecimal)
-        .root().right()
-        .isType(PropertyProvider.nameDecimal);
+        .left().isType(PropertyProvider.nameDecimal)
+        .root().right().isType(PropertyProvider.nameDecimal);
     testFilter.runOnETAllPrim("PropertyDecimal le PropertyDecimal")
         .is("<<PropertyDecimal> le <PropertyDecimal>>")
         .isBinary(BinaryOperatorKind.LE)
-        .root().left()
-        .isType(PropertyProvider.nameDecimal)
-        .root().right()
-        .isType(PropertyProvider.nameDecimal);
+        .left().isType(PropertyProvider.nameDecimal)
+        .root().right().isType(PropertyProvider.nameDecimal);
 
-    // Numeric promotion: Double is considered the widest type
-    testFilter.runOnETAllPrim("PropertyDecimal sub NaN")
+    // Numeric promotion: Double is considered the widest type.
+    testFilter.runOnETAllPrim("PropertyDecimal ne NaN")
         .right().isLiteral("NaN").isType(PropertyProvider.nameDouble);
-    testFilter.runOnETAllPrim("PropertyDecimal sub -INF")
+    testFilter.runOnETAllPrim("PropertyDecimal gt -INF")
         .right().isLiteral("-INF").isType(PropertyProvider.nameDouble);
-    testFilter.runOnETAllPrim("PropertyDecimal sub INF")
+    testFilter.runOnETAllPrim("PropertyDecimal lt INF")
         .right().isLiteral("INF").isType(PropertyProvider.nameDouble);
   }
 
-  // TODO
   @Test
-  @Ignore
   public void filterProperties() throws Exception {
     testFilter.runOnETAllPrim("PropertyBoolean eq true")
         .is("<<PropertyBoolean> eq <true>>")
         .isBinary(BinaryOperatorKind.EQ)
         .root().left().goPath().isPrimitiveProperty("PropertyBoolean", PropertyProvider.nameBoolean, false)
         .goUpFilterValidator()
-        .root().right().isTrue();
+        .root().right().isLiteral("true");
 
     testFilter.runOnETAllPrim("PropertyDecimal eq 1.25")
         .is("<<PropertyDecimal> eq <1.25>>")
@@ -3917,37 +3759,43 @@ public class TestFullResourcePath {
         .first().isComplex("PropertyCompMixedEnumDef")
         .n().isPrimitiveProperty("PropertyEnumString", EnumTypeProvider.nameENString, false);
 
-    testFilter.runOnETAllPrim("PropertyByte mod 0")
-        .is("<<PropertyByte> mod <0>>");
+    testFilter.runOnETAllPrim("PropertyByte mod 0 gt 0")
+        .is("<<<PropertyByte> mod <0>> gt <0>>");
+  }
 
-    testFilter.runOnETAllPrim("olingo.odata.test1.UFCRTETTwoKeyNavParamCTTwoPrim(ParameterCTTwoPrim=@ParamAlias)")
-        .is("<UFCRTETTwoKeyNavParamCTTwoPrim>")
-        .goPath()
+  @Test
+  public void filterFunctions() throws Exception {
+    testFilter.runOnETAllPrim(
+        "olingo.odata.test1.UFCRTETTwoKeyNavParamCTTwoPrim(ParameterCTTwoPrim=@ParamAlias) eq null")
+        .is("<<UFCRTETTwoKeyNavParamCTTwoPrim> eq <null>>")
+        .left().goPath()
         .first()
         .isFunction("UFCRTETTwoKeyNavParamCTTwoPrim")
         .isParameterAlias(0, "ParameterCTTwoPrim", "@ParamAlias");
 
-    testFilter.runOnETTwoKeyNav("PropertyComp/olingo.odata.test1.BFCCTPrimCompRTESTwoKeyNavParam"
-        + "(ParameterString=PropertyComp/PropertyComp/PropertyString)(PropertyInt16=1,PropertyString='2')"
-        + "/PropertyString eq 'SomeString'")
-        .is("<<PropertyComp/BFCCTPrimCompRTESTwoKeyNavParam/PropertyString> eq <'SomeString'>>")
+    testFilter.runOnETTwoKeyNav("PropertyComp/olingo.odata.test1.BFCCTPrimCompRTETTwoKeyNavParam"
+        + "(ParameterString=PropertyComp/PropertyComp/PropertyString)/PropertyString eq 'SomeString'")
+        .is("<<PropertyComp/BFCCTPrimCompRTETTwoKeyNavParam/PropertyString> eq <'SomeString'>>")
         .root().left().goPath()
-        .first()
-        .isComplexProperty("PropertyComp", ComplexTypeProvider.nameCTPrimComp, false)
-        .n()
-        .isFunction("BFCCTPrimCompRTESTwoKeyNavParam")
-        .isParameter(0, "ParameterString", "PropertyComp/PropertyComp/PropertyString")
-        .goParameter(0)
-        .isMember()
+        .first().isComplexProperty("PropertyComp", ComplexTypeProvider.nameCTPrimComp, false)
+        .n().isFunction("BFCCTPrimCompRTETTwoKeyNavParam")
+        .goParameter(0).isMember()
         .goPath()
-        .first().isComplex("PropertyComp")
-        .n().isComplex("PropertyComp")
-        .n().isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false).goUpFilterValidator()
-        .goUpToResourceValidator()
+        .first().isComplexProperty("PropertyComp", ComplexTypeProvider.nameCTPrimComp, false)
+        .n().isComplexProperty("PropertyComp", ComplexTypeProvider.nameCTAllPrim, false)
+        .n().isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false)
+        .goUpFilterValidator().goUpToResourceValidator()
+        .n().isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
+
+    testFilter.runOnETTwoKeyNav("PropertyComp/olingo.odata.test1.BFCCTPrimCompRTESTwoKeyNav()"
+        + "(PropertyInt16=1,PropertyString='2')/PropertyString eq 'SomeString'")
+        .is("<<PropertyComp/BFCCTPrimCompRTESTwoKeyNav/PropertyString> eq <'SomeString'>>")
+        .root().left().goPath()
+        .first().isComplexProperty("PropertyComp", ComplexTypeProvider.nameCTPrimComp, false)
+        .n().isFunction("BFCCTPrimCompRTESTwoKeyNav")
         .isKeyPredicate(0, "PropertyInt16", "1")
         .isKeyPredicate(1, "PropertyString", "'2'")
-        .n()
-        .isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
+        .n().isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
 
     testFilter.runOnETTwoKeyNav("PropertyComp/olingo.odata.test1.BFCCTPrimCompRTETTwoKeyNavParam"
         + "(ParameterString=null)/PropertyString eq 'SomeString'")
@@ -3957,9 +3805,7 @@ public class TestFullResourcePath {
         .isComplexProperty("PropertyComp", ComplexTypeProvider.nameCTPrimComp, false)
         .n()
         .isFunction("BFCCTPrimCompRTETTwoKeyNavParam")
-        .goParameter(0)
-        .isNull()
-        .goUpToResourceValidator()
+        .isParameter(0, "ParameterString", null)
         .n()
         .isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
 
@@ -3969,59 +3815,43 @@ public class TestFullResourcePath {
         .root().left().goPath()
         .first()
         .isNavProperty("NavPropertyETTwoKeyNavMany", EntityTypeProvider.nameETTwoKeyNav, true)
-        .n()
-        .isFunction("BFCESTwoKeyNavRTString");
+        .n().isFunction("BFCESTwoKeyNavRTString");
 
-    testFilter.runOnETTwoKeyNav("$it/olingo.odata.test1.BFESTwoKeyNavRTESTwoKeyNav()/PropertyString eq 'SomeString'")
-        .is("<<$it/BFESTwoKeyNavRTESTwoKeyNav/PropertyString> eq <'SomeString'>>")
+    testFilter.runOnETKeyNav("$it/olingo.odata.test1.BFCETKeyNavRTETKeyNav()/PropertyString eq 'SomeString'")
+        .is("<<$it/BFCETKeyNavRTETKeyNav/PropertyString> eq <'SomeString'>>")
         .root().left().goPath()
-        .first()
-        .isIt()
-        .n()
-        .isFunction("BFESTwoKeyNavRTESTwoKeyNav")
-        .n()
-        .isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
+        .first().isIt()
+        .n().isFunction("BFCETKeyNavRTETKeyNav")
+        .n().isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
 
-    testFilter.runOnETTwoKeyNav("olingo.odata.test1.BFESTwoKeyNavRTESTwoKeyNav()/PropertyString eq 'SomeString'")
-        .is("<<BFESTwoKeyNavRTESTwoKeyNav/PropertyString> eq <'SomeString'>>")
+    testFilter.runOnETTwoKeyNav("olingo.odata.test1.BFCESTwoKeyNavRTCTTwoPrim()/PropertyString eq 'SomeString'")
+        .is("<<BFCESTwoKeyNavRTCTTwoPrim/PropertyString> eq <'SomeString'>>")
         .root().left().goPath()
-        .first()
-        .isFunction("BFESTwoKeyNavRTESTwoKeyNav")
-        .n()
-        .isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
+        .first().isFunction("BFCESTwoKeyNavRTCTTwoPrim")
+        .n().isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
 
     testFilter.runOnETTwoKeyNav("NavPropertyETTwoKeyNavOne/olingo.odata.test1.BFCETTwoKeyNavRTETTwoKeyNav()"
         + "/PropertyComp/PropertyComp/PropertyString eq 'Walldorf'")
         .is("<<NavPropertyETTwoKeyNavOne/BFCETTwoKeyNavRTETTwoKeyNav/PropertyComp/PropertyComp/PropertyString> "
             + "eq <'Walldorf'>>")
         .root().left().goPath()
-        .first()
-        .isNavProperty("NavPropertyETTwoKeyNavOne", EntityTypeProvider.nameETTwoKeyNav, false)
-        .n()
-        .isFunction("BFCETTwoKeyNavRTETTwoKeyNav")
-        .n()
-        .isComplexProperty("PropertyComp", ComplexTypeProvider.nameCTPrimComp, false)
-        .n()
-        .isComplexProperty("PropertyComp", ComplexTypeProvider.nameCTAllPrim, false)
-        .n()
-        .isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
+        .first().isNavProperty("NavPropertyETTwoKeyNavOne", EntityTypeProvider.nameETTwoKeyNav, false)
+        .n().isFunction("BFCETTwoKeyNavRTETTwoKeyNav")
+        .n().isComplexProperty("PropertyComp", ComplexTypeProvider.nameCTPrimComp, false)
+        .n().isComplexProperty("PropertyComp", ComplexTypeProvider.nameCTAllPrim, false)
+        .n().isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
 
-    testFilter.runOnETTwoKeyNav("PropertyComp/olingo.odata.test1.BFCCTPrimCompRTESTwoKeyNavParam"
-        + "(ParameterString='1')"
-        + "/olingo.odata.test1.ETBaseTwoKeyNav(PropertyInt16=2,PropertyString='3')"
-        + "/PropertyString eq 'SomeString'")
-        .is("<<PropertyComp/BFCCTPrimCompRTESTwoKeyNavParam/olingo.odata.test1.ETBaseTwoKeyNav/PropertyString> "
+    testFilter.runOnETTwoKeyNav("PropertyComp/olingo.odata.test1.BFCCTPrimCompRTESTwoKeyNav()"
+        + "/olingo.odata.test1.ETBaseTwoKeyNav(PropertyInt16=2,PropertyString='3')/PropertyString eq 'SomeString'")
+        .is("<<PropertyComp/BFCCTPrimCompRTESTwoKeyNav/olingo.odata.test1.ETBaseTwoKeyNav/PropertyString> "
             + "eq <'SomeString'>>")
         .root().left().goPath()
-        .first()
-        .isComplexProperty("PropertyComp", ComplexTypeProvider.nameCTPrimComp, false)
-        .n()
-        .isFunction("BFCCTPrimCompRTESTwoKeyNavParam")
-        .isTypeFilterOnCollection(EntityTypeProvider.nameETBaseTwoKeyNav)
+        .first().isComplexProperty("PropertyComp", ComplexTypeProvider.nameCTPrimComp, false)
+        .n().isFunction("BFCCTPrimCompRTESTwoKeyNav")
+        .isTypeFilterOnEntry(EntityTypeProvider.nameETBaseTwoKeyNav)
         .isKeyPredicate(0, "PropertyInt16", "2")
         .isKeyPredicate(1, "PropertyString", "'3'")
-        .n()
-        .isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
+        .n().isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
 
     testFilter.runOnETTwoKeyNavSingle("$it/olingo.odata.test1.BFCETTwoKeyNavRTCTTwoPrim()/olingo.odata.test1.CTBase"
         + "/PropertyString eq 'SomeString'")
@@ -4071,59 +3901,58 @@ public class TestFullResourcePath {
         .root().left().goPath()
         .first()
         .isFunction("UFCRTETTwoKeyNavParam")
-        .isParameter(0, "ParameterInt16", "PropertyInt16")
-        .n()
-        .isComplexProperty("PropertyComp", ComplexTypeProvider.nameCTPrimComp, false)
-        .n()
-        .isComplexProperty("PropertyComp", ComplexTypeProvider.nameCTAllPrim, false)
-        .n()
-        .isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
+        .goParameter(0)
+        .isMember().goPath().first().isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false)
+        .goUpFilterValidator().goUpToResourceValidator()
+        .n().isComplexProperty("PropertyComp", ComplexTypeProvider.nameCTPrimComp, false)
+        .n().isComplexProperty("PropertyComp", ComplexTypeProvider.nameCTAllPrim, false)
+        .n().isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
   }
 
   @Test
   public void methods() throws Exception {
     testFilter.runOnETKeyNav("indexof(PropertyString,'47') eq 5")
         .is("<<indexof(<PropertyString>,<'47'>)> eq <5>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.INDEXOF, 2)
         .isParameterText(0, "<PropertyString>")
         .isParameterText(1, "<'47'>");
 
     testFilter.runOnETKeyNav("tolower(PropertyString) eq 'foo'")
         .is("<<tolower(<PropertyString>)> eq <'foo'>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.TOLOWER, 1)
         .isParameterText(0, "<PropertyString>");
 
     testFilter.runOnETKeyNav("toupper(PropertyString) eq 'FOO'")
         .is("<<toupper(<PropertyString>)> eq <'FOO'>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.TOUPPER, 1)
         .isParameterText(0, "<PropertyString>");
 
     testFilter.runOnETKeyNav("trim(PropertyString) eq 'fooba'")
         .is("<<trim(<PropertyString>)> eq <'fooba'>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.TRIM, 1)
         .isParameterText(0, "<PropertyString>");
 
     testFilter.runOnETKeyNav("substring(PropertyString,4) eq 'foo'")
         .is("<<substring(<PropertyString>,<4>)> eq <'foo'>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.SUBSTRING, 2)
         .isParameterText(0, "<PropertyString>")
         .isParameterText(1, "<4>");
 
     testFilter.runOnETKeyNav("substring(PropertyString,4) eq 'foo'")
         .is("<<substring(<PropertyString>,<4>)> eq <'foo'>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.SUBSTRING, 2)
         .isParameterText(0, "<PropertyString>")
         .isParameterText(1, "<4>");
 
     testFilter.runOnETKeyNav("substring(PropertyString,2,4) eq 'foo'")
         .is("<<substring(<PropertyString>,<2>,<4>)> eq <'foo'>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.SUBSTRING, 3)
         .isParameterText(0, "<PropertyString>")
         .isParameterText(1, "<2>")
@@ -4131,355 +3960,355 @@ public class TestFullResourcePath {
 
     testFilter.runOnETKeyNav("concat(PropertyString,PropertyCompTwoPrim/PropertyString) eq 'foo'")
         .is("<<concat(<PropertyString>,<PropertyCompTwoPrim/PropertyString>)> eq <'foo'>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.CONCAT, 2)
         .isParameterText(0, "<PropertyString>")
         .isParameterText(1, "<PropertyCompTwoPrim/PropertyString>");
 
     testFilter.runOnETKeyNav("concat(PropertyString,'bar') eq 'foobar'")
         .is("<<concat(<PropertyString>,<'bar'>)> eq <'foobar'>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.CONCAT, 2)
         .isParameterText(0, "<PropertyString>")
         .isParameterText(1, "<'bar'>");
 
     testFilter.runOnETKeyNav("concat(PropertyString,'bar') eq 'foobar'")
         .is("<<concat(<PropertyString>,<'bar'>)> eq <'foobar'>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.CONCAT, 2)
         .isParameterText(0, "<PropertyString>")
         .isParameterText(1, "<'bar'>");
 
     testFilter.runOnETKeyNav("length(PropertyString) eq 32")
         .is("<<length(<PropertyString>)> eq <32>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.LENGTH, 1)
         .isParameterText(0, "<PropertyString>");
 
     testFilter.runOnETAllPrim("year(PropertyDate) eq 2013")
         .is("<<year(<PropertyDate>)> eq <2013>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.YEAR, 1)
         .isParameterText(0, "<PropertyDate>");
 
     testFilter.runOnETAllPrim("year(2013-09-25) eq 2013")
         .is("<<year(<2013-09-25>)> eq <2013>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.YEAR, 1)
         .isParameterText(0, "<2013-09-25>");
 
     testFilter.runOnETAllPrim("year(PropertyDateTimeOffset) eq 2013")
         .is("<<year(<PropertyDateTimeOffset>)> eq <2013>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.YEAR, 1)
         .isParameterText(0, "<PropertyDateTimeOffset>");
 
     testFilter.runOnETAllPrim("year(2013-09-25T12:34:56.123456789012-10:24) eq 2013")
         .is("<<year(<2013-09-25T12:34:56.123456789012-10:24>)> eq <2013>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.YEAR, 1)
         .isParameterText(0, "<2013-09-25T12:34:56.123456789012-10:24>");
 
     testFilter.runOnETAllPrim("month(PropertyDate) eq 9")
         .is("<<month(<PropertyDate>)> eq <9>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.MONTH, 1)
         .isParameterText(0, "<PropertyDate>");
 
     testFilter.runOnETAllPrim("month(2013-09-25) eq 9")
         .is("<<month(<2013-09-25>)> eq <9>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.MONTH, 1)
         .isParameterText(0, "<2013-09-25>");
 
     testFilter.runOnETAllPrim("month(PropertyDateTimeOffset) eq 9")
         .is("<<month(<PropertyDateTimeOffset>)> eq <9>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.MONTH, 1)
         .isParameterText(0, "<PropertyDateTimeOffset>");
 
     testFilter.runOnETAllPrim("month(2013-09-25T12:34:56.123456789012-10:24) eq 9")
         .is("<<month(<2013-09-25T12:34:56.123456789012-10:24>)> eq <9>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.MONTH, 1)
         .isParameterText(0, "<2013-09-25T12:34:56.123456789012-10:24>");
 
     testFilter.runOnETAllPrim("day(PropertyDate) eq 25")
         .is("<<day(<PropertyDate>)> eq <25>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.DAY, 1)
         .isParameterText(0, "<PropertyDate>");
 
     testFilter.runOnETAllPrim("day(2013-09-25) eq 25")
         .is("<<day(<2013-09-25>)> eq <25>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.DAY, 1)
         .isParameterText(0, "<2013-09-25>");
 
     testFilter.runOnETAllPrim("day(PropertyDateTimeOffset) eq 25")
         .is("<<day(<PropertyDateTimeOffset>)> eq <25>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.DAY, 1)
         .isParameterText(0, "<PropertyDateTimeOffset>");
 
     testFilter.runOnETAllPrim("day(2013-09-25T12:34:56.123456789012-10:24) eq 25")
         .is("<<day(<2013-09-25T12:34:56.123456789012-10:24>)> eq <25>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.DAY, 1)
         .isParameterText(0, "<2013-09-25T12:34:56.123456789012-10:24>");
 
     testFilter.runOnETAllPrim("hour(PropertyDateTimeOffset) eq 2")
         .is("<<hour(<PropertyDateTimeOffset>)> eq <2>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.HOUR, 1)
         .isParameterText(0, "<PropertyDateTimeOffset>");
 
     testFilter.runOnETAllPrim("hour(PropertyDateTimeOffset) eq 2")
         .is("<<hour(<PropertyDateTimeOffset>)> eq <2>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.HOUR, 1)
         .isParameterText(0, "<PropertyDateTimeOffset>");
 
     testFilter.runOnETAllPrim("hour(2013-09-25T12:34:56.123456789012-10:24) eq 2")
         .is("<<hour(<2013-09-25T12:34:56.123456789012-10:24>)> eq <2>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.HOUR, 1)
         .isParameterText(0, "<2013-09-25T12:34:56.123456789012-10:24>");
 
     testFilter.runOnETAllPrim("hour(PropertyTimeOfDay) eq 2")
         .is("<<hour(<PropertyTimeOfDay>)> eq <2>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.HOUR, 1)
         .isParameterText(0, "<PropertyTimeOfDay>");
 
     testFilter.runOnETAllPrim("hour(12:34:55.123456789012) eq 12")
         .is("<<hour(<12:34:55.123456789012>)> eq <12>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.HOUR, 1)
         .isParameterText(0, "<12:34:55.123456789012>");
 
     testFilter.runOnETAllPrim("minute(PropertyDateTimeOffset) eq 34")
         .is("<<minute(<PropertyDateTimeOffset>)> eq <34>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.MINUTE, 1)
         .isParameterText(0, "<PropertyDateTimeOffset>");
 
     testFilter.runOnETAllPrim("minute(2013-09-25T12:34:56.123456789012-10:24) eq 34")
         .is("<<minute(<2013-09-25T12:34:56.123456789012-10:24>)> eq <34>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.MINUTE, 1)
         .isParameterText(0, "<2013-09-25T12:34:56.123456789012-10:24>");
 
     testFilter.runOnETAllPrim("minute(PropertyTimeOfDay) eq 34")
         .is("<<minute(<PropertyTimeOfDay>)> eq <34>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.MINUTE, 1)
         .isParameterText(0, "<PropertyTimeOfDay>");
 
     testFilter.runOnETAllPrim("minute(12:34:55.123456789012) eq 34")
         .is("<<minute(<12:34:55.123456789012>)> eq <34>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.MINUTE, 1)
         .isParameterText(0, "<12:34:55.123456789012>");
 
     testFilter.runOnETAllPrim("second(PropertyDateTimeOffset) eq 56")
         .is("<<second(<PropertyDateTimeOffset>)> eq <56>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.SECOND, 1)
         .isParameterText(0, "<PropertyDateTimeOffset>");
 
     testFilter.runOnETAllPrim("second(2013-09-25T12:34:56.123456789012-10:24) eq 56")
         .is("<<second(<2013-09-25T12:34:56.123456789012-10:24>)> eq <56>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.SECOND, 1)
         .isParameterText(0, "<2013-09-25T12:34:56.123456789012-10:24>");
 
     testFilter.runOnETAllPrim("second(PropertyTimeOfDay) eq 56")
         .is("<<second(<PropertyTimeOfDay>)> eq <56>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.SECOND, 1)
         .isParameterText(0, "<PropertyTimeOfDay>");
 
     testFilter.runOnETAllPrim("second(12:34:55.123456789012) eq 56")
         .is("<<second(<12:34:55.123456789012>)> eq <56>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.SECOND, 1)
         .isParameterText(0, "<12:34:55.123456789012>");
 
     testFilter.runOnETAllPrim("fractionalseconds(PropertyDateTimeOffset) eq 123456789012")
         .is("<<fractionalseconds(<PropertyDateTimeOffset>)> eq <123456789012>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.FRACTIONALSECONDS, 1)
         .isParameterText(0, "<PropertyDateTimeOffset>");
 
     testFilter.runOnETAllPrim("fractionalseconds(2013-09-25T12:34:56.123456789012-10:24) eq 123456789012")
         .is("<<fractionalseconds(<2013-09-25T12:34:56.123456789012-10:24>)> eq <123456789012>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.FRACTIONALSECONDS, 1)
         .isParameterText(0, "<2013-09-25T12:34:56.123456789012-10:24>");
 
     testFilter.runOnETAllPrim("fractionalseconds(PropertyTimeOfDay) eq 123456789012")
         .is("<<fractionalseconds(<PropertyTimeOfDay>)> eq <123456789012>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.FRACTIONALSECONDS, 1)
         .isParameterText(0, "<PropertyTimeOfDay>");
 
     testFilter.runOnETAllPrim("fractionalseconds(12:34:55.123456789012) eq 123456789012")
         .is("<<fractionalseconds(<12:34:55.123456789012>)> eq <123456789012>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.FRACTIONALSECONDS, 1)
         .isParameterText(0, "<12:34:55.123456789012>");
 
     testFilter.runOnETAllPrim("totalseconds(PropertyDuration) eq 4711")
         .is("<<totalseconds(<PropertyDuration>)> eq <4711>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.TOTALSECONDS, 1)
         .isParameterText(0, "<PropertyDuration>");
 
     testFilter.runOnETAllPrim("totalseconds(duration'P10DT5H34M21.123456789012S') eq 4711")
         .is("<<totalseconds(<duration'P10DT5H34M21.123456789012S'>)> eq <4711>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.TOTALSECONDS, 1)
         .isParameterText(0, "<duration'P10DT5H34M21.123456789012S'>");
 
     testFilter.runOnETAllPrim("date(PropertyDateTimeOffset) eq 2013-09-25")
         .is("<<date(<PropertyDateTimeOffset>)> eq <2013-09-25>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.DATE, 1)
         .isParameterText(0, "<PropertyDateTimeOffset>");
 
     testFilter.runOnETAllPrim("date(2013-09-25T12:34:56.123456789012-10:24) eq 2013-09-25")
         .is("<<date(<2013-09-25T12:34:56.123456789012-10:24>)> eq <2013-09-25>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.DATE, 1)
         .isParameterText(0, "<2013-09-25T12:34:56.123456789012-10:24>");
 
     testFilter.runOnETAllPrim("time(PropertyDateTimeOffset) eq 12:34:55.123456789012")
         .is("<<time(<PropertyDateTimeOffset>)> eq <12:34:55.123456789012>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.TIME, 1)
         .isParameterText(0, "<PropertyDateTimeOffset>");
 
     testFilter.runOnETAllPrim("time(2013-09-25T12:34:56.123456789012-10:24) eq 12:34:55.123456789012")
         .is("<<time(<2013-09-25T12:34:56.123456789012-10:24>)> eq <12:34:55.123456789012>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.TIME, 1)
         .isParameterText(0, "<2013-09-25T12:34:56.123456789012-10:24>");
 
     testFilter.runOnETAllPrim("round(PropertyDouble) eq 17")
         .is("<<round(<PropertyDouble>)> eq <17>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.ROUND, 1)
         .isParameterText(0, "<PropertyDouble>");
 
     testFilter.runOnETAllPrim("round(17.45e1) eq 17")
         .is("<<round(<17.45e1>)> eq <17>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.ROUND, 1)
         .isParameterText(0, "<17.45e1>");
 
     testFilter.runOnETAllPrim("round(PropertyDecimal) eq 17")
         .is("<<round(<PropertyDecimal>)> eq <17>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.ROUND, 1)
         .isParameterText(0, "<PropertyDecimal>");
 
     testFilter.runOnETAllPrim("round(17.45) eq 17")
         .is("<<round(<17.45>)> eq <17>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.ROUND, 1)
         .isParameterText(0, "<17.45>");
 
     testFilter.runOnETAllPrim("floor(PropertyDouble) eq 17")
         .is("<<floor(<PropertyDouble>)> eq <17>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.FLOOR, 1)
         .isParameterText(0, "<PropertyDouble>");
 
     testFilter.runOnETAllPrim("floor(17.45e1) eq 17")
         .is("<<floor(<17.45e1>)> eq <17>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.FLOOR, 1)
         .isParameterText(0, "<17.45e1>");
 
     testFilter.runOnETAllPrim("floor(PropertyDecimal) eq 17")
         .is("<<floor(<PropertyDecimal>)> eq <17>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.FLOOR, 1)
         .isParameterText(0, "<PropertyDecimal>");
 
     testFilter.runOnETAllPrim("floor(17.45) eq 17")
         .is("<<floor(<17.45>)> eq <17>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.FLOOR, 1)
         .isParameterText(0, "<17.45>");
 
     testFilter.runOnETAllPrim("ceiling(PropertyDouble) eq 18")
         .is("<<ceiling(<PropertyDouble>)> eq <18>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.CEILING, 1)
         .isParameterText(0, "<PropertyDouble>");
 
     testFilter.runOnETAllPrim("ceiling(17.55e1) eq 18")
         .is("<<ceiling(<17.55e1>)> eq <18>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.CEILING, 1)
         .isParameterText(0, "<17.55e1>");
 
     testFilter.runOnETAllPrim("ceiling(PropertyDecimal) eq 18")
         .is("<<ceiling(<PropertyDecimal>)> eq <18>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.CEILING, 1)
         .isParameterText(0, "<PropertyDecimal>");
 
     testFilter.runOnETAllPrim("ceiling(17.55) eq 18")
         .is("<<ceiling(<17.55>)> eq <18>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.CEILING, 1)
         .isParameterText(0, "<17.55>");
 
     testFilter.runOnETAllPrim("totaloffsetminutes(PropertyDateTimeOffset) eq 4711")
         .is("<<totaloffsetminutes(<PropertyDateTimeOffset>)> eq <4711>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.TOTALOFFSETMINUTES, 1)
         .isParameterText(0, "<PropertyDateTimeOffset>");
 
     testFilter.runOnETAllPrim("totaloffsetminutes(2013-09-25T12:34:56.123456789012-10:24) eq 4711")
         .is("<<totaloffsetminutes(<2013-09-25T12:34:56.123456789012-10:24>)> eq <4711>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.TOTALOFFSETMINUTES, 1)
         .isParameterText(0, "<2013-09-25T12:34:56.123456789012-10:24>");
 
-    testFilter.runOnETAllPrim("mindatetime()")
-        .is("<mindatetime()>")
-        .isMethod(MethodKind.MINDATETIME, 0);
+    testFilter.runOnETAllPrim("mindatetime() ne null")
+        .is("<<mindatetime()> ne <null>>")
+        .left().isMethod(MethodKind.MINDATETIME, 0);
 
     testFilter.runOnETAllPrim("mindatetime() eq 2013-09-25T12:34:56.123456789012-10:24")
         .is("<<mindatetime()> eq <2013-09-25T12:34:56.123456789012-10:24>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.MINDATETIME, 0);
 
-    testFilter.runOnETAllPrim("maxdatetime()")
-        .is("<maxdatetime()>")
-        .isMethod(MethodKind.MAXDATETIME, 0);
+    testFilter.runOnETAllPrim("maxdatetime() ne null")
+        .is("<<maxdatetime()> ne <null>>")
+        .left().isMethod(MethodKind.MAXDATETIME, 0);
 
     testFilter.runOnETAllPrim("maxdatetime() eq 2013-09-25T12:34:56.123456789012-10:24")
         .is("<<maxdatetime()> eq <2013-09-25T12:34:56.123456789012-10:24>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.MAXDATETIME, 0);
 
-    testFilter.runOnETAllPrim("now()")
-        .is("<now()>")
-        .isMethod(MethodKind.NOW, 0);
+    testFilter.runOnETAllPrim("now() ne null")
+        .is("<<now()> ne <null>>")
+        .left().isMethod(MethodKind.NOW, 0);
 
     testFilter.runOnETAllPrim("now() eq 2013-09-25T12:34:56.123456789012-10:24")
         .is("<<now()> eq <2013-09-25T12:34:56.123456789012-10:24>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.NOW, 0);
 
     testFilter.runOnETTwoKeyNav("$it/PropertyString eq 'SomeString'")
         .is("<<$it/PropertyString> eq <'SomeString'>>")
-        .root().left()
+        .left()
         .goPath()
         .first().isUriPathInfoKind(UriResourceKind.it)
         .isType(EntityTypeProvider.nameETTwoKeyNav, false)
@@ -4487,7 +4316,7 @@ public class TestFullResourcePath {
 
     testFilter.runOnCTTwoPrim("$it/PropertyString eq 'SomeString'")
         .is("<<$it/PropertyString> eq <'SomeString'>>")
-        .root().left()
+        .left()
         .goPath()
         .first().isUriPathInfoKind(UriResourceKind.it)
         .isType(ComplexTypeProvider.nameCTTwoPrim, false)
@@ -4495,7 +4324,7 @@ public class TestFullResourcePath {
 
     testFilter.runOnString("$it eq 'Walldorf'")
         .is("<<$it> eq <'Walldorf'>>")
-        .root().left()
+        .left()
         .goPath()
         .first().isUriPathInfoKind(UriResourceKind.it)
         .isType(PropertyProvider.nameString, false);
@@ -4512,7 +4341,7 @@ public class TestFullResourcePath {
 
     testFilter.runOnString("endswith($it,'sap.com') eq false")
         .is("<<endswith(<$it>,<'sap.com'>)> eq <false>>")
-        .root().left()
+        .left()
         .isMethod(MethodKind.ENDSWITH, 2)
         .isParameterText(0, "<$it>")
         .isParameterText(1, "<'sap.com'>")
@@ -4644,44 +4473,42 @@ public class TestFullResourcePath {
         .n().isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
   }
 
-  // TODO: Implement cast method.
   @Test
   public void castMethod() throws Exception {
-    testFilter.runOnETKeyNav("cast(olingo.odata.test1.ETBaseTwoKeyNav)")
-        .is("<cast(<olingo.odata.test1.ETBaseTwoKeyNav>)>")
-        .root()
+    testFilter.runOnETKeyNav("cast(olingo.odata.test1.ETBaseTwoKeyNav) ne null")
+        .is("<<cast(<olingo.odata.test1.ETBaseTwoKeyNav>)> ne <n

<TRUNCATED>

[27/30] olingo-odata4 git commit: [OLINGO-834] Delete AntLR dependecies

Posted by ch...@apache.org.
[OLINGO-834] Delete AntLR dependecies


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

Branch: refs/heads/master
Commit: 26080f420ac48ce8a3d60a6372226ee4f2f4aab8
Parents: 010642c
Author: Christian Amend <ch...@sap.com>
Authored: Thu Jan 7 15:00:17 2016 +0100
Committer: Christian Amend <ch...@sap.com>
Committed: Thu Jan 7 15:00:17 2016 +0100

----------------------------------------------------------------------
 lib/server-core-ext/pom.xml                     |   4 -
 lib/server-core/pom.xml                         |  40 --
 .../olingo/server/core/uri/antlr/UriLexer.g4    | 424 ------------------
 .../olingo/server/core/uri/antlr/UriParser.g4   | 447 -------------------
 .../uri/parser/CheckFullContextListener.java    |  60 ---
 lib/server-test/pom.xml                         |   4 -
 pom.xml                                         |  14 -
 7 files changed, 993 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/26080f42/lib/server-core-ext/pom.xml
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/pom.xml b/lib/server-core-ext/pom.xml
index e15dc1a..af286c0 100644
--- a/lib/server-core-ext/pom.xml
+++ b/lib/server-core-ext/pom.xml
@@ -50,10 +50,6 @@
       <version>${project.version}</version>
     </dependency>
     <dependency>
-      <groupId>org.antlr</groupId>
-      <artifactId>antlr4-runtime</artifactId>
-    </dependency>
-    <dependency>
       <groupId>javax.servlet</groupId>
       <artifactId>javax.servlet-api</artifactId>
       <version>3.0.1</version>

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/26080f42/lib/server-core/pom.xml
----------------------------------------------------------------------
diff --git a/lib/server-core/pom.xml b/lib/server-core/pom.xml
index 8b18338..6e22690 100644
--- a/lib/server-core/pom.xml
+++ b/lib/server-core/pom.xml
@@ -46,10 +46,6 @@
       <version>${project.version}</version>
     </dependency>
     <dependency>
-      <groupId>org.antlr</groupId>
-      <artifactId>antlr4-runtime</artifactId>
-    </dependency>
-    <dependency>
       <groupId>javax.servlet</groupId>
       <artifactId>servlet-api</artifactId>
       <version>2.5</version>
@@ -85,42 +81,6 @@
         </configuration>
       </plugin>
       <plugin>
-        <groupId>org.codehaus.mojo</groupId>
-        <artifactId>build-helper-maven-plugin</artifactId>
-        <executions>
-          <execution>
-            <phase>generate-sources</phase>
-            <goals>
-              <goal>add-source</goal>
-            </goals>
-            <configuration>
-              <sources>
-                <source>target/generated-sources/antlr4</source>
-              </sources>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <groupId>org.antlr</groupId>
-        <artifactId>antlr4-maven-plugin</artifactId>
-        <executions>
-          <execution>
-            <goals>
-              <goal>antlr4</goal>
-            </goals>
-          </execution>
-        </executions>
-        <configuration>
-          <!--<arguments><argument>-atn</argument></arguments> -->
-          <listener>true</listener>
-          <visitor>true</visitor>
-          <!--maven antlr plugin has trouble with grammer import if the grammerfiles
-            are not directly inside src/main/antlr4, hence we have to set the libDirectory -->
-          <libDirectory>src/main/antlr4/org/apache/olingo/server/core/uri/antlr</libDirectory>
-        </configuration>
-      </plugin>
-      <plugin>
         <groupId>org.apache.felix</groupId>
         <artifactId>maven-bundle-plugin</artifactId>
     		<version>${maven.bundle.plugin.version}</version>

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/26080f42/lib/server-core/src/main/antlr4/org/apache/olingo/server/core/uri/antlr/UriLexer.g4
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/antlr4/org/apache/olingo/server/core/uri/antlr/UriLexer.g4 b/lib/server-core/src/main/antlr4/org/apache/olingo/server/core/uri/antlr/UriLexer.g4
deleted file mode 100644
index 7a54ab1..0000000
--- a/lib/server-core/src/main/antlr4/org/apache/olingo/server/core/uri/antlr/UriLexer.g4
+++ /dev/null
@@ -1,424 +0,0 @@
-/*******************************************************************************
- * 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.
- ******************************************************************************/
-lexer grammar UriLexer;
-
-//;==============================================================================
-// Mode "DEFAULT_MODE": Processes everything before the first '?' char.
-// On '?' the next mode "MODE_QUERY" is used.
-// The percent encoding rules are defined in RFC3986; ABNF rule "path-rootless" applies.
-//;==============================================================================
-QM              : '?'                 ->        pushMode(MODE_QUERY);               //first query parameter
-AMP             : '&'                 ->        pushMode(MODE_QUERY);               //more query parameters
-STRING          : '\''                -> more,  pushMode(MODE_STRING) ;              //reads up to next single '
-QUOTATION_MARK  : '\u0022'            -> more,  pushMode(MODE_JSON_STRING);         //reads up to next unescaped "
-SEARCH_INLINE   : '$search'           ->        pushMode(MODE_SYSTEM_QUERY_SEARCH); //
-FRAGMENT        : '#'                 ->        pushMode(MODE_FRAGMENT);            //
-STRING_JSON		: '"'				  -> more,  pushMode(MODE_JSON_STRING);			//reads up to next unescaped "
-
-GEOGRAPHY    : G E O G R A P H Y SQUOTE         -> pushMode(MODE_ODATA_GEO); //TODO make case insensitive
-GEOMETRY     : G E O M E T R Y   SQUOTE         -> pushMode(MODE_ODATA_GEO);
-
-//Letters for case insensitivity
-fragment A    : 'A'|'a';
-fragment B    : 'B'|'b';
-fragment D    : 'D'|'d';
-fragment E    : 'E'|'e';
-fragment F    : 'F'|'f';
-fragment G    : 'G'|'g';
-fragment H    : 'H'|'h';
-fragment I    : 'I'|'i';
-fragment L    : 'L'|'l';
-fragment M    : 'M'|'m';
-fragment N    : 'N'|'n';
-fragment O    : 'O'|'o';
-fragment P    : 'P'|'p';
-fragment R    : 'R'|'r';
-fragment S    : 'S'|'s';
-fragment T    : 'T'|'t';
-fragment U    : 'U'|'u';
-fragment Y    : 'Y'|'y';
-fragment Z    : 'Z'|'z';
-
-//special chars
-OPEN            : '(';
-CLOSE           : ')';
-COMMA           : ',';
-SLASH           : '/';
-POINT           : '.';
-AT              : '@';
-EQ              : '=' ;
-STAR            : '*';
-SEMI            : ';';
-COLON           : ':';
-
-EQ_sq           : '='           -> type(EQ);
-AMP_sq          : '&'           -> type(AMP), popMode;
-fragment WS     : ( ' ' | '\u0009' );
-WSP             : WS+;
-
-//JSON support 
-BEGIN_OBJECT    : WS* '{' WS*;
-END_OBJECT      : WS* '}' WS*;
-
-BEGIN_ARRAY     : WS* '[' WS*;
-END_ARRAY       : WS* ']' WS*;
-
-
-//alpha stuff
-fragment ALPHA                : 'a'..'z' | 'A'..'Z';
-fragment ALPHA_A_TO_F         : 'a'..'f' | 'A'..'F';
-fragment DIGIT                : '0'..'9';
-fragment DIGITS               : DIGIT+;
-fragment HEXDIG               : DIGIT | ALPHA_A_TO_F;
-fragment ODI_LEADINGCHARACTER : ALPHA | '_';            //TODO; add Unicode characters from the categories L or Nl
-fragment ODI_CHARACTER        : ALPHA | '_' | DIGIT;    //TODO; add Unicode characters from the categories L, Nl, Nd, Mn, Mc, Pc, or Cf
-
-//helper for date/time values
-fragment ONE_TO_NINE        : '1'..'9';
-fragment ZERO_TO_FIFTYNINE  : ('0'..'5') DIGIT;
-fragment FRACTIONALSECONDS  : DIGIT+;
-fragment SECOND             : ZERO_TO_FIFTYNINE;
-fragment MINUTE             : ZERO_TO_FIFTYNINE;
-fragment HOUR               : ('0' | '1') DIGIT | '2' ( '0'..'3');
-fragment DAY                : '0' '1'..'9' | ('1'|'2') DIGIT | '3' ('0'|'1');
-fragment MONTH              : '0' ONE_TO_NINE | '1' ( '0' | '1' | '2' );
-fragment YEAR               : ('-')? ( '0' DIGIT DIGIT DIGIT | ONE_TO_NINE DIGIT DIGIT DIGIT );
-
-//tags starting with $ 
-BATCH         : '$batch';
-ENTITY        : '$entity';
-METADATA      : '$metadata';
-
-ALL           : '$all';
-CROSSJOIN     : '$crossjoin';
-
-VALUE         : '$value';
-REF           : '$ref';
-COUNT         : '$count';
-
-//inlined query parameters ( e.g. $skip)
-TOP_I     : '$top'    -> type(TOP);
-SKIP_QO_I : '$skip'   -> type(SKIP_QO);
-FILTER_I  : '$filter' -> type(FILTER);
-ORDERBY_I : '$orderby'-> type(ORDERBY);
-SELECT_I  : '$select' -> type(SELECT);
-EXPAND_I  : '$expand' -> type(EXPAND);
-LEVELS_I  : '$levels' -> type(LEVELS);
-MAX: 'max';
-
-ROOT            : '$root/';
-
-//rest
-NULLVALUE     : 'null';
-
-TRUE          : 'true';
-FALSE         : 'false';
-BOOLEAN       :  T R U E |  F A L S E; 
-PLUS          : '+';
-
-MINUS         : '-';
-SIGN          : PLUS  | '-';
-INT           : SIGN? DIGITS;
-DECIMAL       : INT '.' DIGITS (('e'|'E') SIGN?  DIGITS)?;
-NANINFINITY   : 'NaN' | '-INF' | 'INF';
-//primary types
-BINARY                      : B I N A R Y SQUOTE (HEXDIG HEXDIG)* SQUOTE; 
-DATE                        : YEAR '-' MONTH '-' DAY;
-DATETIMEOFFSET              : YEAR '-' MONTH '-' DAY T HOUR ':' MINUTE ( ':' SECOND ( '.' FRACTIONALSECONDS )? )? ( Z | SIGN HOUR ':' MINUTE );
-fragment DUSECONDFRAG       : DIGITS ('.' DIGITS)? 'S';
-fragment DUTIMEFRAG         : 'T' (   
-                              ( DIGITS 'H' (DIGITS 'M')? DUSECONDFRAG?) 
-                              | (DIGITS 'M' DUSECONDFRAG?) 
-                              | DUSECONDFRAG
-                            )?;
-fragment DUDAYTIMEFRAG      : DIGITS 'D' DUTIMEFRAG? | DUTIMEFRAG;
-DURATION                    : D U R A T I O N SQUOTE '-'? 'P' DUDAYTIMEFRAG SQUOTE;
-TIMEOFDAY                   : HOUR ':' MINUTE ( ':' SECOND ( '.' FRACTIONALSECONDS )? )?;
-fragment GUIDVALUE          : HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG'-' 
-                              HEXDIG HEXDIG HEXDIG HEXDIG  '-' 
-                              HEXDIG HEXDIG HEXDIG HEXDIG  '-' 
-                              HEXDIG HEXDIG HEXDIG HEXDIG  '-' 
-                              HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG;
-GUID                        : GUIDVALUE;
-
-//expression tokens
-ASC             : 'asc'; 
-DESC            : 'desc';
-MUL             : 'mul';
-DIV             : 'div';
-MOD             : 'mod';
-HAS             : 'has';
-
-ADD             : 'add';
-SUB             : 'sub';
-
-ANY_LAMDA       : 'any';
-ALL_LAMDA       : 'all';
-
-GT              : 'gt';
-GE              : 'ge';
-LT              : 'lt';
-LE              : 'le';
-ISOF            : 'isof';
-
-EQ_ALPHA        : 'eq';
-NE              : 'ne';
-
-AND             : 'and';
-OR              : 'or';
-
-
-NOT             : 'not';
-
-
-IT  : '$it';
-ITSLASH  : '$it/';
-LEVELS : '$levels';
-
-CONTAINS_WORD             : 'contains(';
-STARTSWITH_WORD           : 'startswith(';
-ENDSWITH_WORD             : 'endswith(';
-LENGTH_WORD               : 'length(';
-INDEXOF_WORD              : 'indexof(';
-SUBSTRING_WORD            : 'substring(';
-TOLOWER_WORD              : 'tolower(';
-TOUPPER_WORD              : 'toupper(';
-TRIM_WORD                 : 'trim(';
-CONCAT_WORD               : 'concat(';
-YEAR_WORD                 : 'year(';
-MONTH_WORD                : 'month(';
-DAY_WORD                  : 'day(';
-HOUR_WORD                 : 'hour(';
-MINUTE_WORD               : 'minute(';
-SECOND_WORD               : 'second(';
-FRACTIONALSECONDS_WORD    : 'fractionalseconds(';
-TOTALSECONDS_WORD         : 'totalseconds(';
-DATE_WORD                 : 'date(';
-TIME_WORD                 : 'time(';
-TOTALOFFSETMINUTES_WORD   : 'totaloffsetminutes(';
-
-MINDATETIME_WORD          : 'mindatetime(';
-MAXDATETIME_WORD          : 'maxdatetime(';
-NOW_WORD                  : 'now(';
-
-ROUND_WORD                : 'round(';
-FLOOR_WORD                : 'floor(';
-CEILING_WORD              : 'ceiling(';
-
-GEO_DISTANCE_WORD         : 'geo.distance(';
-GEO_LENGTH_WORD           : 'geo.length(';
-GEO_INTERSECTS_WORD       : 'geo.intersects(';
-ISOF_WORD                 : 'isof(';
-CAST_WORD                 : 'cast(';
-
-COLLECTION_REF            : 'Collection($ref)';
-COLLECTION_ENTITY_TYPE    : 'Collection(Edm.EntityType)';
-COLLECTION_COMPLEX_TYPE   : 'Collection(Edm.ComplexType)';
-COLLECTION                : 'Collection(' -> type(COLLECTION);
-
-//used in fragment only
-DELETED_ENTITY            : '$deletedEntity';
-LINK                      : '$link';
-DELETED_LINK              : '$deletedLink';
-DELTA                     : '$delta';
-
-ODATAIDENTIFIER : ODI_LEADINGCHARACTER (ODI_CHARACTER)*;
-
-//handle characters that failed to match any other token
-ERROR_CHARACTER : .;
-
-//;==============================================================================
-// Mode "QUERY": Processes everything between the first '?' and the '#' char.
-// On '?' the next mode "FRAGMENT" is used.
-// The percent encoding rules are defined in RFC3986; ABNF rule "query" applies.
-mode MODE_QUERY;
-//;==============================================================================
-
-FRAGMENT_q          : '#'           -> type(FRAGMENT);
-FILTER              : '$filter'     ->                    pushMode(DEFAULT_MODE);
-ORDERBY             : '$orderby'    ->                    pushMode(DEFAULT_MODE);
-EXPAND              : '$expand'     ->                    pushMode(DEFAULT_MODE);
-SELECT              : '$select'     ->                    pushMode(DEFAULT_MODE);
-SKIP_QO             : '$skip'       ->                    pushMode(DEFAULT_MODE);
-SKIPTOKEN           : '$skiptoken'  ->                    pushMode(MODE_SYSTEM_QUERY_REST);
-TOP                 : '$top'        ->                    pushMode(DEFAULT_MODE);
-LEVELS_q            : '$levels'     -> type(LEVELS),      pushMode(DEFAULT_MODE);
-FORMAT              : '$format'     ->                    pushMode(MODE_SYSTEM_QUERY_PCHAR);
-COUNT_q             : '$count'      -> type(COUNT),       pushMode(DEFAULT_MODE);
-REF_q               : '$ref'        -> type(REF);
-VALUE_q             : '$value'      -> type(VALUE);
-ID                  : '$id'         ->                    pushMode(MODE_SYSTEM_QUERY_REST);
-SEARCH              : '$search'     ->                    pushMode(MODE_SYSTEM_QUERY_SEARCH);
-
-EQ_q          : '=' -> type(EQ);
-AMP_q         : '&' -> type(AMP);
-
-AT_Q          : '@' -> pushMode(DEFAULT_MODE);
-
-CUSTOMNAME    : ~[&=@$] ~[&=]* -> pushMode(MODE_SYSTEM_QUERY_REST);
-
-//handle characters that failed to match any other token
-ERROR_CHARACTER_q : .;
-
-//;==============================================================================
-mode MODE_SYSTEM_QUERY_PCHAR;
-//;==============================================================================
-
-AMP_sqp   : '&' -> type(AMP),       popMode;
-
-fragment ALPHA_sqp          : 'a'..'z'|'A'..'Z';
-fragment A_TO_F_sqp         : 'a'..'f'|'A'..'F';
-fragment DIGIT_sqp          : '0'..'9';
-fragment HEXDIG_sqp         : DIGIT_sqp | A_TO_F_sqp;
-fragment PCT_ENCODED_sqp    : '%' HEXDIG_sqp HEXDIG_sqp;
-fragment SUB_DELIMS_sqp     : '$' | /*'&' |*/ '\'' | EQ_sqp | OTHER_DELIMS_sqp;
-fragment OTHER_DELIMS_sqp   : '!' | '(' | ')' | '*' | '+' | ',' | ';';
-fragment UNRESERVED_sqp     : ALPHA_sqp | DIGIT_sqp | '-' |'.' | '_' | '~'; 
-fragment PCHAR              : UNRESERVED_sqp | PCT_ENCODED_sqp | SUB_DELIMS_sqp | ':' | '@'; 
-fragment PCHARSTART         : UNRESERVED_sqp | PCT_ENCODED_sqp | '$' | /*'&' |*/ '\'' | OTHER_DELIMS_sqp | ':' | '@'; 
-
-ATOM : [Aa][Tt][Oo][Mm];
-JSON : [Jj][Ss][Oo][Nn];
-XML  : [Xx][Mm][Ll];
-
-PCHARS : PCHARSTART PCHAR*;
-
-SLASH_sqp : '/' -> type(SLASH);
-EQ_sqp    : '=' -> type(EQ);
-FRAGMENT_sqp  : '#'     -> type(FRAGMENT),  pushMode(MODE_FRAGMENT);
-
-//handle characters that failed to match any other token
-ERROR_CHARACTER_sqp : .;
-
-//;==============================================================================
-mode MODE_FRAGMENT;
-// Read the remaining characters of a URI queryparameter up to an & or # 
-// character.
-//;==============================================================================
-
-REST_F          	: ~('\r'|'\n')* -> type(REST),  popMode;
-
-//;==============================================================================
-mode MODE_SYSTEM_QUERY_REST;
-// Read the remaining characters of a URI queryparameter up to an & or # 
-// character.
-//;==============================================================================
-
-AMP_sqr       			: '&'     -> type(AMP),       popMode;
-FRAGMENT_sqr  			: '#'     -> type(FRAGMENT),  popMode;
-
-EQ_sqr        		 	: '='     -> type(EQ);
-REST          		 	: ~[&#=] ~[&#]*;
-ERROR_CHARACTER_sqmr 	: .;
-
-//;==============================================================================
-mode MODE_SYSTEM_QUERY_SEARCH;
-//;==============================================================================
-
-NOT_sqc             	: 'NOT'   -> type(NOT);
-AND_sqc             	: 'AND'   -> type(AND);
-OR_sqc              	: 'OR'    -> type(OR);
-EQ_sqc              	: '='     -> type(EQ);
-
-fragment WS_sqc     	: ( ' ' | '\u0009');
-WSP_sqc             	: WS_sqc+ -> type(WSP);
-
-QUOTATION_MARK_sqc  	: '\u0022';
-
-SEARCHWORD          	: ('a'..'z'|'A'..'Z')+;
-SEARCHPHRASE        	: QUOTATION_MARK_sqc ~["]* QUOTATION_MARK_sqc;
-
-// Follow Set
-CLOSE_qs            	: ')' -> popMode, type(CLOSE);   
-SEMI_qs             	: ';' -> popMode, type(SEMI);   
-AMP_qs              	: '&' -> popMode, type(AMP);
-ERROR_CHARACTER_sqms	: .;
-
-//;==============================================================================
-mode MODE_STRING;
-// Reads the remaining characters up to an ' character.
-// Any "'" characters inside a string are expressed as double "''".
-//;==============================================================================
-
-STRING_s            	: ('\'\'' | ~[\u0027] )* '\'' -> type(STRING), popMode;
-ERROR_CHARACTER_sm		: EOF | .;
-
-//;==============================================================================
-mode MODE_JSON_STRING;
-// Reads the remaining characters up to an " character.
-// Any """ characters inside a string are escaped with "\".
-//;==============================================================================
-
-STRING_IN_JSON				: (ESCAPED_JSON_CHAR | ~["\\])* '"' -> popMode;
-fragment ESCAPED_JSON_CHAR	: '\\' (["\\/bfnrt] | UNICODE_CHAR);
-fragment UNICODE_CHAR 		: 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT;
-fragment HEX_DIGIT			: [0-9a-fA-F];
-ERROR_CHARACTER_jsm			: EOF | .;
-
-//;==============================================================================
-mode MODE_ODATA_GEO;
-//;==============================================================================
-
-fragment C_  : 'c'|'C';
-fragment D_  : 'd'|'D';
-fragment E_  : 'e'|'E';
-fragment G_  : 'g'|'G';
-fragment H_  : 'h'|'H';
-fragment I_  : 'i'|'I';
-fragment L_  : 'l'|'L';
-fragment M_  : 'm'|'M';
-fragment N_  : 'n'|'N';
-fragment O_  : 'o'|'O';
-fragment P_  : 'p'|'P';
-fragment R_  : 'r'|'R';
-fragment S_  : 's'|'S';
-fragment T_  : 't'|'T';
-fragment U_  : 'u'|'U';
-fragment Y_  : 'y'|'Y';
-
-fragment SP_g   : ' ';                  //'\u0020'; // a simple space
-fragment WS_g   : ( ' ' | '\u0009' );
-
-OPEN_g          : '('   -> type(OPEN);
-CLOSE_g         : ')'   -> type(CLOSE);
-COMMA_g         : ','   -> type(COMMA);
-WSP_g           : WS_g+ -> type(WSP);
-POINT_g         : '.'   -> type(POINT);
-AT_g            : '@'   -> type(AT);
-SEMI_g          : ';'   -> type(SEMI);
-EQ_g            : '='   -> type(EQ);
-
-fragment DIGIT_g    : '0'..'9';
-fragment DIGITS_g   : DIGIT_g+;
-SIGN_g              : ('+' | '-') -> type(SIGN);
-INT_g               : SIGN_g? DIGITS_g -> type(INT);
-DECIMAL_g           : 'SS' INT_g '.' DIGITS_g (('e'|'E') SIGN_g?  DIGITS_g)? -> type(DECIMAL);
-COLLECTION_g        : C_ O_ L_ L_ E_ C_ T_ I_ O_ N_ -> type(COLLECTION);
-LINESTRING          : L_ I_ N_ E_ S_ T_ R_ I_ N_ G_ ;
-MULTILINESTRING     : M_ U_ L_ T_ I_ L_ I_ N_ E_ S_ T_ R_ I_ N_ G_;
-MULTIPOINT          : M_ U_ L_ T_ I_ P_ O_ I_ N_ T_ ;
-MULTIPOLYGON        : M_ U_ L_ T_ I_ P_ O_ L_ Y_ G_ O_ N_;
-GEO_POINT           : P_ O_ I_ N_ T_;
-POLYGON             : P_ O_ L_ Y_ G_ O_ N_ ;
-
-SRID                : S_ R_ I_ D_;
-
-SQUOTE              : '\''  -> popMode;
-
-ERROR_CHARACTER_g	: .;

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/26080f42/lib/server-core/src/main/antlr4/org/apache/olingo/server/core/uri/antlr/UriParser.g4
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/antlr4/org/apache/olingo/server/core/uri/antlr/UriParser.g4 b/lib/server-core/src/main/antlr4/org/apache/olingo/server/core/uri/antlr/UriParser.g4
deleted file mode 100644
index 5a24b29..0000000
--- a/lib/server-core/src/main/antlr4/org/apache/olingo/server/core/uri/antlr/UriParser.g4
+++ /dev/null
@@ -1,447 +0,0 @@
-/*******************************************************************************
- * 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.
- ******************************************************************************/
-
-grammar UriParser;
-
-//------------------------------------------------------------------------------
-// This grammar refers to the "odata-abnf-construction-rules.txt" Revision 517.
-// URL: https://tools.oasis-open.org/version-control/browse/wsvn/odata/trunk/spec/ABNF/odata-abnf-construction-rules.txt?rev=517
-
-// While contructing this grammar we tried to keep it close to the ABNF.
-// However this is not really possible in order to support
-// - percent decoding
-// - operator precedence
-// - having a context free grammar ( without java snipplets to add context)
-// - generating the parser in different target languages
-// Currently not supported are 
-// - $search
-// - geometry data
-// - json data in url
-//------------------------------------------------------------------------------
-
-
-options {
-    language   = Java;
-    tokenVocab = UriLexer;
-}
-
-//;------------------------------------------------------------------------------
-//; 0. URI
-//;------------------------------------------------------------------------------
-
-batchEOF            : BATCH EOF;
-
-entityEOF           : vNS=namespace vODI=odataIdentifier;
-
-metadataEOF         : METADATA EOF;
-
-//;------------------------------------------------------------------------------
-//; 1. Resource Path
-//;------------------------------------------------------------------------------
-
-//resourcePathEOF     : vlPS=pathSegments EOF;
-
-crossjoinEOF        : CROSSJOIN OPEN WSP? vlODI+=odataIdentifier WSP? ( COMMA WSP? vlODI+=odataIdentifier  WSP?)* CLOSE EOF;
-
-allEOF              : ALL;
-
-pathSegmentEOF      : (pathSegment | constSegment) EOF;
-
-pathSegments        : vlPS+=pathSegment (SLASH vlPS+=pathSegment)* (SLASH vCS=constSegment)?;
-
-pathSegment         : vNS=namespace? vODI=odataIdentifier vlNVO+=nameValueOptList*;
-
-nameValueOptList    : OPEN (vVO=commonExpr | vNVL=nameValueList)? CLOSE;
-nameValueList       : WSP* vlNVP+=nameValuePair WSP* ( COMMA WSP* vlNVP+=nameValuePair  WSP*)* ;
-nameValuePair       : vODI=odataIdentifier EQ (AT vALI=odataIdentifier | vCOM=commonExpr /*TODO | val2=enumX*/);
-
-constSegment        : (vV=value | vC=count | vR=ref | vAll=allExpr | vAny=anyExpr);
-
-count               : COUNT;
-ref                 : REF;
-value               : VALUE;
-
-//;------------------------------------------------------------------------------
-//; 2. Query Options
-//;------------------------------------------------------------------------------
-
-queryOptions        : vlQO+=queryOption ( AMP vlQO+=queryOption )*;//TODO can this be removed
-
-queryOption         : systemQueryOption; 
-
-systemQueryOption   : expand
-                    | filter 
-                    | inlinecount 
-                    | orderBy
-                    | search
-                    | select 
-                    | skip 
-                    | skiptoken
-                    | top
-                    ;
-
-skiptoken           : SKIPTOKEN EQ REST;
-expand              : EXPAND EQ expandItems;
-
-expandItemsEOF      : expandItems EOF;
-expandItems         : vlEI+=expandItem ( COMMA vlEI+=expandItem )*; 
-
-
-expandItem          : vS=STAR ( SLASH vR=ref | OPEN LEVELS EQ ( vL=INT | vM=MAX)  CLOSE )?
-                    | vEP=expandPath vEPE=expandPathExtension?;
-
-
-expandPath          : vlPS+=pathSegment (SLASH vlPS+=pathSegment)*;
-
-expandPathExtension : OPEN vlEO+=expandOption                        ( SEMI vlEO+=expandOption       )* CLOSE 
-                    | SLASH vR=ref   ( OPEN vlEOR+=expandRefOption   ( SEMI vlEOR+=expandRefOption   )* CLOSE )?
-                    | SLASH vC=count ( OPEN vlEOC+=expandCountOption ( SEMI vlEOC+=expandCountOption )* CLOSE )?
-                    ;  
-
-expandCountOption   : filter
-                    | searchInline
-                    ;
-
-expandRefOption     : expandCountOption
-                    | orderBy
-                    | skip
-                    | top 
-                    | inlinecount
-                    ;
-
-expandOption        : expandRefOption
-                    | select 
-                    | expand
-                    | levels;
-
-levels              : LEVELS EQ ( INT | MAX );
-
-filter              : FILTER EQ commonExpr;
-
-filterExpressionEOF : commonExpr EOF;
-
-orderBy             : ORDERBY EQ orderList;
-
-orderByEOF          : orderList EOF;
-
-orderList           : vlOI+=orderByItem ( WSP* COMMA WSP* vlOI+=orderByItem )*;
-
-orderByItem         : vC=commonExpr ( WSP ( vA=ASC | vD=DESC ) )?;
-
-skip                : SKIP_QO EQ INT;
-top                 : TOP EQ INT;
-//format              : FORMAT EQ ( ATOM | JSON | XML | PCHARS SLASH PCHARS);
-
-inlinecount         : COUNT EQ booleanNonCaseLiteral;
-
-search              : SEARCH searchSpecialToken;
-searchInline        : SEARCH_INLINE searchSpecialToken;
-
-searchSpecialToken  : EQ WSP? searchExpr;
-
-searchExpr          : (NOT WSP) searchExpr
-                    | searchExpr searchExpr
-                    | searchExpr  WSP searchExpr
-                    | searchExpr ( WSP AND WSP) searchExpr
-                    | searchExpr ( WSP OR WSP) searchExpr
-                    | searchPhrase
-                    | searchWord
-                    ;
-
-searchPhrase        : SEARCHPHRASE;
-searchWord          : SEARCHWORD;  
-
-select              : SELECT EQ vlSI+=selectItem ( COMMA vlSI+=selectItem )*;
-selectEOF           : vlSI+=selectItem ( COMMA vlSI+=selectItem )*;
-
-selectItem          : vlSS+=selectSegment ( SLASH vlSS+=selectSegment ) *;
-selectSegment       : vNS=namespace? ( vODI=odataIdentifier | vS=STAR );
-
-aliasAndValue       : vODI=ODATAIDENTIFIER EQ vV=parameterValue;
-
-parameterValue      : commonExpr  //TODO json not supported arrayOrObject
-                    ;
-
-//;------------------------------------------------------------------------------
-//; 3. Context URL Fragments
-//;------------------------------------------------------------------------------
-
-contextFragment     : REST; // the context fragment is only required on the client side
-
-//;------------------------------------------------------------------------------
-//; 4. Expressions
-//;------------------------------------------------------------------------------
-
-commonExpr          : OPEN commonExpr CLOSE                                                             #altPharenthesis
-                    | vE1=commonExpr (WSP HAS WSP) vE2=commonExpr                                       #altHas
-                    | methodCallExpr                                                                    #altMethod
-                    | ( unary WSP? ) commonExpr                                                         #altUnary
-                    | anyExpr                                                                           #altAny
-                    | allExpr                                                                           #altAll
-                    | memberExpr                                                                        #altMember
-                    | vE1=commonExpr (WSP vO=MUL WSP | WSP vO=DIV WSP | WSP vO=MOD WSP ) vE2=commonExpr #altMult
-                    | vE1=commonExpr (WSP vO=ADD WSP | WSP vO=SUB WSP) vE2=commonExpr                   #altAdd
-                    | vE1=commonExpr (WSP vO=GT WSP | WSP vO=GE WSP | WSP vO=LT WSP 
-                                     | WSP vO=LE WSP ) vE2=commonExpr                                   #altComparism
-                    | vE1=commonExpr (WSP vO=EQ_ALPHA WSP | WSP vO=NE WSP) vE2=commonExpr               #altEquality
-                    | vE1=commonExpr (WSP AND WSP) vE2=commonExpr                                       #altAnd
-                    | vE1=commonExpr (WSP OR WSP) vE2=commonExpr                                        #altOr
-                    | rootExpr                                                                          #altRoot     // $...
-                    | AT odataIdentifier                                                                #altAlias    // @...
-                    | primitiveLiteral                                                                  #altLiteral  // ...
-                    | arrayOrObject																		#altJson
-                    ;
-
-unary               : (MINUS| NOT) ;
-
-rootExpr            : ROOT vPs=pathSegments;
-
-memberExpr          :  vIt=IT ( SLASH (vANY=anyExpr | vALL=allExpr))?
-                    |  vIts=ITSLASH? vPs=pathSegments ( SLASH (vANY=anyExpr | vALL=allExpr))?;
-
-anyExpr             : ANY_LAMDA OPEN WSP? ( vLV=odataIdentifier WSP? COLON WSP? vLE=commonExpr WSP? )? CLOSE;
-allExpr             : ALL_LAMDA OPEN WSP?   vLV=odataIdentifier WSP? COLON WSP? vLE=commonExpr WSP? CLOSE;
-
-methodCallExpr      : indexOfMethodCallExpr
-                    | toLowerMethodCallExpr
-                    | toUpperMethodCallExpr
-                    | trimMethodCallExpr
-                    | substringMethodCallExpr
-                    | concatMethodCallExpr
-                    | lengthMethodCallExpr
-                    | yearMethodCallExpr
-                    | monthMethodCallExpr
-                    | dayMethodCallExpr
-                    | hourMethodCallExpr
-                    | minuteMethodCallExpr
-                    | secondMethodCallExpr
-                    | fractionalsecondsMethodCallExpr
-                    | totalsecondsMethodCallExpr
-                    | dateMethodCallExpr
-                    | timeMethodCallExpr
-                    | roundMethodCallExpr
-                    | floorMethodCallExpr
-                    | ceilingMethodCallExpr
-                    | geoDistanceMethodCallExpr
-                    | geoLengthMethodCallExpr
-                    | totalOffsetMinutesMethodCallExpr
-                    | minDateTimeMethodCallExpr
-                    | maxDateTimeMethodCallExpr
-                    | nowMethodCallExpr
-                    //from boolean
-                    | isofExpr
-                    | castExpr
-                    | endsWithMethodCallExpr
-                    | startsWithMethodCallExpr
-                    | containsMethodCallExpr
-                    | geoIntersectsMethodCallExpr
-                    ;
-
-
-containsMethodCallExpr    : CONTAINS_WORD    WSP? vE1=commonExpr WSP? COMMA WSP? vE2=commonExpr WSP? CLOSE;
-startsWithMethodCallExpr  : STARTSWITH_WORD  WSP? vE1=commonExpr WSP? COMMA WSP? vE2=commonExpr WSP? CLOSE;
-endsWithMethodCallExpr    : ENDSWITH_WORD    WSP? vE1=commonExpr WSP? COMMA WSP? vE2=commonExpr WSP? CLOSE;
-lengthMethodCallExpr      : LENGTH_WORD      WSP? vE1=commonExpr WSP? CLOSE;
-indexOfMethodCallExpr     : INDEXOF_WORD     WSP? vE1=commonExpr WSP? COMMA WSP? vE2=commonExpr WSP? CLOSE;
-substringMethodCallExpr   : SUBSTRING_WORD   WSP? vE1=commonExpr WSP? COMMA WSP? vE2=commonExpr WSP? ( COMMA WSP? vE3=commonExpr WSP? )? CLOSE;
-toLowerMethodCallExpr     : TOLOWER_WORD     WSP? vE1=commonExpr WSP? CLOSE;
-toUpperMethodCallExpr     : TOUPPER_WORD     WSP? vE1=commonExpr WSP? CLOSE;
-trimMethodCallExpr        : TRIM_WORD        WSP? vE1=commonExpr WSP? CLOSE;
-concatMethodCallExpr      : CONCAT_WORD      WSP? vE1=commonExpr WSP? COMMA WSP? vE2=commonExpr WSP? CLOSE;
-
-yearMethodCallExpr                : YEAR_WORD                WSP? vE1=commonExpr WSP? CLOSE;
-monthMethodCallExpr               : MONTH_WORD               WSP? vE1=commonExpr WSP? CLOSE;
-dayMethodCallExpr                 : DAY_WORD                 WSP? vE1=commonExpr WSP? CLOSE;
-hourMethodCallExpr                : HOUR_WORD                WSP? vE1=commonExpr WSP? CLOSE;
-minuteMethodCallExpr              : MINUTE_WORD              WSP? vE1=commonExpr WSP? CLOSE;
-secondMethodCallExpr              : SECOND_WORD              WSP? vE1=commonExpr WSP? CLOSE;
-fractionalsecondsMethodCallExpr   : FRACTIONALSECONDS_WORD   WSP? vE1=commonExpr WSP? CLOSE;
-totalsecondsMethodCallExpr        : TOTALSECONDS_WORD        WSP? vE1=commonExpr WSP? CLOSE;
-dateMethodCallExpr                : DATE_WORD                WSP? vE1=commonExpr WSP? CLOSE;
-timeMethodCallExpr                : TIME_WORD                WSP? vE1=commonExpr WSP? CLOSE;
-totalOffsetMinutesMethodCallExpr  : TOTALOFFSETMINUTES_WORD  WSP? vE1=commonExpr WSP? CLOSE;
-
-minDateTimeMethodCallExpr         : MINDATETIME_WORD WSP? CLOSE;
-maxDateTimeMethodCallExpr         : MAXDATETIME_WORD WSP? CLOSE;
-nowMethodCallExpr                 : NOW_WORD         WSP? CLOSE;
-
-roundMethodCallExpr               : ROUND_WORD   WSP? vE1=commonExpr WSP? CLOSE;
-floorMethodCallExpr               : FLOOR_WORD   WSP? vE1=commonExpr WSP? CLOSE;
-ceilingMethodCallExpr             : CEILING_WORD WSP? vE1=commonExpr WSP? CLOSE;
-
-geoDistanceMethodCallExpr         : GEO_DISTANCE_WORD   WSP? vE1=commonExpr WSP? COMMA WSP? vE2=commonExpr WSP? CLOSE;
-geoLengthMethodCallExpr           : GEO_LENGTH_WORD     WSP? vE1=commonExpr WSP? CLOSE;
-geoIntersectsMethodCallExpr       : GEO_INTERSECTS_WORD WSP? vE1=commonExpr WSP? COMMA WSP? vE2=commonExpr WSP? CLOSE;
-
-isofExpr                          : ISOF_WORD  WSP? ( vE1=commonExpr WSP? COMMA WSP? )? vNS=namespace vODI=odataIdentifier WSP? CLOSE;
-castExpr                          : CAST_WORD  WSP? ( vE1=commonExpr WSP? COMMA WSP? )? vNS=namespace vODI=odataIdentifier WSP? CLOSE;
-
-//;------------------------------------------------------------------------------
-//; 5. JSON format for function parameters
-//;------------------------------------------------------------------------------
-//; Note: the query part of a URI needs to be partially percent-decoded before
-//; applying these rules, see comment at the top of this file
-//;------------------------------------------------------------------------------
-
-arrayOrObject       : json_array
-                    | json_object;
-
-json_array          : BEGIN_ARRAY (json_value (WS* COMMA WS* json_value)*)? END_ARRAY;
-
-json_value          : jsonPrimitive
-                    | rootExpr
-                    | json_object
-                    | json_array;
-
-json_object         : BEGIN_OBJECT
-                      (json_key_value_pair (WS* COMMA WS* json_key_value_pair)*)?
-                      END_OBJECT;
-
-json_key_value_pair : STRING_IN_JSON WS* COLON WS* json_value;
-
-//; JSON syntax: adapted to URI restrictions from [RFC4627]                 
-jsonPrimitive 		: STRING_IN_JSON
-                    | number_in_json
-                    | TRUE
-                    | FALSE
-                    | NULLVALUE
-                    ;
-
-number_in_json		: INT | DECIMAL;
-
-//;------------------------------------------------------------------------------
-//; 6. Names and identifiers
-//;------------------------------------------------------------------------------
-
-qualifiedtypename       : namespace odataIdentifier
-                        | 'collection' OPEN ( namespace odataIdentifier ) CLOSE
-                        ;
-
-namespace               : (odataIdentifier POINT)+;
-
-odataIdentifier         : ODATAIDENTIFIER;
-
-//;------------------------------------------------------------------------------
-//; 7. Literal Data Values
-//;------------------------------------------------------------------------------
-
-
-primitiveLiteral    : nullruleLiteral
-                    | booleanNonCaseLiteral
-                    | decimalLiteral   //includes double and single literals
-                    | naninfinityLiteral
-                    | intLiteral       //includes int16/int32 and int64 literals
-                    | binaryLiteral  
-                    | dateLiteral
-                    | datetimeoffsetLiteral
-                    | durationLiteral
-                    | guidLiteral
-                    | stringLiteral
-                    | timeofdayLiteral
-                    | enumLiteral
-                    | geographyCollection
-                    | geographyLineString
-                    | geographyMultilineString
-                    | geographyMultipoint
-                    | geographyMultipolygon
-                    | geographyPoint
-                    | geographyPolygon
-                    | geometryCollection
-                    | geometryLineString
-                    | geometryMultilineString
-                    | geometryMultipoint
-                    | geometryMultipolygon
-                    | geometryPoint
-                    | geometryPolygon
-                    ;
-
-
-nullruleLiteral            : NULLVALUE;
-booleanNonCaseLiteral      : BOOLEAN | TRUE | FALSE;
-decimalLiteral             : DECIMAL;
-naninfinityLiteral         : NANINFINITY;
-intLiteral                 : INT;
-binaryLiteral              : BINARY;
-dateLiteral                : DATE;
-datetimeoffsetLiteral      : DATETIMEOFFSET;
-durationLiteral            : DURATION;
-guidLiteral                : GUID;
-stringLiteral              : STRING;
-timeofdayLiteral           : TIMEOFDAY;
-
-enumLiteral                : vNS=namespace vODI=odataIdentifier vValues=STRING;
-enumValues                 : vlODI+=odataIdentifier ( COMMA vlODI+=odataIdentifier )*;
-
-geographyCollection         : GEOGRAPHY  fullCollectionLiteral SQUOTE;
-fullCollectionLiteral       : sridLiteral collectionLiteral;
-
-collectionLiteral           : (COLLECTION ) OPEN geoLiteral ( COMMA geoLiteral )* CLOSE;
-
-geoLiteral                  : collectionLiteral
-                            | lineStringLiteral
-                            | multipointLiteral
-                            | multilineStringLiteral
-                            | multipolygonLiteral
-                            | pointLiteral
-                            | polygonLiteral;
-
-geographyLineString         : GEOGRAPHY  fullLineStringLiteral SQUOTE;
-fullLineStringLiteral       : sridLiteral lineStringLiteral;
-lineStringLiteral           : LINESTRING lineStringData;
-lineStringData              : OPEN positionLiteral ( COMMA positionLiteral )* CLOSE;
-
-geographyMultilineString    : GEOGRAPHY  fullMultilineStringLiteral SQUOTE;
-fullMultilineStringLiteral  : sridLiteral multilineStringLiteral;
-multilineStringLiteral      : MULTILINESTRING OPEN ( lineStringData ( COMMA lineStringData )* )? CLOSE;
-
-geographyMultipoint         : GEOGRAPHY  fullMultipointLiteral SQUOTE;
-fullMultipointLiteral       : sridLiteral multipointLiteral;
-multipointLiteral           : MULTIPOINT OPEN ( pointData ( COMMA pointData )* )? CLOSE ;
-
-geographyMultipolygon       : GEOGRAPHY  fullmultipolygonLiteral SQUOTE;
-fullmultipolygonLiteral     : sridLiteral multipolygonLiteral;
-multipolygonLiteral         : MULTIPOLYGON OPEN ( polygonData ( COMMA polygonData )* )? CLOSE;
-
-geographyPoint              : GEOGRAPHY  fullpointLiteral SQUOTE;
-fullpointLiteral            : sridLiteral pointLiteral;
-
-pointLiteral                : GEO_POINT pointData;
-pointData                   : OPEN positionLiteral CLOSE;
-
-positionLiteral             : (DECIMAL | INT ) WSP (DECIMAL | INT );  //; longitude, then latitude
-
-
-geographyPolygon            : GEOGRAPHY fullPolygonLiteral SQUOTE;
-fullPolygonLiteral          : sridLiteral polygonLiteral;
-polygonLiteral              : POLYGON polygonData;
-polygonData                 : OPEN ringLiteral ( COMMA ringLiteral )* CLOSE;
-ringLiteral                 : OPEN positionLiteral ( COMMA positionLiteral )* CLOSE;
-                            
-
-geometryCollection          : GEOMETRY  fullCollectionLiteral      SQUOTE;
-geometryLineString          : GEOMETRY  fullLineStringLiteral      SQUOTE;
-geometryMultilineString     : GEOMETRY  fullMultilineStringLiteral SQUOTE;
-geometryMultipoint          : GEOMETRY  fullMultipointLiteral      SQUOTE;
-geometryMultipolygon        : GEOMETRY  fullmultipolygonLiteral    SQUOTE;
-geometryPoint               : GEOMETRY  fullpointLiteral           SQUOTE;
-geometryPolygon             : GEOMETRY  fullPolygonLiteral         SQUOTE;
-
-sridLiteral                 : SRID EQ INT SEMI;
-
-

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/26080f42/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/CheckFullContextListener.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/CheckFullContextListener.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/CheckFullContextListener.java
deleted file mode 100644
index bdfdf4c..0000000
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/CheckFullContextListener.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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.BitSet;
-
-import org.antlr.v4.runtime.DiagnosticErrorListener;
-import org.antlr.v4.runtime.Parser;
-import org.antlr.v4.runtime.RecognitionException;
-import org.antlr.v4.runtime.Recognizer;
-import org.antlr.v4.runtime.atn.ATNConfigSet;
-import org.antlr.v4.runtime.dfa.DFA;
-
-class CheckFullContextListener extends DiagnosticErrorListener {
-
-  @Override
-  public void syntaxError(final Recognizer<?, ?> recognizer, final Object offendingSymbol, final int line,
-      final int charPositionInLine,
-      final String msg, final RecognitionException e) {
-    // System.err.println("syntaxError detected");
-  }
-
-  @Override
-  public void reportAmbiguity(final Parser recognizer, final DFA dfa, final int startIndex, final int stopIndex,
-      final boolean exact,
-      final BitSet ambigAlts, final ATNConfigSet configs) {
-    // System.err.println("reportAmbiguity detected");
-  }
-
-  @Override
-  public void reportAttemptingFullContext(final Parser recognizer, final DFA dfa, final int startIndex,
-      final int stopIndex,
-      final BitSet conflictingAlts, final ATNConfigSet configs) {
-    // System.err.println("reportAttemptingFullContext detected");
-  }
-
-  @Override
-  public void reportContextSensitivity(final Parser recognizer, final DFA dfa, final int startIndex,
-      final int stopIndex, final int prediction,
-      final ATNConfigSet configs) {
-    // System.err.println("reportContextSensitivity detected");
-  }
-
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/26080f42/lib/server-test/pom.xml
----------------------------------------------------------------------
diff --git a/lib/server-test/pom.xml b/lib/server-test/pom.xml
index 7def3ef..3b48d9e 100644
--- a/lib/server-test/pom.xml
+++ b/lib/server-test/pom.xml
@@ -47,10 +47,6 @@
       <scope>test</scope>
     </dependency>
     <dependency>
-      <groupId>org.antlr</groupId>
-      <artifactId>antlr4-runtime</artifactId>
-    </dependency>
-    <dependency>
       <groupId>junit</groupId>
       <artifactId>junit</artifactId>
     </dependency>

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/26080f42/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 66b5ffc..7005233 100644
--- a/pom.xml
+++ b/pom.xml
@@ -86,8 +86,6 @@
     <jackson.version>2.4.2</jackson.version>
     <aalto-xml.version>0.9.10</aalto-xml.version>
 
-    <antlr.version>4.5</antlr.version>
-
     <android.platform.version>4.1.1.4</android.platform.version>
     <stax.api.version>1.0-2</stax.api.version>
     <woodstox.stax2-api.version>3.1.4</woodstox.stax2-api.version>
@@ -133,12 +131,6 @@
       </dependency>
 
       <dependency>
-        <groupId>org.antlr</groupId>
-        <artifactId>antlr4-runtime</artifactId>
-        <version>${antlr.version}</version>
-      </dependency>
-
-      <dependency>
         <groupId>org.apache.felix</groupId>
         <artifactId>maven-bundle-plugin</artifactId>
         <version>${maven.bundle.plugin.version}</version>
@@ -316,11 +308,6 @@
           <version>1.9</version>
         </plugin>
         <plugin>
-          <groupId>org.antlr</groupId>
-          <artifactId>antlr4-maven-plugin</artifactId>
-          <version>${antlr.version}</version>
-        </plugin>
-        <plugin>
           <groupId>com.keyboardsamurais.maven</groupId>
           <artifactId>maven-timestamp-plugin</artifactId>
           <version>1.0</version>
@@ -543,7 +530,6 @@
               <exclude>org/apache/olingo/**/tecsvc/**/*.class</exclude>
               <exclude>org/apache/olingo/**/fit/**/*.class</exclude>
               <exclude>org/apache/olingo/**/testutil/**/*.class</exclude>
-              <exclude>org/apache/olingo/**/antlr/**/*.class</exclude>
             </excludes>
           </instrumentation>
           <check/>


[19/30] olingo-odata4 git commit: [OLINGO-834] ExpressionParser improvements

Posted by ch...@apache.org.
[OLINGO-834] ExpressionParser improvements


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

Branch: refs/heads/master
Commit: 8919d3ef1198f19b3a2fbc1c8a05e8d39013fcd5
Parents: a809165
Author: Christian Holzer <c....@sap.com>
Authored: Tue Dec 22 17:07:51 2015 +0100
Committer: Christian Holzer <c....@sap.com>
Committed: Tue Dec 22 17:07:51 2015 +0100

----------------------------------------------------------------------
 .../tecsvc/client/FilterSystemQueryITCase.java  |  37 ++-
 .../tecsvc/client/OrderBySystemQueryITCase.java |   3 +
 .../core/uri/parser/ExpressionParser.java       | 309 +++++++++++++------
 .../server/core/uri/parser/FilterParser.java    |   4 +-
 .../olingo/server/core/uri/parser/Parser.java   |   6 +-
 .../uri/parser/UriParserSemanticException.java  |   4 +-
 .../server/core/uri/parser/UriTokenizer.java    |  23 +-
 .../server-core-exceptions-i18n.properties      |   1 +
 .../core/uri/antlr/TestFullResourcePath.java    |  58 ++--
 9 files changed, 291 insertions(+), 154 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8919d3ef/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/FilterSystemQueryITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/FilterSystemQueryITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/FilterSystemQueryITCase.java
index 4ecca7c..ca6eb21 100644
--- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/FilterSystemQueryITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/FilterSystemQueryITCase.java
@@ -35,8 +35,11 @@ import org.apache.olingo.commons.api.edm.FullQualifiedName;
 import org.apache.olingo.commons.api.http.HttpHeader;
 import org.apache.olingo.commons.api.http.HttpStatusCode;
 import org.junit.Assert;
+import org.junit.Ignore;
 import org.junit.Test;
 
+// TODO
+@Ignore
 public class FilterSystemQueryITCase extends AbstractParamTecSvcITCase {
 
   private static final String ES_COMP_ALL_PRIM = "ESCompAllPrim";
@@ -223,18 +226,18 @@ public class FilterSystemQueryITCase extends AbstractParamTecSvcITCase {
   public void methodCallsWithNull() {
     // One representative of "stringFuntion" "residue class"
     ODataRetrieveResponse<ClientEntitySet> result =
-        sendRequest(ES_ALL_PRIM, "endswith(PropertyString, null) eq null"); // null eq null => true
+        sendRequest(ES_ALL_PRIM, "endswith(PropertyString,null) eq null"); // null eq null => true
     assertEquals(3, result.getBody().getEntities().size());
 
     // One representative of "stringifiedValueFunction" "residue class"
-    result = sendRequest(ES_ALL_PRIM, "substring(PropertyString, null) eq null"); // null eq null => true
+    result = sendRequest(ES_ALL_PRIM, "substring(PropertyString,null) eq null"); // null eq null => true
     assertEquals(3, result.getBody().getEntities().size());
 
     // Substring
     result = sendRequest(ES_ALL_PRIM, "hour(null) eq null"); // null eq null => true
     assertEquals(3, result.getBody().getEntities().size());
 
-    result = sendRequest(ES_ALL_PRIM, "substring(PropertyString, 0, null) eq null"); // null eq null => true
+    result = sendRequest(ES_ALL_PRIM, "substring(PropertyString,0,null) eq null"); // null eq null => true
     assertEquals(3, result.getBody().getEntities().size());
   }
 
@@ -244,13 +247,13 @@ public class FilterSystemQueryITCase extends AbstractParamTecSvcITCase {
 
     // -1 should be treated as 0
     ODataRetrieveResponse<ClientEntitySet> response =
-        sendRequest(ES_ALL_PRIM, "substring(PropertyString, -1, 1) eq 'F'");
+        sendRequest(ES_ALL_PRIM, "substring(PropertyString,-1,1) eq 'F'");
     assertEquals(1, response.getBody().getEntities().size());
     assertShortOrInt(32767, response.getBody().getEntities().get(0).getProperty("PropertyInt16")
           .getPrimitiveValue().toValue());
 
     // -1 should be treated as 0, Same values substring(PropertyString, 0, 0) returns the empty String
-    response = sendRequest(ES_ALL_PRIM, "substring(PropertyString, 0, -1) eq ''");
+    response = sendRequest(ES_ALL_PRIM, "substring(PropertyString,0,-1) eq ''");
     assertEquals(3, response.getBody().getEntities().size());
   }
 
@@ -354,7 +357,7 @@ public class FilterSystemQueryITCase extends AbstractParamTecSvcITCase {
 
   @Test
   public void notOperator() {
-    ODataRetrieveResponse<ClientEntitySet> result = sendRequest(ES_TWO_KEY_NAV, "not (PropertyInt16 eq 1)");
+    ODataRetrieveResponse<ClientEntitySet> result = sendRequest(ES_TWO_KEY_NAV, "not(PropertyInt16 eq 1)");
     assertEquals(2, result.getBody().getEntities().size());
 
     ClientEntity clientEntity = result.getBody().getEntities().get(0);
@@ -368,7 +371,7 @@ public class FilterSystemQueryITCase extends AbstractParamTecSvcITCase {
 
   @Test
   public void unaryMinusOperator() {
-    ODataRetrieveResponse<ClientEntitySet> result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 gt -2 add - -3");
+    ODataRetrieveResponse<ClientEntitySet> result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 gt -2 add --3");
     assertEquals(2, result.getBody().getEntities().size());
 
     ClientEntity clientEntity = result.getBody().getEntities().get(0);
@@ -382,7 +385,7 @@ public class FilterSystemQueryITCase extends AbstractParamTecSvcITCase {
 
   @Test
   public void unaryMinusOperatorDecimal() {
-    ODataRetrieveResponse<ClientEntitySet> result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 gt -2.0 add - -3.0");
+    ODataRetrieveResponse<ClientEntitySet> result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 gt -2.0 add --3.0");
     assertEquals(2, result.getBody().getEntities().size());
 
     ClientEntity clientEntity = result.getBody().getEntities().get(0);
@@ -415,7 +418,7 @@ public class FilterSystemQueryITCase extends AbstractParamTecSvcITCase {
   @Test
   public void substringStartAndEndGiven() {
     ODataRetrieveResponse<ClientEntitySet> result =
-        sendRequest(ES_ALL_PRIM, "substring(PropertyString, length('First') add 1, 8) eq ('Resource')");
+        sendRequest(ES_ALL_PRIM, "substring(PropertyString,length('First') add 1,8) eq ('Resource')");
 
     assertEquals(1, result.getBody().getEntities().size());
 
@@ -426,7 +429,7 @@ public class FilterSystemQueryITCase extends AbstractParamTecSvcITCase {
   @Test
   public void substringStartGiven() {
     ODataRetrieveResponse<ClientEntitySet> result =
-        sendRequest(ES_TWO_KEY_NAV, "substring(PropertyComp/PropertyComp/PropertyString, 6) eq 'Value'");
+        sendRequest(ES_TWO_KEY_NAV, "substring(PropertyComp/PropertyComp/PropertyString,6) eq 'Value'");
 
     assertEquals(4, result.getBody().getEntities().size());
 
@@ -450,7 +453,7 @@ public class FilterSystemQueryITCase extends AbstractParamTecSvcITCase {
   @Test
   public void substringDouble() {
     fail(ES_ALL_PRIM,
-        "substring(PropertyString, length('First') add 1, 2.0 * 4) eq ('Resource')",
+        "substring(PropertyString,length('First') add 1,2.0 * 4) eq ('Resource')",
         HttpStatusCode.BAD_REQUEST);
   }
 
@@ -689,7 +692,7 @@ public class FilterSystemQueryITCase extends AbstractParamTecSvcITCase {
 
   @Test
   public void endsWith() {
-    ODataRetrieveResponse<ClientEntitySet> result = sendRequest(ES_ALL_PRIM, "endswith(PropertyString, 'values')");
+    ODataRetrieveResponse<ClientEntitySet> result = sendRequest(ES_ALL_PRIM, "endswith(PropertyString,'values')");
     assertEquals(2, result.getBody().getEntities().size());
 
     ClientEntity clientEntity = result.getBody().getEntities().get(0);
@@ -702,7 +705,7 @@ public class FilterSystemQueryITCase extends AbstractParamTecSvcITCase {
   @Test
   public void indexOf() {
     ODataRetrieveResponse<ClientEntitySet> result =
-        sendRequest(ES_ALL_PRIM, "indexof(PropertyString, 'positive') eq 17");
+        sendRequest(ES_ALL_PRIM, "indexof(PropertyString,'positive') eq 17");
     assertEquals(1, result.getBody().getEntities().size());
 
     ClientEntity clientEntity = result.getBody().getEntities().get(0);
@@ -711,7 +714,7 @@ public class FilterSystemQueryITCase extends AbstractParamTecSvcITCase {
 
   @Test
   public void startsWith() {
-    ODataRetrieveResponse<ClientEntitySet> result = sendRequest(ES_ALL_PRIM, "startswith(PropertyString, 'First')");
+    ODataRetrieveResponse<ClientEntitySet> result = sendRequest(ES_ALL_PRIM, "startswith(PropertyString,'First')");
     assertEquals(1, result.getBody().getEntities().size());
 
     ClientEntity clientEntity = result.getBody().getEntities().get(0);
@@ -721,7 +724,7 @@ public class FilterSystemQueryITCase extends AbstractParamTecSvcITCase {
   @Test
   public void toLower() {
     ODataRetrieveResponse<ClientEntitySet> result =
-        sendRequest(ES_ALL_PRIM, "contains(PropertyString, tolower('POSITIVE'))");
+        sendRequest(ES_ALL_PRIM, "contains(PropertyString,tolower('POSITIVE'))");
     assertEquals(1, result.getBody().getEntities().size());
 
     ClientEntity clientEntity = result.getBody().getEntities().get(0);
@@ -731,7 +734,7 @@ public class FilterSystemQueryITCase extends AbstractParamTecSvcITCase {
   @Test
   public void toUpper() {
     ODataRetrieveResponse<ClientEntitySet> result =
-        sendRequest(ES_ALL_PRIM, "contains(PropertyString, concat(toupper('f'), 'irst'))");
+        sendRequest(ES_ALL_PRIM, "contains(PropertyString,concat(toupper('f'),'irst'))");
     assertEquals(1, result.getBody().getEntities().size());
 
     ClientEntity clientEntity = result.getBody().getEntities().get(0);
@@ -741,7 +744,7 @@ public class FilterSystemQueryITCase extends AbstractParamTecSvcITCase {
   @Test
   public void trim() {
     ODataRetrieveResponse<ClientEntitySet> result =
-        sendRequest(ES_ALL_PRIM, "trim(substring(PropertyString, 0, 6)) eq 'First'");
+        sendRequest(ES_ALL_PRIM, "trim(substring(PropertyString,0,6)) eq 'First'");
     assertEquals(1, result.getBody().getEntities().size());
 
     ClientEntity clientEntity = result.getBody().getEntities().get(0);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8919d3ef/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/OrderBySystemQueryITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/OrderBySystemQueryITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/OrderBySystemQueryITCase.java
index 18db951..0e31b33 100644
--- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/OrderBySystemQueryITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/OrderBySystemQueryITCase.java
@@ -30,8 +30,11 @@ import org.apache.olingo.client.api.domain.ClientEntitySet;
 import org.apache.olingo.client.api.domain.ClientValuable;
 import org.apache.olingo.commons.api.http.HttpStatusCode;
 import org.junit.Assert;
+import org.junit.Ignore;
 import org.junit.Test;
 
+// TODO
+@Ignore
 public class OrderBySystemQueryITCase extends AbstractParamTecSvcITCase {
 
   private static final String ES_TWO_PRIM = "ESTwoPrim";

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8919d3ef/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java
index 2f7fdb2..049880f 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java
@@ -47,6 +47,9 @@ 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.commons.core.edm.primitivetype.EdmByte;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmSByte;
 import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.uri.UriParameter;
 import org.apache.olingo.server.api.uri.UriResourceFunction;
@@ -118,14 +121,6 @@ public class ExpressionParser {
     tokenToBinaryOperator = Collections.unmodifiableMap(temp);
   }
 
-  private static final Map<TokenKind, UnaryOperatorKind> tokenToUnaryOperator;
-  static {
-    Map<TokenKind, UnaryOperatorKind> temp = new HashMap<TokenKind, UnaryOperatorKind>();
-    temp.put(TokenKind.MINUS, UnaryOperatorKind.MINUS);
-    temp.put(TokenKind.NotOperator, UnaryOperatorKind.NOT);
-    tokenToUnaryOperator = Collections.unmodifiableMap(temp);
-  }
-
   // 'cast' and 'isof' are handled specially.
   private static final Map<TokenKind, MethodKind> tokenToMethod;
   static {
@@ -246,23 +241,53 @@ public class ExpressionParser {
     return left;
   }
 
-  // TODO: The 'isof' method has relational precedence and should appear here.
   private Expression parseExprRel() throws UriParserException, UriValidationException {
-    Expression left = parseExprAdd();
-    TokenKind operatorTokenKind = ParserHelper.next(tokenizer,
-        TokenKind.GreaterThanOperator, TokenKind.GreaterThanOrEqualsOperator,
-        TokenKind.LessThanOperator, TokenKind.LessThanOrEqualsOperator);
-    // Null for everything other than GT or GE or LT or LE
-    while (operatorTokenKind != null) {
-      final Expression right = parseExprAdd();
-      checkRelationTypes(left, right);
-      left = new BinaryImpl(left, tokenToBinaryOperator.get(operatorTokenKind), right,
-          odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Boolean));
-      operatorTokenKind = ParserHelper.next(tokenizer,
+    if(tokenizer.next(TokenKind.IsofMethod)) {
+      // The isof method is a terminal. So no further operators are allowed
+      return parseIsOfMethod(TokenKind.IsofMethod);
+    } else {
+      Expression left = parseExprAdd();
+      TokenKind operatorTokenKind = ParserHelper.next(tokenizer,
           TokenKind.GreaterThanOperator, TokenKind.GreaterThanOrEqualsOperator,
           TokenKind.LessThanOperator, TokenKind.LessThanOrEqualsOperator);
+      // Null for everything other than GT or GE or LT or LE
+      while (operatorTokenKind != null) {
+        final Expression right = parseExprAdd();
+        checkRelationTypes(left, right);
+        left = new BinaryImpl(left, tokenToBinaryOperator.get(operatorTokenKind), right,
+            odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Boolean));
+        operatorTokenKind = ParserHelper.next(tokenizer,
+            TokenKind.GreaterThanOperator, TokenKind.GreaterThanOrEqualsOperator,
+            TokenKind.LessThanOperator, TokenKind.LessThanOrEqualsOperator);
+      }
+      return left;
+    }
+  }
+
+  private Expression parseIsOfMethod(final TokenKind lastToken) throws UriParserException, UriValidationException {
+    if(lastToken == TokenKind.IsofMethod) {
+      // The TokenKind 'IsOfMethod' consumes also the opening parenthesis 
+
+      // The first parameter could be an expression or a type literal
+      final List<Expression> parameters = new ArrayList<Expression>();
+      parameters.add(parseExpression());
+      if(!(parameters.get(0) instanceof TypeLiteral)) {
+        // The first parameter is not a type literal, so there must be a second parameter
+        ParserHelper.requireNext(tokenizer, TokenKind.COMMA);
+        parameters.add(parseExpression());
+        
+        // The second parameter must be a type literal
+        if(!(parameters.get(1) instanceof TypeLiteral)) {
+          throw new UriParserSemanticException("Type literal extected", 
+              UriParserSemanticException.MessageKeys.INCOMPATIBLE_TYPE_FILTER);
+        }
+      }
+      
+      ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
+      return new MethodImpl(MethodKind.ISOF, parameters);
+    } else {
+      throw new UriParserSyntaxException("Unexpected token.", UriParserSyntaxException.MessageKeys.SYNTAX);
     }
-    return left;
   }
 
   private Expression parseExprAdd() throws UriParserException, UriValidationException {
@@ -302,44 +327,50 @@ public class ExpressionParser {
     return left;
   }
 
-  // TODO: The 'cast' method has unary precedence and should appear here.
   private Expression parseExprUnary() throws UriParserException, UriValidationException {
-    // Negative numbers start with a minus indistinguishable from an unary minus operator.
-    // So we read numbers (and primitive values starting with numbers) right here.
-    // TODO: Find a better idea how to solve this problem.
-    final TokenKind numberTokenKind = ParserHelper.next(tokenizer,
-        TokenKind.DoubleValue, TokenKind.DecimalValue, TokenKind.GuidValue,
-        TokenKind.DateTimeOffsetValue, TokenKind.DateValue, TokenKind.TimeOfDayValue,
-        TokenKind.IntegerValue);
-    if (numberTokenKind != null) {
-      final EdmPrimitiveTypeKind primitiveTypeKind = tokenToPrimitiveType.get(numberTokenKind);
-      final EdmPrimitiveType type = primitiveTypeKind == null ?
-          // Null handling
-          null :
-          odata.createPrimitiveTypeInstance(primitiveTypeKind);
-      return new LiteralImpl(tokenizer.getText(), type);
-    }
-    Expression left = null;
-    TokenKind operatorTokenKind = ParserHelper.next(tokenizer, TokenKind.MINUS, TokenKind.NotOperator);
-    // Null for everything other than - or NOT
-    while (operatorTokenKind != null) {
+    final TokenKind operatorTokenKind = ParserHelper.next(tokenizer, TokenKind.MINUS, TokenKind.NotOperator, 
+                                                                     TokenKind.CastMethod);
+    
+    if(operatorTokenKind == TokenKind.MINUS) {
       final Expression expression = parseExprPrimary();
-      if (operatorTokenKind == TokenKind.NotOperator) {
-        checkType(expression, EdmPrimitiveTypeKind.Boolean);
-      } else {
-        checkType(expression,
-            EdmPrimitiveTypeKind.Int16, EdmPrimitiveTypeKind.Int32, EdmPrimitiveTypeKind.Int64,
-            EdmPrimitiveTypeKind.Byte, EdmPrimitiveTypeKind.SByte,
-            EdmPrimitiveTypeKind.Decimal, EdmPrimitiveTypeKind.Single, EdmPrimitiveTypeKind.Double,
-            EdmPrimitiveTypeKind.Duration);
-      }
-      left = new UnaryImpl(tokenToUnaryOperator.get(operatorTokenKind), expression, getType(expression));
-      operatorTokenKind = ParserHelper.next(tokenizer, TokenKind.MINUS, TokenKind.NotOperator);
+      checkType(expression,
+          EdmPrimitiveTypeKind.Int16, EdmPrimitiveTypeKind.Int32, EdmPrimitiveTypeKind.Int64,
+          EdmPrimitiveTypeKind.Byte, EdmPrimitiveTypeKind.SByte,
+          EdmPrimitiveTypeKind.Decimal, EdmPrimitiveTypeKind.Single, EdmPrimitiveTypeKind.Double,
+          EdmPrimitiveTypeKind.Duration);
+      return new UnaryImpl(UnaryOperatorKind.MINUS, expression, getType(expression));
+    } else if(operatorTokenKind == TokenKind.NotOperator) {
+      final Expression expression = parseExprPrimary();
+      checkType(expression, EdmPrimitiveTypeKind.Boolean);
+      return new UnaryImpl(UnaryOperatorKind.NOT, expression, getType(expression));
+    } else if(operatorTokenKind == TokenKind.CastMethod) {
+      return parseCastMethod(operatorTokenKind);
+    } else {
+      final Expression expression = parseExprPrimary();
+      return expression;
     }
-    if (left == null) {
-      left = parseExprPrimary();
+  }
+
+  private Expression parseCastMethod(final TokenKind lastToken) throws UriParserException, UriValidationException {
+    // The TokenKind 'CastMethod' consumes also the opening parenthesis 
+    if(lastToken == TokenKind.CastMethod) {
+      final List<Expression> parameters = new ArrayList<Expression>();
+      parameters.add(parseExpression());
+      
+      if(!(parameters.get(0) instanceof TypeLiteral)) {
+        ParserHelper.requireNext(tokenizer, TokenKind.COMMA);
+        parameters.add(parseExpression());
+        if(!(parameters.get(1) instanceof TypeLiteral)) {
+          throw new UriParserSemanticException("Type literal extected", 
+              UriParserSemanticException.MessageKeys.INCOMPATIBLE_TYPE_FILTER);
+        }
+      }
+      
+      ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
+      return new MethodImpl(MethodKind.CAST, parameters);
+    } else {
+      throw new UriParserSyntaxException("Unexpected token.", UriParserSyntaxException.MessageKeys.SYNTAX);
     }
-    return left;
   }
 
   private Expression parseExprPrimary() throws UriParserException, UriValidationException {
@@ -380,25 +411,12 @@ public class ExpressionParser {
 
     final TokenKind nextPrimitive = ParserHelper.nextPrimitiveValue(tokenizer);
     if (nextPrimitive != null) {
-      final String primitiveValueLiteral = tokenizer.getText();
-      if (nextPrimitive == TokenKind.EnumValue) {
-        return createEnumExpression(primitiveValueLiteral);
-      } else {
-        final EdmPrimitiveTypeKind primitiveTypeKind = tokenToPrimitiveType.get(nextPrimitive);
-        final EdmPrimitiveType type = primitiveTypeKind == null ?
-            // Null handling
-            null :
-            odata.createPrimitiveTypeInstance(primitiveTypeKind);
-        return new LiteralImpl(primitiveValueLiteral, type);
-      }
+      return parsePrimitive(nextPrimitive);
     }
 
-    // The method token text includes the opening parenthesis so that method calls can be recognized unambiguously.
-    // OData identifiers have to be considered after that.
     final TokenKind nextMethod = nextMethod();
     if (nextMethod != null) {
-      MethodKind methodKind = tokenToMethod.get(nextMethod);
-      return new MethodImpl(methodKind, parseMethodParameters(methodKind));
+      return parseMethod(nextMethod);
     }
 
     if (tokenizer.next(TokenKind.QualifiedName)) {
@@ -412,6 +430,57 @@ public class ExpressionParser {
     throw new UriParserSyntaxException("Unexpected token.", UriParserSyntaxException.MessageKeys.SYNTAX);
   }
 
+  private Expression parseMethod(final TokenKind nextMethod) throws UriParserException, UriValidationException {
+    // The method token text includes the opening parenthesis so that method calls can be recognized unambiguously.
+    // OData identifiers have to be considered after that.
+    
+    final MethodKind methodKind = tokenToMethod.get(nextMethod);
+    return new MethodImpl(methodKind, parseMethodParameters(methodKind));
+  }
+
+  private Expression parsePrimitive(TokenKind nextPrimitive) throws UriParserException {
+    final String primitiveValueLiteral = tokenizer.getText();
+    if (nextPrimitive == TokenKind.EnumValue) {
+      return createEnumExpression(primitiveValueLiteral);
+    } else {
+      EdmPrimitiveTypeKind primitiveTypeKind = tokenToPrimitiveType.get(nextPrimitive);
+      
+      if(primitiveTypeKind == EdmPrimitiveTypeKind.Int64) {
+        primitiveTypeKind = determineIntegerType(primitiveValueLiteral);
+      }
+      
+      final EdmPrimitiveType type = primitiveTypeKind == null ?
+          // Null handling
+          null :
+          odata.createPrimitiveTypeInstance(primitiveTypeKind);
+      return new LiteralImpl(primitiveValueLiteral, type);
+    }
+  }
+
+  private EdmPrimitiveTypeKind determineIntegerType(final String intValueAsString) throws UriParserSyntaxException {
+    EdmPrimitiveTypeKind typeKind = null;
+    try {
+      final long value = Long.parseLong(intValueAsString);
+      if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
+        typeKind = EdmPrimitiveTypeKind.SByte;
+      } else if (value >= 0 && value <= 255) {
+        typeKind = EdmPrimitiveTypeKind.Byte;
+      } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
+        typeKind = EdmPrimitiveTypeKind.Int16;
+      } else if (value >= Integer.MIN_VALUE && value <= Integer.MAX_VALUE) {
+        typeKind = EdmPrimitiveTypeKind.Int32;
+      } else {
+        typeKind = EdmPrimitiveTypeKind.Int64;
+      }
+    } catch (NumberFormatException e) {
+      // This should never happen. Because the tokenizer has figured out that the literal is an integer
+      throw new UriParserSyntaxException(intValueAsString + " is not an integer", 
+          UriParserSyntaxException.MessageKeys.SYNTAX);
+    }
+
+    return typeKind;
+  }
+
   private List<Expression> parseMethodParameters(final MethodKind methodKind)
       throws UriParserException, UriValidationException {
     List<Expression> parameters = new ArrayList<Expression>();
@@ -545,40 +614,60 @@ public class ExpressionParser {
     if (lastTokenKind == TokenKind.ROOT) {
       parseDollarRoot(uriInfo);
     } else if (lastTokenKind == TokenKind.IT) {
-      parseDollarIt(uriInfo);
-    } else if (lastTokenKind == TokenKind.ODataIdentifier) {
-      parseFirstMemberODataIdentifier(uriInfo);
+      parseDollarIt(uriInfo, referringType);
     } else if (lastTokenKind == TokenKind.QualifiedName) {
       // Special handling for leading type casts and type literals
       final FullQualifiedName fullQualifiedName = new FullQualifiedName(tokenizer.getText());
-      EdmStructuredType structuredType = edm.getEntityType(fullQualifiedName);
-      if (structuredType == null) {
-        structuredType = edm.getComplexType(fullQualifiedName);
+      EdmType filterType = edm.getEntityType(fullQualifiedName);
+      if (filterType == null) {
+        filterType = edm.getComplexType(fullQualifiedName);
       }
-
-      if (structuredType != null) {
+      
+      if(filterType == null) {
+        filterType = getEdmType(fullQualifiedName);
+      }
+      
+      if(filterType == null) {
+        filterType = edm.getEnumType(fullQualifiedName);
+      }
+      
+      if(filterType == null) {
+        filterType = edm.getTypeDefinition(fullQualifiedName);
+      }
+      
+      if (filterType != null) {
         if (tokenizer.next(TokenKind.SLASH)) {
           // Leading type cast
-          checkStructuredTypeFilter(referringType, structuredType);
-          startTypeFilter = structuredType;
+          checkStructuredTypeFilter(referringType, filterType);
+          startTypeFilter = filterType;
 
           final TokenKind tokenKind = ParserHelper.next(tokenizer, TokenKind.QualifiedName, TokenKind.ODataIdentifier);
-          parseMemberExpression(tokenKind, uriInfo, new UriResourceStartingTypeFilterImpl(structuredType, false),
+          parseMemberExpression(tokenKind, uriInfo, new UriResourceStartingTypeFilterImpl(filterType, false), 
               false);
         } else {
           // Type literal
-          checkStructuredTypeFilter(referringType, structuredType);
-          return new TypeLiteralImpl(structuredType);
+          return new TypeLiteralImpl(filterType);
         }
       } else {
-        // Must be bound or unbound function. // TODO: Is unbound function allowed?
+        // Must be bound or unbound function. 
         parseFunction(fullQualifiedName, uriInfo, referringType, true);
       }
+    } else if (lastTokenKind == TokenKind.ODataIdentifier) {
+      parseFirstMemberODataIdentifier(uriInfo);
     }
-
+    
     return new MemberImpl(uriInfo, startTypeFilter);
   }
 
+  private EdmType getEdmType(final FullQualifiedName fullQualifiedName) {
+    if(!fullQualifiedName.getNamespace().equals(EdmPrimitiveType.EDM_NAMESPACE)) {
+      return null;
+    }
+    
+    final EdmPrimitiveTypeKind primitiveTypeKind = EdmPrimitiveTypeKind.valueOfFQN(fullQualifiedName);
+    return primitiveTypeKind == null ? null : EdmPrimitiveTypeFactory.getInstance(primitiveTypeKind);
+  }
+
   private void parseDollarRoot(UriInfoImpl uriInfo) throws UriParserException, UriValidationException {
     UriResourceRootImpl rootResource = new UriResourceRootImpl(referringType, true);
     uriInfo.addResourcePart(rootResource);
@@ -605,9 +694,9 @@ public class ExpressionParser {
     parseSingleNavigationExpr(uriInfo, resource);
   }
 
-  private void parseDollarIt(UriInfoImpl uriInfo) throws UriParserException, UriValidationException {
-    UriResourceItImpl itResource = new UriResourceItImpl(referringType,
-        referringType instanceof EdmEntityType); // TODO: Determine isCollection.
+  private void parseDollarIt(UriInfoImpl uriInfo, EdmType referringType) 
+      throws UriParserException, UriValidationException {
+    UriResourceItImpl itResource = new UriResourceItImpl(referringType, false);
     uriInfo.addResourcePart(itResource);
     if (tokenizer.next(TokenKind.SLASH)) {
       final TokenKind tokenKind = ParserHelper.next(tokenizer, TokenKind.QualifiedName, TokenKind.ODataIdentifier);
@@ -670,6 +759,19 @@ public class ExpressionParser {
       if (edmEntityType != null) {
         if (allowTypeFilter) {
           setTypeFilter(lastResource, edmEntityType);
+          
+          if(tokenizer.next(TokenKind.SLASH)) {
+            final TokenKind nextTokenKind = ParserHelper.next(tokenizer, TokenKind.QualifiedName, 
+                                                                         TokenKind.ODataIdentifier);
+            if(nextTokenKind == TokenKind.ODataIdentifier) {
+              parsePropertyPathExpr(uriInfo, lastResource);
+            } else if(nextTokenKind == TokenKind.QualifiedName) {
+              parseBoundFunction(fullQualifiedName, uriInfo, lastResource);
+            } else {
+              throw new UriParserSyntaxException("Extected OData Identifier or Full Qualified Name", 
+                  UriParserSyntaxException.MessageKeys.SYNTAX);
+            }
+          }
         } else {
           throw new UriParserSemanticException("Type filters are not chainable.",
               UriParserSemanticException.MessageKeys.TYPE_FILTER_NOT_CHAINABLE,
@@ -686,7 +788,7 @@ public class ExpressionParser {
     }
   }
 
-  private void setTypeFilter(UriResourcePartTyped lastResource, final EdmEntityType entityTypeFilter)
+  private void setTypeFilter(UriResourcePartTyped lastResource, final EdmStructuredType entityTypeFilter)
       throws UriParserException {
     checkStructuredTypeFilter(lastResource.getType(), entityTypeFilter);
     if (lastResource instanceof UriResourceTypedImpl) {
@@ -798,10 +900,10 @@ public class ExpressionParser {
     if (tokenizer.next(TokenKind.SLASH)) {
       if (tokenizer.next(TokenKind.QualifiedName)) {
         final FullQualifiedName fullQualifiedName = new FullQualifiedName(tokenizer.getText());
-        final EdmEntityType edmEntityType = edm.getEntityType(fullQualifiedName);
+        final EdmComplexType edmComplexType = edm.getComplexType(fullQualifiedName);
 
-        if (edmEntityType != null) {
-          setTypeFilter(lastResource, edmEntityType);
+        if (edmComplexType != null) {
+          setTypeFilter(lastResource, edmComplexType);
           if (tokenizer.next(TokenKind.SLASH)) {
             parseComplexPathRestExpr(uriInfo, lastResource);
           }
@@ -893,9 +995,9 @@ public class ExpressionParser {
     if (function.isComposable()) {
       if (edmType instanceof EdmEntityType ) {
         if (isCollection) {
-          parseCollectionNavigationExpr(uriInfo, null); // TODO: Get navigation property.
+          parseCollectionNavigationExpr(uriInfo, functionResource); 
         } else {
-          parseSingleNavigationExpr(uriInfo, null); // TODO: Get navigation property.
+          parseSingleNavigationExpr(uriInfo, functionResource);
         }
       } else if (edmType instanceof EdmComplexType) {
         if (isCollection) {
@@ -1035,12 +1137,21 @@ public class ExpressionParser {
     if (leftType == null || rightType == null || leftType.equals(rightType)) {
       return;
     }
+    
+    // Numeric promotion for Edm.Byte and Edm.SByte
+    if((leftType instanceof EdmByte || leftType instanceof EdmSByte) 
+        && (rightType instanceof EdmByte || rightType instanceof EdmSByte)) {
+      return;
+    }
+    
     if (leftType.getKind() != EdmTypeKind.PRIMITIVE
         || rightType.getKind() != EdmTypeKind.PRIMITIVE
         || !(((EdmPrimitiveType) leftType).isCompatible((EdmPrimitiveType) rightType)
-        || ((EdmPrimitiveType) rightType).isCompatible((EdmPrimitiveType) leftType))) {
+        || ((EdmPrimitiveType) rightType).isCompatible((EdmPrimitiveType) leftType)))
+        {
       throw new UriParserSemanticException("Incompatible types.",
-          UriParserSemanticException.MessageKeys.UNKNOWN_TYPE, ""); // TODO: better message
+          UriParserSemanticException.MessageKeys.TYPES_NOT_COMPATIBLE, leftType.getFullQualifiedName().toString(), 
+                                                                       rightType.getFullQualifiedName().toString());
     }
   }
 
@@ -1053,7 +1164,7 @@ public class ExpressionParser {
     }
     return type;
   }
-
+  
   private boolean isEnumType(final Expression expression) throws UriParserException {
     final EdmType expressionType = getType(expression);
     return expressionType == null
@@ -1132,9 +1243,9 @@ public class ExpressionParser {
         UriParserSemanticException.MessageKeys.UNKNOWN_TYPE, ""); // TODO: better message
   }
 
-  private void checkStructuredTypeFilter(final EdmType type, final EdmStructuredType filterType)
+  private void checkStructuredTypeFilter(final EdmType type, final EdmType filterType)
       throws UriParserException {
-    if (!filterType.compatibleTo(type)) {
+    if (!(filterType instanceof EdmStructuredType && ((EdmStructuredType)filterType).compatibleTo(type))) {
       throw new UriParserSemanticException("Incompatible type filter.",
           UriParserSemanticException.MessageKeys.INCOMPATIBLE_TYPE_FILTER,
           filterType.getFullQualifiedName().getFullQualifiedNameAsString());

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8919d3ef/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/FilterParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/FilterParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/FilterParser.java
index a3376e0..e2767a1 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/FilterParser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/FilterParser.java
@@ -21,7 +21,7 @@ package org.apache.olingo.server.core.uri.parser;
 import java.util.Collection;
 
 import org.apache.olingo.commons.api.edm.Edm;
-import org.apache.olingo.commons.api.edm.EdmStructuredType;
+import org.apache.olingo.commons.api.edm.EdmType;
 import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.uri.queryoption.FilterOption;
 import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
@@ -38,7 +38,7 @@ public class FilterParser {
     this.odata = odata;
   }
 
-  public FilterOption parse(UriTokenizer tokenizer, final EdmStructuredType referencedType,
+  public FilterOption parse(UriTokenizer tokenizer, final EdmType referencedType,
       final Collection<String> crossjoinEntitySetNames)
       throws UriParserException, UriValidationException {
     final Expression filterExpression = new ExpressionParser(edm, odata)

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8919d3ef/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 118c649..47efda5 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
@@ -191,10 +191,8 @@ public class Parser {
         SystemQueryOption systemOption = null;
         if (optionName.equals(SystemQueryOptionKind.FILTER.toString())) {
           UriTokenizer filterTokenizer = new UriTokenizer(optionValue);
-          systemOption = new FilterParser(edm, odata).parse(filterTokenizer,
-              context.contextTypes.peek() instanceof EdmStructuredType ?
-                  (EdmStructuredType) context.contextTypes.peek() :
-                  null,
+          // The Referring type could also be a primitive type not only a structured type
+          systemOption = new FilterParser(edm, odata).parse(filterTokenizer, context.contextTypes.peek(),
                   context.contextUriInfo.getEntitySetNames());
           checkOptionEOF(filterTokenizer, optionName, optionValue);
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8919d3ef/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 9135dd8..cc31e34 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
@@ -83,7 +83,9 @@ public class UriParserSemanticException extends UriParserException {
     /** parameter: complex parameter value */
     COMPLEX_PARAMETER_IN_RESOURCE_PATH, 
     /** parameter: function import name */
-    FUNCTION_IMPORT_NOT_ALLOWED;
+    FUNCTION_IMPORT_NOT_ALLOWED, 
+    /** parameters: left type, right type */
+    TYPES_NOT_COMPATIBLE;
     
     @Override
     public String getKey() {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8919d3ef/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java
index 37f1b76..f505a21 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java
@@ -219,7 +219,7 @@ public class UriTokenizer {
       found = nextCharacter('+');
       break;
     case MINUS:
-      found = nextCharacter('-');
+      found = nextMinus();
       break;
     case NULL:
       found = nextConstant("null");
@@ -444,6 +444,27 @@ public class UriTokenizer {
     return found;
   }
 
+  private boolean nextMinus() {
+    if(parseString.startsWith("-", index)) {
+      final int lastGoodIndex = index;
+      
+      if(nextDoubleValue()) {
+        index = lastGoodIndex;
+        return false;
+      } else if(nextDecimalValue()) {
+        index = lastGoodIndex;
+        return false;
+      } else if(nextIntegerValue(true)) {
+        index = lastGoodIndex;
+        return false;
+      } else {
+        index++;
+        return true;
+      }
+    }
+    return false;
+  }
+
   /**
    * Moves past the given string constant if found; otherwise leaves the index unchanged.
    * @return whether the constant has been found at the current index

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8919d3ef/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 3de8814..0b43f70 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
@@ -85,6 +85,7 @@ UriParserSemanticException.NOT_IMPLEMENTED=%1$s is not implemented!
 UriParserSemanticException.NAMESPACE_NOT_ALLOWED_AT_FIRST_ELEMENT=Namespace is not allowed for Entity Sets, Singeltons, Action Imports and Function Imports. Found '%1$s'.
 UriParserSemanticException.COMPLEX_PARAMETER_IN_RESOURCE_PATH=Complex parameters must not appear in resource path segments. Found: '%1$s'.
 UriParserSemanticException.FUNCTION_IMPORT_NOT_ALLOWED=Function Imports are not allowed in $filter or $orderby. Found: '%1$s'.
+UriParserSemanticException.TYPES_NOT_COMPATIBLE=Types are not compatible. Left type: '%1$s', right type: '%1$s'.
 
 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/8919d3ef/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java
index ec9cc22..c27c960 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java
@@ -33,6 +33,7 @@ import org.apache.olingo.commons.api.edm.EdmProperty;
 import org.apache.olingo.commons.api.edm.FullQualifiedName;
 import org.apache.olingo.commons.api.format.ContentType;
 import org.apache.olingo.commons.core.Encoder;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmString;
 import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.edmx.EdmxReference;
 import org.apache.olingo.server.api.uri.UriInfoKind;
@@ -3231,7 +3232,6 @@ public class TestFullResourcePath {
 
   // TODO
   @Test
-  @Ignore
   public void filter() throws Exception {
 
     testFilter.runOnETTwoKeyNav("PropertyString")
@@ -3334,21 +3334,22 @@ public class TestFullResourcePath {
     //     .isExSemantic(MessageKeys.UNKNOWN_TYPE);
     testFilter.runOnETTwoKeyNavEx("PropertyComp/invalid")
         .isExSemantic(MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
-    testFilter.runOnETTwoKeyNavEx("concat('a','b')/invalid").isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
+    testFilter.runOnETTwoKeyNavEx("concat('a','b')/invalid")
+        .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION);
     testFilter.runOnETTwoKeyNavEx("PropertyComp/concat('a','b')")
-        .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
+        .isExSemantic(MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
     testFilter.runOnETTwoKeyNavEx("PropertyComp/PropertyInt16 eq '1'")
-        .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
+        .isExSemantic(MessageKeys.TYPES_NOT_COMPATIBLE);
     testFilter.runOnETTwoKeyNavEx("PropertyComp/PropertyComp/PropertyDate eq 1")
-        .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
+        .isExSemantic(MessageKeys.TYPES_NOT_COMPATIBLE);
     testFilter.runOnETTwoKeyNavEx("PropertyComp/PropertyComp/PropertyString eq 1")
-        .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
+        .isExSemantic(MessageKeys.TYPES_NOT_COMPATIBLE);
     testFilter.runOnETTwoKeyNavEx("PropertyComp/PropertyInt64 eq 1")
         .isExSemantic(MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
     testFilter.runOnETTwoKeyNavEx("NavPropertyETKeyNavMany/PropertyInt16 gt 42")
-        .isExSemantic(MessageKeys.PROPERTY_AFTER_COLLECTION);
+        .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION);
     testFilter.runOnETTwoKeyNavEx("NavPropertyETKeyNavMany/NavPropertyETTwoKeyNavOne eq null")
-        .isExSemantic(MessageKeys.PROPERTY_AFTER_COLLECTION);
+        .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION);
 
     testFilter.runOnETAllPrim("PropertySByte eq PropertySByte")
         .is("<<PropertySByte> eq <PropertySByte>>")
@@ -3758,12 +3759,13 @@ public class TestFullResourcePath {
         .root().right()
         .isType(PropertyProvider.nameDecimal);
 
+    // Numeric promotion: Double is considered the widest type
     testFilter.runOnETAllPrim("PropertyDecimal sub NaN")
-        .right().isLiteral("NaN").isType(PropertyProvider.nameDecimal);
+        .right().isLiteral("NaN").isType(PropertyProvider.nameDouble);
     testFilter.runOnETAllPrim("PropertyDecimal sub -INF")
-        .right().isLiteral("-INF").isType(PropertyProvider.nameDecimal);
+        .right().isLiteral("-INF").isType(PropertyProvider.nameDouble);
     testFilter.runOnETAllPrim("PropertyDecimal sub INF")
-        .right().isLiteral("INF").isType(PropertyProvider.nameDecimal);
+        .right().isLiteral("INF").isType(PropertyProvider.nameDouble);
   }
 
   // TODO
@@ -4078,9 +4080,7 @@ public class TestFullResourcePath {
         .isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
   }
 
-  // TODO: $it on primitive types?
   @Test
-  @Ignore
   public void methods() throws Exception {
     testFilter.runOnETKeyNav("indexof(PropertyString,'47') eq 5")
         .is("<<indexof(<PropertyString>,<'47'>)> eq <5>>")
@@ -4482,7 +4482,7 @@ public class TestFullResourcePath {
         .root().left()
         .goPath()
         .first().isUriPathInfoKind(UriResourceKind.it)
-        .isType(EntityTypeProvider.nameETTwoKeyNav, true)
+        .isType(EntityTypeProvider.nameETTwoKeyNav, false)
         .n().isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
 
     testFilter.runOnCTTwoPrim("$it/PropertyString eq 'SomeString'")
@@ -4529,7 +4529,7 @@ public class TestFullResourcePath {
         .goParameter(0)
         .goPath()
         .first().isUriPathInfoKind(UriResourceKind.it)
-        .isType(EntityTypeProvider.nameETTwoKeyNav, true)
+        .isType(EntityTypeProvider.nameETTwoKeyNav, false)
         .n().isPrimitiveProperty("CollPropertyString", PropertyProvider.nameString, true);
 
     testFilter.runOnETTwoKeyNav("endswith(PropertyComp/PropertyComp/PropertyString,'dorf')")
@@ -4646,7 +4646,6 @@ public class TestFullResourcePath {
 
   // TODO: Implement cast method.
   @Test
-  @Ignore
   public void castMethod() throws Exception {
     testFilter.runOnETKeyNav("cast(olingo.odata.test1.ETBaseTwoKeyNav)")
         .is("<cast(<olingo.odata.test1.ETBaseTwoKeyNav>)>")
@@ -4795,13 +4794,14 @@ public class TestFullResourcePath {
 
     testFilter.runOnETKeyNavEx("cast(NavPropertyETKeyPrimNavOne,olingo.odata.test1.ETKeyNav)")
         .isExSemantic(MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
-    testFilter.runOnETKeyNav("any()")
-        .isMember().goPath().first().isUriPathInfoKind(UriResourceKind.lambdaAny);
+    // TODO Is that case makes not really sense, each any / all lambda expr must 
+    // containing at least one lambdaVariableExpr 
+//    testFilter.runOnETKeyNav("any()")
+//        .isMember().goPath().first().isUriPathInfoKind(UriResourceKind.lambdaAny);
   }
 
   // TODO: Check whether lambda expressions really are allowed on complex collections.
   @Test
-  @Ignore
   public void lambdaFunctions() throws Exception {
     testFilter.runOnETKeyNav("NavPropertyETTwoKeyNavMany/any(d:d/PropertyString eq 'SomeString')")
         .is("<NavPropertyETTwoKeyNavMany/<ANY;<<d/PropertyString> eq <'SomeString'>>>>")
@@ -4846,9 +4846,9 @@ public class TestFullResourcePath {
         .n().isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
 
     testFilter.runOnETKeyNav("NavPropertyETTwoKeyNavMany/any(d:d/PropertyInt16 eq 1 or "
-        + "d/any(e:e/CollPropertyString eq 'SomeString'))")
-        .is("<NavPropertyETTwoKeyNavMany/<ANY;<<<d/PropertyInt16> eq <1>> or "
-            + "<d/<ANY;<<e/CollPropertyString> eq <'SomeString'>>>>>>>")
+        + "d/CollPropertyString/any(e:e eq 'SomeString'))")
+        .is("<NavPropertyETTwoKeyNavMany/<ANY;<<<d/PropertyInt16> eq <1>>" 
+            + " or <d/CollPropertyString/<ANY;<<e> eq <'SomeString'>>>>>>>")
         .root().goPath()
         .first().isNavProperty("NavPropertyETTwoKeyNavMany", EntityTypeProvider.nameETTwoKeyNav, true)
         .n().isUriPathInfoKind(UriResourceKind.lambdaAny)
@@ -4866,12 +4866,13 @@ public class TestFullResourcePath {
         .goPath()
         .first().isUriPathInfoKind(UriResourceKind.lambdaVariable)
         .isType(EntityTypeProvider.nameETTwoKeyNav, false)
-        .n().isUriPathInfoKind(UriResourceKind.lambdaAny)
+        .n().isUriPathInfoKind(UriResourceKind.primitiveProperty)
+        .isPrimitiveProperty("CollPropertyString", PropertyProvider.nameString, true)
+        .at(2).isUriPathInfoKind(UriResourceKind.lambdaAny)        
         .goLambdaExpression()
         .root().left().goPath()
         .first().isUriPathInfoKind(UriResourceKind.lambdaVariable)
-        .isType(EntityTypeProvider.nameETTwoKeyNav, false)
-        .n().isPrimitiveProperty("CollPropertyString", PropertyProvider.nameString, true);
+        .isType(EdmString.getInstance().getFullQualifiedName(), false);
 
     testFilter.runOnETKeyNav("NavPropertyETTwoKeyNavMany/any(d:d/PropertyInt16 eq 1 or "
         + "d/CollPropertyString/any(e:e eq 'SomeString'))")
@@ -4934,12 +4935,10 @@ public class TestFullResourcePath {
         .n().isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
 
     testFilter.runOnETKeyNavEx("any(d:d/PropertyInt16 eq 1)")
-        .isExSemantic(MessageKeys.PROPERTY_NOT_IN_TYPE);
+        .isExSemantic(MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
   }
 
-  // TODO: Implement isof method.
   @Test
-  @Ignore
   public void isOfMethod() throws Exception {
     testFilter.runOnETKeyNav("isof(olingo.odata.test1.ETTwoKeyNav)")
         .is("<isof(<olingo.odata.test1.ETTwoKeyNav>)>")
@@ -4962,7 +4961,7 @@ public class TestFullResourcePath {
         .left().isMethod(MethodKind.ISOF, 1)
         .goParameter(0).isTypedLiteral(EntityTypeProvider.nameETBaseTwoKeyNav);
 
-    testFilter.runOnETKeyNav("isof(NavPropertyETKeyNavOne, olingo.odata.test1.ETKeyNav) eq true")
+    testFilter.runOnETKeyNav("isof(NavPropertyETKeyNavOne,olingo.odata.test1.ETKeyNav) eq true")
         .is("<<isof(<NavPropertyETKeyNavOne>,<olingo.odata.test1.ETKeyNav>)> eq <true>>")
         .root().isBinary(BinaryOperatorKind.EQ)
         .left().isMethod(MethodKind.ISOF, 2)
@@ -5865,7 +5864,6 @@ public class TestFullResourcePath {
 
   // TODO: Better type determination for literal numbers.
   @Test
-  @Ignore
   public void filterLiteralTypes() throws Exception {
     testFilter.runOnETAllPrim("-1000 eq 42")
         .isBinary(BinaryOperatorKind.EQ)


[05/30] olingo-odata4 git commit: [OLINGO-834] Filter parser refactoring first draft

Posted by ch...@apache.org.
[OLINGO-834] Filter parser refactoring first draft


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

Branch: refs/heads/master
Commit: 7b23ad71a7faab152841a3776b4db3ac9dffccf2
Parents: a47e9f6
Author: Christian Amend <ch...@sap.com>
Authored: Wed Dec 9 14:00:48 2015 +0100
Committer: Christian Amend <ch...@sap.com>
Committed: Wed Dec 9 14:11:46 2015 +0100

----------------------------------------------------------------------
 .../core/uri/expression/FilterParser.java       | 562 +++++++++++++++++++
 .../uri/queryoption/expression/AliasImpl.java   |   8 +
 .../uri/queryoption/expression/BinaryImpl.java  |  16 +
 .../uri/queryoption/expression/LiteralImpl.java |  14 +
 .../uri/queryoption/expression/MethodImpl.java  |  24 +
 .../uri/queryoption/expression/UnaryImpl.java   |  14 +
 .../core/uri/expression/FilterParserTest.java   | 210 +++++++
 7 files changed, 848 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/7b23ad71/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/expression/FilterParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/expression/FilterParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/expression/FilterParser.java
new file mode 100644
index 0000000..32cbc1a
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/expression/FilterParser.java
@@ -0,0 +1,562 @@
+/*
+ * 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.expression;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
+import org.apache.olingo.server.api.uri.queryoption.expression.BinaryOperatorKind;
+import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
+import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind;
+import org.apache.olingo.server.api.uri.queryoption.expression.UnaryOperatorKind;
+import org.apache.olingo.server.core.uri.queryoption.expression.AliasImpl;
+import org.apache.olingo.server.core.uri.queryoption.expression.BinaryImpl;
+import org.apache.olingo.server.core.uri.queryoption.expression.ExpressionImpl;
+import org.apache.olingo.server.core.uri.queryoption.expression.LiteralImpl;
+import org.apache.olingo.server.core.uri.queryoption.expression.MethodImpl;
+import org.apache.olingo.server.core.uri.queryoption.expression.UnaryImpl;
+
+public class FilterParser {
+  private Tokenizer tokenizer;
+
+  private static final Map<TokenKind, BinaryOperatorKind> tokenToBinaryOperator;
+  static {
+    HashMap<TokenKind, BinaryOperatorKind> temp = new HashMap<FilterParser.TokenKind, BinaryOperatorKind>();
+    temp.put(TokenKind.OR_OP, BinaryOperatorKind.OR);
+    temp.put(TokenKind.AND_OP, BinaryOperatorKind.AND);
+
+    temp.put(TokenKind.EQ_OP, BinaryOperatorKind.EQ);
+    temp.put(TokenKind.NE_OP, BinaryOperatorKind.NE);
+
+    temp.put(TokenKind.GT_OP, BinaryOperatorKind.GT);
+    temp.put(TokenKind.GE_OP, BinaryOperatorKind.GE);
+    temp.put(TokenKind.LT_OP, BinaryOperatorKind.LT);
+    temp.put(TokenKind.LE_OP, BinaryOperatorKind.LE);
+
+    temp.put(TokenKind.ADD_OP, BinaryOperatorKind.ADD);
+    temp.put(TokenKind.SUB_OP, BinaryOperatorKind.SUB);
+
+    temp.put(TokenKind.MUL_OP, BinaryOperatorKind.MUL);
+    temp.put(TokenKind.DIV_OP, BinaryOperatorKind.DIV);
+    temp.put(TokenKind.MOD_OP, BinaryOperatorKind.MOD);
+
+    tokenToBinaryOperator = Collections.unmodifiableMap(temp);
+  }
+
+  private static final Map<TokenKind, UnaryOperatorKind> tokenToUnaryOperator;
+  static {
+    HashMap<TokenKind, UnaryOperatorKind> temp = new HashMap<FilterParser.TokenKind, UnaryOperatorKind>();
+    temp.put(TokenKind.MINUS, UnaryOperatorKind.MINUS);
+    temp.put(TokenKind.NOT, UnaryOperatorKind.NOT);
+    tokenToUnaryOperator = Collections.unmodifiableMap(temp);
+  }
+
+  private static final Map<TokenKind, MethodKind> tokenToMethod;
+  static {
+    HashMap<TokenKind, MethodKind> temp = new HashMap<FilterParser.TokenKind, MethodKind>();
+    temp.put(TokenKind.Cast, MethodKind.CAST);
+    temp.put(TokenKind.Ceiling, MethodKind.CEILING);
+    temp.put(TokenKind.Concat, MethodKind.CONCAT);
+    temp.put(TokenKind.Contains, MethodKind.CONTAINS);
+    temp.put(TokenKind.Date, MethodKind.DATE);
+    temp.put(TokenKind.Day, MethodKind.DAY);
+    temp.put(TokenKind.Endswith, MethodKind.ENDSWITH);
+    temp.put(TokenKind.Floor, MethodKind.FLOOR);
+    temp.put(TokenKind.Fractionalseconds, MethodKind.FRACTIONALSECONDS);
+    temp.put(TokenKind.GeoDistance, MethodKind.GEODISTANCE);
+    temp.put(TokenKind.GeoIntersects, MethodKind.GEOINTERSECTS);
+    temp.put(TokenKind.GeoLength, MethodKind.GEOLENGTH);
+    temp.put(TokenKind.Hour, MethodKind.HOUR);
+    temp.put(TokenKind.Indexof, MethodKind.INDEXOF);
+    temp.put(TokenKind.Isof, MethodKind.ISOF);
+    temp.put(TokenKind.Length, MethodKind.LENGTH);
+    temp.put(TokenKind.Maxdatetime, MethodKind.MAXDATETIME);
+    temp.put(TokenKind.Mindatetime, MethodKind.MINDATETIME);
+    temp.put(TokenKind.Minute, MethodKind.MINUTE);
+    temp.put(TokenKind.Month, MethodKind.MONTH);
+    temp.put(TokenKind.Now, MethodKind.NOW);
+    temp.put(TokenKind.Round, MethodKind.ROUND);
+    temp.put(TokenKind.Second, MethodKind.SECOND);
+    temp.put(TokenKind.Startswith, MethodKind.STARTSWITH);
+    temp.put(TokenKind.Substring, MethodKind.SUBSTRING);
+    temp.put(TokenKind.Time, MethodKind.TIME);
+    temp.put(TokenKind.Tolower, MethodKind.TOLOWER);
+    temp.put(TokenKind.Totaloffsetminutes, MethodKind.TOTALOFFSETMINUTES);
+    temp.put(TokenKind.Totalseconds, MethodKind.TOTALSECONDS);
+    temp.put(TokenKind.Toupper, MethodKind.TOUPPER);
+    temp.put(TokenKind.Trim, MethodKind.TRIM);
+    temp.put(TokenKind.Year, MethodKind.YEAR);
+
+    tokenToMethod = Collections.unmodifiableMap(temp);
+  }
+
+  private static final Map<TokenKind, EdmPrimitiveTypeKind> tokenToPrimitiveType;
+  static {
+    /* Enum and null are not present in the map. These have to be handled differently */
+    HashMap<TokenKind, EdmPrimitiveTypeKind> temp = new HashMap<FilterParser.TokenKind, EdmPrimitiveTypeKind>();
+    temp.put(TokenKind.PrimitiveBooleanValue, EdmPrimitiveTypeKind.Boolean);
+    temp.put(TokenKind.PrimitiveStringValue, EdmPrimitiveTypeKind.String);
+    // TODO:Check if int64 is correct here or if it has to be single instead
+    temp.put(TokenKind.PrimitiveIntegerValue, EdmPrimitiveTypeKind.Int64);
+    temp.put(TokenKind.PrimitiveGuidValue, EdmPrimitiveTypeKind.Guid);
+    temp.put(TokenKind.PrimitiveDateValue, EdmPrimitiveTypeKind.Date);
+    temp.put(TokenKind.PrimitiveDateTimeOffsetValue, EdmPrimitiveTypeKind.DateTimeOffset);
+    temp.put(TokenKind.PrimitiveTimeOfDayValue, EdmPrimitiveTypeKind.TimeOfDay);
+    temp.put(TokenKind.PrimitiveDecimalValue, EdmPrimitiveTypeKind.Decimal);
+    temp.put(TokenKind.PrimitiveDoubleValue, EdmPrimitiveTypeKind.Double);
+    temp.put(TokenKind.PrimitiveDurationValue, EdmPrimitiveTypeKind.Duration);
+    temp.put(TokenKind.PrimitiveBinaryValue, EdmPrimitiveTypeKind.Binary);
+
+    tokenToPrimitiveType = Collections.unmodifiableMap(temp);
+  }
+
+  public Expression parse(Tokenizer tokenizer) {
+    // Initialize tokenizer
+    this.tokenizer = tokenizer;
+
+    Expression exp = parseExpression();
+    return exp;
+  }
+
+  private Expression parseExpression() {
+    Expression left = parseAnd();
+
+    while (is(TokenKind.OR_OP) != null) {
+      tokenizer.getText();
+
+      Expression right = parseAnd();
+      left = new BinaryImpl(left, BinaryOperatorKind.OR, right);
+    }
+
+    return left;
+  }
+
+  private Expression parseAnd() {
+    Expression left = parseExprEquality();
+    while (is(TokenKind.AND_OP) != null) {
+      tokenizer.getText();
+
+      Expression right = parseExprEquality();
+      left = new BinaryImpl(left, BinaryOperatorKind.AND, right);
+    }
+    return left;
+  }
+
+  private Expression parseExprEquality() {
+    Expression left = parseExprRel();
+
+    TokenKind nextTokenKind = is(TokenKind.EQ_OP, TokenKind.NE_OP);
+    // Null for everything other than EQ or NE
+    while (nextTokenKind != null) {
+      tokenizer.getText();
+
+      Expression right = parseExprEquality();
+      left = new BinaryImpl(left, tokenToBinaryOperator.get(nextTokenKind), right);
+      nextTokenKind = is(TokenKind.EQ_OP, TokenKind.NE_OP);
+    }
+
+    return left;
+  }
+
+  private Expression parseExprRel() {
+    Expression left = parseExprAdd();
+
+    TokenKind nextTokenKind = is(TokenKind.GT_OP, TokenKind.GE_OP, TokenKind.LT_OP, TokenKind.LE_OP);
+    // Null for everything other than GT or GE or LT or LE
+    while (nextTokenKind != null) {
+      tokenizer.getText();
+
+      Expression right = parseExprAdd();
+      left = new BinaryImpl(left, tokenToBinaryOperator.get(nextTokenKind), right);
+      nextTokenKind = is(TokenKind.GT_OP, TokenKind.GE_OP, TokenKind.LT_OP, TokenKind.LE_OP);
+    }
+
+    return left;
+  }
+
+  private Expression parseExprAdd() {
+    Expression left = parseExprMul();
+
+    TokenKind nextTokenKind = is(TokenKind.ADD_OP, TokenKind.SUB_OP);
+    // Null for everything other than ADD or SUB
+    while (nextTokenKind != null) {
+      tokenizer.getText();
+
+      Expression right = parseExprMul();
+      left = new BinaryImpl(left, tokenToBinaryOperator.get(nextTokenKind), right);
+      nextTokenKind = is(TokenKind.ADD_OP, TokenKind.SUB_OP);
+    }
+
+    return left;
+  }
+
+  private Expression parseExprMul() {
+    Expression left = parseExprUnary();
+
+    TokenKind nextTokenKind = is(TokenKind.MUL_OP, TokenKind.DIV_OP, TokenKind.MOD_OP);
+    // Null for everything other than MUL or DIV or MOD
+    while (nextTokenKind != null) {
+      tokenizer.getText();
+
+      Expression right = parseExprUnary();
+      left = new BinaryImpl(left, tokenToBinaryOperator.get(nextTokenKind), right);
+      nextTokenKind = is(TokenKind.MUL_OP, TokenKind.DIV_OP, TokenKind.MOD_OP);
+    }
+
+    return left;
+  }
+
+  private Expression parseExprUnary() {
+    Expression left = null;
+    TokenKind nextTokenKind = is(TokenKind.MINUS, TokenKind.NOT);
+    // Null for everything other than - or NOT
+    while (nextTokenKind != null) {
+      tokenizer.getText();
+
+      Expression exp = parseExprValue();
+      left = new UnaryImpl(tokenToUnaryOperator.get(nextTokenKind), exp);
+      nextTokenKind = is(TokenKind.MINUS, TokenKind.NOT);
+    }
+
+    if (left == null) {
+      left = parseExprValue();
+    }
+
+    return left;
+  }
+
+  private Expression parseExprValue() {
+    if (is(TokenKind.OPEN) != null) {
+      tokenizer.getText();
+      Expression exp = parseExpression();
+      require(TokenKind.CLOSE);
+      return exp;
+    }
+
+    if (is(TokenKind.ParameterAlias) != null) {
+      return new AliasImpl(tokenizer.getText());
+    }
+
+    if (is(TokenKind.RootExpr) != null) {
+      tokenizer.getText();
+      // TODO: ConsumeRootExpression
+    }
+
+    TokenKind nextPrimitive = isPrimitive();
+    if (nextPrimitive != null) {
+      EdmPrimitiveTypeKind primitiveTypeKind = tokenToPrimitiveType.get(nextPrimitive);
+      EdmPrimitiveType type;
+      if (primitiveTypeKind == null) {
+        if (nextPrimitive == TokenKind.PrimitiveEnumValue) {
+          // TODO: Get enum type
+          type = null;
+        } else {
+          // Null handling
+          type = null;
+        }
+      } else {
+        type = EdmPrimitiveTypeFactory.getInstance(primitiveTypeKind);
+      }
+      return new LiteralImpl(tokenizer.getText(), type);
+    }
+
+    TokenKind nextMethod = isMethod();
+    if (nextMethod != null) {
+      MethodImpl methodImpl = new MethodImpl(tokenToMethod.get(nextMethod));
+      // Consume Method
+      tokenizer.getText();
+      if (is(TokenKind.CLOSE) != null) {
+        // Consume closing bracket
+        tokenizer.getText();
+      } else {
+        // TODO: Remove Cast
+        methodImpl.addParameter((ExpressionImpl) parseExpression());
+        while (is(TokenKind.COMMA) != null) {
+          tokenizer.getText();
+          methodImpl.addParameter((ExpressionImpl) parseExpression());
+        }
+        require(TokenKind.CLOSE);
+      }
+
+      validateMethodParameters(methodImpl);
+
+      return methodImpl;
+    }
+
+    throw new RuntimeException("Unexpected token");
+  }
+
+  private void validateMethodParameters(MethodImpl methodImpl) {
+    // We might validate parameter types in the future
+    int size = methodImpl.getParameters().size();
+    switch (methodImpl.getMethod()) {
+    // Must have two Parameters
+    case CONTAINS:
+    case ENDSWITH:
+    case STARTSWITH:
+    case INDEXOF:
+    case CONCAT:
+    case GEODISTANCE:
+    case GEOINTERSECTS:
+      if (size != 2) {
+        throw new RuntimeException("The method " + methodImpl.getMethod() + " needs exactly two parameters.");
+      }
+      break;
+    // Must have one parameter
+    case LENGTH:
+    case TOLOWER:
+    case TOUPPER:
+    case TRIM:
+    case YEAR:
+    case MONTH:
+    case DAY:
+    case HOUR:
+    case MINUTE:
+    case SECOND:
+    case FRACTIONALSECONDS:
+    case DATE:
+    case TIME:
+    case TOTALOFFSETMINUTES:
+    case TOTALSECONDS:
+    case ROUND:
+    case FLOOR:
+    case CEILING:
+    case GEOLENGTH:
+      if (size != 1) {
+        throw new RuntimeException("The method: '" + methodImpl.getMethod() + "' needs exactly one parameter.");
+      }
+      break;
+    // Must have no parameter
+    case NOW:
+    case MAXDATETIME:
+    case MINDATETIME:
+      if (size != 0) {
+        throw new RuntimeException("The method: '" + methodImpl.getMethod() + "' must have no parameters.");
+      }
+      break;
+    // Variable parameter number
+    case CAST:
+    case ISOF:
+      if (size == 1 || size == 2) {
+        throw new RuntimeException("The method: '" + methodImpl.getMethod() + "' must have one or two parameters.");
+      }
+      break;
+    case SUBSTRING:
+      if (size == 2 || size == 3) {
+        throw new RuntimeException("The method: '" + methodImpl.getMethod() + "' must have two or three parameters.");
+      }
+      break;
+    default:
+      throw new RuntimeException("Unkown method: '" + methodImpl.getMethod() + "'");
+    }
+  }
+
+  private String require(TokenKind required) {
+    if (is(required) == null) {
+      throw new RuntimeException("Requred token: " + required);
+    }
+    return tokenizer.getText();
+  }
+
+  private TokenKind is(TokenKind... kind) {
+    for (int i = 0; i < kind.length; i++) {
+      if (tokenizer.next(kind[i])) {
+        return kind[i];
+      }
+    }
+    return null;
+  }
+
+  private TokenKind isMethod() {
+    return is(TokenKind.Cast,
+        TokenKind.Ceiling,
+        TokenKind.Concat,
+        TokenKind.Contains,
+        TokenKind.Date,
+        TokenKind.Day,
+        TokenKind.Endswith,
+        TokenKind.Floor,
+        TokenKind.Fractionalseconds,
+        TokenKind.GeoDistance,
+        TokenKind.GeoIntersects,
+        TokenKind.GeoLength,
+        TokenKind.Hour,
+        TokenKind.Indexof,
+        TokenKind.Isof,
+        TokenKind.Length,
+        TokenKind.Maxdatetime,
+        TokenKind.Mindatetime,
+        TokenKind.Minute,
+        TokenKind.Month,
+        TokenKind.Now,
+        TokenKind.Round,
+        TokenKind.Second,
+        TokenKind.Startswith,
+        TokenKind.Substring,
+        TokenKind.Time,
+        TokenKind.Tolower,
+        TokenKind.Totaloffsetminutes,
+        TokenKind.Totalseconds,
+        TokenKind.Toupper,
+        TokenKind.Trim,
+        TokenKind.Year);
+  }
+
+  private TokenKind isPrimitive() {
+    return is(TokenKind.PrimitiveNullValue,
+        TokenKind.PrimitiveBooleanValue,
+        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 ...).
+        TokenKind.PrimitiveDoubleValue,
+        TokenKind.PrimitiveDecimalValue,
+        TokenKind.PrimitiveGuidValue,
+        TokenKind.PrimitiveDateTimeOffsetValue,
+        TokenKind.PrimitiveDateValue,
+        TokenKind.PrimitiveTimeOfDayValue,
+        TokenKind.PrimitiveIntegerValue,
+        TokenKind.PrimitiveDurationValue,
+        TokenKind.PrimitiveBinaryValue,
+        TokenKind.PrimitiveEnumValue);
+  }
+
+  public enum TokenKind {
+    // BINARY
+    OR_OP,
+    AND_OP,
+
+    EQ_OP,
+    NE_OP,
+
+    GT_OP,
+    GE_OP,
+    LT_OP,
+    LE_OP,
+
+    ADD_OP,
+    SUB_OP,
+
+    MUL_OP,
+    DIV_OP,
+    MOD_OP,
+
+    MINUS,
+    NOT,
+
+    // Grouping
+    OPEN,
+    CLOSE,
+
+    // PrimitiveValues
+    PrimitiveNullValue,
+    PrimitiveBooleanValue,
+
+    PrimitiveStringValue,
+    PrimitiveIntegerValue,
+    PrimitiveGuidValue,
+    PrimitiveDateValue,
+    PrimitiveDateTimeOffsetValue,
+    PrimitiveTimeOfDayValue,
+    PrimitiveDecimalValue,
+    PrimitiveDoubleValue,
+    PrimitiveDurationValue,
+    PrimitiveBinaryValue,
+    PrimitiveEnumValue,
+
+    // ExpressionValues
+    ParameterAlias,
+    ArrayOrObject,
+    RootExpr,
+    IT,
+
+    // BuiltInMethods
+    Cast,
+    Ceiling,
+    Concat,
+    Contains,
+    Date,
+    Day,
+    Endswith,
+    Floor,
+    Fractionalseconds,
+    GeoDistance,
+    GeoIntersects,
+    GeoLength,
+    Hour,
+    Indexof,
+    Isof,
+    Length,
+    Maxdatetime,
+    Mindatetime,
+    Minute,
+    Month,
+    Now,
+    Round,
+    Second,
+    Startswith,
+    Substring,
+    Time,
+    Tolower,
+    Totaloffsetminutes,
+    Totalseconds,
+    Toupper,
+    Trim,
+    Year,
+    COMMA
+  }
+
+  public static class Token {
+    TokenKind kind;
+    String text;
+
+    public Token(TokenKind kind, String text) {
+      this.kind = kind;
+      this.text = text;
+    }
+  }
+
+  public static class Tokenizer {
+    private List<Token> tokens;
+    int counter = 0;
+
+    public Tokenizer(List<Token> tokens) {
+      this.tokens = tokens;
+    }
+
+    public boolean next(TokenKind expectedKind) {
+      if (counter < tokens.size() && expectedKind == tokens.get(counter).kind) {
+        return true;
+      }
+      return false;
+    }
+
+    public String getText() {
+      String text = tokens.get(counter).text;
+      counter++;
+      return text;
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/7b23ad71/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/AliasImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/AliasImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/AliasImpl.java
index 09af93f..5309d73 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/AliasImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/AliasImpl.java
@@ -27,6 +27,14 @@ public class AliasImpl extends ExpressionImpl implements Alias {
 
   private String parameterName;
 
+  public AliasImpl() {
+    //TODO: Delete Constructor
+  }
+
+  public AliasImpl(String parameterName) {
+    this.parameterName = parameterName;
+  }
+
   @Override
   public String getParameterName() {
     return parameterName;

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/7b23ad71/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/BinaryImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/BinaryImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/BinaryImpl.java
index a28f92c..c3530c0 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/BinaryImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/BinaryImpl.java
@@ -31,6 +31,17 @@ public class BinaryImpl extends ExpressionImpl implements Binary {
   private ExpressionImpl left;
   private ExpressionImpl right;
 
+  public BinaryImpl() {
+    // TODO: Delete
+  }
+
+  public BinaryImpl(Expression left, BinaryOperatorKind operator, Expression right) {
+    // TODO:DeleteCast
+    this.left = (ExpressionImpl) left;
+    this.operator = operator;
+    this.right = (ExpressionImpl) right;
+  }
+
   @Override
   public BinaryOperatorKind getOperator() {
     return operator;
@@ -67,4 +78,9 @@ public class BinaryImpl extends ExpressionImpl implements Binary {
     return visitor.visitBinaryOperator(operator, left, right);
   }
 
+  @Override
+  public String toString() {
+    return "{" + left + " " + operator.name() + " " + right + '}';
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/7b23ad71/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/LiteralImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/LiteralImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/LiteralImpl.java
index 1dd9fa7..e275fdd 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/LiteralImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/LiteralImpl.java
@@ -29,6 +29,15 @@ public class LiteralImpl extends ExpressionImpl implements Literal {
   private String text;
   private EdmType type;
 
+  public LiteralImpl() {
+
+  }
+
+  public LiteralImpl(String text, EdmType type) {
+    this.text = text;
+    this.type = type;
+  }
+
   @Override
   public String getText() {
     return text;
@@ -54,4 +63,9 @@ public class LiteralImpl extends ExpressionImpl implements Literal {
     return visitor.visitLiteral(this);
   }
 
+  @Override
+  public String toString() {
+    return "" + text;
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/7b23ad71/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MethodImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MethodImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MethodImpl.java
index 7104a9f..8175c85 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MethodImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MethodImpl.java
@@ -33,6 +33,14 @@ public class MethodImpl extends ExpressionImpl implements Method {
   private MethodKind method;
   private List<ExpressionImpl> parameters = new ArrayList<ExpressionImpl>();
 
+  public MethodImpl() {
+    // TODO: Delete constructor
+  }
+
+  public MethodImpl(MethodKind method) {
+    this.method = method;
+  }
+
   @Override
   public MethodKind getMethod() {
     return method;
@@ -66,4 +74,20 @@ public class MethodImpl extends ExpressionImpl implements Method {
     return visitor.visitMethodCall(method, userParameters);
   }
 
+  @Override
+  public String toString() {
+    String parametersString = "[";
+    boolean first = true;
+    for (Expression exp : parameters) {
+      if(first){
+        first = false;
+        parametersString = parametersString + exp.toString();
+      }else {
+        parametersString = parametersString + ", " + exp.toString();
+      }
+    }
+    parametersString = parametersString + "]";
+    return "{" + method + " " + parametersString + "}";
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/7b23ad71/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/UnaryImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/UnaryImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/UnaryImpl.java
index 796191f..f1edf91 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/UnaryImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/UnaryImpl.java
@@ -30,6 +30,15 @@ public class UnaryImpl extends ExpressionImpl implements Unary {
   private UnaryOperatorKind operator;
   private ExpressionImpl expression;
 
+  public UnaryImpl() {
+
+  }
+
+  public UnaryImpl(UnaryOperatorKind operator, Expression expression) {
+    this.operator = operator;
+    this.expression = (ExpressionImpl) expression;
+  }
+
   @Override
   public UnaryOperatorKind getOperator() {
     return operator;
@@ -54,4 +63,9 @@ public class UnaryImpl extends ExpressionImpl implements Unary {
     return visitor.visitUnaryOperator(operator, operand);
   }
 
+  @Override
+  public String toString() {
+    return "{" + operator + " " + expression + '}';
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/7b23ad71/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/expression/FilterParserTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/expression/FilterParserTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/expression/FilterParserTest.java
new file mode 100644
index 0000000..7bfc369
--- /dev/null
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/expression/FilterParserTest.java
@@ -0,0 +1,210 @@
+/*
+ * 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.expression;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.ArrayList;
+
+import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
+import org.apache.olingo.server.core.uri.expression.FilterParser.TokenKind;
+import org.apache.olingo.server.core.uri.expression.FilterParser.Tokenizer;
+import org.apache.olingo.server.core.uri.expression.FilterParser.Token;
+import org.junit.Test;
+
+public class FilterParserTest {
+
+  @Test
+  public void equality() {
+    Expression expression = parseExpression(TokenKind.EQ_OP);
+    assertEquals("{5 EQ 5}", expression.toString());
+
+    expression = parseExpression(TokenKind.NE_OP);
+    assertEquals("{5 NE 5}", expression.toString());
+  }
+
+  @Test
+  public void relational() {
+    Expression expression = parseExpression(TokenKind.GT_OP);
+    assertEquals("{5 GT 5}", expression.toString());
+
+    expression = parseExpression(TokenKind.GE_OP);
+    assertEquals("{5 GE 5}", expression.toString());
+
+    expression = parseExpression(TokenKind.LT_OP);
+    assertEquals("{5 LT 5}", expression.toString());
+
+    expression = parseExpression(TokenKind.LE_OP);
+    assertEquals("{5 LE 5}", expression.toString());
+  }
+
+  @Test
+  public void additive() {
+    Expression expression = parseExpression(TokenKind.ADD_OP);
+    assertEquals("{5 ADD 5}", expression.toString());
+
+    expression = parseExpression(TokenKind.SUB_OP);
+    assertEquals("{5 SUB 5}", expression.toString());
+  }
+
+  @Test
+  public void multiplicative() {
+    Expression expression = parseExpression(TokenKind.MUL_OP);
+    assertEquals("{5 MUL 5}", expression.toString());
+
+    expression = parseExpression(TokenKind.DIV_OP);
+    assertEquals("{5 DIV 5}", expression.toString());
+
+    expression = parseExpression(TokenKind.MOD_OP);
+    assertEquals("{5 MOD 5}", expression.toString());
+  }
+
+  @Test
+  public void unary() {
+    ArrayList<Token> tokens = new ArrayList<Token>();
+    tokens.add(new Token(TokenKind.MINUS, ""));
+    tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
+    Tokenizer tokenizer = new Tokenizer(tokens);
+    Expression expression = new FilterParser().parse(tokenizer);
+    assertEquals("{- 5}", expression.toString());
+
+    tokens = new ArrayList<Token>();
+    tokens.add(new Token(TokenKind.NOT, ""));
+    tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
+    tokenizer = new Tokenizer(tokens);
+    expression = new FilterParser().parse(tokenizer);
+    assertEquals("{not 5}", expression.toString());
+  }
+
+  @Test
+  public void grouping() {
+    ArrayList<Token> tokens = new ArrayList<Token>();
+    tokens.add(new Token(TokenKind.MINUS, ""));
+    tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
+    tokens.add(new Token(TokenKind.ADD_OP, ""));
+    tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
+    Tokenizer tokenizer = new Tokenizer(tokens);
+    Expression expression = new FilterParser().parse(tokenizer);
+    assertEquals("{{- 5} ADD 5}", expression.toString());
+
+    tokens = new ArrayList<Token>();
+    tokens.add(new Token(TokenKind.MINUS, ""));
+    tokens.add(new Token(TokenKind.OPEN, ""));
+    tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
+    tokens.add(new Token(TokenKind.ADD_OP, ""));
+    tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
+    tokens.add(new Token(TokenKind.CLOSE, ""));
+    tokenizer = new Tokenizer(tokens);
+    expression = new FilterParser().parse(tokenizer);
+    assertEquals("{- {5 ADD 5}}", expression.toString());
+  }
+
+  @Test
+  public void noParameterMethods() {
+    Expression expression = parseMethod(TokenKind.Now);
+    assertEquals("{now []}", expression.toString());
+
+    expression = parseMethod(TokenKind.Maxdatetime);
+    assertEquals("{maxdatetime []}", expression.toString());
+
+    expression = parseMethod(TokenKind.Mindatetime);
+    assertEquals("{mindatetime []}", expression.toString());
+  }
+
+  @Test
+  public void oneParameterMethods() {
+    Expression expression = parseMethod(TokenKind.Length, TokenKind.PrimitiveStringValue);
+    assertEquals("{length [String1]}", expression.toString());
+
+    expression = parseMethod(TokenKind.Tolower, TokenKind.PrimitiveStringValue);
+    assertEquals("{tolower [String1]}", expression.toString());
+
+    expression = parseMethod(TokenKind.Toupper, TokenKind.PrimitiveStringValue);
+    assertEquals("{toupper [String1]}", expression.toString());
+
+    expression = parseMethod(TokenKind.Trim, TokenKind.PrimitiveStringValue);
+    assertEquals("{trim [String1]}", expression.toString());
+
+    expression = parseMethod(TokenKind.Year, TokenKind.PrimitiveDateValue);
+    assertEquals("{year [Date1]}", expression.toString());
+
+    expression = parseMethod(TokenKind.Month, TokenKind.PrimitiveDateValue);
+    assertEquals("{month [Date1]}", expression.toString());
+
+    expression = parseMethod(TokenKind.Day, TokenKind.PrimitiveDateValue);
+    assertEquals("{day [Date1]}", expression.toString());
+
+    expression = parseMethod(TokenKind.Hour, TokenKind.PrimitiveDateTimeOffsetValue);
+    assertEquals("{hour [DateTimeOffset1]}", expression.toString());
+
+    expression = parseMethod(TokenKind.Minute, TokenKind.PrimitiveDateTimeOffsetValue);
+    assertEquals("{minute [DateTimeOffset1]}", expression.toString());
+
+    expression = parseMethod(TokenKind.Second, TokenKind.PrimitiveDateTimeOffsetValue);
+    assertEquals("{second [DateTimeOffset1]}", expression.toString());
+  }
+
+  @Test
+  public void twoParameterMethods() {
+
+  }
+
+  private Expression parseMethod(TokenKind... kind) {
+    ArrayList<Token> tokens = new ArrayList<Token>();
+    tokens.add(new Token(kind[0], ""));
+
+    for (int i = 1; i < kind.length; i++) {
+      String text = null;
+      switch (kind[i]) {
+      case PrimitiveStringValue:
+        text = "String" + i;
+        break;
+      case PrimitiveDateValue:
+        text = "Date" + i;
+        break;
+      case PrimitiveDateTimeOffsetValue:
+        text = "DateTimeOffset" + i;
+        break;
+      default:
+        text = "" + i;
+        break;
+      }
+      tokens.add(new Token(kind[i], text));
+    }
+
+    tokens.add(new Token(TokenKind.CLOSE, ""));
+    Tokenizer tokenizer = new Tokenizer(tokens);
+    Expression expression = new FilterParser().parse(tokenizer);
+    assertNotNull(expression);
+    return expression;
+  }
+
+  private Expression parseExpression(TokenKind operator) {
+    ArrayList<Token> tokens = new ArrayList<Token>();
+    tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
+    tokens.add(new Token(operator, ""));
+    tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
+    Tokenizer tokenizer = new Tokenizer(tokens);
+
+    Expression expression = new FilterParser().parse(tokenizer);
+    assertNotNull(expression);
+    return expression;
+  }
+}


[12/30] olingo-odata4 git commit: [OLINGO-834] ExpressionParser uses UriTokenizer

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2f3bc286/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java
index 177a396..b5614ad 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java
@@ -22,6 +22,8 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
+import java.util.Locale;
+
 import org.apache.olingo.server.core.uri.parser.UriTokenizer.TokenKind;
 import org.junit.Test;
 
@@ -44,6 +46,8 @@ public class UriTokenizerTest {
     assertTrue(new UriTokenizer("$value").next(TokenKind.VALUE));
     assertTrue(new UriTokenizer("$count").next(TokenKind.COUNT));
     assertTrue(new UriTokenizer("$crossjoin").next(TokenKind.CROSSJOIN));
+    assertTrue(new UriTokenizer("$root").next(TokenKind.ROOT));
+    assertTrue(new UriTokenizer("$it").next(TokenKind.IT));
     assertTrue(new UriTokenizer("null").next(TokenKind.NULL));
 
     wrongToken(TokenKind.REF, "$ref", 'x');
@@ -51,19 +55,19 @@ public class UriTokenizerTest {
 
   @Test
   public void sequence() {
-    final UriTokenizer tokenizer = new UriTokenizer("(A=1,B=2);.*/+");
+    final UriTokenizer tokenizer = new UriTokenizer("(A=1,B=2);.*/+-");
     assertTrue(tokenizer.next(TokenKind.OPEN));
     assertFalse(tokenizer.next(TokenKind.OPEN));
     assertTrue(tokenizer.next(TokenKind.ODataIdentifier));
     assertEquals("A", tokenizer.getText());
     assertTrue(tokenizer.next(TokenKind.EQ));
-    assertTrue(tokenizer.next(TokenKind.PrimitiveIntegerValue));
+    assertTrue(tokenizer.next(TokenKind.IntegerValue));
     assertEquals("1", tokenizer.getText());
     assertTrue(tokenizer.next(TokenKind.COMMA));
     assertTrue(tokenizer.next(TokenKind.ODataIdentifier));
     assertEquals("B", tokenizer.getText());
     assertTrue(tokenizer.next(TokenKind.EQ));
-    assertTrue(tokenizer.next(TokenKind.PrimitiveIntegerValue));
+    assertTrue(tokenizer.next(TokenKind.IntegerValue));
     assertEquals("2", tokenizer.getText());
     assertFalse(tokenizer.next(TokenKind.EOF));
     assertTrue(tokenizer.next(TokenKind.CLOSE));
@@ -72,6 +76,7 @@ public class UriTokenizerTest {
     assertTrue(tokenizer.next(TokenKind.STAR));
     assertTrue(tokenizer.next(TokenKind.SLASH));
     assertTrue(tokenizer.next(TokenKind.PLUS));
+    assertTrue(tokenizer.next(TokenKind.MINUS));
     assertTrue(tokenizer.next(TokenKind.EOF));
   }
 
@@ -107,7 +112,7 @@ public class UriTokenizerTest {
     final UriTokenizer tokenizer = new UriTokenizer("multi.part.namespace.name.1");
     assertTrue(tokenizer.next(TokenKind.QualifiedName));
     assertTrue(tokenizer.next(TokenKind.DOT));
-    assertTrue(tokenizer.next(TokenKind.PrimitiveIntegerValue));
+    assertTrue(tokenizer.next(TokenKind.IntegerValue));
     assertTrue(tokenizer.next(TokenKind.EOF));
 
     assertFalse(new UriTokenizer("name").next(TokenKind.QualifiedName));
@@ -127,174 +132,174 @@ public class UriTokenizerTest {
 
   @Test
   public void booleanValue() {
-    assertTrue(new UriTokenizer("true").next(TokenKind.PrimitiveBooleanValue));
-    assertTrue(new UriTokenizer("tRuE").next(TokenKind.PrimitiveBooleanValue));
-    assertTrue(new UriTokenizer("false").next(TokenKind.PrimitiveBooleanValue));
-    assertTrue(new UriTokenizer("False").next(TokenKind.PrimitiveBooleanValue));
+    assertTrue(new UriTokenizer("true").next(TokenKind.BooleanValue));
+    assertTrue(new UriTokenizer("tRuE").next(TokenKind.BooleanValue));
+    assertTrue(new UriTokenizer("false").next(TokenKind.BooleanValue));
+    assertTrue(new UriTokenizer("False").next(TokenKind.BooleanValue));
 
-    wrongToken(TokenKind.PrimitiveBooleanValue, "true", 'x');
+    wrongToken(TokenKind.BooleanValue, "true", 'x');
   }
 
   @Test
   public void string() {
-    assertTrue(new UriTokenizer("'ABC'").next(TokenKind.PrimitiveStringValue));
-    assertTrue(new UriTokenizer("'€\uFDFC'").next(TokenKind.PrimitiveStringValue));
+    assertTrue(new UriTokenizer("'ABC'").next(TokenKind.StringValue));
+    assertTrue(new UriTokenizer("'€\uFDFC'").next(TokenKind.StringValue));
     assertTrue(new UriTokenizer('\'' + String.valueOf(Character.toChars(0x1F603)) + '\'')
-        .next(TokenKind.PrimitiveStringValue));
+        .next(TokenKind.StringValue));
 
     final UriTokenizer tokenizer = new UriTokenizer("'AB''''C'''D");
-    assertTrue(tokenizer.next(TokenKind.PrimitiveStringValue));
+    assertTrue(tokenizer.next(TokenKind.StringValue));
     assertEquals("'AB''''C'''", tokenizer.getText());
     assertTrue(tokenizer.next(TokenKind.ODataIdentifier));
     assertEquals("D", tokenizer.getText());
 
-    assertFalse(new UriTokenizer("A").next(TokenKind.PrimitiveStringValue));
-    assertFalse(new UriTokenizer("'A").next(TokenKind.PrimitiveStringValue));
+    assertFalse(new UriTokenizer("A").next(TokenKind.StringValue));
+    assertFalse(new UriTokenizer("'A").next(TokenKind.StringValue));
   }
 
   @Test
   public void integer() {
-    assertTrue(new UriTokenizer("1").next(TokenKind.PrimitiveIntegerValue));
-    assertTrue(new UriTokenizer("1.").next(TokenKind.PrimitiveIntegerValue));
-    assertFalse(new UriTokenizer(".1").next(TokenKind.PrimitiveIntegerValue));
-    assertTrue(new UriTokenizer("-1").next(TokenKind.PrimitiveIntegerValue));
-    assertTrue(new UriTokenizer("1234567890").next(TokenKind.PrimitiveIntegerValue));
+    assertTrue(new UriTokenizer("1").next(TokenKind.IntegerValue));
+    assertTrue(new UriTokenizer("1.").next(TokenKind.IntegerValue));
+    assertFalse(new UriTokenizer(".1").next(TokenKind.IntegerValue));
+    assertTrue(new UriTokenizer("-1").next(TokenKind.IntegerValue));
+    assertTrue(new UriTokenizer("1234567890").next(TokenKind.IntegerValue));
   }
 
   @Test
   public void guid() {
-    assertTrue(new UriTokenizer("12345678-abcd-ef12-1234-567890ABCDEF").next(TokenKind.PrimitiveGuidValue));
-    wrongToken(TokenKind.PrimitiveGuidValue, "12345678-1234-1234-1234-123456789ABC", 'G');
+    assertTrue(new UriTokenizer("12345678-abcd-ef12-1234-567890ABCDEF").next(TokenKind.GuidValue));
+    wrongToken(TokenKind.GuidValue, "12345678-1234-1234-1234-123456789ABC", 'G');
   }
 
   @Test
   public void date() {
-    assertTrue(new UriTokenizer("12345-12-25").next(TokenKind.PrimitiveDateValue));
-    assertTrue(new UriTokenizer("-0001-12-24").next(TokenKind.PrimitiveDateValue));
-    assertFalse(new UriTokenizer("1234-13-01").next(TokenKind.PrimitiveDateValue));
-    assertFalse(new UriTokenizer("1234-12-32").next(TokenKind.PrimitiveDateValue));
-    assertFalse(new UriTokenizer("123-01-01").next(TokenKind.PrimitiveDateValue));
-    assertFalse(new UriTokenizer("1234-00-01").next(TokenKind.PrimitiveDateValue));
-    assertFalse(new UriTokenizer("1234-01-00").next(TokenKind.PrimitiveDateValue));
-    wrongToken(TokenKind.PrimitiveDateValue, "2000-12-29", 'A');
-    wrongToken(TokenKind.PrimitiveDateValue, "0001-01-01", 'A');
-    wrongToken(TokenKind.PrimitiveDateValue, "-12345-01-31", 'A');
+    assertTrue(new UriTokenizer("12345-12-25").next(TokenKind.DateValue));
+    assertTrue(new UriTokenizer("-0001-12-24").next(TokenKind.DateValue));
+    assertFalse(new UriTokenizer("1234-13-01").next(TokenKind.DateValue));
+    assertFalse(new UriTokenizer("1234-12-32").next(TokenKind.DateValue));
+    assertFalse(new UriTokenizer("123-01-01").next(TokenKind.DateValue));
+    assertFalse(new UriTokenizer("1234-00-01").next(TokenKind.DateValue));
+    assertFalse(new UriTokenizer("1234-01-00").next(TokenKind.DateValue));
+    wrongToken(TokenKind.DateValue, "2000-12-29", 'A');
+    wrongToken(TokenKind.DateValue, "0001-01-01", 'A');
+    wrongToken(TokenKind.DateValue, "-12345-01-31", 'A');
   }
 
   @Test
   public void dateTimeOffset() {
-    assertTrue(new UriTokenizer("1234-12-25T11:12:13.456Z").next(TokenKind.PrimitiveDateTimeOffsetValue));
-    assertTrue(new UriTokenizer("-1234-12-25t01:12z").next(TokenKind.PrimitiveDateTimeOffsetValue));
-    assertTrue(new UriTokenizer("-1234-12-25T21:22:23+01:00").next(TokenKind.PrimitiveDateTimeOffsetValue));
-    assertTrue(new UriTokenizer("1234-12-25T11:12:13-00:30").next(TokenKind.PrimitiveDateTimeOffsetValue));
-    assertFalse(new UriTokenizer("1234-10-01").next(TokenKind.PrimitiveDateTimeOffsetValue));
-    wrongToken(TokenKind.PrimitiveDateTimeOffsetValue, "-1234-12-25T11:12:13.456+01:00", 'P');
+    assertTrue(new UriTokenizer("1234-12-25T11:12:13.456Z").next(TokenKind.DateTimeOffsetValue));
+    assertTrue(new UriTokenizer("-1234-12-25t01:12z").next(TokenKind.DateTimeOffsetValue));
+    assertTrue(new UriTokenizer("-1234-12-25T21:22:23+01:00").next(TokenKind.DateTimeOffsetValue));
+    assertTrue(new UriTokenizer("1234-12-25T11:12:13-00:30").next(TokenKind.DateTimeOffsetValue));
+    assertFalse(new UriTokenizer("1234-10-01").next(TokenKind.DateTimeOffsetValue));
+    wrongToken(TokenKind.DateTimeOffsetValue, "-1234-12-25T11:12:13.456+01:00", 'P');
   }
 
   @Test
   public void timeOfDay() {
-    assertTrue(new UriTokenizer("11:12:13").next(TokenKind.PrimitiveTimeOfDayValue));
-    assertTrue(new UriTokenizer("11:12:13.456").next(TokenKind.PrimitiveTimeOfDayValue));
-    assertFalse(new UriTokenizer("24:00:00").next(TokenKind.PrimitiveTimeOfDayValue));
-    assertFalse(new UriTokenizer("01:60:00").next(TokenKind.PrimitiveTimeOfDayValue));
-    assertFalse(new UriTokenizer("01:00:60").next(TokenKind.PrimitiveTimeOfDayValue));
-    assertFalse(new UriTokenizer("01:00:00.").next(TokenKind.PrimitiveTimeOfDayValue));
-    assertFalse(new UriTokenizer("0:02:03").next(TokenKind.PrimitiveTimeOfDayValue));
-    assertFalse(new UriTokenizer("01:0:03").next(TokenKind.PrimitiveTimeOfDayValue));
-    assertFalse(new UriTokenizer("01:02:0").next(TokenKind.PrimitiveTimeOfDayValue));
-    wrongToken(TokenKind.PrimitiveTimeOfDayValue, "11:12", '-');
+    assertTrue(new UriTokenizer("11:12:13").next(TokenKind.TimeOfDayValue));
+    assertTrue(new UriTokenizer("11:12:13.456").next(TokenKind.TimeOfDayValue));
+    assertFalse(new UriTokenizer("24:00:00").next(TokenKind.TimeOfDayValue));
+    assertFalse(new UriTokenizer("01:60:00").next(TokenKind.TimeOfDayValue));
+    assertFalse(new UriTokenizer("01:00:60").next(TokenKind.TimeOfDayValue));
+    assertFalse(new UriTokenizer("01:00:00.").next(TokenKind.TimeOfDayValue));
+    assertFalse(new UriTokenizer("0:02:03").next(TokenKind.TimeOfDayValue));
+    assertFalse(new UriTokenizer("01:0:03").next(TokenKind.TimeOfDayValue));
+    assertFalse(new UriTokenizer("01:02:0").next(TokenKind.TimeOfDayValue));
+    wrongToken(TokenKind.TimeOfDayValue, "11:12", '-');
   }
 
   @Test
   public void decimal() {
-    assertTrue(new UriTokenizer("1.2").next(TokenKind.PrimitiveDecimalValue));
-    assertFalse(new UriTokenizer(".1").next(TokenKind.PrimitiveDecimalValue));
-    assertTrue(new UriTokenizer("-12.34").next(TokenKind.PrimitiveDecimalValue));
-    assertTrue(new UriTokenizer("1234567890.0123456789").next(TokenKind.PrimitiveDecimalValue));
-    assertFalse(new UriTokenizer("0,1").next(TokenKind.PrimitiveDecimalValue));
-    assertFalse(new UriTokenizer("0..1").next(TokenKind.PrimitiveDecimalValue));
+    assertTrue(new UriTokenizer("1.2").next(TokenKind.DecimalValue));
+    assertFalse(new UriTokenizer(".1").next(TokenKind.DecimalValue));
+    assertTrue(new UriTokenizer("-12.34").next(TokenKind.DecimalValue));
+    assertTrue(new UriTokenizer("1234567890.0123456789").next(TokenKind.DecimalValue));
+    assertFalse(new UriTokenizer("0,1").next(TokenKind.DecimalValue));
+    assertFalse(new UriTokenizer("0..1").next(TokenKind.DecimalValue));
   }
 
   @Test
   public void doubleValue() {
-    assertTrue(new UriTokenizer("NaN").next(TokenKind.PrimitiveDoubleValue));
-    assertTrue(new UriTokenizer("-INF").next(TokenKind.PrimitiveDoubleValue));
-    assertTrue(new UriTokenizer("INF").next(TokenKind.PrimitiveDoubleValue));
-    assertFalse(new UriTokenizer("inf").next(TokenKind.PrimitiveDoubleValue));
-    assertTrue(new UriTokenizer("1.2E3").next(TokenKind.PrimitiveDoubleValue));
-    assertTrue(new UriTokenizer("-12.34e-05").next(TokenKind.PrimitiveDoubleValue));
-    assertTrue(new UriTokenizer("1E2").next(TokenKind.PrimitiveDoubleValue));
-    assertFalse(new UriTokenizer("1.E2").next(TokenKind.PrimitiveDoubleValue));
-    wrongToken(TokenKind.PrimitiveDoubleValue, "-12.34E+5", 'i');
+    assertTrue(new UriTokenizer("NaN").next(TokenKind.DoubleValue));
+    assertTrue(new UriTokenizer("-INF").next(TokenKind.DoubleValue));
+    assertTrue(new UriTokenizer("INF").next(TokenKind.DoubleValue));
+    assertFalse(new UriTokenizer("inf").next(TokenKind.DoubleValue));
+    assertTrue(new UriTokenizer("1.2E3").next(TokenKind.DoubleValue));
+    assertTrue(new UriTokenizer("-12.34e-05").next(TokenKind.DoubleValue));
+    assertTrue(new UriTokenizer("1E2").next(TokenKind.DoubleValue));
+    assertFalse(new UriTokenizer("1.E2").next(TokenKind.DoubleValue));
+    wrongToken(TokenKind.DoubleValue, "-12.34E+5", 'i');
   }
 
   @Test
   public void duration() {
-    assertTrue(new UriTokenizer("duration'P'").next(TokenKind.PrimitiveDurationValue));
-    assertTrue(new UriTokenizer("DURATION'P1D'").next(TokenKind.PrimitiveDurationValue));
-    assertTrue(new UriTokenizer("duration'PT'").next(TokenKind.PrimitiveDurationValue));
-    assertTrue(new UriTokenizer("duration'PT1H'").next(TokenKind.PrimitiveDurationValue));
-    assertTrue(new UriTokenizer("duration'pt1M'").next(TokenKind.PrimitiveDurationValue));
-    assertTrue(new UriTokenizer("duration'PT1S'").next(TokenKind.PrimitiveDurationValue));
-    assertTrue(new UriTokenizer("duration'PT1.2s'").next(TokenKind.PrimitiveDurationValue));
-    assertTrue(new UriTokenizer("duration'-p1dt2h3m4.5s'").next(TokenKind.PrimitiveDurationValue));
-    assertFalse(new UriTokenizer("-p1dt2h3m4.5s").next(TokenKind.PrimitiveDurationValue));
-    assertFalse(new UriTokenizer("duration'-p1dt2h3m4.5s").next(TokenKind.PrimitiveDurationValue));
-    assertFalse(new UriTokenizer("duration'2h3m4s'").next(TokenKind.PrimitiveDurationValue));
-    wrongToken(TokenKind.PrimitiveDurationValue, "duration'P1DT2H3M4.5S'", ':');
+    assertTrue(new UriTokenizer("duration'P'").next(TokenKind.DurationValue));
+    assertTrue(new UriTokenizer("DURATION'P1D'").next(TokenKind.DurationValue));
+    assertTrue(new UriTokenizer("duration'PT'").next(TokenKind.DurationValue));
+    assertTrue(new UriTokenizer("duration'PT1H'").next(TokenKind.DurationValue));
+    assertTrue(new UriTokenizer("duration'pt1M'").next(TokenKind.DurationValue));
+    assertTrue(new UriTokenizer("duration'PT1S'").next(TokenKind.DurationValue));
+    assertTrue(new UriTokenizer("duration'PT1.2s'").next(TokenKind.DurationValue));
+    assertTrue(new UriTokenizer("duration'-p1dt2h3m4.5s'").next(TokenKind.DurationValue));
+    assertFalse(new UriTokenizer("-p1dt2h3m4.5s").next(TokenKind.DurationValue));
+    assertFalse(new UriTokenizer("duration'-p1dt2h3m4.5s").next(TokenKind.DurationValue));
+    assertFalse(new UriTokenizer("duration'2h3m4s'").next(TokenKind.DurationValue));
+    wrongToken(TokenKind.DurationValue, "duration'P1DT2H3M4.5S'", ':');
   }
 
   @Test
   public void binary() {
-    assertTrue(new UriTokenizer("binary''").next(TokenKind.PrimitiveBinaryValue));
-    assertTrue(new UriTokenizer("Binary'bm93'").next(TokenKind.PrimitiveBinaryValue));
+    assertTrue(new UriTokenizer("binary''").next(TokenKind.BinaryValue));
+    assertTrue(new UriTokenizer("Binary'bm93'").next(TokenKind.BinaryValue));
 
     // all cases with three base64 characters (and one fill character) at the end
-    assertTrue(new UriTokenizer("binary'QUA='").next(TokenKind.PrimitiveBinaryValue));
-    assertTrue(new UriTokenizer("binary'QUE='").next(TokenKind.PrimitiveBinaryValue));
-    assertTrue(new UriTokenizer("binary'QUI='").next(TokenKind.PrimitiveBinaryValue));
-    assertTrue(new UriTokenizer("binary'QUM='").next(TokenKind.PrimitiveBinaryValue));
-    assertTrue(new UriTokenizer("binary'QUQ='").next(TokenKind.PrimitiveBinaryValue));
-    assertTrue(new UriTokenizer("binary'QUU='").next(TokenKind.PrimitiveBinaryValue));
-    assertTrue(new UriTokenizer("binary'QUY='").next(TokenKind.PrimitiveBinaryValue));
-    assertTrue(new UriTokenizer("binary'QUc='").next(TokenKind.PrimitiveBinaryValue));
-    assertTrue(new UriTokenizer("binary'QUg='").next(TokenKind.PrimitiveBinaryValue));
-    assertTrue(new UriTokenizer("binary'QUk='").next(TokenKind.PrimitiveBinaryValue));
-    assertTrue(new UriTokenizer("binary'QUo='").next(TokenKind.PrimitiveBinaryValue));
-    assertTrue(new UriTokenizer("binary'QUs='").next(TokenKind.PrimitiveBinaryValue));
-    assertTrue(new UriTokenizer("binary'QUw='").next(TokenKind.PrimitiveBinaryValue));
-    assertTrue(new UriTokenizer("binary'QU0='").next(TokenKind.PrimitiveBinaryValue));
-    assertTrue(new UriTokenizer("binary'QU4='").next(TokenKind.PrimitiveBinaryValue));
-    assertTrue(new UriTokenizer("binary'QU8='").next(TokenKind.PrimitiveBinaryValue));
-    assertFalse(new UriTokenizer("binary'QUB='").next(TokenKind.PrimitiveBinaryValue));
+    assertTrue(new UriTokenizer("binary'QUA='").next(TokenKind.BinaryValue));
+    assertTrue(new UriTokenizer("binary'QUE='").next(TokenKind.BinaryValue));
+    assertTrue(new UriTokenizer("binary'QUI='").next(TokenKind.BinaryValue));
+    assertTrue(new UriTokenizer("binary'QUM='").next(TokenKind.BinaryValue));
+    assertTrue(new UriTokenizer("binary'QUQ='").next(TokenKind.BinaryValue));
+    assertTrue(new UriTokenizer("binary'QUU='").next(TokenKind.BinaryValue));
+    assertTrue(new UriTokenizer("binary'QUY='").next(TokenKind.BinaryValue));
+    assertTrue(new UriTokenizer("binary'QUc='").next(TokenKind.BinaryValue));
+    assertTrue(new UriTokenizer("binary'QUg='").next(TokenKind.BinaryValue));
+    assertTrue(new UriTokenizer("binary'QUk='").next(TokenKind.BinaryValue));
+    assertTrue(new UriTokenizer("binary'QUo='").next(TokenKind.BinaryValue));
+    assertTrue(new UriTokenizer("binary'QUs='").next(TokenKind.BinaryValue));
+    assertTrue(new UriTokenizer("binary'QUw='").next(TokenKind.BinaryValue));
+    assertTrue(new UriTokenizer("binary'QU0='").next(TokenKind.BinaryValue));
+    assertTrue(new UriTokenizer("binary'QU4='").next(TokenKind.BinaryValue));
+    assertTrue(new UriTokenizer("binary'QU8='").next(TokenKind.BinaryValue));
+    assertFalse(new UriTokenizer("binary'QUB='").next(TokenKind.BinaryValue));
 
     // all cases with two base64 characters (and two fill characters) at the end
-    assertTrue(new UriTokenizer("BINARY'VGVzdA=='").next(TokenKind.PrimitiveBinaryValue));
-    assertTrue(new UriTokenizer("binary'U-RnZQ=='").next(TokenKind.PrimitiveBinaryValue));
-    assertTrue(new UriTokenizer("binary'Yg=='").next(TokenKind.PrimitiveBinaryValue));
-    assertTrue(new UriTokenizer("binary'Yw=='").next(TokenKind.PrimitiveBinaryValue));
+    assertTrue(new UriTokenizer("BINARY'VGVzdA=='").next(TokenKind.BinaryValue));
+    assertTrue(new UriTokenizer("binary'U-RnZQ=='").next(TokenKind.BinaryValue));
+    assertTrue(new UriTokenizer("binary'Yg=='").next(TokenKind.BinaryValue));
+    assertTrue(new UriTokenizer("binary'Yw=='").next(TokenKind.BinaryValue));
 
     // without optional fill character
-    assertTrue(new UriTokenizer("binary'T0RhdGE'").next(TokenKind.PrimitiveBinaryValue));
+    assertTrue(new UriTokenizer("binary'T0RhdGE'").next(TokenKind.BinaryValue));
 
     // special character '_' (the other, '-', already has been used above)
-    assertTrue(new UriTokenizer("binary'V_ZydGVy'").next(TokenKind.PrimitiveBinaryValue));
+    assertTrue(new UriTokenizer("binary'V_ZydGVy'").next(TokenKind.BinaryValue));
 
-    wrongToken(TokenKind.PrimitiveBinaryValue, "binary'VGVzdA=='", '+');
+    wrongToken(TokenKind.BinaryValue, "binary'VGVzdA=='", '+');
   }
 
   @Test
   public void enumValue() {
-    assertTrue(new UriTokenizer("namespace.name'value'").next(TokenKind.PrimitiveEnumValue));
-    assertTrue(new UriTokenizer("namespace.name'flag1,flag2,-3'").next(TokenKind.PrimitiveEnumValue));
-    assertFalse(new UriTokenizer("namespace.name'1flag'").next(TokenKind.PrimitiveEnumValue));
-    assertFalse(new UriTokenizer("namespace.name'flag1,,flag2'").next(TokenKind.PrimitiveEnumValue));
-    assertFalse(new UriTokenizer("namespace.name',value'").next(TokenKind.PrimitiveEnumValue));
-    assertFalse(new UriTokenizer("namespace.name'value,'").next(TokenKind.PrimitiveEnumValue));
-    assertFalse(new UriTokenizer("namespace.name''").next(TokenKind.PrimitiveEnumValue));
-    assertFalse(new UriTokenizer("'1'").next(TokenKind.PrimitiveEnumValue));
-    assertFalse(new UriTokenizer("1").next(TokenKind.PrimitiveEnumValue));
-    wrongToken(TokenKind.PrimitiveEnumValue, "namespace.name'_1,_2,3'", ';');
+    assertTrue(new UriTokenizer("namespace.name'value'").next(TokenKind.EnumValue));
+    assertTrue(new UriTokenizer("namespace.name'flag1,flag2,-3'").next(TokenKind.EnumValue));
+    assertFalse(new UriTokenizer("namespace.name'1flag'").next(TokenKind.EnumValue));
+    assertFalse(new UriTokenizer("namespace.name'flag1,,flag2'").next(TokenKind.EnumValue));
+    assertFalse(new UriTokenizer("namespace.name',value'").next(TokenKind.EnumValue));
+    assertFalse(new UriTokenizer("namespace.name'value,'").next(TokenKind.EnumValue));
+    assertFalse(new UriTokenizer("namespace.name''").next(TokenKind.EnumValue));
+    assertFalse(new UriTokenizer("'1'").next(TokenKind.EnumValue));
+    assertFalse(new UriTokenizer("1").next(TokenKind.EnumValue));
+    wrongToken(TokenKind.EnumValue, "namespace.name'_1,_2,3'", ';');
   }
 
   @Test
@@ -360,6 +365,92 @@ public class UriTokenizerTest {
     wrongToken(TokenKind.jsonArrayOrObject, "[{\"name\":+123.456},null]", '\\');
   }
 
+  @Test
+  public void operators() {
+    UriTokenizer tokenizer = new UriTokenizer("1 ne 2");
+    assertTrue(tokenizer.next(TokenKind.IntegerValue));
+    assertFalse(tokenizer.next(TokenKind.EqualsOperator));
+    assertTrue(tokenizer.next(TokenKind.NotEqualsOperator));
+    assertTrue(tokenizer.next(TokenKind.IntegerValue));
+    assertTrue(tokenizer.next(TokenKind.EOF));
+
+    tokenizer = new UriTokenizer("1ne 2");
+    assertTrue(tokenizer.next(TokenKind.IntegerValue));
+    assertFalse(tokenizer.next(TokenKind.NotEqualsOperator));
+
+    tokenizer = new UriTokenizer("1 ne2");
+    assertTrue(tokenizer.next(TokenKind.IntegerValue));
+    assertFalse(tokenizer.next(TokenKind.NotEqualsOperator));
+
+    tokenizer = new UriTokenizer("1    \tle\t\t\t2");
+    assertTrue(tokenizer.next(TokenKind.IntegerValue));
+    assertTrue(tokenizer.next(TokenKind.LessThanOrEqualsOperator));
+    assertTrue(tokenizer.next(TokenKind.IntegerValue));
+    assertTrue(tokenizer.next(TokenKind.EOF));
+
+    assertFalse(new UriTokenizer("nottrue").next(TokenKind.NotOperator));
+    assertFalse(new UriTokenizer("no true").next(TokenKind.NotOperator));
+
+    tokenizer = new UriTokenizer("true or not false and 1 eq 2 add 3 sub 4 mul 5 div 6 mod 7");
+    assertTrue(tokenizer.next(TokenKind.BooleanValue));
+    assertTrue(tokenizer.next(TokenKind.OrOperator));
+    assertTrue(tokenizer.next(TokenKind.NotOperator));
+    assertTrue(tokenizer.next(TokenKind.BooleanValue));
+    assertTrue(tokenizer.next(TokenKind.AndOperator));
+    assertTrue(tokenizer.next(TokenKind.IntegerValue));
+    assertTrue(tokenizer.next(TokenKind.EqualsOperator));
+    assertTrue(tokenizer.next(TokenKind.IntegerValue));
+    assertTrue(tokenizer.next(TokenKind.AddOperator));
+    assertTrue(tokenizer.next(TokenKind.IntegerValue));
+    assertTrue(tokenizer.next(TokenKind.SubOperator));
+    assertTrue(tokenizer.next(TokenKind.IntegerValue));
+    assertTrue(tokenizer.next(TokenKind.MulOperator));
+    assertTrue(tokenizer.next(TokenKind.IntegerValue));
+    assertTrue(tokenizer.next(TokenKind.DivOperator));
+    assertTrue(tokenizer.next(TokenKind.IntegerValue));
+    assertTrue(tokenizer.next(TokenKind.ModOperator));
+    assertTrue(tokenizer.next(TokenKind.IntegerValue));
+    assertTrue(tokenizer.next(TokenKind.EOF));
+
+    tokenizer = new UriTokenizer("1 gt 2 or 3 ge 4 or 5 lt 6");
+    assertTrue(tokenizer.next(TokenKind.IntegerValue));
+    assertTrue(tokenizer.next(TokenKind.GreaterThanOperator));
+    assertTrue(tokenizer.next(TokenKind.IntegerValue));
+    assertTrue(tokenizer.next(TokenKind.OrOperator));
+    assertTrue(tokenizer.next(TokenKind.IntegerValue));
+    assertTrue(tokenizer.next(TokenKind.GreaterThanOrEqualsOperator));
+    assertTrue(tokenizer.next(TokenKind.IntegerValue));
+    assertTrue(tokenizer.next(TokenKind.OrOperator));
+    assertTrue(tokenizer.next(TokenKind.IntegerValue));
+    assertTrue(tokenizer.next(TokenKind.LessThanOperator));
+    assertTrue(tokenizer.next(TokenKind.IntegerValue));
+    assertTrue(tokenizer.next(TokenKind.EOF));
+  }
+
+  @Test
+  public void methods() {
+    UriTokenizer tokenizer = new UriTokenizer("now()");
+    assertTrue(tokenizer.next(TokenKind.NowMethod));
+    assertTrue(tokenizer.next(TokenKind.CLOSE));
+    assertTrue(tokenizer.next(TokenKind.EOF));
+
+    assertFalse(new UriTokenizer("no w()").next(TokenKind.NowMethod));
+    assertFalse(new UriTokenizer("now ()").next(TokenKind.NowMethod));
+
+    assertTrue(new UriTokenizer("maxdatetime()").next(TokenKind.MaxdatetimeMethod));
+    assertTrue(new UriTokenizer("mindatetime()").next(TokenKind.MindatetimeMethod));
+
+    for (final TokenKind tokenKind : TokenKind.values()) {
+      if (tokenKind.name().endsWith("Method")) {
+        assertTrue(tokenKind.name(),
+            new UriTokenizer(
+                tokenKind.name().substring(0, tokenKind.name().indexOf("Method"))
+                    .toLowerCase(Locale.ROOT).replace("geo", "geo.") + '(')
+                .next(tokenKind));
+      }
+    }
+  }
+
   private void wrongToken(final TokenKind kind, final String value, final char disturbCharacter) {
     assertFalse(new UriTokenizer(disturbCharacter + value).next(kind));
 


[11/30] olingo-odata4 git commit: [OLINGO-834] clean-up Expression implementations

Posted by ch...@apache.org.
[OLINGO-834] clean-up Expression implementations

Signed-off-by: Christian Amend <ch...@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/208f26c7
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/208f26c7
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/208f26c7

Branch: refs/heads/master
Commit: 208f26c746263c2d5b9a14e48bae9a7091e1f839
Parents: d7e23bf
Author: Klaus Straubinger <kl...@sap.com>
Authored: Fri Dec 11 10:10:03 2015 +0100
Committer: Christian Amend <ch...@sap.com>
Committed: Fri Dec 11 12:30:10 2015 +0100

----------------------------------------------------------------------
 .../core/uri/UriResourceLambdaAllImpl.java      |  11 +-
 .../core/uri/UriResourceLambdaAnyImpl.java      |  11 +-
 .../core/uri/UriResourceLambdaVarImpl.java      |   4 +-
 .../core/uri/expression/FilterParser.java       | 562 ------------------
 .../core/uri/parser/ExpressionParser.java       | 575 +++++++++++++++++++
 .../core/uri/parser/UriParseTreeVisitor.java    | 498 ++++++----------
 .../core/uri/queryoption/OrderByItemImpl.java   |   8 +-
 .../uri/queryoption/expression/AliasImpl.java   |  14 +-
 .../uri/queryoption/expression/BinaryImpl.java  |  34 +-
 .../queryoption/expression/EnumerationImpl.java |  28 +-
 .../queryoption/expression/ExpressionImpl.java  |  25 -
 .../queryoption/expression/LambdaRefImpl.java   |  14 +-
 .../uri/queryoption/expression/LiteralImpl.java |  25 +-
 .../uri/queryoption/expression/MemberImpl.java  |  28 +-
 .../uri/queryoption/expression/MethodImpl.java  |  52 +-
 .../queryoption/expression/TypeLiteralImpl.java |  14 +-
 .../uri/queryoption/expression/UnaryImpl.java   |  23 +-
 .../core/uri/expression/FilterParserTest.java   | 210 -------
 .../core/uri/parser/ExpressionParserTest.java   | 210 +++++++
 .../server/core/uri/UriResourceImplTest.java    |   8 +-
 .../core/uri/queryoption/QueryOptionTest.java   |   6 +-
 .../queryoption/expression/ExpressionTest.java  | 103 ++--
 22 files changed, 1095 insertions(+), 1368 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/208f26c7/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceLambdaAllImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceLambdaAllImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceLambdaAllImpl.java
index b57d12c..d980777 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceLambdaAllImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceLambdaAllImpl.java
@@ -25,15 +25,12 @@ import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
 import org.apache.olingo.server.api.uri.UriResourceKind;
 import org.apache.olingo.server.api.uri.UriResourceLambdaAll;
 import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
-import org.apache.olingo.server.core.uri.queryoption.expression.ExpressionImpl;
 
 public class UriResourceLambdaAllImpl extends UriResourceTypedImpl implements UriResourceLambdaAll {
 
   protected EdmProperty property;
-
   private String lambdaVariable;
-
-  private ExpressionImpl expression;
+  private Expression expression;
 
   public UriResourceLambdaAllImpl() {
     super(UriResourceKind.lambdaAll);
@@ -64,13 +61,13 @@ public class UriResourceLambdaAllImpl extends UriResourceTypedImpl implements Ur
     return expression;
   }
 
-  public UriResourceLambdaAllImpl setExpression(final ExpressionImpl expression) {
+  public UriResourceLambdaAllImpl setExpression(final Expression expression) {
     this.expression = expression;
     return this;
   }
-  
+
   @Override
-  public String getSegmentValue(){
+  public String getSegmentValue() {
     return "all";
   }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/208f26c7/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceLambdaAnyImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceLambdaAnyImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceLambdaAnyImpl.java
index 49be2fe..fe5dfee 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceLambdaAnyImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceLambdaAnyImpl.java
@@ -25,15 +25,12 @@ import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
 import org.apache.olingo.server.api.uri.UriResourceKind;
 import org.apache.olingo.server.api.uri.UriResourceLambdaAny;
 import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
-import org.apache.olingo.server.core.uri.queryoption.expression.ExpressionImpl;
 
 public class UriResourceLambdaAnyImpl extends UriResourceTypedImpl implements UriResourceLambdaAny {
 
   protected EdmProperty property;
-
   private String lambdaVariable;
-
-  private ExpressionImpl expression;
+  private Expression expression;
 
   public UriResourceLambdaAnyImpl() {
     super(UriResourceKind.lambdaAny);
@@ -64,13 +61,13 @@ public class UriResourceLambdaAnyImpl extends UriResourceTypedImpl implements Ur
     return expression;
   }
 
-  public UriResourceLambdaAnyImpl setExpression(final ExpressionImpl expression) {
+  public UriResourceLambdaAnyImpl setExpression(final Expression expression) {
     this.expression = expression;
     return this;
   }
-  
+
   @Override
-  public String getSegmentValue(){
+  public String getSegmentValue() {
     return "any";
   }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/208f26c7/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceLambdaVarImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceLambdaVarImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceLambdaVarImpl.java
index f7fa6fc..2eb7607 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceLambdaVarImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceLambdaVarImpl.java
@@ -64,10 +64,10 @@ public class UriResourceLambdaVarImpl extends UriResourceTypedImpl implements Ur
   }
 
   @Override
-  public String getSegmentValue(){
+  public String getSegmentValue() {
     return variableText;
   }
-  
+
   @Override
   public String toString() {
     return getSegmentValue();

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/208f26c7/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/expression/FilterParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/expression/FilterParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/expression/FilterParser.java
deleted file mode 100644
index 32cbc1a..0000000
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/expression/FilterParser.java
+++ /dev/null
@@ -1,562 +0,0 @@
-/*
- * 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.expression;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
-import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
-import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
-import org.apache.olingo.server.api.uri.queryoption.expression.BinaryOperatorKind;
-import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
-import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind;
-import org.apache.olingo.server.api.uri.queryoption.expression.UnaryOperatorKind;
-import org.apache.olingo.server.core.uri.queryoption.expression.AliasImpl;
-import org.apache.olingo.server.core.uri.queryoption.expression.BinaryImpl;
-import org.apache.olingo.server.core.uri.queryoption.expression.ExpressionImpl;
-import org.apache.olingo.server.core.uri.queryoption.expression.LiteralImpl;
-import org.apache.olingo.server.core.uri.queryoption.expression.MethodImpl;
-import org.apache.olingo.server.core.uri.queryoption.expression.UnaryImpl;
-
-public class FilterParser {
-  private Tokenizer tokenizer;
-
-  private static final Map<TokenKind, BinaryOperatorKind> tokenToBinaryOperator;
-  static {
-    HashMap<TokenKind, BinaryOperatorKind> temp = new HashMap<FilterParser.TokenKind, BinaryOperatorKind>();
-    temp.put(TokenKind.OR_OP, BinaryOperatorKind.OR);
-    temp.put(TokenKind.AND_OP, BinaryOperatorKind.AND);
-
-    temp.put(TokenKind.EQ_OP, BinaryOperatorKind.EQ);
-    temp.put(TokenKind.NE_OP, BinaryOperatorKind.NE);
-
-    temp.put(TokenKind.GT_OP, BinaryOperatorKind.GT);
-    temp.put(TokenKind.GE_OP, BinaryOperatorKind.GE);
-    temp.put(TokenKind.LT_OP, BinaryOperatorKind.LT);
-    temp.put(TokenKind.LE_OP, BinaryOperatorKind.LE);
-
-    temp.put(TokenKind.ADD_OP, BinaryOperatorKind.ADD);
-    temp.put(TokenKind.SUB_OP, BinaryOperatorKind.SUB);
-
-    temp.put(TokenKind.MUL_OP, BinaryOperatorKind.MUL);
-    temp.put(TokenKind.DIV_OP, BinaryOperatorKind.DIV);
-    temp.put(TokenKind.MOD_OP, BinaryOperatorKind.MOD);
-
-    tokenToBinaryOperator = Collections.unmodifiableMap(temp);
-  }
-
-  private static final Map<TokenKind, UnaryOperatorKind> tokenToUnaryOperator;
-  static {
-    HashMap<TokenKind, UnaryOperatorKind> temp = new HashMap<FilterParser.TokenKind, UnaryOperatorKind>();
-    temp.put(TokenKind.MINUS, UnaryOperatorKind.MINUS);
-    temp.put(TokenKind.NOT, UnaryOperatorKind.NOT);
-    tokenToUnaryOperator = Collections.unmodifiableMap(temp);
-  }
-
-  private static final Map<TokenKind, MethodKind> tokenToMethod;
-  static {
-    HashMap<TokenKind, MethodKind> temp = new HashMap<FilterParser.TokenKind, MethodKind>();
-    temp.put(TokenKind.Cast, MethodKind.CAST);
-    temp.put(TokenKind.Ceiling, MethodKind.CEILING);
-    temp.put(TokenKind.Concat, MethodKind.CONCAT);
-    temp.put(TokenKind.Contains, MethodKind.CONTAINS);
-    temp.put(TokenKind.Date, MethodKind.DATE);
-    temp.put(TokenKind.Day, MethodKind.DAY);
-    temp.put(TokenKind.Endswith, MethodKind.ENDSWITH);
-    temp.put(TokenKind.Floor, MethodKind.FLOOR);
-    temp.put(TokenKind.Fractionalseconds, MethodKind.FRACTIONALSECONDS);
-    temp.put(TokenKind.GeoDistance, MethodKind.GEODISTANCE);
-    temp.put(TokenKind.GeoIntersects, MethodKind.GEOINTERSECTS);
-    temp.put(TokenKind.GeoLength, MethodKind.GEOLENGTH);
-    temp.put(TokenKind.Hour, MethodKind.HOUR);
-    temp.put(TokenKind.Indexof, MethodKind.INDEXOF);
-    temp.put(TokenKind.Isof, MethodKind.ISOF);
-    temp.put(TokenKind.Length, MethodKind.LENGTH);
-    temp.put(TokenKind.Maxdatetime, MethodKind.MAXDATETIME);
-    temp.put(TokenKind.Mindatetime, MethodKind.MINDATETIME);
-    temp.put(TokenKind.Minute, MethodKind.MINUTE);
-    temp.put(TokenKind.Month, MethodKind.MONTH);
-    temp.put(TokenKind.Now, MethodKind.NOW);
-    temp.put(TokenKind.Round, MethodKind.ROUND);
-    temp.put(TokenKind.Second, MethodKind.SECOND);
-    temp.put(TokenKind.Startswith, MethodKind.STARTSWITH);
-    temp.put(TokenKind.Substring, MethodKind.SUBSTRING);
-    temp.put(TokenKind.Time, MethodKind.TIME);
-    temp.put(TokenKind.Tolower, MethodKind.TOLOWER);
-    temp.put(TokenKind.Totaloffsetminutes, MethodKind.TOTALOFFSETMINUTES);
-    temp.put(TokenKind.Totalseconds, MethodKind.TOTALSECONDS);
-    temp.put(TokenKind.Toupper, MethodKind.TOUPPER);
-    temp.put(TokenKind.Trim, MethodKind.TRIM);
-    temp.put(TokenKind.Year, MethodKind.YEAR);
-
-    tokenToMethod = Collections.unmodifiableMap(temp);
-  }
-
-  private static final Map<TokenKind, EdmPrimitiveTypeKind> tokenToPrimitiveType;
-  static {
-    /* Enum and null are not present in the map. These have to be handled differently */
-    HashMap<TokenKind, EdmPrimitiveTypeKind> temp = new HashMap<FilterParser.TokenKind, EdmPrimitiveTypeKind>();
-    temp.put(TokenKind.PrimitiveBooleanValue, EdmPrimitiveTypeKind.Boolean);
-    temp.put(TokenKind.PrimitiveStringValue, EdmPrimitiveTypeKind.String);
-    // TODO:Check if int64 is correct here or if it has to be single instead
-    temp.put(TokenKind.PrimitiveIntegerValue, EdmPrimitiveTypeKind.Int64);
-    temp.put(TokenKind.PrimitiveGuidValue, EdmPrimitiveTypeKind.Guid);
-    temp.put(TokenKind.PrimitiveDateValue, EdmPrimitiveTypeKind.Date);
-    temp.put(TokenKind.PrimitiveDateTimeOffsetValue, EdmPrimitiveTypeKind.DateTimeOffset);
-    temp.put(TokenKind.PrimitiveTimeOfDayValue, EdmPrimitiveTypeKind.TimeOfDay);
-    temp.put(TokenKind.PrimitiveDecimalValue, EdmPrimitiveTypeKind.Decimal);
-    temp.put(TokenKind.PrimitiveDoubleValue, EdmPrimitiveTypeKind.Double);
-    temp.put(TokenKind.PrimitiveDurationValue, EdmPrimitiveTypeKind.Duration);
-    temp.put(TokenKind.PrimitiveBinaryValue, EdmPrimitiveTypeKind.Binary);
-
-    tokenToPrimitiveType = Collections.unmodifiableMap(temp);
-  }
-
-  public Expression parse(Tokenizer tokenizer) {
-    // Initialize tokenizer
-    this.tokenizer = tokenizer;
-
-    Expression exp = parseExpression();
-    return exp;
-  }
-
-  private Expression parseExpression() {
-    Expression left = parseAnd();
-
-    while (is(TokenKind.OR_OP) != null) {
-      tokenizer.getText();
-
-      Expression right = parseAnd();
-      left = new BinaryImpl(left, BinaryOperatorKind.OR, right);
-    }
-
-    return left;
-  }
-
-  private Expression parseAnd() {
-    Expression left = parseExprEquality();
-    while (is(TokenKind.AND_OP) != null) {
-      tokenizer.getText();
-
-      Expression right = parseExprEquality();
-      left = new BinaryImpl(left, BinaryOperatorKind.AND, right);
-    }
-    return left;
-  }
-
-  private Expression parseExprEquality() {
-    Expression left = parseExprRel();
-
-    TokenKind nextTokenKind = is(TokenKind.EQ_OP, TokenKind.NE_OP);
-    // Null for everything other than EQ or NE
-    while (nextTokenKind != null) {
-      tokenizer.getText();
-
-      Expression right = parseExprEquality();
-      left = new BinaryImpl(left, tokenToBinaryOperator.get(nextTokenKind), right);
-      nextTokenKind = is(TokenKind.EQ_OP, TokenKind.NE_OP);
-    }
-
-    return left;
-  }
-
-  private Expression parseExprRel() {
-    Expression left = parseExprAdd();
-
-    TokenKind nextTokenKind = is(TokenKind.GT_OP, TokenKind.GE_OP, TokenKind.LT_OP, TokenKind.LE_OP);
-    // Null for everything other than GT or GE or LT or LE
-    while (nextTokenKind != null) {
-      tokenizer.getText();
-
-      Expression right = parseExprAdd();
-      left = new BinaryImpl(left, tokenToBinaryOperator.get(nextTokenKind), right);
-      nextTokenKind = is(TokenKind.GT_OP, TokenKind.GE_OP, TokenKind.LT_OP, TokenKind.LE_OP);
-    }
-
-    return left;
-  }
-
-  private Expression parseExprAdd() {
-    Expression left = parseExprMul();
-
-    TokenKind nextTokenKind = is(TokenKind.ADD_OP, TokenKind.SUB_OP);
-    // Null for everything other than ADD or SUB
-    while (nextTokenKind != null) {
-      tokenizer.getText();
-
-      Expression right = parseExprMul();
-      left = new BinaryImpl(left, tokenToBinaryOperator.get(nextTokenKind), right);
-      nextTokenKind = is(TokenKind.ADD_OP, TokenKind.SUB_OP);
-    }
-
-    return left;
-  }
-
-  private Expression parseExprMul() {
-    Expression left = parseExprUnary();
-
-    TokenKind nextTokenKind = is(TokenKind.MUL_OP, TokenKind.DIV_OP, TokenKind.MOD_OP);
-    // Null for everything other than MUL or DIV or MOD
-    while (nextTokenKind != null) {
-      tokenizer.getText();
-
-      Expression right = parseExprUnary();
-      left = new BinaryImpl(left, tokenToBinaryOperator.get(nextTokenKind), right);
-      nextTokenKind = is(TokenKind.MUL_OP, TokenKind.DIV_OP, TokenKind.MOD_OP);
-    }
-
-    return left;
-  }
-
-  private Expression parseExprUnary() {
-    Expression left = null;
-    TokenKind nextTokenKind = is(TokenKind.MINUS, TokenKind.NOT);
-    // Null for everything other than - or NOT
-    while (nextTokenKind != null) {
-      tokenizer.getText();
-
-      Expression exp = parseExprValue();
-      left = new UnaryImpl(tokenToUnaryOperator.get(nextTokenKind), exp);
-      nextTokenKind = is(TokenKind.MINUS, TokenKind.NOT);
-    }
-
-    if (left == null) {
-      left = parseExprValue();
-    }
-
-    return left;
-  }
-
-  private Expression parseExprValue() {
-    if (is(TokenKind.OPEN) != null) {
-      tokenizer.getText();
-      Expression exp = parseExpression();
-      require(TokenKind.CLOSE);
-      return exp;
-    }
-
-    if (is(TokenKind.ParameterAlias) != null) {
-      return new AliasImpl(tokenizer.getText());
-    }
-
-    if (is(TokenKind.RootExpr) != null) {
-      tokenizer.getText();
-      // TODO: ConsumeRootExpression
-    }
-
-    TokenKind nextPrimitive = isPrimitive();
-    if (nextPrimitive != null) {
-      EdmPrimitiveTypeKind primitiveTypeKind = tokenToPrimitiveType.get(nextPrimitive);
-      EdmPrimitiveType type;
-      if (primitiveTypeKind == null) {
-        if (nextPrimitive == TokenKind.PrimitiveEnumValue) {
-          // TODO: Get enum type
-          type = null;
-        } else {
-          // Null handling
-          type = null;
-        }
-      } else {
-        type = EdmPrimitiveTypeFactory.getInstance(primitiveTypeKind);
-      }
-      return new LiteralImpl(tokenizer.getText(), type);
-    }
-
-    TokenKind nextMethod = isMethod();
-    if (nextMethod != null) {
-      MethodImpl methodImpl = new MethodImpl(tokenToMethod.get(nextMethod));
-      // Consume Method
-      tokenizer.getText();
-      if (is(TokenKind.CLOSE) != null) {
-        // Consume closing bracket
-        tokenizer.getText();
-      } else {
-        // TODO: Remove Cast
-        methodImpl.addParameter((ExpressionImpl) parseExpression());
-        while (is(TokenKind.COMMA) != null) {
-          tokenizer.getText();
-          methodImpl.addParameter((ExpressionImpl) parseExpression());
-        }
-        require(TokenKind.CLOSE);
-      }
-
-      validateMethodParameters(methodImpl);
-
-      return methodImpl;
-    }
-
-    throw new RuntimeException("Unexpected token");
-  }
-
-  private void validateMethodParameters(MethodImpl methodImpl) {
-    // We might validate parameter types in the future
-    int size = methodImpl.getParameters().size();
-    switch (methodImpl.getMethod()) {
-    // Must have two Parameters
-    case CONTAINS:
-    case ENDSWITH:
-    case STARTSWITH:
-    case INDEXOF:
-    case CONCAT:
-    case GEODISTANCE:
-    case GEOINTERSECTS:
-      if (size != 2) {
-        throw new RuntimeException("The method " + methodImpl.getMethod() + " needs exactly two parameters.");
-      }
-      break;
-    // Must have one parameter
-    case LENGTH:
-    case TOLOWER:
-    case TOUPPER:
-    case TRIM:
-    case YEAR:
-    case MONTH:
-    case DAY:
-    case HOUR:
-    case MINUTE:
-    case SECOND:
-    case FRACTIONALSECONDS:
-    case DATE:
-    case TIME:
-    case TOTALOFFSETMINUTES:
-    case TOTALSECONDS:
-    case ROUND:
-    case FLOOR:
-    case CEILING:
-    case GEOLENGTH:
-      if (size != 1) {
-        throw new RuntimeException("The method: '" + methodImpl.getMethod() + "' needs exactly one parameter.");
-      }
-      break;
-    // Must have no parameter
-    case NOW:
-    case MAXDATETIME:
-    case MINDATETIME:
-      if (size != 0) {
-        throw new RuntimeException("The method: '" + methodImpl.getMethod() + "' must have no parameters.");
-      }
-      break;
-    // Variable parameter number
-    case CAST:
-    case ISOF:
-      if (size == 1 || size == 2) {
-        throw new RuntimeException("The method: '" + methodImpl.getMethod() + "' must have one or two parameters.");
-      }
-      break;
-    case SUBSTRING:
-      if (size == 2 || size == 3) {
-        throw new RuntimeException("The method: '" + methodImpl.getMethod() + "' must have two or three parameters.");
-      }
-      break;
-    default:
-      throw new RuntimeException("Unkown method: '" + methodImpl.getMethod() + "'");
-    }
-  }
-
-  private String require(TokenKind required) {
-    if (is(required) == null) {
-      throw new RuntimeException("Requred token: " + required);
-    }
-    return tokenizer.getText();
-  }
-
-  private TokenKind is(TokenKind... kind) {
-    for (int i = 0; i < kind.length; i++) {
-      if (tokenizer.next(kind[i])) {
-        return kind[i];
-      }
-    }
-    return null;
-  }
-
-  private TokenKind isMethod() {
-    return is(TokenKind.Cast,
-        TokenKind.Ceiling,
-        TokenKind.Concat,
-        TokenKind.Contains,
-        TokenKind.Date,
-        TokenKind.Day,
-        TokenKind.Endswith,
-        TokenKind.Floor,
-        TokenKind.Fractionalseconds,
-        TokenKind.GeoDistance,
-        TokenKind.GeoIntersects,
-        TokenKind.GeoLength,
-        TokenKind.Hour,
-        TokenKind.Indexof,
-        TokenKind.Isof,
-        TokenKind.Length,
-        TokenKind.Maxdatetime,
-        TokenKind.Mindatetime,
-        TokenKind.Minute,
-        TokenKind.Month,
-        TokenKind.Now,
-        TokenKind.Round,
-        TokenKind.Second,
-        TokenKind.Startswith,
-        TokenKind.Substring,
-        TokenKind.Time,
-        TokenKind.Tolower,
-        TokenKind.Totaloffsetminutes,
-        TokenKind.Totalseconds,
-        TokenKind.Toupper,
-        TokenKind.Trim,
-        TokenKind.Year);
-  }
-
-  private TokenKind isPrimitive() {
-    return is(TokenKind.PrimitiveNullValue,
-        TokenKind.PrimitiveBooleanValue,
-        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 ...).
-        TokenKind.PrimitiveDoubleValue,
-        TokenKind.PrimitiveDecimalValue,
-        TokenKind.PrimitiveGuidValue,
-        TokenKind.PrimitiveDateTimeOffsetValue,
-        TokenKind.PrimitiveDateValue,
-        TokenKind.PrimitiveTimeOfDayValue,
-        TokenKind.PrimitiveIntegerValue,
-        TokenKind.PrimitiveDurationValue,
-        TokenKind.PrimitiveBinaryValue,
-        TokenKind.PrimitiveEnumValue);
-  }
-
-  public enum TokenKind {
-    // BINARY
-    OR_OP,
-    AND_OP,
-
-    EQ_OP,
-    NE_OP,
-
-    GT_OP,
-    GE_OP,
-    LT_OP,
-    LE_OP,
-
-    ADD_OP,
-    SUB_OP,
-
-    MUL_OP,
-    DIV_OP,
-    MOD_OP,
-
-    MINUS,
-    NOT,
-
-    // Grouping
-    OPEN,
-    CLOSE,
-
-    // PrimitiveValues
-    PrimitiveNullValue,
-    PrimitiveBooleanValue,
-
-    PrimitiveStringValue,
-    PrimitiveIntegerValue,
-    PrimitiveGuidValue,
-    PrimitiveDateValue,
-    PrimitiveDateTimeOffsetValue,
-    PrimitiveTimeOfDayValue,
-    PrimitiveDecimalValue,
-    PrimitiveDoubleValue,
-    PrimitiveDurationValue,
-    PrimitiveBinaryValue,
-    PrimitiveEnumValue,
-
-    // ExpressionValues
-    ParameterAlias,
-    ArrayOrObject,
-    RootExpr,
-    IT,
-
-    // BuiltInMethods
-    Cast,
-    Ceiling,
-    Concat,
-    Contains,
-    Date,
-    Day,
-    Endswith,
-    Floor,
-    Fractionalseconds,
-    GeoDistance,
-    GeoIntersects,
-    GeoLength,
-    Hour,
-    Indexof,
-    Isof,
-    Length,
-    Maxdatetime,
-    Mindatetime,
-    Minute,
-    Month,
-    Now,
-    Round,
-    Second,
-    Startswith,
-    Substring,
-    Time,
-    Tolower,
-    Totaloffsetminutes,
-    Totalseconds,
-    Toupper,
-    Trim,
-    Year,
-    COMMA
-  }
-
-  public static class Token {
-    TokenKind kind;
-    String text;
-
-    public Token(TokenKind kind, String text) {
-      this.kind = kind;
-      this.text = text;
-    }
-  }
-
-  public static class Tokenizer {
-    private List<Token> tokens;
-    int counter = 0;
-
-    public Tokenizer(List<Token> tokens) {
-      this.tokens = tokens;
-    }
-
-    public boolean next(TokenKind expectedKind) {
-      if (counter < tokens.size() && expectedKind == tokens.get(counter).kind) {
-        return true;
-      }
-      return false;
-    }
-
-    public String getText() {
-      String text = tokens.get(counter).text;
-      counter++;
-      return text;
-    }
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/208f26c7/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java
new file mode 100644
index 0000000..854536d
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java
@@ -0,0 +1,575 @@
+/*
+ * 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.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
+import org.apache.olingo.server.api.uri.queryoption.expression.BinaryOperatorKind;
+import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
+import org.apache.olingo.server.api.uri.queryoption.expression.Method;
+import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind;
+import org.apache.olingo.server.api.uri.queryoption.expression.UnaryOperatorKind;
+import org.apache.olingo.server.core.uri.queryoption.expression.AliasImpl;
+import org.apache.olingo.server.core.uri.queryoption.expression.BinaryImpl;
+import org.apache.olingo.server.core.uri.queryoption.expression.LiteralImpl;
+import org.apache.olingo.server.core.uri.queryoption.expression.MethodImpl;
+import org.apache.olingo.server.core.uri.queryoption.expression.UnaryImpl;
+
+public class ExpressionParser {
+  private Tokenizer tokenizer;
+
+  private static final Map<TokenKind, BinaryOperatorKind> tokenToBinaryOperator;
+  static {
+    Map<TokenKind, BinaryOperatorKind> temp = new HashMap<ExpressionParser.TokenKind, BinaryOperatorKind>();
+    temp.put(TokenKind.OR_OP, BinaryOperatorKind.OR);
+    temp.put(TokenKind.AND_OP, BinaryOperatorKind.AND);
+
+    temp.put(TokenKind.EQ_OP, BinaryOperatorKind.EQ);
+    temp.put(TokenKind.NE_OP, BinaryOperatorKind.NE);
+
+    temp.put(TokenKind.GT_OP, BinaryOperatorKind.GT);
+    temp.put(TokenKind.GE_OP, BinaryOperatorKind.GE);
+    temp.put(TokenKind.LT_OP, BinaryOperatorKind.LT);
+    temp.put(TokenKind.LE_OP, BinaryOperatorKind.LE);
+
+    temp.put(TokenKind.ADD_OP, BinaryOperatorKind.ADD);
+    temp.put(TokenKind.SUB_OP, BinaryOperatorKind.SUB);
+
+    temp.put(TokenKind.MUL_OP, BinaryOperatorKind.MUL);
+    temp.put(TokenKind.DIV_OP, BinaryOperatorKind.DIV);
+    temp.put(TokenKind.MOD_OP, BinaryOperatorKind.MOD);
+
+    tokenToBinaryOperator = Collections.unmodifiableMap(temp);
+  }
+
+  private static final Map<TokenKind, UnaryOperatorKind> tokenToUnaryOperator;
+  static {
+    Map<TokenKind, UnaryOperatorKind> temp = new HashMap<ExpressionParser.TokenKind, UnaryOperatorKind>();
+    temp.put(TokenKind.MINUS, UnaryOperatorKind.MINUS);
+    temp.put(TokenKind.NOT, UnaryOperatorKind.NOT);
+    tokenToUnaryOperator = Collections.unmodifiableMap(temp);
+  }
+
+  private static final Map<TokenKind, MethodKind> tokenToMethod;
+  static {
+    Map<TokenKind, MethodKind> temp = new HashMap<ExpressionParser.TokenKind, MethodKind>();
+    temp.put(TokenKind.Cast, MethodKind.CAST);
+    temp.put(TokenKind.Ceiling, MethodKind.CEILING);
+    temp.put(TokenKind.Concat, MethodKind.CONCAT);
+    temp.put(TokenKind.Contains, MethodKind.CONTAINS);
+    temp.put(TokenKind.Date, MethodKind.DATE);
+    temp.put(TokenKind.Day, MethodKind.DAY);
+    temp.put(TokenKind.Endswith, MethodKind.ENDSWITH);
+    temp.put(TokenKind.Floor, MethodKind.FLOOR);
+    temp.put(TokenKind.Fractionalseconds, MethodKind.FRACTIONALSECONDS);
+    temp.put(TokenKind.GeoDistance, MethodKind.GEODISTANCE);
+    temp.put(TokenKind.GeoIntersects, MethodKind.GEOINTERSECTS);
+    temp.put(TokenKind.GeoLength, MethodKind.GEOLENGTH);
+    temp.put(TokenKind.Hour, MethodKind.HOUR);
+    temp.put(TokenKind.Indexof, MethodKind.INDEXOF);
+    temp.put(TokenKind.Isof, MethodKind.ISOF);
+    temp.put(TokenKind.Length, MethodKind.LENGTH);
+    temp.put(TokenKind.Maxdatetime, MethodKind.MAXDATETIME);
+    temp.put(TokenKind.Mindatetime, MethodKind.MINDATETIME);
+    temp.put(TokenKind.Minute, MethodKind.MINUTE);
+    temp.put(TokenKind.Month, MethodKind.MONTH);
+    temp.put(TokenKind.Now, MethodKind.NOW);
+    temp.put(TokenKind.Round, MethodKind.ROUND);
+    temp.put(TokenKind.Second, MethodKind.SECOND);
+    temp.put(TokenKind.Startswith, MethodKind.STARTSWITH);
+    temp.put(TokenKind.Substring, MethodKind.SUBSTRING);
+    temp.put(TokenKind.Time, MethodKind.TIME);
+    temp.put(TokenKind.Tolower, MethodKind.TOLOWER);
+    temp.put(TokenKind.Totaloffsetminutes, MethodKind.TOTALOFFSETMINUTES);
+    temp.put(TokenKind.Totalseconds, MethodKind.TOTALSECONDS);
+    temp.put(TokenKind.Toupper, MethodKind.TOUPPER);
+    temp.put(TokenKind.Trim, MethodKind.TRIM);
+    temp.put(TokenKind.Year, MethodKind.YEAR);
+
+    tokenToMethod = Collections.unmodifiableMap(temp);
+  }
+
+  private static final Map<TokenKind, EdmPrimitiveTypeKind> tokenToPrimitiveType;
+  static {
+    /* Enum and null are not present in the map. These have to be handled differently */
+    Map<TokenKind, EdmPrimitiveTypeKind> temp = new HashMap<ExpressionParser.TokenKind, EdmPrimitiveTypeKind>();
+    temp.put(TokenKind.PrimitiveBooleanValue, EdmPrimitiveTypeKind.Boolean);
+    temp.put(TokenKind.PrimitiveStringValue, EdmPrimitiveTypeKind.String);
+    // TODO:Check if int64 is correct here or if it has to be single instead
+    temp.put(TokenKind.PrimitiveIntegerValue, EdmPrimitiveTypeKind.Int64);
+    temp.put(TokenKind.PrimitiveGuidValue, EdmPrimitiveTypeKind.Guid);
+    temp.put(TokenKind.PrimitiveDateValue, EdmPrimitiveTypeKind.Date);
+    temp.put(TokenKind.PrimitiveDateTimeOffsetValue, EdmPrimitiveTypeKind.DateTimeOffset);
+    temp.put(TokenKind.PrimitiveTimeOfDayValue, EdmPrimitiveTypeKind.TimeOfDay);
+    temp.put(TokenKind.PrimitiveDecimalValue, EdmPrimitiveTypeKind.Decimal);
+    temp.put(TokenKind.PrimitiveDoubleValue, EdmPrimitiveTypeKind.Double);
+    temp.put(TokenKind.PrimitiveDurationValue, EdmPrimitiveTypeKind.Duration);
+    temp.put(TokenKind.PrimitiveBinaryValue, EdmPrimitiveTypeKind.Binary);
+
+    tokenToPrimitiveType = Collections.unmodifiableMap(temp);
+  }
+
+  public Expression parse(Tokenizer tokenizer) throws UriParserException {
+    // Initialize tokenizer.
+    this.tokenizer = tokenizer;
+
+    return parseExpression();
+  }
+
+  private Expression parseExpression() throws UriParserException {
+    Expression left = parseAnd();
+
+    while (is(TokenKind.OR_OP) != null) {
+      tokenizer.getText();
+
+      Expression right = parseAnd();
+      left = new BinaryImpl(left, BinaryOperatorKind.OR, right);
+    }
+
+    return left;
+  }
+
+  private Expression parseAnd() throws UriParserException {
+    Expression left = parseExprEquality();
+    while (is(TokenKind.AND_OP) != null) {
+      tokenizer.getText();
+
+      Expression right = parseExprEquality();
+      left = new BinaryImpl(left, BinaryOperatorKind.AND, right);
+    }
+    return left;
+  }
+
+  private Expression parseExprEquality() throws UriParserException {
+    Expression left = parseExprRel();
+
+    TokenKind nextTokenKind = is(TokenKind.EQ_OP, TokenKind.NE_OP);
+    // Null for everything other than EQ or NE
+    while (nextTokenKind != null) {
+      tokenizer.getText();
+
+      Expression right = parseExprEquality();
+      left = new BinaryImpl(left, tokenToBinaryOperator.get(nextTokenKind), right);
+      nextTokenKind = is(TokenKind.EQ_OP, TokenKind.NE_OP);
+    }
+
+    return left;
+  }
+
+  private Expression parseExprRel() throws UriParserException {
+    Expression left = parseExprAdd();
+
+    TokenKind nextTokenKind = is(TokenKind.GT_OP, TokenKind.GE_OP, TokenKind.LT_OP, TokenKind.LE_OP);
+    // Null for everything other than GT or GE or LT or LE
+    while (nextTokenKind != null) {
+      tokenizer.getText();
+
+      Expression right = parseExprAdd();
+      left = new BinaryImpl(left, tokenToBinaryOperator.get(nextTokenKind), right);
+      nextTokenKind = is(TokenKind.GT_OP, TokenKind.GE_OP, TokenKind.LT_OP, TokenKind.LE_OP);
+    }
+
+    return left;
+  }
+
+  private Expression parseExprAdd() throws UriParserException {
+    Expression left = parseExprMul();
+
+    TokenKind nextTokenKind = is(TokenKind.ADD_OP, TokenKind.SUB_OP);
+    // Null for everything other than ADD or SUB
+    while (nextTokenKind != null) {
+      tokenizer.getText();
+
+      Expression right = parseExprMul();
+      left = new BinaryImpl(left, tokenToBinaryOperator.get(nextTokenKind), right);
+      nextTokenKind = is(TokenKind.ADD_OP, TokenKind.SUB_OP);
+    }
+
+    return left;
+  }
+
+  private Expression parseExprMul() throws UriParserException {
+    Expression left = parseExprUnary();
+
+    TokenKind nextTokenKind = is(TokenKind.MUL_OP, TokenKind.DIV_OP, TokenKind.MOD_OP);
+    // Null for everything other than MUL or DIV or MOD
+    while (nextTokenKind != null) {
+      tokenizer.getText();
+
+      Expression right = parseExprUnary();
+      left = new BinaryImpl(left, tokenToBinaryOperator.get(nextTokenKind), right);
+      nextTokenKind = is(TokenKind.MUL_OP, TokenKind.DIV_OP, TokenKind.MOD_OP);
+    }
+
+    return left;
+  }
+
+  private Expression parseExprUnary() throws UriParserException {
+    Expression left = null;
+    TokenKind nextTokenKind = is(TokenKind.MINUS, TokenKind.NOT);
+    // Null for everything other than - or NOT
+    while (nextTokenKind != null) {
+      tokenizer.getText();
+
+      Expression exp = parseExprValue();
+      left = new UnaryImpl(tokenToUnaryOperator.get(nextTokenKind), exp);
+      nextTokenKind = is(TokenKind.MINUS, TokenKind.NOT);
+    }
+
+    if (left == null) {
+      left = parseExprValue();
+    }
+
+    return left;
+  }
+
+  private Expression parseExprValue() throws UriParserException {
+    if (is(TokenKind.OPEN) != null) {
+      tokenizer.getText();
+      Expression exp = parseExpression();
+      require(TokenKind.CLOSE);
+      return exp;
+    }
+
+    if (is(TokenKind.ParameterAlias) != null) {
+      return new AliasImpl(tokenizer.getText());
+    }
+
+    if (is(TokenKind.RootExpr) != null) {
+      tokenizer.getText();
+      // TODO: Consume $root Expression.
+    }
+
+    TokenKind nextPrimitive = isPrimitive();
+    if (nextPrimitive != null) {
+      EdmPrimitiveTypeKind primitiveTypeKind = tokenToPrimitiveType.get(nextPrimitive);
+      EdmPrimitiveType type;
+      if (primitiveTypeKind == null) {
+        if (nextPrimitive == TokenKind.PrimitiveEnumValue) {
+          // TODO: Get enum type.
+          type = null;
+        } else {
+          // Null handling
+          type = null;
+        }
+      } else {
+        type = EdmPrimitiveTypeFactory.getInstance(primitiveTypeKind);
+      }
+      return new LiteralImpl(tokenizer.getText(), type);
+    }
+
+    TokenKind nextMethod = isMethod();
+    if (nextMethod != null) {
+      MethodKind methodKind = tokenToMethod.get(nextMethod);
+      List<Expression> parameters = new ArrayList<Expression>();
+      // Consume Method name.
+      tokenizer.getText();
+      if (is(TokenKind.CLOSE) != null) {
+        // Consume closing parenthesis.
+        tokenizer.getText();
+      } else {
+        parameters.add(parseExpression());
+        while (is(TokenKind.COMMA) != null) {
+          tokenizer.getText();
+          parameters.add(parseExpression());
+        }
+        require(TokenKind.CLOSE);
+      }
+
+      MethodImpl methodImpl = new MethodImpl(methodKind, parameters);
+      validateMethodParameters(methodImpl);
+
+      return methodImpl;
+    }
+
+    throw new UriParserSyntaxException("Unexpected token", UriParserSyntaxException.MessageKeys.SYNTAX);
+  }
+
+  private void validateMethodParameters(final Method method) throws UriParserException {
+    // We might validate parameter types in the future.
+    int size = method.getParameters().size();
+    switch (method.getMethod()) {
+    // Must have two Parameters.
+    case CONTAINS:
+    case ENDSWITH:
+    case STARTSWITH:
+    case INDEXOF:
+    case CONCAT:
+    case GEODISTANCE:
+    case GEOINTERSECTS:
+      if (size != 2) {
+        throw new UriParserSemanticException(
+            "The method " + method.getMethod() + " needs exactly two parameters.",
+            null); // TODO: message key
+      }
+      break;
+    // Must have one parameter.
+    case LENGTH:
+    case TOLOWER:
+    case TOUPPER:
+    case TRIM:
+    case YEAR:
+    case MONTH:
+    case DAY:
+    case HOUR:
+    case MINUTE:
+    case SECOND:
+    case FRACTIONALSECONDS:
+    case DATE:
+    case TIME:
+    case TOTALOFFSETMINUTES:
+    case TOTALSECONDS:
+    case ROUND:
+    case FLOOR:
+    case CEILING:
+    case GEOLENGTH:
+      if (size != 1) {
+        throw new UriParserSemanticException(
+            "The method '" + method.getMethod() + "' needs exactly one parameter.",
+            null); // TODO: message key
+      }
+      break;
+    // Must have no parameter.
+    case NOW:
+    case MAXDATETIME:
+    case MINDATETIME:
+      if (size != 0) {
+        throw new UriParserSemanticException("The method '" + method.getMethod() + "' must have no parameters.",
+            null); // TODO: message key
+      }
+      break;
+    // Variable parameter number
+    case CAST:
+    case ISOF:
+      if (size < 1 || size > 2) {
+        throw new UriParserSemanticException(
+            "The method '" + method.getMethod() + "' must have one or two parameters.",
+            null); // TODO: message key
+      }
+      break;
+    case SUBSTRING:
+      if (size < 2 || size > 3) {
+        throw new UriParserSemanticException(
+            "The method '" + method.getMethod() + "' must have two or three parameters.",
+            null); // TODO: message key
+      }
+      break;
+    default:
+      throw new UriParserSemanticException(
+          "Unkown method '" + method.getMethod() + "'",
+          null); // TODO: message key
+    }
+  }
+
+  private String require(TokenKind required) throws UriParserException {
+    if (is(required) == null) {
+      throw new UriParserSyntaxException("Required token: " + required,
+          UriParserSyntaxException.MessageKeys.SYNTAX);
+    }
+    return tokenizer.getText();
+  }
+
+  private TokenKind is(TokenKind... kind) {
+    for (int i = 0; i < kind.length; i++) {
+      if (tokenizer.next(kind[i])) {
+        return kind[i];
+      }
+    }
+    return null;
+  }
+
+  private TokenKind isMethod() {
+    return is(TokenKind.Cast,
+        TokenKind.Ceiling,
+        TokenKind.Concat,
+        TokenKind.Contains,
+        TokenKind.Date,
+        TokenKind.Day,
+        TokenKind.Endswith,
+        TokenKind.Floor,
+        TokenKind.Fractionalseconds,
+        TokenKind.GeoDistance,
+        TokenKind.GeoIntersects,
+        TokenKind.GeoLength,
+        TokenKind.Hour,
+        TokenKind.Indexof,
+        TokenKind.Isof,
+        TokenKind.Length,
+        TokenKind.Maxdatetime,
+        TokenKind.Mindatetime,
+        TokenKind.Minute,
+        TokenKind.Month,
+        TokenKind.Now,
+        TokenKind.Round,
+        TokenKind.Second,
+        TokenKind.Startswith,
+        TokenKind.Substring,
+        TokenKind.Time,
+        TokenKind.Tolower,
+        TokenKind.Totaloffsetminutes,
+        TokenKind.Totalseconds,
+        TokenKind.Toupper,
+        TokenKind.Trim,
+        TokenKind.Year);
+  }
+
+  private TokenKind isPrimitive() {
+    return is(TokenKind.PrimitiveNullValue,
+        TokenKind.PrimitiveBooleanValue,
+        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 ...).
+        TokenKind.PrimitiveDoubleValue,
+        TokenKind.PrimitiveDecimalValue,
+        TokenKind.PrimitiveGuidValue,
+        TokenKind.PrimitiveDateTimeOffsetValue,
+        TokenKind.PrimitiveDateValue,
+        TokenKind.PrimitiveTimeOfDayValue,
+        TokenKind.PrimitiveIntegerValue,
+        TokenKind.PrimitiveDurationValue,
+        TokenKind.PrimitiveBinaryValue,
+        TokenKind.PrimitiveEnumValue);
+  }
+
+  public enum TokenKind {
+    // BINARY
+    OR_OP,
+    AND_OP,
+
+    EQ_OP,
+    NE_OP,
+
+    GT_OP,
+    GE_OP,
+    LT_OP,
+    LE_OP,
+
+    ADD_OP,
+    SUB_OP,
+
+    MUL_OP,
+    DIV_OP,
+    MOD_OP,
+
+    MINUS,
+    NOT,
+
+    // Grouping
+    OPEN,
+    CLOSE,
+
+    // PrimitiveValues
+    PrimitiveNullValue,
+    PrimitiveBooleanValue,
+
+    PrimitiveStringValue,
+    PrimitiveIntegerValue,
+    PrimitiveGuidValue,
+    PrimitiveDateValue,
+    PrimitiveDateTimeOffsetValue,
+    PrimitiveTimeOfDayValue,
+    PrimitiveDecimalValue,
+    PrimitiveDoubleValue,
+    PrimitiveDurationValue,
+    PrimitiveBinaryValue,
+    PrimitiveEnumValue,
+
+    // ExpressionValues
+    ParameterAlias,
+    ArrayOrObject,
+    RootExpr,
+    IT,
+
+    // BuiltInMethods
+    Cast,
+    Ceiling,
+    Concat,
+    Contains,
+    Date,
+    Day,
+    Endswith,
+    Floor,
+    Fractionalseconds,
+    GeoDistance,
+    GeoIntersects,
+    GeoLength,
+    Hour,
+    Indexof,
+    Isof,
+    Length,
+    Maxdatetime,
+    Mindatetime,
+    Minute,
+    Month,
+    Now,
+    Round,
+    Second,
+    Startswith,
+    Substring,
+    Time,
+    Tolower,
+    Totaloffsetminutes,
+    Totalseconds,
+    Toupper,
+    Trim,
+    Year,
+    COMMA
+  }
+
+  public static class Token {
+    TokenKind kind;
+    String text;
+
+    public Token(TokenKind kind, String text) {
+      this.kind = kind;
+      this.text = text;
+    }
+  }
+
+  public static class Tokenizer {
+    private List<Token> tokens;
+    int counter = 0;
+
+    public Tokenizer(List<Token> tokens) {
+      this.tokens = tokens;
+    }
+
+    public boolean next(TokenKind expectedKind) {
+      if (counter < tokens.size() && expectedKind == tokens.get(counter).kind) {
+        return true;
+      }
+      return false;
+    }
+
+    public String getText() {
+      String text = tokens.get(counter).text;
+      counter++;
+      return text;
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/208f26c7/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 c58327b..3f7f70c 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
@@ -19,6 +19,7 @@
 package org.apache.olingo.server.core.uri.parser;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
@@ -59,6 +60,7 @@ import org.apache.olingo.server.api.uri.UriResourcePartTyped;
 import org.apache.olingo.server.api.uri.UriResourceRoot;
 import org.apache.olingo.server.api.uri.queryoption.SelectItem;
 import org.apache.olingo.server.api.uri.queryoption.expression.BinaryOperatorKind;
+import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
 import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind;
 import org.apache.olingo.server.api.uri.queryoption.expression.UnaryOperatorKind;
 import org.apache.olingo.server.core.uri.UriInfoImpl;
@@ -82,7 +84,9 @@ import org.apache.olingo.server.core.uri.UriResourceStartingTypeFilterImpl;
 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.antlr.*;
+import org.apache.olingo.server.core.uri.antlr.UriLexer;
+import org.apache.olingo.server.core.uri.antlr.UriParserBaseVisitor;
+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.AllExprContext;
 import org.apache.olingo.server.core.uri.antlr.UriParserParser.AltAddContext;
@@ -96,7 +100,6 @@ import org.apache.olingo.server.core.uri.antlr.UriParserParser.AltMultContext;
 import org.apache.olingo.server.core.uri.antlr.UriParserParser.AltOrContext;
 import org.apache.olingo.server.core.uri.antlr.UriParserParser.AnyExprContext;
 import org.apache.olingo.server.core.uri.antlr.UriParserParser.ArrayOrObjectContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.BatchEOFContext;
 import org.apache.olingo.server.core.uri.antlr.UriParserParser.BinaryLiteralContext;
 import org.apache.olingo.server.core.uri.antlr.UriParserParser.BooleanNonCaseLiteralContext;
 import org.apache.olingo.server.core.uri.antlr.UriParserParser.CastExprContext;
@@ -197,7 +200,6 @@ import org.apache.olingo.server.core.uri.queryoption.TopOptionImpl;
 import org.apache.olingo.server.core.uri.queryoption.expression.AliasImpl;
 import org.apache.olingo.server.core.uri.queryoption.expression.BinaryImpl;
 import org.apache.olingo.server.core.uri.queryoption.expression.EnumerationImpl;
-import org.apache.olingo.server.core.uri.queryoption.expression.ExpressionImpl;
 import org.apache.olingo.server.core.uri.queryoption.expression.LiteralImpl;
 import org.apache.olingo.server.core.uri.queryoption.expression.MemberImpl;
 import org.apache.olingo.server.core.uri.queryoption.expression.MethodImpl;
@@ -725,26 +727,18 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
 
     all.setLamdaVariable(ctx.vLV.getText());
     context.allowedLambdaVariables.push(var);
-    all.setExpression((ExpressionImpl) ctx.vLE.accept(this));
+    all.setExpression((Expression) ctx.vLE.accept(this));
     context.allowedLambdaVariables.pop();
     return all;
   }
 
   @Override
-  public ExpressionImpl visitAltAdd(final AltAddContext ctx) {
-    BinaryImpl binary = new BinaryImpl();
-
+  public Expression visitAltAdd(final AltAddContext ctx) {
     int tokenIndex = ctx.vO.getType();
-
-    if (tokenIndex == UriLexer.ADD) {
-      binary.setOperator(BinaryOperatorKind.ADD);
-    } else if (tokenIndex == UriLexer.SUB) {
-      binary.setOperator(BinaryOperatorKind.SUB);
-    }
-
-    binary.setLeftOperand((ExpressionImpl) ctx.vE1.accept(this));
-    binary.setRightOperand((ExpressionImpl) ctx.vE2.accept(this));
-    return binary;
+    return new BinaryImpl(
+        (Expression) ctx.vE1.accept(this),
+        tokenIndex == UriLexer.ADD ? BinaryOperatorKind.ADD : BinaryOperatorKind.SUB,
+        (Expression) ctx.vE2.accept(this));
   }
 
   @Override
@@ -756,14 +750,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
 
     EdmType startType = removeUriResourceStartingTypeFilterImpl(uriInfoImplpath);
 
-    MemberImpl ret = new MemberImpl();
-
-    ret.setResourcePath(uriInfoImplpath);
-    if (startType != null) {
-      ret.setTypeFilter(startType);
-    }
-
-    return ret;
+    return new MemberImpl(uriInfoImplpath, startType);
   }
 
   private EdmType removeUriResourceStartingTypeFilterImpl(final UriInfoImpl uriInfoImplpath) {
@@ -794,14 +781,11 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
   }
 
   @Override
-  public ExpressionImpl visitAltAnd(final AltAndContext ctx) {
-    BinaryImpl binary = new BinaryImpl();
-
-    binary.setOperator(BinaryOperatorKind.AND);
-    binary.setLeftOperand((ExpressionImpl) ctx.vE1.accept(this));
-    binary.setRightOperand((ExpressionImpl) ctx.vE2.accept(this));
-
-    return binary;
+  public Expression visitAltAnd(final AltAndContext ctx) {
+    return new BinaryImpl(
+        (Expression) ctx.vE1.accept(this),
+        BinaryOperatorKind.AND,
+        (Expression) ctx.vE2.accept(this));
   }
 
   @Override
@@ -812,39 +796,26 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
 
     EdmType startType = removeUriResourceStartingTypeFilterImpl(uriInfoImplpath);
 
-    MemberImpl ret = new MemberImpl();
-    ret.setResourcePath(uriInfoImplpath);
-    if (startType != null) {
-      ret.setTypeFilter(startType);
-    }
-    return ret;
-  }
-
-  @Override
-  public Object visitBatchEOF(final BatchEOFContext ctx) {
-    context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.batch);
-    return null;
+    return new MemberImpl(uriInfoImplpath, startType);
   }
 
   @Override
-  public ExpressionImpl visitAltComparism(final AltComparismContext ctx) {
-    BinaryImpl binary = new BinaryImpl();
-
+  public Expression visitAltComparism(final AltComparismContext ctx) {
     int tokenIndex = ctx.vO.getType();
-
+    BinaryOperatorKind kind = null;
     if (tokenIndex == UriLexer.GT) {
-      binary.setOperator(BinaryOperatorKind.GT);
+      kind = BinaryOperatorKind.GT;
     } else if (tokenIndex == UriLexer.GE) {
-      binary.setOperator(BinaryOperatorKind.GE);
+      kind = BinaryOperatorKind.GE;
     } else if (tokenIndex == UriLexer.LT) {
-      binary.setOperator(BinaryOperatorKind.LT);
+      kind = BinaryOperatorKind.LT;
     } else if (tokenIndex == UriLexer.LE) {
-      binary.setOperator(BinaryOperatorKind.LE);
+      kind = BinaryOperatorKind.LE;
     }
-
-    binary.setLeftOperand((ExpressionImpl) ctx.vE1.accept(this));
-    binary.setRightOperand((ExpressionImpl) ctx.vE2.accept(this));
-    return binary;
+    return new BinaryImpl(
+        (Expression) ctx.vE1.accept(this),
+        kind,
+        (Expression) ctx.vE2.accept(this));
   }
 
   @Override
@@ -867,31 +838,20 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
   }
 
   @Override
-  public ExpressionImpl visitAltEquality(final AltEqualityContext ctx) {
-    BinaryImpl binary = new BinaryImpl();
-
+  public Expression visitAltEquality(final AltEqualityContext ctx) {
     int tokenIndex = ctx.vO.getType();
-
-    if (tokenIndex == UriLexer.EQ_ALPHA) {
-      binary.setOperator(BinaryOperatorKind.EQ);
-    } else {
-      binary.setOperator(BinaryOperatorKind.NE);
-    }
-    binary.setLeftOperand((ExpressionImpl) ctx.vE1.accept(this));
-    binary.setRightOperand((ExpressionImpl) ctx.vE2.accept(this));
-
-    return binary;
+    return new BinaryImpl(
+        (Expression) ctx.vE1.accept(this),
+        tokenIndex == UriLexer.EQ_ALPHA ? BinaryOperatorKind.EQ : BinaryOperatorKind.NE,
+        (Expression) ctx.vE2.accept(this));
   }
 
   @Override
   public Object visitAltHas(final AltHasContext ctx) {
-    BinaryImpl binary = new BinaryImpl();
-
-    binary.setOperator(BinaryOperatorKind.HAS);
-    binary.setLeftOperand((ExpressionImpl) ctx.vE1.accept(this));
-    binary.setRightOperand((ExpressionImpl) ctx.vE2.accept(this));
-
-    return binary;
+    return new BinaryImpl(
+        (Expression) ctx.vE1.accept(this),
+        BinaryOperatorKind.HAS,
+        (Expression) ctx.vE2.accept(this));
   }
 
   @Override
@@ -902,33 +862,28 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
   }
 
   @Override
-  public ExpressionImpl visitAltMult(final AltMultContext ctx) {
-    BinaryImpl binary = new BinaryImpl();
-
+  public Expression visitAltMult(final AltMultContext ctx) {
     int tokenIndex = ctx.vO.getType();
-
+    BinaryOperatorKind kind;
     if (tokenIndex == UriLexer.MUL) {
-      binary.setOperator(BinaryOperatorKind.MUL);
+      kind = BinaryOperatorKind.MUL;
     } else if (tokenIndex == UriLexer.DIV) {
-      binary.setOperator(BinaryOperatorKind.DIV);
+      kind = BinaryOperatorKind.DIV;
     } else {
-      binary.setOperator(BinaryOperatorKind.MOD);
+      kind = BinaryOperatorKind.MOD;
     }
-    binary.setLeftOperand((ExpressionImpl) ctx.vE1.accept(this));
-    binary.setRightOperand((ExpressionImpl) ctx.vE2.accept(this));
-
-    return binary;
+    return new BinaryImpl(
+        (Expression) ctx.vE1.accept(this),
+        kind,
+        (Expression) ctx.vE2.accept(this));
   }
 
   @Override
-  public ExpressionImpl visitAltOr(final AltOrContext ctx) {
-    BinaryImpl binary = new BinaryImpl();
-
-    binary.setOperator(BinaryOperatorKind.OR);
-    binary.setLeftOperand((ExpressionImpl) ctx.vE1.accept(this));
-    binary.setRightOperand((ExpressionImpl) ctx.vE2.accept(this));
-
-    return binary;
+  public Expression visitAltOr(final AltOrContext ctx) {
+    return new BinaryImpl(
+        (Expression) ctx.vE1.accept(this),
+        BinaryOperatorKind.OR,
+        (Expression) ctx.vE2.accept(this));
   }
 
   @Override
@@ -954,7 +909,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
 
       any.setLamdaVariable(ctx.vLV.getText());
       context.allowedLambdaVariables.push(var);
-      any.setExpression((ExpressionImpl) ctx.vLE.accept(this));
+      any.setExpression((Expression) ctx.vLE.accept(this));
       context.allowedLambdaVariables.pop();
     }
     return any;
@@ -963,17 +918,16 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
   @Override
   public Object visitBooleanNonCaseLiteral(final BooleanNonCaseLiteralContext ctx) {
     final String text = ctx.getText().toLowerCase();
-    return new LiteralImpl().setText(text.equals("false") ? "false" : "true")
-        .setType(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Boolean));
+    return new LiteralImpl(text.equals("false") ? "false" : "true",
+        EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Boolean));
   }
 
   @Override
-  public ExpressionImpl visitCastExpr(final CastExprContext ctx) {
-    MethodImpl method = new MethodImpl();
+  public Expression visitCastExpr(final CastExprContext ctx) {
+    List<Expression> parameters = new ArrayList<Expression>();
     if (ctx.vE1 != null) {
       // is optional parameter
-      ExpressionImpl onExpression = (ExpressionImpl) ctx.vE1.accept(this);
-      method.addParameter(onExpression);
+      parameters.add((Expression) ctx.vE1.accept(this));
     }
 
     String namespace = ctx.vNS.getText();
@@ -981,9 +935,8 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
 
     FullQualifiedName fullName = new FullQualifiedName(namespace, ctx.vODI.getText());
     EdmType type = getType(fullName);
-    method.setMethod(MethodKind.CAST);
-    method.addParameter(new TypeLiteralImpl().setType(type));
-    return method;
+    parameters.add(new TypeLiteralImpl(type));
+    return new MethodImpl(MethodKind.CAST, parameters);
   }
 
   private EdmType getType(final FullQualifiedName fullName) {
@@ -1022,18 +975,15 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
   }
 
   @Override
-  public ExpressionImpl visitCeilingMethodCallExpr(final CeilingMethodCallExprContext ctx) {
-    return new MethodImpl()
-        .setMethod(MethodKind.CEILING)
-        .addParameter((ExpressionImpl) ctx.vE1.accept(this));
+  public Expression visitCeilingMethodCallExpr(final CeilingMethodCallExprContext ctx) {
+    return new MethodImpl(MethodKind.CEILING, Collections.singletonList((Expression) ctx.vE1.accept(this)));
   }
 
   @Override
-  public ExpressionImpl visitConcatMethodCallExpr(final ConcatMethodCallExprContext ctx) {
-    return new MethodImpl()
-        .setMethod(MethodKind.CONCAT)
-        .addParameter((ExpressionImpl) ctx.vE1.accept(this))
-        .addParameter((ExpressionImpl) ctx.vE2.accept(this));
+  public Expression visitConcatMethodCallExpr(final ConcatMethodCallExprContext ctx) {
+    return new MethodImpl(MethodKind.CONCAT, Arrays.asList(
+        (Expression) ctx.vE1.accept(this),
+        (Expression) ctx.vE2.accept(this)));
   }
 
   @Override
@@ -1090,47 +1040,38 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
   }
 
   @Override
-  public ExpressionImpl visitContainsMethodCallExpr(final ContainsMethodCallExprContext ctx) {
-    return new MethodImpl()
-        .setMethod(MethodKind.CONTAINS)
-        .addParameter((ExpressionImpl) ctx.vE1.accept(this))
-        .addParameter((ExpressionImpl) ctx.vE2.accept(this));
+  public Expression visitContainsMethodCallExpr(final ContainsMethodCallExprContext ctx) {
+    return new MethodImpl(MethodKind.CONTAINS, Arrays.asList(
+        (Expression) ctx.vE1.accept(this),
+        (Expression) ctx.vE2.accept(this)));
   }
 
   @Override
   public Object visitDateMethodCallExpr(final DateMethodCallExprContext ctx) {
-    return new MethodImpl()
-        .setMethod(MethodKind.DATE)
-        .addParameter((ExpressionImpl) ctx.vE1.accept(this));
+    return new MethodImpl(MethodKind.DATE, Collections.singletonList((Expression) ctx.vE1.accept(this)));
   }
 
   @Override
-  public ExpressionImpl visitDayMethodCallExpr(final DayMethodCallExprContext ctx) {
-    return new MethodImpl()
-        .setMethod(MethodKind.DAY)
-        .addParameter((ExpressionImpl) ctx.vE1.accept(this));
+  public Expression visitDayMethodCallExpr(final DayMethodCallExprContext ctx) {
+    return new MethodImpl(MethodKind.DAY, Collections.singletonList((Expression) ctx.vE1.accept(this)));
   }
 
   @Override
-  public ExpressionImpl visitGeoDistanceMethodCallExpr(final GeoDistanceMethodCallExprContext ctx) {
-    return new MethodImpl()
-        .setMethod(MethodKind.GEODISTANCE)
-        .addParameter((ExpressionImpl) ctx.vE1.accept(this))
-        .addParameter((ExpressionImpl) ctx.vE2.accept(this));
+  public Expression visitGeoDistanceMethodCallExpr(final GeoDistanceMethodCallExprContext ctx) {
+    return new MethodImpl(MethodKind.GEODISTANCE, Arrays.asList(
+        (Expression) ctx.vE1.accept(this),
+        (Expression) ctx.vE2.accept(this)));
   }
 
   @Override
   public Object visitEndsWithMethodCallExpr(final EndsWithMethodCallExprContext ctx) {
-    return new MethodImpl()
-        .setMethod(MethodKind.ENDSWITH)
-        .addParameter((ExpressionImpl) ctx.vE1.accept(this))
-        .addParameter((ExpressionImpl) ctx.vE2.accept(this));
+    return new MethodImpl(MethodKind.ENDSWITH, Arrays.asList(
+        (Expression) ctx.vE1.accept(this),
+        (Expression) ctx.vE2.accept(this)));
   }
 
   @Override
   public Object visitEnumLiteral(final EnumLiteralContext ctx) {
-    EnumerationImpl enum1 = new EnumerationImpl();
-
     // get type
     final String odi = ctx.vODI.getText();
 
@@ -1141,17 +1082,11 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
           "Enum type '" + fullName.getFullQualifiedNameAsString() + "' not found!",
           UriParserSemanticException.MessageKeys.UNKNOWN_TYPE, fullName.getFullQualifiedNameAsString()));
     }
-    enum1.setType(edmEnumType);
 
     String valueString = ctx.vValues.getText();
     valueString = valueString.substring(1, valueString.length() - 1);
-
     String[] values = valueString.split(",");
-    for (String item : values) {
-      enum1.addValue(item);
-    }
-
-    return enum1;
+    return new EnumerationImpl(edmEnumType, Arrays.asList(values));
   }
 
   @Override
@@ -1343,7 +1278,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
   @Override
   public Object visitFilter(final FilterContext ctx) {
     context.contextReadingQueryPart = true;
-    final FilterOptionImpl result = new FilterOptionImpl().setExpression((ExpressionImpl) ctx.children.get(2)
+    final FilterOptionImpl result = new FilterOptionImpl().setExpression((Expression) ctx.children.get(2)
                                                           .accept(this));
     context.contextReadingQueryPart = false;
 
@@ -1353,7 +1288,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
   @Override
   public Object visitFilterExpressionEOF(final FilterExpressionEOFContext ctx) {
     context.contextReadingQueryPart = true;
-    final FilterOptionImpl result = new FilterOptionImpl().setExpression((ExpressionImpl) ctx.children.get(0)
+    final FilterOptionImpl result = new FilterOptionImpl().setExpression((Expression) ctx.children.get(0)
                                                           .accept(this));
     context.contextReadingQueryPart = false;
 
@@ -1361,39 +1296,30 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
   }
 
   @Override
-  public ExpressionImpl visitFloorMethodCallExpr(final FloorMethodCallExprContext ctx) {
-    return new MethodImpl()
-        .setMethod(MethodKind.FLOOR)
-        .addParameter((ExpressionImpl) ctx.vE1.accept(this));
+  public Expression visitFloorMethodCallExpr(final FloorMethodCallExprContext ctx) {
+    return new MethodImpl(MethodKind.FLOOR, Collections.singletonList((Expression) ctx.vE1.accept(this)));
   }
 
   @Override
-  public ExpressionImpl visitFractionalsecondsMethodCallExpr(final FractionalsecondsMethodCallExprContext ctx) {
-    return new MethodImpl()
-        .setMethod(MethodKind.FRACTIONALSECONDS)
-        .addParameter((ExpressionImpl) ctx.vE1.accept(this));
+  public Expression visitFractionalsecondsMethodCallExpr(final FractionalsecondsMethodCallExprContext ctx) {
+    return new MethodImpl(MethodKind.FRACTIONALSECONDS, Collections.singletonList((Expression) ctx.vE1.accept(this)));
   }
 
   @Override
-  public ExpressionImpl visitGeoLengthMethodCallExpr(final GeoLengthMethodCallExprContext ctx) {
-    return new MethodImpl()
-        .setMethod(MethodKind.GEOLENGTH)
-        .addParameter((ExpressionImpl) ctx.vE1.accept(this));
+  public Expression visitGeoLengthMethodCallExpr(final GeoLengthMethodCallExprContext ctx) {
+    return new MethodImpl(MethodKind.GEOLENGTH, Collections.singletonList((Expression) ctx.vE1.accept(this)));
   }
 
   @Override
-  public ExpressionImpl visitHourMethodCallExpr(final HourMethodCallExprContext ctx) {
-    return new MethodImpl()
-        .setMethod(MethodKind.HOUR)
-        .addParameter((ExpressionImpl) ctx.vE1.accept(this));
+  public Expression visitHourMethodCallExpr(final HourMethodCallExprContext ctx) {
+    return new MethodImpl(MethodKind.HOUR, Collections.singletonList((Expression) ctx.vE1.accept(this)));
   }
 
   @Override
-  public ExpressionImpl visitIndexOfMethodCallExpr(final IndexOfMethodCallExprContext ctx) {
-    return new MethodImpl()
-        .setMethod(MethodKind.INDEXOF)
-        .addParameter((ExpressionImpl) ctx.vE1.accept(this))
-        .addParameter((ExpressionImpl) ctx.vE2.accept(this));
+  public Expression visitIndexOfMethodCallExpr(final IndexOfMethodCallExprContext ctx) {
+    return new MethodImpl(MethodKind.INDEXOF, Arrays.asList(
+        (Expression) ctx.vE1.accept(this),
+        (Expression) ctx.vE2.accept(this)));
   }
 
   @Override
@@ -1405,19 +1331,17 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
   }
 
   @Override
-  public ExpressionImpl visitGeoIntersectsMethodCallExpr(final GeoIntersectsMethodCallExprContext ctx) {
-    return new MethodImpl()
-        .setMethod(MethodKind.GEOINTERSECTS)
-        .addParameter((ExpressionImpl) ctx.vE1.accept(this))
-        .addParameter((ExpressionImpl) ctx.vE2.accept(this));
+  public Expression visitGeoIntersectsMethodCallExpr(final GeoIntersectsMethodCallExprContext ctx) {
+    return new MethodImpl(MethodKind.GEOINTERSECTS, Arrays.asList(
+        (Expression) ctx.vE1.accept(this),
+        (Expression) ctx.vE2.accept(this)));
   }
 
   @Override
-  public ExpressionImpl visitIsofExpr(final IsofExprContext ctx) {
-    MethodImpl method = new MethodImpl();
+  public Expression visitIsofExpr(final IsofExprContext ctx) {
+    List<Expression> parameters = new ArrayList<Expression>();
     if (ctx.vE1 != null) {
-      ExpressionImpl onExpression = (ExpressionImpl) ctx.vE1.accept(this);
-      method.addParameter(onExpression);
+      parameters.add((Expression) ctx.vE1.accept(this));
     }
 
     String namespace = ctx.vNS.getText();
@@ -1425,17 +1349,14 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
 
     FullQualifiedName fullName = new FullQualifiedName(namespace, ctx.vODI.getText());
     EdmType type = getType(fullName);
-    method.setMethod(MethodKind.ISOF);
-    method.addParameter(new TypeLiteralImpl().setType(type));
+    parameters.add(new TypeLiteralImpl(type));
 
-    return method;
+    return new MethodImpl(MethodKind.ISOF, parameters);
   }
 
   @Override
-  public ExpressionImpl visitLengthMethodCallExpr(final LengthMethodCallExprContext ctx) {
-    return new MethodImpl()
-        .setMethod(MethodKind.LENGTH)
-        .addParameter((ExpressionImpl) ctx.vE1.accept(this));
+  public Expression visitLengthMethodCallExpr(final LengthMethodCallExprContext ctx) {
+    return new MethodImpl(MethodKind.LENGTH, Collections.singletonList((Expression) ctx.vE1.accept(this)));
   }
 
   @Override
@@ -1457,9 +1378,8 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
   }
 
   @Override
-  public ExpressionImpl visitMaxDateTimeMethodCallExpr(final MaxDateTimeMethodCallExprContext ctx) {
-    return new MethodImpl()
-        .setMethod(MethodKind.MAXDATETIME);
+  public Expression visitMaxDateTimeMethodCallExpr(final MaxDateTimeMethodCallExprContext ctx) {
+    return new MethodImpl(MethodKind.MAXDATETIME, null);
   }
 
   @Override
@@ -1501,33 +1421,22 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
 
     EdmType startType = removeUriResourceStartingTypeFilterImpl(uriInfoImplpath);
 
-    MemberImpl ret = new MemberImpl();
-    ret.setResourcePath(uriInfoImplpath);
-    if (startType != null) {
-      ret.setTypeFilter(startType);
-    }
-
-    return ret;
+    return new MemberImpl(uriInfoImplpath, startType);
   }
 
   @Override
-  public ExpressionImpl visitMinDateTimeMethodCallExpr(final MinDateTimeMethodCallExprContext ctx) {
-    return new MethodImpl()
-        .setMethod(MethodKind.MINDATETIME);
+  public Expression visitMinDateTimeMethodCallExpr(final MinDateTimeMethodCallExprContext ctx) {
+    return new MethodImpl(MethodKind.MINDATETIME, null);
   }
 
   @Override
-  public ExpressionImpl visitMinuteMethodCallExpr(final MinuteMethodCallExprContext ctx) {
-    return new MethodImpl()
-        .setMethod(MethodKind.MINUTE)
-        .addParameter((ExpressionImpl) ctx.vE1.accept(this));
+  public Expression visitMinuteMethodCallExpr(final MinuteMethodCallExprContext ctx) {
+    return new MethodImpl(MethodKind.MINUTE, Collections.singletonList((Expression) ctx.vE1.accept(this)));
   }
 
   @Override
-  public ExpressionImpl visitMonthMethodCallExpr(final MonthMethodCallExprContext ctx) {
-    return new MethodImpl()
-        .setMethod(MethodKind.MONTH)
-        .addParameter((ExpressionImpl) ctx.vE1.accept(this));
+  public Expression visitMonthMethodCallExpr(final MonthMethodCallExprContext ctx) {
+    return new MethodImpl(MethodKind.MONTH, Collections.singletonList((Expression) ctx.vE1.accept(this)));
   }
 
   @Override
@@ -1537,9 +1446,9 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
 
       // is single key predicate without a name
       String valueText = ctx.vVO.getText();
-      ExpressionImpl expression = null;
+      Expression expression = null;
       try {
-        expression = (ExpressionImpl) ctx.vVO.accept(this);
+        expression = (Expression) ctx.vVO.accept(this);
       } catch (final RuntimeException e) {
         throw wrap(new UriParserSemanticException("Invalid key value: " + valueText, e,
             UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE, valueText));
@@ -1763,7 +1672,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
     if (ctx.vCOM != null) {
       final String text = ctx.vCOM.getText();
       uriParameter.setText("null".equals(text) ? null : text);
-      uriParameter.setExpression((ExpressionImpl) ctx.vCOM.accept(this));
+      uriParameter.setExpression((Expression) ctx.vCOM.accept(this));
     } else {
       uriParameter.setAlias("@" + ctx.vALI.getText());
     }
@@ -1773,29 +1682,20 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
 
   @Override
   public Object visitNaninfinityLiteral(final NaninfinityLiteralContext ctx) {
-    return new LiteralImpl().setType(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal)).setText(ctx
-        .getText());
+    return new LiteralImpl(ctx.getText(),
+        EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal));
   }
 
   @Override
-  public ExpressionImpl visitNowMethodCallExpr(final NowMethodCallExprContext ctx) {
-    return new MethodImpl()
-        .setMethod(MethodKind.NOW);
+  public Expression visitNowMethodCallExpr(final NowMethodCallExprContext ctx) {
+    return new MethodImpl(MethodKind.NOW, null);
   }
 
   @Override
   public Object visitNullruleLiteral(final NullruleLiteralContext ctx) {
-    return new LiteralImpl().setText("null");
+    return new LiteralImpl("null", null);
   }
 
-  /*
-   * @Override
-   * public Object visitOdataRelativeUriEOF(final OdataRelativeUriEOFContext ctx) {
-   * contextUriInfo = null;
-   * super.visitOdataRelativeUriEOF(ctx);
-   * return contextUriInfo;
-   * }
-   */
   @Override
   public Object visitOrderBy(final OrderByContext ctx) {
 
@@ -1831,7 +1731,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
       oItem.setDescending(true);
     }
 
-    oItem.setExpression((ExpressionImpl) ctx.vC.accept(this));
+    oItem.setExpression((Expression) ctx.vC.accept(this));
     return oItem;
   }
 
@@ -1906,19 +1806,19 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
     }
 
     // TODO Implement geography types and set a proper type
-    return new LiteralImpl().setText(ctx.getText());
+    return new LiteralImpl(ctx.getText(), null);
   }
 
   @Override
   public Object visitBinaryLiteral(BinaryLiteralContext ctx) {
-    return new LiteralImpl().setText(ctx.getText())
-        .setType(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Binary));
+    return new LiteralImpl(ctx.getText(),
+        EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Binary));
   }
 
   @Override
   public Object visitStringLiteral(final StringLiteralContext ctx) {
-    return new LiteralImpl().setText(ctx.getText())
-        .setType(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.String));
+    return new LiteralImpl(ctx.getText(),
+        EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.String));
   }
 
   @Override
@@ -1928,7 +1828,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
             EdmPrimitiveTypeKind.Double :
             EdmPrimitiveTypeKind.Decimal);
 
-    return new LiteralImpl().setText(ctx.getText()).setType(type);
+    return new LiteralImpl(ctx.getText(), type);
   }
 
   @Override
@@ -1948,41 +1848,41 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
         typeKind = EdmPrimitiveTypeKind.Int64;
       }
     } catch (NumberFormatException e) {
-      return new LiteralImpl().setText(ctx.getText())
-          .setType(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal));
+      return new LiteralImpl(ctx.getText(),
+          EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal));
     }
-    return new LiteralImpl().setText(ctx.getText())
-        .setType(EdmPrimitiveTypeFactory.getInstance(typeKind));
+    return new LiteralImpl(ctx.getText(),
+        EdmPrimitiveTypeFactory.getInstance(typeKind));
   }
 
   @Override
   public Object visitDateLiteral(final DateLiteralContext ctx) {
-    return new LiteralImpl().setText(ctx.getText())
-        .setType(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Date));
+    return new LiteralImpl(ctx.getText(),
+        EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Date));
   }
 
   @Override
   public Object visitDatetimeoffsetLiteral(final DatetimeoffsetLiteralContext ctx) {
-    return new LiteralImpl().setText(ctx.getText())
-        .setType(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.DateTimeOffset));
+    return new LiteralImpl(ctx.getText(),
+        EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.DateTimeOffset));
   }
 
   @Override
   public Object visitDurationLiteral(final DurationLiteralContext ctx) {
-    return new LiteralImpl().setText(ctx.getText())
-        .setType(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Duration));
+    return new LiteralImpl(ctx.getText(),
+        EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Duration));
   }
 
   @Override
   public Object visitGuidLiteral(final GuidLiteralContext ctx) {
-    return new LiteralImpl().setText(ctx.getText())
-        .setType(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Guid));
+    return new LiteralImpl(ctx.getText(),
+        EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Guid));
   }
 
   @Override
   public Object visitTimeofdayLiteral(final TimeofdayLiteralContext ctx) {
-    return new LiteralImpl().setText(ctx.getText())
-        .setType(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.TimeOfDay));
+    return new LiteralImpl(ctx.getText(),
+        EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.TimeOfDay));
   }
 
   @Override
@@ -1996,21 +1896,6 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
     return qpList;
   }
 
-  /*
-   * @Override
-   * public Object visitResourcePath(final ResourcePathContext ctx) {
-   * if (ctx.vAll != null) {
-   * contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.all);
-   * } else if (ctx.vCJ != null) {
-   * ctx.vCJ.accept(this);
-   * } else if (ctx.vlPS != null) {
-   * UriInfoImpl uriInfoPath = new UriInfoImpl().setKind(UriInfoKind.resource);
-   * contextUriInfo = uriInfoPath;
-   * super.visitResourcePath(ctx); // visit all children of ctx
-   * }
-   * return contextUriInfo;
-   * }
-   */
   @Override
   public Object visitRootExpr(final RootExprContext ctx) {
 
@@ -2042,23 +1927,18 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
       context.contextUriInfo = backupUriInfoPath;
 
     }
-    return new MemberImpl()
-        .setResourcePath(uriInfoImplpath);
+    return new MemberImpl(uriInfoImplpath, null);
 
   }
 
   @Override
-  public ExpressionImpl visitRoundMethodCallExpr(final RoundMethodCallExprContext ctx) {
-    return new MethodImpl()
-        .setMethod(MethodKind.ROUND)
-        .addParameter((ExpressionImpl) ctx.vE1.accept(this));
+  public Expression visitRoundMethodCallExpr(final RoundMethodCallExprContext ctx) {
+    return new MethodImpl(MethodKind.ROUND, Collections.singletonList((Expression) ctx.vE1.accept(this)));
   }
 
   @Override
-  public ExpressionImpl visitSecondMethodCallExpr(final SecondMethodCallExprContext ctx) {
-    return new MethodImpl()
-        .setMethod(MethodKind.SECOND)
-        .addParameter((ExpressionImpl) ctx.vE1.accept(this));
+  public Expression visitSecondMethodCallExpr(final SecondMethodCallExprContext ctx) {
+    return new MethodImpl(MethodKind.SECOND, Collections.singletonList((Expression) ctx.vE1.accept(this)));
   }
 
   @Override
@@ -2344,33 +2224,28 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
   }
 
   @Override
-  public ExpressionImpl visitStartsWithMethodCallExpr(final StartsWithMethodCallExprContext ctx) {
-    return new MethodImpl()
-        .setMethod(MethodKind.STARTSWITH)
-        .addParameter((ExpressionImpl) ctx.vE1.accept(this))
-        .addParameter((ExpressionImpl) ctx.vE2.accept(this));
+  public Expression visitStartsWithMethodCallExpr(final StartsWithMethodCallExprContext ctx) {
+    return new MethodImpl(MethodKind.STARTSWITH, Arrays.asList(
+        (Expression) ctx.vE1.accept(this),
+        (Expression) ctx.vE2.accept(this)));
   }
 
   @Override
-  public ExpressionImpl visitSubstringMethodCallExpr(final SubstringMethodCallExprContext ctx) {
-    MethodImpl ret = new MethodImpl();
-    ret.setMethod(MethodKind.SUBSTRING);
-    ret.addParameter((ExpressionImpl) ctx.vE1.accept(this));
-    ret.addParameter((ExpressionImpl) ctx.vE2.accept(this));
+  public Expression visitSubstringMethodCallExpr(final SubstringMethodCallExprContext ctx) {
+    List<Expression> parameters = new ArrayList<Expression>();
+    parameters.add((Expression) ctx.vE1.accept(this));
+    parameters.add((Expression) ctx.vE2.accept(this));
 
     if (ctx.vE3 != null) {
-      ret.addParameter((ExpressionImpl) ctx.vE3.accept(this));
+      parameters.add((Expression) ctx.vE3.accept(this));
     }
 
-    return ret;
-
+    return new MethodImpl(MethodKind.SUBSTRING, parameters);
   }
 
   @Override
-  public ExpressionImpl visitTimeMethodCallExpr(final TimeMethodCallExprContext ctx) {
-    return new MethodImpl()
-        .setMethod(MethodKind.TIME)
-        .addParameter((ExpressionImpl) ctx.vE1.accept(this));
+  public Expression visitTimeMethodCallExpr(final TimeMethodCallExprContext ctx) {
+    return new MethodImpl(MethodKind.TIME, Collections.singletonList((Expression) ctx.vE1.accept(this)));
   }
 
   @Override
@@ -2382,45 +2257,33 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
   }
 
   @Override
-  public ExpressionImpl visitToLowerMethodCallExpr(final ToLowerMethodCallExprContext ctx) {
-    return new MethodImpl()
-        .setMethod(MethodKind.TOLOWER)
-        .addParameter((ExpressionImpl) ctx.vE1.accept(this));
+  public Expression visitToLowerMethodCallExpr(final ToLowerMethodCallExprContext ctx) {
+    return new MethodImpl(MethodKind.TOLOWER, Collections.singletonList((Expression) ctx.vE1.accept(this)));
   }
 
   @Override
-  public ExpressionImpl visitTotalOffsetMinutesMethodCallExpr(final TotalOffsetMinutesMethodCallExprContext ctx) {
-    return new MethodImpl()
-        .setMethod(MethodKind.TOTALOFFSETMINUTES)
-        .addParameter((ExpressionImpl) ctx.vE1.accept(this));
+  public Expression visitTotalOffsetMinutesMethodCallExpr(final TotalOffsetMinutesMethodCallExprContext ctx) {
+    return new MethodImpl(MethodKind.TOTALOFFSETMINUTES, Collections.singletonList((Expression) ctx.vE1.accept(this)));
   }
 
   @Override
-  public ExpressionImpl visitTotalsecondsMethodCallExpr(final TotalsecondsMethodCallExprContext ctx) {
-    return new MethodImpl()
-        .setMethod(MethodKind.TOTALSECONDS)
-        .addParameter((ExpressionImpl) ctx.vE1.accept(this));
+  public Expression visitTotalsecondsMethodCallExpr(final TotalsecondsMethodCallExprContext ctx) {
+    return new MethodImpl(MethodKind.TOTALSECONDS, Collections.singletonList((Expression) ctx.vE1.accept(this)));
   }
 
   @Override
-  public ExpressionImpl visitToUpperMethodCallExpr(final ToUpperMethodCallExprContext ctx) {
-    return new MethodImpl()
-        .setMethod(MethodKind.TOUPPER)
-        .addParameter((ExpressionImpl) ctx.vE1.accept(this));
+  public Expression visitToUpperMethodCallExpr(final ToUpperMethodCallExprContext ctx) {
+    return new MethodImpl(MethodKind.TOUPPER, Collections.singletonList((Expression) ctx.vE1.accept(this)));
   }
 
   @Override
-  public ExpressionImpl visitTrimMethodCallExpr(final TrimMethodCallExprContext ctx) {
-    return new MethodImpl()
-        .setMethod(MethodKind.TRIM)
-        .addParameter((ExpressionImpl) ctx.vE1.accept(this));
+  public Expression visitTrimMethodCallExpr(final TrimMethodCallExprContext ctx) {
+    return new MethodImpl(MethodKind.TRIM, Collections.singletonList((Expression) ctx.vE1.accept(this)));
   }
 
   @Override
-  public ExpressionImpl visitYearMethodCallExpr(final YearMethodCallExprContext ctx) {
-    return new MethodImpl()
-        .setMethod(MethodKind.YEAR)
-        .addParameter((ExpressionImpl) ctx.vE1.accept(this));
+  public Expression visitYearMethodCallExpr(final YearMethodCallExprContext ctx) {
+    return new MethodImpl(MethodKind.YEAR, Collections.singletonList((Expression) ctx.vE1.accept(this)));
   }
 
   private ParseCancellationException wrap(final UriParserException uriParserException) {
@@ -2428,18 +2291,15 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
   }
 
   @Override
-  public ExpressionImpl visitAltUnary(@NotNull final UriParserParser.AltUnaryContext ctx) {
-    UnaryImpl unary = new UnaryImpl();
-    unary.setOperator(ctx.unary().NOT() == null ? UnaryOperatorKind.MINUS : UnaryOperatorKind.NOT);
-    unary.setOperand((ExpressionImpl) ctx.commonExpr().accept(this));
-    return unary;
+  public Expression visitAltUnary(@NotNull final UriParserParser.AltUnaryContext ctx) {
+    return new UnaryImpl(
+        ctx.unary().NOT() == null ? UnaryOperatorKind.MINUS : UnaryOperatorKind.NOT,
+        (Expression) ctx.commonExpr().accept(this));
   }
 
   @Override
-  public ExpressionImpl visitAltAlias(@NotNull final UriParserParser.AltAliasContext ctx) {
-    AliasImpl alias = new AliasImpl();
-    alias.setParameter("@" + ctx.odataIdentifier().getChild(0).getText());
-    return alias;
+  public Expression visitAltAlias(@NotNull final UriParserParser.AltAliasContext ctx) {
+    return new AliasImpl("@" + ctx.odataIdentifier().getChild(0).getText());
   }
 
   @Override
@@ -2455,7 +2315,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
           MessageKeys.COMPLEX_PARAMETER_IN_RESOURCE_PATH, ctx.getText()));
     }
 
-    return new LiteralImpl().setText(ctx.getText()).setType(null);
+    return new LiteralImpl(ctx.getText(), null);
   }
   
   @Override

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/208f26c7/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/OrderByItemImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/OrderByItemImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/OrderByItemImpl.java
index aac33f0..71c728c 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/OrderByItemImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/OrderByItemImpl.java
@@ -19,11 +19,11 @@
 package org.apache.olingo.server.core.uri.queryoption;
 
 import org.apache.olingo.server.api.uri.queryoption.OrderByItem;
-import org.apache.olingo.server.core.uri.queryoption.expression.ExpressionImpl;
+import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
 
 public class OrderByItemImpl implements OrderByItem {
 
-  private ExpressionImpl expression;
+  private Expression expression;
   private boolean descending = false; // default sort order is ascending
 
   @Override
@@ -37,11 +37,11 @@ public class OrderByItemImpl implements OrderByItem {
   }
 
   @Override
-  public ExpressionImpl getExpression() {
+  public Expression getExpression() {
     return expression;
   }
 
-  public OrderByItem setExpression(final ExpressionImpl expression) {
+  public OrderByItem setExpression(final Expression expression) {
     this.expression = expression;
     return this;
   }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/208f26c7/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/AliasImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/AliasImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/AliasImpl.java
index 5309d73..c7d7c20 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/AliasImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/AliasImpl.java
@@ -23,15 +23,11 @@ import org.apache.olingo.server.api.uri.queryoption.expression.Alias;
 import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitException;
 import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitor;
 
-public class AliasImpl extends ExpressionImpl implements Alias {
+public class AliasImpl implements Alias {
 
-  private String parameterName;
+  private final String parameterName;
 
-  public AliasImpl() {
-    //TODO: Delete Constructor
-  }
-
-  public AliasImpl(String parameterName) {
+  public AliasImpl(final String parameterName) {
     this.parameterName = parameterName;
   }
 
@@ -40,10 +36,6 @@ public class AliasImpl extends ExpressionImpl implements Alias {
     return parameterName;
   }
 
-  public void setParameter(final String ParameterName) {
-    parameterName = ParameterName;
-  }
-
   @Override
   public <T> T accept(final ExpressionVisitor<T> visitor) throws ExpressionVisitException, ODataApplicationException {
     return visitor.visitAlias(parameterName);


[08/30] olingo-odata4 git commit: [OLINGO-834] $select parser in Java + clean-up

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d7e23bf8/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java
index 87e09ad..8051573 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java
@@ -39,7 +39,11 @@ public class UriTokenizer {
     CLOSE,
     COMMA,
     SEMI,
+    DOT,
+    SLASH,
     EQ,
+    STAR,
+    PLUS,
     NULL,
 
     // variable-value tokens (convention: mixed case)
@@ -63,18 +67,18 @@ public class UriTokenizer {
     jsonArrayOrObject
   }
 
-  private final String pathSegment;
+  private final String parseString;
 
   private int startIndex = 0;
   private int index = 0;
 
-  public UriTokenizer(final String pathSegment) {
-    this.pathSegment = pathSegment == null ? "" : pathSegment;
+  public UriTokenizer(final String parseString) {
+    this.parseString = parseString == null ? "" : parseString;
   }
 
   /** Returns the string value corresponding to the last successful {@link #next(TokenKind)} call. */
   public String getText() {
-    return pathSegment.substring(startIndex, index);
+    return parseString.substring(startIndex, index);
   }
 
   /**
@@ -119,14 +123,26 @@ public class UriTokenizer {
     case SEMI:
       found = nextCharacter(';');
       break;
+    case DOT:
+      found = nextCharacter('.');
+      break;
+    case SLASH:
+      found = nextCharacter('/');
+      break;
     case EQ:
       found = nextCharacter('=');
       break;
+    case STAR:
+      found = nextCharacter('*');
+      break;
+    case PLUS:
+      found = nextCharacter('+');
+      break;
     case NULL:
       found = nextConstant("null");
       break;
     case EOF:
-      found = index >= pathSegment.length();
+      found = index >= parseString.length();
       break;
 
     // Identifiers
@@ -192,8 +208,12 @@ public class UriTokenizer {
     return found;
   }
 
+  /**
+   * Moves past the given string constant if found; otherwise leaves the index unchanged.
+   * @return whether the constant has been found at the current index
+   */
   private boolean nextConstant(final String constant) {
-    if (pathSegment.startsWith(constant, index)) {
+    if (parseString.startsWith(constant, index)) {
       index += constant.length();
       return true;
     } else {
@@ -201,10 +221,14 @@ public class UriTokenizer {
     }
   }
 
+  /**
+   * Moves past the given string constant, ignoring case, if found; otherwise leaves the index unchanged.
+   * @return whether the constant has been found at the current index
+   */
   private boolean nextConstantIgnoreCase(final String constant) {
     final int length = constant.length();
-    if (index + length <= pathSegment.length()
-        && constant.equalsIgnoreCase(pathSegment.substring(index, index + length))) {
+    if (index + length <= parseString.length()
+        && constant.equalsIgnoreCase(parseString.substring(index, index + length))) {
       index += length;
       return true;
     } else {
@@ -217,7 +241,7 @@ public class UriTokenizer {
    * @return whether the given character has been found at the current index
    */
   private boolean nextCharacter(final char character) {
-    if (index < pathSegment.length() && pathSegment.charAt(index) == character) {
+    if (index < parseString.length() && parseString.charAt(index) == character) {
       index++;
       return true;
     } else {
@@ -231,8 +255,8 @@ public class UriTokenizer {
    * @return whether the given character has been found at the current index
    */
   private boolean nextCharacterRange(final char from, final char to) {
-    if (index < pathSegment.length()) {
-      final char code = pathSegment.charAt(index);
+    if (index < parseString.length()) {
+      final char code = parseString.charAt(index);
       if (code >= from && code <= to) {
         index++;
         return true;
@@ -276,16 +300,20 @@ public class UriTokenizer {
     return nextCharacter('+') || nextCharacter('-');
   }
 
+  /**
+   * Moves past an OData identifier if found; otherwise leaves the index unchanged.
+   * @return whether an OData identifier has been found at the current index
+   */
   private boolean nextODataIdentifier() {
     int count = 0;
-    if (index < pathSegment.length()) {
-      int code = pathSegment.codePointAt(index);
+    if (index < parseString.length()) {
+      int code = parseString.codePointAt(index);
       if (Character.isUnicodeIdentifierStart(code) || code == '_') {
         count++;
         // Unicode characters outside of the Basic Multilingual Plane are represented as two Java characters.
         index += Character.isSupplementaryCodePoint(code) ? 2 : 1;
-        while (index < pathSegment.length() && count < 128) {
-          code = pathSegment.codePointAt(index);
+        while (index < parseString.length() && count < 128) {
+          code = parseString.codePointAt(index);
           if (Character.isUnicodeIdentifierPart(code) && !Character.isISOControl(code)) {
             count++;
             // Unicode characters outside of the Basic Multilingual Plane are represented as two Java characters.
@@ -299,16 +327,30 @@ public class UriTokenizer {
     return count > 0;
   }
 
+  /**
+   * Moves past a qualified name if found; otherwise leaves the index unchanged.
+   * @return whether a qualified name has been found at the current index
+   */
   private boolean nextQualifiedName() {
-    int count = 0;
-    do {
+    final int lastGoodIndex = index;
+    if (!nextODataIdentifier()) {
+      return false;
+    }
+    int count = 1;
+    while (nextCharacter('.')) {
       if (nextODataIdentifier()) {
         count++;
       } else {
-        return false;
+        index--;
+        break;
       }
-    } while (nextCharacter('.'));
-    return count >= 2;
+    }
+    if (count >= 2) {
+      return true;
+    } else {
+      index = lastGoodIndex;
+      return false;
+    }
   }
 
   private boolean nextParameterAliasName() {
@@ -323,12 +365,12 @@ public class UriTokenizer {
     if (!nextCharacter('\'')) {
       return false;
     }
-    while (index < pathSegment.length()) {
-      if (pathSegment.charAt(index) == '\'') {
+    while (index < parseString.length()) {
+      if (parseString.charAt(index) == '\'') {
         // If a single quote is followed by another single quote,
         // it represents one single quote within the string literal,
         // otherwise it marks the end of the string literal.
-        if (index + 1 < pathSegment.length() && pathSegment.charAt(index + 1) == '\'') {
+        if (index + 1 < parseString.length() && parseString.charAt(index + 1) == '\'') {
           index++;
         } else {
           break;
@@ -339,7 +381,13 @@ public class UriTokenizer {
     return nextCharacter('\'');
   }
 
+  /**
+   * Moves past an integer value if found; otherwise leaves the index unchanged.
+   * @param signed whether a sign character ('+' or '-') at the beginning is allowed
+   * @return whether an integer value has been found at the current index
+   */
   private boolean nextIntegerValue(final boolean signed) {
+    final int lastGoodIndex = index;
     if (signed) {
       nextSign();
     }
@@ -347,33 +395,53 @@ public class UriTokenizer {
     while (nextDigit()) {
       hasDigits = true;
     }
-    return hasDigits;
+    if (hasDigits) {
+      return true;
+    } else {
+      index = lastGoodIndex;
+      return false;
+    }
   }
 
-  /** Finds and returns only decimal-number tokens with a fractional part.
-   *  Whole numbers must be found with {@link #nextIntegerValue()}.
+  /**
+   * Moves past a decimal value with a fractional part if found; otherwise leaves the index unchanged.
+   * Whole numbers must be found with {@link #nextIntegerValue()}.
    */
   private boolean nextDecimalValue() {
-    return nextIntegerValue(true) && nextCharacter('.') && nextIntegerValue(false);
+    final int lastGoodIndex = index;
+    if (nextIntegerValue(true) && nextCharacter('.') && nextIntegerValue(false)) {
+      return true;
+    } else {
+      index = lastGoodIndex;
+      return false;
+    }
   }
 
   /**
-   * Finds and returns only floating-point-number tokens with an exponential part
-   * and the special three constants "NaN", "-INF", and "INF".
-   *  Whole numbers must be found with {@link #nextIntegerValue()}.
-   *  Decimal numbers must be found with {@link #nextDecimalValue()}.
+   * Moves past a floating-point-number value with an exponential part
+   * or one of the special constants "NaN", "-INF", and "INF"
+   * if found; otherwise leaves the index unchanged.
+   * Whole numbers must be found with {@link #nextIntegerValue()}.
+   * Decimal numbers must be found with {@link #nextDecimalValue()}.
    */
   private boolean nextDoubleValue() {
     if (nextConstant("NaN") || nextConstant("-INF") || nextConstant("INF")) {
       return true;
     } else {
+      final int lastGoodIndex = index;
       if (!nextIntegerValue(true)) {
         return false;
       }
       if (nextCharacter('.') && !nextIntegerValue(false)) {
+        index = lastGoodIndex;
+        return false;
+      }
+      if ((nextCharacter('E') || nextCharacter('e')) && nextIntegerValue(true)) {
+        return true;
+      } else {
+        index = lastGoodIndex;
         return false;
       }
-      return (nextCharacter('E') || nextCharacter('e')) && nextIntegerValue(true);
     }
   }
 
@@ -533,7 +601,12 @@ public class UriTokenizer {
     return false;
   }
 
+  /**
+   * Moves past a JSON string if found; otherwise leaves the index unchanged.
+   * @return whether a JSON string has been found at the current index
+   */
   private boolean nextJsonString() {
+    final int lastGoodIndex = index;
     if (nextCharacter('"')) {
       do {
         if (nextCharacter('\\')) {
@@ -541,6 +614,7 @@ public class UriTokenizer {
               || nextCharacter('n') || nextCharacter('f') || nextCharacter('r')
               || nextCharacter('"') || nextCharacter('/') || nextCharacter('\\')
               || nextCharacter('u') && nextHexDigit() && nextHexDigit() && nextHexDigit() && nextHexDigit())) {
+            index = lastGoodIndex;
             return false;
           }
         } else if (nextCharacter('"')) {
@@ -548,16 +622,17 @@ public class UriTokenizer {
         } else {
           index++;
         }
-      } while (index < pathSegment.length());
+      } while (index < parseString.length());
+      index = lastGoodIndex;
       return false;
     }
+    index = lastGoodIndex;
     return false;
   }
 
   private boolean nextJsonValue() {
     return nextConstant("null") || nextConstant("true") || nextConstant("false")
-        // If a double or decimal number is not found, the index must be reset; the internal methods don't do that.
-        || next(TokenKind.PrimitiveDoubleValue) || next(TokenKind.PrimitiveDecimalValue) || nextIntegerValue(true)
+        || nextDoubleValue() || nextDecimalValue() || nextIntegerValue(true)
         || nextJsonString()
         || nextJsonArrayOrObject();
   }
@@ -566,25 +641,42 @@ public class UriTokenizer {
     return nextJsonString() && nextCharacter(':') && nextJsonValue();
   }
 
+  /**
+   * Moves past a JSON array or object if found; otherwise leaves the index unchanged.
+   * @return whether a JSON array or object has been found at the current index
+   */
   private boolean nextJsonArrayOrObject() {
+    final int lastGoodIndex = index;
     if (nextCharacter('[')) {
       if (nextJsonValue()) {
         while (nextCharacter(',')) {
           if (!nextJsonValue()) {
+            index = lastGoodIndex;
             return false;
           }
         }
       }
-      return nextCharacter(']');
+      if (nextCharacter(']')) {
+        return true;
+      } else {
+        index = lastGoodIndex;
+        return false;
+      }
     } else if (nextCharacter('{')) {
       if (nextJsonMember()) {
         while (nextCharacter(',')) {
           if (!nextJsonMember()) {
+            index = lastGoodIndex;
             return false;
           }
         }
       }
-      return nextCharacter('}');
+      if (nextCharacter('}')) {
+        return true;
+      } else {
+        index = lastGoodIndex;
+        return false;
+      }
     } else {
       return false;
     }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d7e23bf8/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/UriInfoImplTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/UriInfoImplTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/UriInfoImplTest.java
new file mode 100644
index 0000000..4c76e96
--- /dev/null
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/UriInfoImplTest.java
@@ -0,0 +1,204 @@
+/*
+ * 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;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.apache.olingo.commons.api.edm.EdmEntityType;
+import org.apache.olingo.commons.api.ex.ODataRuntimeException;
+import org.apache.olingo.server.api.uri.UriInfo;
+import org.apache.olingo.server.api.uri.UriInfoKind;
+import org.apache.olingo.server.api.uri.UriResourceAction;
+import org.apache.olingo.server.api.uri.UriResourceEntitySet;
+import org.apache.olingo.server.api.uri.queryoption.AliasQueryOption;
+import org.apache.olingo.server.api.uri.queryoption.QueryOption;
+import org.apache.olingo.server.core.uri.UriInfoImpl;
+import org.apache.olingo.server.core.uri.UriResourceActionImpl;
+import org.apache.olingo.server.core.uri.UriResourceEntitySetImpl;
+import org.apache.olingo.server.core.uri.queryoption.AliasQueryOptionImpl;
+import org.apache.olingo.server.core.uri.queryoption.CountOptionImpl;
+import org.apache.olingo.server.core.uri.queryoption.CustomQueryOptionImpl;
+import org.apache.olingo.server.core.uri.queryoption.ExpandOptionImpl;
+import org.apache.olingo.server.core.uri.queryoption.FilterOptionImpl;
+import org.apache.olingo.server.core.uri.queryoption.FormatOptionImpl;
+import org.apache.olingo.server.core.uri.queryoption.IdOptionImpl;
+import org.apache.olingo.server.core.uri.queryoption.LevelsOptionImpl;
+import org.apache.olingo.server.core.uri.queryoption.OrderByOptionImpl;
+import org.apache.olingo.server.core.uri.queryoption.SearchOptionImpl;
+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.junit.Test;
+import org.mockito.Mockito;
+
+public class UriInfoImplTest {
+
+  @Test
+  public void kind() {
+    final UriInfo uriInfo = new UriInfoImpl().setKind(UriInfoKind.all);
+    assertEquals(UriInfoKind.all, uriInfo.getKind());
+  }
+
+  @Test
+  public void casts() {
+    final UriInfo uriInfo = new UriInfoImpl();
+
+    assertEquals(uriInfo, uriInfo.asUriInfoAll());
+    assertEquals(uriInfo, uriInfo.asUriInfoBatch());
+    assertEquals(uriInfo, uriInfo.asUriInfoCrossjoin());
+    assertEquals(uriInfo, uriInfo.asUriInfoEntityId());
+    assertEquals(uriInfo, uriInfo.asUriInfoMetadata());
+    assertEquals(uriInfo, uriInfo.asUriInfoResource());
+    assertEquals(uriInfo, uriInfo.asUriInfoService());
+  }
+
+  @Test
+  public void entityNames() {
+    final UriInfo uriInfo = new UriInfoImpl()
+        .addEntitySetName("A")
+        .addEntitySetName("B");
+    assertArrayEquals(new String[] { "A", "B" }, uriInfo.getEntitySetNames().toArray());
+  }
+
+  @Test
+  public void resourceParts() {
+    UriInfoImpl uriInfo = new UriInfoImpl();
+
+    final UriResourceAction action = new UriResourceActionImpl();
+    final UriResourceEntitySet entitySet0 = new UriResourceEntitySetImpl();
+    final UriResourceEntitySet entitySet1 = new UriResourceEntitySetImpl();
+
+    uriInfo.addResourcePart(action);
+    uriInfo.addResourcePart(entitySet0);
+
+    assertEquals(action, uriInfo.getUriResourceParts().get(0));
+    assertEquals(entitySet0, uriInfo.getUriResourceParts().get(1));
+
+    assertEquals(entitySet0, uriInfo.getLastResourcePart());
+
+    uriInfo.addResourcePart(entitySet1);
+    assertEquals(entitySet1, uriInfo.getLastResourcePart());
+  }
+
+  @Test(expected = ODataRuntimeException.class)
+  public void doubleSystemQueryOptions() {
+    new UriInfoImpl()
+        .setSystemQueryOption(new FormatOptionImpl())
+        .setSystemQueryOption(new FormatOptionImpl());
+  }
+
+  @Test
+  public void customQueryOption() {
+    final QueryOption expand = new ExpandOptionImpl().setName("");
+    final QueryOption filter = new FilterOptionImpl().setName("");
+    final QueryOption format = new FormatOptionImpl().setName("");
+    final QueryOption id = new IdOptionImpl().setName("");
+    final QueryOption inlinecount = new CountOptionImpl().setName("");
+    final QueryOption orderby = new OrderByOptionImpl().setName("");
+    final QueryOption search = new SearchOptionImpl().setName("");
+    final QueryOption select = new SelectOptionImpl().setName("");
+    final QueryOption skip = new SkipOptionImpl().setName("");
+    final QueryOption skipToken = new SkipTokenOptionImpl().setName("");
+    final QueryOption top = new TopOptionImpl().setName("");
+    final QueryOption levels = new LevelsOptionImpl().setName("");
+
+    final QueryOption customOption0 = new CustomQueryOptionImpl().setName("").setText("A");
+    final QueryOption customOption1 = new CustomQueryOptionImpl().setName("").setText("B");
+
+    final QueryOption initialQueryOption = new CustomQueryOptionImpl();
+
+    final QueryOption alias = new AliasQueryOptionImpl().setName("alias").setText("C");
+
+    final UriInfo uriInfo = new UriInfoImpl()
+        .setQueryOptions(Arrays.asList(
+            expand,
+            filter,
+            format,
+            id,
+            inlinecount,
+            orderby,
+            search,
+            select,
+            skip,
+            skipToken,
+            top,
+            customOption0,
+            customOption1,
+            levels,
+            initialQueryOption,
+            alias));
+
+    assertEquals(12, uriInfo.getSystemQueryOptions().size());
+    assertEquals(expand, uriInfo.getExpandOption());
+    assertEquals(filter, uriInfo.getFilterOption());
+    assertEquals(format, uriInfo.getFormatOption());
+    assertEquals(id, uriInfo.getIdOption());
+    assertEquals(inlinecount, uriInfo.getCountOption());
+    assertEquals(orderby, uriInfo.getOrderByOption());
+    assertEquals(search, uriInfo.getSearchOption());
+    assertEquals(select, uriInfo.getSelectOption());
+    assertEquals(skip, uriInfo.getSkipOption());
+    assertEquals(skipToken, uriInfo.getSkipTokenOption());
+    assertEquals(top, uriInfo.getTopOption());
+
+    assertArrayEquals(new QueryOption[] { alias }, uriInfo.getAliases().toArray());
+    assertEquals("C", uriInfo.getValueForAlias("alias"));
+
+    assertArrayEquals(new QueryOption[] { customOption0, customOption1, initialQueryOption },
+        uriInfo.getCustomQueryOptions().toArray());
+  }
+
+  @Test
+  public void fragment() {
+    final UriInfo uriInfo = new UriInfoImpl().setFragment("F");
+    assertEquals("F", uriInfo.getFragment());
+  }
+
+  @Test
+  public void entityTypeCast() {
+    final EdmEntityType entityType = Mockito.mock(EdmEntityType.class);
+    final UriInfo uriInfo = new UriInfoImpl()
+        .setEntityTypeCast(entityType);
+    assertEquals(entityType, uriInfo.getEntityTypeCast());
+  }
+
+  @Test
+  public void alias() {
+    final UriInfo uriInfo = new UriInfoImpl()
+        .addAlias((AliasQueryOption) new AliasQueryOptionImpl().setName("A").setText("notUsed"))
+        .addAlias((AliasQueryOption) new AliasQueryOptionImpl().setName("A").setText("X"))
+        .addAlias((AliasQueryOption) new AliasQueryOptionImpl().setName("B").setText("Y"))
+        .addAlias((AliasQueryOption) new AliasQueryOptionImpl().setName("C").setText("Z"));
+
+    assertEquals(3, uriInfo.getAliases().size());
+    assertEquals("X", uriInfo.getValueForAlias("A"));
+    assertEquals("Y", uriInfo.getValueForAlias("B"));
+    assertEquals("Z", uriInfo.getValueForAlias("C"));
+    assertNull(uriInfo.getValueForAlias("D"));
+
+    assertTrue(uriInfo.getSystemQueryOptions().isEmpty());
+    assertTrue(uriInfo.getCustomQueryOptions().isEmpty());
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d7e23bf8/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriDecoderTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriDecoderTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriDecoderTest.java
new file mode 100644
index 0000000..20ab94f
--- /dev/null
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriDecoderTest.java
@@ -0,0 +1,94 @@
+/*
+ * 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 static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.olingo.server.api.uri.queryoption.QueryOption;
+import org.junit.Test;
+
+public class UriDecoderTest {
+
+  @Test
+  public void split() throws Exception {
+    assertTrue(UriDecoder.splitAndDecodePath("").isEmpty());
+    assertTrue(UriDecoder.splitAndDecodePath("/").isEmpty());
+    assertEquals(Arrays.asList("a"), UriDecoder.splitAndDecodePath("a"));
+    assertEquals(Arrays.asList("a"), UriDecoder.splitAndDecodePath("a/"));
+    assertEquals(Arrays.asList("a"), UriDecoder.splitAndDecodePath("/a"));
+    assertEquals(Arrays.asList("a", "a"), UriDecoder.splitAndDecodePath("a/a"));
+    assertEquals(Arrays.asList("a", "a"), UriDecoder.splitAndDecodePath("/a/a"));
+  }
+
+  @Test
+  public void path() throws Exception {
+    assertEquals(Arrays.asList("a", "entitySet('/')", "bcd"),
+        UriDecoder.splitAndDecodePath("a/entitySet('%2F')/b%63d"));
+  }
+
+  @Test
+  public void options() throws Exception {
+    assertTrue(UriDecoder.splitAndDecodeOptions("").isEmpty());
+
+    checkOption("a", "a", "");
+    checkOption("a=b", "a", "b");
+    checkOption("=", "", "");
+    checkOption("=b", "", "b");
+
+    checkOption("a&c", "a", "");
+    checkOption("a&c", "c", "");
+
+    checkOption("a=b&c", "a", "b");
+    checkOption("a=b&c", "c", "");
+
+    checkOption("a=b&c=d", "a", "b");
+    checkOption("a=b&c=d", "c", "d");
+
+    checkOption("=&=", "", "");
+    assertEquals(2, UriDecoder.splitAndDecodeOptions("=&=").size());
+
+    checkOption("=&c=d", "", "");
+    checkOption("=&c=d", "c", "d");
+
+    checkOption("a%62c=d%65f", "abc", "def");
+    checkOption("a='%26%3D'", "a", "'&='");
+  }
+
+  @Test(expected = UriParserSyntaxException.class)
+  public void wrongPercentEncoding() throws Exception {
+    UriDecoder.splitAndDecodePath("%wrong");
+  }
+
+  private void checkOption(final String query, final String name, final String value)
+      throws UriParserSyntaxException {
+    final List<QueryOption> options = UriDecoder.splitAndDecodeOptions(query);
+    for (final QueryOption option : options) {
+      if (option.getName().equals(name)) {
+        assertEquals(value, option.getText());
+        return;
+      }
+    }
+    fail("Option " + name + " not found!");
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d7e23bf8/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java
index a9e97ce..177a396 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java
@@ -51,7 +51,7 @@ public class UriTokenizerTest {
 
   @Test
   public void sequence() {
-    final UriTokenizer tokenizer = new UriTokenizer("(A=1,B=2);");
+    final UriTokenizer tokenizer = new UriTokenizer("(A=1,B=2);.*/+");
     assertTrue(tokenizer.next(TokenKind.OPEN));
     assertFalse(tokenizer.next(TokenKind.OPEN));
     assertTrue(tokenizer.next(TokenKind.ODataIdentifier));
@@ -68,6 +68,10 @@ public class UriTokenizerTest {
     assertFalse(tokenizer.next(TokenKind.EOF));
     assertTrue(tokenizer.next(TokenKind.CLOSE));
     assertTrue(tokenizer.next(TokenKind.SEMI));
+    assertTrue(tokenizer.next(TokenKind.DOT));
+    assertTrue(tokenizer.next(TokenKind.STAR));
+    assertTrue(tokenizer.next(TokenKind.SLASH));
+    assertTrue(tokenizer.next(TokenKind.PLUS));
     assertTrue(tokenizer.next(TokenKind.EOF));
   }
 
@@ -100,8 +104,10 @@ public class UriTokenizerTest {
   public void qualifiedName() {
     assertTrue(new UriTokenizer("namespace.name").next(TokenKind.QualifiedName));
 
-    final UriTokenizer tokenizer = new UriTokenizer("multi.part.namespace.name");
+    final UriTokenizer tokenizer = new UriTokenizer("multi.part.namespace.name.1");
     assertTrue(tokenizer.next(TokenKind.QualifiedName));
+    assertTrue(tokenizer.next(TokenKind.DOT));
+    assertTrue(tokenizer.next(TokenKind.PrimitiveIntegerValue));
     assertTrue(tokenizer.next(TokenKind.EOF));
 
     assertFalse(new UriTokenizer("name").next(TokenKind.QualifiedName));
@@ -334,6 +340,7 @@ public class UriTokenizerTest {
     assertFalse(new UriTokenizer("[,1]").next(TokenKind.jsonArrayOrObject));
     assertFalse(new UriTokenizer("[1,,2]").next(TokenKind.jsonArrayOrObject));
     assertFalse(new UriTokenizer("[1,x]").next(TokenKind.jsonArrayOrObject));
+    assertFalse(new UriTokenizer("[+\"x\"]").next(TokenKind.jsonArrayOrObject));
     assertFalse(new UriTokenizer("{\"name\":1,}").next(TokenKind.jsonArrayOrObject));
     assertFalse(new UriTokenizer("{,\"name\":1}").next(TokenKind.jsonArrayOrObject));
     assertFalse(new UriTokenizer("{\"name\":1,,\"name2\":2}").next(TokenKind.jsonArrayOrObject));
@@ -350,6 +357,7 @@ public class UriTokenizerTest {
     assertFalse(new UriTokenizer("[\"\\u1\"]").next(TokenKind.jsonArrayOrObject));
     assertFalse(new UriTokenizer("[\"\\u12x\"]").next(TokenKind.jsonArrayOrObject));
     assertFalse(new UriTokenizer("[\"\\u123x\"]").next(TokenKind.jsonArrayOrObject));
+    wrongToken(TokenKind.jsonArrayOrObject, "[{\"name\":+123.456},null]", '\\');
   }
 
   private void wrongToken(final TokenKind kind, final String value, final char disturbCharacter) {
@@ -358,6 +366,7 @@ public class UriTokenizerTest {
     final UriTokenizer tokenizer = new UriTokenizer(value + disturbCharacter);
     assertTrue(tokenizer.next(kind));
     assertEquals(value, tokenizer.getText());
+    assertFalse(tokenizer.next(TokenKind.EOF));
 
     // Place the disturbing character at every position in the value string
     // and check that this leads to a failed token recognition.

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d7e23bf8/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/UriInfoImplTest.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/UriInfoImplTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/UriInfoImplTest.java
deleted file mode 100644
index 20bdade..0000000
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/UriInfoImplTest.java
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * 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;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import java.util.Arrays;
-import java.util.Collections;
-
-import org.apache.olingo.commons.api.edm.Edm;
-import org.apache.olingo.commons.api.edm.EdmEntityType;
-import org.apache.olingo.commons.api.ex.ODataRuntimeException;
-import org.apache.olingo.server.api.OData;
-import org.apache.olingo.server.api.edmx.EdmxReference;
-import org.apache.olingo.server.api.uri.UriInfo;
-import org.apache.olingo.server.api.uri.UriInfoKind;
-import org.apache.olingo.server.api.uri.UriResourceAction;
-import org.apache.olingo.server.api.uri.UriResourceEntitySet;
-import org.apache.olingo.server.api.uri.queryoption.AliasQueryOption;
-import org.apache.olingo.server.api.uri.queryoption.QueryOption;
-import org.apache.olingo.server.core.uri.queryoption.AliasQueryOptionImpl;
-import org.apache.olingo.server.core.uri.queryoption.CountOptionImpl;
-import org.apache.olingo.server.core.uri.queryoption.CustomQueryOptionImpl;
-import org.apache.olingo.server.core.uri.queryoption.ExpandOptionImpl;
-import org.apache.olingo.server.core.uri.queryoption.FilterOptionImpl;
-import org.apache.olingo.server.core.uri.queryoption.FormatOptionImpl;
-import org.apache.olingo.server.core.uri.queryoption.IdOptionImpl;
-import org.apache.olingo.server.core.uri.queryoption.LevelsOptionImpl;
-import org.apache.olingo.server.core.uri.queryoption.OrderByOptionImpl;
-import org.apache.olingo.server.core.uri.queryoption.SearchOptionImpl;
-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.tecsvc.provider.EdmTechProvider;
-import org.apache.olingo.server.tecsvc.provider.EntityTypeProvider;
-import org.junit.Test;
-
-public class UriInfoImplTest {
-
-  private static final Edm edm = OData.newInstance().createServiceMetadata(
-      new EdmTechProvider(), Collections.<EdmxReference> emptyList()).getEdm();
-
-  @Test
-  public void kind() {
-    final UriInfo uriInfo = new UriInfoImpl().setKind(UriInfoKind.all);
-    assertEquals(UriInfoKind.all, uriInfo.getKind());
-  }
-
-  @Test
-  public void casts() {
-    final UriInfo uriInfo = new UriInfoImpl();
-
-    assertEquals(uriInfo, uriInfo.asUriInfoAll());
-    assertEquals(uriInfo, uriInfo.asUriInfoBatch());
-    assertEquals(uriInfo, uriInfo.asUriInfoCrossjoin());
-    assertEquals(uriInfo, uriInfo.asUriInfoEntityId());
-    assertEquals(uriInfo, uriInfo.asUriInfoMetadata());
-    assertEquals(uriInfo, uriInfo.asUriInfoResource());
-    assertEquals(uriInfo, uriInfo.asUriInfoService());
-  }
-
-  @Test
-  public void entityNames() {
-    final UriInfo uriInfo = new UriInfoImpl()
-        .addEntitySetName("A")
-        .addEntitySetName("B");
-    assertArrayEquals(new String[] { "A", "B" }, uriInfo.getEntitySetNames().toArray());
-  }
-
-  @Test
-  public void resourceParts() {
-    UriInfoImpl uriInfo = new UriInfoImpl();
-
-    final UriResourceAction action = new UriResourceActionImpl();
-    final UriResourceEntitySet entitySet0 = new UriResourceEntitySetImpl();
-    final UriResourceEntitySet entitySet1 = new UriResourceEntitySetImpl();
-
-    uriInfo.addResourcePart(action);
-    uriInfo.addResourcePart(entitySet0);
-
-    assertEquals(action, uriInfo.getUriResourceParts().get(0));
-    assertEquals(entitySet0, uriInfo.getUriResourceParts().get(1));
-
-    assertEquals(entitySet0, uriInfo.getLastResourcePart());
-
-    uriInfo.addResourcePart(entitySet1);
-    assertEquals(entitySet1, uriInfo.getLastResourcePart());
-  }
-
-  @Test(expected = ODataRuntimeException.class)
-  public void doubleSystemQueryOptions() {
-    new UriInfoImpl()
-        .setSystemQueryOption(new FormatOptionImpl())
-        .setSystemQueryOption(new FormatOptionImpl());
-  }
-
-  @Test
-  public void customQueryOption() {
-    final QueryOption expand = new ExpandOptionImpl().setName("");
-    final QueryOption filter = new FilterOptionImpl().setName("");
-    final QueryOption format = new FormatOptionImpl().setName("");
-    final QueryOption id = new IdOptionImpl().setName("");
-    final QueryOption inlinecount = new CountOptionImpl().setName("");
-    final QueryOption orderby = new OrderByOptionImpl().setName("");
-    final QueryOption search = new SearchOptionImpl().setName("");
-    final QueryOption select = new SelectOptionImpl().setName("");
-    final QueryOption skip = new SkipOptionImpl().setName("");
-    final QueryOption skipToken = new SkipTokenOptionImpl().setName("");
-    final QueryOption top = new TopOptionImpl().setName("");
-    final QueryOption levels = new LevelsOptionImpl().setName("");
-
-    final QueryOption customOption0 = new CustomQueryOptionImpl().setName("").setText("A");
-    final QueryOption customOption1 = new CustomQueryOptionImpl().setName("").setText("B");
-
-    final QueryOption initialQueryOption = new CustomQueryOptionImpl();
-
-    final QueryOption alias = new AliasQueryOptionImpl().setName("alias").setText("C");
-
-    final UriInfo uriInfo = new UriInfoImpl()
-        .setQueryOptions(Arrays.asList(
-            expand,
-            filter,
-            format,
-            id,
-            inlinecount,
-            orderby,
-            search,
-            select,
-            skip,
-            skipToken,
-            top,
-            customOption0,
-            customOption1,
-            levels,
-            initialQueryOption,
-            alias));
-
-    assertEquals(12, uriInfo.getSystemQueryOptions().size());
-    assertEquals(expand, uriInfo.getExpandOption());
-    assertEquals(filter, uriInfo.getFilterOption());
-    assertEquals(format, uriInfo.getFormatOption());
-    assertEquals(id, uriInfo.getIdOption());
-    assertEquals(inlinecount, uriInfo.getCountOption());
-    assertEquals(orderby, uriInfo.getOrderByOption());
-    assertEquals(search, uriInfo.getSearchOption());
-    assertEquals(select, uriInfo.getSelectOption());
-    assertEquals(skip, uriInfo.getSkipOption());
-    assertEquals(skipToken, uriInfo.getSkipTokenOption());
-    assertEquals(top, uriInfo.getTopOption());
-
-    assertArrayEquals(new QueryOption[] { alias }, uriInfo.getAliases().toArray());
-    assertEquals("C", uriInfo.getValueForAlias("alias"));
-
-    assertArrayEquals(new QueryOption[] { customOption0, customOption1, initialQueryOption },
-        uriInfo.getCustomQueryOptions().toArray());
-  }
-
-  @Test
-  public void fragment() {
-    final UriInfo uriInfo = new UriInfoImpl().setFragment("F");
-    assertEquals("F", uriInfo.getFragment());
-  }
-
-  @Test
-  public void entityTypeCast() {
-    final EdmEntityType entityType = edm.getEntityType(EntityTypeProvider.nameETKeyNav);
-    assertNotNull(entityType);
-
-    final UriInfo uriInfo = new UriInfoImpl()
-        .setEntityTypeCast(entityType);
-    assertEquals(entityType, uriInfo.getEntityTypeCast());
-  }
-
-  @Test
-  public void alias() {
-    final UriInfo uriInfo = new UriInfoImpl()
-        .addAlias((AliasQueryOption) new AliasQueryOptionImpl().setName("A").setText("notUsed"))
-        .addAlias((AliasQueryOption) new AliasQueryOptionImpl().setName("A").setText("X"))
-        .addAlias((AliasQueryOption) new AliasQueryOptionImpl().setName("B").setText("Y"))
-        .addAlias((AliasQueryOption) new AliasQueryOptionImpl().setName("C").setText("Z"));
-
-    assertEquals(3, uriInfo.getAliases().size());
-    assertEquals("X", uriInfo.getValueForAlias("A"));
-    assertEquals("Y", uriInfo.getValueForAlias("B"));
-    assertEquals("Z", uriInfo.getValueForAlias("C"));
-    assertNull(uriInfo.getValueForAlias("D"));
-
-    assertTrue(uriInfo.getSystemQueryOptions().isEmpty());
-    assertTrue(uriInfo.getCustomQueryOptions().isEmpty());
-  }
-}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d7e23bf8/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java
index 11acede..e9f1c07 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java
@@ -40,18 +40,19 @@ import org.apache.olingo.server.api.uri.UriResourceKind;
 import org.apache.olingo.server.api.uri.queryoption.expression.BinaryOperatorKind;
 import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind;
 import org.apache.olingo.server.core.uri.parser.UriParserException;
-import org.apache.olingo.server.core.uri.parser.UriParserSemanticException;
 import org.apache.olingo.server.core.uri.parser.UriParserSemanticException.MessageKeys;
 import org.apache.olingo.server.core.uri.parser.UriParserSyntaxException;
 import org.apache.olingo.server.core.uri.parser.search.SearchParserException;
 import org.apache.olingo.server.core.uri.testutil.FilterValidator;
 import org.apache.olingo.server.core.uri.testutil.TestUriValidator;
 import org.apache.olingo.server.core.uri.validator.UriValidationException;
+import org.apache.olingo.server.tecsvc.provider.ActionProvider;
 import org.apache.olingo.server.tecsvc.provider.ComplexTypeProvider;
 import org.apache.olingo.server.tecsvc.provider.ContainerProvider;
 import org.apache.olingo.server.tecsvc.provider.EdmTechProvider;
 import org.apache.olingo.server.tecsvc.provider.EntityTypeProvider;
 import org.apache.olingo.server.tecsvc.provider.EnumTypeProvider;
+import org.apache.olingo.server.tecsvc.provider.FunctionProvider;
 import org.apache.olingo.server.tecsvc.provider.PropertyProvider;
 import org.apache.olingo.server.tecsvc.provider.TypeDefinitionProvider;
 import org.junit.Ignore;
@@ -2731,17 +2732,6 @@ public class TestFullResourcePath {
         .isNavProperty("NavPropertyETKeyNavOne", EntityTypeProvider.nameETKeyNav, false)
         .isType(EntityTypeProvider.nameETKeyNav);
 
-    testUri.run("ESTwoKeyNav(PropertyInt16=1,PropertyString='2')", "$select=olingo.odata.test1.ETBaseTwoKeyNav"
-        + "/PropertyInt16")
-        .isKind(UriInfoKind.resource).goPath()
-        .first()
-        .isKeyPredicate(0, "PropertyInt16", "1")
-        .isKeyPredicate(1, "PropertyString", "'2'")
-        .isSelectStartType(0, EntityTypeProvider.nameETBaseTwoKeyNav)
-        .goSelectItem(0)
-        .first()
-        .isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
-
     testUri.run("ESKeyNav", "$expand=NavPropertyETKeyNavOne($select=PropertyInt16)")
         .isKind(UriInfoKind.resource)
         .goPath().first()
@@ -2763,17 +2753,6 @@ public class TestFullResourcePath {
         .goUpExpandValidator()
         .isSelectText("PropertyCompNav/PropertyInt16");
 
-    testUri.run("ESMixEnumDefCollComp",
-        "$select=PropertyEnumString,PropertyDefString,CollPropertyEnumString,CollPropertyDefString")
-        .isKind(UriInfoKind.resource)
-        .goSelectItemPath(0).isPrimitiveProperty("PropertyEnumString", EnumTypeProvider.nameENString, false)
-        .goUpUriValidator()
-        .goSelectItemPath(1).isPrimitiveProperty("PropertyDefString", TypeDefinitionProvider.nameTDString, false)
-        .goUpUriValidator()
-        .goSelectItemPath(2).isPrimitiveProperty("CollPropertyEnumString", EnumTypeProvider.nameENString, true)
-        .goUpUriValidator()
-        .goSelectItemPath(3).isPrimitiveProperty("CollPropertyDefString", TypeDefinitionProvider.nameTDString, true);
-
     testUri.runEx("ESKeyNav", "$expand=undefined")
         .isExSemantic(MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
     testUri.runEx("ESTwoKeyNav", "$expand=PropertyCompNav/undefined")
@@ -2815,6 +2794,134 @@ public class TestFullResourcePath {
   }
 
   @Test
+  public void select() throws Exception {
+    testUri.run("ESTwoKeyNav", "$select=*")
+        .isSelectItemStar(0);
+
+    testUri.run("ESTwoKeyNav", "$select=olingo.odata.test1.*")
+        .isSelectItemAllOp(0, new FullQualifiedName("olingo.odata.test1", "*"));
+    testUri.run("ESTwoKeyNav", "$select=Namespace1_Alias.*")
+        .isSelectItemAllOp(0, new FullQualifiedName("Namespace1_Alias", "*"));
+
+    testUri.run("ESTwoKeyNav", "$select=PropertyString")
+        .goSelectItemPath(0).isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
+
+    testUri.run("ESTwoKeyNav", "$select=PropertyComp")
+        .goSelectItemPath(0).isComplexProperty("PropertyComp", ComplexTypeProvider.nameCTPrimComp, false);
+
+    testUri.run("ESAllPrim", "$select=PropertyTimeOfDay,PropertyDate,NavPropertyETTwoPrimOne")
+        .isKind(UriInfoKind.resource)
+        .goSelectItemPath(0).first().isPrimitiveProperty("PropertyTimeOfDay", PropertyProvider.nameTimeOfDay, false)
+        .goUpUriValidator()
+        .goSelectItemPath(1).first().isPrimitiveProperty("PropertyDate", PropertyProvider.nameDate, false)
+        .goUpUriValidator()
+        .goSelectItemPath(2).first().isNavProperty("NavPropertyETTwoPrimOne", EntityTypeProvider.nameETTwoPrim, false);
+
+    testUri.run("ESMixEnumDefCollComp",
+        "$select=PropertyEnumString,PropertyDefString,CollPropertyEnumString,CollPropertyDefString")
+        .isKind(UriInfoKind.resource)
+        .goSelectItemPath(0).isPrimitiveProperty("PropertyEnumString", EnumTypeProvider.nameENString, false)
+        .goUpUriValidator()
+        .goSelectItemPath(1).isPrimitiveProperty("PropertyDefString", TypeDefinitionProvider.nameTDString, false)
+        .goUpUriValidator()
+        .goSelectItemPath(2).isPrimitiveProperty("CollPropertyEnumString", EnumTypeProvider.nameENString, true)
+        .goUpUriValidator()
+        .goSelectItemPath(3).isPrimitiveProperty("CollPropertyDefString", TypeDefinitionProvider.nameTDString, true);
+
+    testUri.run("ESTwoKeyNav", "$select=PropertyComp/PropertyInt16")
+        .goSelectItemPath(0)
+        .first()
+        .isComplexProperty("PropertyComp", ComplexTypeProvider.nameCTPrimComp, false)
+        .n()
+        .isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
+
+    testUri.run("ESTwoKeyNav", "$select=PropertyComp/PropertyComp")
+        .goSelectItemPath(0)
+        .first()
+        .isComplexProperty("PropertyComp", ComplexTypeProvider.nameCTPrimComp, false)
+        .n()
+        .isComplexProperty("PropertyComp", ComplexTypeProvider.nameCTAllPrim, false);
+
+    testUri.run("ESTwoKeyNav", "$select=olingo.odata.test1.ETBaseTwoKeyNav")
+        .isSelectStartType(0, EntityTypeProvider.nameETBaseTwoKeyNav);
+
+    testUri.run("ESTwoKeyNav(PropertyInt16=1,PropertyString='2')",
+        "$select=olingo.odata.test1.ETBaseTwoKeyNav/PropertyInt16")
+        .isKind(UriInfoKind.resource).goPath()
+        .first()
+        .isKeyPredicate(0, "PropertyInt16", "1")
+        .isKeyPredicate(1, "PropertyString", "'2'")
+        .isSelectStartType(0, EntityTypeProvider.nameETBaseTwoKeyNav)
+        .goSelectItem(0)
+        .first()
+        .isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
+
+    testUri.run("ESTwoKeyNav(PropertyInt16=1,PropertyString='1')/PropertyCompNav",
+        "$select=olingo.odata.test1.CTTwoBasePrimCompNav")
+        .isSelectStartType(0, ComplexTypeProvider.nameCTTwoBasePrimCompNav);
+
+    testUri.run("ESTwoKeyNav", "$select=PropertyCompNav/olingo.odata.test1.CTTwoBasePrimCompNav")
+        .goSelectItemPath(0)
+        .first()
+        .isComplexProperty("PropertyCompNav", ComplexTypeProvider.nameCTBasePrimCompNav, false)
+        .isTypeFilter(ComplexTypeProvider.nameCTTwoBasePrimCompNav);
+
+    testUri.run("ESTwoKeyNav", "$select=PropertyCompNav/Namespace1_Alias.CTTwoBasePrimCompNav/PropertyInt16")
+        .goSelectItemPath(0)
+        .first()
+        .isComplexProperty("PropertyCompNav", ComplexTypeProvider.nameCTBasePrimCompNav, false)
+        .isTypeFilter(ComplexTypeProvider.nameCTTwoBasePrimCompNav)
+        .n()
+        .isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
+
+    testUri.run("ESAllPrim", "$select=olingo.odata.test1.BAESAllPrimRTETAllPrim")
+        .goSelectItemPath(0)
+        .first()
+        .isAction(ActionProvider.nameBAESAllPrimRTETAllPrim.getName());
+    testUri.run("ESTwoKeyNav", "$select=Namespace1_Alias.BFCESTwoKeyNavRTString")
+        .goSelectItemPath(0)
+        .first()
+        .isFunction(FunctionProvider.nameBFCESTwoKeyNavRTString.getName());
+    testUri.run("ESTwoKeyNav", "$select=olingo.odata.test1.BFCESTwoKeyNavRTStringParam(ParameterComp)")
+        .goSelectItemPath(0)
+        .first()
+        .isFunction(FunctionProvider.nameBFCESTwoKeyNavRTStringParam.getName());
+
+    testUri.runEx("ESMixPrimCollComp", "$select=wrong")
+        .isExSemantic(MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
+    testUri.runEx("ESMixPrimCollComp", "$select=PropertyComp/wrong")
+        .isExSemantic(MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
+    testUri.runEx("ESMixPrimCollComp", "$select=PropertyComp///PropertyInt16")
+        .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
+    testUri.runEx("ESMixPrimCollComp", "$select=/PropertyInt16")
+        .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
+    testUri.runEx("ESMixPrimCollComp", "$select=PropertyInt16+")
+        .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION);
+    testUri.runEx("ESTwoKeyNav", "$select=olingo.odata.test1.1")
+        .isExSemantic(MessageKeys.UNKNOWN_PART);
+    testUri.runEx("ESTwoKeyNav", "$select=olingo.odata.test1.ETKeyNav")
+        .isExSemantic(MessageKeys.INCOMPATIBLE_TYPE_FILTER);
+    testUri.runEx("ESTwoKeyNav", "$select=PropertyCompNav/olingo.odata.test1.CTTwoPrim")
+        .isExSemantic(MessageKeys.INCOMPATIBLE_TYPE_FILTER);
+    testUri.runEx("ESTwoKeyNav", "$select=PropertyCompNav/olingo.odata.test1.CTwrong")
+        .isExSemantic(MessageKeys.UNKNOWN_TYPE);
+    testUri.runEx("ESTwoKeyNav", "$select=PropertyCompNav/.")
+        .isExSemantic(MessageKeys.UNKNOWN_PART);
+    testUri.runEx("ESTwoKeyNav", "$select=PropertyCompNav/olingo.odata.test1.CTTwoBasePrimCompNav/.")
+        .isExSemantic(MessageKeys.UNKNOWN_PART);
+    testUri.runEx("AIRT", "$select=wrong")
+        .isExSemantic(MessageKeys.ONLY_FOR_TYPED_PARTS);
+    testUri.runEx("AIRT", "$select=olingo.odata.test1.BAESAllPrimRT")
+        .isExSemantic(MessageKeys.ONLY_FOR_TYPED_PARTS);
+    testUri.runEx("ESTwoKeyNav", "$select=olingo.odata.test1.BFwrong")
+        .isExSemantic(MessageKeys.UNKNOWN_PART);
+    testUri.runEx("ESTwoKeyNav", "$select=olingo.odata.test1.BFCESTwoKeyNavRTStringParam()")
+        .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
+    testUri.runEx("ESTwoKeyNav", "$select=Namespace1_Alias.BFCESTwoKeyNavRTStringParam(ParameterComp,...)")
+        .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
+  }
+
+  @Test
   public void runTop() throws Exception {
     // top
     testUri.run("ESKeyNav", "$top=1")
@@ -5950,7 +6057,7 @@ public class TestFullResourcePath {
 
     testUri.runEx("ESTwoKeyNav/olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
         + "(ParameterComp={\"PropertyInt16\":1,\"PropertyString\":\"Test\"})")
-        .isExSemantic(UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE);
+        .isExSemantic(MessageKeys.INVALID_KEY_VALUE);
 
     testUri.runEx("FICRTCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=null)")
         .isExValidation(UriValidationException.MessageKeys.MISSING_PARAMETER);
@@ -5964,7 +6071,7 @@ public class TestFullResourcePath {
     testUri.run("FICRTCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test)", "@test='null'");
 
     testUri.runEx("FICRTCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test,UnknownParam=1)", "@test='null'")
-        .isExSemantic(UriParserSemanticException.MessageKeys.FUNCTION_NOT_FOUND);
+        .isExSemantic(MessageKeys.FUNCTION_NOT_FOUND);
 
     testUri.run("FICRTCollCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test)", "@test='null'");
     testUri.run("FICRTCollCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test)", "@test=null");
@@ -5975,7 +6082,7 @@ public class TestFullResourcePath {
         .isExSyntax(UriParserSyntaxException.MessageKeys.DUPLICATED_ALIAS);
 
     testUri.runEx("ESAllPrim", "$filter=FINRTInt16() eq 0")
-        .isExSemantic(UriParserSemanticException.MessageKeys.FUNCTION_IMPORT_NOT_ALLOWED);
+        .isExSemantic(MessageKeys.FUNCTION_IMPORT_NOT_ALLOWED);
 
     testUri.runEx("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
         + "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":1,\"PropertyString\":\"1\"")

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d7e23bf8/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestUriParserImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestUriParserImpl.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestUriParserImpl.java
index e6612ff..19f5946 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestUriParserImpl.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestUriParserImpl.java
@@ -22,13 +22,11 @@ import java.util.Arrays;
 import java.util.Collections;
 
 import org.apache.olingo.commons.api.edm.Edm;
-import org.apache.olingo.commons.api.edm.FullQualifiedName;
 import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.edmx.EdmxReference;
 import org.apache.olingo.server.api.uri.UriInfoKind;
 import org.apache.olingo.server.api.uri.UriResourceKind;
 import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind;
-import org.apache.olingo.server.core.uri.parser.UriParserSemanticException;
 import org.apache.olingo.server.core.uri.parser.UriParserSyntaxException;
 import org.apache.olingo.server.core.uri.testutil.FilterValidator;
 import org.apache.olingo.server.core.uri.testutil.ResourceValidator;
@@ -1112,64 +1110,6 @@ public class TestUriParserImpl {
     .isMethod(MethodKind.GEOINTERSECTS, 2);
   }
 
-  @Test
-  public void testSelect() throws Exception {
-    testUri.run("ESTwoKeyNav", "$select=*")
-    .isSelectItemStar(0);
-
-    testUri.run("ESTwoKeyNav", "$select=olingo.odata.test1.*")
-    .isSelectItemAllOp(0, new FullQualifiedName("olingo.odata.test1", "*"));
-
-    testUri.run("ESTwoKeyNav", "$select=PropertyString")
-    .goSelectItemPath(0).isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
-
-    testUri.run("ESTwoKeyNav", "$select=PropertyComp")
-    .goSelectItemPath(0).isComplexProperty("PropertyComp", ComplexTypeProvider.nameCTPrimComp, false);
-
-    testUri.run("ESTwoKeyNav", "$select=PropertyComp/PropertyInt16")
-    .goSelectItemPath(0)
-    .first()
-    .isComplexProperty("PropertyComp", ComplexTypeProvider.nameCTPrimComp, false)
-    .n()
-    .isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
-
-    testUri.run("ESTwoKeyNav", "$select=PropertyComp/PropertyComp")
-    .goSelectItemPath(0)
-    .first()
-    .isComplexProperty("PropertyComp", ComplexTypeProvider.nameCTPrimComp, false)
-    .n()
-    .isComplexProperty("PropertyComp", ComplexTypeProvider.nameCTAllPrim, false);
-
-    testUri.run("ESTwoKeyNav", "$select=olingo.odata.test1.ETBaseTwoKeyNav")
-    .isSelectStartType(0, EntityTypeProvider.nameETBaseTwoKeyNav);
-
-    testUri.run("ESTwoKeyNav(PropertyInt16=1,PropertyString='1')/PropertyCompNav",
-        "$select=olingo.odata.test1.CTTwoBasePrimCompNav")
-        .isSelectStartType(0, ComplexTypeProvider.nameCTTwoBasePrimCompNav);
-
-    testUri.run("ESTwoKeyNav", "$select=PropertyCompNav/olingo.odata.test1.CTTwoBasePrimCompNav")
-    .goSelectItemPath(0)
-    .first()
-    .isComplexProperty("PropertyCompNav", ComplexTypeProvider.nameCTBasePrimCompNav, false)
-    .n()
-    .isTypeFilterOnCollection(ComplexTypeProvider.nameCTTwoBasePrimCompNav);
-
-    testUri.run("ESAllPrim", "$select=PropertyTimeOfDay,PropertyDate,PropertyTimeOfDay")
-    .isKind(UriInfoKind.resource)
-    .goSelectItemPath(0).first().isPrimitiveProperty("PropertyTimeOfDay", PropertyProvider.nameTimeOfDay, false)
-    .goUpUriValidator()
-    .goSelectItemPath(1).first().isPrimitiveProperty("PropertyDate", PropertyProvider.nameDate, false);
-
-    testUri.runEx("ESMixPrimCollComp", "$select=wrong")
-    .isExSemantic(UriParserSemanticException.MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
-    testUri.runEx("ESMixPrimCollComp", "$select=PropertyComp/wrong")
-    .isExSemantic(UriParserSemanticException.MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
-    testUri.runEx("ESMixPrimCollComp", "$select=PropertyComp///PropertyInt16")
-    .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
-    testUri.runEx("ESMixPrimCollComp", "$select=/PropertyInt16")
-    .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
-  }
-
   private final String encode(final String uriPart) {
     return uriPart.replaceAll(":", "%3A");
   }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d7e23bf8/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/RawUriTest.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/RawUriTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/RawUriTest.java
deleted file mode 100644
index c897400..0000000
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/RawUriTest.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * 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 static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-import org.junit.Test;
-
-public class RawUriTest {
-
-  private RawUri runRawParser(final String path, final String query, final int skipSegments)
-      throws UriParserSyntaxException {
-    return UriDecoder.decodeUri(path, query, null, skipSegments);
-  }
-
-  @Test
-  public void testOption() throws Exception {
-    RawUri rawUri;
-    rawUri = runRawParser("", "", 0);
-    checkOptionCount(rawUri, 0);
-
-    rawUri = runRawParser("", "a", 0);
-    checkOption(rawUri, 0, "a", "");
-
-    rawUri = runRawParser("", "a=b", 0);
-    checkOption(rawUri, 0, "a", "b");
-
-    rawUri = runRawParser("", "=", 0);
-    checkOption(rawUri, 0, "", "");
-
-    rawUri = runRawParser("", "=b", 0);
-    checkOption(rawUri, 0, "", "b");
-
-    rawUri = runRawParser("", "a&c", 0);
-    checkOption(rawUri, 0, "a", "");
-    checkOption(rawUri, 1, "c", "");
-
-    rawUri = runRawParser("", "a=b&c", 0);
-    checkOption(rawUri, 0, "a", "b");
-    checkOption(rawUri, 1, "c", "");
-
-    rawUri = runRawParser("", "a=b&c=d", 0);
-    checkOption(rawUri, 0, "a", "b");
-    checkOption(rawUri, 1, "c", "d");
-
-    rawUri = runRawParser("", "=&=", 0);
-    checkOption(rawUri, 0, "", "");
-    checkOption(rawUri, 1, "", "");
-
-    rawUri = runRawParser("", "=&c=d", 0);
-    checkOption(rawUri, 0, "", "");
-    checkOption(rawUri, 1, "c", "d");
-  }
-
-  private void checkOption(final RawUri rawUri, final int index, final String name, final String value) {
-    RawUri.QueryOption option = rawUri.queryOptionListDecoded.get(index);
-
-    assertEquals(name, option.name);
-    assertEquals(value, option.value);
-  }
-
-  private void checkOptionCount(final RawUri rawUri, final int count) {
-    assertEquals(count, rawUri.queryOptionListDecoded.size());
-  }
-
-  @Test
-  public void testPath() throws Exception {
-    RawUri rawUri;
-
-    rawUri = runRawParser("", null, 0);
-    checkPath(rawUri, "", Collections.<String> emptyList());
-
-    rawUri = runRawParser("/", null, 0);
-    checkPath(rawUri, "/", Collections.<String> emptyList());
-
-    rawUri = runRawParser("/entitySet", null, 0);
-    checkPath(rawUri, "/entitySet", Arrays.asList("entitySet"));
-
-    rawUri = runRawParser("//entitySet", null, 0);
-    checkPath(rawUri, "//entitySet", Arrays.asList("entitySet"));
-
-    rawUri = runRawParser("entitySet", null, 0);
-    checkPath(rawUri, "entitySet", Arrays.asList("entitySet"));
-
-    rawUri = runRawParser("/nonServiceSegment/entitySet", null, 0);
-    checkPath(rawUri, "/nonServiceSegment/entitySet", Arrays.asList("nonServiceSegment", "entitySet"));
-
-    rawUri = runRawParser("/nonServiceSegment/entitySet", null, 1);
-    checkPath(rawUri, "/nonServiceSegment/entitySet", Arrays.asList("entitySet"));
-
-    rawUri = runRawParser("nonServiceSegment/entitySet", null, 0);
-    checkPath(rawUri, "nonServiceSegment/entitySet", Arrays.asList("nonServiceSegment", "entitySet"));
-
-    rawUri = runRawParser("nonServiceSegment/entitySet", null, 1);
-    checkPath(rawUri, "nonServiceSegment/entitySet", Arrays.asList("entitySet"));
-
-    rawUri = runRawParser("non//Service/Segment///entitySet/", null, 3);
-    checkPath(rawUri, "non//Service/Segment///entitySet/", Arrays.asList("entitySet"));
-
-    rawUri = runRawParser("/a", "abc=xx+yz", 0);
-    checkPath(rawUri, "/a", Arrays.asList("a"));
-  }
-
-  @Test
-  public void testSplit() {
-    assertTrue(UriDecoder.splitSkipEmpty("", '/').isEmpty());
-    assertTrue(UriDecoder.splitSkipEmpty("/", '/').isEmpty());
-    assertEquals(Arrays.asList("a"), UriDecoder.splitSkipEmpty("a", '/'));
-    assertEquals(Arrays.asList("a"), UriDecoder.splitSkipEmpty("a/", '/'));
-    assertEquals(Arrays.asList("a"), UriDecoder.splitSkipEmpty("/a", '/'));
-    assertEquals(Arrays.asList("a", "a"), UriDecoder.splitSkipEmpty("a/a", '/'));
-    assertEquals(Arrays.asList("a", "a"), UriDecoder.splitSkipEmpty("/a/a", '/'));
-  }
-
-  private void checkPath(final RawUri rawUri, final String path, final List<String> list) {
-    assertEquals(path, rawUri.path);
-
-    assertEquals(list.size(), rawUri.pathSegmentListDecoded.size());
-
-    for (int i = 0; i < list.size(); i++) {
-      assertEquals(list.get(i), rawUri.pathSegmentListDecoded.get(i));
-    }
-  }
-
-  @Test(expected = UriParserSyntaxException.class)
-  public void wrongPercentEncoding() throws Exception {
-    runRawParser("%wrong", null, 0);
-  }
-}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d7e23bf8/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/ParserWithLogging.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/ParserWithLogging.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/ParserWithLogging.java
deleted file mode 100644
index 5ebc57e..0000000
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/ParserWithLogging.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.testutil;
-
-import org.antlr.v4.runtime.DefaultErrorStrategy;
-import org.antlr.v4.runtime.DiagnosticErrorListener;
-import org.apache.olingo.commons.api.edm.Edm;
-import org.apache.olingo.server.api.OData;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser;
-import org.apache.olingo.server.core.uri.parser.Parser;
-
-public class ParserWithLogging extends Parser {
-  TestErrorLogger errorCollector1;
-  TestErrorLogger errorCollector2;
-
-  public ParserWithLogging(final Edm edm, final OData odata) {
-    super(edm, odata);
-    errorCollector1 = new TestErrorLogger("Stage 1", 1);
-    errorCollector2 = new TestErrorLogger("Stage 2", 1);
-  }
-
-  @Override
-  protected void addStage2ErrorStategy(final UriParserParser parser) {
-    // Don't throw an at first syntax error, so the error listener will be called
-    parser.setErrorHandler(new DefaultErrorStrategy());
-  }
-
-  @Override
-  protected void addStage1ErrorListener(final UriParserParser parser) {
-    // Log error to console
-    parser.removeErrorListeners();
-    parser.addErrorListener(errorCollector1);
-    parser.addErrorListener(new DiagnosticErrorListener());
-  }
-
-  @Override
-  protected void addStage2ErrorListener(final UriParserParser parser) {
-    // Log error to console
-    parser.removeErrorListeners();
-    parser.addErrorListener(errorCollector2);
-    parser.addErrorListener(new DiagnosticErrorListener());
-  }
-}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d7e23bf8/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 d70b204..a9d25be 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
@@ -52,6 +52,7 @@ import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
 import org.apache.olingo.server.api.uri.queryoption.SelectItem;
 import org.apache.olingo.server.api.uri.queryoption.SelectOption;
 import org.apache.olingo.server.core.uri.UriResourceWithKeysImpl;
+import org.apache.olingo.server.core.uri.parser.Parser;
 import org.apache.olingo.server.core.uri.validator.UriValidationException;
 import org.apache.olingo.server.core.uri.validator.UriValidator;
 
@@ -85,7 +86,7 @@ public class ResourceValidator implements TestValidator {
   // --- Execution ---
 
   public ResourceValidator run(final String path) {
-    ParserWithLogging testParser = new ParserWithLogging(edm, odata);
+    Parser testParser = new Parser(edm, odata);
 
     UriInfo uriInfoTmp = null;
     uriPathInfo = null;

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d7e23bf8/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/TestErrorLogger.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/TestErrorLogger.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/TestErrorLogger.java
deleted file mode 100644
index 76b0d38..0000000
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/TestErrorLogger.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * 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.testutil;
-
-import java.util.BitSet;
-import java.util.Collections;
-import java.util.List;
-
-import org.antlr.v4.runtime.ANTLRErrorListener;
-import org.antlr.v4.runtime.Parser;
-import org.antlr.v4.runtime.RecognitionException;
-import org.antlr.v4.runtime.Recognizer;
-import org.antlr.v4.runtime.atn.ATNConfigSet;
-import org.antlr.v4.runtime.dfa.DFA;
-import org.apache.olingo.server.core.uri.antlr.UriLexer;
-
-class TestErrorLogger implements ANTLRErrorListener {
-
-  private String prefix;
-  private int logLevel = 0;
-
-  public TestErrorLogger(final String prefix, final int logLevel) {
-    this.prefix = prefix;
-    this.logLevel = logLevel;
-  }
-
-  @Override
-  public void syntaxError(final Recognizer<?, ?> recognizer, final Object offendingSymbol, final int line,
-      final int charPositionInLine,
-      final String msg, final RecognitionException e) {
-
-    if (logLevel > 0) {
-      System.out.println("\n" + prefix + " -- SyntaxError");
-      trace(recognizer, offendingSymbol, line, charPositionInLine, msg, e);
-    }
-
-  }
-
-  @Override
-  public void reportAmbiguity(final Parser recognizer, final DFA dfa, final int startIndex, final int stopIndex,
-      final boolean exact,
-      final BitSet ambigAlts, final ATNConfigSet configs) {
-    // Test
-  }
-
-  @Override
-  public void reportAttemptingFullContext(final Parser recognizer, final DFA dfa, final int startIndex,
-      final int stopIndex,
-      final BitSet conflictingAlts, final ATNConfigSet configs) {
-    // Test
-  }
-
-  @Override
-  public void reportContextSensitivity(final Parser recognizer, final DFA dfa, final int startIndex,
-      final int stopIndex, final int prediction,
-      final ATNConfigSet configs) {
-    // Test
-  }
-
-  private void printStack(final Recognizer<?, ?> recognizer) {
-    List<String> stack = ((Parser) recognizer).getRuleInvocationStack();
-    Collections.reverse(stack);
-    System.out.println(" rule stack: " + stack);
-  }
-
-  public void trace(final Recognizer<?, ?> recognizer, final Object offendingSymbol,
-      final int line, final int charPositionInLine, final String msg, final RecognitionException e) {
-
-    System.out.println("Error message: " + msg);
-
-    printStack(recognizer);
-
-    System.out.println(" line/char :" + line + " / " + charPositionInLine);
-    System.out.println(" sym       :" + offendingSymbol);
-    if (e != null && e.getOffendingToken() != null) {
-
-      String lexerTokenName = "";
-      try {
-        lexerTokenName = UriLexer.VOCABULARY.getDisplayName(e.getOffendingToken().getType());
-      } catch (ArrayIndexOutOfBoundsException es) {
-        lexerTokenName = "token error";
-      }
-
-      System.out.println(" tokenname:" + lexerTokenName);
-    }
-
-  }
-
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d7e23bf8/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/TokenValidator.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/TokenValidator.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/TokenValidator.java
index 3ec6229..547c2ea 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/TokenValidator.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/TokenValidator.java
@@ -29,35 +29,18 @@ import org.apache.olingo.server.core.uri.antlr.UriLexer;
 public class TokenValidator {
 
   private String input = null;
-
   private List<? extends Token> tokens = null;
   private Token curToken = null;
   private Exception curException = null;
 
   private int startMode;
-  private int logLevel = 0;
-
-  // --- Setup ---
-
-  public TokenValidator log(final int logLevel) {
-    this.logLevel = logLevel;
-    return this;
-  }
 
   // --- Execution ---
 
   public TokenValidator run(final String uri) {
     input = uri;
-
     tokens = parseInput(uri);
-    if (logLevel > 0) {
-      showTokens();
-    }
-
     first();
-    exFirst();
-    logLevel = 0;
-
     return this;
   }
 
@@ -87,31 +70,6 @@ public class TokenValidator {
     return this;
   }
 
-  public TokenValidator exLast() {
-    // curException = exceptions.get(exceptions.size() - 1);
-    return this;
-  }
-
-  // navigate within the exception list
-  public TokenValidator exFirst() {
-    try {
-      // curException = exceptions.get(0);
-    } catch (IndexOutOfBoundsException ex) {
-      curException = null;
-    }
-    return this;
-
-  }
-
-  public TokenValidator exAt(final int index) {
-    try {
-      // curException = exceptions.get(index);
-    } catch (IndexOutOfBoundsException ex) {
-      curException = null;
-    }
-    return this;
-  }
-
   // --- Validation ---
 
   public TokenValidator isText(final String expected) {
@@ -162,32 +120,8 @@ public class TokenValidator {
 
   private List<? extends Token> parseInput(final String input) {
     ANTLRInputStream inputStream = new ANTLRInputStream(input);
-
-    UriLexer lexer = new UriLexerWithTrace(inputStream, logLevel, startMode);
-    // lexer.addErrorListener(new ErrorCollector(this));
+    UriLexer lexer = new UriLexer(inputStream);
+    lexer.mode(startMode);
     return lexer.getAllTokens();
   }
-
-  public TokenValidator showTokens() {
-    boolean first = true;
-    System.out.println("input: " + input);
-    String nL = "\n";
-    String out = "[" + nL;
-    for (Token token : tokens) {
-      if (!first) {
-        out += ",";
-        first = false;
-      }
-      int index = token.getType();
-      if (index != -1) {
-        out += "\"" + token.getText() + "\"" + "     " + UriLexer.VOCABULARY.getDisplayName(index) + nL;
-      } else {
-        out += "\"" + token.getText() + "\"" + "     " + index + nL;
-      }
-    }
-    out += ']';
-    System.out.println("tokens: " + out);
-    return this;
-  }
-
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/d7e23bf8/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/UriLexerWithTrace.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/UriLexerWithTrace.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/UriLexerWithTrace.java
deleted file mode 100644
index c067394..0000000
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/UriLexerWithTrace.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * 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.testutil;
-
-import org.antlr.v4.runtime.ANTLRInputStream;
-import org.antlr.v4.runtime.Token;
-import org.apache.olingo.server.core.uri.antlr.UriLexer;
-
-public class UriLexerWithTrace extends UriLexer {
-  int logLevel = 0;
-
-  public UriLexerWithTrace(final ANTLRInputStream antlrInputStream, final int logLevel) {
-    super(antlrInputStream);
-    this.logLevel = logLevel;
-  }
-
-  public UriLexerWithTrace(final ANTLRInputStream antlrInputStream, final int logLevel, final int mode) {
-    super(antlrInputStream);
-    super.mode(mode);
-    this.logLevel = logLevel;
-  }
-
-  @Override
-  public void emit(final Token token) {
-    if (logLevel > 1) {
-      String out = String.format("%1$-" + 20 + "s", token.getText());
-
-      int tokenType = token.getType();
-      if (tokenType == -1) {
-        out += "-1/EOF";
-      } else {
-        out += UriLexer.VOCABULARY.getDisplayName(tokenType);
-      }
-      System.out.println("Lexer.emit(...):" + out);
-    }
-
-    super.emit(token);
-  }
-
-  @Override
-  public void pushMode(final int m) {
-
-    String out = UriLexer.modeNames[_mode] + "-->";
-
-    super.pushMode(m);
-
-    out += UriLexer.modeNames[_mode];
-
-    if (logLevel > 1) {
-      System.out.println(out + "            ");
-    }
-  }
-
-  @Override
-  public int popMode() {
-
-    String out = UriLexer.modeNames[_mode] + "-->";
-
-    int m = super.popMode();
-
-    out += UriLexer.modeNames[_mode];
-
-    if (logLevel > 1) {
-      System.out.println(out + "            ");
-    }
-
-    return m;
-  }
-}


[04/30] olingo-odata4 git commit: [OLINGO-833] Replace unicode 6.x characters in fit-test

Posted by ch...@apache.org.
[OLINGO-833] Replace unicode 6.x characters in fit-test


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

Branch: refs/heads/master
Commit: 83f11b926da1e52c09b0bc8320eec251946f4952
Parents: 927ecb9
Author: Christian Holzer <c....@sap.com>
Authored: Tue Dec 8 10:20:59 2015 +0100
Committer: Christian Holzer <c....@sap.com>
Committed: Tue Dec 8 10:20:59 2015 +0100

----------------------------------------------------------------------
 .../apache/olingo/fit/tecsvc/client/SystemQueryOptionITCase.java   | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/83f11b92/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/SystemQueryOptionITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/SystemQueryOptionITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/SystemQueryOptionITCase.java
index 3d0df10..bb7fd31 100644
--- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/SystemQueryOptionITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/SystemQueryOptionITCase.java
@@ -320,7 +320,7 @@ public class SystemQueryOptionITCase extends AbstractParamTecSvcITCase {
         .getEntitySetRequest(getClient().newURIBuilder(SERVICE_URI)
             .appendEntitySetSegment(ES_ALL_PRIM)
             .search("\"This is a \\\"$imple\\\"\\\\Phras~\" AND "
-                + "AnUnicodeWordLl\u01E3Lm\u02B5Lo\u1BE4Lt\u01F2Lu\u03D3Nl\u216F")
+                + "AnUnicodeWordLl\u01E3Lm\u02B5Lo\u00AALt\u01F2Lu\u03D3Nl\u216F")
             .build());
     setCookieHeader(request);
     final ODataRetrieveResponse<ClientEntitySet> response = request.execute();


[16/30] olingo-odata4 git commit: [OLINGO-834] ExpressionParser parses path expressions

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8091658/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java
index 1b2d508..af45e80 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java
@@ -55,7 +55,7 @@ public class UriTokenizerTest {
 
   @Test
   public void sequence() {
-    final UriTokenizer tokenizer = new UriTokenizer("(A=1,B=2);.*/+-");
+    UriTokenizer tokenizer = new UriTokenizer("(A=1,B=2);.*/+-");
     assertTrue(tokenizer.next(TokenKind.OPEN));
     assertFalse(tokenizer.next(TokenKind.OPEN));
     assertTrue(tokenizer.next(TokenKind.ODataIdentifier));
@@ -78,6 +78,22 @@ public class UriTokenizerTest {
     assertTrue(tokenizer.next(TokenKind.PLUS));
     assertTrue(tokenizer.next(TokenKind.MINUS));
     assertTrue(tokenizer.next(TokenKind.EOF));
+
+    tokenizer = new UriTokenizer("any(a:true) or all(b:false)");
+    assertTrue(tokenizer.next(TokenKind.ANY));
+    assertTrue(tokenizer.next(TokenKind.OPEN));
+    assertTrue(tokenizer.next(TokenKind.ODataIdentifier));
+    assertTrue(tokenizer.next(TokenKind.COLON));
+    assertTrue(tokenizer.next(TokenKind.BooleanValue));
+    assertTrue(tokenizer.next(TokenKind.CLOSE));
+    assertTrue(tokenizer.next(TokenKind.OrOperator));
+    assertTrue(tokenizer.next(TokenKind.ALL));
+    assertTrue(tokenizer.next(TokenKind.OPEN));
+    assertTrue(tokenizer.next(TokenKind.ODataIdentifier));
+    assertTrue(tokenizer.next(TokenKind.COLON));
+    assertTrue(tokenizer.next(TokenKind.BooleanValue));
+    assertTrue(tokenizer.next(TokenKind.CLOSE));
+    assertTrue(tokenizer.next(TokenKind.EOF));
   }
 
   @Test
@@ -455,6 +471,19 @@ public class UriTokenizerTest {
     }
   }
 
+  @Test
+  public void suffixes() {
+    UriTokenizer tokenizer = new UriTokenizer("p1 asc,p2 desc");
+    assertTrue(tokenizer.next(TokenKind.ODataIdentifier));
+    assertTrue(tokenizer.next(TokenKind.AscSuffix));
+    assertTrue(tokenizer.next(TokenKind.COMMA));
+    assertTrue(tokenizer.next(TokenKind.ODataIdentifier));
+    assertTrue(tokenizer.next(TokenKind.DescSuffix));
+    assertTrue(tokenizer.next(TokenKind.EOF));
+
+    wrongToken(TokenKind.DescSuffix, " desc", 'D');
+  }
+
   private void wrongToken(final TokenKind kind, final String value, final char disturbCharacter) {
     assertFalse(new UriTokenizer(disturbCharacter + value).next(kind));
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8091658/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/UriResourceImplTest.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/UriResourceImplTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/UriResourceImplTest.java
index a945d11..72f3eb9 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/UriResourceImplTest.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/UriResourceImplTest.java
@@ -57,7 +57,7 @@ public class UriResourceImplTest {
       new EdmTechProvider(), Collections.<EdmxReference> emptyList()).getEdm();
 
   @Test
-  public void testUriParameterImpl() {
+  public void uriParameterImpl() {
     UriParameterImpl impl = new UriParameterImpl();
     Expression expression = new LiteralImpl("Expression", null);
 
@@ -73,21 +73,20 @@ public class UriResourceImplTest {
   }
 
   @Test
-  public void testUriResourceActionImpl() {
-    UriResourceActionImpl impl = new UriResourceActionImpl();
+  public void uriResourceActionImpl() {
+    UriResourceActionImpl impl = new UriResourceActionImpl((EdmAction) null);
     assertEquals(UriResourceKind.action, impl.getKind());
     assertEquals("", impl.toString());
 
     // action
     EdmAction action = edm.getUnboundAction(ActionProvider.nameUARTETTwoKeyTwoPrimParam);
-    impl.setAction(action);
+    impl = new UriResourceActionImpl(action);
     assertEquals(action, impl.getAction());
     assertEquals(ActionProvider.nameUARTETTwoKeyTwoPrimParam.getName(), impl.toString());
 
     // action import
-    impl = new UriResourceActionImpl();
     EdmActionImport actionImport = edm.getEntityContainer().getActionImport("AIRTCTTwoPrimParam");
-    impl.setActionImport(actionImport);
+    impl = new UriResourceActionImpl(actionImport);
     assertEquals(actionImport, impl.getActionImport());
     assertEquals(actionImport.getUnboundAction(), impl.getAction());
     assertFalse(impl.isCollection());
@@ -95,20 +94,16 @@ public class UriResourceImplTest {
     assertEquals(actionImport.getUnboundAction().getReturnType().getType(), impl.getType());
 
     actionImport = edm.getEntityContainer().getActionImport("AIRT");
-    impl.setActionImport(actionImport);
+    impl = new UriResourceActionImpl(actionImport);
     assertFalse(impl.isCollection());
     assertNull(impl.getType());
   }
 
   @Test
-  public void testUriResourceLambdaAllImpl() {
-    UriResourceLambdaAllImpl impl = new UriResourceLambdaAllImpl();
-    assertEquals(UriResourceKind.lambdaAll, impl.getKind());
-
+  public void uriResourceLambdaAllImpl() {
     Expression expression = new LiteralImpl("Expression", null);
-    impl.setExpression(expression);
-    impl.setLamdaVariable("A");
-
+    UriResourceLambdaAllImpl impl = new UriResourceLambdaAllImpl("A", expression);
+    assertEquals(UriResourceKind.lambdaAll, impl.getKind());
     assertFalse(impl.isCollection());
     assertEquals(expression, impl.getExpression());
     assertEquals("A", impl.getLambdaVariable());
@@ -117,14 +112,10 @@ public class UriResourceImplTest {
   }
 
   @Test
-  public void testUriResourceLambdaAnyImpl() {
-    UriResourceLambdaAnyImpl impl = new UriResourceLambdaAnyImpl();
-    assertEquals(UriResourceKind.lambdaAny, impl.getKind());
-
+  public void uriResourceLambdaAnyImpl() {
     Expression expression = new LiteralImpl("Expression", null);
-    impl.setExpression(expression);
-    impl.setLamdaVariable("A");
-
+    UriResourceLambdaAnyImpl impl = new UriResourceLambdaAnyImpl("A", expression);
+    assertEquals(UriResourceKind.lambdaAny, impl.getKind());
     assertFalse(impl.isCollection());
     assertEquals(expression, impl.getExpression());
     assertEquals("A", impl.getLambdaVariable());
@@ -133,14 +124,11 @@ public class UriResourceImplTest {
   }
 
   @Test
-  public void testUriResourceComplexPropertyImpl() {
-    UriResourceComplexPropertyImpl impl = new UriResourceComplexPropertyImpl();
-    assertEquals(UriResourceKind.complexProperty, impl.getKind());
-
+  public void uriResourceComplexPropertyImpl() {
     EdmEntityType entityType = edm.getEntityType(EntityTypeProvider.nameETKeyNav);
     EdmProperty property = (EdmProperty) entityType.getProperty("PropertyCompNav");
-    impl.setProperty(property);
-
+    UriResourceComplexPropertyImpl impl = new UriResourceComplexPropertyImpl(property);
+    assertEquals(UriResourceKind.complexProperty, impl.getKind());
     assertEquals(property, impl.getProperty());
     assertEquals(property.getName(), impl.toString());
     assertFalse(impl.isCollection());
@@ -158,14 +146,11 @@ public class UriResourceImplTest {
   }
 
   @Test
-  public void testUriResourcePrimitivePropertyImpl() {
-    UriResourcePrimitivePropertyImpl impl = new UriResourcePrimitivePropertyImpl();
-    assertEquals(UriResourceKind.primitiveProperty, impl.getKind());
-
+  public void uriResourcePrimitivePropertyImpl() {
     EdmEntityType entityType = edm.getEntityType(EntityTypeProvider.nameETKeyNav);
     EdmProperty property = (EdmProperty) entityType.getProperty("PropertyInt16");
-    impl.setProperty(property);
-
+    UriResourcePrimitivePropertyImpl impl = new UriResourcePrimitivePropertyImpl(property);
+    assertEquals(UriResourceKind.primitiveProperty, impl.getKind());
     assertEquals(property, impl.getProperty());
     assertEquals(property.getName(), impl.toString());
     assertFalse(impl.isCollection());
@@ -173,20 +158,17 @@ public class UriResourceImplTest {
   }
 
   @Test
-  public void testUriResourceCountImpl() {
+  public void uriResourceCountImpl() {
     UriResourceCountImpl impl = new UriResourceCountImpl();
     assertEquals(UriResourceKind.count, impl.getKind());
     assertEquals("$count", impl.toString());
   }
 
   @Test
-  public void testUriResourceEntitySetImpl() {
-    UriResourceEntitySetImpl impl = new UriResourceEntitySetImpl();
-    assertEquals(UriResourceKind.entitySet, impl.getKind());
-
+  public void uriResourceEntitySetImpl() {
     EdmEntitySet entitySet = edm.getEntityContainer().getEntitySet("ESAllPrim");
-    impl.setEntitSet(entitySet);
-
+    UriResourceEntitySetImpl impl = new UriResourceEntitySetImpl(entitySet);
+    assertEquals(UriResourceKind.entitySet, impl.getKind());
     assertEquals("ESAllPrim", impl.toString());
     assertEquals(entitySet, impl.getEntitySet());
 
@@ -201,8 +183,8 @@ public class UriResourceImplTest {
   }
 
   @Test
-  public void testUriResourceFunctionImpl() {
-    UriResourceFunctionImpl impl = new UriResourceFunctionImpl();
+  public void uriResourceFunctionImpl() {
+    UriResourceFunctionImpl impl = new UriResourceFunctionImpl(null, null, null);
     assertEquals(UriResourceKind.function, impl.getKind());
     assertEquals("", impl.toString());
 
@@ -210,39 +192,38 @@ public class UriResourceImplTest {
     EdmFunction function = edm.getEntityContainer().getFunctionImport("FINRTInt16")
         .getUnboundFunction(Collections.<String> emptyList());
     assertNotNull(function);
-    impl.setFunction(function);
+    impl = new UriResourceFunctionImpl(null, function, null);
 
     assertEquals(function, impl.getFunction());
     assertEquals("UFNRTInt16", impl.toString());
     assertEquals(function.getReturnType().getType(), impl.getType());
-    assertFalse(impl.isParameterListFilled());
+    assertTrue(impl.getParameters().isEmpty());
 
     // function import
-    impl = new UriResourceFunctionImpl();
     EdmFunctionImport functionImport = edm.getEntityContainer().getFunctionImport("FINRTInt16");
-    impl.setFunctionImport(functionImport, Collections.<UriParameter> emptyList());
+    impl = new UriResourceFunctionImpl(functionImport, functionImport.getUnboundFunctions().get(0),
+        Collections.<UriParameter> emptyList());
     assertEquals(functionImport, impl.getFunctionImport());
     assertEquals("FINRTInt16", impl.toString());
 
     // function collection
-    impl = new UriResourceFunctionImpl();
     functionImport = edm.getEntityContainer().getFunctionImport("FICRTCollESTwoKeyNavParam");
-    assertNotNull(function);
     UriParameter parameter = new UriParameterImpl().setName("ParameterInt16");
-    impl.setFunctionImport(functionImport, Collections.singletonList(parameter));
+    impl = new UriResourceFunctionImpl(functionImport,
+        functionImport.getUnboundFunction(Collections.singletonList("ParameterInt16")),
+        Collections.singletonList(parameter));
     assertEquals("FICRTCollESTwoKeyNavParam", impl.toString());
 
-    impl.setFunction(functionImport.getUnboundFunction(Collections.singletonList("ParameterInt16")));
     assertTrue(impl.isCollection());
     impl.setKeyPredicates(Collections.<UriParameter> emptyList());
     assertFalse(impl.isCollection());
 
+    assertFalse(impl.getParameters().isEmpty());
     assertEquals(parameter, impl.getParameters().get(0));
-    assertTrue(impl.isParameterListFilled());
   }
 
   @Test
-  public void testUriResourceImplKeyPred() {
+  public void uriResourceImplKeyPred() {
     final EdmEntityType entityType = edm.getEntityType(EntityTypeProvider.nameETTwoKeyNav);
     class Mock extends UriResourceWithKeysImpl {
 
@@ -306,7 +287,7 @@ public class UriResourceImplTest {
   }
 
   @Test
-  public void testUriResourceImplTyped() {
+  public void uriResourceImplTyped() {
     final EdmEntityType entityType = edm.getEntityType(EntityTypeProvider.nameETTwoKeyNav);
     class Mock extends UriResourceTypedImpl {
 
@@ -344,18 +325,15 @@ public class UriResourceImplTest {
   }
 
   @Test
-  public void testUriResourceItImpl() {
-    UriResourceItImpl impl = new UriResourceItImpl();
-    assertEquals(UriResourceKind.it, impl.getKind());
-
+  public void uriResourceItImpl() {
     EdmEntityType entityType = edm.getEntityType(EntityTypeProvider.nameETTwoKeyNav);
+    UriResourceItImpl impl = new UriResourceItImpl(entityType, false);
+    assertEquals(UriResourceKind.it, impl.getKind());
     assertEquals("$it", impl.toString());
-
-    impl.setType(entityType);
     assertEquals(entityType, impl.getType());
-
     assertFalse(impl.isCollection());
-    impl.setCollection(true);
+
+    impl = new UriResourceItImpl(entityType, true);
     assertTrue(impl.isCollection());
     impl.setKeyPredicates(Collections.singletonList(
         (UriParameter) new UriParameterImpl().setName("ParameterInt16")));
@@ -363,15 +341,13 @@ public class UriResourceImplTest {
   }
 
   @Test
-  public void testUriResourceNavigationPropertyImpl() {
-    UriResourceNavigationPropertyImpl impl = new UriResourceNavigationPropertyImpl();
-    assertEquals(UriResourceKind.navigationProperty, impl.getKind());
-
+  public void uriResourceNavigationPropertyImpl() {
     EdmEntityType entityType = edm.getEntityType(EntityTypeProvider.nameETTwoKeyNav);
     EdmNavigationProperty property = (EdmNavigationProperty) entityType.getProperty("NavPropertyETKeyNavMany");
     assertNotNull(property);
 
-    impl.setNavigationProperty(property);
+    UriResourceNavigationPropertyImpl impl = new UriResourceNavigationPropertyImpl(property);
+    assertEquals(UriResourceKind.navigationProperty, impl.getKind());
     assertEquals(property, impl.getProperty());
 
     assertEquals("NavPropertyETKeyNavMany", impl.toString());
@@ -384,25 +360,22 @@ public class UriResourceImplTest {
   }
 
   @Test
-  public void testUriResourceRefImpl() {
+  public void uriResourceRefImpl() {
     UriResourceRefImpl impl = new UriResourceRefImpl();
     assertEquals(UriResourceKind.ref, impl.getKind());
     assertEquals("$ref", impl.toString());
   }
 
   @Test
-  public void testUriResourceRootImpl() {
-    UriResourceRootImpl impl = new UriResourceRootImpl();
-    assertEquals(UriResourceKind.root, impl.getKind());
-
+  public void uriResourceRootImpl() {
     EdmEntityType entityType = edm.getEntityType(EntityTypeProvider.nameETTwoKeyNav);
+    UriResourceRootImpl impl = new UriResourceRootImpl(entityType, false);
+    assertEquals(UriResourceKind.root, impl.getKind());
     assertEquals("$root", impl.toString());
-
-    impl.setType(entityType);
     assertEquals(entityType, impl.getType());
-
     assertFalse(impl.isCollection());
-    impl.setCollection(true);
+
+    impl = new UriResourceRootImpl(entityType, true);
     assertTrue(impl.isCollection());
     impl.setKeyPredicates(Collections.singletonList(
         (UriParameter) new UriParameterImpl().setName("ParameterInt16")));
@@ -410,14 +383,11 @@ public class UriResourceImplTest {
   }
 
   @Test
-  public void testUriResourceSingletonImpl() {
-    UriResourceSingletonImpl impl = new UriResourceSingletonImpl();
-    assertEquals(UriResourceKind.singleton, impl.getKind());
-
+  public void uriResourceSingletonImpl() {
     EdmSingleton singleton = edm.getEntityContainer().getSingleton("SINav");
     EdmEntityType entityTypeBaseColl = edm.getEntityType(EntityTypeProvider.nameETBaseTwoKeyNav);
-    impl.setSingleton(singleton);
-
+    UriResourceSingletonImpl impl = new UriResourceSingletonImpl(singleton);
+    assertEquals(UriResourceKind.singleton, impl.getKind());
     assertEquals("SINav", impl.toString());
     assertEquals(singleton, impl.getSingleton());
 
@@ -433,41 +403,33 @@ public class UriResourceImplTest {
   }
 
   @Test
-  public void testUriResourceValueImpl() {
+  public void uriResourceValueImpl() {
     UriResourceValueImpl impl = new UriResourceValueImpl();
     assertEquals(UriResourceKind.value, impl.getKind());
     assertEquals("$value", impl.toString());
   }
 
   @Test
-  public void testUriResourceLambdaVarImpl() {
-    UriResourceLambdaVarImpl impl = new UriResourceLambdaVarImpl();
-    assertEquals(UriResourceKind.lambdaVariable, impl.getKind());
-
+  public void uriResourceLambdaVarImpl() {
     EdmEntityType entityType = edm.getEntityType(EntityTypeProvider.nameETTwoKeyNav);
-    impl.setType(entityType);
-    impl.setVariableText("A");
-
+    UriResourceLambdaVarImpl impl = new UriResourceLambdaVarImpl("A", entityType);
+    assertEquals(UriResourceKind.lambdaVariable, impl.getKind());
     assertEquals("A", impl.toString());
     assertEquals(entityType, impl.getType());
     assertEquals("A", impl.getVariableName());
     assertFalse(impl.isCollection());
-    impl.setCollection(true);
-    assertTrue(impl.isCollection());
   }
 
   @Test
-  public void testUriResourceStartingTypeFilterImpl() {
-    UriResourceStartingTypeFilterImpl impl = new UriResourceStartingTypeFilterImpl();
-
+  public void uriResourceStartingTypeFilterImpl() {
     EdmEntityType entityType = edm.getEntityType(EntityTypeProvider.nameETTwoKeyNav);
 
-    impl.setType(entityType);
+    UriResourceStartingTypeFilterImpl impl = new UriResourceStartingTypeFilterImpl(entityType, false);
     assertEquals("olingo.odata.test1.ETTwoKeyNav", impl.toString());
     assertEquals(entityType, impl.getType());
-
     assertFalse(impl.isCollection());
-    impl.setCollection(true);
+
+    impl = new UriResourceStartingTypeFilterImpl(entityType, true);
     assertTrue(impl.isCollection());
     impl.setKeyPredicates(Collections.singletonList(
         (UriParameter) new UriParameterImpl().setName("ParameterInt16")));


[14/30] olingo-odata4 git commit: [OLINGO-834] Type checks in ExpressionParser

Posted by ch...@apache.org.
[OLINGO-834] Type checks in ExpressionParser

Signed-off-by: Christian Amend <ch...@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/104ecf43
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/104ecf43
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/104ecf43

Branch: refs/heads/master
Commit: 104ecf43d255722e99e18641a1444e33a0ff11b1
Parents: 2f3bc28
Author: Klaus Straubinger <kl...@sap.com>
Authored: Wed Dec 16 16:14:12 2015 +0100
Committer: Christian Amend <ch...@sap.com>
Committed: Wed Dec 16 16:26:51 2015 +0100

----------------------------------------------------------------------
 .../core/uri/parser/ExpressionParser.java       | 413 +++++++++++++++----
 .../core/uri/parser/UriParseTreeVisitor.java    |  24 +-
 .../server/core/uri/parser/UriTokenizer.java    |   5 +
 .../uri/queryoption/expression/BinaryImpl.java  |  10 +-
 .../uri/queryoption/expression/MethodImpl.java  |  70 ++++
 .../uri/queryoption/expression/UnaryImpl.java   |   9 +-
 .../core/uri/parser/ExpressionParserTest.java   | 142 ++++++-
 .../core/uri/parser/UriTokenizerTest.java       |   6 +-
 .../queryoption/expression/ExpressionTest.java  |  64 +--
 9 files changed, 616 insertions(+), 127 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/104ecf43/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java
index 3b04089..61c023d 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java
@@ -24,13 +24,26 @@ 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.EdmPrimitiveType;
 import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
-import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
+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.queryoption.expression.Alias;
+import org.apache.olingo.server.api.uri.queryoption.expression.Binary;
 import org.apache.olingo.server.api.uri.queryoption.expression.BinaryOperatorKind;
+import org.apache.olingo.server.api.uri.queryoption.expression.Enumeration;
 import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
+import org.apache.olingo.server.api.uri.queryoption.expression.LambdaRef;
+import org.apache.olingo.server.api.uri.queryoption.expression.Literal;
+import org.apache.olingo.server.api.uri.queryoption.expression.Member;
 import org.apache.olingo.server.api.uri.queryoption.expression.Method;
 import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind;
+import org.apache.olingo.server.api.uri.queryoption.expression.TypeLiteral;
+import org.apache.olingo.server.api.uri.queryoption.expression.Unary;
 import org.apache.olingo.server.api.uri.queryoption.expression.UnaryOperatorKind;
 import org.apache.olingo.server.core.uri.parser.UriTokenizer.TokenKind;
 import org.apache.olingo.server.core.uri.queryoption.expression.AliasImpl;
@@ -72,10 +85,10 @@ public class ExpressionParser {
     tokenToUnaryOperator = Collections.unmodifiableMap(temp);
   }
 
+  // 'cast' and 'isof' are handled specially.
   private static final Map<TokenKind, MethodKind> tokenToMethod;
   static {
     Map<TokenKind, MethodKind> temp = new HashMap<TokenKind, MethodKind>();
-    temp.put(TokenKind.CastMethod, MethodKind.CAST);
     temp.put(TokenKind.CeilingMethod, MethodKind.CEILING);
     temp.put(TokenKind.ConcatMethod, MethodKind.CONCAT);
     temp.put(TokenKind.ContainsMethod, MethodKind.CONTAINS);
@@ -89,7 +102,6 @@ public class ExpressionParser {
     temp.put(TokenKind.GeoLengthMethod, MethodKind.GEOLENGTH);
     temp.put(TokenKind.HourMethod, MethodKind.HOUR);
     temp.put(TokenKind.IndexofMethod, MethodKind.INDEXOF);
-    temp.put(TokenKind.IsofMethod, MethodKind.ISOF);
     temp.put(TokenKind.LengthMethod, MethodKind.LENGTH);
     temp.put(TokenKind.MaxdatetimeMethod, MethodKind.MAXDATETIME);
     temp.put(TokenKind.MindatetimeMethod, MethodKind.MINDATETIME);
@@ -131,8 +143,16 @@ public class ExpressionParser {
     tokenToPrimitiveType = Collections.unmodifiableMap(temp);
   }
 
+  private final Edm edm;
+  private final OData odata;
+
   private UriTokenizer tokenizer;
 
+  public ExpressionParser(final Edm edm, final OData odata) {
+    this.edm = edm;
+    this.odata = odata;
+  }
+
   public Expression parse(UriTokenizer tokenizer) throws UriParserException {
     // Initialize tokenizer.
     this.tokenizer = tokenizer;
@@ -144,7 +164,10 @@ public class ExpressionParser {
     Expression left = parseAnd();
     while (tokenizer.next(TokenKind.OrOperator)) {
       final Expression right = parseAnd();
-      left = new BinaryImpl(left, BinaryOperatorKind.OR, right);
+      checkType(left, EdmPrimitiveTypeKind.Boolean);
+      checkType(right, EdmPrimitiveTypeKind.Boolean);
+      left = new BinaryImpl(left, BinaryOperatorKind.OR, right,
+          odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Boolean));
     }
     return left;
   }
@@ -153,7 +176,10 @@ public class ExpressionParser {
     Expression left = parseExprEquality();
     while (tokenizer.next(TokenKind.AndOperator)) {
       final Expression right = parseExprEquality();
-      left = new BinaryImpl(left, BinaryOperatorKind.AND, right);
+      checkType(left, EdmPrimitiveTypeKind.Boolean);
+      checkType(right, EdmPrimitiveTypeKind.Boolean);
+      left = new BinaryImpl(left, BinaryOperatorKind.AND, right,
+          odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Boolean));
     }
     return left;
   }
@@ -164,12 +190,15 @@ public class ExpressionParser {
     // Null for everything other than EQ or NE
     while (operatorTokenKind != null) {
       final Expression right = parseExprEquality();
-      left = new BinaryImpl(left, tokenToBinaryOperator.get(operatorTokenKind), right);
+      checkEqualityTypes(left, right);
+      left = new BinaryImpl(left, tokenToBinaryOperator.get(operatorTokenKind), right,
+          odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Boolean));
       operatorTokenKind = ParserHelper.next(tokenizer, TokenKind.EqualsOperator, TokenKind.NotEqualsOperator);
     }
     return left;
   }
 
+  // TODO: The 'isof' method has relational precedence and should appear here.
   private Expression parseExprRel() throws UriParserException {
     Expression left = parseExprAdd();
     TokenKind operatorTokenKind = ParserHelper.next(tokenizer,
@@ -178,7 +207,9 @@ public class ExpressionParser {
     // Null for everything other than GT or GE or LT or LE
     while (operatorTokenKind != null) {
       final Expression right = parseExprAdd();
-      left = new BinaryImpl(left, tokenToBinaryOperator.get(operatorTokenKind), right);
+      checkRelationTypes(left, right);
+      left = new BinaryImpl(left, tokenToBinaryOperator.get(operatorTokenKind), right,
+          odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Boolean));
       operatorTokenKind = ParserHelper.next(tokenizer,
           TokenKind.GreaterThanOperator, TokenKind.GreaterThanOrEqualsOperator,
           TokenKind.LessThanOperator, TokenKind.LessThanOrEqualsOperator);
@@ -192,7 +223,9 @@ public class ExpressionParser {
     // Null for everything other than ADD or SUB
     while (operatorTokenKind != null) {
       final Expression right = parseExprMul();
-      left = new BinaryImpl(left, tokenToBinaryOperator.get(operatorTokenKind), right);
+      checkAddSubTypes(left, right, operatorTokenKind == TokenKind.AddOperator);
+      left = new BinaryImpl(left, tokenToBinaryOperator.get(operatorTokenKind), right,
+          odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Double));
       operatorTokenKind = ParserHelper.next(tokenizer, TokenKind.AddOperator, TokenKind.SubOperator);
     }
     return left;
@@ -205,28 +238,61 @@ public class ExpressionParser {
     // Null for everything other than MUL or DIV or MOD
     while (operatorTokenKind != null) {
       final Expression right = parseExprUnary();
-      left = new BinaryImpl(left, tokenToBinaryOperator.get(operatorTokenKind), right);
+      checkType(left,
+          EdmPrimitiveTypeKind.Int16, EdmPrimitiveTypeKind.Int32, EdmPrimitiveTypeKind.Int64,
+          EdmPrimitiveTypeKind.Byte, EdmPrimitiveTypeKind.SByte,
+          EdmPrimitiveTypeKind.Decimal, EdmPrimitiveTypeKind.Single, EdmPrimitiveTypeKind.Double);
+      checkType(right,
+          EdmPrimitiveTypeKind.Int16, EdmPrimitiveTypeKind.Int32, EdmPrimitiveTypeKind.Int64,
+          EdmPrimitiveTypeKind.Byte, EdmPrimitiveTypeKind.SByte,
+          EdmPrimitiveTypeKind.Decimal, EdmPrimitiveTypeKind.Single, EdmPrimitiveTypeKind.Double);
+      left = new BinaryImpl(left, tokenToBinaryOperator.get(operatorTokenKind), right,
+          odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Double));
       operatorTokenKind = ParserHelper.next(tokenizer,
           TokenKind.MulOperator, TokenKind.DivOperator, TokenKind.ModOperator);
     }
     return left;
   }
 
+  // TODO: The 'cast' method has unary precedence and should appear here.
   private Expression parseExprUnary() throws UriParserException {
     Expression left = null;
     TokenKind operatorTokenKind = ParserHelper.next(tokenizer, TokenKind.MINUS, TokenKind.NotOperator);
     // Null for everything other than - or NOT
     while (operatorTokenKind != null) {
-      final Expression expression = parseExprValue();
-      left = new UnaryImpl(tokenToUnaryOperator.get(operatorTokenKind), expression);
+      final Expression expression = parseExprPrimary();
+      if (operatorTokenKind == TokenKind.NotOperator) {
+        checkType(expression, EdmPrimitiveTypeKind.Boolean);
+      } else {
+        checkType(expression,
+            EdmPrimitiveTypeKind.Int16, EdmPrimitiveTypeKind.Int32, EdmPrimitiveTypeKind.Int64,
+            EdmPrimitiveTypeKind.Byte, EdmPrimitiveTypeKind.SByte,
+            EdmPrimitiveTypeKind.Decimal, EdmPrimitiveTypeKind.Single, EdmPrimitiveTypeKind.Double,
+            EdmPrimitiveTypeKind.Duration);
+      }
+      left = new UnaryImpl(tokenToUnaryOperator.get(operatorTokenKind), expression, getType(expression));
       operatorTokenKind = ParserHelper.next(tokenizer, TokenKind.MINUS, TokenKind.NotOperator);
     }
     if (left == null) {
-      left = parseExprValue();
+      left = parseExprPrimary();
     }
     return left;
   }
 
+  private Expression parseExprPrimary() throws UriParserException {
+    final Expression left = parseExprValue();
+    if (isEnumType(left) && tokenizer.next(TokenKind.HasOperator)) {
+      ParserHelper.requireNext(tokenizer, TokenKind.EnumValue);
+      final String primitiveValueLiteral = tokenizer.getText();
+      final Expression right = new LiteralImpl(primitiveValueLiteral, getEnumType(primitiveValueLiteral));
+      checkEnumLiteral(right);
+      return new BinaryImpl(left, BinaryOperatorKind.HAS, right,
+          odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Boolean));
+    } else {
+      return left;
+    }
+  }
+
   private Expression parseExprValue() throws UriParserException {
     if (tokenizer.next(TokenKind.OPEN)) {
       final Expression expression = parseExpression();
@@ -251,44 +317,34 @@ public class ExpressionParser {
       // TODO: Consume $it expression.
     }
 
-    if (tokenizer.next(TokenKind.QualifiedName)) {
-      // TODO: Consume typecast or bound-function expression.
-    }
-
     TokenKind nextPrimitive = ParserHelper.nextPrimitive(tokenizer);
     if (nextPrimitive != null) {
+      final String primitiveValueLiteral = tokenizer.getText();
       final EdmPrimitiveTypeKind primitiveTypeKind = tokenToPrimitiveType.get(nextPrimitive);
       EdmPrimitiveType type;
       if (primitiveTypeKind == null) {
         if (nextPrimitive == TokenKind.EnumValue) {
-          // TODO: Get enum type.
-          type = null;
+          type = getEnumType(primitiveValueLiteral);
         } else {
           // Null handling
           type = null;
         }
       } else {
-        type = EdmPrimitiveTypeFactory.getInstance(primitiveTypeKind);
+        type = odata.createPrimitiveTypeInstance(primitiveTypeKind);
       }
-      return new LiteralImpl(tokenizer.getText(), type);
+      return new LiteralImpl(primitiveValueLiteral, type);
     }
 
+    // The method token text includes the opening parenthesis so that method calls can be recognized unambiguously.
+    // OData identifiers have to be considered after that.
     TokenKind nextMethod = nextMethod();
     if (nextMethod != null) {
       MethodKind methodKind = tokenToMethod.get(nextMethod);
-      List<Expression> parameters = new ArrayList<Expression>();
-      // The method token text includes the opening parenthesis!
-      if (!tokenizer.next(TokenKind.CLOSE)) {
-        do {
-          parameters.add(parseExpression());
-        } while (tokenizer.next(TokenKind.COMMA));
-        ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
-      }
-
-      MethodImpl methodImpl = new MethodImpl(methodKind, parameters);
-      validateMethodParameters(methodImpl);
+      return new MethodImpl(methodKind, parseMethodParameters(methodKind));
+    }
 
-      return methodImpl;
+    if (tokenizer.next(TokenKind.QualifiedName)) {
+      // TODO: Consume typecast or bound-function expression.
     }
 
     if (tokenizer.next(TokenKind.ODataIdentifier)) {
@@ -298,85 +354,131 @@ public class ExpressionParser {
     throw new UriParserSyntaxException("Unexpected token", UriParserSyntaxException.MessageKeys.SYNTAX);
   }
 
-  private void validateMethodParameters(final Method method) throws UriParserException {
-    // We might validate parameter types in the future.
-    int size = method.getParameters().size();
-    switch (method.getMethod()) {
-    // Must have two Parameters.
-    case CONTAINS:
-    case ENDSWITH:
-    case STARTSWITH:
-    case INDEXOF:
-    case CONCAT:
-    case GEODISTANCE:
-    case GEOINTERSECTS:
-      if (size != 2) {
-        throw new UriParserSemanticException(
-            "The method " + method.getMethod() + " needs exactly two parameters.",
-            null); // TODO: message key
-      }
+  private List<Expression> parseMethodParameters(final MethodKind methodKind) throws UriParserException {
+    List<Expression> parameters = new ArrayList<Expression>();
+    switch (methodKind) {
+    // Must have no parameter.
+    case NOW:
+    case MAXDATETIME:
+    case MINDATETIME:
       break;
+
     // Must have one parameter.
     case LENGTH:
     case TOLOWER:
     case TOUPPER:
     case TRIM:
+      final Expression stringParameter = parseExpression();
+      checkType(stringParameter, EdmPrimitiveTypeKind.String);
+      parameters.add(stringParameter);
+      break;
     case YEAR:
     case MONTH:
     case DAY:
+      final Expression dateParameter = parseExpression();
+      checkType(dateParameter, EdmPrimitiveTypeKind.Date, EdmPrimitiveTypeKind.DateTimeOffset);
+      parameters.add(dateParameter);
+      break;
     case HOUR:
     case MINUTE:
     case SECOND:
     case FRACTIONALSECONDS:
+      final Expression timeParameter = parseExpression();
+      checkType(timeParameter, EdmPrimitiveTypeKind.TimeOfDay, EdmPrimitiveTypeKind.DateTimeOffset);
+      parameters.add(timeParameter);
+      break;
     case DATE:
     case TIME:
     case TOTALOFFSETMINUTES:
+      final Expression dateTimeParameter = parseExpression();
+      checkType(dateTimeParameter, EdmPrimitiveTypeKind.DateTimeOffset);
+      parameters.add(dateTimeParameter);
+      break;
     case TOTALSECONDS:
+      final Expression durationParameter = parseExpression();
+      checkType(durationParameter, EdmPrimitiveTypeKind.Duration);
+      parameters.add(durationParameter);
+      break;
     case ROUND:
     case FLOOR:
     case CEILING:
+      final Expression decimalParameter = parseExpression();
+      checkType(decimalParameter,
+          EdmPrimitiveTypeKind.Decimal, EdmPrimitiveTypeKind.Single, EdmPrimitiveTypeKind.Double);
+      parameters.add(decimalParameter);
+      break;
     case GEOLENGTH:
-      if (size != 1) {
-        throw new UriParserSemanticException(
-            "The method '" + method.getMethod() + "' needs exactly one parameter.",
-            null); // TODO: message key
-      }
+      final Expression geoParameter = parseExpression();
+      checkType(geoParameter,
+          EdmPrimitiveTypeKind.GeographyLineString, EdmPrimitiveTypeKind.GeometryLineString);
+      parameters.add(geoParameter);
       break;
-    // Must have no parameter.
-    case NOW:
-    case MAXDATETIME:
-    case MINDATETIME:
-      if (size > 0) {
-        throw new UriParserSemanticException("The method '" + method.getMethod() + "' must have no parameters.",
-            null); // TODO: message key
-      }
+
+    // Must have two parameters.
+    case CONTAINS:
+    case ENDSWITH:
+    case STARTSWITH:
+    case INDEXOF:
+    case CONCAT:
+      final Expression stringParameter1 = parseExpression();
+      checkType(stringParameter1, EdmPrimitiveTypeKind.String);
+      parameters.add(stringParameter1);
+      ParserHelper.requireNext(tokenizer, TokenKind.COMMA);
+      final Expression stringParameter2 = parseExpression();
+      checkType(stringParameter2, EdmPrimitiveTypeKind.String);
+      parameters.add(stringParameter2);
       break;
-    // Variable parameter number
-    case CAST:
-    case ISOF:
-      if (size < 1 || size > 2) {
-        throw new UriParserSemanticException(
-            "The method '" + method.getMethod() + "' must have one or two parameters.",
-            null); // TODO: message key
-      }
+    case GEODISTANCE:
+      final Expression geoParameter1 = parseExpression();
+      checkType(geoParameter1, EdmPrimitiveTypeKind.GeographyPoint, EdmPrimitiveTypeKind.GeometryPoint);
+      parameters.add(geoParameter1);
+      ParserHelper.requireNext(tokenizer, TokenKind.COMMA);
+      final Expression geoParameter2 = parseExpression();
+      checkType(geoParameter2, EdmPrimitiveTypeKind.GeographyPoint, EdmPrimitiveTypeKind.GeometryPoint);
+      parameters.add(geoParameter2);
+      break;
+    case GEOINTERSECTS:
+      final Expression geoPointParameter = parseExpression();
+      checkType(geoPointParameter,
+          EdmPrimitiveTypeKind.GeographyPoint, EdmPrimitiveTypeKind.GeometryPoint);
+      parameters.add(geoPointParameter);
+      ParserHelper.requireNext(tokenizer, TokenKind.COMMA);
+      final Expression geoPolygonParameter = parseExpression();
+      checkType(geoPolygonParameter,
+          EdmPrimitiveTypeKind.GeographyPolygon, EdmPrimitiveTypeKind.GeometryPolygon);
+      parameters.add(geoPolygonParameter);
       break;
+
+    // Can have two or three parameters.
     case SUBSTRING:
-      if (size < 2 || size > 3) {
-        throw new UriParserSemanticException(
-            "The method '" + method.getMethod() + "' must have two or three parameters.",
-            null); // TODO: message key
+      final Expression parameterFirst = parseExpression();
+      checkType(parameterFirst, EdmPrimitiveTypeKind.String);
+      parameters.add(parameterFirst);
+      ParserHelper.requireNext(tokenizer, TokenKind.COMMA);
+      final Expression parameterSecond = parseExpression();
+      checkType(parameterSecond,
+          EdmPrimitiveTypeKind.Int64, EdmPrimitiveTypeKind.Int32, EdmPrimitiveTypeKind.Int16,
+          EdmPrimitiveTypeKind.Byte, EdmPrimitiveTypeKind.SByte);
+      parameters.add(parameterSecond);
+      if (tokenizer.next(TokenKind.COMMA)) {
+        final Expression parameterThird = parseExpression();
+        checkType(parameterThird,
+            EdmPrimitiveTypeKind.Int64, EdmPrimitiveTypeKind.Int32, EdmPrimitiveTypeKind.Int16,
+            EdmPrimitiveTypeKind.Byte, EdmPrimitiveTypeKind.SByte);
+        parameters.add(parameterThird);
       }
       break;
+
     default:
-      throw new UriParserSemanticException(
-          "Unkown method '" + method.getMethod() + "'",
-          null); // TODO: message key
+      throw new UriParserSemanticException("Unkown method '" + methodKind.name() + "'",
+          UriParserSemanticException.MessageKeys.NOT_IMPLEMENTED, methodKind.name()); // TODO: better message
     }
+    ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
+    return parameters;
   }
 
   private TokenKind nextMethod() {
     return ParserHelper.next(tokenizer,
-        TokenKind.CastMethod,
         TokenKind.CeilingMethod,
         TokenKind.ConcatMethod,
         TokenKind.ContainsMethod,
@@ -390,7 +492,6 @@ public class ExpressionParser {
         TokenKind.GeoLengthMethod,
         TokenKind.HourMethod,
         TokenKind.IndexofMethod,
-        TokenKind.IsofMethod,
         TokenKind.LengthMethod,
         TokenKind.MaxdatetimeMethod,
         TokenKind.MindatetimeMethod,
@@ -409,4 +510,158 @@ public class ExpressionParser {
         TokenKind.TrimMethod,
         TokenKind.YearMethod);
   }
+
+  private EdmType getType(final Expression expression) throws UriParserException {
+    EdmType type;
+    if (expression instanceof Literal) {
+      type = ((Literal) expression).getType();
+    } else if (expression instanceof TypeLiteral) {
+      type = ((TypeLiteral) expression).getType();
+    } else if (expression instanceof Enumeration) {
+      type = ((Enumeration) expression).getType();
+    } else if (expression instanceof Member) {
+      type = ((Member) expression).getType();
+    } else if (expression instanceof Unary) {
+      type = ((UnaryImpl) expression).getType();
+    } else if (expression instanceof Binary) {
+      type = ((BinaryImpl) expression).getType();
+    } else if (expression instanceof Method) {
+      type = ((MethodImpl) expression).getType();
+    } else if (expression instanceof LambdaRef) {
+      throw new UriParserSemanticException("Type determination not implemented.",
+          UriParserSemanticException.MessageKeys.NOT_IMPLEMENTED, expression.toString());
+    } else if (expression instanceof Alias) {
+      type = null; // The alias would have to be available already parsed.
+    } else {
+      throw new UriParserSemanticException("Unknown expression type.",
+          UriParserSemanticException.MessageKeys.NOT_IMPLEMENTED, expression.toString());
+    }
+    if (type != null && type.getKind() == EdmTypeKind.DEFINITION) {
+      type = ((EdmTypeDefinition) type).getUnderlyingType();
+    }
+    return type;
+  }
+
+  private boolean isType(final Expression expression, final EdmPrimitiveTypeKind... kinds) throws UriParserException {
+    final EdmType expressionType = getType(expression);
+    if (expressionType == null) {
+      return true;
+    }
+    for (final EdmPrimitiveTypeKind kind : kinds) {
+      if (expressionType.equals(odata.createPrimitiveTypeInstance(kind))) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  private void checkType(final Expression expression, final EdmPrimitiveTypeKind... kinds) throws UriParserException {
+    if (!isType(expression, kinds)) {
+      throw new UriParserSemanticException("Incompatible type.",
+          UriParserSemanticException.MessageKeys.UNKNOWN_TYPE, // TODO: better message
+          getType(expression) == null ?
+              "" :
+              getType(expression).getFullQualifiedName().getFullQualifiedNameAsString());
+    }
+  }
+
+  private void checkEqualityTypes(final Expression left, final Expression right) throws UriParserException {
+    final EdmType leftType = getType(left);
+    final EdmType rightType = getType(right);
+    if (leftType == null || rightType == null || leftType.equals(rightType)) {
+      return;
+    }
+    if (leftType.getKind() != EdmTypeKind.PRIMITIVE
+        || rightType.getKind() != EdmTypeKind.PRIMITIVE
+        || !(((EdmPrimitiveType) leftType).isCompatible((EdmPrimitiveType) rightType)
+        || ((EdmPrimitiveType) rightType).isCompatible((EdmPrimitiveType) leftType))) {
+      throw new UriParserSemanticException("Incompatible types.",
+          UriParserSemanticException.MessageKeys.UNKNOWN_TYPE, ""); // TODO: better message
+    }
+  }
+
+  private EdmPrimitiveType getEnumType(final String primitiveValueLiteral) throws UriParserException {
+    final String enumTypeName = primitiveValueLiteral.substring(0, primitiveValueLiteral.indexOf('\''));
+    final EdmPrimitiveType type = edm.getEnumType(new FullQualifiedName(enumTypeName));
+    if (type == null) {
+      throw new UriParserSemanticException("Unknown Enum type '" + enumTypeName + "'.",
+          UriParserSemanticException.MessageKeys.UNKNOWN_TYPE, enumTypeName);
+    }
+    return type;
+  }
+
+  private boolean isEnumType(final Expression expression) throws UriParserException {
+    final EdmType expressionType = getType(expression);
+    return expressionType == null
+        || expressionType.getKind() == EdmTypeKind.ENUM
+        || isType(expression,
+            EdmPrimitiveTypeKind.Int16, EdmPrimitiveTypeKind.Int32, EdmPrimitiveTypeKind.Int64,
+            EdmPrimitiveTypeKind.Byte, EdmPrimitiveTypeKind.SByte);
+  }
+
+  private void checkEnumLiteral(final Expression expression) throws UriParserException {
+    if (expression == null
+        || !(expression instanceof Literal)
+        || ((Literal) expression).getType() == null
+        || ((Literal) expression).getType().getKind() != EdmTypeKind.ENUM) {
+      throw new UriParserSemanticException("Enum literal expected.",
+          UriParserSemanticException.MessageKeys.UNKNOWN_TYPE, ""); // TODO: better message
+    }
+  }
+
+  private void checkRelationTypes(final Expression left, final Expression right) throws UriParserException {
+    final EdmType leftType = getType(left);
+    final EdmType rightType = getType(right);
+    if (leftType == null || rightType == null) {
+      return;
+    }
+    checkType(left,
+        EdmPrimitiveTypeKind.Int16, EdmPrimitiveTypeKind.Int32, EdmPrimitiveTypeKind.Int64,
+        EdmPrimitiveTypeKind.Byte, EdmPrimitiveTypeKind.SByte,
+        EdmPrimitiveTypeKind.Decimal, EdmPrimitiveTypeKind.Single, EdmPrimitiveTypeKind.Double,
+        EdmPrimitiveTypeKind.Boolean, EdmPrimitiveTypeKind.Guid, EdmPrimitiveTypeKind.String,
+        EdmPrimitiveTypeKind.Date, EdmPrimitiveTypeKind.TimeOfDay,
+        EdmPrimitiveTypeKind.DateTimeOffset, EdmPrimitiveTypeKind.Duration);
+    checkType(right,
+        EdmPrimitiveTypeKind.Int16, EdmPrimitiveTypeKind.Int32, EdmPrimitiveTypeKind.Int64,
+        EdmPrimitiveTypeKind.Byte, EdmPrimitiveTypeKind.SByte,
+        EdmPrimitiveTypeKind.Decimal, EdmPrimitiveTypeKind.Single, EdmPrimitiveTypeKind.Double,
+        EdmPrimitiveTypeKind.Boolean, EdmPrimitiveTypeKind.Guid, EdmPrimitiveTypeKind.String,
+        EdmPrimitiveTypeKind.Date, EdmPrimitiveTypeKind.TimeOfDay,
+        EdmPrimitiveTypeKind.DateTimeOffset, EdmPrimitiveTypeKind.Duration);
+    if (!(((EdmPrimitiveType) leftType).isCompatible((EdmPrimitiveType) rightType)
+    || ((EdmPrimitiveType) rightType).isCompatible((EdmPrimitiveType) leftType))) {
+      throw new UriParserSemanticException("Incompatible types.",
+          UriParserSemanticException.MessageKeys.UNKNOWN_TYPE, ""); // TODO: better message
+    }
+  }
+
+  private void checkAddSubTypes(final Expression left, final Expression right, final boolean isAdd)
+      throws UriParserException {
+    final EdmType leftType = getType(left);
+    final EdmType rightType = getType(right);
+    if (leftType == null || rightType == null
+        || isType(left,
+            EdmPrimitiveTypeKind.Int16, EdmPrimitiveTypeKind.Int32, EdmPrimitiveTypeKind.Int64,
+            EdmPrimitiveTypeKind.Byte, EdmPrimitiveTypeKind.SByte,
+            EdmPrimitiveTypeKind.Decimal, EdmPrimitiveTypeKind.Single, EdmPrimitiveTypeKind.Double)
+        && isType(right,
+            EdmPrimitiveTypeKind.Int16, EdmPrimitiveTypeKind.Int32, EdmPrimitiveTypeKind.Int64,
+            EdmPrimitiveTypeKind.Byte, EdmPrimitiveTypeKind.SByte,
+            EdmPrimitiveTypeKind.Decimal, EdmPrimitiveTypeKind.Single, EdmPrimitiveTypeKind.Double)) {
+      return;
+    }
+    if (isType(left, EdmPrimitiveTypeKind.DateTimeOffset)
+        && (isType(right, EdmPrimitiveTypeKind.Duration)
+        || isType(right, EdmPrimitiveTypeKind.DateTimeOffset) && !isAdd)) {
+      return;
+    }
+    if (isType(left, EdmPrimitiveTypeKind.Duration) && isType(right, EdmPrimitiveTypeKind.Duration)
+        || isType(left, EdmPrimitiveTypeKind.Date)
+        && (isType(right, EdmPrimitiveTypeKind.Duration) || isType(right, EdmPrimitiveTypeKind.Date) && !isAdd)) {
+      return;
+    }
+    throw new UriParserSemanticException("Incompatible types.",
+        UriParserSemanticException.MessageKeys.UNKNOWN_TYPE, ""); // TODO: better message
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/104ecf43/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 3f7f70c..9d29ab2 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
@@ -738,7 +738,8 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
     return new BinaryImpl(
         (Expression) ctx.vE1.accept(this),
         tokenIndex == UriLexer.ADD ? BinaryOperatorKind.ADD : BinaryOperatorKind.SUB,
-        (Expression) ctx.vE2.accept(this));
+        (Expression) ctx.vE2.accept(this),
+        null);
   }
 
   @Override
@@ -785,7 +786,8 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
     return new BinaryImpl(
         (Expression) ctx.vE1.accept(this),
         BinaryOperatorKind.AND,
-        (Expression) ctx.vE2.accept(this));
+        (Expression) ctx.vE2.accept(this),
+        EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Boolean));
   }
 
   @Override
@@ -815,7 +817,8 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
     return new BinaryImpl(
         (Expression) ctx.vE1.accept(this),
         kind,
-        (Expression) ctx.vE2.accept(this));
+        (Expression) ctx.vE2.accept(this),
+        EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Boolean));
   }
 
   @Override
@@ -843,7 +846,8 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
     return new BinaryImpl(
         (Expression) ctx.vE1.accept(this),
         tokenIndex == UriLexer.EQ_ALPHA ? BinaryOperatorKind.EQ : BinaryOperatorKind.NE,
-        (Expression) ctx.vE2.accept(this));
+        (Expression) ctx.vE2.accept(this),
+        EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Boolean));
   }
 
   @Override
@@ -851,7 +855,8 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
     return new BinaryImpl(
         (Expression) ctx.vE1.accept(this),
         BinaryOperatorKind.HAS,
-        (Expression) ctx.vE2.accept(this));
+        (Expression) ctx.vE2.accept(this),
+        EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Boolean));
   }
 
   @Override
@@ -875,7 +880,8 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
     return new BinaryImpl(
         (Expression) ctx.vE1.accept(this),
         kind,
-        (Expression) ctx.vE2.accept(this));
+        (Expression) ctx.vE2.accept(this),
+        null);
   }
 
   @Override
@@ -883,7 +889,8 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
     return new BinaryImpl(
         (Expression) ctx.vE1.accept(this),
         BinaryOperatorKind.OR,
-        (Expression) ctx.vE2.accept(this));
+        (Expression) ctx.vE2.accept(this),
+        EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Boolean));
   }
 
   @Override
@@ -2294,7 +2301,8 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
   public Expression visitAltUnary(@NotNull final UriParserParser.AltUnaryContext ctx) {
     return new UnaryImpl(
         ctx.unary().NOT() == null ? UnaryOperatorKind.MINUS : UnaryOperatorKind.NOT,
-        (Expression) ctx.commonExpr().accept(this));
+        (Expression) ctx.commonExpr().accept(this),
+        null);
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/104ecf43/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java
index a40f4ec..4b43cd9 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java
@@ -80,6 +80,7 @@ public class UriTokenizer {
     GreaterThanOrEqualsOperator,
     LessThanOperator,
     LessThanOrEqualsOperator,
+    HasOperator,
     AddOperator,
     SubOperator,
     MulOperator,
@@ -140,6 +141,7 @@ public class UriTokenizer {
    * The order in which this method is called with different token kinds is important,
    * not only for performance reasons but also if tokens can start with the same characters
    * (e.g., a qualified name starts with an OData identifier).
+   * The index is advanced to the end of this token if the token is found.
    * @param allowedTokenKind the kind of token to expect
    * @return <code>true</code> if the token is found; <code>false</code> otherwise
    * @see #getText()
@@ -288,6 +290,9 @@ public class UriTokenizer {
     case LessThanOrEqualsOperator:
       found = nextBinaryOperator("le");
       break;
+    case HasOperator:
+      found = nextBinaryOperator("has");
+      break;
     case AddOperator:
       found = nextBinaryOperator("add");
       break;

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/104ecf43/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/BinaryImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/BinaryImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/BinaryImpl.java
index 3f2e8f2..2439bcf 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/BinaryImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/BinaryImpl.java
@@ -18,6 +18,7 @@
  */
 package org.apache.olingo.server.core.uri.queryoption.expression;
 
+import org.apache.olingo.commons.api.edm.EdmType;
 import org.apache.olingo.server.api.ODataApplicationException;
 import org.apache.olingo.server.api.uri.queryoption.expression.Binary;
 import org.apache.olingo.server.api.uri.queryoption.expression.BinaryOperatorKind;
@@ -30,11 +31,14 @@ public class BinaryImpl implements Binary {
   private final Expression left;
   private final BinaryOperatorKind operator;
   private final Expression right;
+  private final EdmType type;
 
-  public BinaryImpl(final Expression left, final BinaryOperatorKind operator, final Expression right) {
+  public BinaryImpl(final Expression left, final BinaryOperatorKind operator, final Expression right,
+      final EdmType type) {
     this.left = left;
     this.operator = operator;
     this.right = right;
+    this.type = type;
   }
 
   @Override
@@ -52,6 +56,10 @@ public class BinaryImpl implements Binary {
     return right;
   }
 
+  public EdmType getType() {
+    return type;
+  }
+
   @Override
   public <T> T accept(final ExpressionVisitor<T> visitor) throws ExpressionVisitException, ODataApplicationException {
     T left = this.left.accept(visitor);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/104ecf43/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MethodImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MethodImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MethodImpl.java
index 1c8ce64..0346292 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MethodImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MethodImpl.java
@@ -22,12 +22,16 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
+import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
+import org.apache.olingo.commons.api.edm.EdmType;
 import org.apache.olingo.server.api.ODataApplicationException;
 import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
 import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitException;
 import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitor;
 import org.apache.olingo.server.api.uri.queryoption.expression.Method;
 import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind;
+import org.apache.olingo.server.api.uri.queryoption.expression.TypeLiteral;
+import org.apache.olingo.server.core.ODataImpl;
 
 public class MethodImpl implements Method {
 
@@ -44,6 +48,72 @@ public class MethodImpl implements Method {
     return method;
   }
 
+  public EdmType getType() {
+    EdmPrimitiveTypeKind kind = null;
+    switch (method) {
+    case CONTAINS:
+    case STARTSWITH:
+    case ENDSWITH:
+      kind = EdmPrimitiveTypeKind.Boolean;
+      break;
+    case LENGTH:
+    case INDEXOF:
+      kind = EdmPrimitiveTypeKind.Int32;
+      break;
+    case SUBSTRING:
+    case TOLOWER:
+    case TOUPPER:
+    case TRIM:
+    case CONCAT:
+      kind = EdmPrimitiveTypeKind.String;
+      break;
+    case YEAR:
+    case MONTH:
+    case DAY:
+    case HOUR:
+    case MINUTE:
+    case SECOND:
+      kind = EdmPrimitiveTypeKind.Int32;
+      break;
+    case FRACTIONALSECONDS:
+    case TOTALSECONDS:
+      kind = EdmPrimitiveTypeKind.Decimal;
+      break;
+    case DATE:
+      kind = EdmPrimitiveTypeKind.Date;
+      break;
+    case TIME:
+      kind = EdmPrimitiveTypeKind.TimeOfDay;
+      break;
+    case TOTALOFFSETMINUTES:
+      kind = EdmPrimitiveTypeKind.Int32;
+      break;
+    case MINDATETIME:
+    case MAXDATETIME:
+    case NOW:
+      kind = EdmPrimitiveTypeKind.DateTimeOffset;
+      break;
+    case ROUND:
+    case FLOOR:
+    case CEILING:
+      kind = EdmPrimitiveTypeKind.Double; // Needs to be refined if Decimal must be distinguished from Double.
+      break;
+    case GEODISTANCE:
+    case GEOLENGTH:
+      kind = EdmPrimitiveTypeKind.Double;
+      break;
+    case GEOINTERSECTS:
+      kind = EdmPrimitiveTypeKind.Boolean;
+      break;
+    case CAST:
+      return ((TypeLiteral) parameters.get(parameters.size() - 1)).getType();
+    case ISOF:
+      kind = EdmPrimitiveTypeKind.Boolean;
+      break;
+    }
+    return new ODataImpl().createPrimitiveTypeInstance(kind);
+  }
+
   @Override
   public List<Expression> getParameters() {
     return parameters == null ?

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/104ecf43/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/UnaryImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/UnaryImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/UnaryImpl.java
index 910997e..86639a6 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/UnaryImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/UnaryImpl.java
@@ -18,6 +18,7 @@
  */
 package org.apache.olingo.server.core.uri.queryoption.expression;
 
+import org.apache.olingo.commons.api.edm.EdmType;
 import org.apache.olingo.server.api.ODataApplicationException;
 import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
 import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitException;
@@ -29,10 +30,12 @@ public class UnaryImpl implements Unary {
 
   private final UnaryOperatorKind operator;
   private final Expression expression;
+  private final EdmType type;
 
-  public UnaryImpl(final UnaryOperatorKind operator, final Expression expression) {
+  public UnaryImpl(final UnaryOperatorKind operator, final Expression expression, final EdmType type) {
     this.operator = operator;
     this.expression = expression;
+    this.type = type;
   }
 
   @Override
@@ -45,6 +48,10 @@ public class UnaryImpl implements Unary {
     return expression;
   }
 
+  public EdmType getType() {
+    return type;
+  }
+
   @Override
   public <T> T accept(final ExpressionVisitor<T> visitor) throws ExpressionVisitException, ODataApplicationException {
     T operand = expression.accept(visitor);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/104ecf43/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java
index 58f2a1f..183ff22 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java
@@ -21,15 +21,19 @@ package org.apache.olingo.server.core.uri.parser;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import java.util.Locale;
 
+import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
 import org.apache.olingo.server.core.uri.parser.UriTokenizer.TokenKind;
 import org.junit.Test;
 
 public class ExpressionParserTest {
 
+  private final OData odata = OData.newInstance();
+
   @Test
   public void equality() throws Exception {
     Expression expression = parseExpression("5 eq 5");
@@ -37,6 +41,12 @@ public class ExpressionParserTest {
 
     expression = parseExpression("5 ne 5");
     assertEquals("{5 NE 5}", expression.toString());
+
+    assertEquals("{1 EQ null}", parseExpression("1 eq null").toString());
+    assertEquals("{null NE 2}", parseExpression("null ne 2").toString());
+    assertEquals("{null EQ null}", parseExpression("null eq null").toString());
+
+    wrongExpression("5 eq '5'");
   }
 
   @Test
@@ -52,6 +62,14 @@ public class ExpressionParserTest {
 
     expression = parseExpression("5 le 5");
     assertEquals("{5 LE 5}", expression.toString());
+
+    assertEquals("{5 LE 5.1}", parseExpression("5 le 5.1").toString());
+
+    assertEquals("{1 GT null}", parseExpression("1 gt null").toString());
+    assertEquals("{null GE 2}", parseExpression("null ge 2").toString());
+    assertEquals("{null LE null}", parseExpression("null le null").toString());
+
+    wrongExpression("5 gt duration'PT5H'");
   }
 
   @Test
@@ -59,8 +77,37 @@ public class ExpressionParserTest {
     Expression expression = parseExpression("5 add 5");
     assertEquals("{5 ADD 5}", expression.toString());
 
-    expression = parseExpression("5 sub 5");
-    assertEquals("{5 SUB 5}", expression.toString());
+    expression = parseExpression("5 sub 5.1");
+    assertEquals("{5 SUB 5.1}", expression.toString());
+
+    expression = parseExpression("2000-02-29 sub 2016-02-29");
+    assertEquals("{2000-02-29 SUB 2016-02-29}", expression.toString());
+
+    expression = parseExpression("2000-02-29T00:00:00Z sub 2016-02-29T01:02:03Z");
+    assertEquals("{2000-02-29T00:00:00Z SUB 2016-02-29T01:02:03Z}", expression.toString());
+
+    expression = parseExpression("duration'PT1H' add duration'PT1M'");
+    assertEquals("{duration'PT1H' ADD duration'PT1M'}", expression.toString());
+
+    expression = parseExpression("2016-01-01 add duration'P60D'");
+    assertEquals("{2016-01-01 ADD duration'P60D'}", expression.toString());
+
+    expression = parseExpression("2000-02-29T00:00:00Z add duration'PT12H'");
+    assertEquals("{2000-02-29T00:00:00Z ADD duration'PT12H'}", expression.toString());
+
+    assertEquals("{1 ADD null}", parseExpression("1 add null").toString());
+    assertEquals("{null ADD 2}", parseExpression("null add 2").toString());
+    assertEquals("{null SUB null}", parseExpression("null sub null").toString());
+
+    wrongExpression("1 add '2'");
+    wrongExpression("'1' add 2");
+    wrongExpression("1 add 2000-02-29");
+    wrongExpression("11:12:13 sub 2000-02-29T11:12:13Z");
+    wrongExpression("2000-02-29 add 2016-02-29");
+    wrongExpression("2000-02-29T00:00:00Z add 2016-02-29T01:02:03Z");
+    wrongExpression("2000-02-29T00:00:00Z add 1");
+    wrongExpression("2000-02-29 sub 1");
+    wrongExpression("duration'P7D' add 2000-02-29");
   }
 
   @Test
@@ -73,6 +120,8 @@ public class ExpressionParserTest {
 
     expression = parseExpression("5 mod 5");
     assertEquals("{5 MOD 5}", expression.toString());
+
+    wrongExpression("1 mod '2'");
   }
 
   @Test
@@ -81,9 +130,12 @@ public class ExpressionParserTest {
     assertEquals("{MINUS 5}", expression.toString());
 
     assertEquals("{MINUS -1}", parseExpression("--1").toString());
+    assertEquals("{MINUS duration'PT1M'}", parseExpression("-duration'PT1M'").toString());
+
+    expression = parseExpression("not false");
+    assertEquals("{NOT false}", expression.toString());
 
-    expression = parseExpression("not 5");
-    assertEquals("{NOT 5}", expression.toString());
+    wrongExpression("-11:12:13");
   }
 
   @Test
@@ -111,6 +163,8 @@ public class ExpressionParserTest {
 
     expression = parseMethod(TokenKind.MindatetimeMethod);
     assertEquals("{mindatetime []}", expression.toString());
+
+    wrongExpression("now(1)");
   }
 
   @Test
@@ -148,16 +202,79 @@ public class ExpressionParserTest {
 
     expression = parseMethod(TokenKind.SecondMethod, dateTimeOffsetValue);
     assertEquals("{second [" + dateTimeOffsetValue + "]}", expression.toString());
+
+    expression = parseMethod(TokenKind.DateMethod, dateTimeOffsetValue);
+    assertEquals("{date [" + dateTimeOffsetValue + "]}", expression.toString());
+
+    expression = parseMethod(TokenKind.TotalsecondsMethod, "duration'PT1H'");
+    assertEquals("{totalseconds [duration'PT1H']}", expression.toString());
+
+    expression = parseMethod(TokenKind.RoundMethod, "3.141592653589793");
+    assertEquals("{round [3.141592653589793]}", expression.toString());
+
+    assertEquals("{hour [null]}", parseMethod(TokenKind.HourMethod, new String[] { null }).toString());
+
+    wrongExpression("trim()");
+    wrongExpression("trim(1)");
+    wrongExpression("ceiling('1.2')");
+  }
+
+  @Test
+  public void twoParameterMethods() throws Exception {
+    Expression expression = parseMethod(TokenKind.ContainsMethod, "'a'", "'b'");
+    assertEquals("{contains ['a', 'b']}", expression.toString());
+
+    expression = parseMethod(TokenKind.EndswithMethod, "'a'", "'b'");
+    assertEquals("{endswith ['a', 'b']}", expression.toString());
+
+    expression = parseMethod(TokenKind.StartswithMethod, "'a'", "'b'");
+    assertEquals("{startswith ['a', 'b']}", expression.toString());
+
+    expression = parseMethod(TokenKind.IndexofMethod, "'a'", "'b'");
+    assertEquals("{indexof ['a', 'b']}", expression.toString());
+
+    expression = parseMethod(TokenKind.ConcatMethod, "'a'", "'b'");
+    assertEquals("{concat ['a', 'b']}", expression.toString());
+
+    // TODO: Geo methods.
+//    expression = parseMethod(TokenKind.GeoDistanceMethod,
+//        "geography'SRID=0;Point(1.2 3.4)'", "geography'SRID=0;Point(5.6 7.8)'");
+//    assertEquals("{geo.distance [geography'SRID=0;Point(1.2 3.4)', geography'SRID=0;Point(5.6 7.8)']}",
+//        expression.toString());
+//
+//    expression = parseMethod(TokenKind.GeoIntersectsMethod);
+//    assertEquals("{geo.intersects []}", expression.toString());
+
+    assertEquals("{startswith [null, 'b']}", parseMethod(TokenKind.StartswithMethod, null, "'b'").toString());
+    assertEquals("{indexof ['a', null]}", parseMethod(TokenKind.IndexofMethod, "'a'", null).toString());
+
+    wrongExpression("concat('a')");
+    wrongExpression("endswith('a',1)");
+}
+
+  @Test
+  public void variableParameterNumberMethods() throws Exception {
+    Expression expression = parseMethod(TokenKind.SubstringMethod, "'abc'", "1", "2");
+    assertEquals("{substring ['abc', 1, 2]}", expression.toString());
+    expression = parseMethod(TokenKind.SubstringMethod, "'abc'", "1");
+    assertEquals("{substring ['abc', 1]}", expression.toString());
+
+    wrongExpression("substring('abc')");
+    wrongExpression("substring('abc',1,2,3)");
+    wrongExpression("substring(1,2)");
   }
 
   private Expression parseMethod(TokenKind kind, String... parameters) throws UriParserException {
     String expressionString = kind.name().substring(0, kind.name().indexOf("Method"))
         .toLowerCase(Locale.ROOT).replace("geo", "geo.") + '(';
-    for (int i = 0; i < parameters.length; i++) {
-      if (i > 0) {
+    boolean first = true;
+    for (final String parameter : parameters) {
+      if (first) {
+        first = false;
+      } else {
         expressionString += ',';
       }
-      expressionString += parameters[i];
+      expressionString += parameter;
     }
     expressionString += ')';
 
@@ -168,9 +285,18 @@ public class ExpressionParserTest {
 
   private Expression parseExpression(final String expressionString) throws UriParserException {
     UriTokenizer tokenizer = new UriTokenizer(expressionString);
-    Expression expression = new ExpressionParser().parse(tokenizer);
+    Expression expression = new ExpressionParser(null, odata).parse(tokenizer);
     assertNotNull(expression);
     assertTrue(tokenizer.next(TokenKind.EOF));
     return expression;
   }
+
+  private void wrongExpression(final String expressionString) {
+    try {
+      new ExpressionParser(null, odata).parse(new UriTokenizer(expressionString));
+      fail("Expected exception not thrown.");
+    } catch (final UriParserException e) {
+      assertNotNull(e);
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/104ecf43/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java
index b5614ad..1b2d508 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/UriTokenizerTest.java
@@ -412,7 +412,7 @@ public class UriTokenizerTest {
     assertTrue(tokenizer.next(TokenKind.IntegerValue));
     assertTrue(tokenizer.next(TokenKind.EOF));
 
-    tokenizer = new UriTokenizer("1 gt 2 or 3 ge 4 or 5 lt 6");
+    tokenizer = new UriTokenizer("1 gt 2 or 3 ge 4 or 5 lt 6 or 7 has namespace.name'flag1,flag2'");
     assertTrue(tokenizer.next(TokenKind.IntegerValue));
     assertTrue(tokenizer.next(TokenKind.GreaterThanOperator));
     assertTrue(tokenizer.next(TokenKind.IntegerValue));
@@ -424,6 +424,10 @@ public class UriTokenizerTest {
     assertTrue(tokenizer.next(TokenKind.IntegerValue));
     assertTrue(tokenizer.next(TokenKind.LessThanOperator));
     assertTrue(tokenizer.next(TokenKind.IntegerValue));
+    assertTrue(tokenizer.next(TokenKind.OrOperator));
+    assertTrue(tokenizer.next(TokenKind.IntegerValue));
+    assertTrue(tokenizer.next(TokenKind.HasOperator));
+    assertTrue(tokenizer.next(TokenKind.EnumValue));
     assertTrue(tokenizer.next(TokenKind.EOF));
   }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/104ecf43/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/queryoption/expression/ExpressionTest.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/queryoption/expression/ExpressionTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/queryoption/expression/ExpressionTest.java
index ec5ce6e..864b17a 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/queryoption/expression/ExpressionTest.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/queryoption/expression/ExpressionTest.java
@@ -31,14 +31,13 @@ import org.apache.olingo.commons.api.edm.EdmAction;
 import org.apache.olingo.commons.api.edm.EdmEntityType;
 import org.apache.olingo.commons.api.edm.EdmEnumType;
 import org.apache.olingo.commons.api.edm.EdmFunction;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
 import org.apache.olingo.server.api.OData;
-import org.apache.olingo.server.api.ODataApplicationException;
 import org.apache.olingo.server.api.edmx.EdmxReference;
 import org.apache.olingo.server.api.uri.UriInfoKind;
 import org.apache.olingo.server.api.uri.UriInfoResource;
 import org.apache.olingo.server.api.uri.queryoption.expression.BinaryOperatorKind;
 import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
-import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitException;
 import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind;
 import org.apache.olingo.server.api.uri.queryoption.expression.UnaryOperatorKind;
 import org.apache.olingo.server.core.uri.UriInfoImpl;
@@ -53,7 +52,8 @@ import org.apache.olingo.server.tecsvc.provider.FunctionProvider;
 import org.junit.Test;
 
 public class ExpressionTest {
-  private static final Edm edm = OData.newInstance().createServiceMetadata(
+  private static final OData odata = OData.newInstance();
+  private static final Edm edm = odata.createServiceMetadata(
       new EdmTechProvider(), Collections.<EdmxReference> emptyList()).getEdm();
 
   @Test
@@ -69,7 +69,7 @@ public class ExpressionTest {
   }
 
   @Test
-  public void aliasExpression() throws ExpressionVisitException, ODataApplicationException {
+  public void aliasExpression() throws Exception {
     AliasImpl expression = new AliasImpl("Test");
 
     assertEquals("Test", expression.getParameterName());
@@ -79,47 +79,50 @@ public class ExpressionTest {
   }
 
   @Test
-  public void binaryExpression() throws ExpressionVisitException, ODataApplicationException {
-    Expression expressionLeft = new LiteralImpl("A", null);
-    Expression expressionRight = new LiteralImpl("B", null);
+  public void binaryExpression() throws Exception {
+    Expression expressionLeft = new LiteralImpl("2", odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Byte));
+    Expression expressionRight = new LiteralImpl("-1", odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.SByte));
 
-    BinaryImpl expression = new BinaryImpl(expressionLeft, BinaryOperatorKind.SUB, expressionRight);
+    BinaryImpl expression = new BinaryImpl(expressionLeft, BinaryOperatorKind.SUB, expressionRight,
+        odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Byte));
 
     assertEquals(expressionLeft, expression.getLeftOperand());
     assertEquals(expressionRight, expression.getRightOperand());
     assertEquals(BinaryOperatorKind.SUB, expression.getOperator());
+    assertEquals(odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Byte), expression.getType());
 
     String output = expression.accept(new FilterTreeToText());
-    assertEquals("<<A> sub <B>>", output);
+    assertEquals("<<2> sub <-1>>", output);
   }
 
   @Test
-  public void enumerationExpression() throws ExpressionVisitException, ODataApplicationException {
+  public void enumerationExpression() throws Exception {
     EdmEnumType type = edm.getEnumType(EnumTypeProvider.nameENString);
     assertNotNull(type);
-    EnumerationImpl expression = new EnumerationImpl(type, Arrays.asList("A", "B"));
+    EnumerationImpl expression = new EnumerationImpl(type, Arrays.asList("String1", "String2"));
     assertEquals(type, expression.getType());
-    assertEquals("A", expression.getValues().get(0));
-    assertEquals("B", expression.getValues().get(1));
-    assertEquals("<olingo.odata.test1.ENString<A,B>>", expression.accept(new FilterTreeToText()));
+    assertEquals("String1", expression.getValues().get(0));
+    assertEquals("String2", expression.getValues().get(1));
+    assertEquals("<olingo.odata.test1.ENString<String1,String2>>", expression.accept(new FilterTreeToText()));
   }
 
   @Test
-  public void lambdaRefExpression() throws ExpressionVisitException, ODataApplicationException {
+  public void lambdaRefExpression() throws Exception {
     LambdaRefImpl expression = new LambdaRefImpl("A");
     assertEquals("A", expression.getVariableName());
     assertEquals("<A>", expression.accept(new FilterTreeToText()));
   }
 
   @Test
-  public void literalExpression() throws ExpressionVisitException, ODataApplicationException {
-    LiteralImpl expression = new LiteralImpl("A", null);
-    assertEquals("A", expression.getText());
-    assertEquals("<A>", expression.accept(new FilterTreeToText()));
+  public void literalExpression() throws Exception {
+    LiteralImpl expression = new LiteralImpl("'A'", odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.String));
+    assertEquals("'A'", expression.getText());
+    assertEquals("<'A'>", expression.accept(new FilterTreeToText()));
+    assertEquals(odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.String), expression.getType());
   }
 
   @Test
-  public void memberExpression() throws ExpressionVisitException, ODataApplicationException {
+  public void memberExpression() throws Exception {
     EdmEntityType entityType = edm.getEntityType(EntityTypeProvider.nameETKeyNav);
 
     // UriResourceImpl
@@ -189,20 +192,21 @@ public class ExpressionTest {
   }
 
   @Test
-  public void methodCallExpression() throws ExpressionVisitException, ODataApplicationException {
-    Expression p0 = new LiteralImpl("A", null);
-    Expression p1 = new LiteralImpl("B", null);
+  public void methodCallExpression() throws Exception {
+    Expression p0 = new LiteralImpl("'A'", odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.String));
+    Expression p1 = new LiteralImpl("'B'", odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.String));
     MethodImpl expression = new MethodImpl(MethodKind.CONCAT, Arrays.asList(p0, p1));
 
     assertEquals(MethodKind.CONCAT, expression.getMethod());
-    assertEquals("<concat(<A>,<B>)>", expression.accept(new FilterTreeToText()));
+    assertEquals("<concat(<'A'>,<'B'>)>", expression.accept(new FilterTreeToText()));
+    assertEquals(odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.String), expression.getType());
 
     assertEquals(p0, expression.getParameters().get(0));
     assertEquals(p1, expression.getParameters().get(1));
   }
 
   @Test
-  public void typeLiteralExpression() throws ExpressionVisitException, ODataApplicationException {
+  public void typeLiteralExpression() throws Exception {
     EdmEntityType entityBaseType = edm.getEntityType(EntityTypeProvider.nameETBaseTwoKeyNav);
     TypeLiteralImpl expression = new TypeLiteralImpl(entityBaseType);
 
@@ -211,13 +215,15 @@ public class ExpressionTest {
   }
 
   @Test
-  public void unaryExpression() throws ExpressionVisitException, ODataApplicationException {
-    Expression operand = new LiteralImpl("A", null);
-    UnaryImpl expression = new UnaryImpl(UnaryOperatorKind.MINUS, operand);
+  public void unaryExpression() throws Exception {
+    Expression operand = new LiteralImpl("1.2", odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Decimal));
+    UnaryImpl expression = new UnaryImpl(UnaryOperatorKind.MINUS, operand,
+        odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Decimal));
 
     assertEquals(UnaryOperatorKind.MINUS, expression.getOperator());
     assertEquals(operand, expression.getOperand());
+    assertEquals(odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Decimal), expression.getType());
 
-    assertEquals("<- <A>>", expression.accept(new FilterTreeToText()));
+    assertEquals("<- <1.2>>", expression.accept(new FilterTreeToText()));
   }
 }


[07/30] olingo-odata4 git commit: Merge remote-tracking branch 'origin/OLINGO-834_RefactorUriParsing' into OLINGO-834_Filter_Parser

Posted by ch...@apache.org.
Merge remote-tracking branch 'origin/OLINGO-834_RefactorUriParsing' into OLINGO-834_Filter_Parser


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

Branch: refs/heads/master
Commit: ef19c9be1f6714b7c50aea3ff5623bb2d5857653
Parents: 7b23ad7 7bc932a
Author: Christian Amend <ch...@sap.com>
Authored: Thu Dec 10 15:34:39 2015 +0100
Committer: Christian Amend <ch...@sap.com>
Committed: Thu Dec 10 15:34:39 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(-)
----------------------------------------------------------------------



[23/30] olingo-odata4 git commit: [OLINGO-834] $expand parser in Java + clean-up

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8925274c/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
deleted file mode 100644
index 1bab218..0000000
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParseTreeVisitor.java
+++ /dev/null
@@ -1,2313 +0,0 @@
-/*
- * 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.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-import org.antlr.v4.runtime.misc.NotNull;
-import org.antlr.v4.runtime.misc.ParseCancellationException;
-import org.antlr.v4.runtime.tree.ParseTree;
-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.EdmComplexType;
-import org.apache.olingo.commons.api.edm.EdmElement;
-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.EdmEnumType;
-import org.apache.olingo.commons.api.edm.EdmFunction;
-import org.apache.olingo.commons.api.edm.EdmFunctionImport;
-import org.apache.olingo.commons.api.edm.EdmNavigationProperty;
-import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
-import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
-import org.apache.olingo.commons.api.edm.EdmProperty;
-import org.apache.olingo.commons.api.edm.EdmReturnType;
-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.FullQualifiedName;
-import org.apache.olingo.commons.api.edm.constants.EdmTypeKind;
-import org.apache.olingo.commons.api.ex.ODataRuntimeException;
-import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
-import org.apache.olingo.server.api.uri.UriInfoKind;
-import org.apache.olingo.server.api.uri.UriInfoResource;
-import org.apache.olingo.server.api.uri.UriParameter;
-import org.apache.olingo.server.api.uri.UriResource;
-import org.apache.olingo.server.api.uri.UriResourceEntitySet;
-import org.apache.olingo.server.api.uri.UriResourceFunction;
-import org.apache.olingo.server.api.uri.UriResourceNavigation;
-import org.apache.olingo.server.api.uri.UriResourcePartTyped;
-import org.apache.olingo.server.api.uri.UriResourceRoot;
-import org.apache.olingo.server.api.uri.queryoption.SelectItem;
-import org.apache.olingo.server.api.uri.queryoption.expression.BinaryOperatorKind;
-import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
-import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind;
-import org.apache.olingo.server.api.uri.queryoption.expression.UnaryOperatorKind;
-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.UriResourceImpl;
-import org.apache.olingo.server.core.uri.UriResourceItImpl;
-import org.apache.olingo.server.core.uri.UriResourceLambdaAllImpl;
-import org.apache.olingo.server.core.uri.UriResourceLambdaAnyImpl;
-import org.apache.olingo.server.core.uri.UriResourceLambdaVarImpl;
-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.UriResourceRootImpl;
-import org.apache.olingo.server.core.uri.UriResourceSingletonImpl;
-import org.apache.olingo.server.core.uri.UriResourceStartingTypeFilterImpl;
-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.antlr.UriLexer;
-import org.apache.olingo.server.core.uri.antlr.UriParserBaseVisitor;
-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.AllExprContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.AltAddContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.AltAllContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.AltAndContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.AltAnyContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.AltComparismContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.AltEqualityContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.AltHasContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.AltMultContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.AltOrContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.AnyExprContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.ArrayOrObjectContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.BinaryLiteralContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.BooleanNonCaseLiteralContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.CastExprContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.CeilingMethodCallExprContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.ConcatMethodCallExprContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.ConstSegmentContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.ContainsMethodCallExprContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.DateLiteralContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.DateMethodCallExprContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.DatetimeoffsetLiteralContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.DayMethodCallExprContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.DecimalLiteralContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.DurationLiteralContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.EndsWithMethodCallExprContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.EntityEOFContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.EnumLiteralContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandCountOptionContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandItemContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandItemsContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandItemsEOFContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandOptionContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandPathContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandPathExtensionContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandRefOptionContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.FilterContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.FilterExpressionEOFContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.FloorMethodCallExprContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.FractionalsecondsMethodCallExprContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.GeoDistanceMethodCallExprContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.GeoIntersectsMethodCallExprContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.GeoLengthMethodCallExprContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.GuidLiteralContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.HourMethodCallExprContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.IndexOfMethodCallExprContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.InlinecountContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.IntLiteralContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.IsofExprContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.LengthMethodCallExprContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.LevelsContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.MaxDateTimeMethodCallExprContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.MemberExprContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.MetadataEOFContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.MinDateTimeMethodCallExprContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.MinuteMethodCallExprContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.MonthMethodCallExprContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.NameValueOptListContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.NameValuePairContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.NamespaceContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.NaninfinityLiteralContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.NowMethodCallExprContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.NullruleLiteralContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.OrderByContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.OrderByEOFContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.OrderByItemContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.OrderListContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.PathSegmentContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.PathSegmentsContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.PrimitiveLiteralContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.QueryOptionContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.QueryOptionsContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.RootExprContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.RoundMethodCallExprContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.SearchSpecialTokenContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.SecondMethodCallExprContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.SelectContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.SelectEOFContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.SelectItemContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.SelectSegmentContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.SkipContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.SkiptokenContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.StartsWithMethodCallExprContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.StringLiteralContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.SubstringMethodCallExprContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.TimeMethodCallExprContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.TimeofdayLiteralContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.ToLowerMethodCallExprContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.ToUpperMethodCallExprContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.TopContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.TotalOffsetMinutesMethodCallExprContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.TotalsecondsMethodCallExprContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.TrimMethodCallExprContext;
-import org.apache.olingo.server.core.uri.antlr.UriParserParser.YearMethodCallExprContext;
-import org.apache.olingo.server.core.uri.parser.UriParserSemanticException.MessageKeys;
-import org.apache.olingo.server.core.uri.queryoption.CountOptionImpl;
-import org.apache.olingo.server.core.uri.queryoption.ExpandItemImpl;
-import org.apache.olingo.server.core.uri.queryoption.ExpandOptionImpl;
-import org.apache.olingo.server.core.uri.queryoption.FilterOptionImpl;
-import org.apache.olingo.server.core.uri.queryoption.LevelsOptionImpl;
-import org.apache.olingo.server.core.uri.queryoption.OrderByItemImpl;
-import org.apache.olingo.server.core.uri.queryoption.OrderByOptionImpl;
-import org.apache.olingo.server.core.uri.queryoption.QueryOptionImpl;
-import org.apache.olingo.server.core.uri.queryoption.SelectItemImpl;
-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.SystemQueryOptionImpl;
-import org.apache.olingo.server.core.uri.queryoption.TopOptionImpl;
-import org.apache.olingo.server.core.uri.queryoption.expression.AliasImpl;
-import org.apache.olingo.server.core.uri.queryoption.expression.BinaryImpl;
-import org.apache.olingo.server.core.uri.queryoption.expression.EnumerationImpl;
-import org.apache.olingo.server.core.uri.queryoption.expression.LiteralImpl;
-import org.apache.olingo.server.core.uri.queryoption.expression.MemberImpl;
-import org.apache.olingo.server.core.uri.queryoption.expression.MethodImpl;
-import org.apache.olingo.server.core.uri.queryoption.expression.TypeLiteralImpl;
-import org.apache.olingo.server.core.uri.queryoption.expression.UnaryImpl;
-
-/**
- * Converts the URI parse tree as generated by ANTLR into an internal representation
- * suitable to give to an application.
- * While converting the tree is only validated against the EDM if necessary.
- * <br>
- * Attention:
- * <ul>
- * <li>This UriVisitor is at somes point more lax than the original ABNF.</li>
- * <li>It is more tolerable against additional white spaces.</li>
- * </ul>
- * Currently not supported are
- * <ul>
- * <li>parsing the context of $metadata</li>
- * <li>parsing $search</li>
- * </ul>
- */
-public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
-
-  public UriContext context = null;
-
-  public Edm edm;
-
-  public EdmEntityContainer edmEntityContainer;
-
-  // --- class ---
-  public UriParseTreeVisitor(final Edm edm, final UriContext context) {
-    this.edm = edm;
-    this.context = context;
-    edmEntityContainer = edm.getEntityContainer();
-  }
-
-  @Override
-  protected Object aggregateResult(final Object aggregate, final Object nextResult) {
-    if (aggregate != null) {
-      return aggregate;
-    } else {
-      return nextResult;
-    }
-  }
-
-  private FullQualifiedName getFullNameFromContext(final NamespaceContext vNS, final String odi) {
-    String namespace = vNS.getText();
-    namespace = namespace.substring(0, namespace.length() - 1); // vNS contains a trailing point that has to be removed
-    return new FullQualifiedName(namespace, odi);
-  }
-
-  private UriContext.LambdaVariable getLambdaVar(final String odi) {
-    for (UriContext.LambdaVariable item : context.allowedLambdaVariables) {
-      if (item.name.equals(odi)) {
-        return item;
-      }
-    }
-    return null;
-  }
-
-  public UriResourceTypedImpl readResourcePathSegment(final PathSegmentContext ctx) {
-
-    final boolean checkFirst =
-        context.contextUriInfo.getLastResourcePart() == null
-            || context.contextUriInfo.getLastResourcePart() instanceof UriResourceRootImpl;
-
-    String odi = ctx.vODI.getText();
-
-    boolean searchInContainer = true;
-    // validate if context type and according property is available
-    // otherwise search in container for first element
-    if (checkFirst && ctx.vNS == null && !context.contextTypes.isEmpty()) {
-      EdmType sourceType = context.contextTypes.peek();
-      if (sourceType instanceof EdmStructuredType) {
-        EdmStructuredType str = (EdmStructuredType) sourceType;
-        EdmElement property = str.getProperty(odi);
-        if (property != null) {
-          searchInContainer = false;
-        }
-      }
-    }
-
-    if (searchInContainer) {
-      final List<UriResource> parts = context.contextUriInfo.getUriResourceParts();
-      // check EntitySet
-      EdmEntitySet edmEntitySet = edmEntityContainer.getEntitySet(odi);
-      if (edmEntitySet != null
-          && (parts.isEmpty() || !(parts.get(0) instanceof UriResourcePartTyped)
-              || parts.get(0) instanceof UriResourceRoot)) {
-        ensureNamespaceIsNull(ctx.vNS);
-        context.contextUriInfo.addResourcePart(
-            new UriResourceEntitySetImpl(edmEntitySet));
-        return null;
-      }
-
-      // check Singleton
-      EdmSingleton edmSingleton = edmEntityContainer.getSingleton(odi);
-      if (edmSingleton != null
-          && (parts.isEmpty() || !(parts.get(0) instanceof UriResourcePartTyped)
-              || parts.get(0) instanceof UriResourceRoot)) {
-        ensureNamespaceIsNull(ctx.vNS);
-        context.contextUriInfo.addResourcePart(
-            new UriResourceSingletonImpl(edmSingleton));
-        return null;
-      }
-
-      // check ActionImport
-      EdmActionImport edmActionImport = edmEntityContainer.getActionImport(odi);
-      if (edmActionImport != null
-          && (parts.isEmpty() || !(parts.get(0) instanceof UriResourcePartTyped)
-              || parts.get(0) instanceof UriResourceRoot)) {
-        ensureNamespaceIsNull(ctx.vNS);
-        context.contextUriInfo.addResourcePart(
-            new UriResourceActionImpl(edmActionImport));
-        return null;
-      }
-
-      // check FunctionImport
-      EdmFunctionImport edmFunctionImport = edmEntityContainer.getFunctionImport(odi);
-      
-      if(edmFunctionImport != null && context.contextReadingQueryPart) {
-        throw wrap(new UriParserSemanticException("Function Imports are not allowed in $filter or $orderby", 
-            UriParserSemanticException.MessageKeys.FUNCTION_IMPORT_NOT_ALLOWED, odi));
-      }
-      
-      if (edmFunctionImport != null
-          && (parts.isEmpty() || !(parts.get(0) instanceof UriResourcePartTyped)
-              || parts.get(0) instanceof UriResourceRoot)) {
-
-        // read the URI parameters
-        if (ctx.vlNVO.isEmpty()) {
-          throw wrap(new UriParserSyntaxException(
-              "Function imports must have a (possibly empty) parameter list written in parentheses",
-              UriParserSyntaxException.MessageKeys.SYNTAX));
-        }
-        context.contextReadingFunctionParameters = true;
-        @SuppressWarnings("unchecked")
-        List<UriParameter> parameters = (List<UriParameter>) ctx.vlNVO.get(0).accept(this);
-        context.contextReadingFunctionParameters = false;
-
-        // mark parameters as consumed
-        ctx.vlNVO.remove(0);
-
-        // collect parameter names
-        List<String> names = new ArrayList<String>();
-        for (UriParameter item : parameters) {
-          names.add(item.getName());
-        }
-
-        // get function from function import
-        EdmFunction function = edmFunctionImport.getUnboundFunction(names);
-        if (function == null) {
-          StringBuilder tmp = new StringBuilder();
-          for (String name : names) {
-            tmp.append((tmp.length() != 0 ? "," : "")).append(name);
-          }
-          throw wrap(new UriParserSemanticException("Function of functionimport '" + edmFunctionImport.getName()
-              + "' with parameters [" + tmp.toString() + "] not found",
-              UriParserSemanticException.MessageKeys.FUNCTION_NOT_FOUND, edmFunctionImport.getName(), tmp.toString()));
-        }
-
-        ensureNamespaceIsNull(ctx.vNS);
-        UriResourceFunctionImpl uriResource = new UriResourceFunctionImpl(edmFunctionImport,
-            edmFunctionImport.getUnboundFunction(names),
-            parameters);
-        context.contextUriInfo.addResourcePart(uriResource);
-        return null;
-      }
-    }
-
-    EdmType sourceType;
-    boolean sourceIsCollection = false;
-    final UriResource lastResourcePart = context.contextUriInfo.getLastResourcePart();
-
-    if (lastResourcePart == null) {
-      if (context.contextTypes.isEmpty()) {
-        if (checkFirst && ctx.vNS == null) {
-          throw wrap(new UriParserSemanticException(
-              "Cannot find EntitySet, Singleton, ActionImport or FunctionImport with name '" + odi + "'.",
-              UriParserSemanticException.MessageKeys.RESOURCE_NOT_FOUND, odi));
-        }
-        throw wrap(new UriParserSemanticException(
-            "Resource part '" + odi + "' can only applied on typed resource parts",
-            UriParserSemanticException.MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS, odi));
-      }
-      sourceType = context.contextTypes.peek();
-      sourceIsCollection = context.isCollection;
-    } else if (lastResourcePart instanceof UriResourcePartTyped) {
-      sourceType = ParserHelper.getTypeInformation((UriResourcePartTyped) lastResourcePart);
-      sourceIsCollection = ((UriResourcePartTyped) lastResourcePart).isCollection();
-    } else {
-      throw wrap(new UriParserSemanticException(
-          "Resource part '" + odi + "' can only be applied on typed resource parts.",
-          UriParserSemanticException.MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS, odi));
-    }
-
-    if (ctx.vNS == null) { // without namespace
-
-      // first check for lambda variable because a newly add property should not shadow a long used lambda variable
-      UriContext.LambdaVariable lVar = getLambdaVar(odi);
-      if (lVar != null) {
-        UriResourceLambdaVarImpl lambdaResource = new UriResourceLambdaVarImpl(lVar.name, lVar.type);
-        context.contextUriInfo.addResourcePart(lambdaResource);
-        return null;
-      }
-
-      if (!(sourceType instanceof EdmStructuredType)) {
-        throw wrap(new UriParserSemanticException(
-            "Cannot parse '" + odi + "'; previous path segment is not a structural type.",
-            UriParserSemanticException.MessageKeys.RESOURCE_PART_MUST_BE_PRECEDED_BY_STRUCTURAL_TYPE, odi));
-      }
-
-      if ((ctx.depth() <= 2 // path evaluation for the resource path
-          || lastResourcePart instanceof UriResourceTypedImpl
-          || lastResourcePart instanceof UriResourceNavigationPropertyImpl)
-          && sourceIsCollection) {
-        throw wrap(new UriParserSemanticException("Property '" + odi + "' is not allowed after collection.",
-            UriParserSemanticException.MessageKeys.PROPERTY_AFTER_COLLECTION, odi));
-      }
-
-      EdmStructuredType structType = (EdmStructuredType) sourceType;
-
-      EdmElement property = structType.getProperty(odi);
-      if (property == null) {
-        throw wrap(new UriParserSemanticException("Property '" + odi + "' not found in type '"
-            + structType.getFullQualifiedName().getFullQualifiedNameAsString() + "'",
-            ctx.depth() > 2 ? // path evaluation inside an expression or for the resource path?
-                UriParserSemanticException.MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE
-                : UriParserSemanticException.MessageKeys.PROPERTY_NOT_IN_TYPE,
-            structType.getFullQualifiedName().getFullQualifiedNameAsString(), odi));
-      }
-
-      if (property instanceof EdmProperty) {
-        if (((EdmProperty) property).isPrimitive()
-            || property.getType().getKind() == EdmTypeKind.ENUM
-            || property.getType().getKind() == EdmTypeKind.DEFINITION) {
-          // create simple property
-          UriResourcePrimitivePropertyImpl simpleResource =
-              new UriResourcePrimitivePropertyImpl((EdmProperty) property);
-          context.contextUriInfo.addResourcePart(simpleResource);
-          return null;
-        } else {
-          // create complex property
-          UriResourceComplexPropertyImpl complexResource = new UriResourceComplexPropertyImpl((EdmProperty) property);
-          context.contextUriInfo.addResourcePart(complexResource);
-          return null;
-        }
-      } else if (property instanceof EdmNavigationProperty) {
-        // create navigation property
-        if (context.contextVisitExpandResourcePath && ctx.vlNVO.size() > 0) {
-          throw wrap(new UriParserSemanticException(
-              "Navigation properties in expand system query options must not be followed by a key.",
-              UriParserSemanticException.MessageKeys.KEY_NOT_ALLOWED));
-        }
-
-        UriResourceNavigationPropertyImpl navigationResource =
-            new UriResourceNavigationPropertyImpl((EdmNavigationProperty) property);
-        context.contextUriInfo.addResourcePart(navigationResource);
-        return null;
-      } else {
-        throw wrap(new UriParserSemanticException("Unkown type for property '" + property + "'",
-            UriParserSemanticException.MessageKeys.UNKNOWN_PROPERTY_TYPE, property.getName()));
-      }
-
-    } else { // with namespace
-
-      FullQualifiedName fullFilterName = getFullNameFromContext(ctx.vNS, odi);
-
-      // EdmType lastType = getLastType(lastTyped);
-      if (sourceType instanceof EdmEntityType) {
-
-        EdmEntityType filterEntityType = edm.getEntityType(fullFilterName);
-        if (filterEntityType != null) {
-          // is entity type cast
-          if (!(filterEntityType.compatibleTo(sourceType))) {
-            throw wrap(new UriParserSemanticException(
-                "Entity typefilter not compatible to previous path segment: " + fullFilterName.toString(),
-                UriParserSemanticException.MessageKeys.INCOMPATIBLE_TYPE_FILTER, fullFilterName.toString()));
-          }
-
-          if (lastResourcePart == null) {
-            // this may be the case if a member expression within a filter starts with a typeCast
-            UriResourceStartingTypeFilterImpl uriResource = new UriResourceStartingTypeFilterImpl(
-                filterEntityType,
-                sourceIsCollection);
-            if (sourceIsCollection) {
-              uriResource.setCollectionTypeFilter(filterEntityType);
-            } else {
-              uriResource.setEntryTypeFilter(filterEntityType);
-            }
-            context.contextUriInfo.addResourcePart(uriResource);
-            return null;
-          } else {
-
-            // check if last segment may contain key properties
-            if (lastResourcePart instanceof UriResourceWithKeysImpl) {
-              UriResourceWithKeysImpl lastPartWithKeys = (UriResourceWithKeysImpl) lastResourcePart;
-
-              if (!lastPartWithKeys.isCollection()) {
-                if (lastPartWithKeys.getTypeFilterOnEntry() != null) {
-                  throw wrap(new UriParserSemanticException("Entry typefilters are not chainable, used '"
-                      + getName(filterEntityType) + "' behind '"
-                      + getName(lastPartWithKeys.getTypeFilterOnEntry()) + "'",
-                      UriParserSemanticException.MessageKeys.TYPE_FILTER_NOT_CHAINABLE,
-                      getName(lastPartWithKeys.getTypeFilterOnEntry()), getName(filterEntityType)));
-                }
-                lastPartWithKeys.setEntryTypeFilter(filterEntityType);
-                return null;
-              } else {
-                if (lastPartWithKeys.getTypeFilterOnCollection() != null) {
-                  throw wrap(new UriParserSemanticException("Collection typefilters are not chainable, used '"
-                      + getName(filterEntityType) + "' behind '"
-                      + getName(lastPartWithKeys.getTypeFilterOnCollection()) + "'",
-                      UriParserSemanticException.MessageKeys.TYPE_FILTER_NOT_CHAINABLE,
-                      getName(lastPartWithKeys.getTypeFilterOnCollection()), getName(filterEntityType)));
-                }
-                lastPartWithKeys.setCollectionTypeFilter(filterEntityType);
-                return null;
-              }
-            } else if (lastResourcePart instanceof UriResourceTypedImpl) {
-              UriResourceTypedImpl lastPartTyped = (UriResourceTypedImpl) lastResourcePart;
-              if (lastPartTyped.getTypeFilter() != null) {
-                throw wrap(new UriParserSemanticException("Typefilters are not chainable, used '"
-                    + getName(filterEntityType) + "' behind '"
-                    + getName(lastPartTyped.getTypeFilter()) + "'",
-                    UriParserSemanticException.MessageKeys.TYPE_FILTER_NOT_CHAINABLE,
-                    getName(lastPartTyped.getTypeFilter()), getName(filterEntityType)));
-              }
-
-              lastPartTyped.setTypeFilter(filterEntityType);
-              return null;
-            } else {
-              throw wrap(new UriParserSemanticException("Path segment before '" + getName(filterEntityType)
-                  + "' not typed",
-                  UriParserSemanticException.MessageKeys.PREVIOUS_PART_NOT_TYPED, getName(filterEntityType)));
-            }
-          }
-        }
-
-      } else if (sourceType instanceof EdmComplexType) {
-
-        EdmComplexType filterComplexType = edm.getComplexType(fullFilterName);
-
-        if (filterComplexType != null) {
-
-          // is complex type cast
-          if (!(filterComplexType.compatibleTo(sourceType))) {
-            throw wrap(new UriParserSemanticException(
-                "Complex typefilter '" + getName(sourceType) + "'not compatible type of previous path segment '"
-                    + getName(filterComplexType) + "'",
-                UriParserSemanticException.MessageKeys.INCOMPATIBLE_TYPE_FILTER, getName(sourceType)));
-          }
-
-          // is simple complex type cast
-          if (lastResourcePart == null) {
-            // this may be the case if a member expression within a filter starts with a typeCast
-            UriResourceStartingTypeFilterImpl uriResource =
-                new UriResourceStartingTypeFilterImpl(filterComplexType, sourceIsCollection);
-
-            if (sourceIsCollection) {
-              uriResource.setCollectionTypeFilter(filterComplexType);
-            } else {
-              uriResource.setEntryTypeFilter(filterComplexType);
-            }
-            context.contextUriInfo.addResourcePart(uriResource);
-            return null;
-          } else {
-            if (lastResourcePart instanceof UriResourceWithKeysImpl) {
-              // e.g. in case of function returning complex data or a list of complex data
-              UriResourceWithKeysImpl lastPartWithKeys = (UriResourceWithKeysImpl) lastResourcePart;
-
-              if (!lastPartWithKeys.isCollection()) {
-                if (lastPartWithKeys.getTypeFilterOnEntry() != null) {
-                  throw wrap(new UriParserSemanticException("Entry typefilters are not chainable, used '"
-                      + getName(filterComplexType) + "' behind '"
-                      + getName(lastPartWithKeys.getTypeFilterOnEntry()) + "'",
-                      UriParserSemanticException.MessageKeys.TYPE_FILTER_NOT_CHAINABLE,
-                      getName(lastPartWithKeys.getTypeFilterOnEntry()), getName(filterComplexType)));
-                }
-                lastPartWithKeys.setEntryTypeFilter(filterComplexType);
-                return null;
-              } else {
-                if (lastPartWithKeys.getTypeFilterOnCollection() != null) {
-                  throw wrap(new UriParserSemanticException("Collection typefilters are not chainable, used '"
-                      + getName(filterComplexType) + "' behind '"
-                      + getName(lastPartWithKeys.getTypeFilterOnCollection()) + "'",
-                      UriParserSemanticException.MessageKeys.TYPE_FILTER_NOT_CHAINABLE,
-                      getName(lastPartWithKeys.getTypeFilterOnCollection()), getName(filterComplexType)));
-                }
-                lastPartWithKeys.setCollectionTypeFilter(filterComplexType);
-                return null;
-              }
-
-            } else if (lastResourcePart instanceof UriResourceTypedImpl) {
-              UriResourceTypedImpl lastPartTyped = (UriResourceTypedImpl) lastResourcePart;
-              if (lastPartTyped.getTypeFilter() != null) {
-                throw wrap(new UriParserSemanticException("Typefilters are not chainable, used '"
-                    + getName(filterComplexType) + "' behind '"
-                    + getName(lastPartTyped.getTypeFilter()) + "'",
-                    UriParserSemanticException.MessageKeys.TYPE_FILTER_NOT_CHAINABLE,
-                    getName(lastPartTyped.getTypeFilter()), getName(filterComplexType)));
-              }
-
-              lastPartTyped.setTypeFilter(filterComplexType);
-              return null;
-            } else {
-              throw wrap(new UriParserSemanticException("Path segment before '" + getName(filterComplexType)
-                  + "' not typed",
-                  UriParserSemanticException.MessageKeys.PREVIOUS_PART_NOT_TYPED, getName(filterComplexType)));
-            }
-          }
-        }
-      }
-
-      FullQualifiedName fullBindingTypeName = sourceType.getFullQualifiedName();
-
-      // check for action
-      EdmAction action = edm.getBoundAction(fullFilterName, fullBindingTypeName, sourceIsCollection);
-      if (action != null) {
-        UriResourceActionImpl pathInfoAction = new UriResourceActionImpl(action);
-        context.contextUriInfo.addResourcePart(pathInfoAction);
-        return null;
-      }
-
-      // do a check for bound functions (which requires a parameter list)
-      if (ctx.vlNVO.size() == 0) {
-        throw wrap(new UriParserSemanticException("Unknown type for type cast " + fullFilterName.toString()
-            + " not found", UriParserSemanticException.MessageKeys.UNKNOWN_TYPE, fullFilterName.toString()));
-      }
-
-      context.contextReadingFunctionParameters = true;
-      @SuppressWarnings("unchecked")
-      List<UriParameter> parameters = (List<UriParameter>) ctx.vlNVO.get(0).accept(this);
-      context.contextReadingFunctionParameters = false;
-
-      // get names of function parameters
-      List<String> names = new ArrayList<String>();
-      for (UriParameter item : parameters) {
-        names.add(item.getName());
-      }
-
-      EdmFunction function = edm.getBoundFunction(fullFilterName, fullBindingTypeName, sourceIsCollection, names);
-
-      if (function != null) {
-        UriResourceFunctionImpl pathInfoFunction = new UriResourceFunctionImpl(null, function, parameters);
-        context.contextUriInfo.addResourcePart(pathInfoFunction);
-
-        // mark parameters as consumed
-        ctx.vlNVO.remove(0);
-        return null;
-      }
-
-      // check for unbound function in the $filter case ( where the previous resource segment is a $it)
-      function = edm.getUnboundFunction(fullFilterName, names);
-
-      if (function != null) {
-        UriResourceFunctionImpl pathInfoFunction = new UriResourceFunctionImpl(null, function, parameters);
-        context.contextUriInfo.addResourcePart(pathInfoFunction);
-
-        // mark parameters as consumed
-        ctx.vlNVO.remove(0);
-        return null;
-      }
-
-      throw wrap(new UriParserSemanticException("Unknown resource path segment:" + fullFilterName.toString(),
-          UriParserSemanticException.MessageKeys.UNKNOWN_PART, fullFilterName.toString()));
-    }
-  }
-
-  /**
-   * Ensures that the namespace of the first resource parts is null
-   * @param vNS namespace or null
-   */
-  private void ensureNamespaceIsNull(final NamespaceContext vNS) {
-    if (vNS != null && context.contextUriInfo.getLastResourcePart() == null) {
-      // First resource part and namespace is not null!
-      throw wrap(new UriParserSemanticException("Namespace is not allowed for EntitySets, Singeltons, "
-          + " Action Imports and Function Imports. Found " + vNS.getText(),
-          UriParserSemanticException.MessageKeys.NAMESPACE_NOT_ALLOWED_AT_FIRST_ELEMENT, vNS.getText()));
-    }
-  }
-
-  private String getName(final EdmType type) {
-    return type.getFullQualifiedName().getFullQualifiedNameAsString();
-  }
-
-  @Override
-  public Object visitAllEOF(final AllEOFContext ctx) {
-    context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.all);
-    return null;
-  }
-
-  @Override
-  public Object visitAllExpr(final AllExprContext ctx) {
-    UriResource obj = context.contextUriInfo.getLastResourcePart();
-    if (!(obj instanceof UriResourcePartTyped)) {
-      throw wrap(new UriParserSemanticException("all only allowed on typed path segments",
-          UriParserSemanticException.MessageKeys.ONLY_FOR_TYPED_PARTS, "all"));
-    } else if (obj instanceof UriResourceNavigation) {
-      if (!((UriResourceNavigation) obj).getKeyPredicates().isEmpty()) {
-        throw wrap(new UriParserSemanticException(
-            "Any lamdba expression must not be following navigation properties with key predicates.",
-            UriParserSemanticException.MessageKeys.KEY_NOT_ALLOWED));
-      }
-    }
-
-    UriContext.LambdaVariable var = new UriContext.LambdaVariable();
-    var.name = ctx.vLV.getText();
-    var.type = ParserHelper.getTypeInformation((UriResourcePartTyped) obj);
-
-    context.allowedLambdaVariables.push(var);
-    Expression expression = (Expression) ctx.vLE.accept(this);
-    context.allowedLambdaVariables.pop();
-    return new UriResourceLambdaAllImpl(var.name, expression);
-  }
-
-  @Override
-  public Expression visitAltAdd(final AltAddContext ctx) {
-    int tokenIndex = ctx.vO.getType();
-    return new BinaryImpl(
-        (Expression) ctx.vE1.accept(this),
-        tokenIndex == UriLexer.ADD ? BinaryOperatorKind.ADD : BinaryOperatorKind.SUB,
-        (Expression) ctx.vE2.accept(this),
-        null);
-  }
-
-  @Override
-  public Object visitAltAll(final AltAllContext ctx) {
-
-    UriInfoImpl uriInfoImplpath = new UriInfoImpl().setKind(UriInfoKind.resource);
-
-    uriInfoImplpath.addResourcePart((UriResourceImpl) super.visitAltAll(ctx));
-
-    EdmType startType = removeUriResourceStartingTypeFilterImpl(uriInfoImplpath);
-
-    return new MemberImpl(uriInfoImplpath, startType);
-  }
-
-  private EdmType removeUriResourceStartingTypeFilterImpl(final UriInfoImpl uriInfoImplpath) {
-
-    List<UriResource> segments = uriInfoImplpath.getUriResourceParts();
-    if (segments.size() == 0) {
-      return null;
-    }
-
-    UriResource segment = segments.get(0);
-    if (segment instanceof UriResourceStartingTypeFilterImpl) {
-      UriResourceStartingTypeFilterImpl startingTypeFilter = (UriResourceStartingTypeFilterImpl) segment;
-
-      EdmType type = null;
-      if (startingTypeFilter.getTypeFilterOnEntry() != null) {
-        type = startingTypeFilter.getTypeFilterOnEntry();
-      } else if (startingTypeFilter.getTypeFilterOnCollection() != null) {
-        type = startingTypeFilter.getTypeFilterOnCollection();
-      } else {
-        type = startingTypeFilter.getType();
-      }
-
-      uriInfoImplpath.removeResourcePart(0);
-      return type;
-    }
-
-    return null;
-  }
-
-  @Override
-  public Expression visitAltAnd(final AltAndContext ctx) {
-    return new BinaryImpl(
-        (Expression) ctx.vE1.accept(this),
-        BinaryOperatorKind.AND,
-        (Expression) ctx.vE2.accept(this),
-        EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Boolean));
-  }
-
-  @Override
-  public Object visitAltAny(final AltAnyContext ctx) {
-    UriInfoImpl uriInfoImplpath = new UriInfoImpl().setKind(UriInfoKind.resource);
-
-    uriInfoImplpath.addResourcePart((UriResourceImpl) super.visitAltAny(ctx));
-
-    EdmType startType = removeUriResourceStartingTypeFilterImpl(uriInfoImplpath);
-
-    return new MemberImpl(uriInfoImplpath, startType);
-  }
-
-  @Override
-  public Expression visitAltComparism(final AltComparismContext ctx) {
-    int tokenIndex = ctx.vO.getType();
-    BinaryOperatorKind kind = null;
-    if (tokenIndex == UriLexer.GT) {
-      kind = BinaryOperatorKind.GT;
-    } else if (tokenIndex == UriLexer.GE) {
-      kind = BinaryOperatorKind.GE;
-    } else if (tokenIndex == UriLexer.LT) {
-      kind = BinaryOperatorKind.LT;
-    } else if (tokenIndex == UriLexer.LE) {
-      kind = BinaryOperatorKind.LE;
-    }
-    return new BinaryImpl(
-        (Expression) ctx.vE1.accept(this),
-        kind,
-        (Expression) ctx.vE2.accept(this),
-        EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Boolean));
-  }
-
-  @Override
-  public Object visitEntityEOF(final EntityEOFContext ctx) {
-    String odi = ctx.vODI.getText();
-    FullQualifiedName fullName = getFullNameFromContext(ctx.vNS, odi);
-
-    EdmEntityType type = edm.getEntityType(fullName);
-    if (type == null) {
-      throw wrap(new UriParserSemanticException("Expected EntityTypeName",
-          UriParserSemanticException.MessageKeys.UNKNOWN_ENTITY_TYPE, fullName.toString()));
-    }
-    context.contextUriInfo.setEntityTypeCast(type);
-
-    // contextUriInfo = uriInfo;
-    context.contextTypes.push(context.contextUriInfo.getEntityTypeCast());
-    context.isCollection = true;  // TODO: check!
-
-    return null;
-  }
-
-  @Override
-  public Expression visitAltEquality(final AltEqualityContext ctx) {
-    int tokenIndex = ctx.vO.getType();
-    return new BinaryImpl(
-        (Expression) ctx.vE1.accept(this),
-        tokenIndex == UriLexer.EQ_ALPHA ? BinaryOperatorKind.EQ : BinaryOperatorKind.NE,
-        (Expression) ctx.vE2.accept(this),
-        EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Boolean));
-  }
-
-  @Override
-  public Object visitAltHas(final AltHasContext ctx) {
-    return new BinaryImpl(
-        (Expression) ctx.vE1.accept(this),
-        BinaryOperatorKind.HAS,
-        (Expression) ctx.vE2.accept(this),
-        EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Boolean));
-  }
-
-  @Override
-  public Object visitMetadataEOF(final MetadataEOFContext ctx) {
-
-    context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.metadata);
-    return null;
-  }
-
-  @Override
-  public Expression visitAltMult(final AltMultContext ctx) {
-    int tokenIndex = ctx.vO.getType();
-    BinaryOperatorKind kind;
-    if (tokenIndex == UriLexer.MUL) {
-      kind = BinaryOperatorKind.MUL;
-    } else if (tokenIndex == UriLexer.DIV) {
-      kind = BinaryOperatorKind.DIV;
-    } else {
-      kind = BinaryOperatorKind.MOD;
-    }
-    return new BinaryImpl(
-        (Expression) ctx.vE1.accept(this),
-        kind,
-        (Expression) ctx.vE2.accept(this),
-        null);
-  }
-
-  @Override
-  public Expression visitAltOr(final AltOrContext ctx) {
-    return new BinaryImpl(
-        (Expression) ctx.vE1.accept(this),
-        BinaryOperatorKind.OR,
-        (Expression) ctx.vE2.accept(this),
-        EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Boolean));
-  }
-
-  @Override
-  public Object visitAnyExpr(final AnyExprContext ctx) {
-    if (ctx.vLV != null) {
-      UriResourceImpl lastResourcePart = (UriResourceImpl) context.contextUriInfo.getLastResourcePart();
-      if (!(lastResourcePart instanceof UriResourcePartTyped)) {
-        throw wrap(new UriParserSemanticException("any only allowed on typed path segments",
-            UriParserSemanticException.MessageKeys.ONLY_FOR_TYPED_PARTS, "any"));
-      } else if (lastResourcePart instanceof UriResourceNavigation) {
-        if (!((UriResourceNavigation) lastResourcePart).getKeyPredicates().isEmpty()) {
-          throw wrap(new UriParserSemanticException(
-              "Any lamdba expression must not be following navigation properties with key predicates",
-              UriParserSemanticException.MessageKeys.KEY_NOT_ALLOWED));
-        }
-      }
-
-      UriContext.LambdaVariable var = new UriContext.LambdaVariable();
-      var.name = ctx.vLV.getText();
-      var.type = ParserHelper.getTypeInformation((UriResourcePartTyped) lastResourcePart);
-
-      context.allowedLambdaVariables.push(var);
-      Expression expression = (Expression) ctx.vLE.accept(this);
-      context.allowedLambdaVariables.pop();
-      return new UriResourceLambdaAnyImpl(var.name, expression);
-    }
-    return null;
-  }
-
-  @Override
-  public Object visitBooleanNonCaseLiteral(final BooleanNonCaseLiteralContext ctx) {
-    final String text = ctx.getText().toLowerCase();
-    return new LiteralImpl(text.equals("false") ? "false" : "true",
-        EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Boolean));
-  }
-
-  @Override
-  public Expression visitCastExpr(final CastExprContext ctx) {
-    List<Expression> parameters = new ArrayList<Expression>();
-    if (ctx.vE1 != null) {
-      // is optional parameter
-      parameters.add((Expression) ctx.vE1.accept(this));
-    }
-
-    String namespace = ctx.vNS.getText();
-    namespace = namespace.substring(0, namespace.length() - 1);
-
-    FullQualifiedName fullName = new FullQualifiedName(namespace, ctx.vODI.getText());
-    EdmType type = getType(fullName);
-    parameters.add(new TypeLiteralImpl(type));
-    return new MethodImpl(MethodKind.CAST, parameters);
-  }
-
-  private EdmType getType(final FullQualifiedName fullName) {
-    EdmType type = null;
-
-    type = edm.getEntityType(fullName);
-    if (type != null) {
-      return type;
-    }
-
-    type = edm.getComplexType(fullName);
-    if (type != null) {
-      return type;
-    }
-
-    type = edm.getTypeDefinition(fullName);
-    if (type != null) {
-      return type;
-    }
-
-    type = edm.getEnumType(fullName);
-    if (type != null) {
-      return type;
-    }
-
-    if (fullName.getNamespace().equals(EdmPrimitiveType.EDM_NAMESPACE)) {
-      final EdmPrimitiveTypeKind typeKind = EdmPrimitiveTypeKind.valueOf(fullName.getName());
-      type = EdmPrimitiveTypeFactory.getInstance(typeKind);
-      if (type != null) {
-        return type;
-      }
-    }
-
-    return null;
-
-  }
-
-  @Override
-  public Expression visitCeilingMethodCallExpr(final CeilingMethodCallExprContext ctx) {
-    return new MethodImpl(MethodKind.CEILING, Collections.singletonList((Expression) ctx.vE1.accept(this)));
-  }
-
-  @Override
-  public Expression visitConcatMethodCallExpr(final ConcatMethodCallExprContext ctx) {
-    return new MethodImpl(MethodKind.CONCAT, Arrays.asList(
-        (Expression) ctx.vE1.accept(this),
-        (Expression) ctx.vE2.accept(this)));
-  }
-
-  @Override
-  public Object visitConstSegment(final ConstSegmentContext ctx) {
-    UriInfoImpl uriInfoResource = context.contextUriInfo;
-    UriResource pathInfo = uriInfoResource.getLastResourcePart();
-
-    if (ctx.vV != null) {
-      if (pathInfo instanceof UriResourcePartTyped) {
-        if (!((UriResourcePartTyped) pathInfo).isCollection()) {
-          context.contextUriInfo.addResourcePart(new UriResourceValueImpl());
-        } else {
-          throw wrap(new UriParserSemanticException("$value only allowed on typed path segments",
-              UriParserSemanticException.MessageKeys.ONLY_FOR_TYPED_PARTS, "$value"));
-        }
-        return null;
-      } else {
-        throw wrap(new UriParserSemanticException("$value only allowed on typed path segments",
-            UriParserSemanticException.MessageKeys.ONLY_FOR_TYPED_PARTS, "$value"));
-      }
-
-    } else if (ctx.vC != null) {
-      if (pathInfo instanceof UriResourcePartTyped) {
-        if (((UriResourcePartTyped) pathInfo).isCollection()) {
-          context.contextUriInfo.addResourcePart(new UriResourceCountImpl());
-        } else {
-          throw wrap(new UriParserSemanticException("$count only allowed on collection properties",
-              UriParserSemanticException.MessageKeys.ONLY_FOR_COLLECTIONS, "$count"));
-        }
-      } else {
-        throw wrap(new UriParserSemanticException("$count only allowed on typed properties",
-            UriParserSemanticException.MessageKeys.ONLY_FOR_TYPED_PARTS, "$count"));
-      }
-    } else if (ctx.vR != null) {
-      if (pathInfo instanceof UriResourcePartTyped) {
-        EdmType type = ((UriResourcePartTyped) pathInfo).getType();
-        if (type instanceof EdmEntityType) {
-          context.contextUriInfo.addResourcePart(new UriResourceRefImpl());
-        } else {
-          throw wrap(new UriParserSemanticException("$ref only allowed on entity types",
-              UriParserSemanticException.MessageKeys.ONLY_FOR_ENTITY_TYPES, "$ref"));
-        }
-      } else {
-        throw wrap(new UriParserSemanticException("$ref only allowed on typed properties",
-            UriParserSemanticException.MessageKeys.ONLY_FOR_TYPED_PROPERTIES, "$ref"));
-      }
-
-    } else if (ctx.vAll != null) {
-      context.contextUriInfo.addResourcePart((UriResourceLambdaAllImpl) ctx.vAll.accept(this));
-    } else if (ctx.vAny != null) {
-      context.contextUriInfo.addResourcePart((UriResourceLambdaAnyImpl) ctx.vAny.accept(this));
-    }
-    return null;
-  }
-
-  @Override
-  public Expression visitContainsMethodCallExpr(final ContainsMethodCallExprContext ctx) {
-    return new MethodImpl(MethodKind.CONTAINS, Arrays.asList(
-        (Expression) ctx.vE1.accept(this),
-        (Expression) ctx.vE2.accept(this)));
-  }
-
-  @Override
-  public Object visitDateMethodCallExpr(final DateMethodCallExprContext ctx) {
-    return new MethodImpl(MethodKind.DATE, Collections.singletonList((Expression) ctx.vE1.accept(this)));
-  }
-
-  @Override
-  public Expression visitDayMethodCallExpr(final DayMethodCallExprContext ctx) {
-    return new MethodImpl(MethodKind.DAY, Collections.singletonList((Expression) ctx.vE1.accept(this)));
-  }
-
-  @Override
-  public Expression visitGeoDistanceMethodCallExpr(final GeoDistanceMethodCallExprContext ctx) {
-    return new MethodImpl(MethodKind.GEODISTANCE, Arrays.asList(
-        (Expression) ctx.vE1.accept(this),
-        (Expression) ctx.vE2.accept(this)));
-  }
-
-  @Override
-  public Object visitEndsWithMethodCallExpr(final EndsWithMethodCallExprContext ctx) {
-    return new MethodImpl(MethodKind.ENDSWITH, Arrays.asList(
-        (Expression) ctx.vE1.accept(this),
-        (Expression) ctx.vE2.accept(this)));
-  }
-
-  @Override
-  public Object visitEnumLiteral(final EnumLiteralContext ctx) {
-    // get type
-    final String odi = ctx.vODI.getText();
-
-    final FullQualifiedName fullName = getFullNameFromContext(ctx.vNS, odi);
-    final EdmEnumType edmEnumType = edm.getEnumType(fullName);
-    if (edmEnumType == null) {
-      throw wrap(new UriParserSemanticException(
-          "Enum type '" + fullName.getFullQualifiedNameAsString() + "' not found!",
-          UriParserSemanticException.MessageKeys.UNKNOWN_TYPE, fullName.getFullQualifiedNameAsString()));
-    }
-
-    String valueString = ctx.vValues.getText();
-    valueString = valueString.substring(1, valueString.length() - 1);
-    String[] values = valueString.split(",");
-    return new EnumerationImpl(edmEnumType, Arrays.asList(values));
-  }
-
-  @Override
-  public Object visitExpandItems(final ExpandItemsContext ctx) {
-    ExpandOptionImpl expand = new ExpandOptionImpl();
-    expand.setText(ctx.getText());
-    for (ExpandItemContext eI : ctx.vlEI) {
-      expand.addExpandItem((ExpandItemImpl) eI.accept(this));
-    }
-
-    return expand;
-  }
-
-  @Override
-  public Object visitExpandItem(final ExpandItemContext ctx) {
-
-    ExpandItemImpl expandItem = null;
-    if (ctx.vS != null) {
-      expandItem = new ExpandItemImpl().setIsStar(true);
-      if (ctx.vR != null) {
-        expandItem.setIsRef(true);
-      } else if (ctx.vM != null) {
-        LevelsOptionImpl levels = new LevelsOptionImpl().setMax();
-        levels.setText(ctx.vM.getText());
-        try {
-          expandItem.setSystemQueryOption(levels);
-        } catch (ODataRuntimeException e) {
-          // Thrown if duplicated system query options are detected
-          throw wrap(new UriParserSyntaxException("Double system query option!", e,
-              UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION, e.getMessage()));
-        }
-      } else if (ctx.vL != null) {
-        LevelsOptionImpl levels = new LevelsOptionImpl();
-        String text = ctx.vL.getText();
-        levels.setText(text);
-        levels.setValue(Integer.parseInt(text));
-        try {
-          expandItem.setSystemQueryOption(levels);
-        } catch (ODataRuntimeException e) {
-          // Thrown if duplicated system query options are detected
-          throw wrap(new UriParserSyntaxException("Double system query option!", e,
-              UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION, e.getMessage()));
-        }
-      }
-
-    } else if (ctx.vEP != null) {
-      expandItem = (ExpandItemImpl) ctx.vEP.accept(this);
-
-      if (ctx.vEPE != null) {
-        ExpandItemImpl contextExpandItemPathBU = context.contextExpandItemPath;
-        context.contextExpandItemPath = expandItem;
-
-        @SuppressWarnings("unchecked")
-        List<SystemQueryOptionImpl> list = (List<SystemQueryOptionImpl>) ctx.vEPE.accept(this);
-        try {
-          for (SystemQueryOptionImpl option : list) {
-            expandItem.setSystemQueryOption(option);
-          }
-        } catch (ODataRuntimeException e) {
-          // Thrown if duplicated system query options are detected
-          throw wrap(new UriParserSyntaxException("Double system query option!", e,
-              UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION, e.getMessage()));
-        }
-        context.contextExpandItemPath = contextExpandItemPathBU;
-      }
-    }
-
-    return expandItem;
-
-  }
-
-  @Override
-  public Object visitExpandPath(final ExpandPathContext ctx) {
-    ExpandItemImpl expandItem = new ExpandItemImpl();
-
-    // save context
-    ExpandItemImpl contextExpandItemPathBU = context.contextExpandItemPath;
-    UriInfoImpl uriInfoResourceBU = context.contextUriInfo;
-
-    // set tmp context
-    context.contextExpandItemPath = expandItem;
-    context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.resource);
-
-    context.contextVisitExpandResourcePath = true;
-    super.visitExpandPath(ctx);
-    context.contextVisitExpandResourcePath = false;
-
-    EdmType startType = removeUriResourceStartingTypeFilterImpl(context.contextUriInfo);
-    expandItem.setResourcePath(context.contextUriInfo);
-    if (startType != null) {
-      expandItem.setTypeFilter(startType);
-    }
-
-    // reset context
-    context.contextUriInfo = uriInfoResourceBU;
-    context.contextExpandItemPath = contextExpandItemPathBU;
-
-    // test
-    validate(uriInfoResourceBU.asUriInfoResource(), expandItem);
-    //
-
-    return expandItem;
-  }
-
-  private void validate(UriInfoResource uriInfoResource, ExpandItemImpl expandItem) {
-    if (uriInfoResource != null) {
-      EdmEntityType type = getEntityType(uriInfoResource);
-      EdmEntityType name = getEntityType(expandItem.getResourcePath());
-
-      if (name != null && type != null) {
-        EdmElement property = type.getProperty(name.getName());
-        if (!(property instanceof EdmNavigationProperty)) {
-          throw wrap(new UriParserSemanticException(
-              "NavigationProperty '" + name.getName() + "' not found in type '"
-                  + type.getFullQualifiedName().getFullQualifiedNameAsString() + "'",
-              UriParserSemanticException.MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE,
-              name.getFullQualifiedName().getFullQualifiedNameAsString(),
-              type.getFullQualifiedName().getFullQualifiedNameAsString()));
-        }
-      }
-    }
-  }
-
-  private EdmEntityType getEntityType(UriInfoResource test) {
-    List<UriResource> parts = test.getUriResourceParts();
-    if (!parts.isEmpty()) {
-      UriResource lastPart = parts.get(parts.size() - 1);
-      if (lastPart instanceof UriResourceEntitySet) {
-        UriResourceEntitySet entitySet = (UriResourceEntitySet) lastPart;
-        return entitySet.getEntityType();
-      }
-    }
-    return null;
-  }
-
-  @Override
-  public Object visitExpandPathExtension(final ExpandPathExtensionContext ctx) {
-    List<SystemQueryOptionImpl> list = new ArrayList<SystemQueryOptionImpl>();
-
-    EdmType targetType = null;
-    boolean isColl = false;
-    if (context.contextExpandItemPath == null) {
-      // use the type of the last resource path segement
-      UriResourceTypedImpl lastSegment = (UriResourceTypedImpl) context.contextUriInfo.getLastResourcePart();
-      targetType = ParserHelper.getTypeInformation(lastSegment);
-      isColl = lastSegment.isCollection();
-    } else {
-      if (context.contextExpandItemPath.getResourcePath() == null) {
-        // use the type of the last resource path segement
-        UriResourceTypedImpl lastSegment = (UriResourceTypedImpl) context.contextUriInfo.getLastResourcePart();
-        targetType = ParserHelper.getTypeInformation(lastSegment);
-        isColl = lastSegment.isCollection();
-      } else {
-        // use the type of the last ''expand'' path segement
-        UriInfoImpl info = (UriInfoImpl) context.contextExpandItemPath.getResourcePath();
-        targetType = ParserHelper.getTypeInformation((UriResourcePartTyped) info.getLastResourcePart());
-        isColl = ((UriResourcePartTyped) info.getLastResourcePart()).isCollection();
-      }
-    }
-
-    context.contextTypes.push(targetType);
-    context.isCollection = isColl;
-
-    if (ctx.vC != null) {
-      UriInfoImpl resourcePath = (UriInfoImpl) context.contextExpandItemPath.getResourcePath();
-      resourcePath.addResourcePart(new UriResourceCountImpl());
-
-      for (ExpandCountOptionContext s : ctx.vlEOC) {
-        list.add((SystemQueryOptionImpl) s.accept(this));
-      }
-    } else if (ctx.vR != null) {
-      UriInfoImpl resourcePath = (UriInfoImpl) context.contextExpandItemPath.getResourcePath();
-      resourcePath.addResourcePart(new UriResourceRefImpl());
-
-      for (ExpandRefOptionContext s : ctx.vlEOR) {
-        list.add((SystemQueryOptionImpl) s.accept(this));
-      }
-    } else {
-      for (ExpandOptionContext s : ctx.vlEO) {
-        list.add((SystemQueryOptionImpl) s.accept(this));
-      }
-    }
-
-    context.contextTypes.pop();
-    return list;
-
-  }
-
-  @Override
-  public Object visitFilter(final FilterContext ctx) {
-    context.contextReadingQueryPart = true;
-    final FilterOptionImpl result = new FilterOptionImpl().setExpression((Expression) ctx.children.get(2)
-                                                          .accept(this));
-    context.contextReadingQueryPart = false;
-
-    return result;
-  }
-
-  @Override
-  public Object visitFilterExpressionEOF(final FilterExpressionEOFContext ctx) {
-    context.contextReadingQueryPart = true;
-    final FilterOptionImpl result = new FilterOptionImpl().setExpression((Expression) ctx.children.get(0)
-                                                          .accept(this));
-    context.contextReadingQueryPart = false;
-
-    return result;
-  }
-
-  @Override
-  public Expression visitFloorMethodCallExpr(final FloorMethodCallExprContext ctx) {
-    return new MethodImpl(MethodKind.FLOOR, Collections.singletonList((Expression) ctx.vE1.accept(this)));
-  }
-
-  @Override
-  public Expression visitFractionalsecondsMethodCallExpr(final FractionalsecondsMethodCallExprContext ctx) {
-    return new MethodImpl(MethodKind.FRACTIONALSECONDS, Collections.singletonList((Expression) ctx.vE1.accept(this)));
-  }
-
-  @Override
-  public Expression visitGeoLengthMethodCallExpr(final GeoLengthMethodCallExprContext ctx) {
-    return new MethodImpl(MethodKind.GEOLENGTH, Collections.singletonList((Expression) ctx.vE1.accept(this)));
-  }
-
-  @Override
-  public Expression visitHourMethodCallExpr(final HourMethodCallExprContext ctx) {
-    return new MethodImpl(MethodKind.HOUR, Collections.singletonList((Expression) ctx.vE1.accept(this)));
-  }
-
-  @Override
-  public Expression visitIndexOfMethodCallExpr(final IndexOfMethodCallExprContext ctx) {
-    return new MethodImpl(MethodKind.INDEXOF, Arrays.asList(
-        (Expression) ctx.vE1.accept(this),
-        (Expression) ctx.vE2.accept(this)));
-  }
-
-  @Override
-  public Object visitInlinecount(final InlinecountContext ctx) {
-    final String text = ctx.children.get(2).getText();
-    return new CountOptionImpl()
-        .setValue(text.equalsIgnoreCase("true") ? true : false)
-        .setText(text);
-  }
-
-  @Override
-  public Expression visitGeoIntersectsMethodCallExpr(final GeoIntersectsMethodCallExprContext ctx) {
-    return new MethodImpl(MethodKind.GEOINTERSECTS, Arrays.asList(
-        (Expression) ctx.vE1.accept(this),
-        (Expression) ctx.vE2.accept(this)));
-  }
-
-  @Override
-  public Expression visitIsofExpr(final IsofExprContext ctx) {
-    List<Expression> parameters = new ArrayList<Expression>();
-    if (ctx.vE1 != null) {
-      parameters.add((Expression) ctx.vE1.accept(this));
-    }
-
-    String namespace = ctx.vNS.getText();
-    namespace = namespace.substring(0, namespace.length() - 1);
-
-    FullQualifiedName fullName = new FullQualifiedName(namespace, ctx.vODI.getText());
-    EdmType type = getType(fullName);
-    parameters.add(new TypeLiteralImpl(type));
-
-    return new MethodImpl(MethodKind.ISOF, parameters);
-  }
-
-  @Override
-  public Expression visitLengthMethodCallExpr(final LengthMethodCallExprContext ctx) {
-    return new MethodImpl(MethodKind.LENGTH, Collections.singletonList((Expression) ctx.vE1.accept(this)));
-  }
-
-  @Override
-  public Object visitLevels(final LevelsContext ctx) {
-
-    LevelsOptionImpl levels = new LevelsOptionImpl();
-
-    String text = ctx.children.get(2).getText();
-
-    if (text.equals("max")) {
-      levels.setMax();
-    } else {
-      levels.setValue(Integer.parseInt(text));
-    }
-    levels.setText(text);
-
-    return levels;
-
-  }
-
-  @Override
-  public Expression visitMaxDateTimeMethodCallExpr(final MaxDateTimeMethodCallExprContext ctx) {
-    return new MethodImpl(MethodKind.MAXDATETIME, null);
-  }
-
-  @Override
-  public Object visitMemberExpr(final MemberExprContext ctx) {
-
-    UriInfoImpl uriInfoImplpath = new UriInfoImpl().setKind(UriInfoKind.resource);
-
-    if (context.contextTypes.isEmpty()) {
-      throw wrap(new UriParserSemanticException("Expression '" + ctx.getText() + "' is not allowed as key value.",
-          UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE, ctx.getText()));
-    }
-
-    if (ctx.vIt != null || ctx.vIts != null) {
-      uriInfoImplpath.addResourcePart(new UriResourceItImpl(context.contextTypes.peek(), context.isCollection));
-    }
-
-    if (ctx.vPs != null) {
-      // save the context
-      UriInfoImpl backupUriInfoPath = context.contextUriInfo;
-
-      // set temporary uriInfoPath
-      context.contextUriInfo = uriInfoImplpath;
-
-      ctx.vPs.accept(this);
-
-      // reset context
-      context.contextUriInfo = backupUriInfoPath;
-    }
-
-    if (ctx.vALL != null) {
-      uriInfoImplpath.addResourcePart((UriResourceImpl) ctx.vALL.accept(this));
-    }
-    if (ctx.vANY != null) {
-      uriInfoImplpath.addResourcePart((UriResourceImpl) ctx.vANY.accept(this));
-    }
-
-    EdmType startType = removeUriResourceStartingTypeFilterImpl(uriInfoImplpath);
-
-    return new MemberImpl(uriInfoImplpath, startType);
-  }
-
-  @Override
-  public Expression visitMinDateTimeMethodCallExpr(final MinDateTimeMethodCallExprContext ctx) {
-    return new MethodImpl(MethodKind.MINDATETIME, null);
-  }
-
-  @Override
-  public Expression visitMinuteMethodCallExpr(final MinuteMethodCallExprContext ctx) {
-    return new MethodImpl(MethodKind.MINUTE, Collections.singletonList((Expression) ctx.vE1.accept(this)));
-  }
-
-  @Override
-  public Expression visitMonthMethodCallExpr(final MonthMethodCallExprContext ctx) {
-    return new MethodImpl(MethodKind.MONTH, Collections.singletonList((Expression) ctx.vE1.accept(this)));
-  }
-
-  @Override
-  public Object visitNameValueOptList(final NameValueOptListContext ctx) {
-    if (ctx.vVO != null) {
-      // This branch is chosen if the key predicate is a common expression e.g. EntitySet(0)
-
-      // is single key predicate without a name
-      String valueText = ctx.vVO.getText();
-      Expression expression = null;
-      try {
-        expression = (Expression) ctx.vVO.accept(this);
-      } catch (final RuntimeException e) {
-        throw wrap(new UriParserSemanticException("Invalid key value: " + valueText, e,
-            UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE, valueText));
-      }
-
-      // get type of last resource part
-      UriResource last = context.contextUriInfo.getLastResourcePart();
-      if (!(last instanceof UriResourcePartTyped)) {
-        throw wrap(new UriParserSemanticException("Parameters list on untyped resource path segment not allowed",
-            UriParserSemanticException.MessageKeys.PARAMETERS_LIST_ONLY_FOR_TYPED_PARTS));
-
-      } else if (last instanceof UriResourceFunction) {
-        // Handle functions
-        final UriResourceFunction uriResourceFunction =
-            (UriResourceFunction) context.contextUriInfo.getLastResourcePart();
-        final EdmReturnType returnType = uriResourceFunction.getFunction().getReturnType();
-
-        if (returnType.getType().getKind() != EdmTypeKind.ENTITY || !returnType.isCollection()) {
-          throw wrap(new UriParserSemanticException("No keys allowed",
-              UriParserSemanticException.MessageKeys.KEY_NOT_ALLOWED));
-        } else {
-          // The functions returns a collection of entities
-          // Get the EDM Type and determine how many key predicates are needed. In this case only one
-          // key predicate is allowed. If the entity type needs more than one key predicate, the client
-          // has to use the key value syntax e.g. EntitySet(ID=1,Order=2)
-          final EdmEntityType entityType = (EdmEntityType) uriResourceFunction.getFunction().getReturnType().getType();
-          final List<String> lastKeyPredicates = entityType.getKeyPredicateNames();
-
-          if (lastKeyPredicates.size() == 1) {
-            return Collections.singletonList(new UriParameterImpl()
-                .setName(lastKeyPredicates.get(0))
-                .setText(valueText)
-                .setExpression(expression));
-          } else {
-            throw wrap(new UriParserSemanticException("Wrong number of key properties.",
-                UriParserSemanticException.MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES,
-                Integer.toString(lastKeyPredicates.size()), "1"));
-          }
-        }
-      } else {
-        // Handle EntitySets
-        EdmEntityType lastType = (EdmEntityType) ((UriResourcePartTyped) last).getType();
-
-        // get list of keys for lastType
-        List<String> lastKeyPredicates = lastType.getKeyPredicateNames();
-
-        // If there is exactly one key defined in the EDM, then this key is the key written in the URI,
-        // so fill the keylist with this key and return.
-        if (lastKeyPredicates.size() == 1) {
-          return Collections.singletonList(new UriParameterImpl()
-              .setName(lastKeyPredicates.get(0))
-              .setText(valueText)
-              .setExpression(expression));
-        }
-
-        // There are more keys defined in the EDM, but only one is written in the URI. This is allowed only if
-        // referential constraints are defined on this navigation property which can be used to fill up all
-        // required keys.
-        // For using referential constraints the last resource part must be a navigation property.
-        if (!(context.contextUriInfo.getLastResourcePart() instanceof UriResourceNavigationPropertyImpl)) {
-          throw wrap(new UriParserSemanticException("Wrong number of key properties.",
-              UriParserSemanticException.MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES,
-              Integer.toString(lastKeyPredicates.size()), "1"));
-        }
-        UriResourceNavigationPropertyImpl lastNav = (UriResourceNavigationPropertyImpl) last;
-
-        // get the partner of the navigation property
-        EdmNavigationProperty partner = lastNav.getProperty().getPartner();
-        if (partner == null) {
-          throw wrap(new UriParserSemanticException("Wrong number of key properties.",
-              UriParserSemanticException.MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES,
-              Integer.toString(lastKeyPredicates.size()), "1"));
-        }
-
-        // create the keylist
-        List<UriParameterImpl> list = new ArrayList<UriParameterImpl>();
-
-        // Find the keys not filled by referential constraints
-        // and collect the other keys filled by referential constraints.
-        String missedKey = null;
-        for (String item : lastKeyPredicates) {
-          String property = partner.getReferencingPropertyName(item);
-          if (property != null) {
-            list.add(new UriParameterImpl().setName(item).setReferencedProperty(property));
-          } else {
-            if (missedKey == null) {
-              missedKey = item;
-            } else {
-              // two of more keys are missing
-              throw wrap(new UriParserSemanticException("Not enough referential constraints defined",
-                  UriParserSemanticException.MessageKeys.NOT_ENOUGH_REFERENTIAL_CONSTRAINTS));
-            }
-          }
-        }
-
-        // the missing key is the one which is defined in the URI
-        list.add(new UriParameterImpl().setName(missedKey).setText(valueText).setExpression(expression));
-
-        return list;
-      }
-    } else if (ctx.vNVL != null) {
-      // The client provided a list of key values pairs e.g. EntitySet(ID=1,Order=2)
-      List<UriParameterImpl> list = new ArrayList<UriParameterImpl>();
-
-      for (ParseTree c : ctx.vNVL.vlNVP) {
-        list.add((UriParameterImpl) c.accept(this));
-      }
-
-      if (context.contextReadingFunctionParameters) {
-        return list;
-      }
-
-      UriResource last = context.contextUriInfo.getLastResourcePart();
-
-      // get type of last resource part
-      if (!(last instanceof UriResourcePartTyped)) {
-        throw wrap(new UriParserSemanticException("Parameters list on untyped resource path segment not allowed",
-            UriParserSemanticException.MessageKeys.PARAMETERS_LIST_ONLY_FOR_TYPED_PARTS));
-      }
-      if (last instanceof UriResourceFunction) {
-        final UriResourceFunction uriResourceFunction = (UriResourceFunction) context.contextUriInfo
-            .getLastResourcePart();
-        final EdmReturnType returnType = uriResourceFunction.getFunction().getReturnType();
-
-        if (returnType.getType().getKind() != EdmTypeKind.ENTITY || !returnType.isCollection()) {
-          throw wrap(new UriParserSemanticException("No keys allowed",
-              UriParserSemanticException.MessageKeys.KEY_NOT_ALLOWED));
-        } else {
-          // The functions returns a collection of entities
-          // Get the EDM Type and determine how many key predicates are needed.
-          // In case of functions all key predicates must be provided by the client.
-          final EdmEntityType entityType = (EdmEntityType) uriResourceFunction.getFunction().getReturnType().getType();
-          final List<String> lastKeyPredicates = entityType.getKeyPredicateNames();
-
-          if (lastKeyPredicates.size() == list.size()) {
-            return list;
-          } else {
-            throw wrap(new UriParserSemanticException("Wrong number of key properties.",
-                UriParserSemanticException.MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES,
-                Integer.toString(lastKeyPredicates.size()), "1"));
-          }
-        }
-      } else {
-        // Handle entity sets
-        EdmEntityType lastType = (EdmEntityType) ((UriResourcePartTyped) last).getType();
-
-        // get list of keys for lastType
-        List<String> lastKeyPredicates = lastType.getKeyPredicateNames();
-
-        // check if all key are filled from the URI
-        if (list.size() == lastKeyPredicates.size()) {
-          return list;
-        }
-
-        // if not, check if the missing key predicates can be satisfied with help of the defined
-        // referential constraints
-        // for using referential constraints the last resource part must be a navigation property
-        if (!(context.contextUriInfo.getLastResourcePart() instanceof UriResourceNavigationPropertyImpl)) {
-          throw wrap(new UriParserSemanticException("Wrong number of key properties.",
-              UriParserSemanticException.MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES,
-              Integer.toString(lastKeyPredicates.size()), Integer.toString(list.size())));
-        }
-        UriResourceNavigationPropertyImpl lastNav = (UriResourceNavigationPropertyImpl) last;
-
-        // get the partner of the navigation property
-        EdmNavigationProperty partner = lastNav.getProperty().getPartner();
-        if (partner == null) {
-          throw wrap(new UriParserSemanticException("Wrong number of key properties.",
-              UriParserSemanticException.MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES,
-              Integer.toString(lastKeyPredicates.size()), Integer.toString(list.size())));
-        }
-
-        // fill missing keys from referential constraints
-        for (String key : lastKeyPredicates) {
-          boolean found = false;
-          for (UriParameterImpl item : list) {
-            if (item.getName().equals(key)) {
-              found = true;
-              break;
-            }
-          }
-
-          if (!found) {
-            String property = partner.getReferencingPropertyName(key);
-            if (property != null) {
-              // store the key name as referenced property
-              list.add(0, new UriParameterImpl().setName(key).setReferencedProperty(property));
-            }
-          }
-        }
-
-        // check again if all key predicates are filled from the URI
-        if (list.size() == lastKeyPredicates.size()) {
-          return list;
-        } else {
-          throw wrap(new UriParserSemanticException("Wrong number of key properties.",
-              UriParserSemanticException.MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES,
-              Integer.toString(lastKeyPredicates.size()), Integer.toString(list.size())));
-        }
-      }
-    } else {
-      // No key predicates are provided by the client
-
-      if (context.contextReadingFunctionParameters) {
-        return Collections.emptyList();
-      } else {
-        final UriResource last = context.contextUriInfo.getLastResourcePart();
-        final int number = last instanceof UriResourcePartTyped ? ((EdmEntityType) ((UriResourcePartTyped) last)
-            .getType()).getKeyPredicateNames().size() : 0;
-        throw wrap(new UriParserSemanticException("Wrong number of key properties.",
-            UriParserSemanticException.MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES, Integer.toString(number), "0"));
-      }
-    }
-  }
-
-  @Override
-  public UriParameterImpl visitNameValuePair(final NameValuePairContext ctx) {
-    UriParameterImpl uriParameter = new UriParameterImpl();
-    uriParameter.setName(ctx.vODI.getText());
-
-    if (ctx.vCOM != null) {
-      final String text = ctx.vCOM.getText();
-      uriParameter.setText("null".equals(text) ? null : text);
-      uriParameter.setExpression((Expression) ctx.vCOM.accept(this));
-    } else {
-      uriParameter.setAlias("@" + ctx.vALI.getText());
-    }
-
-    return uriParameter;
-  }
-
-  @Override
-  public Object visitNaninfinityLiteral(final NaninfinityLiteralContext ctx) {
-    return new LiteralImpl(ctx.getText(),
-        EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal));
-  }
-
-  @Override
-  public Expression visitNowMethodCallExpr(final NowMethodCallExprContext ctx) {
-    return new MethodImpl(MethodKind.NOW, null);
-  }
-
-  @Override
-  public Object visitNullruleLiteral(final NullruleLiteralContext ctx) {
-    return new LiteralImpl("null", null);
-  }
-
-  @Override
-  public Object visitOrderBy(final OrderByContext ctx) {
-
-    OrderByOptionImpl orderBy = new OrderByOptionImpl();
-
-    for (OrderByItemContext item : ((OrderListContext) ctx.getChild(2)).vlOI) {
-      OrderByItemImpl oItem = (OrderByItemImpl) item.accept(this);
-      orderBy.addOrder(oItem);
-    }
-
-    return orderBy;
-  }
-
-  @Override
-  public Object visitOrderByEOF(final OrderByEOFContext ctx) {
-    context.contextReadingQueryPart = true;
-    
-    OrderByOptionImpl orderBy = new OrderByOptionImpl();
-
-    for (OrderByItemContext item : ((OrderListContext) ctx.getChild(0)).vlOI) {
-      OrderByItemImpl oItem = (OrderByItemImpl) item.accept(this);
-      orderBy.addOrder(oItem);
-    }
-
-    context.contextReadingFunctionParameters = false;
-    return orderBy;
-  }
-
-  @Override
-  public Object visitOrderByItem(final OrderByItemContext ctx) {
-    OrderByItemImpl oItem = new OrderByItemImpl();
-    if (ctx.vD != null) {
-      oItem.setDescending(true);
-    }
-
-    oItem.setExpression((Expression) ctx.vC.accept(this));
-    return oItem;
-  }
-
-  @Override
-  public Object visitPathSegment(final PathSegmentContext ctx) {
-    readResourcePathSegment(ctx);
-    /*
-     * if (contextUriInfo.getLastResourcePart() == null ||
-     * contextUriInfo.getLastResourcePart() instanceof UriResourceRootImpl) {
-     * 
-     * } else {
-     * readNextPathInfoSegment(ctx);
-     * }
-     */
-    UriResourceImpl pathInfoSegment = (UriResourceImpl) context.contextUriInfo.getLastResourcePart();
-
-    if (ctx.vlNVO.size() > 0) {
-      // check for keyPredicates
-      if (pathInfoSegment instanceof UriResourceWithKeysImpl) {
-        if (ctx.vlNVO.size() > 1) {
-          throw wrap(new UriParserSemanticException("More than one key predicates found",
-              UriParserSemanticException.MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES, "1",
-              Integer.toString(ctx.vlNVO.size())));
-        }
-
-        @SuppressWarnings("unchecked")
-        List<UriParameter> list = (List<UriParameter>) ctx.vlNVO.get(0).accept(this);
-        ((UriResourceWithKeysImpl) pathInfoSegment)
-            .setKeyPredicates(list);
-      } else {
-        throw wrap(new UriParserSemanticException("Key properties not allowed",
-            UriParserSemanticException.MessageKeys.KEY_NOT_ALLOWED));
-      }
-    }
-
-    return pathInfoSegment;
-  }
-
-  @Override
-  public Object visitPathSegments(final PathSegmentsContext ctx) {
-    // path segment
-    for (PathSegmentContext it : ctx.vlPS) {
-      it.accept(this);
-    }
-
-    // const segment
-    if (ctx.vCS != null) {
-      ctx.vCS.accept(this);
-    }
-    return null;
-  }
-
-  @Override
-  public Object visitPrimitiveLiteral(final PrimitiveLiteralContext ctx) {
-    ParseTree child1 = ctx.children.get(0);
-
-    if (child1 instanceof EnumLiteralContext
-        || child1 instanceof BooleanNonCaseLiteralContext
-        || child1 instanceof NullruleLiteralContext
-        || child1 instanceof NaninfinityLiteralContext
-        || child1 instanceof StringLiteralContext
-        || child1 instanceof IntLiteralContext
-        || child1 instanceof BinaryLiteralContext
-        || child1 instanceof DateLiteralContext
-        || child1 instanceof DatetimeoffsetLiteralContext
-        || child1 instanceof DurationLiteralContext
-        || child1 instanceof GuidLiteralContext
-        || child1 instanceof TimeofdayLiteralContext
-        || child1 instanceof DecimalLiteralContext
-        || child1 instanceof BinaryLiteralContext) {
-      return child1.accept(this);
-    }
-
-    // TODO Implement geography types and set a proper type
-    return new LiteralImpl(ctx.getText(), null);
-  }
-
-  @Override
-  public Object visitBinaryLiteral(BinaryLiteralContext ctx) {
-    return new LiteralImpl(ctx.getText(),
-        EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Binary));
-  }
-
-  @Override
-  public Object visitStringLiteral(final StringLiteralContext ctx) {
-    return new LiteralImpl(ctx.getText(),
-        EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.String));
-  }
-
-  @Override
-  public Object visitDecimalLiteral(final DecimalLiteralContext ctx) {
-    final EdmType type = EdmPrimitiveTypeFactory.getInstance(
-        ctx.getText().contains("e") || ctx.getText().contains("E") ?
-            EdmPrimitiveTypeKind.Double :
-            EdmPrimitiveTypeKind.Decimal);
-
-    return new LiteralImpl(ctx.getText(), type);
-  }
-
-  @Override
-  public Object visitIntLiteral(final IntLiteralContext ctx) {
-    EdmPrimitiveTypeKind typeKind = null;
-    try {
-      final long value = Long.parseLong(ctx.getText());
-      if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
-        typeKind = EdmPrimitiveTypeKind.SByte;
-      } else if (value >= 0 && value <= 255) {
-        typeKind = EdmPrimitiveTypeKind.Byte;
-      } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
-        typeKind = EdmPrimitiveTypeKind.Int16;
-      } else if (value >= Integer.MIN_VALUE && value <= Integer.MAX_VALUE) {
-        typeKind = EdmPrimitiveTypeKind.Int32;
-      } else {
-        typeKind = EdmPrimitiveTypeKind.Int64;
-      }
-    } catch (NumberFormatException e) {
-      return new LiteralImpl(ctx.getText(),
-          EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal));
-    }
-    return new LiteralImpl(ctx.getText(),
-        EdmPrimitiveTypeFactory.getInstance(typeKind));
-  }
-
-  @Override
-  public Object visitDateLiteral(final DateLiteralContext ctx) {
-    return new LiteralImpl(ctx.getText(),
-        EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Date));
-  }
-
-  @Override
-  public Object visitDatetimeoffsetLiteral(final DatetimeoffsetLiteralContext ctx) {
-    return new LiteralImpl(ctx.getText(),
-        EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.DateTimeOffset));
-  }
-
-  @Override
-  public Object visitDurationLiteral(final DurationLiteralContext ctx) {
-    return new LiteralImpl(ctx.getText(),
-        EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Duration));
-  }
-
-  @Override
-  public Object visitGuidLiteral(final GuidLiteralContext ctx) {
-    return new LiteralImpl(ctx.getText(),
-        EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Guid));
-  }
-
-  @Override
-  public Object visitTimeofdayLiteral(final TimeofdayLiteralContext ctx) {
-    return new LiteralImpl(ctx.getText(),
-        EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.TimeOfDay));
-  }
-
-  @Override
-  public Object visitQueryOptions(final QueryOptionsContext ctx) {
-
-    List<QueryOptionImpl> qpList = new ArrayList<QueryOptionImpl>();
-    for (QueryOptionContext entityOption : ctx.vlQO) {
-      qpList.add((QueryOptionImpl) entityOption.accept(this));
-    }
-
-    return qpList;
-  }
-
-  @Override
-  public Object visitRootExpr(final RootExprContext ctx) {
-
-    UriResource lastResource = context.contextUriInfo.getLastResourcePart();
-
-    if (!(lastResource instanceof UriResourcePartTyped)) {
-      throw wrap(new UriParserSemanticException("Resource path not typed",
-          UriParserSemanticException.MessageKeys.RESOURCE_PATH_NOT_TYPED));
-    }
-
-    UriResourcePartTyped lastType = (UriResourcePartTyped) lastResource;
-
-    UriResourceRootImpl pathInfoRoot = new UriResourceRootImpl(
-        ParserHelper.getTypeInformation(lastType),
-        lastType.isCollection());
-
-    UriInfoImpl uriInfoImplpath = new UriInfoImpl().setKind(UriInfoKind.resource);
-    uriInfoImplpath.addResourcePart(pathInfoRoot);
-
-    if (ctx.vPs != null) {
-      // store the context uriInfoPath
-      UriInfoImpl backupUriInfoPath = context.contextUriInfo;
-
-      // set temporary uriInfoPath to collect the path information of the memberExpression
-      context.contextUriInfo = uriInfoImplpath;
-
-      ctx.vPs.accept(this);
-
-      context.contextUriInfo = backupUriInfoPath;
-
-    }
-    return new MemberImpl(uriInfoImplpath, null);
-
-  }
-
-  @Override
-  public Expression visitRoundMethodCallExpr(final RoundMethodCallExprContext ctx) {
-    return new MethodImpl(MethodKind.ROUND, Collections.singletonList((Expression) ctx.vE1.accept(this)));
-  }
-
-  @Override
-  public Expression visitSecondMethodCallExpr(final SecondMethodCallExprContext ctx) {
-    return new MethodImpl(MethodKind.SECOND, Collections.singletonList((Expression) ctx.vE1.accept(this)));
-  }
-
-  @Override
-  public Object visitSelect(final SelectContext ctx) {
-    List<SelectItem> selectItems = new ArrayList<SelectItem>();
-    for (SelectItemContext si : ctx.vlSI) {
-      selectItems.add((SelectItem) si.accept(this));
-    }
-
-    return new SelectOptionImpl().setSelectItems(selectItems).setText(ctx.children.get(2).getText());
-  }
-
-  @Override
-  public Object visitSelectEOF(final SelectEOFContext ctx) {
-    context.contextReadingQueryPart = true;
-    List<SelectItem> selectItems = new ArrayList<SelectItem>();
-    for (SelectItemContext si : ctx.vlSI) {
-      selectItems.add((SelectItem) si.accept(this));
-    }
-
-    final QueryOptionImpl result = new SelectOptionImpl().setSelectItems(selectItems).setText(ctx.getText());
-    context.contextReadingQueryPart = false;
-    
-    return result;
-  }
-
-  @Override
-  public Object visitSelectItem(final SelectItemContext ctx) {
-    SelectItemImpl selectItem = new SelectItemImpl();
-
-    context.contextSelectItem = selectItem;
-    for (SelectSegmentContext si : ctx.vlSS) {
-      si.accept(this);
-    }
-    context.contextSelectItem = null;
-
-    return selectItem;
-  }
-
-  @Override
-  public Object visitSelectSegment(final SelectSegmentContext ctx) {
-
-    if (ctx.vS != null) {
-      if (ctx.vNS != null) {
-        String namespace = ctx.vNS.getText();
-        namespace = namespace.substring(0, namespace.length() - 1);
-        FullQualifiedName fullName = new FullQualifiedName(namespace, "*");
-        context.contextSelectItem.addAllOperationsInSchema(fullName);
-      } else {
-        context.contextSelectItem.setStar(true);
-      }
-      return null;
-    }
-
-    String odi = ctx.vODI.getText();
-    if (ctx.vNS == null) {
-
-      EdmType prevType = null;
-      if (context.contextSelectItem.getResourcePath() == null) {
-        prevType = context.contextTypes.peek();
-      } else {
-        UriInfoImpl uriInfo = (UriInfoImpl) context.contextSelectItem.getResourcePath();
-        UriResource last = uriInfo.getLastResourcePart();
-
-        prevType = ParserHelper.getTypeInformation((UriResourcePartTyped) last);
-        if (prevType == null) {
-          throw wrap(new UriParserSemanticException("prev segment not typed",
-              UriParserSemanticException.MessageKeys.ONLY_FOR_TYPED_PARTS, "select"));
-        }
-      }
-
-      if (!(prevType instanceof EdmStructuredType)) {
-        throw wrap(new UriParserSemanticException("Previous select item is not a structural type",
-            UriParserSemanticException.MessageKeys.ONLY_FOR_STRUCTURAL_TYPES, "select"));

<TRUNCATED>

[20/30] olingo-odata4 git commit: [OLINGO-834] $expand parser in Java + clean-up

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8925274c/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestLexer.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestLexer.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestLexer.java
index 6df6759..6102fd8 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestLexer.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestLexer.java
@@ -18,16 +18,22 @@
  */
 package org.apache.olingo.server.core.uri.antlr;
 
-import org.antlr.v4.runtime.Lexer;
-import org.apache.olingo.server.core.uri.testutil.TokenValidator;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.olingo.server.core.uri.parser.UriTokenizer;
+import org.apache.olingo.server.core.uri.parser.UriTokenizer.TokenKind;
 import org.junit.Test;
 
+/**
+ * Tests originally written for the ANTLR lexer.
+ */
 public class TestLexer {
 
   private TokenValidator test = null;
 
-  private static final String cPCT_ENCODED = "%45%46%47" + "%22" + "%5C";// last two chars are not in
-  // cPCT_ENCODED_UNESCAPED
+  // The last two chars are not in cPCT_ENCODED_UNESCAPED.
+  private static final String cPCT_ENCODED = "%45%46%47" + "%22" + "%5C";
   private static final String cUNRESERVED = "ABCabc123-._~";
   private static final String cOTHER_DELIMS = "!()*+,;";
   private static final String cSUB_DELIMS = "$&'=" + cOTHER_DELIMS;
@@ -39,265 +45,279 @@ public class TestLexer {
   }
 
   @Test
-  public void test() {
-
-    // test.log(1).run("ESAllPrim?$orderby=PropertyDouble eq 3.5E+38");
+  public void unary() {
+    test.run("-a eq a").has(TokenKind.MinusOperator, TokenKind.ODataIdentifier, TokenKind.EqualsOperator,
+        TokenKind.ODataIdentifier).isInput();
   }
 
-  // ;------------------------------------------------------------------------------
-  // ; 0. URI
-  // ;------------------------------------------------------------------------------
-
   @Test
-  public void testUnary() {
-    test.run("- a eq a").isAllInput();
+  public void uriTokens() {
+//    test.run("#").isType(TokenKind.FRAGMENT).isInput();
+    test.run("$count").has(TokenKind.COUNT).isInput();
+    test.run("$ref").has(TokenKind.REF).isInput();
+    test.run("$value").has(TokenKind.VALUE).isInput();
   }
 
   @Test
-  public void testUriTokens() {
-    test.globalMode(UriLexer.MODE_QUERY);
-    test.run("#").isText("#").isType(UriLexer.FRAGMENT);
-    test.run("$count").isText("$count").isType(UriLexer.COUNT);
-    test.run("$ref").isText("$ref").isType(UriLexer.REF);
-    test.run("$value").isText("$value").isType(UriLexer.VALUE);
+  public void queryOptionsTokens() {
+    test.run("$skip=1").has(TokenKind.SKIP, TokenKind.EQ, TokenKind.IntegerValue).isInput();
+    test.run("$skip=2").has(TokenKind.SKIP, TokenKind.EQ, TokenKind.IntegerValue).isInput();
+    test.run("$skip=123").has(TokenKind.SKIP, TokenKind.EQ, TokenKind.IntegerValue).isInput();
+
+    test.run("$top=1").has(TokenKind.TOP, TokenKind.EQ, TokenKind.IntegerValue).isInput();
+    test.run("$top=2").has(TokenKind.TOP, TokenKind.EQ, TokenKind.IntegerValue).isInput();
+    test.run("$top=123").has(TokenKind.TOP, TokenKind.EQ, TokenKind.IntegerValue).isInput();
+
+    test.run("$levels=1").has(TokenKind.LEVELS, TokenKind.EQ, TokenKind.IntegerValue).isInput();
+    test.run("$levels=2").has(TokenKind.LEVELS, TokenKind.EQ, TokenKind.IntegerValue).isInput();
+    test.run("$levels=123").has(TokenKind.LEVELS, TokenKind.EQ, TokenKind.IntegerValue).isInput();
+    test.run("$levels=max").has(TokenKind.LEVELS, TokenKind.EQ, TokenKind.MAX).isInput();
+
+//    test.run("$format=atom").has(TokenKind.FORMAT, TokenKind.EQ, TokenKind.ODataIdentifier).isInput();
+//    test.run("$format=json").has(TokenKind.FORMAT, TokenKind.EQ, TokenKind.ODataIdentifier).isInput();
+//    test.run("$format=xml").has(TokenKind.FORMAT,, TokenKind.EQ, TokenKind.ODataIdentifier).isInput();
+//    test.run("$format=abc/def").has(TokenKind.FORMAT, TokenKind.EQ,
+//        TokenKind.ODataIdentifier, TokenKind.SLASH, TokenKind.ODataIdentifier).isInput();
+
+//    test.run("$id=123").has(TokenKind.ID, TokenKind.EQ, TokenKind.IntegerValue).isInput();
+//    test.run("$id=ABC").has(TokenKind.ID, TokenKind.EQ, TokenKind.ODataIdentifier).isInput();
+
+//    test.run("$skiptoken=ABC").has(TokenKind.SKIPTOKEN, TokenKind.EQ, TokenKind.ODataIdentifier).isInput();
+//    test.run("$skiptoken=ABC").has(TokenKind.SKIPTOKEN, TokenKind.EQ, TokenKind.ODataIdentifier).isInput();
+
+    test.run("$search=\"ABC\"").has(TokenKind.SEARCH, TokenKind.EQ, TokenKind.Phrase).isInput();
+    test.run("$search=ABC").has(TokenKind.SEARCH, TokenKind.EQ, TokenKind.Word).isInput();
+    test.run("$search=\"A%20B%20C\"").has(TokenKind.SEARCH, TokenKind.EQ, TokenKind.Phrase).isInput();
+    test.run("$search=Test Test").has(TokenKind.SEARCH, TokenKind.EQ, TokenKind.Word,
+        TokenKind.AndOperatorSearch, TokenKind.Word).isInput();
+    test.run("$search=Test&$filter=ABC eq 1").has(TokenKind.SEARCH, TokenKind.EQ, TokenKind.Word);
   }
 
-  // ;------------------------------------------------------------------------------
-  // ; 2. Query Options
-  // ;------------------------------------------------------------------------------
   @Test
-  public void testQueryOptionsTokens() {
-
-    test.globalMode(UriLexer.MODE_QUERY);
-    test.run("$skip=1").isAllText("$skip=1").isType(UriLexer.SKIP_QO);
-    test.run("$skip=2").isAllText("$skip=2").isType(UriLexer.SKIP_QO);
-    test.run("$skip=123").isAllText("$skip=123").isType(UriLexer.SKIP_QO);
-
-    test.run("$top=1").isAllText("$top=1").isType(UriLexer.TOP);
-    test.run("$top=2").isAllText("$top=2").isType(UriLexer.TOP);
-    test.run("$top=123").isAllText("$top=123").isType(UriLexer.TOP);
-
-    test.run("$levels=1").isAllText("$levels=1").isType(UriLexer.LEVELS);
-    test.run("$levels=2").isAllText("$levels=2").isType(UriLexer.LEVELS);
-    test.run("$levels=123").isAllText("$levels=123").isType(UriLexer.LEVELS);
-    test.run("$levels=max").isAllText("$levels=max").isType(UriLexer.LEVELS);
-
-    test.run("$format=atom").isAllText("$format=atom").isType(UriLexer.FORMAT);
-    test.run("$format=json").isAllText("$format=json").isType(UriLexer.FORMAT);
-    test.run("$format=xml").isAllText("$format=xml").isType(UriLexer.FORMAT);
-    test.run("$format=abc/def").isAllText("$format=abc/def").isType(UriLexer.FORMAT);
-
-    test.run("$id=123").isAllText("$id=123").isType(UriLexer.ID);
-    test.run("$id=ABC").isAllText("$id=ABC").isType(UriLexer.ID);
-
-    test.run("$skiptoken=ABC").isAllText("$skiptoken=ABC").isType(UriLexer.SKIPTOKEN);
-    test.run("$skiptoken=ABC").isAllText("$skiptoken=ABC").isType(UriLexer.SKIPTOKEN);
-
-    test.run("$search=\"ABC\"").isAllText("$search=\"ABC\"").isType(UriLexer.SEARCH);
-    test.run("$search=ABC").isAllText("$search=ABC").isType(UriLexer.SEARCH);
-    test.run("$search=\"A%20B%20C\"").isAllText("$search=\"A%20B%20C\"").isType(UriLexer.SEARCH);
-    test.run("$search=Test Test").isAllText("$search=Test Test").isType(UriLexer.SEARCH);
-    test.run("$search=Test&$filter=ABC eq 1").isAllText("$search=Test&$filter=ABC eq 1").isType(UriLexer.SEARCH);
-  }
-  
-  @Test
-  public void testQueryOptionsDefaultMode() {
-    // First set query mode, than use expand(switches to default mode) and use nested system query options
-    test.globalMode(UriLexer.MODE_QUERY);
-    test.run("$expand=ABC($skip=1)").isAllText("$expand=ABC($skip=1)").at(4).isType(UriLexer.SKIP_QO);
-    test.run("$expand=ABC($skip=2)").isAllText("$expand=ABC($skip=2)").at(4).isType(UriLexer.SKIP_QO);
-    test.run("$expand=ABC($skip=123)").isAllText("$expand=ABC($skip=123)").at(4).isType(UriLexer.SKIP_QO);
-    test.run("$expand=ABC($search=abc)").isAllText("$expand=ABC($search=abc)").at(4).isType(UriLexer.SEARCH_INLINE);
-    test.run("$expand=ABC($search=\"123\")").isAllText("$expand=ABC($search=\"123\")")
-                                            .at(4).isType(UriLexer.SEARCH_INLINE)
-                                            .at(6).isType(UriLexer.SEARCHPHRASE);
-    test.run("$expand=ABC($top=1)").isAllText("$expand=ABC($top=1)").at(4).isType(UriLexer.TOP);
-    test.run("$expand=ABC($top=2)").isAllText("$expand=ABC($top=2)").at(4).isType(UriLexer.TOP);
-    test.run("$expand=ABC($top=123)").isAllText("$expand=ABC($top=123)").at(4).isType(UriLexer.TOP);
-    
-    test.run("$expand=ABC($expand=DEF($skip=1))").isAllText("$expand=ABC($expand=DEF($skip=1))")
-                                                 .at(8).isType(UriLexer.SKIP_QO);
-    test.run("$expand=ABC($expand=DEF($skip=2))").isAllText("$expand=ABC($expand=DEF($skip=2))")
-                                                 .at(8).isType(UriLexer.SKIP_QO);
-    test.run("$expand=ABC($expand=DEF($skip=123))").isAllText("$expand=ABC($expand=DEF($skip=123))")
-                                                 .at(8).isType(UriLexer.SKIP_QO);
-    
-    test.run("$expand=ABC($expand=DEF($top=1))").isAllText("$expand=ABC($expand=DEF($top=1))")
-                                                .at(8).isType(UriLexer.TOP);
-    test.run("$expand=ABC($expand=DEF($top=2))").isAllText("$expand=ABC($expand=DEF($top=2))")
-                                                .at(8).isType(UriLexer.TOP);
-    test.run("$expand=ABC($expand=DEF($top=123))").isAllText("$expand=ABC($expand=DEF($top=123))")
-                                                  .at(8).isType(UriLexer.TOP);
-    test.run("$expand=ABC($expand=DEF($search=Test Test))").isAllText("$expand=ABC($expand=DEF($search=Test Test))")
-                                                        .at(8).isType(UriLexer.SEARCH_INLINE)
-                                                        .at(10).isType(UriLexer.SEARCHWORD)
-                                                        .at(12).isType(UriLexer.SEARCHWORD);
+  public void queryOptionsDefaultMode() {
+    test.run("$expand=ABC($skip=1)").has(TokenKind.EXPAND, TokenKind.EQ, TokenKind.ODataIdentifier,
+        TokenKind.OPEN, TokenKind.SKIP, TokenKind.EQ, TokenKind.IntegerValue, TokenKind.CLOSE).isInput();
+    test.run("$expand=ABC($skip=123)").has(TokenKind.EXPAND, TokenKind.EQ, TokenKind.ODataIdentifier,
+        TokenKind.OPEN, TokenKind.SKIP, TokenKind.EQ, TokenKind.IntegerValue, TokenKind.CLOSE).isInput();
+    test.run("$expand=ABC($search=abc)").has(TokenKind.EXPAND, TokenKind.EQ, TokenKind.ODataIdentifier,
+        TokenKind.OPEN, TokenKind.SEARCH, TokenKind.EQ, TokenKind.Word, TokenKind.CLOSE).isInput();
+    test.run("$expand=ABC($search=\"123\")").has(TokenKind.EXPAND, TokenKind.EQ, TokenKind.ODataIdentifier,
+        TokenKind.OPEN, TokenKind.SEARCH, TokenKind.EQ, TokenKind.Phrase, TokenKind.CLOSE).isInput();
+    test.run("$expand=ABC($top=1)").has(TokenKind.EXPAND, TokenKind.EQ, TokenKind.ODataIdentifier,
+        TokenKind.OPEN, TokenKind.TOP, TokenKind.EQ, TokenKind.IntegerValue, TokenKind.CLOSE).isInput();
+    test.run("$expand=ABC($top=123)").has(TokenKind.EXPAND, TokenKind.EQ, TokenKind.ODataIdentifier,
+        TokenKind.OPEN, TokenKind.TOP, TokenKind.EQ, TokenKind.IntegerValue, TokenKind.CLOSE).isInput();
+
+    test.run("$expand=ABC($expand=DEF($skip=1))").has(TokenKind.EXPAND, TokenKind.EQ, TokenKind.ODataIdentifier,
+        TokenKind.OPEN, TokenKind.EXPAND, TokenKind.EQ, TokenKind.ODataIdentifier,
+        TokenKind.OPEN, TokenKind.SKIP, TokenKind.EQ, TokenKind.IntegerValue, TokenKind.CLOSE, TokenKind.CLOSE)
+        .isInput();
+    test.run("$expand=ABC($expand=DEF($skip=123))").has(TokenKind.EXPAND, TokenKind.EQ, TokenKind.ODataIdentifier,
+        TokenKind.OPEN, TokenKind.EXPAND, TokenKind.EQ, TokenKind.ODataIdentifier,
+        TokenKind.OPEN, TokenKind.SKIP, TokenKind.EQ, TokenKind.IntegerValue, TokenKind.CLOSE, TokenKind.CLOSE)
+        .isInput();
+
+    test.run("$expand=ABC($expand=DEF($top=1))").has(TokenKind.EXPAND, TokenKind.EQ, TokenKind.ODataIdentifier,
+        TokenKind.OPEN, TokenKind.EXPAND, TokenKind.EQ, TokenKind.ODataIdentifier,
+        TokenKind.OPEN, TokenKind.TOP, TokenKind.EQ, TokenKind.IntegerValue, TokenKind.CLOSE, TokenKind.CLOSE)
+        .isInput();
+    test.run("$expand=ABC($expand=DEF($top=123))").has(TokenKind.EXPAND, TokenKind.EQ, TokenKind.ODataIdentifier,
+        TokenKind.OPEN, TokenKind.EXPAND, TokenKind.EQ, TokenKind.ODataIdentifier,
+        TokenKind.OPEN, TokenKind.TOP, TokenKind.EQ, TokenKind.IntegerValue, TokenKind.CLOSE, TokenKind.CLOSE)
+        .isInput();
+
+    test.run("$expand=ABC($expand=DEF($search=Test Test))")
+        .has(TokenKind.EXPAND, TokenKind.EQ, TokenKind.ODataIdentifier,
+            TokenKind.OPEN, TokenKind.EXPAND, TokenKind.EQ, TokenKind.ODataIdentifier,
+            TokenKind.OPEN, TokenKind.SEARCH, TokenKind.EQ, TokenKind.Word,
+            TokenKind.AndOperatorSearch, TokenKind.Word, TokenKind.CLOSE, TokenKind.CLOSE)
+        .isInput();
     test.run("$expand=ABC($expand=DEF($search=\"Test\" \"Test\"))")
-                .isAllText("$expand=ABC($expand=DEF($search=\"Test\" \"Test\"))")
-                .at(8).isType(UriLexer.SEARCH_INLINE)
-                .at(10).isType(UriLexer.SEARCHPHRASE)
-                .at(12).isType(UriLexer.SEARCHPHRASE);
+        .has(TokenKind.EXPAND, TokenKind.EQ, TokenKind.ODataIdentifier,
+            TokenKind.OPEN, TokenKind.EXPAND, TokenKind.EQ, TokenKind.ODataIdentifier,
+            TokenKind.OPEN, TokenKind.SEARCH, TokenKind.EQ, TokenKind.Phrase,
+            TokenKind.AndOperatorSearch, TokenKind.Phrase, TokenKind.CLOSE, TokenKind.CLOSE)
+        .isInput();
     test.run("$expand=ABC($expand=DEF($search=\"Test\" \"Test\";$filter=PropertyInt16 eq 0;$orderby=PropertyInt16))")
-                .isAllText("$expand=ABC($expand=DEF($search=\"Test\" \"Test\";$filter=PropertyInt16 " + 
-                           "eq 0;$orderby=PropertyInt16))")
-                .at(8).isType(UriLexer.SEARCH_INLINE)
-                .at(10).isType(UriLexer.SEARCHPHRASE)
-                .at(12).isType(UriLexer.SEARCHPHRASE)
-                .at(13).isType(UriLexer.SEMI)
-                .at(14).isType(UriLexer.FILTER)
-                .at(22).isType(UriLexer.ORDERBY);
+        .has(TokenKind.EXPAND, TokenKind.EQ, TokenKind.ODataIdentifier,
+            TokenKind.OPEN, TokenKind.EXPAND, TokenKind.EQ, TokenKind.ODataIdentifier,
+            TokenKind.OPEN, TokenKind.SEARCH, TokenKind.EQ, TokenKind.Phrase,
+            TokenKind.AndOperatorSearch, TokenKind.Phrase, TokenKind.SEMI,
+            TokenKind.FILTER, TokenKind.EQ, TokenKind.ODataIdentifier, TokenKind.EqualsOperator,
+            TokenKind.IntegerValue, TokenKind.SEMI,
+            TokenKind.ORDERBY, TokenKind.EQ, TokenKind.ODataIdentifier, TokenKind.CLOSE, TokenKind.CLOSE)
+        .isInput();
   }
-  
-  // ;------------------------------------------------------------------------------
-  // ; 4. Expressions
-  // ;------------------------------------------------------------------------------
-  @Test
-  public void testQueryExpressions() {
-    test.globalMode(Lexer.DEFAULT_MODE);
-
-    test.run("$it").isText("$it").isType(UriLexer.IT);
-
-    test.run("$filter=contains(").at(2).isText("contains(").isType(UriLexer.CONTAINS_WORD);
-
-    test.run("$filter=containsabc").at(2).isText("containsabc")
-    .isType(UriLexer.ODATAIDENTIFIER); // test that this is a ODI
-
-    test.run("$filter=startswith(").at(2).isText("startswith(").isType(UriLexer.STARTSWITH_WORD);
-    test.run("$filter=endswith(").at(2).isText("endswith(").isType(UriLexer.ENDSWITH_WORD);
-    test.run("$filter=length(").at(2).isText("length(").isType(UriLexer.LENGTH_WORD);
-    test.run("$filter=indexof(").at(2).isText("indexof(").isType(UriLexer.INDEXOF_WORD);
-    test.run("$filter=substring(").at(2).isText("substring(").isType(UriLexer.SUBSTRING_WORD);
-    test.run("$filter=tolower(").at(2).isText("tolower(").isType(UriLexer.TOLOWER_WORD);
-    test.run("$filter=toupper(").at(2).isText("toupper(").isType(UriLexer.TOUPPER_WORD);
-    test.run("$filter=trim(").at(2).isText("trim(").isType(UriLexer.TRIM_WORD);
-    test.run("$filter=concat(").at(2).isText("concat(").isType(UriLexer.CONCAT_WORD);
 
+  @Test
+  public void queryExpressions() {
+    test.run("$it").has(TokenKind.IT).isText("$it");
+
+    test.run("$filter=contains(").has(TokenKind.FILTER, TokenKind.EQ, TokenKind.ContainsMethod).isText("contains(");
+
+    test.run("$filter=containsabc").has(TokenKind.FILTER, TokenKind.EQ, TokenKind.ODataIdentifier)
+        .isText("containsabc");
+
+    test.run("$filter=startswith(").has(TokenKind.FILTER, TokenKind.EQ, TokenKind.StartswithMethod)
+        .isText("startswith(");
+    test.run("$filter=endswith(").has(TokenKind.FILTER, TokenKind.EQ, TokenKind.EndswithMethod).isText("endswith(");
+    test.run("$filter=length(").has(TokenKind.FILTER, TokenKind.EQ, TokenKind.LengthMethod).isText("length(");
+    test.run("$filter=indexof(").has(TokenKind.FILTER, TokenKind.EQ, TokenKind.IndexofMethod).isText("indexof(");
+    test.run("$filter=substring(").has(TokenKind.FILTER, TokenKind.EQ, TokenKind.SubstringMethod).isText("substring(");
+    test.run("$filter=tolower(").has(TokenKind.FILTER, TokenKind.EQ, TokenKind.TolowerMethod).isText("tolower(");
+    test.run("$filter=toupper(").has(TokenKind.FILTER, TokenKind.EQ, TokenKind.ToupperMethod).isText("toupper(");
+    test.run("$filter=trim(").has(TokenKind.FILTER, TokenKind.EQ, TokenKind.TrimMethod).isText("trim(");
+    test.run("$filter=concat(").has(TokenKind.FILTER, TokenKind.EQ, TokenKind.ConcatMethod).isText("concat(");
   }
 
-  // ;------------------------------------------------------------------------------
-  // ; 7. Literal Data Values
-  // ;------------------------------------------------------------------------------
-
   @Test
-  public void testLiteralDataValues() {
-    test.globalMode(Lexer.DEFAULT_MODE);
+  public void literalDataValues() {
     // null
-    test.run("null").isInput().isType(UriLexer.NULLVALUE);
+    test.run("null").has(TokenKind.NULL).isInput();
 
     // binary
-    test.run("binary'ABCD'").isInput().isType(UriLexer.BINARY);
-    test.run("BiNaRy'ABCD'").isInput().isType(UriLexer.BINARY);
+    test.run("binary'ABCD'").has(TokenKind.BinaryValue).isInput();
+    test.run("BiNaRy'ABCD'").has(TokenKind.BinaryValue).isInput();
 
     // boolean
-    test.run("true").isInput().isType(UriLexer.TRUE);
-    test.run("false").isInput().isType(UriLexer.FALSE);
-    test.run("TrUe").isInput().isType(UriLexer.BOOLEAN);
-    test.run("FaLsE").isInput().isType(UriLexer.BOOLEAN);
+    test.run("true").has(TokenKind.BooleanValue).isInput();
+    test.run("false").has(TokenKind.BooleanValue).isInput();
+    test.run("TrUe").has(TokenKind.BooleanValue).isInput();
+    test.run("FaLsE").has(TokenKind.BooleanValue).isInput();
 
     // Lexer rule INT
-    test.run("123").isInput().isType(UriLexer.INT);
-    test.run("123456789").isInput().isType(UriLexer.INT);
-    test.run("+123").isInput().isType(UriLexer.INT);
-    test.run("+123456789").isInput().isType(UriLexer.INT);
-    test.run("-123").isInput().isType(UriLexer.INT);
-    test.run("-123456789").isInput().isType(UriLexer.INT);
+    test.run("123").has(TokenKind.IntegerValue).isInput();
+    test.run("123456789").has(TokenKind.IntegerValue).isInput();
+    test.run("+123").has(TokenKind.IntegerValue).isInput();
+    test.run("+123456789").has(TokenKind.IntegerValue).isInput();
+    test.run("-123").has(TokenKind.IntegerValue).isInput();
+    test.run("-123456789").has(TokenKind.IntegerValue).isInput();
 
     // Lexer rule DECIMAL
-    test.run("0.1").isInput().isType(UriLexer.DECIMAL);
-    test.run("1.1").isInput().isType(UriLexer.DECIMAL);
-    test.run("+0.1").isInput().isType(UriLexer.DECIMAL);
-    test.run("+1.1").isInput().isType(UriLexer.DECIMAL);
-    test.run("-0.1").isInput().isType(UriLexer.DECIMAL);
-    test.run("-1.1").isInput().isType(UriLexer.DECIMAL);
+    test.run("0.1").has(TokenKind.DecimalValue).isInput();
+    test.run("1.1").has(TokenKind.DecimalValue).isInput();
+    test.run("+0.1").has(TokenKind.DecimalValue).isInput();
+    test.run("+1.1").has(TokenKind.DecimalValue).isInput();
+    test.run("-0.1").has(TokenKind.DecimalValue).isInput();
+    test.run("-1.1").has(TokenKind.DecimalValue).isInput();
 
     // Lexer rule EXP
-    test.run("1.1e+1").isInput().isType(UriLexer.DECIMAL);
-    test.run("1.1e-1").isInput().isType(UriLexer.DECIMAL);
+    test.run("1.1e+1").has(TokenKind.DoubleValue).isInput();
+    test.run("1.1e-1").has(TokenKind.DoubleValue).isInput();
 
-    test.run("NaN").isInput().isType(UriLexer.NANINFINITY);
-    test.run("-INF").isInput().isType(UriLexer.NANINFINITY);
-    test.run("INF").isInput().isType(UriLexer.NANINFINITY);
+    test.run("NaN").has(TokenKind.DoubleValue).isInput();
+    test.run("-INF").has(TokenKind.DoubleValue).isInput();
+    test.run("INF").has(TokenKind.DoubleValue).isInput();
 
     // Lexer rule GUID
-    test.run("1234ABCD-12AB-23CD-45EF-123456780ABC").isInput().isType(UriLexer.GUID);
-    test.run("1234ABCD-12AB-23CD-45EF-123456780ABC").isInput().isType(UriLexer.GUID);
+    test.run("1234ABCD-12AB-23CD-45EF-123456780ABC").has(TokenKind.GuidValue).isInput();
+    test.run("1234ABCD-12AB-23CD-45EF-123456780ABC").has(TokenKind.GuidValue).isInput();
 
     // Lexer rule DATE
-    test.run("2013-11-15").isInput().isType(UriLexer.DATE);
+    test.run("2013-11-15").has(TokenKind.DateValue).isInput();
 
     // Lexer rule DATETIMEOFFSET
-    test.run("2013-11-15T13:35Z").isInput().isType(UriLexer.DATETIMEOFFSET);
-    test.run("2013-11-15T13:35:10Z").isInput().isType(UriLexer.DATETIMEOFFSET);
-    test.run("2013-11-15T13:35:10.1234Z").isInput().isType(UriLexer.DATETIMEOFFSET);
+    test.run("2013-11-15T13:35Z").has(TokenKind.DateTimeOffsetValue).isInput();
+    test.run("2013-11-15T13:35:10Z").has(TokenKind.DateTimeOffsetValue).isInput();
+    test.run("2013-11-15T13:35:10.1234Z").has(TokenKind.DateTimeOffsetValue).isInput();
 
-    test.run("2013-11-15T13:35:10.1234+01:30").isInput().isType(UriLexer.DATETIMEOFFSET);
-    test.run("2013-11-15T13:35:10.1234-01:12").isInput().isType(UriLexer.DATETIMEOFFSET);
+    test.run("2013-11-15T13:35:10.1234+01:30").has(TokenKind.DateTimeOffsetValue).isInput();
+    test.run("2013-11-15T13:35:10.1234-01:12").has(TokenKind.DateTimeOffsetValue).isInput();
 
-    test.run("2013-11-15T13:35Z").isInput().isType(UriLexer.DATETIMEOFFSET);
+    test.run("2013-11-15T13:35Z").has(TokenKind.DateTimeOffsetValue).isInput();
 
     // Lexer rule DURATION
-    test.run("duration'PT67S'").isInput().isType(UriLexer.DURATION);
-    test.run("duration'PT67.89S'").isInput().isType(UriLexer.DURATION);
-
-    test.run("duration'PT5M'").isInput().isType(UriLexer.DURATION);
-    test.run("duration'PT5M67S'").isInput().isType(UriLexer.DURATION);
-    test.run("duration'PT5M67.89S'").isInput().isType(UriLexer.DURATION);
-
-    test.run("duration'PT4H'").isInput().isType(UriLexer.DURATION);
-    test.run("duration'PT4H67S'").isInput().isType(UriLexer.DURATION);
-    test.run("duration'PT4H67.89S'").isInput().isType(UriLexer.DURATION);
-    test.run("duration'PT4H5M'").isInput().isType(UriLexer.DURATION);
-    test.run("duration'PT4H5M67S'").isInput().isType(UriLexer.DURATION);
-    test.run("duration'PT4H5M67.89S'").isInput().isType(UriLexer.DURATION);
-
-    test.run("duration'P3D'");
-    test.run("duration'P3DT67S'").isInput().isType(UriLexer.DURATION);
-    test.run("duration'P3DT67.89S'").isInput().isType(UriLexer.DURATION);
-    test.run("duration'P3DT5M'").isInput().isType(UriLexer.DURATION);
-    test.run("duration'P3DT5M67S'").isInput().isType(UriLexer.DURATION);
-    test.run("duration'P3DT5M67.89S'").isInput().isType(UriLexer.DURATION);
-    test.run("duration'P3DT4H'").isInput().isType(UriLexer.DURATION);
-    test.run("duration'P3DT4H67S'").isInput().isType(UriLexer.DURATION);
-    test.run("duration'P3DT4H67.89S'").isInput().isType(UriLexer.DURATION);
-    test.run("duration'P3DT4H5M'").isInput().isType(UriLexer.DURATION);
-    test.run("duration'P3DT4H5M67S'").isInput().isType(UriLexer.DURATION);
-    test.run("duration'P3DT4H5M67.89S'").isInput().isType(UriLexer.DURATION);
-
-    test.run("DuRaTiOn'P3DT4H5M67.89S'").isInput().isType(UriLexer.DURATION);
-    test.run("DuRaTiOn'-P3DT4H5M67.89S'").isInput().isType(UriLexer.DURATION);
-
-    test.run("20:00").isInput().isType(UriLexer.TIMEOFDAY);
-    test.run("20:15:01").isInput().isType(UriLexer.TIMEOFDAY);
-    test.run("20:15:01.02").isInput().isType(UriLexer.TIMEOFDAY);
-
-    test.run("20:15:01.02").isInput().isType(UriLexer.TIMEOFDAY);
+    test.run("duration'PT67S'").has(TokenKind.DurationValue).isInput();
+    test.run("duration'PT67.89S'").has(TokenKind.DurationValue).isInput();
+
+    test.run("duration'PT5M'").has(TokenKind.DurationValue).isInput();
+    test.run("duration'PT5M67S'").has(TokenKind.DurationValue).isInput();
+    test.run("duration'PT5M67.89S'").has(TokenKind.DurationValue).isInput();
+
+    test.run("duration'PT4H'").has(TokenKind.DurationValue).isInput();
+    test.run("duration'PT4H67S'").has(TokenKind.DurationValue).isInput();
+    test.run("duration'PT4H67.89S'").has(TokenKind.DurationValue).isInput();
+    test.run("duration'PT4H5M'").has(TokenKind.DurationValue).isInput();
+    test.run("duration'PT4H5M67S'").has(TokenKind.DurationValue).isInput();
+    test.run("duration'PT4H5M67.89S'").has(TokenKind.DurationValue).isInput();
+
+    test.run("duration'P3D'").has(TokenKind.DurationValue).isInput();
+    test.run("duration'P3DT67S'").has(TokenKind.DurationValue).isInput();
+    test.run("duration'P3DT67.89S'").has(TokenKind.DurationValue).isInput();
+    test.run("duration'P3DT5M'").has(TokenKind.DurationValue).isInput();
+    test.run("duration'P3DT5M67S'").has(TokenKind.DurationValue).isInput();
+    test.run("duration'P3DT5M67.89S'").has(TokenKind.DurationValue).isInput();
+    test.run("duration'P3DT4H'").has(TokenKind.DurationValue).isInput();
+    test.run("duration'P3DT4H67S'").has(TokenKind.DurationValue).isInput();
+    test.run("duration'P3DT4H67.89S'").has(TokenKind.DurationValue).isInput();
+    test.run("duration'P3DT4H5M'").has(TokenKind.DurationValue).isInput();
+    test.run("duration'P3DT4H5M67S'").has(TokenKind.DurationValue).isInput();
+    test.run("duration'P3DT4H5M67.89S'").has(TokenKind.DurationValue).isInput();
+
+    test.run("DuRaTiOn'P3DT4H5M67.89S'").has(TokenKind.DurationValue).isInput();
+    test.run("DuRaTiOn'-P3DT4H5M67.89S'").has(TokenKind.DurationValue).isInput();
+
+    test.run("20:00").has(TokenKind.TimeOfDayValue).isInput();
+    test.run("20:15:01").has(TokenKind.TimeOfDayValue).isInput();
+    test.run("20:15:01.02").has(TokenKind.TimeOfDayValue).isInput();
+
+    test.run("20:15:01.02").has(TokenKind.TimeOfDayValue).isInput();
 
     // String
-    test.run("'ABC'").isText("'ABC'").isType(UriLexer.STRING);
-    test.run("'A%20C'").isInput().isType(UriLexer.STRING);
-    test.run("'%20%20%20ABC'").isInput().isType(UriLexer.STRING);
-
+    test.run("'ABC'").has(TokenKind.StringValue).isInput();
+    test.run("'A%20C'").has(TokenKind.StringValue).isInput();
+    test.run("'%20%20%20ABC'").has(TokenKind.StringValue).isInput();
   }
 
   @Test
-  public void testDelims() {
-    String reserved = "/";
-    test.globalMode(UriLexer.MODE_QUERY);
+  public void delims() {
+    final String reserved = "/";
     // Test lexer rule UNRESERVED
-    test.run("$format=A/" + cUNRESERVED).isAllInput().isType(UriLexer.FORMAT);
-    test.run("$format=A/" + cUNRESERVED + reserved).isType(UriLexer.FORMAT).at(4).isText(cUNRESERVED);
+//    test.run("$format=A/" + cUNRESERVED).has(TokenKind.FORMAT).isInput();
+//    test.run("$format=A/" + cUNRESERVED + reserved).has(TokenKind.FORMAT).isText(cUNRESERVED);
     // Test lexer rule PCT_ENCODED
-    test.run("$format=A/" + cPCT_ENCODED).isAllInput().isType(UriLexer.FORMAT);
-    test.run("$format=A/" + cPCT_ENCODED + reserved).isType(UriLexer.FORMAT).at(4).isText(cPCT_ENCODED);
+//    test.run("$format=A/" + cPCT_ENCODED).has(TokenKind.FORMAT).isInput();
+//    test.run("$format=A/" + cPCT_ENCODED + reserved).has(TokenKind.FORMAT).isText(cPCT_ENCODED);
     // Test lexer rule SUB_DELIMS
-    test.run("$format=A/" + cSUB_DELIMS).isAllInput().isType(UriLexer.FORMAT);
-    test.run("$format=A/" + cSUB_DELIMS + reserved).isType(UriLexer.FORMAT).at(4).isText("$");
+//    test.run("$format=A/" + cSUB_DELIMS).has(TokenKind.FORMAT).isInput();
+//    test.run("$format=A/" + cSUB_DELIMS + reserved).has(TokenKind.FORMAT).isText("$");
     // Test lexer rule PCHAR rest
-    test.run("$format=A/:@").isAllText("$format=A/:@").isType(UriLexer.FORMAT);
-    test.run("$format=A/:@" + reserved).isType(UriLexer.FORMAT).at(4).isText(":@");
+//    test.run("$format=A/:@").has(TokenKind.FORMAT).isInput();
+//    test.run("$format=A/:@" + reserved).has(TokenKind.FORMAT).isText(":@");
     // Test lexer rule PCHAR all
-    test.run("$format=" + cPCHAR + "/" + cPCHAR).isAllInput().isType(UriLexer.FORMAT);
-
+//    test.run("$format=" + cPCHAR + "/" + cPCHAR).has(TokenKind.FORMAT).isInput();
   }
 
+  public class TokenValidator {
+
+    private String input = null;
+    private UriTokenizer tokenizer = null;
+    private String curText = null;
+
+    public TokenValidator run(final String uri) {
+      input = uri;
+      tokenizer = new UriTokenizer(uri);
+      curText = "";
+      return this;
+    }
+
+    public TokenValidator has(final TokenKind... expected) {
+      for (final TokenKind kind : expected) {
+        assertTrue(tokenizer.next(kind));
+        curText += tokenizer.getText();
+      }
+      return this;
+    }
+
+    public TokenValidator isText(final String expected) {
+      assertEquals(expected, tokenizer.getText());
+      return this;
+    }
+
+    public TokenValidator isInput() {
+      assertEquals(input, curText);
+      assertTrue(tokenizer.next(TokenKind.EOF));
+      return this;
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8925274c/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestUriParserImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestUriParserImpl.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestUriParserImpl.java
index 8790766..dd517f9 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestUriParserImpl.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestUriParserImpl.java
@@ -27,7 +27,7 @@ import org.apache.olingo.server.api.edmx.EdmxReference;
 import org.apache.olingo.server.api.uri.UriInfoKind;
 import org.apache.olingo.server.api.uri.UriResourceKind;
 import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind;
-import org.apache.olingo.server.core.uri.parser.UriParserSyntaxException;
+import org.apache.olingo.server.core.uri.parser.UriParserSemanticException;
 import org.apache.olingo.server.core.uri.testutil.FilterValidator;
 import org.apache.olingo.server.core.uri.testutil.ResourceValidator;
 import org.apache.olingo.server.core.uri.testutil.TestUriValidator;
@@ -67,8 +67,7 @@ public class TestUriParserImpl {
       + "," + PropertyDateTimeOffset + "," + PropertyDuration + "," + PropertyGuid + "," + PropertyTimeOfDay;
 
   @Test
-  public void testBoundFunctionImport_VarParameters() {
-
+  public void boundFunctionImport_VarParameters() {
     // no input
     testRes.run("ESKeyNav(1)/olingo.odata.test1.BFCETKeyNavRTETKeyNav()")
     .at(0).isUriPathInfoKind(UriResourceKind.entitySet)
@@ -89,9 +88,8 @@ public class TestUriParserImpl {
   }
 
   @Test
-  public void testFunctionBound_varReturnType() {
-
-    String esTwoKeyNav = "ESTwoKeyNav(PropertyInt16=1,PropertyString='ABC')";
+  public void functionBound_varReturnType() {
+    final String esTwoKeyNav = "ESTwoKeyNav(PropertyInt16=1,PropertyString='ABC')";
 
     // returning primitive
     testRes.run("ESTwoKeyNav/olingo.odata.test1.BFCESTwoKeyNavRTString()")
@@ -151,8 +149,7 @@ public class TestUriParserImpl {
   }
 
   @Test
-  public void runActionImport_VarReturnType() {
-
+  public void actionImport_VarReturnType() {
     testRes.run(ContainerProvider.AIRT_STRING).isKind(UriInfoKind.resource)
     .first()
     .isActionImport(ContainerProvider.AIRT_STRING)
@@ -189,7 +186,6 @@ public class TestUriParserImpl {
 
   @Test
   public void count() {
-
     // count entity set
     testRes.run("ESAllPrim/$count")
     .at(0)
@@ -216,7 +212,7 @@ public class TestUriParserImpl {
   }
 
   @Test
-  public void runCrossJoin() throws Exception {
+  public void crossJoin() throws Exception {
     testUri.run("$crossjoin(ESAllKey)")
     .isKind(UriInfoKind.crossjoin)
     .isCrossJoinEntityList(Arrays.asList("ESAllKey"));
@@ -226,29 +222,15 @@ public class TestUriParserImpl {
     .isCrossJoinEntityList(Arrays.asList("ESAllKey", "ESTwoPrim"));
   }
 
-  @Test(expected = UriValidationException.class)
-  public void testEntityFailOnValidation1() throws Exception {
+  @Test
+  public void entityFailOnValidation() throws Exception {
     // simple entity set; with qualifiedentityTypeName; with filter
-    testUri.run("$entity/olingo.odata.test1.ETTwoPrim", "$filter=PropertyInt16 eq 123&$id=ESAllKey")
-    .isIdText("ESAllKey")
-    .goFilter().is("<<PropertyInt16> eq <123>>");
-  }
-
-  @Test(expected = UriParserSyntaxException.class)
-  public void testEntityFailOnValidation2() throws Exception {
-    // simple entity set; with qualifiedentityTypeName; with 2xformat(before and after), expand, filter
-    testUri.run("$entity/olingo.odata.test1.ETTwoPrim",
-        "$format=xml&$expand=*&abc=123&$id=ESBase&xyz=987&$filter=PropertyInt16 eq 123&$format=atom&$select=*")
-        .isFormatText("atom")
-        .isCustomParameter(0, "abc", "123")
-        .isIdText("ESBase")
-        .isCustomParameter(1, "xyz", "987")
-        .isSelectItemStar(0);
+    testUri.runEx("$entity/olingo.odata.test1.ETTwoPrim", "$filter=PropertyInt16 eq 123&$id=ESAllKey")
+        .isExValidation(UriValidationException.MessageKeys.SYSTEM_QUERY_OPTION_NOT_ALLOWED);
   }
 
   @Test
-  public void testEntity() throws Exception {
-
+  public void entity() throws Exception {
     // simple entity set
     testUri.run("$entity", "$id=ESAllPrim").isKind(UriInfoKind.entityId)
     .isKind(UriInfoKind.entityId)
@@ -311,14 +293,11 @@ public class TestUriParserImpl {
     .isKind(UriInfoKind.entityId)
     .isEntityType(EntityTypeProvider.nameETBase)
     .isIdText("ESTwoPrim")
-    .isExpandText("*")
     .goExpand().first().isSegmentStar();
-
   }
 
   @Test
   public void entitySet() throws Exception {
-
     // plain entity set
     testRes.run("ESAllPrim")
     .isEntitySet("ESAllPrim")
@@ -342,7 +321,7 @@ public class TestUriParserImpl {
     .isKeyPredicate(1, "PropertyString", "'ABC'");
 
     // with all keys
-    testRes.run("ESAllKey(" + encode(allKeys) + ")")
+    testRes.run("ESAllKey(" + allKeys + ")")
     .isEntitySet("ESAllKey")
     .isKeyPredicate(0, "PropertyString", "'ABC'")
     .isKeyPredicate(1, "PropertyInt16", "1")
@@ -360,10 +339,7 @@ public class TestUriParserImpl {
   }
 
   @Test
-  public void testEntitySet_NavigationProperty() {
-
-    // plain entity set ...
-
+  public void entitySet_NavigationProperty() {
     // with navigation property
     testRes.run("ESKeyNav(1)/NavPropertyETTwoKeyNavOne")
     .at(0)
@@ -467,10 +443,7 @@ public class TestUriParserImpl {
   }
 
   @Test
-  public void testEntitySet_Property() {
-
-    // plain entity set ...
-
+  public void entitySet_Property() {
     // with property
     testRes.run("ESAllPrim(1)/PropertyString")
     .at(0)
@@ -499,8 +472,7 @@ public class TestUriParserImpl {
   }
 
   @Test
-  public void testEntitySet_TypeFilter() {
-
+  public void entitySet_TypeFilter() {
     // filter
     testRes.run("ESTwoPrim/olingo.odata.test1.ETBase")
     .at(0)
@@ -556,57 +528,53 @@ public class TestUriParserImpl {
     .at(1)
     .isPrimitiveProperty("AdditionalPropertyString_5", PropertyProvider.nameString, false)
     .isType(PropertyProvider.nameString);
-
   }
 
   @Test
   public void unary() throws Exception {
-    testFilter.runOnETAllPrim("not PropertyBoolean").isCompr("<not <PropertyBoolean>>");
-    testFilter.runOnETAllPrim("-PropertyInt16 eq PropertyInt16").isCompr("<<- <PropertyInt16>> eq <PropertyInt16>>");
+    testFilter.runOnETAllPrim("not PropertyBoolean").is("<not <PropertyBoolean>>");
+    testFilter.runOnETAllPrim("-PropertyInt16 eq PropertyInt16").is("<<- <PropertyInt16>> eq <PropertyInt16>>");
   }
 
-  // TODO: Use correct types.
   @Test
-  @Ignore
   public void filterComplexMixedPriority() throws Exception {
-    testFilter.runOnETAllPrim("PropertyInt16 or PropertyInt32 and PropertyInt64")
-        .isCompr("<<PropertyInt16> or <<PropertyInt32> and <PropertyInt64>>>");
-    testFilter.runOnETAllPrim("PropertyInt16 or PropertyInt32 and PropertyInt64 eq PropertyByte")
-        .isCompr("<<PropertyInt16> or <<PropertyInt32> and <<PropertyInt64> eq <PropertyByte>>>>");
-    testFilter.runOnETAllPrim("PropertyInt16 or PropertyInt32 eq PropertyInt64 and PropertyByte")
-        .isCompr("<<PropertyInt16> or <<<PropertyInt32> eq <PropertyInt64>> and <PropertyByte>>>");
-    testFilter.runOnETAllPrim("PropertyInt16 or PropertyInt32 eq PropertyInt64 and PropertyByte eq PropertySByte")
-        .isCompr("<<PropertyInt16> or <<<PropertyInt32> eq <PropertyInt64>> "
+    testFilter.runOnETAllPrim("PropertyBoolean or true and false")
+        .is("<<PropertyBoolean> or <<true> and <false>>>");
+    testFilter.runOnETAllPrim("PropertyBoolean or true and PropertyInt64 eq PropertyByte")
+        .is("<<PropertyBoolean> or <<true> and <<PropertyInt64> eq <PropertyByte>>>>");
+    testFilter.runOnETAllPrim("PropertyBoolean or PropertyInt32 eq PropertyInt64 and true")
+        .is("<<PropertyBoolean> or <<<PropertyInt32> eq <PropertyInt64>> and <true>>>");
+    testFilter.runOnETAllPrim("PropertyBoolean or PropertyInt32 eq PropertyInt64 and PropertyByte eq PropertySByte")
+        .is("<<PropertyBoolean> or <<<PropertyInt32> eq <PropertyInt64>> "
             + "and <<PropertyByte> eq <PropertySByte>>>>");
-    testFilter.runOnETAllPrim("PropertyInt16 eq PropertyInt32 or PropertyInt64 and PropertyByte")
-        .isCompr("<<<PropertyInt16> eq <PropertyInt32>> or <<PropertyInt64> and <PropertyByte>>>");
-    testFilter.runOnETAllPrim("PropertyInt16 eq PropertyInt32 or PropertyInt64 and PropertyByte eq PropertySByte")
-        .isCompr("<<<PropertyInt16> eq <PropertyInt32>> "
-            + "or <<PropertyInt64> and <<PropertyByte> eq <PropertySByte>>>>");
-    testFilter.runOnETAllPrim("PropertyInt16 eq PropertyInt32 or PropertyInt64 eq PropertyByte and PropertySByte")
-        .isCompr("<<<PropertyInt16> eq <PropertyInt32>> "
-            + "or <<<PropertyInt64> eq <PropertyByte>> and <PropertySByte>>>");
+    testFilter.runOnETAllPrim("PropertyInt16 eq PropertyInt32 or PropertyBoolean and true")
+        .is("<<<PropertyInt16> eq <PropertyInt32>> or <<PropertyBoolean> and <true>>>");
+    testFilter.runOnETAllPrim("PropertyInt16 eq PropertyInt32 or PropertyBoolean and PropertyByte eq PropertySByte")
+        .is("<<<PropertyInt16> eq <PropertyInt32>> "
+            + "or <<PropertyBoolean> and <<PropertyByte> eq <PropertySByte>>>>");
+    testFilter.runOnETAllPrim("PropertyInt16 eq PropertyInt32 or PropertyInt64 eq PropertyByte and PropertyBoolean")
+        .is("<<<PropertyInt16> eq <PropertyInt32>> "
+            + "or <<<PropertyInt64> eq <PropertyByte>> and <PropertyBoolean>>>");
     testFilter.runOnETAllPrim("PropertyInt16 eq PropertyInt32 or PropertyInt64 eq PropertyByte "
         + "and PropertySByte eq PropertyDecimal")
-        .isCompr("<<<PropertyInt16> eq <PropertyInt32>> or <<<PropertyInt64> eq <PropertyByte>> "
+        .is("<<<PropertyInt16> eq <PropertyInt32>> or <<<PropertyInt64> eq <PropertyByte>> "
             + "and <<PropertySByte> eq <PropertyDecimal>>>>");
   }
 
   @Test
   public void filterSimpleSameBinaryBinaryBinaryPriority() throws Exception {
-    testFilter.runOnETAllPrim("1 add 2 add 3 add 4").isCompr("<<< <1> add   <2>> add  <3>>  add <4>>");
-    testFilter.runOnETAllPrim("1 add 2 add 3 div 4").isCompr("<<  <1> add   <2>> add <<3>   div <4>>>");
-    testFilter.runOnETAllPrim("1 add 2 div 3 add 4").isCompr("<<  <1> add  <<2>  div  <3>>> add <4>>");
-    testFilter.runOnETAllPrim("1 add 2 div 3 div 4").isCompr("<   <1> add <<<2>  div  <3>>  div <4>>>");
-    testFilter.runOnETAllPrim("1 div 2 add 3 add 4").isCompr("<<< <1> div   <2>> add  <3>>  add <4>>");
-    testFilter.runOnETAllPrim("1 div 2 add 3 div 4").isCompr("<<  <1> div   <2>> add <<3>   div <4>>>");
-    testFilter.runOnETAllPrim("1 div 2 div 3 add 4").isCompr("<<< <1> div   <2>> div  <3>>  add <4>>");
-    testFilter.runOnETAllPrim("1 div 2 div 3 div 4").isCompr("<<< <1> div   <2>> div  <3>>  div <4>>");
+    testFilter.runOnETAllPrim("1 add 2 add 3 add 4 ge 0").isCompr("<<<< <1> add   <2>> add  <3>>  add <4>> ge <0>>");
+    testFilter.runOnETAllPrim("1 add 2 add 3 div 4 ge 0").isCompr("<<<  <1> add   <2>> add <<3>   div <4>>> ge <0>>");
+    testFilter.runOnETAllPrim("1 add 2 div 3 add 4 ge 0").isCompr("<<<  <1> add  <<2>  div  <3>>> add <4>> ge <0>>");
+    testFilter.runOnETAllPrim("1 add 2 div 3 div 4 ge 0").isCompr("<<   <1> add <<<2>  div  <3>>  div <4>>> ge <0>>");
+    testFilter.runOnETAllPrim("1 div 2 add 3 add 4 ge 0").isCompr("<<<< <1> div   <2>> add  <3>>  add <4>> ge <0>>");
+    testFilter.runOnETAllPrim("1 div 2 add 3 div 4 ge 0").isCompr("<<<  <1> div   <2>> add <<3>   div <4>>> ge <0>>");
+    testFilter.runOnETAllPrim("1 div 2 div 3 add 4 ge 0").isCompr("<<<< <1> div   <2>> div  <3>>  add <4>> ge <0>>");
+    testFilter.runOnETAllPrim("1 div 2 div 3 div 4 ge 0").isCompr("<<<< <1> div   <2>> div  <3>>  div <4>> ge <0>>");
   }
 
   @Test
-  public void testFunctionImport_VarParameters() {
-
+  public void functionImport_VarParameters() {
     // no input
     testRes.run("FINRTInt16()")
     .isFunctionImport("FINRTInt16")
@@ -627,7 +595,7 @@ public class TestUriParserImpl {
   }
 
   @Test
-  public void testFunctionImport_VarReturning() {
+  public void functionImport_VarReturning() {
     // returning primitive
     testRes.run("FINRTInt16()")
     .isFunctionImport("FINRTInt16")
@@ -666,8 +634,7 @@ public class TestUriParserImpl {
   }
 
   @Test
-  public void testFunctionImportChain() {
-
+  public void functionImportChain() {
     // test chain; returning single complex
     testRes.run("FICRTCTAllPrimTwoParam(ParameterString='ABC',ParameterInt16=1)/PropertyInt16")
     .at(0)
@@ -710,12 +677,10 @@ public class TestUriParserImpl {
     .isKeyPredicate(1, "PropertyString", "'ABC'")
     .at(1)
     .isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
-
   }
 
   @Test
-  public void testMetaData() throws Exception {
-
+  public void metaData() throws Exception {
     // Parsing the fragment may be used if a uri has to be parsed on the consumer side.
     // On the producer side this feature is currently not supported, so the context fragment
     // part is only available as text.
@@ -879,12 +844,12 @@ public class TestUriParserImpl {
   }
 
   @Test
-  public void testRef() throws Exception {
+  public void ref() throws Exception {
     testUri.run("ESKeyNav(1)/NavPropertyETTwoKeyNavOne/$ref");
   }
 
   @Test
-  public void testSingleton() {
+  public void singleton() {
     // plain singleton
     testRes.run("SINav")
     .isSingleton("SINav")
@@ -892,10 +857,7 @@ public class TestUriParserImpl {
   }
 
   @Test
-  public void testNavigationProperty() {
-
-    // plain entity set ...
-
+  public void navigationProperty() {
     // with navigation property
     testRes.run("ESKeyNav(1)/NavPropertyETTwoKeyNavOne")
     .at(0).isEntitySet("ESKeyNav")
@@ -969,10 +931,7 @@ public class TestUriParserImpl {
   }
 
   @Test
-  public void testSingleton_Property() {
-
-    // plain singleton ...
-
+  public void singleton_Property() {
     // with property
     testRes.run("SINav/PropertyInt16")
     .at(0)
@@ -1002,72 +961,51 @@ public class TestUriParserImpl {
   }
 
   @Test
-  public void testValue() throws Exception {
+  public void value() throws Exception {
     testUri.run("ESAllPrim(1)/PropertyString/$value");
   }
 
-  @Test(expected = UriValidationException.class)
-  public void testMemberStartingWithCastFailOnValidation1() throws Exception {
+  @Test
+  public void memberStartingWithCastFailOnValidation1() throws Exception {
     // on EntityType entry
-    testUri.run("ESTwoKeyNav(ParameterInt16=1,PropertyString='ABC')",
+    testUri.runEx("ESTwoKeyNav(Property16=1,PropertyString='ABC')",
         "$filter=olingo.odata.test1.ETBaseTwoKeyNav/PropertyDate")
-        .goFilter().root().isMember()
-        .isMemberStartType(EntityTypeProvider.nameETBaseTwoKeyNav).goPath()
-        // .at(0)
-        // .isUriPathInfoKind(UriResourceKind.startingTypeFilter)
-        // .isType(EntityTypeProvider.nameETTwoKeyNav, false)
-        // .isTypeFilterOnEntry(EntityTypeProvider.nameETBaseTwoKeyNav)
-        .at(0).isType(PropertyProvider.nameDate);
+        .isExValidation(UriValidationException.MessageKeys.INVALID_KEY_PROPERTY);
   }
 
-  @Test(expected = UriValidationException.class)
-  public void testMemberStartingWithCastFailOnValidation2() throws Exception {
-    testUri.run("FICRTCTTwoPrimTwoParam(ParameterInt16=1,ParameterString='2')",
+  @Test
+  public void memberStartingWithCastFailOnValidation2() throws Exception {
+    testUri.runEx("FICRTCTTwoPrimTwoParam(ParameterInt16=1,ParameterString='2')",
         "$filter=olingo.odata.test1.CTBase/AdditionalPropString")
-        .goFilter().root().isMember()
-        .isMemberStartType(ComplexTypeProvider.nameCTBase).goPath()
-        // .at(0)
-        // .isUriPathInfoKind(UriResourceKind.startingTypeFilter)
-        // .isType(ComplexTypeProvider.nameCTTwoPrim, false)
-        // .isTypeFilterOnEntry(ComplexTypeProvider.nameCTBase)
-        .at(0).isType(PropertyProvider.nameString);
+        .isExSemantic(UriParserSemanticException.MessageKeys.TYPES_NOT_COMPATIBLE);
   }
 
   @Test
-  public void testMemberStartingWithCast() throws Exception {
-
+  public void memberStartingWithCast() throws Exception {
     // on EntityType collection
-    testUri.run("ESTwoKeyNav", "$filter=olingo.odata.test1.ETBaseTwoKeyNav/PropertyDate")
-    .goFilter().root().isMember()
+    testFilter.runOnETTwoKeyNav("olingo.odata.test1.ETBaseTwoKeyNav/PropertyDate eq null")
+    .left()
+    .isMember()
     .isMemberStartType(EntityTypeProvider.nameETBaseTwoKeyNav).goPath()
-    // .at(0)
-    // .isUriPathInfoKind(UriResourceKind.startingTypeFilter)
-    // .isType(EntityTypeProvider.nameETTwoKeyNav, true)
-    // .isTypeFilterOnCollection(EntityTypeProvider.nameETBaseTwoKeyNav)
     .at(0).isType(PropertyProvider.nameDate);
 
     // on Complex collection
     testUri.run("FICRTCollCTTwoPrimTwoParam(ParameterInt16=1,ParameterString='2')",
-        "$filter=olingo.odata.test1.CTBase/AdditionalPropString")
-        .goFilter().root().isMember()
+        "$filter=olingo.odata.test1.CTBase/AdditionalPropString eq null")
+        .goFilter().left().isMember()
         .isMemberStartType(ComplexTypeProvider.nameCTBase).goPath()
-        // .at(0)
-        // .isUriPathInfoKind(UriResourceKind.startingTypeFilter)
-        // .isType(ComplexTypeProvider.nameCTTwoPrim, true)
-        // .isTypeFilterOnCollection(ComplexTypeProvider.nameCTBase)
         .at(0).isType(PropertyProvider.nameString);
-
   }
 
   @Test
-  public void testComplexTypeCastFollowingAsCollection() throws Exception {
+  public void complexTypeCastFollowingAsCollection() throws Exception {
     testUri.run("FICRTCollCTTwoPrimTwoParam(ParameterInt16=1,ParameterString='2')/olingo.odata.test1.CTBase");
   }
 
   @Test
-  public void testAlias() throws Exception {
-    testUri.run("ESAllPrim", "$filter=PropertyInt16 eq @p1&@p1=1")
-    .goFilter().is("<<PropertyInt16> eq <@p1>>");
+  public void alias() throws Exception {
+    testFilter.runOnETAllPrim("PropertyInt16 eq @p1&@p1=1")
+        .is("<<PropertyInt16> eq <@p1>>");
   }
 
   @Test
@@ -1087,26 +1025,22 @@ public class TestUriParserImpl {
   @Test
   public void customQueryOption() throws Exception {
     testUri.run("ESTwoKeyNav", "custom")
-    .isCustomParameter(0, "custom", "");
+        .isCustomParameter(0, "custom", "");
     testUri.run("ESTwoKeyNav", "custom=ABC")
-    .isCustomParameter(0, "custom", "ABC");
+        .isCustomParameter(0, "custom", "ABC");
   }
 
   @Test
   @Ignore("Geo types are not supported yet.")
   public void geo() throws Exception {
     testFilter.runOnETAllPrim("geo.distance(PropertySByte,PropertySByte)")
-    .is("<geo.distance(<PropertySByte>,<PropertySByte>)>")
-    .isMethod(MethodKind.GEODISTANCE, 2);
+        .is("<geo.distance(<PropertySByte>,<PropertySByte>)>")
+        .isMethod(MethodKind.GEODISTANCE, 2);
     testFilter.runOnETAllPrim("geo.length(PropertySByte)")
-    .is("<geo.length(<PropertySByte>)>")
-    .isMethod(MethodKind.GEOLENGTH, 1);
+        .is("<geo.length(<PropertySByte>)>")
+        .isMethod(MethodKind.GEOLENGTH, 1);
     testFilter.runOnETAllPrim("geo.intersects(PropertySByte,PropertySByte)")
-    .is("<geo.intersects(<PropertySByte>,<PropertySByte>)>")
-    .isMethod(MethodKind.GEOINTERSECTS, 2);
-  }
-
-  private final String encode(final String uriPart) {
-    return uriPart.replaceAll(":", "%3A");
+        .is("<geo.intersects(<PropertySByte>,<PropertySByte>)>")
+        .isMethod(MethodKind.GEOINTERSECTS, 2);
   }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8925274c/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/ParserTest.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/ParserTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/ParserTest.java
index f54ad04..af523aa 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/ParserTest.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/parser/ParserTest.java
@@ -18,12 +18,18 @@
  */
 package org.apache.olingo.server.core.uri.parser;
 
+import java.util.Collections;
+
 import org.apache.olingo.commons.api.edm.Edm;
 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.EdmKeyPropertyRef;
 import org.apache.olingo.commons.api.edm.EdmNavigationProperty;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
+import org.apache.olingo.commons.api.edm.EdmProperty;
 import org.apache.olingo.commons.api.edm.FullQualifiedName;
+import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.uri.UriInfoKind;
 import org.apache.olingo.server.core.uri.testutil.TestUriValidator;
 import org.junit.Test;
@@ -33,17 +39,57 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 
 /**
- * All Tests which involves the <code>Parser</code> implementation
- * (and with that also the <code>UriParseTreeVisitor</code>).
+ * Tests of the <code>Parser</code> implementation that require mocking of the EDM.
  */
 public class ParserTest {
 
+  @Test
+  public void navPropertySameNameAsEntitySet() throws Exception {
+    final String namespace = "namespace";
+    final String entityTypeName = "ETNavProp";
+    final FullQualifiedName nameETNavProp = new FullQualifiedName(namespace, entityTypeName);
+    final String entitySetName = "ESNavProp";
+    final String keyPropertyName = "a";
+    EdmProperty keyProperty = Mockito.mock(EdmProperty.class);
+    Mockito.when(keyProperty.getType())
+        .thenReturn(OData.newInstance().createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Byte));
+    EdmKeyPropertyRef keyPropertyRef = Mockito.mock(EdmKeyPropertyRef.class);
+    Mockito.when(keyPropertyRef.getName()).thenReturn(keyPropertyName);
+    Mockito.when(keyPropertyRef.getProperty()).thenReturn(keyProperty);
+    EdmNavigationProperty navProperty = Mockito.mock(EdmNavigationProperty.class);
+    Mockito.when(navProperty.getName()).thenReturn(entitySetName);
+    Mockito.when(navProperty.isCollection()).thenReturn(true);
+    EdmEntityType entityType = Mockito.mock(EdmEntityType.class);
+    Mockito.when(entityType.getFullQualifiedName()).thenReturn(nameETNavProp);
+    Mockito.when(entityType.getKeyPredicateNames()).thenReturn(Collections.singletonList(keyPropertyName));
+    Mockito.when(entityType.getKeyPropertyRefs()).thenReturn(Collections.singletonList(keyPropertyRef));
+    Mockito.when(entityType.getNavigationProperty(entitySetName)).thenReturn(navProperty);
+    Mockito.when(navProperty.getType()).thenReturn(entityType);
+    EdmEntitySet entitySet = Mockito.mock(EdmEntitySet.class);
+    Mockito.when(entitySet.getName()).thenReturn(entitySetName);
+    Mockito.when(entitySet.getEntityType()).thenReturn(entityType);
+    EdmEntityContainer container = Mockito.mock(EdmEntityContainer.class);
+    Mockito.when(container.getEntitySet(entitySetName)).thenReturn(entitySet);
+    Edm mockedEdm = Mockito.mock(Edm.class);
+    Mockito.when(mockedEdm.getEntityContainer()).thenReturn(container);
+    new TestUriValidator().setEdm(mockedEdm)
+        .run("ESNavProp(1)/ESNavProp(2)/ESNavProp(3)/ESNavProp")
+        .goPath()
+        .at(0).isEntitySet(entitySetName)
+        .at(0).isKeyPredicate(0, keyPropertyName, "1")
+        .at(1).isNavProperty(entitySetName, nameETNavProp, false)
+        .at(1).isKeyPredicate(0, keyPropertyName, "2")
+        .at(2).isNavProperty(entitySetName, nameETNavProp, false)
+        .at(2).isKeyPredicate(0, keyPropertyName, "3")
+        .at(3).isNavProperty(entitySetName, nameETNavProp, true);
+  }
+
   /**
    * Test for EntitySet and NavigationProperty with same name defined in metadata.
    * (related to Olingo issue OLINGO-741)
    */
   @Test
-  public void parseEntitySetAndNavigationPropertyWithSameName() throws Exception {
+  public void expandNavigationPropertyWithSameNameAsEntitySet() throws Exception {
     TestUriValidator testUri = new TestUriValidator();
 
     Edm mockEdm = Mockito.mock(Edm.class);
@@ -60,7 +106,7 @@ public class ParserTest {
     Mockito.when(typeCategory.getNamespace()).thenReturn("NS");
     Mockito.when(esCategory.getEntityType()).thenReturn(typeCategory);
     Mockito.when(productsNavigation.getName()).thenReturn("Products");
-    Mockito.when(typeCategory.getProperty("Products")).thenReturn(productsNavigation);
+    Mockito.when(typeCategory.getNavigationProperty("Products")).thenReturn(productsNavigation);
     Mockito.when(container.getEntitySet("Category")).thenReturn(esCategory);
     Mockito.when(container.getEntitySet("Products")).thenReturn(esProduct);
     Mockito.when(productsType.getFullQualifiedName()).thenReturn(nameProducts);
@@ -122,7 +168,7 @@ public class ParserTest {
           .isType(new FullQualifiedName("NS", "Category"), false);
       fail("Expected exception was not thrown.");
     } catch (final UriParserException e) {
-      assertEquals("NavigationProperty 'Category' not found in type 'NS.Products'", e.getMessage());
+      assertEquals("Navigation Property 'Category' not found in type 'NS.Products'.", e.getMessage());
     }
   }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8925274c/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/ExpandValidator.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/ExpandValidator.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/ExpandValidator.java
index 5638227..35245b4 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/ExpandValidator.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/ExpandValidator.java
@@ -19,6 +19,7 @@
 package org.apache.olingo.server.core.uri.testutil;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -151,12 +152,6 @@ public class ExpandValidator implements TestValidator {
     return this;
   }
 
-  public ExpandValidator isSelectText(final String text) {
-    final QueryOption option = expandItem.getSelectOption();
-    assertEquals(text, option.getText());
-    return this;
-  }
-
   public ExpandValidator isSelectItemStar(final int index) {
     SelectOption select = expandItem.getSelectOption();
     SelectItem item = select.getSelectItems().get(index);
@@ -171,12 +166,6 @@ public class ExpandValidator implements TestValidator {
     return this;
   }
 
-  public ExpandValidator isFilterOptionText(final String text) {
-    QueryOption option = expandItem.getFilterOption();
-    assertEquals(text, option.getText());
-    return this;
-  }
-
   public ExpandValidator isFilterSerialized(final String serialized) {
     FilterOption filter = expandItem.getFilterOption();
 
@@ -201,7 +190,13 @@ public class ExpandValidator implements TestValidator {
   }
 
   public ExpandValidator isExpandStartType(final FullQualifiedName fullName) {
+    assertNotNull(expandItem.getStartTypeFilter());
     assertEquals(fullName, expandItem.getStartTypeFilter().getFullQualifiedName());
     return this;
   }
+
+  public ExpandValidator isSearchSerialized(final String serialized) {
+    assertEquals(serialized, expandItem.getSearchOption().getSearchExpression().toString());
+    return this;
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8925274c/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 0800dd0..161299c 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
@@ -46,13 +46,16 @@ import org.apache.olingo.server.api.uri.queryoption.expression.Member;
 import org.apache.olingo.server.api.uri.queryoption.expression.Method;
 import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind;
 import org.apache.olingo.server.api.uri.queryoption.expression.TypeLiteral;
+import org.apache.olingo.server.api.uri.queryoption.expression.Unary;
 import org.apache.olingo.server.core.uri.UriResourceFunctionImpl;
 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.parser.UriParserSemanticException;
 import org.apache.olingo.server.core.uri.parser.UriParserSyntaxException;
+import org.apache.olingo.server.core.uri.queryoption.expression.BinaryImpl;
 import org.apache.olingo.server.core.uri.queryoption.expression.MemberImpl;
 import org.apache.olingo.server.core.uri.queryoption.expression.MethodImpl;
+import org.apache.olingo.server.core.uri.queryoption.expression.UnaryImpl;
 import org.apache.olingo.server.core.uri.validator.UriValidationException;
 
 public class FilterValidator implements TestValidator {
@@ -127,7 +130,7 @@ public class FilterValidator implements TestValidator {
   }
 
   public FilterValidator runOrderByOnETTwoKeyNavEx(final String orderBy) throws UriParserException {
-    return runUriOrderByEx("ESTwoKeyNav", "$orderby=" + orderBy.trim());
+    return runUriEx("ESTwoKeyNav", "$orderby=" + orderBy.trim());
   }
 
   public FilterValidator runOnETTwoKeyNav(final String filter) throws UriParserException, UriValidationException {
@@ -225,19 +228,6 @@ public class FilterValidator implements TestValidator {
     return this;
   }
 
-  public FilterValidator runUriOrderByEx(final String path, final String query) {
-    exception = null;
-    try {
-      new Parser(edm, odata).parseUri(path, query, null);
-      fail("Expected exception not thrown.");
-    } catch (final UriParserException e) {
-      exception = e;
-    } catch (final UriValidationException e) {
-      exception = e;
-    }
-    return this;
-  }
-
   // --- Navigation ---
 
   public ExpandValidator goUpToExpandValidator() {
@@ -274,8 +264,8 @@ public class FilterValidator implements TestValidator {
   // --- Validation ---
 
   /**
-   * Validates the serialized filterTree against a given filterString
-   * The given expected filterString is compressed before to allow better readable code in the unit tests
+   * Validates the serialized filterTree against a given filterString.
+   * The given expected filterString is compressed before to allow better readable code in the unit tests.
    * @param toBeCompr
    * @return {@link FilterValidator}
    */
@@ -310,14 +300,19 @@ public class FilterValidator implements TestValidator {
     EdmType actualType = null;
 
     if (curExpression instanceof Member) {
-      Member member = (Member) curExpression;
-      actualType = member.getType();
+      actualType = ((Member) curExpression).getType();
     } else if (curExpression instanceof TypeLiteral) {
-      TypeLiteral typeLiteral = (TypeLiteral) curExpression;
-      actualType = typeLiteral.getType();
+      actualType = ((TypeLiteral) curExpression).getType();
     } else if (curExpression instanceof Literal) {
-      Literal typeLiteral = (Literal) curExpression;
-      actualType = typeLiteral.getType();
+      actualType = ((Literal) curExpression).getType();
+    } else if (curExpression instanceof Enumeration) {
+      actualType = ((Enumeration) curExpression).getType();
+    } else if (curExpression instanceof Unary) {
+      actualType = ((UnaryImpl) curExpression).getType();
+    } else if (curExpression instanceof Binary) {
+      actualType = ((BinaryImpl) curExpression).getType();
+    } else if (curExpression instanceof Method) {
+      actualType = ((MethodImpl) curExpression).getType();
     }
 
     if (actualType == null) {
@@ -349,7 +344,6 @@ public class FilterValidator implements TestValidator {
 
     curExpression = ((Binary) curExpression).getRightOperand();
     return this;
-
   }
 
   public FilterValidator isLiteral(final String literalText) {
@@ -361,9 +355,9 @@ public class FilterValidator implements TestValidator {
     assertEquals(literalText, actualLiteralText);
     return this;
   }
-  
-  public FilterValidator isLiteralType(EdmType edmType) {
-    if(!(curExpression instanceof Literal)) {
+
+  public FilterValidator isLiteralType(final EdmType edmType) {
+    if (!(curExpression instanceof Literal)) {
       fail("Current expression is not a literal");
     }
     
@@ -374,7 +368,7 @@ public class FilterValidator implements TestValidator {
   }
 
   public FilterValidator isNullLiteralType() {
-    if(!(curExpression instanceof Literal)) {
+    if (!(curExpression instanceof Literal)) {
       fail("Current expression is not a literal");
     }
 
@@ -495,12 +489,4 @@ public class FilterValidator implements TestValidator {
     assertEquals(messageKey, exception.getMessageKey());
     return this;
   }
-
-  public FilterValidator isNull() {
-    return isLiteral("null");
-  }
-
-  public FilterValidator isTrue() {
-    return isLiteral("true");
-  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8925274c/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 1dbe62b..fbce5c9 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
@@ -140,6 +140,20 @@ public class TestUriValidator implements TestValidator {
     return this;
   }
 
+  public TestUriValidator isSelectItemStar(final int index) {
+    final SelectOption select = uriInfo.getSelectOption();
+    SelectItem item = select.getSelectItems().get(index);
+    assertTrue(item.isStar());
+    return this;
+  }
+
+  public TestUriValidator isSelectItemAllOp(final int index, final FullQualifiedName fqn) {
+    final SelectOption select = uriInfo.getSelectOption();
+    SelectItem item = select.getSelectItems().get(index);
+    assertEquals(fqn, item.getAllOperationsInSchemaNameSpace());
+    return this;
+  }
+
   // Validation
   public TestUriValidator isKind(final UriInfoKind kind) {
     assertEquals(kind, uriInfo.getKind());
@@ -202,16 +216,6 @@ public class TestUriValidator implements TestValidator {
     return this;
   }
 
-  public TestUriValidator isExpandText(final String text) {
-    assertEquals(text, uriInfo.getExpandOption().getText());
-    return this;
-  }
-
-  public TestUriValidator isSelectText(final String text) {
-    assertEquals(text, uriInfo.getSelectOption().getText());
-    return this;
-  }
-
   public TestUriValidator isFormatText(final String text) {
     assertEquals(text, uriInfo.getFormatOption().getText());
     return this;
@@ -234,18 +238,4 @@ public class TestUriValidator implements TestValidator {
     assertEquals(fullName, uriInfo.getEntityTypeCast().getFullQualifiedName());
     return this;
   }
-
-  public TestUriValidator isSelectItemStar(final int index) {
-    final SelectOption select = uriInfo.getSelectOption();
-    SelectItem item = select.getSelectItems().get(index);
-    assertTrue(item.isStar());
-    return this;
-  }
-
-  public TestUriValidator isSelectItemAllOp(final int index, final FullQualifiedName fqn) {
-    final SelectOption select = uriInfo.getSelectOption();
-    SelectItem item = select.getSelectItems().get(index);
-    assertEquals(fqn, item.getAllOperationsInSchemaNameSpace());
-    return this;
-  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8925274c/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/TokenValidator.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/TokenValidator.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/TokenValidator.java
deleted file mode 100644
index 547c2ea..0000000
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/TokenValidator.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * 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.testutil;
-
-import static org.junit.Assert.assertEquals;
-
-import java.util.List;
-
-import org.antlr.v4.runtime.ANTLRInputStream;
-import org.antlr.v4.runtime.Token;
-import org.apache.olingo.server.core.uri.antlr.UriLexer;
-
-public class TokenValidator {
-
-  private String input = null;
-  private List<? extends Token> tokens = null;
-  private Token curToken = null;
-  private Exception curException = null;
-
-  private int startMode;
-
-  // --- Execution ---
-
-  public TokenValidator run(final String uri) {
-    input = uri;
-    tokens = parseInput(uri);
-    first();
-    return this;
-  }
-
-  // --- Navigation ---
-
-  // navigate within the tokenlist
-  public TokenValidator first() {
-    try {
-      curToken = tokens.get(0);
-    } catch (IndexOutOfBoundsException ex) {
-      curToken = null;
-    }
-    return this;
-  }
-
-  public TokenValidator last() {
-    curToken = tokens.get(tokens.size() - 1);
-    return this;
-  }
-
-  public TokenValidator at(final int index) {
-    try {
-      curToken = tokens.get(index);
-    } catch (IndexOutOfBoundsException ex) {
-      curToken = null;
-    }
-    return this;
-  }
-
-  // --- Validation ---
-
-  public TokenValidator isText(final String expected) {
-    assertEquals(expected, curToken.getText());
-    return this;
-  }
-
-  public TokenValidator isAllText(final String expected) {
-    String actual = "";
-
-    for (Token curToken : tokens) {
-      actual += curToken.getText();
-    }
-    assertEquals(expected, actual);
-    return this;
-  }
-
-  public TokenValidator isAllInput() {
-    String actual = "";
-
-    for (Token curToken : tokens) {
-      actual += curToken.getText();
-    }
-    assertEquals(input, actual);
-    return this;
-  }
-
-  public TokenValidator isInput() {
-    assertEquals(input, curToken.getText());
-    return this;
-  }
-
-  public TokenValidator isType(final int expected) {
-    assertEquals(UriLexer.VOCABULARY.getDisplayName(expected), UriLexer.VOCABULARY.getDisplayName(curToken.getType()));
-    return this;
-  }
-
-  public TokenValidator isExType(final Class<?> exClass) {
-    assertEquals(exClass, curException.getClass());
-    return this;
-  }
-
-  public void globalMode(final int mode) {
-    startMode = mode;
-  }
-
-  // --- Helper ---
-
-  private List<? extends Token> parseInput(final String input) {
-    ANTLRInputStream inputStream = new ANTLRInputStream(input);
-    UriLexer lexer = new UriLexer(inputStream);
-    lexer.mode(startMode);
-    return lexer.getAllTokens();
-  }
-}


[30/30] olingo-odata4 git commit: [OLINGO-834] Shift dependecies from commons to core

Posted by ch...@apache.org.
[OLINGO-834] Shift dependecies from commons to core

The dependencies were not used in the commons part of the library


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

Branch: refs/heads/master
Commit: b0866014df9d876cb44ea1f9632cab5ca95be7f5
Parents: 53d2e8b
Author: Christian Amend <ch...@sap.com>
Authored: Fri Jan 8 13:12:45 2016 +0100
Committer: Christian Amend <ch...@sap.com>
Committed: Fri Jan 8 13:12:45 2016 +0100

----------------------------------------------------------------------
 lib/client-core/pom.xml  | 21 +++++++++++++++++++++
 lib/commons-core/pom.xml | 22 ----------------------
 lib/server-core/pom.xml  | 14 ++++++++++++++
 3 files changed, 35 insertions(+), 22 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b0866014/lib/client-core/pom.xml
----------------------------------------------------------------------
diff --git a/lib/client-core/pom.xml b/lib/client-core/pom.xml
index a9c7f7a..092ffac 100644
--- a/lib/client-core/pom.xml
+++ b/lib/client-core/pom.xml
@@ -46,6 +46,27 @@
       <version>${project.version}</version>
     </dependency>
 
+	<dependency>
+      <groupId>com.fasterxml.jackson.core</groupId>
+      <artifactId>jackson-core</artifactId>
+    </dependency>
+	<dependency>
+      <groupId>com.fasterxml.jackson.core</groupId>
+      <artifactId>jackson-databind</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.fasterxml.jackson.core</groupId>
+      <artifactId>jackson-annotations</artifactId>
+    </dependency>
+	<dependency>
+      <groupId>com.fasterxml.jackson.dataformat</groupId>
+      <artifactId>jackson-dataformat-xml</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.fasterxml</groupId>
+      <artifactId>aalto-xml</artifactId>
+    </dependency>
+	
     <dependency>
       <groupId>junit</groupId>
       <artifactId>junit</artifactId>

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b0866014/lib/commons-core/pom.xml
----------------------------------------------------------------------
diff --git a/lib/commons-core/pom.xml b/lib/commons-core/pom.xml
index 2c069f9..e9c0179 100644
--- a/lib/commons-core/pom.xml
+++ b/lib/commons-core/pom.xml
@@ -46,27 +46,6 @@
     </dependency>
 
     <dependency>
-      <groupId>com.fasterxml.jackson.core</groupId>
-      <artifactId>jackson-core</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>com.fasterxml.jackson.core</groupId>
-      <artifactId>jackson-databind</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>com.fasterxml.jackson.core</groupId>
-      <artifactId>jackson-annotations</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>com.fasterxml.jackson.dataformat</groupId>
-      <artifactId>jackson-dataformat-xml</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>com.fasterxml</groupId>
-      <artifactId>aalto-xml</artifactId>
-    </dependency>
-
-    <dependency>
       <groupId>junit</groupId>
       <artifactId>junit</artifactId>
       <scope>test</scope>
@@ -99,7 +78,6 @@
               org.apache.olingo.commons.core.edm,
               org.apache.olingo.commons.core.edm.provider,
               org.apache.olingo.commons.core.edm.primitivetype,
-              org.apache.olingo.commons.core.serialization
             </Export-Package>
             <Import-Package>
               *

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b0866014/lib/server-core/pom.xml
----------------------------------------------------------------------
diff --git a/lib/server-core/pom.xml b/lib/server-core/pom.xml
index 6e22690..0c329d9 100644
--- a/lib/server-core/pom.xml
+++ b/lib/server-core/pom.xml
@@ -57,6 +57,20 @@
       <scope>test</scope>
     </dependency>
 
+	<dependency>
+      <groupId>com.fasterxml.jackson.core</groupId>
+      <artifactId>jackson-core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.fasterxml.jackson.core</groupId>
+      <artifactId>jackson-databind</artifactId>
+    </dependency>
+	
+	<dependency>
+      <groupId>com.fasterxml</groupId>
+      <artifactId>aalto-xml</artifactId>
+    </dependency>
+	
     <dependency>
       <groupId>junit</groupId>
       <artifactId>junit</artifactId>


[25/30] olingo-odata4 git commit: [OLINGO-834] $expand parser in Java + clean-up

Posted by ch...@apache.org.
[OLINGO-834] $expand parser in Java + clean-up

Signed-off-by: Christian Amend <ch...@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/8925274c
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/8925274c
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/8925274c

Branch: refs/heads/master
Commit: 8925274c0b5bd6936c3f6c1d3ab55608ced2cf13
Parents: 8919d3e
Author: Klaus Straubinger <kl...@sap.com>
Authored: Thu Jan 7 13:55:34 2016 +0100
Committer: Christian Amend <ch...@sap.com>
Committed: Thu Jan 7 14:02:09 2016 +0100

----------------------------------------------------------------------
 .../tecsvc/client/FilterSystemQueryITCase.java  |    7 +-
 .../tecsvc/client/OrderBySystemQueryITCase.java |    7 +-
 .../server/api/uri/queryoption/ExpandItem.java  |    1 -
 .../server/core/uri/parser/ExpandParser.java    |  282 +++
 .../core/uri/parser/ExpressionParser.java       |  332 +--
 .../server/core/uri/parser/FilterParser.java    |   11 +-
 .../olingo/server/core/uri/parser/Parser.java   |  234 +-
 .../server/core/uri/parser/ParserHelper.java    |   34 +-
 .../core/uri/parser/ResourcePathParser.java     |   62 +-
 .../server/core/uri/parser/SearchParser.java    |  108 +
 .../server/core/uri/parser/UriContext.java      |  115 -
 .../core/uri/parser/UriParseTreeVisitor.java    | 2313 ------------------
 .../server/core/uri/parser/UriTokenizer.java    |  211 +-
 .../uri/queryoption/expression/AliasImpl.java   |    4 +
 .../queryoption/expression/EnumerationImpl.java |    6 +
 .../queryoption/expression/LambdaRefImpl.java   |    5 +
 .../queryoption/expression/TypeLiteralImpl.java |    5 +
 .../server-core-exceptions-i18n.properties      |    8 +-
 .../core/uri/parser/ExpressionParserTest.java   |   14 +-
 .../core/uri/parser/UriTokenizerTest.java       |   82 +-
 .../search/SearchParserAndTokenizerTest.java    |   44 +-
 .../core/uri/antlr/TestFullResourcePath.java    | 1311 +++++-----
 .../olingo/server/core/uri/antlr/TestLexer.java |  450 ++--
 .../core/uri/antlr/TestUriParserImpl.java       |  220 +-
 .../server/core/uri/parser/ParserTest.java      |   56 +-
 .../core/uri/testutil/ExpandValidator.java      |   19 +-
 .../core/uri/testutil/FilterValidator.java      |   56 +-
 .../core/uri/testutil/TestUriValidator.java     |   38 +-
 .../core/uri/testutil/TokenValidator.java       |  127 -
 29 files changed, 1941 insertions(+), 4221 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8925274c/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/FilterSystemQueryITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/FilterSystemQueryITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/FilterSystemQueryITCase.java
index ca6eb21..6865a65 100644
--- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/FilterSystemQueryITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/FilterSystemQueryITCase.java
@@ -35,11 +35,8 @@ import org.apache.olingo.commons.api.edm.FullQualifiedName;
 import org.apache.olingo.commons.api.http.HttpHeader;
 import org.apache.olingo.commons.api.http.HttpStatusCode;
 import org.junit.Assert;
-import org.junit.Ignore;
 import org.junit.Test;
 
-// TODO
-@Ignore
 public class FilterSystemQueryITCase extends AbstractParamTecSvcITCase {
 
   private static final String ES_COMP_ALL_PRIM = "ESCompAllPrim";
@@ -212,7 +209,7 @@ public class FilterSystemQueryITCase extends AbstractParamTecSvcITCase {
         sendRequest(ES_TWO_KEY_NAV, "PropertyComp/PropertyComp/PropertyBoolean eq not null");
     assertEquals(0, result.getBody().getEntities().size());
 
-    result = sendRequest(ES_TWO_KEY_NAV, "PropertyComp/PropertyComp/PropertyBoolean eq 0 add -(5 add null)");
+    result = sendRequest(ES_TWO_KEY_NAV, "PropertyComp/PropertyComp/PropertyInt16 eq 0 add -(5 add null)");
     assertEquals(0, result.getBody().getEntities().size());
   }
 
@@ -357,7 +354,7 @@ public class FilterSystemQueryITCase extends AbstractParamTecSvcITCase {
 
   @Test
   public void notOperator() {
-    ODataRetrieveResponse<ClientEntitySet> result = sendRequest(ES_TWO_KEY_NAV, "not(PropertyInt16 eq 1)");
+    ODataRetrieveResponse<ClientEntitySet> result = sendRequest(ES_TWO_KEY_NAV, "not (PropertyInt16 eq 1)");
     assertEquals(2, result.getBody().getEntities().size());
 
     ClientEntity clientEntity = result.getBody().getEntities().get(0);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8925274c/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/OrderBySystemQueryITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/OrderBySystemQueryITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/OrderBySystemQueryITCase.java
index 0e31b33..8e16a70 100644
--- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/OrderBySystemQueryITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/OrderBySystemQueryITCase.java
@@ -30,11 +30,8 @@ import org.apache.olingo.client.api.domain.ClientEntitySet;
 import org.apache.olingo.client.api.domain.ClientValuable;
 import org.apache.olingo.commons.api.http.HttpStatusCode;
 import org.junit.Assert;
-import org.junit.Ignore;
 import org.junit.Test;
 
-// TODO
-@Ignore
 public class OrderBySystemQueryITCase extends AbstractParamTecSvcITCase {
 
   private static final String ES_TWO_PRIM = "ESTwoPrim";
@@ -74,7 +71,7 @@ public class OrderBySystemQueryITCase extends AbstractParamTecSvcITCase {
 
   @Test
   public void multipleOrderBy() {
-    final ODataRetrieveResponse<ClientEntitySet> response = sendRequest(ES_ALL_PRIM, "PropertyByte, PropertyInt16");
+    final ODataRetrieveResponse<ClientEntitySet> response = sendRequest(ES_ALL_PRIM, "PropertyByte,PropertyInt16");
     assertEquals(3, response.getBody().getEntities().size());
 
     ClientEntity clientEntity = response.getBody().getEntities().get(0);
@@ -90,7 +87,7 @@ public class OrderBySystemQueryITCase extends AbstractParamTecSvcITCase {
   @Test
   public void multipleOrderByDescending() {
     final ODataRetrieveResponse<ClientEntitySet> response =
-        sendRequest(ES_ALL_PRIM, "PropertyByte, PropertyInt16 desc");
+        sendRequest(ES_ALL_PRIM, "PropertyByte,PropertyInt16 desc");
     assertEquals(3, response.getBody().getEntities().size());
 
     ClientEntity clientEntity = response.getBody().getEntities().get(0);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8925274c/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/ExpandItem.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/ExpandItem.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/ExpandItem.java
index a16c137..fccf844 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/ExpandItem.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/ExpandItem.java
@@ -38,7 +38,6 @@ public interface ExpandItem {
   FilterOption getFilterOption();
 
   /**
-   * <b>CURRENTLY NOT SUPPORTED. WILL ALWAYS RETURN NULL</b>
    * @return Information of the option $search when used within $expand
    */
   SearchOption getSearchOption();

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8925274c/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpandParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpandParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpandParser.java
new file mode 100644
index 0000000..d8209d8
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpandParser.java
@@ -0,0 +1,282 @@
+/*
+ * 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 org.apache.olingo.commons.api.edm.Edm;
+import org.apache.olingo.commons.api.edm.EdmEntityType;
+import org.apache.olingo.commons.api.edm.EdmNavigationProperty;
+import org.apache.olingo.commons.api.edm.EdmProperty;
+import org.apache.olingo.commons.api.edm.EdmStructuredType;
+import org.apache.olingo.commons.api.edm.FullQualifiedName;
+import org.apache.olingo.commons.api.edm.constants.EdmTypeKind;
+import org.apache.olingo.commons.api.ex.ODataRuntimeException;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.uri.UriInfoKind;
+import org.apache.olingo.server.api.uri.UriResourceNavigation;
+import org.apache.olingo.server.api.uri.UriResourcePartTyped;
+import org.apache.olingo.server.api.uri.queryoption.ExpandItem;
+import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
+import org.apache.olingo.server.api.uri.queryoption.LevelsExpandOption;
+import org.apache.olingo.server.api.uri.queryoption.SystemQueryOption;
+import org.apache.olingo.server.api.uri.queryoption.SystemQueryOptionKind;
+import org.apache.olingo.server.core.uri.UriInfoImpl;
+import org.apache.olingo.server.core.uri.UriResourceComplexPropertyImpl;
+import org.apache.olingo.server.core.uri.UriResourceCountImpl;
+import org.apache.olingo.server.core.uri.UriResourceNavigationPropertyImpl;
+import org.apache.olingo.server.core.uri.UriResourceRefImpl;
+import org.apache.olingo.server.core.uri.parser.UriTokenizer.TokenKind;
+import org.apache.olingo.server.core.uri.queryoption.CountOptionImpl;
+import org.apache.olingo.server.core.uri.queryoption.ExpandItemImpl;
+import org.apache.olingo.server.core.uri.queryoption.ExpandOptionImpl;
+import org.apache.olingo.server.core.uri.queryoption.LevelsOptionImpl;
+import org.apache.olingo.server.core.uri.queryoption.SkipOptionImpl;
+import org.apache.olingo.server.core.uri.queryoption.TopOptionImpl;
+import org.apache.olingo.server.core.uri.validator.UriValidationException;
+
+public class ExpandParser {
+
+  private final Edm edm;
+  private final OData odata;
+
+  public ExpandParser(final Edm edm, final OData odata) {
+    this.edm = edm;
+    this.odata = odata;
+  }
+
+  public ExpandOption parse(UriTokenizer tokenizer, final EdmStructuredType referencedType)
+      throws UriParserException, UriValidationException {
+    ExpandOptionImpl expandOption = new ExpandOptionImpl();
+    do {
+      final ExpandItem item = parseItem(tokenizer, referencedType);
+      expandOption.addExpandItem(item);
+    } while (tokenizer.next(TokenKind.COMMA));
+
+    return expandOption;
+  }
+
+  private ExpandItem parseItem(UriTokenizer tokenizer, final EdmStructuredType referencedType)
+      throws UriParserException, UriValidationException {
+    ExpandItemImpl item = new ExpandItemImpl();
+    if (tokenizer.next(TokenKind.STAR)) {
+      item.setIsStar(true);
+      if (tokenizer.next(TokenKind.SLASH)) {
+        ParserHelper.requireNext(tokenizer, TokenKind.REF);
+        item.setIsRef(true);
+      } else if (tokenizer.next(TokenKind.OPEN)) {
+        ParserHelper.requireNext(tokenizer, TokenKind.LEVELS);
+        ParserHelper.requireNext(tokenizer, TokenKind.EQ);
+        item.setSystemQueryOption((SystemQueryOption) parseLevels(tokenizer));
+        ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
+      }
+
+    } else {
+      final EdmStructuredType typeCast = parseTypeCast(tokenizer, referencedType);
+      if (typeCast != null) {
+        item.setTypeFilter(typeCast);
+        ParserHelper.requireNext(tokenizer, TokenKind.SLASH);
+      }
+
+      UriInfoImpl resource = parseExpandPath(tokenizer, referencedType);
+
+      UriResourcePartTyped lastPart = (UriResourcePartTyped) resource.getLastResourcePart();
+
+      boolean hasSlash = false;
+      if (tokenizer.next(TokenKind.SLASH)) {
+        hasSlash = true;
+        if (lastPart instanceof UriResourceNavigation) {
+          UriResourceNavigationPropertyImpl navigationResource = (UriResourceNavigationPropertyImpl) lastPart;
+          final EdmNavigationProperty navigationProperty = navigationResource.getProperty();
+          final EdmStructuredType typeCastSuffix = parseTypeCast(tokenizer, navigationProperty.getType());
+          if (typeCastSuffix != null) {
+            if (navigationProperty.isCollection()) {
+              navigationResource.setCollectionTypeFilter(typeCastSuffix);
+            } else {
+              navigationResource.setEntryTypeFilter(typeCastSuffix);
+            }
+            hasSlash = false;
+          }
+        }
+      }
+
+      final EdmStructuredType newReferencedType = (EdmStructuredType) lastPart.getType();
+      final boolean newReferencedIsCollection = lastPart.isCollection();
+      if (hasSlash || tokenizer.next(TokenKind.SLASH)) {
+        if (tokenizer.next(TokenKind.REF)) {
+          resource.addResourcePart(new UriResourceRefImpl());
+          parseOptions(tokenizer, newReferencedType, newReferencedIsCollection, item, true, false);
+        } else {
+          ParserHelper.requireNext(tokenizer, TokenKind.COUNT);
+          resource.addResourcePart(new UriResourceCountImpl());
+          parseOptions(tokenizer, newReferencedType, newReferencedIsCollection, item, false, true);
+        }
+      } else {
+        parseOptions(tokenizer, newReferencedType, newReferencedIsCollection, item, false, false);
+      }
+
+      item.setResourcePath(resource);
+    }
+
+    return item;
+  }
+
+  private EdmStructuredType parseTypeCast(UriTokenizer tokenizer, final EdmStructuredType referencedType)
+      throws UriParserException {
+    if (tokenizer.next(TokenKind.QualifiedName)) {
+      final FullQualifiedName qualifiedName = new FullQualifiedName(tokenizer.getText());
+      final EdmStructuredType type = referencedType instanceof EdmEntityType ?
+          edm.getEntityType(qualifiedName) :
+          edm.getComplexType(qualifiedName);
+      if (type == null) {
+        throw new UriParserSemanticException("Type '" + qualifiedName + "' not found.",
+            UriParserSemanticException.MessageKeys.UNKNOWN_PART, qualifiedName.getFullQualifiedNameAsString());
+      } else {
+        if (!type.compatibleTo(referencedType)) {
+          throw new UriParserSemanticException("The type cast '" + qualifiedName + "' is not compatible.",
+              UriParserSemanticException.MessageKeys.INCOMPATIBLE_TYPE_FILTER, type.getName());
+        }
+      }
+      return type;
+    }
+    return null;
+  }
+
+  private UriInfoImpl parseExpandPath(UriTokenizer tokenizer, final EdmStructuredType referencedType)
+      throws UriParserException {
+    UriInfoImpl resource = new UriInfoImpl().setKind(UriInfoKind.resource);
+
+    EdmStructuredType type = referencedType;
+    String name = null;
+    while (tokenizer.next(TokenKind.ODataIdentifier)) {
+      name = tokenizer.getText();
+      final EdmProperty property = referencedType.getStructuralProperty(name);
+      if (property != null && property.getType().getKind() == EdmTypeKind.COMPLEX) {
+        type = (EdmStructuredType) property.getType();
+        UriResourceComplexPropertyImpl complexResource = new UriResourceComplexPropertyImpl(property);
+        ParserHelper.requireNext(tokenizer, TokenKind.SLASH);
+        final EdmStructuredType typeCast = parseTypeCast(tokenizer, type);
+        if (typeCast != null) {
+          complexResource.setTypeFilter(typeCast);
+          ParserHelper.requireNext(tokenizer, TokenKind.SLASH);
+          type = typeCast;
+        }
+        resource.addResourcePart(complexResource);
+      }
+    }
+
+    final EdmNavigationProperty navigationProperty = type.getNavigationProperty(name);
+    if (navigationProperty == null) {
+      // TODO: could also have been star after complex property (and maybe type cast)
+      throw new UriParserSemanticException(
+          "Navigation Property '" + name + "' not found in type '" + type.getFullQualifiedName() + "'.",
+          UriParserSemanticException.MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE, type.getName(), name);
+    } else {
+      resource.addResourcePart(new UriResourceNavigationPropertyImpl(navigationProperty));
+    }
+
+    return resource;
+  }
+
+  private void parseOptions(UriTokenizer tokenizer,
+      final EdmStructuredType referencedType, final boolean referencedIsCollection,
+      ExpandItemImpl item,
+      final boolean forRef, final boolean forCount) throws UriParserException, UriValidationException {
+    if (tokenizer.next(TokenKind.OPEN)) {
+      do {
+        SystemQueryOption systemQueryOption;
+        if (!forCount && tokenizer.next(TokenKind.COUNT)) {
+          ParserHelper.requireNext(tokenizer, TokenKind.EQ);
+          ParserHelper.requireNext(tokenizer, TokenKind.BooleanValue);
+          CountOptionImpl countOption = new CountOptionImpl();
+          countOption.setText(tokenizer.getText());
+          countOption.setValue(Boolean.parseBoolean(tokenizer.getText()));
+          systemQueryOption = countOption;
+
+        } else if (!forRef && !forCount && tokenizer.next(TokenKind.EXPAND)) {
+          ParserHelper.requireNext(tokenizer, TokenKind.EQ);
+          systemQueryOption = new ExpandParser(edm, odata).parse(tokenizer, referencedType);
+
+        } else if (tokenizer.next(TokenKind.FILTER)) {
+          ParserHelper.requireNext(tokenizer, TokenKind.EQ);
+          systemQueryOption = new FilterParser(edm, odata).parse(tokenizer, referencedType, null);
+
+        } else if (!forRef && !forCount && tokenizer.next(TokenKind.LEVELS)) {
+          ParserHelper.requireNext(tokenizer, TokenKind.EQ);
+          systemQueryOption = (SystemQueryOption) parseLevels(tokenizer);
+
+        } else if (!forCount && tokenizer.next(TokenKind.ORDERBY)) {
+          ParserHelper.requireNext(tokenizer, TokenKind.EQ);
+          systemQueryOption = new OrderByParser(edm, odata).parse(tokenizer, referencedType, null);
+
+        } else if (tokenizer.next(TokenKind.SEARCH)) {
+          ParserHelper.requireNext(tokenizer, TokenKind.EQ);
+          systemQueryOption = new SearchParser().parse(tokenizer);
+
+        } else if (!forRef && !forCount && tokenizer.next(TokenKind.SELECT)) {
+          ParserHelper.requireNext(tokenizer, TokenKind.EQ);
+          systemQueryOption = new SelectParser(edm).parse(tokenizer, referencedType, referencedIsCollection);
+
+        } else if (!forCount && tokenizer.next(TokenKind.SKIP)) {
+          ParserHelper.requireNext(tokenizer, TokenKind.EQ);
+          ParserHelper.requireNext(tokenizer, TokenKind.IntegerValue);
+          final int value = ParserHelper.parseNonNegativeInteger(SystemQueryOptionKind.SKIP.toString(),
+              tokenizer.getText(), true);
+          SkipOptionImpl skipOption = new SkipOptionImpl();
+          skipOption.setText(tokenizer.getText());
+          skipOption.setValue(value);
+          systemQueryOption = skipOption;
+
+        } else if (!forCount && tokenizer.next(TokenKind.TOP)) {
+          ParserHelper.requireNext(tokenizer, TokenKind.EQ);
+          ParserHelper.requireNext(tokenizer, TokenKind.IntegerValue);
+          final int value = ParserHelper.parseNonNegativeInteger(SystemQueryOptionKind.TOP.toString(),
+              tokenizer.getText(), true);
+          TopOptionImpl topOption = new TopOptionImpl();
+          topOption.setText(tokenizer.getText());
+          topOption.setValue(value);
+          systemQueryOption = topOption;
+
+        } else {
+          throw new UriParserSyntaxException("Allowed query option expected.",
+              UriParserSyntaxException.MessageKeys.SYNTAX);
+        }
+        try {
+          item.setSystemQueryOption(systemQueryOption);
+        } catch (final ODataRuntimeException e) {
+          throw new UriParserSyntaxException("Double system query option '" + systemQueryOption.getName() + "'.", e,
+              UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION, systemQueryOption.getName());
+        }
+      } while (tokenizer.next(TokenKind.SEMI));
+      ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
+    }
+  }
+
+  private LevelsExpandOption parseLevels(UriTokenizer tokenizer) throws UriParserException {
+    final LevelsOptionImpl option = new LevelsOptionImpl();
+    if (tokenizer.next(TokenKind.MAX)) {
+      option.setText(tokenizer.getText());
+      option.setMax();
+    } else {
+      ParserHelper.requireNext(tokenizer, TokenKind.IntegerValue);
+      option.setText(tokenizer.getText());
+      option.setValue(
+          ParserHelper.parseNonNegativeInteger(SystemQueryOptionKind.LEVELS.toString(), tokenizer.getText(), false));
+    }
+    return option;
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8925274c/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java
index 049880f..6fa415f 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java
@@ -47,9 +47,6 @@ 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.commons.core.edm.primitivetype.EdmByte;
-import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
-import org.apache.olingo.commons.core.edm.primitivetype.EdmSByte;
 import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.uri.UriParameter;
 import org.apache.olingo.server.api.uri.UriResourceFunction;
@@ -161,7 +158,7 @@ public class ExpressionParser {
 
   private static final Map<TokenKind, EdmPrimitiveTypeKind> tokenToPrimitiveType;
   static {
-    /* Enum and null are not present in the map. These have to be handled differently */
+    /* Enum and null are not present in the map. These have to be handled differently. */
     Map<TokenKind, EdmPrimitiveTypeKind> temp = new HashMap<TokenKind, EdmPrimitiveTypeKind>();
     temp.put(TokenKind.BooleanValue, EdmPrimitiveTypeKind.Boolean);
     temp.put(TokenKind.StringValue, EdmPrimitiveTypeKind.String);
@@ -242,9 +239,9 @@ public class ExpressionParser {
   }
 
   private Expression parseExprRel() throws UriParserException, UriValidationException {
-    if(tokenizer.next(TokenKind.IsofMethod)) {
-      // The isof method is a terminal. So no further operators are allowed
-      return parseIsOfMethod(TokenKind.IsofMethod);
+    if (tokenizer.next(TokenKind.IsofMethod)) {
+      // The isof method is a terminal.  So no further operators are allowed.
+      return parseIsOfOrCastMethod(MethodKind.ISOF);
     } else {
       Expression left = parseExprAdd();
       TokenKind operatorTokenKind = ParserHelper.next(tokenizer,
@@ -264,30 +261,25 @@ public class ExpressionParser {
     }
   }
 
-  private Expression parseIsOfMethod(final TokenKind lastToken) throws UriParserException, UriValidationException {
-    if(lastToken == TokenKind.IsofMethod) {
-      // The TokenKind 'IsOfMethod' consumes also the opening parenthesis 
-
-      // The first parameter could be an expression or a type literal
-      final List<Expression> parameters = new ArrayList<Expression>();
+  private Expression parseIsOfOrCastMethod(final MethodKind kind) throws UriParserException, UriValidationException {
+    // The TokenKind 'IsOfMethod' consumes also the opening parenthesis.
+    // The first parameter could be an expression or a type literal.
+    List<Expression> parameters = new ArrayList<Expression>();
+    parameters.add(parseExpression());
+    if (!(parameters.get(0) instanceof TypeLiteral)) {
+      // The first parameter is not a type literal, so there must be a second parameter.
+      ParserHelper.requireNext(tokenizer, TokenKind.COMMA);
       parameters.add(parseExpression());
-      if(!(parameters.get(0) instanceof TypeLiteral)) {
-        // The first parameter is not a type literal, so there must be a second parameter
-        ParserHelper.requireNext(tokenizer, TokenKind.COMMA);
-        parameters.add(parseExpression());
-        
-        // The second parameter must be a type literal
-        if(!(parameters.get(1) instanceof TypeLiteral)) {
-          throw new UriParserSemanticException("Type literal extected", 
-              UriParserSemanticException.MessageKeys.INCOMPATIBLE_TYPE_FILTER);
-        }
+
+      // The second parameter must be a type literal.
+      if (!(parameters.get(1) instanceof TypeLiteral)) {
+        throw new UriParserSemanticException("Type literal expected.",
+            UriParserSemanticException.MessageKeys.INCOMPATIBLE_TYPE_FILTER);
       }
-      
-      ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
-      return new MethodImpl(MethodKind.ISOF, parameters);
-    } else {
-      throw new UriParserSyntaxException("Unexpected token.", UriParserSyntaxException.MessageKeys.SYNTAX);
     }
+
+    ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
+    return new MethodImpl(kind, parameters);
   }
 
   private Expression parseExprAdd() throws UriParserException, UriValidationException {
@@ -296,9 +288,9 @@ public class ExpressionParser {
     // Null for everything other than ADD or SUB
     while (operatorTokenKind != null) {
       final Expression right = parseExprMul();
-      checkAddSubTypes(left, right, operatorTokenKind == TokenKind.AddOperator);
-      left = new BinaryImpl(left, tokenToBinaryOperator.get(operatorTokenKind), right,
-          odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Double));
+      final EdmType resultType = getAddSubTypeAndCheckLeftAndRight(left, right,
+          operatorTokenKind == TokenKind.SubOperator);
+      left = new BinaryImpl(left, tokenToBinaryOperator.get(operatorTokenKind), right, resultType);
       operatorTokenKind = ParserHelper.next(tokenizer, TokenKind.AddOperator, TokenKind.SubOperator);
     }
     return left;
@@ -328,10 +320,7 @@ public class ExpressionParser {
   }
 
   private Expression parseExprUnary() throws UriParserException, UriValidationException {
-    final TokenKind operatorTokenKind = ParserHelper.next(tokenizer, TokenKind.MINUS, TokenKind.NotOperator, 
-                                                                     TokenKind.CastMethod);
-    
-    if(operatorTokenKind == TokenKind.MINUS) {
+    if (tokenizer.next(TokenKind.MinusOperator)) {
       final Expression expression = parseExprPrimary();
       checkType(expression,
           EdmPrimitiveTypeKind.Int16, EdmPrimitiveTypeKind.Int32, EdmPrimitiveTypeKind.Int64,
@@ -339,37 +328,14 @@ public class ExpressionParser {
           EdmPrimitiveTypeKind.Decimal, EdmPrimitiveTypeKind.Single, EdmPrimitiveTypeKind.Double,
           EdmPrimitiveTypeKind.Duration);
       return new UnaryImpl(UnaryOperatorKind.MINUS, expression, getType(expression));
-    } else if(operatorTokenKind == TokenKind.NotOperator) {
+    } else if (tokenizer.next(TokenKind.NotOperator)) {
       final Expression expression = parseExprPrimary();
       checkType(expression, EdmPrimitiveTypeKind.Boolean);
       return new UnaryImpl(UnaryOperatorKind.NOT, expression, getType(expression));
-    } else if(operatorTokenKind == TokenKind.CastMethod) {
-      return parseCastMethod(operatorTokenKind);
+    } else if (tokenizer.next(TokenKind.CastMethod)) {
+      return parseIsOfOrCastMethod(MethodKind.CAST);
     } else {
-      final Expression expression = parseExprPrimary();
-      return expression;
-    }
-  }
-
-  private Expression parseCastMethod(final TokenKind lastToken) throws UriParserException, UriValidationException {
-    // The TokenKind 'CastMethod' consumes also the opening parenthesis 
-    if(lastToken == TokenKind.CastMethod) {
-      final List<Expression> parameters = new ArrayList<Expression>();
-      parameters.add(parseExpression());
-      
-      if(!(parameters.get(0) instanceof TypeLiteral)) {
-        ParserHelper.requireNext(tokenizer, TokenKind.COMMA);
-        parameters.add(parseExpression());
-        if(!(parameters.get(1) instanceof TypeLiteral)) {
-          throw new UriParserSemanticException("Type literal extected", 
-              UriParserSemanticException.MessageKeys.INCOMPATIBLE_TYPE_FILTER);
-        }
-      }
-      
-      ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
-      return new MethodImpl(MethodKind.CAST, parameters);
-    } else {
-      throw new UriParserSyntaxException("Unexpected token.", UriParserSyntaxException.MessageKeys.SYNTAX);
+      return parseExprPrimary();
     }
   }
 
@@ -433,22 +399,20 @@ public class ExpressionParser {
   private Expression parseMethod(final TokenKind nextMethod) throws UriParserException, UriValidationException {
     // The method token text includes the opening parenthesis so that method calls can be recognized unambiguously.
     // OData identifiers have to be considered after that.
-    
     final MethodKind methodKind = tokenToMethod.get(nextMethod);
     return new MethodImpl(methodKind, parseMethodParameters(methodKind));
   }
 
-  private Expression parsePrimitive(TokenKind nextPrimitive) throws UriParserException {
+  private Expression parsePrimitive(final TokenKind primitiveTokenKind) throws UriParserException {
     final String primitiveValueLiteral = tokenizer.getText();
-    if (nextPrimitive == TokenKind.EnumValue) {
+    if (primitiveTokenKind == TokenKind.EnumValue) {
       return createEnumExpression(primitiveValueLiteral);
     } else {
-      EdmPrimitiveTypeKind primitiveTypeKind = tokenToPrimitiveType.get(nextPrimitive);
-      
-      if(primitiveTypeKind == EdmPrimitiveTypeKind.Int64) {
+      EdmPrimitiveTypeKind primitiveTypeKind = tokenToPrimitiveType.get(primitiveTokenKind);
+      if (primitiveTypeKind == EdmPrimitiveTypeKind.Int64) {
         primitiveTypeKind = determineIntegerType(primitiveValueLiteral);
       }
-      
+
       final EdmPrimitiveType type = primitiveTypeKind == null ?
           // Null handling
           null :
@@ -472,12 +436,11 @@ public class ExpressionParser {
       } else {
         typeKind = EdmPrimitiveTypeKind.Int64;
       }
-    } catch (NumberFormatException e) {
-      // This should never happen. Because the tokenizer has figured out that the literal is an integer
-      throw new UriParserSyntaxException(intValueAsString + " is not an integer", 
+    } catch (final NumberFormatException e) {
+      // This should never happen because the tokenizer has figured out that the literal is an integer.
+      throw new UriParserSyntaxException("'" + intValueAsString + "' is not an integer.", e,
           UriParserSyntaxException.MessageKeys.SYNTAX);
     }
-
     return typeKind;
   }
 
@@ -622,19 +585,19 @@ public class ExpressionParser {
       if (filterType == null) {
         filterType = edm.getComplexType(fullQualifiedName);
       }
-      
-      if(filterType == null) {
-        filterType = getEdmType(fullQualifiedName);
+
+      if (filterType == null) {
+        filterType = getPrimitiveType(fullQualifiedName);
       }
-      
-      if(filterType == null) {
+
+      if (filterType == null) {
         filterType = edm.getEnumType(fullQualifiedName);
       }
-      
-      if(filterType == null) {
+
+      if (filterType == null) {
         filterType = edm.getTypeDefinition(fullQualifiedName);
       }
-      
+
       if (filterType != null) {
         if (tokenizer.next(TokenKind.SLASH)) {
           // Leading type cast
@@ -642,30 +605,29 @@ public class ExpressionParser {
           startTypeFilter = filterType;
 
           final TokenKind tokenKind = ParserHelper.next(tokenizer, TokenKind.QualifiedName, TokenKind.ODataIdentifier);
-          parseMemberExpression(tokenKind, uriInfo, new UriResourceStartingTypeFilterImpl(filterType, false), 
-              false);
+          parseMemberExpression(tokenKind, uriInfo, new UriResourceStartingTypeFilterImpl(filterType, false), false);
         } else {
           // Type literal
           return new TypeLiteralImpl(filterType);
         }
       } else {
-        // Must be bound or unbound function. 
+        // Must be bound or unbound function.
         parseFunction(fullQualifiedName, uriInfo, referringType, true);
       }
     } else if (lastTokenKind == TokenKind.ODataIdentifier) {
       parseFirstMemberODataIdentifier(uriInfo);
     }
-    
+
     return new MemberImpl(uriInfo, startTypeFilter);
   }
 
-  private EdmType getEdmType(final FullQualifiedName fullQualifiedName) {
-    if(!fullQualifiedName.getNamespace().equals(EdmPrimitiveType.EDM_NAMESPACE)) {
+  private EdmType getPrimitiveType(final FullQualifiedName fullQualifiedName) {
+    if (EdmPrimitiveType.EDM_NAMESPACE.equals(fullQualifiedName.getNamespace())) {
+      final EdmPrimitiveTypeKind primitiveTypeKind = EdmPrimitiveTypeKind.valueOf(fullQualifiedName.getName());
+      return primitiveTypeKind == null ? null : odata.createPrimitiveTypeInstance(primitiveTypeKind);
+    } else {
       return null;
     }
-    
-    final EdmPrimitiveTypeKind primitiveTypeKind = EdmPrimitiveTypeKind.valueOfFQN(fullQualifiedName);
-    return primitiveTypeKind == null ? null : EdmPrimitiveTypeFactory.getInstance(primitiveTypeKind);
   }
 
   private void parseDollarRoot(UriInfoImpl uriInfo) throws UriParserException, UriValidationException {
@@ -694,7 +656,7 @@ public class ExpressionParser {
     parseSingleNavigationExpr(uriInfo, resource);
   }
 
-  private void parseDollarIt(UriInfoImpl uriInfo, EdmType referringType) 
+  private void parseDollarIt(UriInfoImpl uriInfo, final EdmType referringType)
       throws UriParserException, UriValidationException {
     UriResourceItImpl itResource = new UriResourceItImpl(referringType, false);
     uriInfo.addResourcePart(itResource);
@@ -759,16 +721,14 @@ public class ExpressionParser {
       if (edmEntityType != null) {
         if (allowTypeFilter) {
           setTypeFilter(lastResource, edmEntityType);
-          
-          if(tokenizer.next(TokenKind.SLASH)) {
-            final TokenKind nextTokenKind = ParserHelper.next(tokenizer, TokenKind.QualifiedName, 
-                                                                         TokenKind.ODataIdentifier);
-            if(nextTokenKind == TokenKind.ODataIdentifier) {
-              parsePropertyPathExpr(uriInfo, lastResource);
-            } else if(nextTokenKind == TokenKind.QualifiedName) {
+
+          if (tokenizer.next(TokenKind.SLASH)) {
+            if (tokenizer.next(TokenKind.QualifiedName)) {
               parseBoundFunction(fullQualifiedName, uriInfo, lastResource);
+            } else if (tokenizer.next(TokenKind.ODataIdentifier)) {
+              parsePropertyPathExpr(uriInfo, lastResource);
             } else {
-              throw new UriParserSyntaxException("Extected OData Identifier or Full Qualified Name", 
+              throw new UriParserSyntaxException("Expected OData Identifier or Full Qualified Name.",
                   UriParserSyntaxException.MessageKeys.SYNTAX);
             }
           }
@@ -814,7 +774,9 @@ public class ExpressionParser {
 
     if (property == null) {
       throw new UriParserSemanticException("Unknown property.",
-          UriParserSemanticException.MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE, oDataIdentifier);
+          UriParserSemanticException.MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE,
+          lastType.getFullQualifiedName().getFullQualifiedNameAsString(),
+          oDataIdentifier);
     }
 
     if (property.getType() instanceof EdmComplexType) {
@@ -823,7 +785,9 @@ public class ExpressionParser {
       uriInfo.addResourcePart(complexResource);
 
       if (property.isCollection()) {
-        parseCollectionPathExpr(uriInfo, complexResource);
+        if (tokenizer.next(TokenKind.SLASH)) {
+          parseCollectionPathExpr(uriInfo, complexResource);
+        }
       } else {
         parseComplexPathExpr(uriInfo, complexResource);
       }
@@ -847,7 +811,9 @@ public class ExpressionParser {
       uriInfo.addResourcePart(primitiveResource);
 
       if (property.isCollection()) {
-        parseCollectionPathExpr(uriInfo, primitiveResource);
+        if (tokenizer.next(TokenKind.SLASH)) {
+          parseCollectionPathExpr(uriInfo, primitiveResource);
+        }
       } else {
         parseSinglePathExpr(uriInfo, primitiveResource);
       }
@@ -856,7 +822,6 @@ public class ExpressionParser {
 
   private void parseSingleNavigationExpr(UriInfoImpl uriInfo, final UriResourcePartTyped lastResource)
       throws UriParserException, UriValidationException {
-    // TODO: Is that correct?
     if (tokenizer.next(TokenKind.SLASH)) {
       final TokenKind tokenKind = ParserHelper.next(tokenizer, TokenKind.QualifiedName, TokenKind.ODataIdentifier);
       parseMemberExpression(tokenKind, uriInfo, lastResource, true);
@@ -865,8 +830,22 @@ public class ExpressionParser {
 
   private void parseCollectionNavigationExpr(UriInfoImpl uriInfo, UriResourcePartTyped lastResource)
       throws UriParserException, UriValidationException {
-    // TODO: Is type cast missing?
-    if (tokenizer.next(TokenKind.OPEN)) {
+    boolean hasSlash = false;
+    if (tokenizer.next(TokenKind.SLASH)) {
+      hasSlash = true;
+      if (tokenizer.next(TokenKind.QualifiedName)) {
+        final FullQualifiedName qualifiedName = new FullQualifiedName(tokenizer.getText());
+        final EdmEntityType edmEntityType = edm.getEntityType(qualifiedName);
+        if (edmEntityType == null) {
+          parseBoundFunction(qualifiedName, uriInfo, lastResource);
+        } else {
+          setTypeFilter(lastResource, edmEntityType);
+        }
+        hasSlash = false;
+      }
+    }
+
+    if (!hasSlash && tokenizer.next(TokenKind.OPEN)) {
       if (lastResource instanceof UriResourceNavigation) {
         ((UriResourceNavigationPropertyImpl) lastResource).setKeyPredicates(
               ParserHelper.parseNavigationKeyPredicate(tokenizer,
@@ -883,7 +862,10 @@ public class ExpressionParser {
       }
       parseSingleNavigationExpr(uriInfo, lastResource);
     }
-    parseCollectionPathExpr(uriInfo, lastResource);
+
+    if (hasSlash || tokenizer.next(TokenKind.SLASH)) {
+      parseCollectionPathExpr(uriInfo, lastResource);
+    }
   }
 
   private void parseSinglePathExpr(UriInfoImpl uriInfo, final UriResourcePartTyped lastResource)
@@ -932,25 +914,23 @@ public class ExpressionParser {
 
   private void parseCollectionPathExpr(UriInfoImpl uriInfo, final UriResourcePartTyped lastResource)
       throws UriParserException, UriValidationException {
-
-    if (tokenizer.next(TokenKind.SLASH)) {
-      if (tokenizer.next(TokenKind.COUNT)) {
-        uriInfo.addResourcePart(new UriResourceCountImpl());
-      } else if (tokenizer.next(TokenKind.ANY)) {
-        uriInfo.addResourcePart(parseLambdaRest(TokenKind.ANY, lastResource));
-      } else if (tokenizer.next(TokenKind.ALL)) {
-        uriInfo.addResourcePart(parseLambdaRest(TokenKind.ALL, lastResource));
-      } else if (tokenizer.next(TokenKind.QualifiedName)) {
-        final FullQualifiedName fullQualifiedName = new FullQualifiedName(tokenizer.getText());
-        parseBoundFunction(fullQualifiedName, uriInfo, lastResource);
-      }
+    // The initial slash (see grammar) must have been checked and consumed by the caller.
+    if (tokenizer.next(TokenKind.COUNT)) {
+      uriInfo.addResourcePart(new UriResourceCountImpl());
+    } else if (tokenizer.next(TokenKind.ANY)) {
+      uriInfo.addResourcePart(parseLambdaRest(TokenKind.ANY, lastResource));
+    } else if (tokenizer.next(TokenKind.ALL)) {
+      uriInfo.addResourcePart(parseLambdaRest(TokenKind.ALL, lastResource));
+    } else if (tokenizer.next(TokenKind.QualifiedName)) {
+      final FullQualifiedName fullQualifiedName = new FullQualifiedName(tokenizer.getText());
+      parseBoundFunction(fullQualifiedName, uriInfo, lastResource);
     }
   }
 
   private void parseFunction(final FullQualifiedName fullQualifiedName, UriInfoImpl uriInfo,
       final EdmType lastType, final boolean lastIsCollection) throws UriParserException, UriValidationException {
 
-    final List<UriParameter> parameters = ParserHelper.parseFunctionParameters(tokenizer, true);
+    final List<UriParameter> parameters = ParserHelper.parseFunctionParameters(tokenizer, edm, referringType, true);
     final List<String> parameterNames = ParserHelper.getParameterNames(parameters);
     final EdmFunction boundFunction = edm.getBoundFunction(fullQualifiedName,
         lastType.getFullQualifiedName(), lastIsCollection, parameterNames);
@@ -966,18 +946,19 @@ public class ExpressionParser {
       return;
     }
 
-    throw new UriParserSemanticException("No function found.",
+    throw new UriParserSemanticException("No function '" + fullQualifiedName + "' found.",
         UriParserSemanticException.MessageKeys.FUNCTION_NOT_FOUND, fullQualifiedName.getFullQualifiedNameAsString());
   }
 
   private void parseBoundFunction(final FullQualifiedName fullQualifiedName, UriInfoImpl uriInfo,
       final UriResourcePartTyped lastResource) throws UriParserException, UriValidationException {
-    final List<UriParameter> parameters = ParserHelper.parseFunctionParameters(tokenizer, true);
+    final EdmType type = lastResource.getType();
+    final List<UriParameter> parameters = ParserHelper.parseFunctionParameters(tokenizer, edm, referringType, true);
     final List<String> parameterNames = ParserHelper.getParameterNames(parameters);
     final EdmFunction boundFunction = edm.getBoundFunction(fullQualifiedName,
-        lastResource.getType().getFullQualifiedName(), lastResource.isCollection(), parameterNames);
+        type.getFullQualifiedName(), lastResource.isCollection(), parameterNames);
     if (boundFunction == null) {
-      throw new UriParserSemanticException("Bound function not found.",
+      throw new UriParserSemanticException("Bound function '" + fullQualifiedName + "' not found.",
           UriParserSemanticException.MessageKeys.FUNCTION_NOT_FOUND, fullQualifiedName.getFullQualifiedNameAsString());
     }
     parseFunctionRest(uriInfo, boundFunction, parameters);
@@ -995,19 +976,23 @@ public class ExpressionParser {
     if (function.isComposable()) {
       if (edmType instanceof EdmEntityType ) {
         if (isCollection) {
-          parseCollectionNavigationExpr(uriInfo, functionResource); 
+          parseCollectionNavigationExpr(uriInfo, functionResource);
         } else {
           parseSingleNavigationExpr(uriInfo, functionResource);
         }
       } else if (edmType instanceof EdmComplexType) {
         if (isCollection) {
-          parseCollectionPathExpr(uriInfo, functionResource);
+          if (tokenizer.next(TokenKind.SLASH)) {
+            parseCollectionPathExpr(uriInfo, functionResource);
+          }
         } else {
           parseComplexPathExpr(uriInfo, functionResource);
         }
       } else if (edmType instanceof EdmPrimitiveType) {
         if (isCollection) {
-          parseCollectionPathExpr(uriInfo, functionResource);
+          if (tokenizer.next(TokenKind.SLASH)) {
+            parseCollectionPathExpr(uriInfo, functionResource);
+          }
         } else {
           parseSinglePathExpr(uriInfo, functionResource);
         }
@@ -1077,7 +1062,7 @@ public class ExpressionParser {
         TokenKind.YearMethod);
   }
 
-  private EdmType getType(final Expression expression) throws UriParserException {
+  protected static EdmType getType(final Expression expression) throws UriParserException {
     EdmType type;
     if (expression instanceof Literal) {
       type = ((Literal) expression).getType();
@@ -1108,13 +1093,12 @@ public class ExpressionParser {
     return type;
   }
 
-  private boolean isType(final Expression expression, final EdmPrimitiveTypeKind... kinds) throws UriParserException {
-    final EdmType expressionType = getType(expression);
-    if (expressionType == null) {
+  private boolean isType(final EdmType type, final EdmPrimitiveTypeKind... kinds) throws UriParserException {
+    if (type == null) {
       return true;
     }
     for (final EdmPrimitiveTypeKind kind : kinds) {
-      if (expressionType.equals(odata.createPrimitiveTypeInstance(kind))) {
+      if (type.equals(odata.createPrimitiveTypeInstance(kind))) {
         return true;
       }
     }
@@ -1122,12 +1106,13 @@ public class ExpressionParser {
   }
 
   private void checkType(final Expression expression, final EdmPrimitiveTypeKind... kinds) throws UriParserException {
-    if (!isType(expression, kinds)) {
+    final EdmType type = getType(expression);
+    if (!isType(type, kinds)) {
       throw new UriParserSemanticException("Incompatible type.",
           UriParserSemanticException.MessageKeys.UNKNOWN_TYPE, // TODO: better message
-          getType(expression) == null ?
+          type == null ?
               "" :
-              getType(expression).getFullQualifiedName().getFullQualifiedNameAsString());
+              type.getFullQualifiedName().getFullQualifiedNameAsString());
     }
   }
 
@@ -1137,21 +1122,21 @@ public class ExpressionParser {
     if (leftType == null || rightType == null || leftType.equals(rightType)) {
       return;
     }
-    
+
     // Numeric promotion for Edm.Byte and Edm.SByte
-    if((leftType instanceof EdmByte || leftType instanceof EdmSByte) 
-        && (rightType instanceof EdmByte || rightType instanceof EdmSByte)) {
+    if (isType(leftType, EdmPrimitiveTypeKind.Byte, EdmPrimitiveTypeKind.SByte)
+        && isType(rightType, EdmPrimitiveTypeKind.Byte, EdmPrimitiveTypeKind.SByte)) {
       return;
     }
-    
+
     if (leftType.getKind() != EdmTypeKind.PRIMITIVE
         || rightType.getKind() != EdmTypeKind.PRIMITIVE
         || !(((EdmPrimitiveType) leftType).isCompatible((EdmPrimitiveType) rightType)
-        || ((EdmPrimitiveType) rightType).isCompatible((EdmPrimitiveType) leftType)))
-        {
+        || ((EdmPrimitiveType) rightType).isCompatible((EdmPrimitiveType) leftType))) {
       throw new UriParserSemanticException("Incompatible types.",
-          UriParserSemanticException.MessageKeys.TYPES_NOT_COMPATIBLE, leftType.getFullQualifiedName().toString(), 
-                                                                       rightType.getFullQualifiedName().toString());
+          UriParserSemanticException.MessageKeys.TYPES_NOT_COMPATIBLE,
+          leftType.getFullQualifiedName().getFullQualifiedNameAsString(),
+          rightType.getFullQualifiedName().getFullQualifiedNameAsString());
     }
   }
 
@@ -1164,12 +1149,12 @@ public class ExpressionParser {
     }
     return type;
   }
-  
+
   private boolean isEnumType(final Expression expression) throws UriParserException {
     final EdmType expressionType = getType(expression);
     return expressionType == null
         || expressionType.getKind() == EdmTypeKind.ENUM
-        || isType(expression,
+        || isType(expressionType,
             EdmPrimitiveTypeKind.Int16, EdmPrimitiveTypeKind.Int32, EdmPrimitiveTypeKind.Int64,
             EdmPrimitiveTypeKind.Byte, EdmPrimitiveTypeKind.SByte);
   }
@@ -1208,44 +1193,69 @@ public class ExpressionParser {
         EdmPrimitiveTypeKind.Date, EdmPrimitiveTypeKind.TimeOfDay,
         EdmPrimitiveTypeKind.DateTimeOffset, EdmPrimitiveTypeKind.Duration);
     if (!(((EdmPrimitiveType) leftType).isCompatible((EdmPrimitiveType) rightType)
-    || ((EdmPrimitiveType) rightType).isCompatible((EdmPrimitiveType) leftType))) {
+        || ((EdmPrimitiveType) rightType).isCompatible((EdmPrimitiveType) leftType))) {
       throw new UriParserSemanticException("Incompatible types.",
-          UriParserSemanticException.MessageKeys.UNKNOWN_TYPE, ""); // TODO: better message
+          UriParserSemanticException.MessageKeys.TYPES_NOT_COMPATIBLE,
+          leftType.getFullQualifiedName().getFullQualifiedNameAsString(),
+          rightType.getFullQualifiedName().getFullQualifiedNameAsString());
     }
   }
 
-  private void checkAddSubTypes(final Expression left, final Expression right, final boolean isAdd)
+  private EdmType getAddSubTypeAndCheckLeftAndRight(final Expression left, final Expression right, final boolean isSub)
       throws UriParserException {
     final EdmType leftType = getType(left);
     final EdmType rightType = getType(right);
-    if (leftType == null || rightType == null
-        || isType(left,
+    if (leftType == null || rightType == null) {
+      return null;
+    }
+    if (isType(leftType,
             EdmPrimitiveTypeKind.Int16, EdmPrimitiveTypeKind.Int32, EdmPrimitiveTypeKind.Int64,
             EdmPrimitiveTypeKind.Byte, EdmPrimitiveTypeKind.SByte,
             EdmPrimitiveTypeKind.Decimal, EdmPrimitiveTypeKind.Single, EdmPrimitiveTypeKind.Double)
-        && isType(right,
+        && isType(rightType,
             EdmPrimitiveTypeKind.Int16, EdmPrimitiveTypeKind.Int32, EdmPrimitiveTypeKind.Int64,
             EdmPrimitiveTypeKind.Byte, EdmPrimitiveTypeKind.SByte,
             EdmPrimitiveTypeKind.Decimal, EdmPrimitiveTypeKind.Single, EdmPrimitiveTypeKind.Double)) {
-      return;
+      // The result type must be able to handle the overflow,
+      // so we return always a wider type than the types of the operands.
+      if (isType(leftType, EdmPrimitiveTypeKind.Decimal, EdmPrimitiveTypeKind.Single, EdmPrimitiveTypeKind.Double)
+          || isType(rightType,
+              EdmPrimitiveTypeKind.Decimal, EdmPrimitiveTypeKind.Single, EdmPrimitiveTypeKind.Double)) {
+        return odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Double);
+      } else if (isType(leftType, EdmPrimitiveTypeKind.Int64) || isType(rightType, EdmPrimitiveTypeKind.Int64)) {
+        return odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Decimal);
+      } else if (isType(leftType, EdmPrimitiveTypeKind.Int32) || isType(rightType, EdmPrimitiveTypeKind.Int32)) {
+        return odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Int64);
+      } else if (isType(leftType, EdmPrimitiveTypeKind.Int16) || isType(rightType, EdmPrimitiveTypeKind.Int16)) {
+        return odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Int32);
+      } else {
+        return odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Int16);
+      }
     }
-    if (isType(left, EdmPrimitiveTypeKind.DateTimeOffset)
-        && (isType(right, EdmPrimitiveTypeKind.Duration)
-        || isType(right, EdmPrimitiveTypeKind.DateTimeOffset) && !isAdd)) {
-      return;
+    if ((isType(leftType, EdmPrimitiveTypeKind.DateTimeOffset)
+        || isType(leftType, EdmPrimitiveTypeKind.Duration))
+        && isType(rightType, EdmPrimitiveTypeKind.Duration)) {
+      return leftType;
     }
-    if (isType(left, EdmPrimitiveTypeKind.Duration) && isType(right, EdmPrimitiveTypeKind.Duration)
-        || isType(left, EdmPrimitiveTypeKind.Date)
-        && (isType(right, EdmPrimitiveTypeKind.Duration) || isType(right, EdmPrimitiveTypeKind.Date) && !isAdd)) {
-      return;
+    if (isType(leftType, EdmPrimitiveTypeKind.Date) && isType(rightType, EdmPrimitiveTypeKind.Duration)) {
+      return odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.DateTimeOffset);
+    }
+    if (isSub
+        && (isType(leftType, EdmPrimitiveTypeKind.DateTimeOffset)
+            && isType(rightType, EdmPrimitiveTypeKind.DateTimeOffset)
+            || isType(leftType, EdmPrimitiveTypeKind.Date)
+            && isType(rightType, EdmPrimitiveTypeKind.Date))) {
+      return odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Duration);
     }
     throw new UriParserSemanticException("Incompatible types.",
-        UriParserSemanticException.MessageKeys.UNKNOWN_TYPE, ""); // TODO: better message
+        UriParserSemanticException.MessageKeys.TYPES_NOT_COMPATIBLE,
+        leftType.getFullQualifiedName().getFullQualifiedNameAsString(),
+        rightType.getFullQualifiedName().getFullQualifiedNameAsString());
   }
 
   private void checkStructuredTypeFilter(final EdmType type, final EdmType filterType)
       throws UriParserException {
-    if (!(filterType instanceof EdmStructuredType && ((EdmStructuredType)filterType).compatibleTo(type))) {
+    if (!(filterType instanceof EdmStructuredType && ((EdmStructuredType) filterType).compatibleTo(type))) {
       throw new UriParserSemanticException("Incompatible type filter.",
           UriParserSemanticException.MessageKeys.INCOMPATIBLE_TYPE_FILTER,
           filterType.getFullQualifiedName().getFullQualifiedNameAsString());

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8925274c/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/FilterParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/FilterParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/FilterParser.java
index e2767a1..dd73009 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/FilterParser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/FilterParser.java
@@ -21,6 +21,7 @@ package org.apache.olingo.server.core.uri.parser;
 import java.util.Collection;
 
 import org.apache.olingo.commons.api.edm.Edm;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
 import org.apache.olingo.commons.api.edm.EdmType;
 import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.uri.queryoption.FilterOption;
@@ -43,7 +44,13 @@ public class FilterParser {
       throws UriParserException, UriValidationException {
     final Expression filterExpression = new ExpressionParser(edm, odata)
         .parse(tokenizer, referencedType, crossjoinEntitySetNames);
-    // TODO: Check that the expression is boolean.
-    return new FilterOptionImpl().setExpression(filterExpression);
+    final EdmType type = ExpressionParser.getType(filterExpression);
+    if (type == null || type.equals(odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Boolean))) {
+      return new FilterOptionImpl().setExpression(filterExpression);
+    } else {
+      throw new UriParserSemanticException("Filter expressions must be boolean.",
+          UriParserSemanticException.MessageKeys.TYPES_NOT_COMPATIBLE,
+          "Edm.Boolean", type.getFullQualifiedName().getFullQualifiedNameAsString());
+    }
   }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8925274c/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 47efda5..3125fa6 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,18 +18,11 @@
  */
 package org.apache.olingo.server.core.uri.parser;
 
+import java.util.ArrayDeque;
+import java.util.Deque;
 import java.util.List;
 
-import org.antlr.v4.runtime.ANTLRInputStream;
-import org.antlr.v4.runtime.BailErrorStrategy;
-import org.antlr.v4.runtime.CommonTokenStream;
-import org.antlr.v4.runtime.Lexer;
-import org.antlr.v4.runtime.ParserRuleContext;
-import org.antlr.v4.runtime.RecognitionException;
-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.edm.EdmEntitySet;
 import org.apache.olingo.commons.api.edm.EdmStructuredType;
 import org.apache.olingo.commons.api.edm.EdmType;
@@ -52,14 +45,10 @@ 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.ExpandItemsEOFContext;
 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;
-import org.apache.olingo.server.core.uri.queryoption.ExpandOptionImpl;
 import org.apache.olingo.server.core.uri.queryoption.FormatOptionImpl;
 import org.apache.olingo.server.core.uri.queryoption.IdOptionImpl;
 import org.apache.olingo.server.core.uri.queryoption.SkipOptionImpl;
@@ -77,8 +66,6 @@ public class Parser {
   private final Edm edm;
   private final OData odata;
 
-  private enum ParserEntryRules { ExpandItems }
-
   public Parser(final Edm edm, final OData odata) {
     this.edm = edm;
     this.odata = odata;
@@ -87,8 +74,9 @@ public class Parser {
   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);
+    UriInfoImpl contextUriInfo = new UriInfoImpl();
+    Deque<EdmType> contextTypes = new ArrayDeque<EdmType>();
+    boolean contextIsCollection = false;
 
     final List<String> pathSegmentsDecoded = UriDecoder.splitAndDecodePath(path);
     final int numberOfSegments = pathSegmentsDecoded.size();
@@ -98,49 +86,46 @@ public class Parser {
 
     if (firstSegment.isEmpty()) {
       ensureLastSegment(firstSegment, 0, numberOfSegments);
-      context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.service);
+      contextUriInfo.setKind(UriInfoKind.service);
 
     } else if (firstSegment.equals("$batch")) {
       ensureLastSegment(firstSegment, 1, numberOfSegments);
-      context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.batch);
+      contextUriInfo.setKind(UriInfoKind.batch);
 
     } else if (firstSegment.equals("$metadata")) {
       ensureLastSegment(firstSegment, 1, numberOfSegments);
-      context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.metadata);
-      context.contextUriInfo.setFragment(fragment);
+      contextUriInfo.setKind(UriInfoKind.metadata);
+      contextUriInfo.setFragment(fragment);
 
     } else if (firstSegment.equals("$all")) {
       ensureLastSegment(firstSegment, 1, numberOfSegments);
-      context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.all);
+      contextUriInfo.setKind(UriInfoKind.all);
       // This loads nearly the whole schema, but sooner or later '$all' needs all entity sets anyway.
       for (final EdmEntitySet entitySet : edm.getEntityContainer().getEntitySets()) {
-        context.contextTypes.push(entitySet.getEntityType());
+        contextTypes.push(entitySet.getEntityType());
       }
-      context.isCollection = true;
+      contextIsCollection = true;
 
     } else if (firstSegment.equals("$entity")) {
       if (numberOfSegments > 1) {
         final String typeCastSegment = pathSegmentsDecoded.get(1);
         ensureLastSegment(typeCastSegment, 2, numberOfSegments);
-        context.contextUriInfo = new ResourcePathParser(edm).parseDollarEntityTypeCast(typeCastSegment);
-        context.contextTypes.push(context.contextUriInfo.getEntityTypeCast());
+        contextUriInfo = new ResourcePathParser(edm).parseDollarEntityTypeCast(typeCastSegment);
+        contextTypes.push(contextUriInfo.getEntityTypeCast());
       } else {
-        context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.entityId);
+        contextUriInfo.setKind(UriInfoKind.entityId);
         // The type of the entity is not known until the $id query option has been parsed.
+        // TODO: Set the type (needed for the evaluation of system query options).
       }
-      context.isCollection = false;
+      contextIsCollection = false;
 
     } else if (firstSegment.startsWith("$crossjoin")) {
       ensureLastSegment(firstSegment, 1, numberOfSegments);
-      context.contextUriInfo = new ResourcePathParser(edm).parseCrossjoinSegment(firstSegment);
-      final EdmEntityContainer container = edm.getEntityContainer();
-      for (final String name : context.contextUriInfo.getEntitySetNames()) {
-        context.contextTypes.push(container.getEntitySet(name).getEntityType());
-      }
-      context.isCollection = true;
+      contextUriInfo = new ResourcePathParser(edm).parseCrossjoinSegment(firstSegment);
+      contextIsCollection = true;
 
     } else {
-      context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.resource);
+      contextUriInfo.setKind(UriInfoKind.resource);
       final ResourcePathParser resourcePathParser = new ResourcePathParser(edm);
       int count = 0;
       UriResource lastSegment = null;
@@ -168,7 +153,7 @@ public class Parser {
           } else {
             lastSegment = segment;
           }
-          context.contextUriInfo.addResourcePart(segment);
+          contextUriInfo.addResourcePart(segment);
         }
       }
 
@@ -176,9 +161,9 @@ public class Parser {
         final UriResourcePartTyped typed = (UriResourcePartTyped) lastSegment;
         final EdmType type = ParserHelper.getTypeInformation(typed);
         if (type != null) { // could be null for, e.g., actions without return type
-          context.contextTypes.push(type);
+          contextTypes.push(type);
         }
-        context.isCollection = typed.isCollection();
+        contextIsCollection = typed.isCollection();
       }
     }
 
@@ -191,9 +176,10 @@ public class Parser {
         SystemQueryOption systemOption = null;
         if (optionName.equals(SystemQueryOptionKind.FILTER.toString())) {
           UriTokenizer filterTokenizer = new UriTokenizer(optionValue);
-          // The Referring type could also be a primitive type not only a structured type
-          systemOption = new FilterParser(edm, odata).parse(filterTokenizer, context.contextTypes.peek(),
-                  context.contextUriInfo.getEntitySetNames());
+          // The referring type could be a primitive type or a structured type.
+          systemOption = new FilterParser(edm, odata).parse(filterTokenizer,
+              contextTypes.peek(),
+              contextUriInfo.getEntitySetNames());
           checkOptionEOF(filterTokenizer, optionName, optionValue);
 
         } else if (optionName.equals(SystemQueryOptionKind.FORMAT.toString())) {
@@ -211,19 +197,26 @@ public class Parser {
           systemOption = formatOption;
 
         } else if (optionName.equals(SystemQueryOptionKind.EXPAND.toString())) {
-          try {
-            ExpandItemsEOFContext ctxExpandItems =
-                (ExpandItemsEOFContext) parseRule(optionValue, ParserEntryRules.ExpandItems);
-            systemOption = (ExpandOptionImpl) uriParseTreeVisitor.visitExpandItemsEOF(ctxExpandItems);
-          } catch (final ParseCancellationException e) {
-            throw e.getCause() instanceof UriParserException ?
-                (UriParserException) e.getCause() :
-                new UriParserSyntaxException("Syntax error", e, UriParserSyntaxException.MessageKeys.SYNTAX);
+          if (contextTypes.peek() instanceof EdmStructuredType
+              || !contextUriInfo.getEntitySetNames().isEmpty()
+              || contextUriInfo.getKind() == UriInfoKind.entityId) { // TODO: Remove once the type has been set above.
+            UriTokenizer expandTokenizer = new UriTokenizer(optionValue);
+            systemOption = new ExpandParser(edm, odata).parse(expandTokenizer,
+                contextTypes.peek() instanceof EdmStructuredType ? (EdmStructuredType) contextTypes.peek() : null);
+            checkOptionEOF(expandTokenizer, optionName, optionValue);
+          } else {
+            throw new UriValidationException("Expand is only allowed on structured types!",
+                UriValidationException.MessageKeys.SYSTEM_QUERY_OPTION_NOT_ALLOWED, optionName);
           }
 
         } else if (optionName.equals(SystemQueryOptionKind.ID.toString())) {
           IdOptionImpl idOption = new IdOptionImpl();
           idOption.setText(optionValue);
+          if (optionValue == null || optionValue.isEmpty()) {
+            throw new UriParserSyntaxException("Illegal value of $id option!",
+                UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION,
+                optionName, optionValue);
+          }
           idOption.setValue(optionValue);
           systemOption = idOption;
 
@@ -234,10 +227,8 @@ public class Parser {
         } else if (optionName.equals(SystemQueryOptionKind.ORDERBY.toString())) {
           UriTokenizer orderByTokenizer = new UriTokenizer(optionValue);
           systemOption = new OrderByParser(edm, odata).parse(orderByTokenizer,
-              context.contextTypes.peek() instanceof EdmStructuredType ?
-                  (EdmStructuredType) context.contextTypes.peek() :
-                  null,
-                  context.contextUriInfo.getEntitySetNames());
+              contextTypes.peek() instanceof EdmStructuredType ? (EdmStructuredType) contextTypes.peek() : null,
+              contextUriInfo.getEntitySetNames());
           checkOptionEOF(orderByTokenizer, optionName, optionValue);
 
         } else if (optionName.equals(SystemQueryOptionKind.SEARCH.toString())) {
@@ -246,40 +237,31 @@ public class Parser {
         } else if (optionName.equals(SystemQueryOptionKind.SELECT.toString())) {
           UriTokenizer selectTokenizer = new UriTokenizer(optionValue);
           systemOption = new SelectParser(edm).parse(selectTokenizer,
-              context.contextTypes.peek() instanceof EdmStructuredType ?
-                  (EdmStructuredType) context.contextTypes.peek() :
-                  null,
-              context.isCollection);
+              contextTypes.peek() instanceof EdmStructuredType ? (EdmStructuredType) contextTypes.peek() : null,
+              contextIsCollection);
           checkOptionEOF(selectTokenizer, optionName, optionValue);
 
         } else if (optionName.equals(SystemQueryOptionKind.SKIP.toString())) {
           SkipOptionImpl skipOption = new SkipOptionImpl();
           skipOption.setText(optionValue);
-          try {
-            skipOption.setValue(Integer.parseInt(optionValue));
-          } catch (final NumberFormatException e) {
-            throw new UriParserSyntaxException("Illegal value of $skip option!", e,
-                UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION,
-                optionName, optionValue);
-          }
+          skipOption.setValue(ParserHelper.parseNonNegativeInteger(optionName, optionValue, true));
           systemOption = skipOption;
 
         } else if (optionName.equals(SystemQueryOptionKind.SKIPTOKEN.toString())) {
           SkipTokenOptionImpl skipTokenOption = new SkipTokenOptionImpl();
           skipTokenOption.setText(optionValue);
+          if (optionValue == null || optionValue.isEmpty()) {
+            throw new UriParserSyntaxException("Illegal value of $skiptoken option!",
+                UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION,
+                optionName, optionValue);
+          }
           skipTokenOption.setValue(optionValue);
           systemOption = skipTokenOption;
 
         } else if (optionName.equals(SystemQueryOptionKind.TOP.toString())) {
           TopOptionImpl topOption = new TopOptionImpl();
           topOption.setText(optionValue);
-          try {
-            topOption.setValue(Integer.parseInt(optionValue));
-          } catch (final NumberFormatException e) {
-            throw new UriParserSyntaxException("Illegal value of $top option!", e,
-                UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION,
-                optionName, optionValue);
-          }
+          topOption.setValue(ParserHelper.parseNonNegativeInteger(optionName, optionValue, true));
           systemOption = topOption;
 
         } else if (optionName.equals(SystemQueryOptionKind.COUNT.toString())) {
@@ -299,14 +281,14 @@ public class Parser {
               UriParserSyntaxException.MessageKeys.UNKNOWN_SYSTEM_QUERY_OPTION, optionName);
         }
         try {
-          context.contextUriInfo.setSystemQueryOption(systemOption);
+          contextUriInfo.setSystemQueryOption(systemOption);
         } catch (final ODataRuntimeException e) {
           throw new UriParserSyntaxException("Double system query option!", e,
               UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION, optionName);
         }
 
       } else if (optionName.startsWith(AT)) {
-        if (context.contextUriInfo.getAlias(optionName) == null) {
+        if (contextUriInfo.getAlias(optionName) == null) {
           // TODO: Create a proper alias-value parser that can parse also common expressions.
           Expression expression = null;
           UriTokenizer aliasTokenizer = new UriTokenizer(optionValue);
@@ -318,13 +300,13 @@ public class Parser {
           } else {
             UriTokenizer aliasValueTokenizer = new UriTokenizer(optionValue);
             expression = new ExpressionParser(edm, odata).parse(aliasValueTokenizer, null,
-                context.contextUriInfo.getEntitySetNames());
+                contextUriInfo.getEntitySetNames());
             if (!aliasValueTokenizer.next(TokenKind.EOF)) {
               throw new UriParserSyntaxException("Illegal value for alias '" + optionName + "'.",
                   UriParserSyntaxException.MessageKeys.SYNTAX);
             }
           }
-          context.contextUriInfo.addAlias((AliasQueryOption) new AliasQueryOptionImpl()
+          contextUriInfo.addAlias((AliasQueryOption) new AliasQueryOptionImpl()
               .setAliasValue(expression)
               .setName(optionName)
               .setText(NULL.equals(optionValue) ? null : optionValue));
@@ -334,11 +316,11 @@ public class Parser {
         }
 
       } else {
-        context.contextUriInfo.addCustomQueryOption((CustomQueryOption) option);
+        contextUriInfo.addCustomQueryOption((CustomQueryOption) option);
       }
     }
 
-    return context.contextUriInfo;
+    return contextUriInfo;
   }
 
   private void ensureLastSegment(final String segment, final int pos, final int size)
@@ -362,102 +344,4 @@ public class Parser {
           optionName, optionValue);
     }
   }
-
-  private ParserRuleContext parseRule(final String input, final ParserEntryRules entryPoint)
-      throws UriParserSyntaxException {
-    UriParserParser parser = null;
-    UriLexer lexer = null;
-    ParserRuleContext ret = null;
-
-    // Use 2 stage approach to improve performance
-    // see https://github.com/antlr/antlr4/issues/192
-
-    // stage = 1
-    try {
-
-      // create parser
-      lexer = new UriLexer(new ANTLRInputStream(input));
-      parser = new UriParserParser(new CommonTokenStream(lexer));
-
-      // Set error strategy
-      addStage1ErrorStrategy(parser);
-
-      // Set error collector
-      addStage1ErrorListener(parser);
-
-      // user the faster LL parsing
-      parser.getInterpreter().setPredictionMode(PredictionMode.SLL);
-
-      // parse
-      switch (entryPoint) {
-      case ExpandItems:
-        lexer.mode(Lexer.DEFAULT_MODE);
-        ret = parser.expandItemsEOF();
-        break;
-      default:
-        break;
-
-      }
-
-    } catch (ParseCancellationException hardException) {
-      // stage = 2
-      try {
-
-        // create parser
-        lexer = new UriLexer(new ANTLRInputStream(input));
-        parser = new UriParserParser(new CommonTokenStream(lexer));
-
-        // Set error strategy
-        addStage2ErrorStrategy(parser);
-
-        // Set error collector
-        addStage2ErrorListener(parser);
-
-        // Use the slower SLL parsing
-        parser.getInterpreter().setPredictionMode(PredictionMode.LL);
-
-        // parse
-        switch (entryPoint) {
-        case ExpandItems:
-          lexer.mode(Lexer.DEFAULT_MODE);
-          ret = parser.expandItemsEOF();
-          break;
-        default:
-          break;
-        }
-
-      } catch (final RecognitionException weakException) {
-        throw new UriParserSyntaxException("Error in syntax", weakException,
-            UriParserSyntaxException.MessageKeys.SYNTAX);
-
-        // exceptionOnStage = 2;
-      }
-    } catch (final RecognitionException hardException) {
-      throw new UriParserSyntaxException("Error in syntax", hardException,
-          UriParserSyntaxException.MessageKeys.SYNTAX);
-    }
-
-    return ret;
-  }
-
-  protected void addStage1ErrorStrategy(final UriParserParser parser) {
-    // Throw exception at first syntax error
-    parser.setErrorHandler(new BailErrorStrategy());
-
-  }
-
-  protected void addStage2ErrorStrategy(final UriParserParser parser) {
-    // Throw exception at first syntax error
-    parser.setErrorHandler(new BailErrorStrategy());
-  }
-
-  protected void addStage1ErrorListener(final UriParserParser parser) {
-    // No error logging to System.out or System.err, only exceptions used (depending on ErrorStrategy)
-    parser.removeErrorListeners();
-  }
-
-  protected void addStage2ErrorListener(final UriParserParser parser) {
-    // No error logging to System.out or System.err, only exceptions used (depending on ErrorStrategy)
-    parser.removeErrorListeners();
-  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8925274c/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ParserHelper.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ParserHelper.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ParserHelper.java
index 65ee461..7f4abf7 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ParserHelper.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ParserHelper.java
@@ -23,6 +23,7 @@ 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.EdmEntityType;
 import org.apache.olingo.commons.api.edm.EdmKeyPropertyRef;
 import org.apache.olingo.commons.api.edm.EdmNavigationProperty;
@@ -36,6 +37,8 @@ import org.apache.olingo.commons.api.edm.constants.EdmTypeKind;
 import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.uri.UriParameter;
 import org.apache.olingo.server.api.uri.UriResourcePartTyped;
+import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
+import org.apache.olingo.server.api.uri.queryoption.expression.Literal;
 import org.apache.olingo.server.core.ODataImpl;
 import org.apache.olingo.server.core.uri.UriParameterImpl;
 import org.apache.olingo.server.core.uri.UriResourceTypedImpl;
@@ -88,8 +91,9 @@ public class ParserHelper {
         TokenKind.EnumValue);
   }
 
-  protected static List<UriParameter> parseFunctionParameters(UriTokenizer tokenizer, final boolean withComplex)
-      throws UriParserException {
+  protected static List<UriParameter> parseFunctionParameters(UriTokenizer tokenizer,
+      final Edm edm, final EdmType referringType, final boolean withComplex)
+      throws UriParserException, UriValidationException {
     List<UriParameter> parameters = new ArrayList<UriParameter>();
     ParserHelper.requireNext(tokenizer, TokenKind.OPEN);
     if (tokenizer.next(TokenKind.CLOSE)) {
@@ -115,6 +119,13 @@ public class ParserHelper {
           throw new UriParserSemanticException("A JSON array or object is not allowed as parameter value.",
               UriParserSemanticException.MessageKeys.COMPLEX_PARAMETER_IN_RESOURCE_PATH, tokenizer.getText());
         }
+      } else if (withComplex) {
+        final Expression expression = new ExpressionParser(edm, odata).parse(tokenizer, referringType, null);
+        parameters.add(new UriParameterImpl().setName(name)
+            .setText(expression instanceof Literal ?
+                "null".equals(((Literal) expression).getText()) ? null : ((Literal) expression).getText() :
+                null)
+            .setExpression(expression instanceof Literal ? null : expression));
       } else if (nextPrimitiveValue(tokenizer) == null) {
         throw new UriParserSemanticException("Wrong parameter value.",
             UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE, "");
@@ -387,4 +398,23 @@ public class ParserHelper {
 
     return type;
   }
+
+  protected static int parseNonNegativeInteger(final String optionName, final String optionValue,
+      final boolean zeroAllowed) throws UriParserException {
+    int value;
+    try {
+      value = Integer.parseInt(optionValue);
+    } catch (final NumberFormatException e) {
+      throw new UriParserSyntaxException("Illegal value of '" + optionName + "' option!", e,
+          UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION,
+          optionName, optionValue);
+    }
+    if (value > 0 || value == 0 && zeroAllowed) {
+      return value;
+    } else {
+      throw new UriParserSyntaxException("Illegal value of '" + optionName + "' option!",
+          UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION,
+          optionName, optionValue);
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8925274c/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
index 1cd4d7a..87cb91a 100644
--- 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
@@ -261,30 +261,33 @@ public class ResourcePathParser {
       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) {
-        ParserHelper.requireTokenEnd(tokenizer);
-        return new UriResourceActionImpl(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());
+    final UriResourcePartTyped previousTyped = (UriResourcePartTyped) previous;
+    final EdmType previousTypeFilter = getPreviousTypeFilter(previousTyped);
+    final EdmType previousType = previousTypeFilter == null ? previousTyped.getType() : previousTypeFilter;
+
+    // We check for bound actions first because they cannot be followed by anything.
+    final EdmAction boundAction =
+        edm.getBoundAction(name, previousType.getFullQualifiedName(), previousTyped.isCollection());
+    if (boundAction != null) {
+      ParserHelper.requireTokenEnd(tokenizer);
+      return new UriResourceActionImpl(boundAction);
+    }
+
+    // Type casts can be syntactically indistinguishable from bound function calls in the case of additional keys.
+    // But normally they are shorter, so they come next.
+    final EdmStructuredType type = previousTyped.getType() instanceof EdmEntityType ?
+        edm.getEntityType(name) :
+        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());
+    }
+
+    // Now a bound function call is the only remaining option.
+    return functionCall(null, name, previousType.getFullQualifiedName(), previousTyped.isCollection());
   }
 
   private void requireTyped(final UriResource previous, final String forWhat) throws UriParserException {
@@ -317,8 +320,13 @@ public class ResourcePathParser {
           ((UriResourceWithKeysImpl) previousTyped).setEntryTypeFilter(type);
         }
         if (tokenizer.next(TokenKind.OPEN)) {
-          ((UriResourceWithKeysImpl) previousTyped).setKeyPredicates(
-              ParserHelper.parseKeyPredicate(tokenizer, (EdmEntityType) type, null));
+          final List<UriParameter> keys = ParserHelper.parseKeyPredicate(tokenizer, (EdmEntityType) type, null);
+          if (previousTyped.isCollection()) {
+            ((UriResourceWithKeysImpl) previousTyped).setKeyPredicates(keys);
+          } else {
+            throw new UriParserSemanticException("Key not allowed here.",
+                UriParserSemanticException.MessageKeys.KEY_NOT_ALLOWED);
+          }
         }
       } else {
         previousTypeFilter = ((UriResourceTypedImpl) previousTyped).getTypeFilter();
@@ -351,7 +359,7 @@ public class ResourcePathParser {
   private UriResource functionCall(final EdmFunctionImport edmFunctionImport,
       final FullQualifiedName boundFunctionName, final FullQualifiedName bindingParameterTypeName,
       final boolean isBindingParameterCollection) throws UriParserException, UriValidationException {
-    final List<UriParameter> parameters = ParserHelper.parseFunctionParameters(tokenizer, false);
+    final List<UriParameter> parameters = ParserHelper.parseFunctionParameters(tokenizer, edm, null, false);
     final List<String> names = ParserHelper.getParameterNames(parameters);
     EdmFunction function = null;
     if (edmFunctionImport != null) {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8925274c/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/SearchParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/SearchParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/SearchParser.java
new file mode 100644
index 0000000..a072327
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/SearchParser.java
@@ -0,0 +1,108 @@
+/*
+ * 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 org.apache.olingo.server.api.uri.queryoption.SearchOption;
+import org.apache.olingo.server.api.uri.queryoption.search.SearchBinaryOperatorKind;
+import org.apache.olingo.server.api.uri.queryoption.search.SearchExpression;
+import org.apache.olingo.server.api.uri.queryoption.search.SearchTerm;
+import org.apache.olingo.server.core.uri.parser.UriTokenizer.TokenKind;
+import org.apache.olingo.server.core.uri.parser.search.SearchBinaryImpl;
+import org.apache.olingo.server.core.uri.parser.search.SearchParserException;
+import org.apache.olingo.server.core.uri.parser.search.SearchTermImpl;
+import org.apache.olingo.server.core.uri.parser.search.SearchUnaryImpl;
+import org.apache.olingo.server.core.uri.queryoption.SearchOptionImpl;
+
+/**
+ * Parses search expressions according to the following (rewritten) grammar:
+ * <pre>
+ * SearchExpr  ::= ExprOR
+ * ExprOR      ::= ExprAnd ('OR' ExprAnd)*
+ * ExprAnd     ::= Term ('AND'? Term)*
+ * Term        ::= ('NOT'? (Word | Phrase)) | ('(' SearchExpr ')')
+ * </pre> 
+ */
+public class SearchParser {
+
+  public SearchOption parse(UriTokenizer tokenizer) throws SearchParserException {
+    SearchOptionImpl searchOption = new SearchOptionImpl();
+    searchOption.setSearchExpression(processExprOr(tokenizer));
+    return searchOption;
+  }
+
+  private SearchExpression processExprOr(UriTokenizer tokenizer) throws SearchParserException {
+    SearchExpression left = processExprAnd(tokenizer);
+
+    while (tokenizer.next(TokenKind.OrOperatorSearch)) {
+      final SearchExpression right = processExprAnd(tokenizer);
+      left = new SearchBinaryImpl(left, SearchBinaryOperatorKind.OR, right);
+    }
+
+    return left;
+  }
+
+  private SearchExpression processExprAnd(UriTokenizer tokenizer) throws SearchParserException {
+    SearchExpression left = processTerm(tokenizer);
+
+    while (tokenizer.next(TokenKind.AndOperatorSearch)) { // Could be whitespace or whitespace-surrounded 'AND'.
+      final SearchExpression right = processTerm(tokenizer);
+      left = new SearchBinaryImpl(left, SearchBinaryOperatorKind.AND, right);
+    }
+
+    return left;
+  }
+
+  private SearchExpression processTerm(UriTokenizer tokenizer) throws SearchParserException {
+    if (tokenizer.next(TokenKind.OPEN)) {
+      final SearchExpression expr = processExprOr(tokenizer);
+      if (!tokenizer.next(TokenKind.CLOSE)) {
+        throw new SearchParserException("Missing close parenthesis after open parenthesis.",
+            SearchParserException.MessageKeys.MISSING_CLOSE);
+      }
+      return expr;
+    } else if (tokenizer.next(TokenKind.NotOperatorSearch)) {
+      return processNot(tokenizer);
+    } else if (tokenizer.next(TokenKind.Word)) {
+      return new SearchTermImpl(tokenizer.getText());
+    } else if (tokenizer.next(TokenKind.Phrase)) {
+      return processPhrase(tokenizer);
+    } else {
+      throw new SearchParserException("Expected PHRASE or WORD not found.",
+          SearchParserException.MessageKeys.EXPECTED_DIFFERENT_TOKEN, "PHRASE, WORD", "");
+    }
+  }
+
+  private SearchExpression processNot(UriTokenizer tokenizer) throws SearchParserException {
+    if (tokenizer.next(TokenKind.Word)) {
+      return new SearchUnaryImpl(new SearchTermImpl(tokenizer.getText()));
+    } else if (tokenizer.next(TokenKind.Phrase)) {
+      return new SearchUnaryImpl(processPhrase(tokenizer));
+    } else {
+      throw new SearchParserException("NOT must be followed by a term.",
+          SearchParserException.MessageKeys.INVALID_NOT_OPERAND, "");
+    }
+  }
+
+  private SearchTerm processPhrase(UriTokenizer tokenizer) {
+    final String literal = tokenizer.getText();
+    return new SearchTermImpl(literal.substring(1, literal.length() - 1)
+        .replace("\\\"", "\"")
+        .replace("\\\\", "\\"));
+  }
+}