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 2014/10/02 14:55:36 UTC

[2/3] git commit: better segment handling in server URI parser

better segment handling in server URI parser

Change-Id: Id9b20d66f878c44c3d60cc5cfc2214d3692e1603

Signed-off-by: Christian Amend <ch...@apache.org>


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

Branch: refs/heads/master
Commit: aaa0916188b4424f804b0c58123e77776af49fcc
Parents: 11bee5d
Author: Klaus Straubinger <kl...@sap.com>
Authored: Thu Oct 2 08:47:30 2014 +0200
Committer: Christian Amend <ch...@apache.org>
Committed: Thu Oct 2 14:37:03 2014 +0200

----------------------------------------------------------------------
 .../apache/olingo/server/core/ODataHandler.java |  18 +-
 .../olingo/server/core/uri/parser/Parser.java   | 288 +++++++++----------
 .../server/core/uri/parser/UriDecoder.java      |  66 ++---
 .../uri/parser/UriParserSyntaxException.java    |   7 +-
 .../server-core-exceptions-i18n.properties      |   3 +-
 .../olingo/server/core/uri/RawUriTest.java      |  75 +++--
 .../core/uri/antlr/TestFullResourcePath.java    | 219 +++++++-------
 .../core/uri/antlr/TestUriParserImpl.java       | 145 +++++-----
 .../core/uri/testutil/FilterValidator.java      |  64 ++---
 .../core/uri/testutil/ResourceValidator.java    |   8 +-
 .../core/uri/testutil/TestUriValidator.java     |  38 +--
 .../core/uri/validator/UriValidatorTest.java    |  80 +++---
 12 files changed, 482 insertions(+), 529 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/aaa09161/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 fed47a7..5527607 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
@@ -90,9 +90,6 @@ public class ODataHandler {
       handleException(request, response, serverError, null);
     } catch (ODataHandlerException e) {
       ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null);
-      handleException(request, response, serverError, null);
-    } catch (ODataTranslatedException e) {
-      ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null);
       handleException(request, response, serverError, requestedContentType);
     } catch (ODataApplicationException e) {
       ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e);
@@ -106,14 +103,12 @@ public class ODataHandler {
 
   private void processInternal(final ODataRequest request, ContentType requestedContentType,
       final ODataResponse response)
-      throws ODataTranslatedException, UriParserException, UriValidationException, ContentNegotiatorException,
+      throws ODataHandlerException, UriParserException, UriValidationException, ContentNegotiatorException,
       ODataApplicationException {
     validateODataVersion(request, response);
 
     Parser parser = new Parser();
-    String odUri =
-        request.getRawODataPath() + (request.getRawQueryPath() == null ? "" : "?" + request.getRawQueryPath());
-    UriInfo uriInfo = parser.parseUri(odUri, edm);
+    final UriInfo uriInfo = parser.parseUri(request.getRawODataPath(), request.getRawQueryPath(), null, edm);
 
     UriValidator validator = new UriValidator();
     validator.validate(uriInfo, request.getMethod());
@@ -165,7 +160,7 @@ public class ODataHandler {
   }
 
   private void handleResourceDispatching(final ODataRequest request, final ODataResponse response,
-      final UriInfo uriInfo) throws ODataTranslatedException {
+      final UriInfo uriInfo) throws ODataHandlerException, ContentNegotiatorException {
     int lastPathSegmentIndex = uriInfo.getUriResourceParts().size() - 1;
     UriResource lastPathSegment = uriInfo.getUriResourceParts().get(lastPathSegmentIndex);
     ContentType requestedContentType = null;
@@ -243,7 +238,7 @@ public class ODataHandler {
   }
 
   private void validateODataVersion(final ODataRequest request, final ODataResponse response)
-      throws ODataTranslatedException {
+      throws ODataHandlerException {
     String maxVersion = request.getHeader(HttpHeader.ODATA_MAX_VERSION);
     response.setHeader(HttpHeader.ODATA_VERSION, ODataServiceVersion.V40.toString());
 
@@ -255,8 +250,7 @@ public class ODataHandler {
     }
   }
 
-  private <T extends Processor> T selectProcessor(final Class<T> cls)
-      throws ODataTranslatedException {
+  private <T extends Processor> T selectProcessor(final Class<T> cls) throws ODataHandlerException {
     @SuppressWarnings("unchecked")
     T p = (T) processors.get(cls);
 
@@ -279,4 +273,4 @@ public class ODataHandler {
       }
     }
   }
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/aaa09161/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 450ad2b..a22933f 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
@@ -76,62 +76,58 @@ public class Parser {
     return this;
   }
 
-  public UriInfo parseUri(final String input, final Edm edm) throws UriParserException {
-
-    boolean readQueryParameter = false;
-    boolean readFragment = false;
+  public UriInfo parseUri(final String path, final String query, final String fragment, final Edm edm)
+      throws UriParserException {
 
     UriContext context = new UriContext();
     UriParseTreeVisitor uriParseTreeVisitor = new UriParseTreeVisitor(edm, context);
 
     try {
-      RawUri uri = UriDecoder.decodeUri(input, 0); // -> 0 segments are before the service url
+      final RawUri uri = UriDecoder.decodeUri(path, query, fragment, 0); // -> 0 segments are before the service url
 
       // first, read the decoded path segments
-      String firstSegment = "";
-      if (uri.pathSegmentListDecoded.size() > 0) {
-        firstSegment = uri.pathSegmentListDecoded.get(0);
-      }
+      final String firstSegment = uri.pathSegmentListDecoded.isEmpty() ? "" : uri.pathSegmentListDecoded.get(0);
 
-      if (firstSegment.length() == 0) {
-        readQueryParameter = true;
+      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);
-        readQueryParameter = true;
       } else if (firstSegment.startsWith("$metadata")) {
+        ensureLastSegment(firstSegment, 1, uri.pathSegmentListDecoded.size());
         MetadataEOFContext ctxMetadataEOF =
             (MetadataEOFContext) parseRule(uri.pathSegmentListDecoded.get(0), ParserEntryRules.Metadata);
 
         uriParseTreeVisitor.visitMetadataEOF(ctxMetadataEOF);
-        readQueryParameter = true;
-        readFragment = true;
+
+        context.contextUriInfo.setFragment(uri.fragment);
       } else if (firstSegment.startsWith("$entity")) {
 
         context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.entityId);
         if (uri.pathSegmentListDecoded.size() > 1) {
+          final String typeCastSegment = uri.pathSegmentListDecoded.get(1);
+          ensureLastSegment(typeCastSegment, 2, uri.pathSegmentListDecoded.size());
           EntityEOFContext ctxEntityEOF =
-              (EntityEOFContext) parseRule(uri.pathSegmentListDecoded.get(1), ParserEntryRules.Entity);
+              (EntityEOFContext) parseRule(typeCastSegment, ParserEntryRules.Entity);
           uriParseTreeVisitor.visitEntityEOF(ctxEntityEOF);
-
         }
-        readQueryParameter = true;
 
       } else if (firstSegment.startsWith("$all")) {
+        ensureLastSegment(firstSegment, 1, uri.pathSegmentListDecoded.size());
         AllEOFContext ctxResourcePathEOF =
             (AllEOFContext) parseRule(uri.pathSegmentListDecoded.get(0), ParserEntryRules.All);
 
         uriParseTreeVisitor.visitAllEOF(ctxResourcePathEOF);
-        readQueryParameter = true;
       } else if (firstSegment.startsWith("$crossjoin")) {
+        ensureLastSegment(firstSegment, 1, uri.pathSegmentListDecoded.size());
         CrossjoinEOFContext ctxResourcePathEOF =
             (CrossjoinEOFContext) parseRule(uri.pathSegmentListDecoded.get(0), ParserEntryRules.CrossJoin);
 
         uriParseTreeVisitor.visitCrossjoinEOF(ctxResourcePathEOF);
-        readQueryParameter = true;
       } else {
         List<PathSegmentEOFContext> ctxPathSegments = new ArrayList<PathSegmentEOFContext>();
         for (String pathSegment : uri.pathSegmentListDecoded) {
@@ -155,143 +151,133 @@ public class Parser {
           UriParseTreeVisitor.TypeInformation typeInfo =
               uriParseTreeVisitor.new TypeInformation(myType.type, typed.isCollection());
           context.contextTypes.push(typeInfo);
-
         }
-
-        readQueryParameter = true;
-
       }
 
-      if (readQueryParameter) {
-        // second, read the system query options and the custom query options
-        for (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);
-
-              FilterOptionImpl filterOption =
-                  (FilterOptionImpl) uriParseTreeVisitor.visitFilterExpressionEOF(ctxFilterExpression);
-
-              systemOption = filterOption;
-
-            } else if (option.name.equals(SystemQueryOptionKind.FORMAT.toString())) {
-              FormatOptionImpl formatOption = new FormatOptionImpl();
-              formatOption.setName(option.name);
-              formatOption.setText(option.value);
-              if (option.value.equalsIgnoreCase(ODataFormat.JSON.name())
-                  || option.value.equalsIgnoreCase(ODataFormat.XML.name())
-                  || option.value.equalsIgnoreCase(ODataFormat.ATOM.name())
-                  || isFormatSyntaxValid(option)) {
-                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 (option.name.equals(SystemQueryOptionKind.EXPAND.toString())) {
-              ExpandItemsEOFContext ctxExpandItems =
-                  (ExpandItemsEOFContext) parseRule(option.value, ParserEntryRules.ExpandItems);
-
-              ExpandOptionImpl expandOption =
-                  (ExpandOptionImpl) uriParseTreeVisitor.visitExpandItemsEOF(ctxExpandItems);
-
-              systemOption = expandOption;
-
-            } 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 (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);
-
-              OrderByOptionImpl orderByOption =
-                  (OrderByOptionImpl) uriParseTreeVisitor.visitOrderByEOF(ctxOrderByExpression);
-
-              systemOption = orderByOption;
-            } else if (option.name.equals(SystemQueryOptionKind.SEARCH.toString())) {
-              throw new RuntimeException("System query option '$search' not implemented!");
-            } else if (option.name.equals(SystemQueryOptionKind.SELECT.toString())) {
-              SelectEOFContext ctxSelectEOF =
-                  (SelectEOFContext) parseRule(option.value, ParserEntryRules.Select);
-
-              SelectOptionImpl selectOption =
-                  (SelectOptionImpl) uriParseTreeVisitor.visitSelectEOF(ctxSelectEOF);
-
-              systemOption = selectOption;
-            } 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;
+      // second, read the system query options and the custom query options
+      for (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);
+
+            FilterOptionImpl filterOption =
+                (FilterOptionImpl) uriParseTreeVisitor.visitFilterExpressionEOF(ctxFilterExpression);
+
+            systemOption = filterOption;
+
+          } else if (option.name.equals(SystemQueryOptionKind.FORMAT.toString())) {
+            FormatOptionImpl formatOption = new FormatOptionImpl();
+            formatOption.setName(option.name);
+            formatOption.setText(option.value);
+            if (option.value.equalsIgnoreCase(ODataFormat.JSON.name())
+                || option.value.equalsIgnoreCase(ODataFormat.XML.name())
+                || option.value.equalsIgnoreCase(ODataFormat.ATOM.name())
+                || isFormatSyntaxValid(option.value)) {
+              formatOption.setFormat(option.value);
             } else {
-              throw new UriParserSyntaxException("Unknown system query option!",
-                  UriParserSyntaxException.MessageKeys.UNKNOWN_SYSTEM_QUERY_OPTION, option.name);
+              throw new UriParserSyntaxException("Illegal value of $format option!",
+                  UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION_FORMAT, option.value);
+            }
+            systemOption = formatOption;
+
+          } else if (option.name.equals(SystemQueryOptionKind.EXPAND.toString())) {
+            ExpandItemsEOFContext ctxExpandItems =
+                (ExpandItemsEOFContext) parseRule(option.value, ParserEntryRules.ExpandItems);
+
+            ExpandOptionImpl expandOption =
+                (ExpandOptionImpl) uriParseTreeVisitor.visitExpandItemsEOF(ctxExpandItems);
+
+            systemOption = expandOption;
+
+          } 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 (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);
+
+            OrderByOptionImpl orderByOption =
+                (OrderByOptionImpl) uriParseTreeVisitor.visitOrderByEOF(ctxOrderByExpression);
+
+            systemOption = orderByOption;
+          } else if (option.name.equals(SystemQueryOptionKind.SEARCH.toString())) {
+            throw new RuntimeException("System query option '$search' not implemented!");
+          } else if (option.name.equals(SystemQueryOptionKind.SELECT.toString())) {
+            SelectEOFContext ctxSelectEOF =
+                (SelectEOFContext) parseRule(option.value, ParserEntryRules.Select);
+
+            SelectOptionImpl selectOption =
+                (SelectOptionImpl) uriParseTreeVisitor.visitSelectEOF(ctxSelectEOF);
+
+            systemOption = selectOption;
+          } 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 {
-              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(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 {
-            CustomQueryOptionImpl customOption = new CustomQueryOptionImpl();
-            customOption.setName(option.name);
-            customOption.setText(option.value);
-            context.contextUriInfo.addCustomQueryOption(customOption);
+            throw new UriParserSyntaxException("Unknown system query option!",
+                UriParserSyntaxException.MessageKeys.UNKNOWN_SYSTEM_QUERY_OPTION, option.name);
+          }
+          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);
           }
+        } else {
+          CustomQueryOptionImpl customOption = new CustomQueryOptionImpl();
+          customOption.setName(option.name);
+          customOption.setText(option.value);
+          context.contextUriInfo.addCustomQueryOption(customOption);
         }
       }
 
-      if (readFragment) {
-        context.contextUriInfo.setFragment(uri.fragment);
-      }
-
       return context.contextUriInfo;
     } catch (ParseCancellationException e) {
       throw e.getCause() instanceof UriParserException ?
@@ -300,9 +286,17 @@ public class Parser {
     }
   }
 
-  private boolean isFormatSyntaxValid(RawUri.QueryOption option) {
-    final int index = option.value.indexOf('/');
-    return index > 0 && index < option.value.length() - 1 && index == option.value.lastIndexOf('/');
+  private void ensureLastSegment(final String segment, final int pos, final int size)
+      throws UriParserSyntaxException {
+    if (pos < size) {
+      throw new UriParserSyntaxException(segment + " must be the last segment.",
+          UriParserSyntaxException.MessageKeys.MUST_BE_LAST_SEGMENT, segment);
+    }
+  }
+
+  private boolean isFormatSyntaxValid(final String value) {
+    final int index = value.indexOf('/');
+    return index > 0 && index < value.length() - 1 && index == value.lastIndexOf('/');
   }
 
   private ParserRuleContext parseRule(final String input, final ParserEntryRules entryPoint)

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/aaa09161/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 37ce102..8585edb 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
@@ -19,69 +19,57 @@
 package org.apache.olingo.server.core.uri.parser;
 
 import org.apache.olingo.commons.core.Decoder;
-import org.apache.olingo.server.core.uri.parser.RawUri.QueryOption;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 public class UriDecoder {
 
-  private static final Pattern uriPattern =
-      Pattern.compile("^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?");
-
-  public static RawUri decodeUri(final String uri, final int skipSegments) throws UriParserSyntaxException {
+  public static RawUri decodeUri(final String path, final String query, final String fragment,
+      final int skipSegments) throws UriParserSyntaxException {
     RawUri rawUri = new RawUri();
 
-    Matcher m = uriPattern.matcher(uri);
-    if (m.matches()) {
-      rawUri.scheme = m.group(2);
-      rawUri.authority = m.group(4);
-      rawUri.path = m.group(5);
-      rawUri.queryOptionString = m.group(7);
-      rawUri.fragment = m.group(9);
-    }
+    rawUri.path = path;
+    rawUri.queryOptionString = query;
+    rawUri.fragment = fragment;
 
-    splitPath(rawUri, skipSegments);
-    splitOptions(rawUri);
+    rawUri.pathSegmentList = splitPath(path, skipSegments);
+    rawUri.queryOptionList = splitOptions(query);
     decode(rawUri);
 
     return rawUri;
   }
 
-  private static void decode(final RawUri rawUri) throws UriParserSyntaxException {
+  private static void decode(RawUri rawUri) throws UriParserSyntaxException {
     rawUri.pathSegmentListDecoded = new ArrayList<String>();
     for (String segment : rawUri.pathSegmentList) {
       rawUri.pathSegmentListDecoded.add(decode(segment));
     }
 
-    rawUri.queryOptionListDecoded = new ArrayList<QueryOption>();
-    for (QueryOption optionPair : rawUri.queryOptionList) {
-      rawUri.queryOptionListDecoded.add(new QueryOption(
+    rawUri.queryOptionListDecoded = new ArrayList<RawUri.QueryOption>();
+    for (RawUri.QueryOption optionPair : rawUri.queryOptionList) {
+      rawUri.queryOptionListDecoded.add(new RawUri.QueryOption(
           decode(optionPair.name),
           decode(optionPair.value)));
     }
   }
 
-  private static void splitOptions(final RawUri rawUri) {
-    rawUri.queryOptionList = new ArrayList<RawUri.QueryOption>();
-
-    if (rawUri.queryOptionString == null) {
-      return;
+  private static List<RawUri.QueryOption> splitOptions(final String queryOptionString) {
+    if (queryOptionString == null) {
+      return Collections.<RawUri.QueryOption> emptyList();
     }
 
-    List<String> options = split(rawUri.queryOptionString, '&');
-
-    for (String option : options) {
+    List<RawUri.QueryOption> queryOptionList = new ArrayList<RawUri.QueryOption>();
+    for (String option : split(queryOptionString, '&')) {
       if (option.length() != 0) {
-        List<String> pair = splitFirst(option, '=');
-        rawUri.queryOptionList.add(
-            new RawUri.QueryOption(pair.get(0), pair.get(1)));
+        final List<String> pair = splitFirst(option, '=');
+        queryOptionList.add(new RawUri.QueryOption(pair.get(0), pair.get(1)));
       }
     }
+    return queryOptionList;
   }
 
   private static List<String> splitFirst(final String input, final char c) {
@@ -93,16 +81,16 @@ public class UriDecoder {
     }
   }
 
-  public static void splitPath(final RawUri rawUri, int skipSegments) {
-    List<String> list = split(rawUri.path, '/');
+  private static List<String> splitPath(final String path, int skipSegments) {
+    List<String> list = split(path, '/');
 
-    if (list.get(0).length() == 0) {
-      skipSegments++;
+    // Empty path segments of the resource path are removed.
+    while (list.remove("")) {
+      // this place intentionally left blank
+      ;
     }
 
-    rawUri.pathSegmentList = skipSegments > 0 ?
-        list.subList(skipSegments, list.size()) :
-        list;
+    return skipSegments > 0 ? list.subList(skipSegments, list.size()) : list;
   }
 
   public static List<String> split(final String input, final char c) {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/aaa09161/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParserSyntaxException.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParserSyntaxException.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParserSyntaxException.java
index e5e1955..1d4ce0a 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParserSyntaxException.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParserSyntaxException.java
@@ -24,12 +24,13 @@ public class UriParserSyntaxException extends UriParserException {
   private static final long serialVersionUID = 5887744747812478226L;
 
   public static enum MessageKeys implements MessageKey {
+    /** parameter: segment */ MUST_BE_LAST_SEGMENT,
     /** parameter: query-option name */ UNKNOWN_SYSTEM_QUERY_OPTION,
     /** parameter: query-option name */ DOUBLE_SYSTEM_QUERY_OPTION,
     /** parameters: query-option name, query-option value */ WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION,
-    SYNTAX,
-    SYSTEM_QUERY_OPTION_LEVELS_NOT_ALLOWED_HERE, 
-    /** parameter: $format option value */ WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION_FORMAT;
+    /** parameter: $format option value */ WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION_FORMAT,
+    SYSTEM_QUERY_OPTION_LEVELS_NOT_ALLOWED_HERE,
+    SYNTAX;
 
     @Override
     public String getKey() {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/aaa09161/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 d9fa6f7..540119e 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
@@ -24,12 +24,13 @@ ODataHandlerException.PROCESSOR_NOT_IMPLEMENTED=No processor for interface '%1$s
 ODataHandlerException.FUNCTIONALITY_NOT_IMPLEMENTED=The requested functionality has not been implemented (yet).
 ODataHandlerException.ODATA_VERSION_NOT_SUPPORTED=OData version '%1$s' is not supported.
 
+UriParserSyntaxException.MUST_BE_LAST_SEGMENT=The segment '%1$s' must be the last segment.
 UriParserSyntaxException.UNKNOWN_SYSTEM_QUERY_OPTION=The system query option '%1$s' is not defined.
 UriParserSyntaxException.DOUBLE_SYSTEM_QUERY_OPTION=The system query option '%1$s' can be specified only once.
 UriParserSyntaxException.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION=The system query option '%1$s' has the not-allowed value '%2$s'.
 UriParserSyntaxException.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION_FORMAT=The system query option '$format' must be either 'json', 'xml', 'atom', or a valid content type; the value '%1$s' is neither.
-UriParserSyntaxException.SYNTAX=The URI is malformed.
 UriParserSyntaxException.SYSTEM_QUERY_OPTION_LEVELS_NOT_ALLOWED_HERE=The system query option '$levels' is not allowed here.
+UriParserSyntaxException.SYNTAX=The URI is malformed.
 
 UriParserSemanticException.FUNCTION_NOT_FOUND=The function import '%1$s' has no function with parameters '%2$s'.
 UriParserSemanticException.RESOURCE_PART_ONLY_FOR_TYPED_PARTS='%1$s' is only allowed for typed parts.

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/aaa09161/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/RawUriTest.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/RawUriTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/RawUriTest.java
index 4dc06c0..5e991b0 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/RawUriTest.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/RawUriTest.java
@@ -23,53 +23,54 @@ import org.apache.olingo.server.core.uri.parser.UriDecoder;
 import org.apache.olingo.server.core.uri.parser.UriParserSyntaxException;
 import org.junit.Test;
 
-import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 
 import static org.junit.Assert.assertEquals;
 
 public class RawUriTest {
 
-  private RawUri runRawParser(final String uri, final int skipSegments) throws UriParserSyntaxException {
-    return UriDecoder.decodeUri(uri, skipSegments);
+  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);
+    rawUri = runRawParser("", "", 0);
     checkOptionCount(rawUri, 0);
 
-    rawUri = runRawParser("?a", 0);
+    rawUri = runRawParser("", "a", 0);
     checkOption(rawUri, 0, "a", "");
 
-    rawUri = runRawParser("?a=b", 0);
+    rawUri = runRawParser("", "a=b", 0);
     checkOption(rawUri, 0, "a", "b");
 
-    rawUri = runRawParser("?=", 0);
+    rawUri = runRawParser("", "=", 0);
     checkOption(rawUri, 0, "", "");
 
-    rawUri = runRawParser("?=b", 0);
+    rawUri = runRawParser("", "=b", 0);
     checkOption(rawUri, 0, "", "b");
 
-    rawUri = runRawParser("?a&c", 0);
+    rawUri = runRawParser("", "a&c", 0);
     checkOption(rawUri, 0, "a", "");
     checkOption(rawUri, 1, "c", "");
 
-    rawUri = runRawParser("?a=b&c", 0);
+    rawUri = runRawParser("", "a=b&c", 0);
     checkOption(rawUri, 0, "a", "b");
     checkOption(rawUri, 1, "c", "");
 
-    rawUri = runRawParser("?a=b&c=d", 0);
+    rawUri = runRawParser("", "a=b&c=d", 0);
     checkOption(rawUri, 0, "a", "b");
     checkOption(rawUri, 1, "c", "d");
 
-    rawUri = runRawParser("?=&=", 0);
+    rawUri = runRawParser("", "=&=", 0);
     checkOption(rawUri, 0, "", "");
     checkOption(rawUri, 1, "", "");
 
-    rawUri = runRawParser("?=&c=d", 0);
+    rawUri = runRawParser("", "=&c=d", 0);
     checkOption(rawUri, 0, "", "");
     checkOption(rawUri, 1, "c", "d");
   }
@@ -89,40 +90,38 @@ public class RawUriTest {
   public void testPath() throws Exception {
     RawUri rawUri;
 
-    rawUri = runRawParser("http://test.org", 0);
-    checkPath(rawUri, "", new ArrayList<String>());
+    rawUri = runRawParser("", null, 0);
+    checkPath(rawUri, "", Collections.<String> emptyList());
 
-    rawUri = runRawParser("http://test.org/", 0);
-    checkPath(rawUri, "/", Arrays.asList(""));
+    rawUri = runRawParser("/", null, 0);
+    checkPath(rawUri, "/", Collections.<String> emptyList());
 
-    rawUri = runRawParser("http://test.org/entitySet", 0);
+    rawUri = runRawParser("/entitySet", null, 0);
     checkPath(rawUri, "/entitySet", Arrays.asList("entitySet"));
 
-    rawUri = runRawParser("http://test.org/nonServiceSegment/entitySet", 0);
-    checkPath(rawUri, "/nonServiceSegment/entitySet", Arrays.asList("nonServiceSegment", "entitySet"));
-
-    rawUri = runRawParser("http://test.org/nonServiceSegment/entitySet", 1);
-    checkPath(rawUri, "/nonServiceSegment/entitySet", Arrays.asList("entitySet"));
+    rawUri = runRawParser("//entitySet", null, 0);
+    checkPath(rawUri, "//entitySet", Arrays.asList("entitySet"));
 
-    rawUri = runRawParser("", 0);
-    checkPath(rawUri, "", new ArrayList<String>());
-
-    rawUri = runRawParser("/", 0);
-    checkPath(rawUri, "/", Arrays.asList(""));
+    rawUri = runRawParser("entitySet", null, 0);
+    checkPath(rawUri, "entitySet", Arrays.asList("entitySet"));
 
-    rawUri = runRawParser("/entitySet", 0);
-    checkPath(rawUri, "/entitySet", Arrays.asList("entitySet"));
+    rawUri = runRawParser("/nonServiceSegment/entitySet", null, 0);
+    checkPath(rawUri, "/nonServiceSegment/entitySet", Arrays.asList("nonServiceSegment", "entitySet"));
 
-    rawUri = runRawParser("entitySet", 0);
-    checkPath(rawUri, "entitySet", Arrays.asList("entitySet"));
+    rawUri = runRawParser("/nonServiceSegment/entitySet", null, 1);
+    checkPath(rawUri, "/nonServiceSegment/entitySet", Arrays.asList("entitySet"));
 
-    rawUri = runRawParser("nonServiceSegment/entitySet", 0);
+    rawUri = runRawParser("nonServiceSegment/entitySet", null, 0);
     checkPath(rawUri, "nonServiceSegment/entitySet", Arrays.asList("nonServiceSegment", "entitySet"));
 
-    rawUri = runRawParser("nonServiceSegment/entitySet", 1);
+    rawUri = runRawParser("nonServiceSegment/entitySet", null, 1);
     checkPath(rawUri, "nonServiceSegment/entitySet", Arrays.asList("entitySet"));
 
-    rawUri = runRawParser("http://test.org/a?abc=xx+yz", 0);
+    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
@@ -140,15 +139,13 @@ public class RawUriTest {
 
     assertEquals(list.size(), rawUri.pathSegmentListDecoded.size());
 
-    int i = 0;
-    while (i < list.size()) {
+    for (int i = 0; i < list.size(); i++) {
       assertEquals(list.get(i), rawUri.pathSegmentListDecoded.get(i));
-      i++;
     }
   }
 
   @Test(expected = UriParserSyntaxException.class)
   public void wrongPercentEncoding() throws Exception {
-    runRawParser("%wrong", 0);
+    runRawParser("%wrong", null, 0);
   }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/aaa09161/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 856be6b..1b3a335 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
@@ -901,18 +901,18 @@ public class TestFullResourcePath {
   @Test
   public void runCrossjoinError() throws Exception {
     testUri.runEx("$crossjoin").isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
-    testUri.runEx("$crossjoin/error").isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
+    testUri.runEx("$crossjoin/error").isExSyntax(UriParserSyntaxException.MessageKeys.MUST_BE_LAST_SEGMENT);
     testUri.runEx("$crossjoin()").isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
-    // testUri.runEx("$crossjoin(ESKeyNav, ESTwoKeyNav)/invalid")
-    //     .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
+    testUri.runEx("$crossjoin(ESKeyNav, ESTwoKeyNav)/invalid")
+        .isExSyntax(UriParserSyntaxException.MessageKeys.MUST_BE_LAST_SEGMENT);
   }
 
   @Test
   public void runEntityId() throws Exception {
-    testUri.run("$entity?$id=ESKeyNav(1)")
+    testUri.run("$entity", "$id=ESKeyNav(1)")
         .isKind(UriInfoKind.entityId)
         .isIdText("ESKeyNav(1)");
-    testUri.run("$entity/olingo.odata.test1.ETKeyNav?$id=ESKeyNav(1)")
+    testUri.run("$entity/olingo.odata.test1.ETKeyNav", "$id=ESKeyNav(1)")
         .isKind(UriInfoKind.entityId)
         .isEntityType(EntityTypeProvider.nameETKeyNav)
         .isIdText("ESKeyNav(1)");
@@ -1823,9 +1823,9 @@ public class TestFullResourcePath {
   @Test
   public void runFunctionImpEsAlias() throws Exception {
 
-    testUri.run("FICRTESTwoKeyNavParam(ParameterInt16=@parameterAlias)?@parameterAlias=1");
-    testUri.run("FICRTESTwoKeyNavParam(ParameterInt16=@parameterAlias)/$count?@parameterAlias=1");
-    testUri.run("FICRTESTwoKeyNavParam(ParameterInt16=@invalidAlias)?@validAlias=1");
+    testUri.run("FICRTESTwoKeyNavParam(ParameterInt16=@parameterAlias)", "@parameterAlias=1");
+    testUri.run("FICRTESTwoKeyNavParam(ParameterInt16=@parameterAlias)/$count", "@parameterAlias=1");
+    testUri.run("FICRTESTwoKeyNavParam(ParameterInt16=@invalidAlias)", "@validAlias=1");
   }
 
   @Test
@@ -2062,18 +2062,18 @@ public class TestFullResourcePath {
   @Test
   public void runExpand() throws Exception {
 
-    testUri.run("ESKeyNav(1)?$expand=*")
+    testUri.run("ESKeyNav(1)", "$expand=*")
         .isKind(UriInfoKind.resource).goPath().goExpand()
         .first()
         .isSegmentStar();
 
-    testUri.run("ESKeyNav(1)?$expand=*/$ref")
+    testUri.run("ESKeyNav(1)", "$expand=*/$ref")
         .isKind(UriInfoKind.resource).goPath().goExpand()
         .first()
         .isSegmentStar()
         .isSegmentRef();
 
-    testUri.run("ESKeyNav(1)?$expand=*/$ref,NavPropertyETKeyNavMany")
+    testUri.run("ESKeyNav(1)", "$expand=*/$ref,NavPropertyETKeyNavMany")
         .isKind(UriInfoKind.resource).goPath().goExpand()
         .first()
         .isSegmentStar().isSegmentRef()
@@ -2081,19 +2081,19 @@ public class TestFullResourcePath {
         .goPath().first()
         .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true);
 
-    testUri.run("ESKeyNav(1)?$expand=*($levels=3)")
+    testUri.run("ESKeyNav(1)", "$expand=*($levels=3)")
         .isKind(UriInfoKind.resource).goPath().goExpand()
         .first()
         .isSegmentStar()
         .isLevelText("3");
 
-    testUri.run("ESKeyNav(1)?$expand=*($levels=max)")
+    testUri.run("ESKeyNav(1)", "$expand=*($levels=max)")
         .isKind(UriInfoKind.resource).goPath().goExpand()
         .first()
         .isSegmentStar()
         .isLevelText("max");
 
-    testUri.run("ESKeyNav(1)?$expand=NavPropertyETKeyNavMany/$ref")
+    testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany/$ref")
         .isKind(UriInfoKind.resource).goPath().goExpand()
         .first()
         .goPath().first()
@@ -2101,7 +2101,7 @@ public class TestFullResourcePath {
         .isType(EntityTypeProvider.nameETKeyNav, true)
         .n().isRef();
 
-    testUri.run("ESKeyNav(1)?$expand=NavPropertyETKeyNavOne/$ref")
+    testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavOne/$ref")
         .isKind(UriInfoKind.resource).goPath().goExpand()
         .first()
         .goPath().first()
@@ -2109,7 +2109,7 @@ public class TestFullResourcePath {
         .isType(EntityTypeProvider.nameETKeyNav, false)
         .n().isRef();
 
-    testUri.run("ESKeyNav(1)?$expand=NavPropertyETKeyNavMany/$ref($filter=PropertyInt16 eq 1)")
+    testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany/$ref($filter=PropertyInt16 eq 1)")
         .isKind(UriInfoKind.resource).goPath().goExpand()
         .first()
         .goPath().first()
@@ -2118,7 +2118,7 @@ public class TestFullResourcePath {
         .n().isRef()
         .goUpExpandValidator().isFilterSerialized("<<PropertyInt16> eq <1>>");
 
-    testUri.run("ESKeyNav(1)?$expand=NavPropertyETKeyNavMany/$ref($orderby=PropertyInt16)")
+    testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany/$ref($orderby=PropertyInt16)")
         .isKind(UriInfoKind.resource).goPath().goExpand()
         .first()
         .goPath().first()
@@ -2129,7 +2129,7 @@ public class TestFullResourcePath {
         .isSortOrder(0, false)
         .goOrder(0).goPath().isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
 
-    testUri.run("ESKeyNav(1)?$expand=NavPropertyETKeyNavMany/$ref($skip=1)")
+    testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany/$ref($skip=1)")
         .isKind(UriInfoKind.resource).goPath().goExpand()
         .first()
         .goPath().first()
@@ -2139,7 +2139,7 @@ public class TestFullResourcePath {
         .goUpExpandValidator()
         .isSkipText("1");
 
-    testUri.run("ESKeyNav(1)?$expand=NavPropertyETKeyNavMany/$ref($top=2)")
+    testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany/$ref($top=2)")
         .isKind(UriInfoKind.resource).goPath().goExpand()
         .first()
         .goPath().first()
@@ -2149,7 +2149,7 @@ public class TestFullResourcePath {
         .goUpExpandValidator()
         .isTopText("2");
 
-    testUri.run("ESKeyNav(1)?$expand=NavPropertyETKeyNavMany/$ref($count=true)")
+    testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany/$ref($count=true)")
         .isKind(UriInfoKind.resource).goPath().goExpand()
         .first()
         .goPath().first()
@@ -2159,7 +2159,7 @@ public class TestFullResourcePath {
         .goUpExpandValidator()
         .isInlineCountText("true");
 
-    testUri.run("ESKeyNav(1)?$expand=NavPropertyETKeyNavMany/$ref($skip=1;$top=3)")
+    testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany/$ref($skip=1;$top=3)")
         .isKind(UriInfoKind.resource).goPath().goExpand()
         .first()
         .goPath().first()
@@ -2170,7 +2170,7 @@ public class TestFullResourcePath {
         .isSkipText("1")
         .isTopText("3");
 
-    testUri.run("ESKeyNav(1)?$expand=NavPropertyETKeyNavMany/$ref($skip=1%3b$top=3)")
+    testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany/$ref($skip=1%3b$top=3)")
         .isKind(UriInfoKind.resource).goPath().goExpand()
         .first()
         .goPath().first()
@@ -2181,7 +2181,7 @@ public class TestFullResourcePath {
         .isSkipText("1")
         .isTopText("3");
 
-    testUri.run("ESKeyNav(1)?$expand=NavPropertyETKeyNavMany/$count")
+    testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany/$count")
         .isKind(UriInfoKind.resource).goPath().goExpand()
         .first()
         .goPath().first()
@@ -2189,7 +2189,7 @@ public class TestFullResourcePath {
         .isType(EntityTypeProvider.nameETKeyNav, true)
         .n().isCount();
 
-    testUri.run("ESKeyNav(1)?$expand=NavPropertyETKeyNavOne/$count")
+    testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavOne/$count")
         .isKind(UriInfoKind.resource).goPath().goExpand()
         .first()
         .goPath().first()
@@ -2197,7 +2197,7 @@ public class TestFullResourcePath {
         .isType(EntityTypeProvider.nameETKeyNav, false)
         .n().isCount();
 
-    testUri.run("ESKeyNav(1)?$expand=NavPropertyETKeyNavMany/$count($filter=PropertyInt16 gt 1)")
+    testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany/$count($filter=PropertyInt16 gt 1)")
         .isKind(UriInfoKind.resource).goPath().goExpand()
         .first()
         .goPath().first()
@@ -2207,7 +2207,7 @@ public class TestFullResourcePath {
         .goUpExpandValidator()
         .isFilterSerialized("<<PropertyInt16> gt <1>>");
 
-    testUri.run("ESKeyNav(1)?$expand=NavPropertyETKeyNavMany($filter=PropertyInt16 eq 1)")
+    testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany($filter=PropertyInt16 eq 1)")
         .isKind(UriInfoKind.resource).goPath().goExpand()
         .first()
         .goPath().first()
@@ -2216,7 +2216,7 @@ public class TestFullResourcePath {
         .goUpExpandValidator()
         .isFilterSerialized("<<PropertyInt16> eq <1>>");
 
-    testUri.run("ESKeyNav(1)?$expand=NavPropertyETKeyNavMany($orderby=PropertyInt16)")
+    testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany($orderby=PropertyInt16)")
         .isKind(UriInfoKind.resource).goPath().goExpand()
         .first()
         .goPath().first()
@@ -2226,7 +2226,7 @@ public class TestFullResourcePath {
         .isSortOrder(0, false)
         .goOrder(0).goPath().isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
 
-    testUri.run("ESKeyNav(1)?$expand=NavPropertyETKeyNavMany($skip=1)")
+    testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany($skip=1)")
         .isKind(UriInfoKind.resource).goPath().goExpand()
         .first()
         .goPath().first()
@@ -2235,7 +2235,7 @@ public class TestFullResourcePath {
         .goUpExpandValidator()
         .isSkipText("1");
 
-    testUri.run("ESKeyNav(1)?$expand=NavPropertyETKeyNavMany($top=2)")
+    testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany($top=2)")
         .isKind(UriInfoKind.resource).goPath().goExpand()
         .first()
         .goPath().first()
@@ -2244,7 +2244,7 @@ public class TestFullResourcePath {
         .goUpExpandValidator()
         .isTopText("2");
 
-    testUri.run("ESKeyNav(1)?$expand=NavPropertyETKeyNavMany($count=true)")
+    testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany($count=true)")
         .isKind(UriInfoKind.resource).goPath().goExpand()
         .first()
         .goPath().first()
@@ -2253,7 +2253,7 @@ public class TestFullResourcePath {
         .goUpExpandValidator()
         .isInlineCountText("true");
 
-    testUri.run("ESKeyNav(1)?$expand=NavPropertyETKeyNavMany($select=PropertyString)")
+    testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany($select=PropertyString)")
         .isKind(UriInfoKind.resource).goPath().goExpand()
         .first()
         .goPath().first()
@@ -2263,7 +2263,7 @@ public class TestFullResourcePath {
         .isSelectText("PropertyString")
         .goSelectItem(0).isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
 
-    testUri.run("ESKeyNav(1)?$expand=NavPropertyETKeyNavMany($expand=NavPropertyETTwoKeyNavOne)")
+    testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany($expand=NavPropertyETTwoKeyNavOne)")
         .isKind(UriInfoKind.resource).goPath().goExpand()
         .first()
         .goPath().first()
@@ -2274,7 +2274,7 @@ public class TestFullResourcePath {
         .goPath().first()
         .isNavProperty("NavPropertyETTwoKeyNavOne", EntityTypeProvider.nameETTwoKeyNav, false);
 
-    testUri.run("ESKeyNav(1)?$expand=NavPropertyETKeyNavMany($expand=NavPropertyETKeyNavMany)")
+    testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany($expand=NavPropertyETKeyNavMany)")
         .isKind(UriInfoKind.resource).goPath().goExpand()
         .first()
         .goPath().first()
@@ -2285,7 +2285,7 @@ public class TestFullResourcePath {
         .goPath().first()
         .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true);
 
-    testUri.run("ESKeyNav(1)?$expand=NavPropertyETKeyNavOne($levels=5)")
+    testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavOne($levels=5)")
         .isKind(UriInfoKind.resource).goPath().goExpand()
         .first()
         .goPath().first()
@@ -2294,7 +2294,7 @@ public class TestFullResourcePath {
         .goUpExpandValidator()
         .isLevelText("5");
 
-    testUri.run("ESKeyNav(1)?$expand=NavPropertyETKeyNavMany($select=PropertyString)")
+    testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany($select=PropertyString)")
         .isKind(UriInfoKind.resource).goPath().goExpand()
         .first()
         .goPath().first()
@@ -2304,7 +2304,7 @@ public class TestFullResourcePath {
         .isSelectText("PropertyString")
         .goSelectItem(0).isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
 
-    testUri.run("ESKeyNav(1)?$expand=NavPropertyETKeyNavOne($levels=max)")
+    testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavOne($levels=max)")
         .isKind(UriInfoKind.resource).goPath().goExpand()
         .first()
         .goPath().first()
@@ -2313,7 +2313,7 @@ public class TestFullResourcePath {
         .goUpExpandValidator()
         .isLevelText("max");
 
-    testUri.run("ESKeyNav(1)?$expand=NavPropertyETKeyNavMany($skip=1;$top=2)")
+    testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany($skip=1;$top=2)")
         .isKind(UriInfoKind.resource).goPath().goExpand()
         .first()
         .goPath().first()
@@ -2323,7 +2323,7 @@ public class TestFullResourcePath {
         .isSkipText("1")
         .isTopText("2");
 
-    testUri.run("ESKeyNav(1)?$expand=NavPropertyETKeyNavMany($skip=1%3b$top=2)")
+    testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany($skip=1%3b$top=2)")
         .isKind(UriInfoKind.resource).goPath().goExpand()
         .first()
         .goPath().first()
@@ -2333,7 +2333,7 @@ public class TestFullResourcePath {
         .isSkipText("1")
         .isTopText("2");
 
-    testUri.run("ESTwoKeyNav(PropertyInt16=1,PropertyString='Hugo')?$expand=NavPropertyETKeyNavMany")
+    testUri.run("ESTwoKeyNav(PropertyInt16=1,PropertyString='Hugo')", "$expand=NavPropertyETKeyNavMany")
         .isKind(UriInfoKind.resource).goPath()
         .first()
         .isKeyPredicate(0, "PropertyInt16", "1")
@@ -2344,8 +2344,7 @@ public class TestFullResourcePath {
         .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true)
         .isType(EntityTypeProvider.nameETKeyNav, true);
 
-    testUri.run("ESTwoKeyNav?"
-        + "$expand=olingo.odata.test1.ETBaseTwoKeyNav/NavPropertyETKeyNavMany")
+    testUri.run("ESTwoKeyNav", "$expand=olingo.odata.test1.ETBaseTwoKeyNav/NavPropertyETKeyNavMany")
         .isKind(UriInfoKind.resource).goPath().first()
         .goExpand().first()
         .isExpandStartType(EntityTypeProvider.nameETBaseTwoKeyNav)
@@ -2355,8 +2354,8 @@ public class TestFullResourcePath {
         // .n()
         .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true);
 
-    testUri.run("ESTwoKeyNav(PropertyInt16=1,PropertyString='Hugo')?"
-        + "$expand=olingo.odata.test1.ETBaseTwoKeyNav/NavPropertyETKeyNavMany")
+    testUri.run("ESTwoKeyNav(PropertyInt16=1,PropertyString='Hugo')",
+        "$expand=olingo.odata.test1.ETBaseTwoKeyNav/NavPropertyETKeyNavMany")
         .isKind(UriInfoKind.resource).goPath().first()
         .isKeyPredicate(0, "PropertyInt16", "1")
         .isKeyPredicate(1, "PropertyString", "'Hugo'")
@@ -2368,8 +2367,8 @@ public class TestFullResourcePath {
         // .n()
         .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true);
 
-    testUri.run("ESTwoKeyNav(PropertyInt16=1,PropertyString='2')?"
-        + "$expand=olingo.odata.test1.ETBaseTwoKeyNav/NavPropertyETTwoKeyNavMany")
+    testUri.run("ESTwoKeyNav(PropertyInt16=1,PropertyString='2')",
+        "$expand=olingo.odata.test1.ETBaseTwoKeyNav/NavPropertyETTwoKeyNavMany")
         .isKind(UriInfoKind.resource).goPath().first()
         .isKeyPredicate(0, "PropertyInt16", "1")
         .isKeyPredicate(1, "PropertyString", "'2'")
@@ -2381,8 +2380,9 @@ public class TestFullResourcePath {
         // .n()
         .isNavProperty("NavPropertyETTwoKeyNavMany", EntityTypeProvider.nameETTwoKeyNav, true);
 
-    testUri.run("ESTwoKeyNav(PropertyInt16=1,PropertyString='2')?$expand=olingo.odata.test1.ETBaseTwoKeyNav"
-        + "/NavPropertyETTwoKeyNavMany/olingo.odata.test1.ETTwoBaseTwoKeyNav")
+    testUri.run("ESTwoKeyNav(PropertyInt16=1,PropertyString='2')",
+        "$expand=olingo.odata.test1.ETBaseTwoKeyNav"
+             + "/NavPropertyETTwoKeyNavMany/olingo.odata.test1.ETTwoBaseTwoKeyNav")
         .isKind(UriInfoKind.resource).goPath().first()
         .isKeyPredicate(0, "PropertyInt16", "1")
         .isKeyPredicate(1, "PropertyString", "'2'")
@@ -2395,7 +2395,7 @@ public class TestFullResourcePath {
         .isNavProperty("NavPropertyETTwoKeyNavMany", EntityTypeProvider.nameETTwoKeyNav, true)
         .isTypeFilterOnCollection(EntityTypeProvider.nameETTwoBaseTwoKeyNav);
 
-    testUri.run("ESTwoKeyNav?$expand=olingo.odata.test1.ETBaseTwoKeyNav/PropertyCompNav/NavPropertyETTwoKeyNavOne")
+    testUri.run("ESTwoKeyNav", "$expand=olingo.odata.test1.ETBaseTwoKeyNav/PropertyCompNav/NavPropertyETTwoKeyNavOne")
         .isKind(UriInfoKind.resource).goPath().first()
         .goExpand().first()
         .isExpandStartType(EntityTypeProvider.nameETBaseTwoKeyNav)
@@ -2408,7 +2408,7 @@ public class TestFullResourcePath {
         .n()
         .isNavProperty("NavPropertyETTwoKeyNavOne", EntityTypeProvider.nameETTwoKeyNav, false);
 
-    testUri.run("ESTwoKeyNav?$expand=olingo.odata.test1.ETBaseTwoKeyNav/PropertyCompNav"
+    testUri.run("ESTwoKeyNav", "$expand=olingo.odata.test1.ETBaseTwoKeyNav/PropertyCompNav"
         + "/olingo.odata.test1.CTTwoBasePrimCompNav/NavPropertyETTwoKeyNavOne")
         .isKind(UriInfoKind.resource).goPath().first()
         .goExpand().first()
@@ -2422,7 +2422,7 @@ public class TestFullResourcePath {
         .n()
         .isNavProperty("NavPropertyETTwoKeyNavOne", EntityTypeProvider.nameETTwoKeyNav, false);
 
-    testUri.run("ESKeyNav(1)?$expand=NavPropertyETKeyNavMany/$ref,NavPropertyETTwoKeyNavMany($skip=2;$top=1)")
+    testUri.run("ESKeyNav(1)", "$expand=NavPropertyETKeyNavMany/$ref,NavPropertyETTwoKeyNavMany($skip=2;$top=1)")
         .isKind(UriInfoKind.resource).goPath().first()
         .goExpand().first()
         .goPath()
@@ -2437,7 +2437,7 @@ public class TestFullResourcePath {
         .isSkipText("2")
         .isTopText("1");
 
-    testUri.run("ESTwoKeyNav(PropertyInt16=1,PropertyString='2')?$expand=olingo.odata.test1.ETBaseTwoKeyNav"
+    testUri.run("ESTwoKeyNav(PropertyInt16=1,PropertyString='2')", "$expand=olingo.odata.test1.ETBaseTwoKeyNav"
         + "/NavPropertyETTwoKeyNavMany/olingo.odata.test1.ETTwoBaseTwoKeyNav($select=PropertyString)")
         .isKind(UriInfoKind.resource).goPath()
         .first()
@@ -2455,7 +2455,7 @@ public class TestFullResourcePath {
         .goUpExpandValidator()
         .goSelectItem(0).isPrimitiveProperty("PropertyString", PropertyProvider.nameString, false);
 
-    testUri.run("ESKeyNav?$expand=NavPropertyETKeyNavOne($expand=NavPropertyETKeyNavMany("
+    testUri.run("ESKeyNav", "$expand=NavPropertyETKeyNavOne($expand=NavPropertyETKeyNavMany("
         + "$expand=NavPropertyETKeyNavOne))")
         .isKind(UriInfoKind.resource)
         .goPath().first()
@@ -2474,7 +2474,7 @@ public class TestFullResourcePath {
         .isNavProperty("NavPropertyETKeyNavOne", EntityTypeProvider.nameETKeyNav, false)
         .isType(EntityTypeProvider.nameETKeyNav);
 
-    testUri.run("ESTwoKeyNav(PropertyInt16=1,PropertyString='2')?$select=olingo.odata.test1.ETBaseTwoKeyNav"
+    testUri.run("ESTwoKeyNav(PropertyInt16=1,PropertyString='2')", "$select=olingo.odata.test1.ETBaseTwoKeyNav"
         + "/PropertyInt16")
         .isKind(UriInfoKind.resource).goPath()
         .first()
@@ -2485,7 +2485,7 @@ public class TestFullResourcePath {
         .first()
         .isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
 
-    testUri.run("ESKeyNav?$expand=NavPropertyETKeyNavOne($select=PropertyInt16)")
+    testUri.run("ESKeyNav", "$expand=NavPropertyETKeyNavOne($select=PropertyInt16)")
         .isKind(UriInfoKind.resource)
         .goPath().first()
         .goExpand().first()
@@ -2496,7 +2496,7 @@ public class TestFullResourcePath {
         .isSelectText("PropertyInt16")
         .goSelectItem(0).isPrimitiveProperty("PropertyInt16", PropertyProvider.nameInt16, false);
 
-    testUri.run("ESKeyNav?$expand=NavPropertyETKeyNavOne($select=PropertyComp/PropertyInt16)")
+    testUri.run("ESKeyNav", "$expand=NavPropertyETKeyNavOne($select=PropertyComp/PropertyInt16)")
         .isKind(UriInfoKind.resource)
         .goPath().first()
         .goExpand().first()
@@ -2510,103 +2510,103 @@ public class TestFullResourcePath {
   @Test
   public void runTop() throws Exception {
     // top
-    testUri.run("ESKeyNav?$top=1")
+    testUri.run("ESKeyNav", "$top=1")
         .isKind(UriInfoKind.resource).goPath()
         .isEntitySet("ESKeyNav")
         .isTopText("1");
 
-    testUri.run("ESKeyNav?$top=0")
+    testUri.run("ESKeyNav", "$top=0")
         .isKind(UriInfoKind.resource).goPath()
         .isEntitySet("ESKeyNav")
         .isTopText("0");
 
-    testUri.run("ESKeyNav?$top=-3")
+    testUri.run("ESKeyNav", "$top=-3")
         .isKind(UriInfoKind.resource).goPath()
         .isEntitySet("ESKeyNav")
         .isTopText("-3");
 
-    testUri.runEx("ESKeyNav?$top=undefined")
+    testUri.runEx("ESKeyNav", "$top=undefined")
         .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION);
-    testUri.runEx("ESKeyNav?$top=")
+    testUri.runEx("ESKeyNav", "$top=")
         .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION);
   }
 
   @Test
   public void runFormat() throws Exception {
     // format
-    testUri.run("ESKeyNav(1)?$format=atom")
+    testUri.run("ESKeyNav(1)", "$format=atom")
         .isKind(UriInfoKind.resource).goPath()
         .isFormatText("atom");
-    testUri.run("ESKeyNav(1)?$format=json")
+    testUri.run("ESKeyNav(1)", "$format=json")
         .isKind(UriInfoKind.resource).goPath()
         .isFormatText("json");
-    testUri.run("ESKeyNav(1)?$format=xml")
+    testUri.run("ESKeyNav(1)", "$format=xml")
         .isKind(UriInfoKind.resource).goPath()
         .isFormatText("xml");
-    testUri.run("ESKeyNav(1)?$format=IANA_content_type/must_contain_a_slash")
+    testUri.run("ESKeyNav(1)", "$format=IANA_content_type/must_contain_a_slash")
         .isKind(UriInfoKind.resource).goPath()
         .isFormatText("IANA_content_type/must_contain_a_slash");
-    testUri.run("ESKeyNav(1)?$format=Test_all_valid_signsSpecified_for_format_signs%26-._~$@%27/Aa123%26-._~$@%27")
+    testUri.run("ESKeyNav(1)", "$format=Test_all_valid_signsSpecified_for_format_signs%26-._~$@%27/Aa123%26-._~$@%27")
         .isKind(UriInfoKind.resource).goPath()
         .isFormatText("Test_all_valid_signsSpecified_for_format_signs&-._~$@'/Aa123&-._~$@'");
-    testUri.run("ESKeyNav(1)?$format=" + HttpContentType.APPLICATION_ATOM_XML_ENTRY_UTF8)
+    testUri.run("ESKeyNav(1)", "$format=" + HttpContentType.APPLICATION_ATOM_XML_ENTRY_UTF8)
         .isKind(UriInfoKind.resource).goPath()
         .isFormatText(HttpContentType.APPLICATION_ATOM_XML_ENTRY_UTF8);
-    testUri.runEx("ESKeyNav(1)?$format=noSlash")
+    testUri.runEx("ESKeyNav(1)", "$format=noSlash")
         .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION_FORMAT);
-    testUri.runEx("ESKeyNav(1)?$format=slashAtEnd/")
+    testUri.runEx("ESKeyNav(1)", "$format=slashAtEnd/")
         .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION_FORMAT);
-    testUri.runEx("ESKeyNav(1)?$format=/startsWithSlash")
+    testUri.runEx("ESKeyNav(1)", "$format=/startsWithSlash")
         .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION_FORMAT);
-    testUri.runEx("ESKeyNav(1)?$format=two/Slashes/tooMuch")
+    testUri.runEx("ESKeyNav(1)", "$format=two/Slashes/tooMuch")
         .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION_FORMAT);
-    testUri.runEx("ESKeyNav(1)?$format=")
+    testUri.runEx("ESKeyNav(1)", "$format=")
         .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION_FORMAT);
   }
 
   @Test
   public void runCount() throws Exception {
     // count
-    testUri.run("ESAllPrim?$count=true")
+    testUri.run("ESAllPrim", "$count=true")
         .isKind(UriInfoKind.resource).goPath()
         .isInlineCountText("true");
-    testUri.run("ESAllPrim?$count=false")
+    testUri.run("ESAllPrim", "$count=false")
         .isKind(UriInfoKind.resource).goPath()
         .isInlineCountText("false");
-    testUri.runEx("ESAllPrim?$count=undefined")
+    testUri.runEx("ESAllPrim", "$count=undefined")
         .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION);
-    testUri.runEx("ESAllPrim?$count=")
+    testUri.runEx("ESAllPrim", "$count=")
         .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION);
   }
 
   @Test
   public void skip() throws Exception {
     // skip
-    testUri.run("ESAllPrim?$skip=3")
+    testUri.run("ESAllPrim", "$skip=3")
         .isKind(UriInfoKind.resource).goPath()
         .isSkipText("3");
-    testUri.run("ESAllPrim?$skip=0")
+    testUri.run("ESAllPrim", "$skip=0")
         .isKind(UriInfoKind.resource).goPath()
         .isSkipText("0");
-    testUri.run("ESAllPrim?$skip=-3")
+    testUri.run("ESAllPrim", "$skip=-3")
         .isKind(UriInfoKind.resource).goPath()
         .isSkipText("-3");
-    testUri.runEx("ESAllPrim?$skip=F")
+    testUri.runEx("ESAllPrim", "$skip=F")
         .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION);
-    testUri.runEx("ESAllPrim?$skip=")
+    testUri.runEx("ESAllPrim", "$skip=")
         .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION);
   }
 
   @Test
   public void skiptoken() throws Exception {
-    testUri.run("ESAllPrim?$skiptoken=foo")
+    testUri.run("ESAllPrim", "$skiptoken=foo")
         .isKind(UriInfoKind.resource).goPath()
         .isSkipTokenText("foo");
   }
 
   @Test
   public void notExistingSystemQueryOption() throws Exception {
-    testUri.runEx("ESAllPrim?$wrong=error")
+    testUri.runEx("ESAllPrim", "$wrong=error")
         .isExSyntax(UriParserSyntaxException.MessageKeys.UNKNOWN_SYSTEM_QUERY_OPTION);
   }
 
@@ -2631,6 +2631,13 @@ public class TestFullResourcePath {
         .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);
+
     testUri.run("ESKeyNav")
         .isKind(UriInfoKind.resource)
         .goPath().first()
@@ -5069,37 +5076,37 @@ public class TestFullResourcePath {
   @Ignore("$search currently not implemented")
   public void testSearch() throws Exception {
 
-    testUri.run("ESTwoKeyNav?$search=abc");
-    testUri.run("ESTwoKeyNav?$search=NOT abc");
+    testUri.run("ESTwoKeyNav", "$search=abc");
+    testUri.run("ESTwoKeyNav", "$search=NOT abc");
 
-    testUri.run("ESTwoKeyNav?$search=abc AND def");
-    testUri.run("ESTwoKeyNav?$search=abc  OR def");
-    testUri.run("ESTwoKeyNav?$search=abc     def");
+    testUri.run("ESTwoKeyNav", "$search=abc AND def");
+    testUri.run("ESTwoKeyNav", "$search=abc  OR def");
+    testUri.run("ESTwoKeyNav", "$search=abc     def");
 
-    testUri.run("ESTwoKeyNav?$search=abc AND def AND ghi");
-    testUri.run("ESTwoKeyNav?$search=abc AND def  OR ghi");
-    testUri.run("ESTwoKeyNav?$search=abc AND def     ghi");
+    testUri.run("ESTwoKeyNav", "$search=abc AND def AND ghi");
+    testUri.run("ESTwoKeyNav", "$search=abc AND def  OR ghi");
+    testUri.run("ESTwoKeyNav", "$search=abc AND def     ghi");
 
-    testUri.run("ESTwoKeyNav?$search=abc  OR def AND ghi");
-    testUri.run("ESTwoKeyNav?$search=abc  OR def  OR ghi");
-    testUri.run("ESTwoKeyNav?$search=abc  OR def     ghi");
+    testUri.run("ESTwoKeyNav", "$search=abc  OR def AND ghi");
+    testUri.run("ESTwoKeyNav", "$search=abc  OR def  OR ghi");
+    testUri.run("ESTwoKeyNav", "$search=abc  OR def     ghi");
 
-    testUri.run("ESTwoKeyNav?$search=abc     def AND ghi");
-    testUri.run("ESTwoKeyNav?$search=abc     def  OR ghi");
-    testUri.run("ESTwoKeyNav?$search=abc     def     ghi");
+    testUri.run("ESTwoKeyNav", "$search=abc     def AND ghi");
+    testUri.run("ESTwoKeyNav", "$search=abc     def  OR ghi");
+    testUri.run("ESTwoKeyNav", "$search=abc     def     ghi");
 
     // mixed not
-    testUri.run("ESTwoKeyNav?$search=    abc         def AND     ghi");
-    testUri.run("ESTwoKeyNav?$search=NOT abc  NOT    def  OR NOT ghi");
-    testUri.run("ESTwoKeyNav?$search=    abc         def     NOT ghi");
+    testUri.run("ESTwoKeyNav", "$search=    abc         def AND     ghi");
+    testUri.run("ESTwoKeyNav", "$search=NOT abc  NOT    def  OR NOT ghi");
+    testUri.run("ESTwoKeyNav", "$search=    abc         def     NOT ghi");
 
     // parenthesis
-    testUri.run("ESTwoKeyNav?$search= (abc)");
-    testUri.run("ESTwoKeyNav?$search= (abc AND  def)");
-    testUri.run("ESTwoKeyNav?$search= (abc AND  def)   OR  ghi ");
-    testUri.run("ESTwoKeyNav?$search= (abc AND  def)       ghi ");
-    testUri.run("ESTwoKeyNav?$search=  abc AND (def    OR  ghi)");
-    testUri.run("ESTwoKeyNav?$search=  abc AND (def        ghi)");
+    testUri.run("ESTwoKeyNav", "$search= (abc)");
+    testUri.run("ESTwoKeyNav", "$search= (abc AND  def)");
+    testUri.run("ESTwoKeyNav", "$search= (abc AND  def)   OR  ghi ");
+    testUri.run("ESTwoKeyNav", "$search= (abc AND  def)       ghi ");
+    testUri.run("ESTwoKeyNav", "$search=  abc AND (def    OR  ghi)");
+    testUri.run("ESTwoKeyNav", "$search=  abc AND (def        ghi)");
   }
 
   @Test
@@ -5156,7 +5163,7 @@ public class TestFullResourcePath {
 
   @Test
   public void testAlias() throws Exception {
-    testUri.run("ESTwoKeyNav(PropertyInt16=1,PropertyString=@A)?@A='2'").goPath()
+    testUri.run("ESTwoKeyNav(PropertyInt16=1,PropertyString=@A)", "@A='2'").goPath()
         .isKeyPredicate(0, "PropertyInt16", "1")
         .isKeyPredicateAlias(1, "PropertyString", "@A")
         .isInAliasToValueMap("@A", "'2'")