You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by mi...@apache.org on 2014/11/05 14:31:56 UTC

[6/9] git commit: better key validation in server URI parsing

better key validation in server URI parsing

Change-Id: Iab5d223e518af369dad046b4ea499e61bfaab7d0

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/b5e40fdf
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/b5e40fdf
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/b5e40fdf

Branch: refs/heads/OLINGO-450_FunctionActionExecution
Commit: b5e40fdfa4e836ff3420af33fa72b5aca3bda988
Parents: 1e578d7
Author: Klaus Straubinger <kl...@sap.com>
Authored: Fri Oct 24 15:18:24 2014 +0200
Committer: Michael Bolz <mi...@sap.com>
Committed: Mon Oct 27 09:24:58 2014 +0100

----------------------------------------------------------------------
 .../core/uri/parser/UriParseTreeVisitor.java    |  70 ++++---
 .../uri/parser/UriParserSemanticException.java  |   2 +-
 .../uri/validator/UriValidationException.java   |   2 +
 .../server/core/uri/validator/UriValidator.java |  41 ++--
 .../server-core-exceptions-i18n.properties      |   3 +-
 .../core/uri/antlr/TestFullResourcePath.java    |   8 +-
 .../core/uri/validator/UriValidatorTest.java    | 200 +++++++++----------
 7 files changed, 167 insertions(+), 159 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b5e40fdf/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 9c2906d..4b6745a 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
@@ -182,6 +182,7 @@ import org.apache.olingo.server.core.uri.queryoption.expression.TypeLiteralImpl;
 import org.apache.olingo.server.core.uri.queryoption.expression.UnaryImpl;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -1459,37 +1460,39 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
       // get list of keys for lastType
       List<String> lastKeyPredicates = lastType.getKeyPredicateNames();
 
-      // if there is exactly one key defined in the EDM, then this key the the key written in the URI,
-      // so fill the keylist with this key and return
+      // 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) {
-        String keyName = lastKeyPredicates.get(0);
-        List<UriParameterImpl> list = new ArrayList<UriParameterImpl>();
-        list.add(new UriParameterImpl().setName(keyName).setText(valueText).setExpression(expression));
-        return list;
+        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 constrains are defined on this navigation property which can be used to will up all required
-      // key.
-      // for using referential constrains the last resource part must be a navigation property
+      // 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("Not enough key properties defined",
-            UriParserSemanticException.MessageKeys.NOT_ENOUGH_KEY_PROPERTIES));
+        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("Not enough key properties defined",
-            UriParserSemanticException.MessageKeys.NOT_ENOUGH_KEY_PROPERTIES));
+        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 key not filled by referential constrains and collect the other keys filled by
-      // referential constrains
+      // 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);
@@ -1548,22 +1551,25 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
         return list;
       }
 
-      // if not, check if the missing key predicates can be satisfied with help of the defined referential constrains
-      // for using referential constrains the last resource part must be a navigation property
+      // 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("Not enough key properties defined",
-            UriParserSemanticException.MessageKeys.NOT_ENOUGH_KEY_PROPERTIES));
+        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("Not enough key properties defined",
-            UriParserSemanticException.MessageKeys.NOT_ENOUGH_KEY_PROPERTIES));
+        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 constrains
+      // fill missing keys from referential constraints
       for (String key : lastKeyPredicates) {
         boolean found = false;
         for (UriParameterImpl item : list) {
@@ -1582,15 +1588,25 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
         }
       }
 
-      // check again if all keyPredicate are filled from the URI
+      // 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 {
+      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"));
       }
-
-      throw wrap(new UriParserSemanticException("Not enough key properties defined",
-          UriParserSemanticException.MessageKeys.NOT_ENOUGH_KEY_PROPERTIES));
     }
-    return new ArrayList<String>();
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b5e40fdf/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 78a32cf..77f975b 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
@@ -44,7 +44,7 @@ public class UriParserSemanticException extends UriParserException {
     /** parameter: expression */ ONLY_FOR_TYPED_PROPERTIES,
     /** parameter: value */ INVALID_KEY_VALUE,
     PARAMETERS_LIST_ONLY_FOR_TYPED_PARTS,
-    NOT_ENOUGH_KEY_PROPERTIES,
+    /** parameters: expected number, actual number */ WRONG_NUMBER_OF_KEY_PROPERTIES,
     NOT_ENOUGH_REFERENTIAL_CONSTRAINTS,
     KEY_NOT_ALLOWED,
     RESOURCE_PATH_NOT_TYPED,

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b5e40fdf/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/validator/UriValidationException.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/validator/UriValidationException.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/validator/UriValidationException.java
index f7156cd..9bba0c5 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/validator/UriValidationException.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/validator/UriValidationException.java
@@ -43,6 +43,8 @@ public class UriValidationException extends ODataTranslatedException {
     SYSTEM_QUERY_OPTION_NOT_ALLOWED_FOR_HTTP_METHOD,
     /** parameter: invalid key property */
     INVALID_KEY_PROPERTY,
+    /** parameter: key property */
+    DOUBLE_KEY_PROPERTY,
     /** parameter: untyped segment name */
     LAST_SEGMENT_NOT_TYPED,
     /** parameter: untyped segment name */

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b5e40fdf/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 9c03db4..32fc690 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
@@ -176,7 +176,7 @@ public class UriValidator {
   public void validate(final UriInfo uriInfo, final HttpMethod httpMethod) throws UriValidationException {
     validateForHttpMethod(uriInfo, httpMethod);
     validateQueryOptions(uriInfo);
-    validateKeyPredicateTypes(uriInfo);
+    validateKeyPredicates(uriInfo);
   }
 
   private ColumnIndex colIndex(final SystemQueryOptionKind queryOptionKind) throws UriValidationException {
@@ -613,38 +613,40 @@ public class UriValidator {
     return idx;
   }
 
-  private void validateKeyPredicateTypes(final UriInfo uriInfo) throws UriValidationException {
+  private void validateKeyPredicates(final UriInfo uriInfo) throws UriValidationException {
     for (UriResource pathSegment : uriInfo.getUriResourceParts()) {
       if (pathSegment.getKind() == UriResourceKind.entitySet) {
         UriResourceEntitySet pathEntitySet = (UriResourceEntitySet) pathSegment;
-
-        EdmEntityType type = pathEntitySet.getEntityType();
-        List<EdmKeyPropertyRef> keys = type.getKeyPropertyRefs();
         List<UriParameter> keyPredicates = pathEntitySet.getKeyPredicates();
 
-        if (null != keyPredicates) {
+        if (keyPredicates != null) {
 
+          final List<String> keyPredicateNames = pathEntitySet.getEntityType().getKeyPredicateNames();
           HashMap<String, EdmKeyPropertyRef> edmKeys = new HashMap<String, EdmKeyPropertyRef>();
-          for (EdmKeyPropertyRef key : keys) {
+          for (EdmKeyPropertyRef key : pathEntitySet.getEntityType().getKeyPropertyRefs()) {
             edmKeys.put(key.getKeyPropertyName(), key);
-            String alias = key.getAlias();
-            if (null != alias) {
+            final String alias = key.getAlias();
+            if (alias != null) {
               edmKeys.put(alias, key);
             }
           }
 
           for (UriParameter keyPredicate : keyPredicates) {
-            String name = keyPredicate.getName();
-            String alias = keyPredicate.getAlias();
-            String value = keyPredicate.getText();
-            if (alias != null) {
-              value = uriInfo.getValueForAlias(alias);
-            }
-            EdmKeyPropertyRef edmKey = edmKeys.get(name);
+            final String name = keyPredicate.getName();
+            final String alias = keyPredicate.getAlias();
+            final String value = alias == null ?
+                keyPredicate.getText() :
+                uriInfo.getValueForAlias(alias);
 
+            EdmKeyPropertyRef edmKey = edmKeys.get(name);
             if (edmKey == null) {
-              throw new UriValidationException("Unknown key property: " + name,
-                  UriValidationException.MessageKeys.INVALID_KEY_PROPERTY, name);
+              if (keyPredicateNames.contains(name)) {
+                throw new UriValidationException("Double key property: " + name,
+                    UriValidationException.MessageKeys.DOUBLE_KEY_PROPERTY, name);
+              } else {
+                throw new UriValidationException("Unknown key property: " + name,
+                    UriValidationException.MessageKeys.INVALID_KEY_PROPERTY, name);
+              }
             }
 
             final EdmProperty property = edmKey.getProperty();
@@ -662,6 +664,9 @@ public class UriValidator {
               throw new UriValidationException("PrimitiveTypeException", e,
                   UriValidationException.MessageKeys.INVALID_KEY_PROPERTY, name);
             }
+
+            edmKeys.remove(name);
+            edmKeys.remove(alias);
           }
         }
       }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b5e40fdf/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 06fa51c..15f4ab8 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
@@ -53,7 +53,7 @@ UriParserSemanticException.ONLY_FOR_STRUCTURAL_TYPES='%1$s' is only allowed for
 UriParserSemanticException.ONLY_FOR_TYPED_PROPERTIES='%1$s' is only allowed for typed properties.
 UriParserSemanticException.INVALID_KEY_VALUE=The key value '%1$s' is invalid.
 UriParserSemanticException.PARAMETERS_LIST_ONLY_FOR_TYPED_PARTS=A list of parameters is only allowed for typed parts.
-UriParserSemanticException.NOT_ENOUGH_KEY_PROPERTIES=There are not enough key properties.
+UriParserSemanticException.WRONG_NUMBER_OF_KEY_PROPERTIES=There are %2$s key properties instead of the expected %1$s.
 UriParserSemanticException.NOT_ENOUGH_REFERENTIAL_CONSTRAINTS=There are not enough referential constraints.
 UriParserSemanticException.KEY_NOT_ALLOWED=A key is not allowed.
 UriParserSemanticException.RESOURCE_PATH_NOT_TYPED=The resource path is not typed.
@@ -72,6 +72,7 @@ UriValidationException.UNSUPPORTED_HTTP_METHOD=The HTTP method '%1$s' is not sup
 UriValidationException.SYSTEM_QUERY_OPTION_NOT_ALLOWED=The system query option '%1$s' is not allowed.
 UriValidationException.SYSTEM_QUERY_OPTION_NOT_ALLOWED_FOR_HTTP_METHOD=The system query option '%1$s' is not allowed for HTTP method '%2$s'.
 UriValidationException.INVALID_KEY_PROPERTY=The key property '%1$s' is invalid.
+UriValidationException.DOUBLE_KEY_PROPERTY=The key property '%1$s' has been specified twice.
 UriValidationException.LAST_SEGMENT_NOT_TYPED=The last segment '%1$s' is not typed.
 UriValidationException.SECOND_LAST_SEGMENT_NOT_TYPED=The second last segment '%1$s' is not typed.
 UriValidationException.UNALLOWED_KIND_BEFORE_VALUE=The kind '%1$s' is not allowed before '$value'.

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b5e40fdf/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 3c237da..d850edd 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
@@ -31,7 +31,6 @@ import org.apache.olingo.server.core.edm.provider.EdmProviderImpl;
 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.validator.UriValidationException;
 import org.apache.olingo.server.core.uri.testutil.EdmTechTestProvider;
 import org.apache.olingo.server.core.uri.testutil.FilterValidator;
 import org.apache.olingo.server.core.uri.testutil.ResourceValidator;
@@ -959,14 +958,12 @@ public class TestFullResourcePath {
         .isExSemantic(UriParserSemanticException.MessageKeys.PROPERTY_AFTER_COLLECTION);
     testUri.runEx("ESAllPrim(1)/whatever")
         .isExSemantic(UriParserSemanticException.MessageKeys.PROPERTY_NOT_IN_TYPE);
-    // testUri.runEx("ESAllPrim(PropertyInt16='1')")
-    //     .isExSemantic(UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE);
     testUri.runEx("ESAllPrim(PropertyInt16)")
         .isExSemantic(UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE);
     testUri.runEx("ESAllPrim(PropertyInt16=)")
         .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
     testUri.runEx("ESAllPrim(PropertyInt16=1,Invalid='1')")
-        .isExSemantic(UriParserSemanticException.MessageKeys.NOT_ENOUGH_KEY_PROPERTIES);
+        .isExSemantic(UriParserSemanticException.MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES);
 
     testUri.runEx("ESBase/olingo.odata.test1.ETBase/PropertyInt16")
         .isExSemantic(UriParserSemanticException.MessageKeys.PROPERTY_AFTER_COLLECTION);
@@ -1087,8 +1084,6 @@ public class TestFullResourcePath {
         .isKeyPredicate(1, "KeyAlias1", "2")
         .isKeyPredicate(2, "KeyAlias2", "'3'")
         .isKeyPredicate(3, "KeyAlias3", "'4'");
-
-    testUri.runEx("ESCollAllPrim(null)").isExValidation(UriValidationException.MessageKeys.INVALID_KEY_PROPERTY);
   }
 
   @Test
@@ -2660,6 +2655,7 @@ public class TestFullResourcePath {
         .goPath().first()
         .isEntitySet("ESKeyNav")
         .isKeyPredicate(0, "PropertyInt16", "1");
+    testUri.runEx("ESKeyNav()").isExSemantic(UriParserSemanticException.MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES);
 
     testUri.run("SINav")
         .isKind(UriInfoKind.resource)

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b5e40fdf/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 d9dc5e1..02b51b1 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
@@ -26,13 +26,11 @@ 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.testutil.TestUriValidator;
 import org.apache.olingo.server.tecsvc.provider.EdmTechProvider;
-import org.junit.Before;
 import org.junit.Test;
 
-import java.util.ArrayList;
-import java.util.List;
-
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 
 public class UriValidatorTest {
@@ -69,7 +67,7 @@ public class UriValidatorTest {
   private static final String QO_ID = "$id=Products(0)";
   private static final String QO_COUNT = "$count=true";
   private static final String QO_ORDERBY = "$orderby=true";
-//  private static final String QO_SEARCH = "$search='bla'";
+  //  private static final String QO_SEARCH = "$search='bla'";
   private static final String QO_SELECT = "$select=*";
   private static final String QO_SKIP = "$skip=3";
   private static final String QO_SKIPTOKEN = "$skiptoken=123";
@@ -77,23 +75,23 @@ public class UriValidatorTest {
   private static final String QO_TOP = "$top=1";
 
   private String[][] urisWithValidSystemQueryOptions = {
-      { URI_ALL, QO_FILTER, }, { URI_ALL, QO_FORMAT }, { URI_ALL, QO_EXPAND }, { URI_ALL, QO_COUNT },
+      { URI_ALL, QO_FILTER }, { URI_ALL, QO_FORMAT }, { URI_ALL, QO_EXPAND }, { URI_ALL, QO_COUNT },
       { URI_ALL, QO_ORDERBY }, /* { URI_ALL, QO_SEARCH }, */{ URI_ALL, QO_SELECT }, { URI_ALL, QO_SKIP },
       { URI_ALL, QO_SKIPTOKEN }, { URI_ALL, QO_LEVELS },
 
-      { URI_CROSSJOIN, QO_FILTER, }, { URI_CROSSJOIN, QO_FORMAT },
+      { URI_CROSSJOIN, QO_FILTER }, { URI_CROSSJOIN, QO_FORMAT },
       { URI_CROSSJOIN, QO_EXPAND }, { URI_CROSSJOIN, QO_COUNT }, { URI_CROSSJOIN, QO_ORDERBY },
       /* { URI_CROSSJOIN, QO_SEARCH }, */{ URI_CROSSJOIN, QO_SELECT }, { URI_CROSSJOIN, QO_SKIP },
       { URI_CROSSJOIN, QO_SKIPTOKEN }, { URI_CROSSJOIN, QO_LEVELS }, { URI_CROSSJOIN, QO_TOP },
 
-      { URI_ENTITY_ID, QO_ID, QO_FORMAT }, { URI_ENTITY_ID, QO_ID, }, { URI_ENTITY_ID, QO_ID, QO_EXPAND },
+      { URI_ENTITY_ID, QO_ID, QO_FORMAT }, { URI_ENTITY_ID, QO_ID }, { URI_ENTITY_ID, QO_ID, QO_EXPAND },
       { URI_ENTITY_ID, QO_ID, QO_SELECT }, { URI_ENTITY_ID, QO_ID, QO_LEVELS },
 
       { URI_METADATA, QO_FORMAT },
 
       { URI_SERVICE, QO_FORMAT },
 
-      { URI_ENTITY_SET, QO_FILTER, }, { URI_ENTITY_SET, QO_FORMAT }, { URI_ENTITY_SET, QO_EXPAND },
+      { URI_ENTITY_SET, QO_FILTER }, { URI_ENTITY_SET, QO_FORMAT }, { URI_ENTITY_SET, QO_EXPAND },
       { URI_ENTITY_SET, QO_COUNT }, { URI_ENTITY_SET, QO_ORDERBY }, /* { URI_ENTITY_SET, QO_SEARCH }, */
       { URI_ENTITY_SET, QO_SELECT },
       { URI_ENTITY_SET, QO_SKIP }, { URI_ENTITY_SET, QO_SKIPTOKEN }, { URI_ENTITY_SET, QO_LEVELS },
@@ -139,7 +137,7 @@ public class UriValidatorTest {
       { URI_NAV_ENTITY, QO_FORMAT }, { URI_NAV_ENTITY, QO_EXPAND }, { URI_NAV_ENTITY, QO_SELECT },
       { URI_NAV_ENTITY, QO_LEVELS },
 
-      { URI_NAV_ENTITY_SET, QO_FILTER, }, { URI_NAV_ENTITY_SET, QO_FORMAT }, { URI_NAV_ENTITY_SET, QO_EXPAND },
+      { URI_NAV_ENTITY_SET, QO_FILTER }, { URI_NAV_ENTITY_SET, QO_FORMAT }, { URI_NAV_ENTITY_SET, QO_EXPAND },
       { URI_NAV_ENTITY_SET, QO_COUNT }, { URI_NAV_ENTITY_SET, QO_ORDERBY },
       /* { URI_NAV_ENTITY_SET, QO_SEARCH }, */{ URI_NAV_ENTITY_SET, QO_SELECT }, { URI_NAV_ENTITY_SET, QO_SKIP },
       { URI_NAV_ENTITY_SET, QO_SKIPTOKEN }, { URI_NAV_ENTITY_SET, QO_LEVELS }, { URI_NAV_ENTITY_SET, QO_TOP },
@@ -156,25 +154,24 @@ public class UriValidatorTest {
       { "ESAllPrim/olingo.odata.test1.BAESAllPrimRTETAllPrim" },
       { "AIRTPrimCollParam" },
       { "AIRTETParam" },
-      { "AIRTPrimParam" },
-
+      { "AIRTPrimParam" }
   };
 
   private String[][] urisWithNonValidSystemQueryOptions = {
-      { URI_ALL, QO_ID, }, { URI_ALL, QO_TOP },
+      { URI_ALL, QO_ID }, { URI_ALL, QO_TOP },
 
-      { URI_BATCH, QO_FILTER, }, { URI_BATCH, QO_FORMAT }, { URI_BATCH, QO_ID, }, { URI_BATCH, QO_EXPAND },
+      { URI_BATCH, QO_FILTER }, { URI_BATCH, QO_FORMAT }, { URI_BATCH, QO_ID }, { URI_BATCH, QO_EXPAND },
       { URI_BATCH, QO_COUNT }, { URI_BATCH, QO_ORDERBY }, /* { URI_BATCH, QO_SEARCH }, */{ URI_BATCH, QO_SELECT },
       { URI_BATCH, QO_SKIP }, { URI_BATCH, QO_SKIPTOKEN }, { URI_BATCH, QO_LEVELS }, { URI_BATCH, QO_TOP },
 
-      { URI_CROSSJOIN, QO_ID, },
+      { URI_CROSSJOIN, QO_ID },
 
-      { URI_ENTITY_ID, QO_ID, QO_FILTER, },
+      { URI_ENTITY_ID, QO_ID, QO_FILTER },
       { URI_ENTITY_ID, QO_ID, QO_COUNT }, { URI_ENTITY_ID, QO_ORDERBY }, /* { URI_ENTITY_ID, QO_SEARCH }, */
 
       { URI_ENTITY_ID, QO_ID, QO_SKIP }, { URI_ENTITY_ID, QO_ID, QO_SKIPTOKEN }, { URI_ENTITY_ID, QO_ID, QO_TOP },
 
-      { URI_METADATA, QO_FILTER, }, { URI_METADATA, QO_ID, }, { URI_METADATA, QO_EXPAND },
+      { URI_METADATA, QO_FILTER }, { URI_METADATA, QO_ID }, { URI_METADATA, QO_EXPAND },
       { URI_METADATA, QO_COUNT }, { URI_METADATA, QO_ORDERBY }, /* { URI_METADATA, QO_SEARCH }, */
       { URI_METADATA, QO_SELECT }, { URI_METADATA, QO_SKIP }, { URI_METADATA, QO_SKIPTOKEN },
       { URI_METADATA, QO_LEVELS }, { URI_METADATA, QO_TOP },
@@ -194,52 +191,52 @@ public class UriValidatorTest {
       { URI_ENTITY, QO_FILTER }, { URI_ENTITY, QO_ID }, { URI_ENTITY, QO_COUNT }, /* { URI_ENTITY, QO_ORDERBY }, */
       /* { URI_ENTITY, QO_SEARCH }, */{ URI_ENTITY, QO_SKIP }, { URI_ENTITY, QO_SKIPTOKEN }, { URI_ENTITY, QO_TOP },
 
-      { URI_MEDIA_STREAM, QO_FILTER }, { URI_MEDIA_STREAM, QO_ID, }, { URI_MEDIA_STREAM, QO_EXPAND },
+      { URI_MEDIA_STREAM, QO_FILTER }, { URI_MEDIA_STREAM, QO_ID }, { URI_MEDIA_STREAM, QO_EXPAND },
       { URI_MEDIA_STREAM, QO_COUNT }, { URI_MEDIA_STREAM, QO_ORDERBY }, /* { URI_MEDIA_STREAM, QO_SEARCH }, */
       { URI_MEDIA_STREAM, QO_SELECT }, { URI_MEDIA_STREAM, QO_SKIP }, { URI_MEDIA_STREAM, QO_SKIPTOKEN },
       { URI_MEDIA_STREAM, QO_LEVELS }, { URI_MEDIA_STREAM, QO_TOP },
 
-      { URI_REFERENCES, QO_ID, }, { URI_REFERENCES, QO_EXPAND }, { URI_REFERENCES, QO_COUNT },
+      { URI_REFERENCES, QO_ID }, { URI_REFERENCES, QO_EXPAND }, { URI_REFERENCES, QO_COUNT },
       { URI_REFERENCES, QO_SELECT }, { URI_REFERENCES, QO_LEVELS },
 
-      { URI_REFERENCE, QO_FILTER }, { URI_REFERENCE, QO_ID, }, { URI_REFERENCE, QO_EXPAND },
+      { URI_REFERENCE, QO_FILTER }, { URI_REFERENCE, QO_ID }, { URI_REFERENCE, QO_EXPAND },
       { URI_REFERENCE, QO_COUNT }, { URI_REFERENCE, QO_ORDERBY }, /* { URI_REFERENCE, QO_SEARCH }, */
       { URI_REFERENCE, QO_SELECT }, { URI_REFERENCE, QO_SKIP }, { URI_REFERENCE, QO_SKIPTOKEN },
       { URI_REFERENCE, QO_LEVELS }, { URI_REFERENCE, QO_TOP },
 
-      { URI_PROPERTY_COMPLEX, QO_FILTER }, { URI_PROPERTY_COMPLEX, QO_ID, }, { URI_PROPERTY_COMPLEX, QO_COUNT },
+      { URI_PROPERTY_COMPLEX, QO_FILTER }, { URI_PROPERTY_COMPLEX, QO_ID }, { URI_PROPERTY_COMPLEX, QO_COUNT },
       { URI_PROPERTY_COMPLEX, QO_ORDERBY }, /* { URI_PROPERTY_COMPLEX, QO_SEARCH }, */
       { URI_PROPERTY_COMPLEX, QO_SKIP }, { URI_PROPERTY_COMPLEX, QO_SKIPTOKEN }, { URI_PROPERTY_COMPLEX, QO_TOP },
 
-      { URI_PROPERTY_COMPLEX_COLLECTION, QO_ID, },
+      { URI_PROPERTY_COMPLEX_COLLECTION, QO_ID },
       /* { URI_PROPERTY_COMPLEX_COLLECTION, QO_SEARCH }, */{ URI_PROPERTY_COMPLEX_COLLECTION, QO_SELECT },
 
       { URI_PROPERTY_COMPLEX_COLLECTION_COUNT, QO_FORMAT },
-      { URI_PROPERTY_COMPLEX_COLLECTION_COUNT, QO_ID, }, { URI_PROPERTY_COMPLEX_COLLECTION_COUNT, QO_EXPAND },
+      { URI_PROPERTY_COMPLEX_COLLECTION_COUNT, QO_ID }, { URI_PROPERTY_COMPLEX_COLLECTION_COUNT, QO_EXPAND },
       { URI_PROPERTY_COMPLEX_COLLECTION_COUNT, QO_COUNT }, { URI_PROPERTY_COMPLEX_COLLECTION_COUNT, QO_ORDERBY },
       { URI_PROPERTY_COMPLEX_COLLECTION_COUNT, QO_SELECT },
       { URI_PROPERTY_COMPLEX_COLLECTION_COUNT, QO_SKIP }, { URI_PROPERTY_COMPLEX_COLLECTION_COUNT, QO_SKIPTOKEN },
       { URI_PROPERTY_COMPLEX_COLLECTION_COUNT, QO_LEVELS }, { URI_PROPERTY_COMPLEX_COLLECTION_COUNT, QO_TOP },
 
-      { URI_PROPERTY_PRIMITIVE, QO_FILTER }, { URI_PROPERTY_PRIMITIVE, QO_ID, }, { URI_PROPERTY_PRIMITIVE, QO_EXPAND },
+      { URI_PROPERTY_PRIMITIVE, QO_FILTER }, { URI_PROPERTY_PRIMITIVE, QO_ID }, { URI_PROPERTY_PRIMITIVE, QO_EXPAND },
       { URI_PROPERTY_PRIMITIVE, QO_COUNT }, { URI_PROPERTY_PRIMITIVE, QO_ORDERBY },
       /* { URI_PROPERTY_PRIMITIVE, QO_SEARCH }, */{ URI_PROPERTY_PRIMITIVE, QO_SELECT },
       { URI_PROPERTY_PRIMITIVE, QO_SKIP }, { URI_PROPERTY_PRIMITIVE, QO_SKIPTOKEN },
       { URI_PROPERTY_PRIMITIVE, QO_LEVELS }, { URI_PROPERTY_PRIMITIVE, QO_TOP },
 
-      { URI_PROPERTY_PRIMITIVE_COLLECTION, QO_ID, }, { URI_PROPERTY_PRIMITIVE_COLLECTION, QO_EXPAND },
+      { URI_PROPERTY_PRIMITIVE_COLLECTION, QO_ID }, { URI_PROPERTY_PRIMITIVE_COLLECTION, QO_EXPAND },
       { URI_PROPERTY_PRIMITIVE_COLLECTION, QO_COUNT }, /* { URI_PROPERTY_PRIMITIVE_COLLECTION, QO_SEARCH }, */
       { URI_PROPERTY_PRIMITIVE_COLLECTION, QO_SELECT }, { URI_PROPERTY_PRIMITIVE_COLLECTION, QO_LEVELS },
 
       { URI_PROPERTY_PRIMITIVE_COLLECTION_COUNT, QO_FORMAT },
-      { URI_PROPERTY_PRIMITIVE_COLLECTION_COUNT, QO_ID, }, { URI_PROPERTY_PRIMITIVE_COLLECTION_COUNT, QO_EXPAND },
+      { URI_PROPERTY_PRIMITIVE_COLLECTION_COUNT, QO_ID }, { URI_PROPERTY_PRIMITIVE_COLLECTION_COUNT, QO_EXPAND },
       { URI_PROPERTY_PRIMITIVE_COLLECTION_COUNT, QO_COUNT },
       { URI_PROPERTY_PRIMITIVE_COLLECTION_COUNT, QO_ORDERBY },
       { URI_PROPERTY_PRIMITIVE_COLLECTION_COUNT, QO_SELECT }, { URI_PROPERTY_PRIMITIVE_COLLECTION_COUNT, QO_SKIP },
       { URI_PROPERTY_PRIMITIVE_COLLECTION_COUNT, QO_SKIPTOKEN },
       { URI_PROPERTY_PRIMITIVE_COLLECTION_COUNT, QO_LEVELS }, { URI_PROPERTY_PRIMITIVE_COLLECTION_COUNT, QO_TOP },
 
-      { URI_PROPERTY_PRIMITIVE_VALUE, QO_FILTER }, { URI_PROPERTY_PRIMITIVE_VALUE, QO_ID, },
+      { URI_PROPERTY_PRIMITIVE_VALUE, QO_FILTER }, { URI_PROPERTY_PRIMITIVE_VALUE, QO_ID },
       { URI_PROPERTY_PRIMITIVE_VALUE, QO_EXPAND }, { URI_PROPERTY_PRIMITIVE_VALUE, QO_COUNT },
       { URI_PROPERTY_PRIMITIVE_VALUE, QO_ORDERBY },/* { URI_PROPERTY_PRIMITIVE_VALUE, QO_SEARCH }, */
       { URI_PROPERTY_PRIMITIVE_VALUE, QO_SELECT }, { URI_PROPERTY_PRIMITIVE_VALUE, QO_SKIP },
@@ -254,92 +251,90 @@ public class UriValidatorTest {
       { URI_NAV_ENTITY, QO_ORDERBY }, /* { URI_NAV_ENTITY, QO_SEARCH }, */{ URI_NAV_ENTITY, QO_SKIP },
       { URI_NAV_ENTITY, QO_SKIPTOKEN }, { URI_SINGLETON, QO_TOP },
 
-      { URI_NAV_ENTITY_SET, QO_ID },
-
+      { URI_NAV_ENTITY_SET, QO_ID }
   };
 
-  private Parser parser;
-  private Edm edm;
-
-  @Before
-  public void before() {
-    parser = new Parser();
-    edm = new EdmProviderImpl(new EdmTechProvider());
-  }
+  private static final Edm edm = new EdmProviderImpl(new EdmTechProvider());
 
   @Test
-  public void validateSelect() throws Exception {
-    parseAndValidate("/ESAllPrim(1)", "$select=PropertyString", HttpMethod.GET);
+  public void validateForHttpMethods() throws Exception {
+    final UriInfo uri = new Parser().parseUri(URI_ENTITY, null, null, edm);
+    final UriValidator validator = new UriValidator();
+
+    validator.validate(uri, HttpMethod.GET);
+    validator.validate(uri, HttpMethod.POST);
+    validator.validate(uri, HttpMethod.PUT);
+    validator.validate(uri, HttpMethod.DELETE);
+    validator.validate(uri, HttpMethod.PATCH);
+    validator.validate(uri, HttpMethod.MERGE);
   }
 
   @Test
-  public void validateForHttpMethods() throws Exception {
-    String uri = URI_ENTITY;
-    parseAndValidate(uri, null, HttpMethod.GET);
-    parseAndValidate(uri, null, HttpMethod.POST);
-    parseAndValidate(uri, null, HttpMethod.PUT);
-    parseAndValidate(uri, null, HttpMethod.DELETE);
-    parseAndValidate(uri, null, HttpMethod.PATCH);
-    parseAndValidate(uri, null, HttpMethod.MERGE);
+  public void validateSelect() throws Exception {
+    new TestUriValidator().setEdm(edm).run(URI_ENTITY, "$select=PropertyString");
   }
 
   @Test
   public void validateOrderBy() throws Exception {
-    parseAndValidate("/ESAllPrim", "$orderby=PropertyString", HttpMethod.GET);
-  }
+    final TestUriValidator testUri = new TestUriValidator().setEdm(edm);
+
+    testUri.run(URI_ENTITY_SET, "$orderby=PropertyString");
 
-  @Test(expected = UriParserSemanticException.class)
-  public void validateOrderByInvalid() throws Exception {
-    parseAndValidate("/ESAllPrim(1)", "$orderby=XXXX", HttpMethod.GET);
+    testUri.runEx(URI_ENTITY, "$orderby=XXXX")
+        .isExSemantic(UriParserSemanticException.MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE);
   }
 
-  @Test(expected = UriParserSyntaxException.class)
+  @Test
   public void validateCountInvalid() throws Exception {
-    parseAndValidate("ESAllPrim", "$count=foo", HttpMethod.GET);
+    new TestUriValidator().setEdm(edm).runEx(URI_ENTITY_SET, "$count=foo")
+        .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION);
   }
 
-  @Test(expected = UriParserSyntaxException.class)
+  @Test
   public void validateTopInvalid() throws Exception {
-    parseAndValidate("ESAllPrim", "$top=foo", HttpMethod.GET);
+    new TestUriValidator().setEdm(edm).runEx(URI_ENTITY_SET, "$top=foo")
+        .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION);
   }
 
-  @Test(expected = UriParserSyntaxException.class)
+  @Test
   public void validateSkipInvalid() throws Exception {
-    parseAndValidate("ESAllPrim", "$skip=foo", HttpMethod.GET);
+    new TestUriValidator().setEdm(edm).runEx(URI_ENTITY_SET, "$skip=foo")
+        .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION);
   }
 
-  @Test(expected = UriParserSyntaxException.class)
+  @Test
   public void validateDoubleSystemOptions() throws Exception {
-    parseAndValidate("ESAllPrim", "$skip=1&$skip=2", HttpMethod.GET);
-  }
-
-  @Test(expected = UriValidationException.class)
-  public void validateKeyPredicatesWrongKey() throws Exception {
-    parseAndValidate("ESTwoKeyNav(xxx=1, yyy='abc')", null, HttpMethod.GET);
+    new TestUriValidator().setEdm(edm).runEx(URI_ENTITY_SET, "$skip=1&$skip=2")
+        .isExSyntax(UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION);
   }
 
   @Test
-  public void validateKeyPredicates() throws Exception {
-    parseAndValidate("ESTwoKeyNav(PropertyInt16=1, PropertyString='abc')", null, HttpMethod.GET);
+  public void checkKeys() throws Exception {
+    final TestUriValidator testUri = new TestUriValidator().setEdm(edm);
+
+    testUri.run("ESTwoKeyNav(PropertyInt16=1, PropertyString='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);
+    testUri.runEx("ESAllPrim(12345678901234567890)")
+        .isExValidation(UriValidationException.MessageKeys.INVALID_KEY_PROPERTY);
+    testUri.runEx("ESTwoKeyNav(PropertyInt16=1,PropertyString=1)")
+        .isExValidation(UriValidationException.MessageKeys.INVALID_KEY_PROPERTY);
+    testUri.runEx("ESTwoKeyNav(PropertyInt16=1,PropertyInt16=1)")
+        .isExValidation(UriValidationException.MessageKeys.DOUBLE_KEY_PROPERTY);
   }
 
-  @Test(expected = UriValidationException.class)
-  public void validateKeyPredicatesWrongValueType() throws Exception {
-    parseAndValidate("ESTwoKeyNav(PropertyInt16='abc', PropertyString=1)", null, HttpMethod.GET);
-  }
-
-  @Test(expected = UriValidationException.class)
-  public void validateKeyPredicatesWrongValueTypeForValidateMethod() throws Exception {
-    parseAndValidate("ESTwoKeyNav(PropertyInt16='abc', PropertyString='abc')", null, HttpMethod.GET);
-  }
-  
   @Test
   public void checkValidSystemQueryOption() throws Exception {
-    List<String[]> uris = constructUri(urisWithValidSystemQueryOptions);
-
-    for (String[] uri : uris) {
+    for (final String[] uriArray : urisWithValidSystemQueryOptions) {
+      final String[] uri = constructUri(uriArray);
       try {
-        parseAndValidate(uri[0], uri[1], HttpMethod.GET);
+        new UriValidator().validate(
+            new Parser().parseUri(uri[0], uri[1], null, edm),
+            HttpMethod.GET);
       } catch (final UriParserException e) {
         fail("Failed for uri: " + uri[0] + '?' + uri[1]);
       } catch (final UriValidationException e) {
@@ -350,38 +345,31 @@ public class UriValidatorTest {
 
   @Test
   public void checkNonValidSystemQueryOption() throws Exception {
-    List<String[]> uris = constructUri(urisWithNonValidSystemQueryOptions);
-
-    for (String[] uri : uris) {
+    for (final String[] uriArray : urisWithNonValidSystemQueryOptions) {
+      final String[] uri = constructUri(uriArray);
       try {
-        parseAndValidate(uri[0], uri[1], HttpMethod.GET);
+        new UriValidator().validate(
+            new Parser().parseUri(uri[0], uri[1], null, edm),
+            HttpMethod.GET);
         fail("Validation Exception not thrown: " + uri[0] + '?' + uri[1]);
-      } catch (UriParserSemanticException e) {
-      } catch (UriValidationException e) {
+      } catch (final UriParserException e) {
+        fail("Wrong Exception thrown: " + uri[0] + '?' + uri[1]);
+      } catch (final UriValidationException e) {
+        assertEquals(UriValidationException.MessageKeys.SYSTEM_QUERY_OPTION_NOT_ALLOWED,
+            e.getMessageKey());
       }
     }
   }
 
-  private List<String[]> constructUri(final String[][] uriParameterMatrix) {
-    List<String[]> uris = new ArrayList<String[]>();
-    for (String[] uriParameter : uriParameterMatrix) {
-      String path = uriParameter[0];
-      String query = "";
-      for (int i = 1; i < uriParameter.length; i++) {
-        query += uriParameter[i];
-        if (i < (uriParameter.length - 1)) {
-          query += "&";
-        }
+  private String[] constructUri(final String[] uriParameterArray) {
+    final String path = uriParameterArray[0];
+    String query = "";
+    for (int i = 1; i < uriParameterArray.length; i++) {
+      if (i > 1) {
+        query += '&';
       }
-      uris.add(new String[] { path, query });
+      query += uriParameterArray[i];
     }
-    return uris;
+    return new String[] { path, query };
   }
-
-  private void parseAndValidate(final String path, final String query, final HttpMethod method)
-      throws UriParserException, UriValidationException {
-    UriInfo uriInfo = parser.parseUri(path.trim(), query, null, edm);
-    new UriValidator().validate(uriInfo, method);
-  }
-
 }