Repository: olingo-odata4
Updated Branches:
  refs/heads/master 0ce0a88be -> 483ee9de1


[OLINGO-801] UriParser supports Complex / Entity Parameters.


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

Branch: refs/heads/master
Commit: 3584e1d71d260a44f9aa685503bdde2d62ad322f
Parents: f221962
Author: Christian Holzer <[email protected]>
Authored: Thu Oct 15 10:01:55 2015 +0200
Committer: Christian Holzer <[email protected]>
Committed: Thu Oct 29 15:31:38 2015 +0100

----------------------------------------------------------------------
 .../olingo/server/core/uri/antlr/UriLexer.g4    |   8 +-
 .../olingo/server/core/uri/antlr/UriParser.g4   |  11 +-
 .../olingo/server/core/uri/UriInfoImpl.java     |  22 ++-
 .../olingo/server/core/uri/parser/Parser.java   |  27 +++-
 .../server/core/uri/parser/UriContext.java      |   7 +-
 .../core/uri/parser/UriParseTreeVisitor.java    | 160 ++++++++++++-------
 .../uri/parser/UriParserSemanticException.java  |   6 +-
 .../uri/parser/UriParserSyntaxException.java    |   4 +-
 .../uri/validator/UriValidationException.java   |   7 +-
 .../server/core/uri/validator/UriValidator.java |  53 ++++++
 .../server-core-exceptions-i18n.properties      |   5 +
 .../core/uri/antlr/TestFullResourcePath.java    |  90 ++++++++++-
 .../core/uri/antlr/TestUriParserImpl.java       |   2 +-
 .../core/uri/testutil/EdmTechTestProvider.java  |  13 +-
 .../core/uri/testutil/FilterValidator.java      |  28 +++-
 15 files changed, 353 insertions(+), 90 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3584e1d7/lib/server-core/src/main/antlr4/org/apache/olingo/server/core/uri/antlr/UriLexer.g4
----------------------------------------------------------------------
diff --git 
a/lib/server-core/src/main/antlr4/org/apache/olingo/server/core/uri/antlr/UriLexer.g4
 
b/lib/server-core/src/main/antlr4/org/apache/olingo/server/core/uri/antlr/UriLexer.g4
index 892accc..7a54ab1 100644
--- 
a/lib/server-core/src/main/antlr4/org/apache/olingo/server/core/uri/antlr/UriLexer.g4
+++ 
b/lib/server-core/src/main/antlr4/org/apache/olingo/server/core/uri/antlr/UriLexer.g4
@@ -29,6 +29,7 @@ STRING          : '\''                -> more,  
pushMode(MODE_STRING) ;
 QUOTATION_MARK  : '\u0022'            -> more,  pushMode(MODE_JSON_STRING);    
     //reads up to next unescaped "
 SEARCH_INLINE   : '$search'           ->        
pushMode(MODE_SYSTEM_QUERY_SEARCH); //
 FRAGMENT        : '#'                 ->        pushMode(MODE_FRAGMENT);       
     //
+STRING_JSON            : '"'                             -> more,  
pushMode(MODE_JSON_STRING);                 //reads up to next unescaped "
 
 GEOGRAPHY    : G E O G R A P H Y SQUOTE         -> pushMode(MODE_ODATA_GEO); 
//TODO make case insensitive
 GEOMETRY     : G E O M E T R Y   SQUOTE         -> pushMode(MODE_ODATA_GEO);
@@ -364,8 +365,11 @@ mode MODE_JSON_STRING;
 // Any """ characters inside a string are escaped with "\".
 
//;==============================================================================
 
-STRING_IN_JSON         : ('\\"' | ~[\u0022] )* '"' -> popMode;
-ERROR_CHARACTER_jsm            : EOF | .;
+STRING_IN_JSON                         : (ESCAPED_JSON_CHAR | ~["\\])* '"' -> 
popMode;
+fragment ESCAPED_JSON_CHAR     : '\\' (["\\/bfnrt] | UNICODE_CHAR);
+fragment UNICODE_CHAR          : 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT;
+fragment HEX_DIGIT                     : [0-9a-fA-F];
+ERROR_CHARACTER_jsm                    : EOF | .;
 
 
//;==============================================================================
 mode MODE_ODATA_GEO;

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3584e1d7/lib/server-core/src/main/antlr4/org/apache/olingo/server/core/uri/antlr/UriParser.g4
----------------------------------------------------------------------
diff --git 
a/lib/server-core/src/main/antlr4/org/apache/olingo/server/core/uri/antlr/UriParser.g4
 
b/lib/server-core/src/main/antlr4/org/apache/olingo/server/core/uri/antlr/UriParser.g4
index 198d1ba..dc1af2b 100644
--- 
a/lib/server-core/src/main/antlr4/org/apache/olingo/server/core/uri/antlr/UriParser.g4
+++ 
b/lib/server-core/src/main/antlr4/org/apache/olingo/server/core/uri/antlr/UriParser.g4
@@ -205,6 +205,7 @@ commonExpr          : OPEN commonExpr CLOSE
                     | rootExpr                                                 
                         #altRoot     // $...
                     | AT odataIdentifier                                       
                         #altAlias    // @...
                     | primitiveLiteral                                         
                         #altLiteral  // ...
+                    | arrayOrObject                                            
                                                                                
                #altJson
                     ;
 
 unary               : (MINUS| NOT) ;
@@ -309,11 +310,15 @@ json_value          : jsonPrimitiv
                     | json_array;
 
 json_object         : BEGIN_OBJECT 
-                      STRING_IN_JSON
-                      WSP? COLON WSP? 
-                      json_value
+                      (
+                                         json_key_value_pair
+                                         (COMMA json_key_value_pair)*
+                      )?       
                       END_OBJECT;
 
+json_key_value_pair : STRING_IN_JSON
+                      WSP? COLON WSP? 
+                      json_value;
                                         
 //; JSON syntax: adapted to URI restrictions from [RFC4627]                 
 jsonPrimitiv        : STRING_IN_JSON

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3584e1d7/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriInfoImpl.java
----------------------------------------------------------------------
diff --git 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriInfoImpl.java
 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriInfoImpl.java
index 6b42a99..0aff5b6 100644
--- 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriInfoImpl.java
+++ 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriInfoImpl.java
@@ -25,8 +25,8 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import org.apache.olingo.commons.api.ex.ODataRuntimeException;
 import org.apache.olingo.commons.api.edm.EdmEntityType;
+import org.apache.olingo.commons.api.ex.ODataRuntimeException;
 import org.apache.olingo.server.api.uri.UriInfo;
 import org.apache.olingo.server.api.uri.UriInfoAll;
 import org.apache.olingo.server.api.uri.UriInfoBatch;
@@ -36,6 +36,7 @@ import org.apache.olingo.server.api.uri.UriInfoKind;
 import org.apache.olingo.server.api.uri.UriInfoMetadata;
 import org.apache.olingo.server.api.uri.UriInfoResource;
 import org.apache.olingo.server.api.uri.UriInfoService;
+import org.apache.olingo.server.api.uri.UriParameter;
 import org.apache.olingo.server.api.uri.UriResource;
 import org.apache.olingo.server.api.uri.queryoption.CountOption;
 import org.apache.olingo.server.api.uri.queryoption.CustomQueryOption;
@@ -63,8 +64,8 @@ public class UriInfoImpl implements UriInfo {
   private EdmEntityType entityTypeCast; // for $entity
 
   private List<CustomQueryOptionImpl> customQueryOptions = new 
ArrayList<CustomQueryOptionImpl>();
-  private Map<String, String> aliasToValue = new HashMap<String, String>();
-
+  private Map<String, UriParameter> aliasValues = new HashMap<String, 
UriParameter>();
+  
   private Map<SystemQueryOptionKind, SystemQueryOption> systemQueryOptions =
       new HashMap<SystemQueryOptionKind, SystemQueryOption>();
 
@@ -138,9 +139,18 @@ public class UriInfoImpl implements UriInfo {
 
   @Override
   public String getValueForAlias(final String alias) {
-    return aliasToValue.get(alias);
+    final UriParameter parameter = aliasValues.get(alias);
+    return parameter == null ? null : parameter.getText();
   }
 
+  public UriParameter getAlias(final String key) {
+    return aliasValues.get(key);
+  }
+  
+  public void addAlias(final String key, UriParameter parameter) {
+    aliasValues.put(key, parameter);
+  }
+  
   @Override
   public EdmEntityType getEntityTypeCast() {
     return entityTypeCast;
@@ -235,9 +245,6 @@ public class UriInfoImpl implements UriInfo {
 
   public void addCustomQueryOption(final CustomQueryOptionImpl item) {
     customQueryOptions.add(item);
-    if (item.getName().startsWith("@")) {
-      aliasToValue.put(item.getName(), item.getText());
-    }
   }
 
   /**
@@ -297,5 +304,4 @@ public class UriInfoImpl implements UriInfo {
   public Collection<SystemQueryOption> getSystemQueryOptions() {
     return Collections.unmodifiableCollection(systemQueryOptions.values());
   }
-
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3584e1d7/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 794948e..9beb251 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
@@ -30,8 +30,8 @@ import org.antlr.v4.runtime.RecognitionException;
 import org.antlr.v4.runtime.Token;
 import org.antlr.v4.runtime.atn.PredictionMode;
 import org.antlr.v4.runtime.misc.ParseCancellationException;
-import org.apache.olingo.commons.api.ex.ODataRuntimeException;
 import org.apache.olingo.commons.api.edm.Edm;
+import org.apache.olingo.commons.api.ex.ODataRuntimeException;
 import org.apache.olingo.server.api.uri.UriInfo;
 import org.apache.olingo.server.api.uri.UriInfoKind;
 import org.apache.olingo.server.api.uri.UriResource;
@@ -42,6 +42,7 @@ import org.apache.olingo.server.api.uri.UriResourceValue;
 import org.apache.olingo.server.api.uri.queryoption.SystemQueryOption;
 import org.apache.olingo.server.api.uri.queryoption.SystemQueryOptionKind;
 import org.apache.olingo.server.core.uri.UriInfoImpl;
+import org.apache.olingo.server.core.uri.UriParameterImpl;
 import org.apache.olingo.server.core.uri.antlr.UriLexer;
 import org.apache.olingo.server.core.uri.antlr.UriParserParser;
 import org.apache.olingo.server.core.uri.antlr.UriParserParser.AllEOFContext;
@@ -65,11 +66,14 @@ import 
org.apache.olingo.server.core.uri.queryoption.SelectOptionImpl;
 import org.apache.olingo.server.core.uri.queryoption.SkipOptionImpl;
 import org.apache.olingo.server.core.uri.queryoption.SkipTokenOptionImpl;
 import org.apache.olingo.server.core.uri.queryoption.TopOptionImpl;
+import org.apache.olingo.server.core.uri.queryoption.expression.ExpressionImpl;
 
 public class Parser {
   private static final String ATOM = "atom";
   private static final String JSON = "json";
   private static final String XML = "xml";
+  private static final String AT = "@";
+  private static final String NULL = "null";
   int logLevel = 0;
 
   private enum ParserEntryRules {
@@ -271,7 +275,26 @@ public class Parser {
                 
UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION, option.name);
           }
         } else {
-          CustomQueryOptionImpl customOption = new CustomQueryOptionImpl();
+          if (option.name.startsWith(AT)) {
+            final FilterExpressionEOFContext filterExpCtx =
+                (FilterExpressionEOFContext) parseRule(option.value, 
ParserEntryRules.FilterExpression);
+            final ExpressionImpl expression = ((FilterOptionImpl) 
uriParseTreeVisitor
+                .visitFilterExpressionEOF(filterExpCtx)).getExpression();
+
+            final UriParameterImpl parameter = new UriParameterImpl();
+            parameter.setAlias(option.name);
+            parameter.setExpression(expression);
+            parameter.setText(NULL.equals(option.value) ? null : option.value);
+            
+            if(context.contextUriInfo.getAlias(option.name) == null) {
+              context.contextUriInfo.addAlias(option.name, parameter);
+            } else {
+              throw new UriParserSyntaxException("Alias already specified! 
Name: " + option.name, 
+                  UriParserSyntaxException.MessageKeys.DUPLICATED_ALIAS, 
option.name);
+            }
+          }
+          
+          final CustomQueryOptionImpl customOption = new 
CustomQueryOptionImpl();
           customOption.setName(option.name);
           customOption.setText(option.value);
           context.contextUriInfo.addCustomQueryOption(customOption);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3584e1d7/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriContext.java
----------------------------------------------------------------------
diff --git 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriContext.java
 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriContext.java
index a6b9bff..b6b6fda 100644
--- 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriContext.java
+++ 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriContext.java
@@ -95,7 +95,12 @@ public class UriContext {
    */
   public UriInfoImpl contextUriInfo;
   public boolean contextReadingFunctionParameters;
-
+  
+  /**
+   * Set to true if the parser operates on query part.
+   */
+  public boolean contextReadingQueryPart;
+  
   public UriContext() {
 
     contextExpandItemPath = null;

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3584e1d7/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 7ea1adb..40c67c7 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
@@ -95,6 +95,7 @@ import 
org.apache.olingo.server.core.uri.antlr.UriParserParser.AltHasContext;
 import org.apache.olingo.server.core.uri.antlr.UriParserParser.AltMultContext;
 import org.apache.olingo.server.core.uri.antlr.UriParserParser.AltOrContext;
 import org.apache.olingo.server.core.uri.antlr.UriParserParser.AnyExprContext;
+import 
org.apache.olingo.server.core.uri.antlr.UriParserParser.ArrayOrObjectContext;
 import org.apache.olingo.server.core.uri.antlr.UriParserParser.BatchEOFContext;
 import 
org.apache.olingo.server.core.uri.antlr.UriParserParser.BinaryLiteralContext;
 import 
org.apache.olingo.server.core.uri.antlr.UriParserParser.BooleanNonCaseLiteralContext;
@@ -116,6 +117,7 @@ import 
org.apache.olingo.server.core.uri.antlr.UriParserParser.EnumLiteralContex
 import 
org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandCountOptionContext;
 import 
org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandItemContext;
 import 
org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandItemsContext;
+import 
org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandItemsEOFContext;
 import 
org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandOptionContext;
 import 
org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandPathContext;
 import 
org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandPathExtensionContext;
@@ -179,6 +181,7 @@ import 
org.apache.olingo.server.core.uri.antlr.UriParserParser.TotalOffsetMinute
 import 
org.apache.olingo.server.core.uri.antlr.UriParserParser.TotalsecondsMethodCallExprContext;
 import 
org.apache.olingo.server.core.uri.antlr.UriParserParser.TrimMethodCallExprContext;
 import 
org.apache.olingo.server.core.uri.antlr.UriParserParser.YearMethodCallExprContext;
+import 
org.apache.olingo.server.core.uri.parser.UriParserSemanticException.MessageKeys;
 import org.apache.olingo.server.core.uri.queryoption.CountOptionImpl;
 import org.apache.olingo.server.core.uri.queryoption.ExpandItemImpl;
 import org.apache.olingo.server.core.uri.queryoption.ExpandOptionImpl;
@@ -306,7 +309,7 @@ public class UriParseTreeVisitor extends 
UriParserBaseVisitor<Object> {
 
     final boolean checkFirst =
         context.contextUriInfo.getLastResourcePart() == null
-        || context.contextUriInfo.getLastResourcePart() instanceof 
UriResourceRootImpl;
+            || context.contextUriInfo.getLastResourcePart() instanceof 
UriResourceRootImpl;
 
     String odi = ctx.vODI.getText();
 
@@ -361,6 +364,12 @@ public class UriParseTreeVisitor extends 
UriParserBaseVisitor<Object> {
 
       // check FunctionImport
       EdmFunctionImport edmFunctionImport = 
edmEntityContainer.getFunctionImport(odi);
+      
+      if(edmFunctionImport != null && context.contextReadingQueryPart) {
+        throw wrap(new UriParserSemanticException("Function Imports are not 
allowed in $filter or $orderby", 
+            
UriParserSemanticException.MessageKeys.FUNCTION_IMPORT_NOT_ALLOWED, odi));
+      }
+      
       if (edmFunctionImport != null
           && (parts.isEmpty() || !(parts.get(0) instanceof 
UriResourcePartTyped)
               || parts.get(0) instanceof UriResourceRoot)) {
@@ -399,7 +408,7 @@ public class UriParseTreeVisitor extends 
UriParserBaseVisitor<Object> {
               + "' with parameters [" + tmp.toString() + "] not found",
               UriParserSemanticException.MessageKeys.FUNCTION_NOT_FOUND, 
edmFunctionImport.getName(), tmp.toString()));
         }
-        
+
         ensureNamespaceIsNull(ctx.vNS);
         uriResource.setFunction(edmFunctionImport.getUnboundFunction(names));
         context.contextUriInfo.addResourcePart(uriResource);
@@ -466,8 +475,8 @@ public class UriParseTreeVisitor extends 
UriParserBaseVisitor<Object> {
         throw wrap(new UriParserSemanticException("Property '" + odi + "' not 
found in type '"
             + structType.getFullQualifiedName().getFullQualifiedNameAsString() 
+ "'",
             ctx.depth() > 2 ? // path evaluation inside an expression or for 
the resource path?
-                
UriParserSemanticException.MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE :
-                UriParserSemanticException.MessageKeys.PROPERTY_NOT_IN_TYPE,
+                
UriParserSemanticException.MessageKeys.EXPRESSION_PROPERTY_NOT_IN_TYPE
+                : UriParserSemanticException.MessageKeys.PROPERTY_NOT_IN_TYPE,
             structType.getFullQualifiedName().getFullQualifiedNameAsString(), 
odi));
       }
 
@@ -492,7 +501,7 @@ public class UriParseTreeVisitor extends 
UriParserBaseVisitor<Object> {
               "Navigation properties in expand system query options must not 
be followed by a key.",
               UriParserSemanticException.MessageKeys.KEY_NOT_ALLOWED));
         }
-        
+
         UriResourceNavigationPropertyImpl navigationResource = new 
UriResourceNavigationPropertyImpl()
             .setNavigationProperty((EdmNavigationProperty) property);
         context.contextUriInfo.addResourcePart(navigationResource);
@@ -666,8 +675,8 @@ public class UriParseTreeVisitor extends 
UriParserBaseVisitor<Object> {
 
       // do a check for bound functions (which requires a parameter list)
       if (ctx.vlNVO.size() == 0) {
-        throw wrap(new UriParserSemanticException("Unknown type for type cast 
" + fullFilterName.toString() 
-        + " not found", UriParserSemanticException.MessageKeys.UNKNOWN_TYPE , 
fullFilterName.toString()));
+        throw wrap(new UriParserSemanticException("Unknown type for type cast 
" + fullFilterName.toString()
+            + " not found", 
UriParserSemanticException.MessageKeys.UNKNOWN_TYPE, 
fullFilterName.toString()));
       }
 
       context.contextReadingFunctionParameters = true;
@@ -712,17 +721,17 @@ public class UriParseTreeVisitor extends 
UriParserBaseVisitor<Object> {
           UriParserSemanticException.MessageKeys.UNKNOWN_PART, 
fullFilterName.toString()));
     }
   }
-  
+
   /**
    * Ensures that the namespace of the first resource parts is null
    * @param vNS namespace or null
    */
   private void ensureNamespaceIsNull(final NamespaceContext vNS) {
-    if(vNS != null && context.contextUriInfo.getLastResourcePart() == null) {
+    if (vNS != null && context.contextUriInfo.getLastResourcePart() == null) {
       // First resource part and namespace is not null!
-      throw wrap(new UriParserSemanticException("Namespace is not allowed for 
EntitySets, Singeltons, " 
-          + " Action Imports and Function Imports. Found " + vNS.getText(), 
-            
UriParserSemanticException.MessageKeys.NAMESPACE_NOT_ALLOWED_AT_FIRST_ELEMENT, 
vNS.getText()));
+      throw wrap(new UriParserSemanticException("Namespace is not allowed for 
EntitySets, Singeltons, "
+          + " Action Imports and Function Imports. Found " + vNS.getText(),
+          
UriParserSemanticException.MessageKeys.NAMESPACE_NOT_ALLOWED_AT_FIRST_ELEMENT, 
vNS.getText()));
     }
   }
 
@@ -1138,22 +1147,22 @@ public class UriParseTreeVisitor extends 
UriParserBaseVisitor<Object> {
     UriInfoImpl crossJoin = new UriInfoImpl().setKind(UriInfoKind.crossjoin);
 
     for (OdataIdentifierContext obj : ctx.vlODI) {
-      String odi = obj.getText();            
+      String odi = obj.getText();
       crossJoin.addEntitySetName(odi);
-      
+
       EdmEntitySet edmEntitySet = edmEntityContainer.getEntitySet(odi);
       if (edmEntitySet == null) {
         throw wrap(new UriParserSemanticException("Expected EntityTypeName",
-            UriParserSemanticException.MessageKeys.UNKNOWN_PART, odi));        
+            UriParserSemanticException.MessageKeys.UNKNOWN_PART, odi));
       }
-      
+
       EdmEntityType type = edmEntitySet.getEntityType();
       if (type == null) {
         throw wrap(new UriParserSemanticException("Expected EntityTypeName",
             UriParserSemanticException.MessageKeys.UNKNOWN_ENTITY_TYPE, odi));
       }
       // contextUriInfo = uriInfo;
-      context.contextTypes.push(new TypeInformation(type, true));    
+      context.contextTypes.push(new TypeInformation(type, true));
     }
 
     context.contextUriInfo = crossJoin;
@@ -1237,10 +1246,10 @@ public class UriParseTreeVisitor extends 
UriParserBaseVisitor<Object> {
         levels.setText(ctx.vM.getText());
         try {
           expandItem.setSystemQueryOption(levels);
-        } catch(ODataRuntimeException e) {
+        } catch (ODataRuntimeException e) {
           // Thrown if duplicated system query options are detected
           throw wrap(new UriParserSyntaxException("Double system query 
option!", e,
-                
UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION, 
e.getMessage()));
+              UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION, 
e.getMessage()));
         }
       } else if (ctx.vL != null) {
         LevelsOptionImpl levels = new LevelsOptionImpl();
@@ -1249,10 +1258,10 @@ public class UriParseTreeVisitor extends 
UriParserBaseVisitor<Object> {
         levels.setValue(Integer.parseInt(text));
         try {
           expandItem.setSystemQueryOption(levels);
-        } catch(ODataRuntimeException e) {
+        } catch (ODataRuntimeException e) {
           // Thrown if duplicated system query options are detected
           throw wrap(new UriParserSyntaxException("Double system query 
option!", e,
-                
UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION, 
e.getMessage()));
+              UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION, 
e.getMessage()));
         }
       }
 
@@ -1269,10 +1278,10 @@ public class UriParseTreeVisitor extends 
UriParserBaseVisitor<Object> {
           for (SystemQueryOptionImpl option : list) {
             expandItem.setSystemQueryOption(option);
           }
-        } catch(ODataRuntimeException e) {
+        } catch (ODataRuntimeException e) {
           // Thrown if duplicated system query options are detected
           throw wrap(new UriParserSyntaxException("Double system query 
option!", e,
-                
UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION, 
e.getMessage()));
+              UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION, 
e.getMessage()));
         }
         context.contextExpandItemPath = contextExpandItemPathBU;
       }
@@ -1293,11 +1302,11 @@ public class UriParseTreeVisitor extends 
UriParserBaseVisitor<Object> {
     // set tmp context
     context.contextExpandItemPath = expandItem;
     context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.resource);
-    
+
     context.contextVisitExpandResourcePath = true;
     super.visitExpandPath(ctx);
     context.contextVisitExpandResourcePath = false;
-    
+
     EdmType startType = 
removeUriResourceStartingTypeFilterImpl(context.contextUriInfo);
     expandItem.setResourcePath(context.contextUriInfo);
     if (startType != null) {
@@ -1400,14 +1409,22 @@ public class UriParseTreeVisitor extends 
UriParserBaseVisitor<Object> {
 
   @Override
   public Object visitFilter(final FilterContext ctx) {
+    context.contextReadingQueryPart = true;
+    final FilterOptionImpl result = new 
FilterOptionImpl().setExpression((ExpressionImpl) ctx.children.get(2)
+                                                          .accept(this));
+    context.contextReadingQueryPart = false;
 
-    return new FilterOptionImpl().setExpression((ExpressionImpl) 
ctx.children.get(2).accept(this));
+    return result;
   }
 
   @Override
   public Object visitFilterExpressionEOF(final FilterExpressionEOFContext ctx) 
{
+    context.contextReadingQueryPart = true;
+    final FilterOptionImpl result = new 
FilterOptionImpl().setExpression((ExpressionImpl) ctx.children.get(0)
+                                                          .accept(this));
+    context.contextReadingQueryPart = false;
 
-    return new FilterOptionImpl().setExpression((ExpressionImpl) 
ctx.children.get(0).accept(this));
+    return result;
   }
 
   @Override
@@ -1614,7 +1631,7 @@ public class UriParseTreeVisitor extends 
UriParserBaseVisitor<Object> {
               UriParserSemanticException.MessageKeys.KEY_NOT_ALLOWED));
         } else {
           // The functions returns a collection of entities
-          // Get the EDM Type and determine how many key predicates are 
needed. In this case only one 
+          // Get the EDM Type and determine how many key predicates are 
needed. In this case only one
           // key predicate is allowed. If the entity type needs more than one 
key predicate, the client
           // has to use the key value syntax e.g. EntitySet(ID=1,Order=2)
           final EdmEntityType entityType = (EdmEntityType) 
uriResourceFunction.getFunction().getReturnType().getType();
@@ -1711,7 +1728,7 @@ public class UriParseTreeVisitor extends 
UriParserBaseVisitor<Object> {
         throw wrap(new UriParserSemanticException("Parameters list on untyped 
resource path segment not allowed",
             
UriParserSemanticException.MessageKeys.PARAMETERS_LIST_ONLY_FOR_TYPED_PARTS));
       }
-      if(last instanceof UriResourceFunction) {
+      if (last instanceof UriResourceFunction) {
         final UriResourceFunction uriResourceFunction = (UriResourceFunction) 
context.contextUriInfo
             .getLastResourcePart();
         final EdmReturnType returnType = 
uriResourceFunction.getFunction().getReturnType();
@@ -1721,12 +1738,12 @@ public class UriParseTreeVisitor extends 
UriParserBaseVisitor<Object> {
               UriParserSemanticException.MessageKeys.KEY_NOT_ALLOWED));
         } else {
           // The functions returns a collection of entities
-          // Get the EDM Type and determine how many key predicates are 
needed. 
+          // Get the EDM Type and determine how many key predicates are needed.
           // In case of functions all key predicates must be provided by the 
client.
           final EdmEntityType entityType = (EdmEntityType) 
uriResourceFunction.getFunction().getReturnType().getType();
           final List<String> lastKeyPredicates = 
entityType.getKeyPredicateNames();
-          
-          if(lastKeyPredicates.size() == list.size()) {
+
+          if (lastKeyPredicates.size() == list.size()) {
             return list;
           } else {
             throw wrap(new UriParserSemanticException("Wrong number of key 
properties.",
@@ -1737,15 +1754,15 @@ public class UriParseTreeVisitor extends 
UriParserBaseVisitor<Object> {
       } else {
         // Handle entity sets
         EdmEntityType lastType = (EdmEntityType) ((UriResourcePartTyped) 
last).getType();
-  
+
         // get list of keys for lastType
         List<String> lastKeyPredicates = lastType.getKeyPredicateNames();
-  
+
         // check if all key are filled from the URI
         if (list.size() == lastKeyPredicates.size()) {
           return list;
         }
-  
+
         // if not, check if the missing key predicates can be satisfied with 
help of the defined
         // referential constraints
         // for using referential constraints the last resource part must be a 
navigation property
@@ -1755,7 +1772,7 @@ public class UriParseTreeVisitor extends 
UriParserBaseVisitor<Object> {
               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) {
@@ -1763,7 +1780,7 @@ public class UriParseTreeVisitor extends 
UriParserBaseVisitor<Object> {
               
UriParserSemanticException.MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES,
               Integer.toString(lastKeyPredicates.size()), 
Integer.toString(list.size())));
         }
-  
+
         // fill missing keys from referential constraints
         for (String key : lastKeyPredicates) {
           boolean found = false;
@@ -1773,7 +1790,7 @@ public class UriParseTreeVisitor extends 
UriParserBaseVisitor<Object> {
               break;
             }
           }
-  
+
           if (!found) {
             String property = partner.getReferencingPropertyName(key);
             if (property != null) {
@@ -1782,7 +1799,7 @@ public class UriParseTreeVisitor extends 
UriParserBaseVisitor<Object> {
             }
           }
         }
-  
+
         // check again if all key predicates are filled from the URI
         if (list.size() == lastKeyPredicates.size()) {
           return list;
@@ -1794,7 +1811,7 @@ public class UriParseTreeVisitor extends 
UriParserBaseVisitor<Object> {
       }
     } else {
       // No key predicates are provided by the client
-      
+
       if (context.contextReadingFunctionParameters) {
         return Collections.emptyList();
       } else {
@@ -1825,8 +1842,8 @@ public class UriParseTreeVisitor extends 
UriParserBaseVisitor<Object> {
 
   @Override
   public Object visitNaninfinityLiteral(final NaninfinityLiteralContext ctx) {
-    return new 
LiteralImpl().setType(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal)).
-        setText(ctx.getText());
+    return new 
LiteralImpl().setType(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal)).setText(ctx
+        .getText());
   }
 
   @Override
@@ -1863,7 +1880,8 @@ public class UriParseTreeVisitor extends 
UriParserBaseVisitor<Object> {
 
   @Override
   public Object visitOrderByEOF(final OrderByEOFContext ctx) {
-
+    context.contextReadingQueryPart = true;
+    
     OrderByOptionImpl orderBy = new OrderByOptionImpl();
 
     for (OrderByItemContext item : ((OrderListContext) ctx.getChild(0)).vlOI) {
@@ -1871,6 +1889,7 @@ public class UriParseTreeVisitor extends 
UriParserBaseVisitor<Object> {
       orderBy.addOrder(oItem);
     }
 
+    context.contextReadingFunctionParameters = false;
     return orderBy;
   }
 
@@ -1902,11 +1921,11 @@ public class UriParseTreeVisitor extends 
UriParserBaseVisitor<Object> {
       // check for keyPredicates
       if (pathInfoSegment instanceof UriResourceWithKeysImpl) {
         if (ctx.vlNVO.size() > 1) {
-          throw wrap(new UriParserSemanticException("More than one key 
predicates found", 
+          throw wrap(new UriParserSemanticException("More than one key 
predicates found",
               
UriParserSemanticException.MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES, "1",
               Integer.toString(ctx.vlNVO.size())));
         }
-        
+
         @SuppressWarnings("unchecked")
         List<UriParameterImpl> list = (List<UriParameterImpl>) 
ctx.vlNVO.get(0).accept(this);
         ((UriResourceWithKeysImpl) pathInfoSegment)
@@ -1937,7 +1956,7 @@ public class UriParseTreeVisitor extends 
UriParserBaseVisitor<Object> {
   @Override
   public Object visitPrimitiveLiteral(final PrimitiveLiteralContext ctx) {
     ParseTree child1 = ctx.children.get(0);
-    
+
     if (child1 instanceof EnumLiteralContext
         || child1 instanceof BooleanNonCaseLiteralContext
         || child1 instanceof NullruleLiteralContext
@@ -1954,11 +1973,11 @@ public class UriParseTreeVisitor extends 
UriParserBaseVisitor<Object> {
         || child1 instanceof BinaryLiteralContext) {
       return child1.accept(this);
     }
-    
-    // TODO Implement geography types and set the proper type
+
+    // TODO Implement geography types and set a proper type
     return new LiteralImpl().setText(ctx.getText());
   }
-  
+
   @Override
   public Object visitBinaryLiteral(BinaryLiteralContext ctx) {
     return new LiteralImpl().setText(ctx.getText())
@@ -1968,14 +1987,14 @@ public class UriParseTreeVisitor extends 
UriParserBaseVisitor<Object> {
   @Override
   public Object visitStringLiteral(final StringLiteralContext ctx) {
     return new LiteralImpl().setText(ctx.getText())
-                            
.setType(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.String));
+        
.setType(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.String));
   }
-  
+
   @Override
   public Object visitDecimalLiteral(final DecimalLiteralContext ctx) {
     final EdmType type = EdmPrimitiveTypeFactory.getInstance(
-        ctx.getText().contains("e") || ctx.getText().contains("E") ?
-            EdmPrimitiveTypeKind.Double : EdmPrimitiveTypeKind.Decimal);
+        ctx.getText().contains("e") || ctx.getText().contains("E") ? 
EdmPrimitiveTypeKind.Double
+            : EdmPrimitiveTypeKind.Decimal);
 
     return new LiteralImpl().setText(ctx.getText()).setType(type);
   }
@@ -1999,7 +2018,7 @@ public class UriParseTreeVisitor extends 
UriParserBaseVisitor<Object> {
       }
 
       return new LiteralImpl().setText(ctx.getText()).setType(type);
-    } catch( NumberFormatException e) {
+    } catch (NumberFormatException e) {
       return new LiteralImpl().setText(ctx.getText())
           
.setType(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal));
     }
@@ -2012,7 +2031,7 @@ public class UriParseTreeVisitor extends 
UriParserBaseVisitor<Object> {
   }
 
   @Override
-  public Object visitDatetimeoffsetLiteral(final  DatetimeoffsetLiteralContext 
ctx) {
+  public Object visitDatetimeoffsetLiteral(final DatetimeoffsetLiteralContext 
ctx) {
     return new LiteralImpl().setText(ctx.getText())
         
.setType(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.DateTimeOffset));
   }
@@ -2124,13 +2143,17 @@ public class UriParseTreeVisitor extends 
UriParserBaseVisitor<Object> {
 
   @Override
   public Object visitSelectEOF(final SelectEOFContext ctx) {
+    context.contextReadingQueryPart = true;
     List<SelectItemImpl> selectItems = new ArrayList<SelectItemImpl>();
 
     for (SelectItemContext si : ctx.vlSI) {
       selectItems.add((SelectItemImpl) si.accept(this));
     }
 
-    return new 
SelectOptionImpl().setSelectItems(selectItems).setText(ctx.getText());
+    final QueryOptionImpl result = new 
SelectOptionImpl().setSelectItems(selectItems).setText(ctx.getText());
+    context.contextReadingQueryPart = false;
+    
+    return result;
   }
 
   @Override
@@ -2492,10 +2515,29 @@ public class UriParseTreeVisitor extends 
UriParserBaseVisitor<Object> {
     alias.setParameter("@" + ctx.odataIdentifier().getChild(0).getText());
     return alias;
   }
-  
+
   @Override
   public Object visitSearchSpecialToken(final SearchSpecialTokenContext ctx) {
-    throw wrap(new UriParserSemanticException("System query option '$search' 
not implemented!", 
-                UriParserSemanticException.MessageKeys.NOT_IMPLEMENTED, 
"System query option '$search"));
+    throw wrap(new UriParserSemanticException("System query option '$search' 
not implemented!",
+        UriParserSemanticException.MessageKeys.NOT_IMPLEMENTED, "System query 
option '$search"));
+  }
+
+  @Override
+  public Object visitArrayOrObject(final ArrayOrObjectContext ctx) {
+    if (!context.contextReadingQueryPart) {
+      throw wrap(new UriParserSemanticException("Complex parameter are not 
allowed in resource path",
+          MessageKeys.COMPLEX_PARAMETER_IN_RESOURCE_PATH, ctx.getText()));
+    }
+
+    return new LiteralImpl().setText(ctx.getText()).setType(null);
+  }
+  
+  @Override
+  public Object visitExpandItemsEOF(ExpandItemsEOFContext ctx) {
+    context.contextReadingQueryPart = true;
+    final Object result = super.visitExpandItemsEOF(ctx);
+    context.contextReadingQueryPart = false;
+    
+    return result;
   }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3584e1d7/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 6803e7a..9135dd8 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
@@ -79,7 +79,11 @@ public class UriParserSemanticException extends 
UriParserException {
     /** parameter: not implemented part */
     NOT_IMPLEMENTED,
     /** parameter: namespace **/
-    NAMESPACE_NOT_ALLOWED_AT_FIRST_ELEMENT;
+    NAMESPACE_NOT_ALLOWED_AT_FIRST_ELEMENT, 
+    /** parameter: complex parameter value */
+    COMPLEX_PARAMETER_IN_RESOURCE_PATH, 
+    /** parameter: function import name */
+    FUNCTION_IMPORT_NOT_ALLOWED;
     
     @Override
     public String getKey() {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3584e1d7/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 2a18d5a..31f69d3 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
@@ -35,7 +35,9 @@ public class UriParserSyntaxException extends 
UriParserException {
     /** parameter: $format option value */
     WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION_FORMAT,
     SYSTEM_QUERY_OPTION_LEVELS_NOT_ALLOWED_HERE,
-    SYNTAX;
+    SYNTAX, 
+    /** parameter: alias name */
+    DUPLICATED_ALIAS;
 
     @Override
     public String getKey() {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3584e1d7/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 d883b0c..01af75d 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
@@ -37,6 +37,8 @@ public class UriValidationException extends 
ODataLibraryException {
     UNSUPPORTED_ACTION_RETURN_TYPE,
     /** parameter: unsupported http method */
     UNSUPPORTED_HTTP_METHOD,
+    /** parameter: unsupported parameter name */
+    UNSUPPORTED_PARAMETER,
     /** parameter: system query option */
     SYSTEM_QUERY_OPTION_NOT_ALLOWED,
     /** parameters: system query option, http method */
@@ -54,8 +56,11 @@ public class UriValidationException extends 
ODataLibraryException {
     /** parameter: unallowed kind before $count */
     UNALLOWED_KIND_BEFORE_COUNT, 
     /** parameter: unallowed resource path */
-    UNALLOWED_RESOURCE_PATH;
+    UNALLOWED_RESOURCE_PATH,
+    /** parameter: missing parameter name */
+    MISSING_PARAMETER;
 
+    
     @Override
     public String getKey() {
       return name();

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3584e1d7/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 feb52ec..39c73da 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
@@ -139,6 +139,7 @@ public class UriValidator {
       validateForHttpMethod(uriInfo, httpMethod);
     }
     validateQueryOptions(uriInfo);
+    validateParameters(uriInfo);
     validateKeyPredicates(uriInfo);
     validatePropertyOperations(uriInfo, httpMethod);
   }
@@ -556,6 +557,58 @@ public class UriValidator {
     return UriResourceKind.action == 
uriResourceParts.get(uriResourceParts.size() - 1).getKind();
   }
 
+  private void validateParameters(final UriInfo uriInfo) throws 
UriValidationException {
+    for (UriResource pathSegment : uriInfo.getUriResourceParts()) {
+      final boolean isFunction = pathSegment.getKind() == 
UriResourceKind.function;
+      
+      if(isFunction) {
+        final UriResourceFunction functionPathSegement = (UriResourceFunction) 
pathSegment;
+        final EdmFunction edmFuntion = functionPathSegement.getFunction();
+        
+        final Map<String, UriParameter> parameters = new HashMap<String, 
UriParameter>();
+        for(final UriParameter parameter : 
functionPathSegement.getParameters()) {
+          parameters.put(parameter.getName(), parameter);
+        }
+        
+        boolean firstParameter = true;
+        for(final String parameterName : edmFuntion.getParameterNames()) {
+          final UriParameter parameter = parameters.get(parameterName);
+          final boolean isNullable = 
edmFuntion.getParameter(parameterName).isNullable();
+          
+          if(parameter != null) {
+            /** No alias, value explicit null */
+            if(parameter.getText() == null 
+                && parameter.getAlias() == null && !isNullable) {
+              throw new UriValidationException("Missing non nullable parameter 
" + parameterName, 
+                  UriValidationException.MessageKeys.MISSING_PARAMETER, 
parameterName);
+            } else if(parameter.getText() == null && parameter.getAlias() != 
null) {
+              final String valueForAlias = 
uriInfo.getValueForAlias(parameter.getAlias());
+              /** Alias value is missing or explicit null **/
+              if(valueForAlias == null && !isNullable) {
+                throw new UriValidationException("Missing non nullable 
parameter " + parameterName, 
+                    UriValidationException.MessageKeys.MISSING_PARAMETER, 
parameterName);
+              }
+            }
+            
+            parameters.remove(parameterName);
+          } else if(!isNullable && !(firstParameter && edmFuntion.isBound())) {
+            // The first parameter of bound functions is implicit provided by 
the preceding path segment
+            throw new UriValidationException("Missing non nullable parameter " 
+ parameterName, 
+                UriValidationException.MessageKeys.MISSING_PARAMETER, 
parameterName);
+          }
+          
+          firstParameter = false;
+        }
+        
+        if(!parameters.isEmpty()) {
+          final String parameterName = parameters.keySet().iterator().next();
+          throw new UriValidationException("Unsupported parameter " + 
parameterName, 
+              UriValidationException.MessageKeys.UNSUPPORTED_PARAMETER, 
parameterName);
+        }
+      }
+    }
+  }
+  
   private void validateKeyPredicates(final UriInfo uriInfo) throws 
UriValidationException {
     for (UriResource pathSegment : uriInfo.getUriResourceParts()) {
       final boolean isEntitySet = pathSegment.getKind() == 
UriResourceKind.entitySet;

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3584e1d7/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 267db11..08e9eb8 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
@@ -35,6 +35,7 @@ 
UriParserSyntaxException.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION=The system query op
 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.SYSTEM_QUERY_OPTION_LEVELS_NOT_ALLOWED_HERE=The 
system query option '$levels' is not allowed here.
 UriParserSyntaxException.SYNTAX=The URI is malformed.
+UriParserSyntaxException.DUPLICATED_ALIAS=Duplicated alias. An alias '%1$s' 
was already specified!.
 
 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.
@@ -68,6 +69,8 @@ UriParserSemanticException.PREVIOUS_PART_TYPED=The previous 
part is typed.
 UriParserSemanticException.RESOURCE_NOT_FOUND=Cannot find EntitySet, 
Singleton, ActionImport or FunctionImport with name '%1$s'.
 UriParserSemanticException.NOT_IMPLEMENTED=%1$s is not implemented!
 UriParserSemanticException.NAMESPACE_NOT_ALLOWED_AT_FIRST_ELEMENT=Namespace is 
not allowed for Entity Sets, Singeltons, Action Imports and Function Imports. 
Found '%1$s'.
+UriParserSemanticException.COMPLEX_PARAMETER_IN_RESOURCE_PATH=Complex 
parameters must not appear in resource path segments. Found: '%1$s'.
+UriParserSemanticException.FUNCTION_IMPORT_NOT_ALLOWED=Function Imports are 
not allowed in $filter or $orderby. Found: '%1$s'.
 
 UriValidationException.UNSUPPORTED_QUERY_OPTION=The query option '%1$s' is not 
supported.
 UriValidationException.UNSUPPORTED_URI_KIND=The URI kind '%1$s' is not 
supported.
@@ -75,6 +78,7 @@ UriValidationException.UNSUPPORTED_URI_RESOURCE_KIND=The URI 
resource kind '%1$s
 UriValidationException.UNSUPPORTED_FUNCTION_RETURN_TYPE=The function return 
type '%1$s' is not supported.
 UriValidationException.UNSUPPORTED_ACTION_RETURN_TYPE=The action return type 
'%1$s' is not supported.
 UriValidationException.UNSUPPORTED_HTTP_METHOD=The HTTP method '%1$s' is not 
supported.
+UriValidationException.UNSUPPORTED_PARAMETER=The parameter '%1$s' is not 
supported.
 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.
@@ -84,6 +88,7 @@ UriValidationException.SECOND_LAST_SEGMENT_NOT_TYPED=The 
second last segment '%1
 UriValidationException.UNALLOWED_KIND_BEFORE_VALUE=The kind '%1$s' is not 
allowed before '$value'.
 UriValidationException.UNALLOWED_KIND_BEFORE_COUNT=The kind '%1$s' is not 
allowed before '$count'.
 UriValidationException.UNALLOWED_RESOURCE_PATH=The resource part '%1$s' is not 
allowed.
+UriValidationException.MISSING_PARAMETER=Missing mandatory parameter '%1$s'.
 
 ContentNegotiatorException.UNSUPPORTED_ACCEPT_TYPES=The content-type range 
'%1$s' is not supported as value of the Accept header.
 ContentNegotiatorException.UNSUPPORTED_CONTENT_TYPE=The content type '%1$s' is 
not supported.

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3584e1d7/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 4d39d97..90f9995 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
@@ -2036,7 +2036,8 @@ public class TestFullResourcePath {
 
     testUri.run("FICRTCollESTwoKeyNavParam(ParameterInt16=@parameterAlias)", 
"@parameterAlias=1");
     
testUri.run("FICRTCollESTwoKeyNavParam(ParameterInt16=@parameterAlias)/$count", 
"@parameterAlias=1");
-    testUri.run("FICRTCollESTwoKeyNavParam(ParameterInt16=@invalidAlias)", 
"@validAlias=1");
+    testUri.runEx("FICRTCollESTwoKeyNavParam(ParameterInt16=@invalidAlias)", 
"@validAlias=1")
+      .isExValidation(UriValidationException.MessageKeys.MISSING_PARAMETER);
   }
 
   @Test
@@ -5658,7 +5659,94 @@ public class TestFullResourcePath {
       .root()
       .right().isLiteral("" + 
Long.MAX_VALUE).isLiteralType(EdmInt64.getInstance());
   }
+  
+  @Test
+  public void parameterAliasLiteralValidation() throws Exception {
+    testUri.run("ESAllPrim(PropertyInt16=@p1)", "@p1=1");
+    testUri.run("ESAllPrim(PropertyInt16=@p1)", "@p1=-2");
+    testUri.runEx("ESAllPrim(PropertyInt16=@p1)", "@p1='ewe'")
+      .isExValidation(UriValidationException.MessageKeys.INVALID_KEY_PROPERTY);
+    testUri.runEx("ESAllPrim(PropertyInt16=@p1)", "@p1='ewe")
+      .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
+  }
+  
+  @Test
+  public void functionsWithComplexParameters() throws Exception {
+    testUri.run("ESTwoKeyNav/olingo.odata.test1.BFCESTwoKeyNavRTStringParam" 
+          + "(ParameterComp=@p1)", 
"@p1={\"PropertyInt16\":1,\"ProperyString\":\"1\"}")
+      .goPath()
+      .at(0).isEntitySet("ESTwoKeyNav")
+      .at(1).isFunction("BFCESTwoKeyNavRTStringParam").isParameterAlias(0, 
"ParameterComp", "@p1")
+      .isInAliasToValueMap("@p1", 
"{\"PropertyInt16\":1,\"ProperyString\":\"1\"}");
+    
+    // Test JSON String lexer rule 
=\"3,Int16=abc},\\\nabc&test%test\b\f\r\t\u0022}
+    final String stringValueEncoded = 
"=\\\"3,Int16=abc},\\\\\\nabc%26test%25test\\b\\f\\r\\t\\u0022}";
+    final String stringValueDecoded = 
"=\\\"3,Int16=abc},\\\\\\nabc&test%test\\b\\f\\r\\t\\u0022}";
 
+    testUri.run("ESTwoKeyNav/olingo.odata.test1.BFCESTwoKeyNavRTStringParam" 
+        + "(ParameterComp=@p1)", 
"@p1={\"PropertyInt16\":1,\"ProperyString\":\"" + stringValueEncoded + "\"}")
+    .goPath()
+    .at(0).isEntitySet("ESTwoKeyNav")
+    .at(1).isFunction("BFCESTwoKeyNavRTStringParam").isParameterAlias(0, 
"ParameterComp", "@p1")
+    .isInAliasToValueMap("@p1", "{\"PropertyInt16\":1,\"ProperyString\":\"" + 
stringValueDecoded + "\"}");
+    
+    testUri.run("ESTwoKeyNav", 
"$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam" 
+        + "(ParameterComp={\"PropertyString\":\"Test\",\"PropertyInt16\":1}) 
eq 'Test'")
+    .goFilter().left().is("<<BFCESTwoKeyNavRTStringParam> eq <'Test'>>")
+    .isParameterText(0, "{\"PropertyString\":\"Test\",\"PropertyInt16\":1}");
+    
+    testUri.run("ESTwoKeyNav", 
"$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam" 
+        + "(ParameterComp={\"PropertyString\":\"" + stringValueEncoded + 
"\",\"PropertyInt16\":1}) eq 'Test'")
+    .goFilter().left().is("<<BFCESTwoKeyNavRTStringParam> eq <'Test'>>")
+    .isParameterText(0, 
"{\"PropertyString\":\"=\\\"3,Int16=abc},\\\\\\nabc&test%test\\b\\f\\r\\t\\u0022}\","
 
+        + "\"PropertyInt16\":1}");
+    
+    testUri.run("ESTwoKeyNav", 
"$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
+        + "(ParameterComp=@p1) eq 
0&@p1={\"PropertyInt16\":1,\"ProperyString\":\"1\"}");
+    
+    testUri.runEx("ESTwoKeyNav/olingo.odata.test1.BFCESTwoKeyNavRTStringParam" 
+        + "(ParameterComp=@p1)", 
"@p1={\"PropertyInt16\":1,\"ProperyString\":'1'}")
+      .isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
+    
+    testUri.runEx("ESTwoKeyNav/olingo.odata.test1.BFCESTwoKeyNavRTStringParam" 
+        + "(ParameterComp={\"PropertyInt16\":1,\"PropertyString\":\"Test\"})")
+      
.isExSemantic(UriParserSemanticException.MessageKeys.COMPLEX_PARAMETER_IN_RESOURCE_PATH);
+    
+    
testUri.runEx("FICRTCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=null)")
+      .isExValidation(UriValidationException.MessageKeys.MISSING_PARAMETER);
+    
+    
testUri.runEx("FICRTCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test)")
+      .isExValidation(UriValidationException.MessageKeys.MISSING_PARAMETER);
+    
+    
testUri.runEx("FICRTCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test)", 
"@test=null")
+      .isExValidation(UriValidationException.MessageKeys.MISSING_PARAMETER);
+    
+    
testUri.run("FICRTCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test)", 
"@test='null'");
+    
+    
testUri.runEx("FICRTCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test, 
UnknownParam=1)", "@test='null'")
+      .isExSemantic(UriParserSemanticException.MessageKeys.FUNCTION_NOT_FOUND);
+    
+    
testUri.run("FICRTCollCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test)",
 "@test='null'");
+    
testUri.run("FICRTCollCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test)",
 "@test=null");
+    
testUri.run("FICRTCollCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test)");
+    
testUri.run("FICRTCollCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=null)");
+    
+    
testUri.runEx("FICRTCollCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test)",
 "@test=null&@test='1'")
+      .isExSyntax(UriParserSyntaxException.MessageKeys.DUPLICATED_ALIAS);
+  
+    testUri.runEx("ESAllPrim", "$filter=FINRTInt16() eq 0")
+      
.isExSemantic(UriParserSemanticException.MessageKeys.FUNCTION_IMPORT_NOT_ALLOWED);
+  }
+  
+  @Test
+  @Ignore("Key predicates in filter/orderby expression are not validated 
currently")
+  public void testKeyPredicatesInExpressions() throws Exception {
+    testUri.run("ESTwoKeyNav", 
"$filter=NavPropertyETTwoKeyNavMany(PropertyString='1',PropertyInt16=1)" 
+          + "/PropertyInt16 eq 1");
+    testUri.runEx("ESTwoKeyNav", 
"$filter=NavPropertyETTwoKeyNavMany(Prop='22',P=2)/PropertyInt16 eq 0")
+      .isExValidation(UriValidationException.MessageKeys.INVALID_KEY_PROPERTY);
+  }
+  
   public static String encode(final String decoded) throws 
UnsupportedEncodingException {
     return Encoder.encode(decoded);
   }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3584e1d7/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestUriParserImpl.java
----------------------------------------------------------------------
diff --git 
a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestUriParserImpl.java
 
b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestUriParserImpl.java
index b115fb8..b171c04 100644
--- 
a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestUriParserImpl.java
+++ 
b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestUriParserImpl.java
@@ -1061,7 +1061,7 @@ public class TestUriParserImpl {
 
   @Test
   public void testAlias() throws Exception {
-    testUri.run("ESAllPrim", "$filter=PropertyInt16 eq @p1&@p1=1)")
+    testUri.run("ESAllPrim", "$filter=PropertyInt16 eq @p1&@p1=1")
     .goFilter().is("<<PropertyInt16> eq <@p1>>");
   }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3584e1d7/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/EdmTechTestProvider.java
----------------------------------------------------------------------
diff --git 
a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/EdmTechTestProvider.java
 
b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/EdmTechTestProvider.java
index 08c6c91..2ab43e1 100644
--- 
a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/EdmTechTestProvider.java
+++ 
b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/EdmTechTestProvider.java
@@ -27,6 +27,7 @@ import org.apache.olingo.commons.api.edm.FullQualifiedName;
 import org.apache.olingo.commons.api.edm.provider.CsdlComplexType;
 import org.apache.olingo.commons.api.edm.provider.CsdlEntitySet;
 import org.apache.olingo.commons.api.edm.provider.CsdlEntityType;
+import org.apache.olingo.commons.api.edm.provider.CsdlFunctionImport;
 import org.apache.olingo.commons.api.edm.provider.CsdlNavigationProperty;
 import org.apache.olingo.commons.api.edm.provider.CsdlProperty;
 import org.apache.olingo.commons.api.edm.provider.CsdlPropertyRef;
@@ -68,7 +69,7 @@ public class EdmTechTestProvider extends EdmTechProvider {
           ));
 
     }
-
+    
     return super.getComplexType(complexTypeName);
   }
 
@@ -115,5 +116,13 @@ public class EdmTechTestProvider extends EdmTechProvider {
 
     return super.getEntityType(entityTypeName);
   }
-
+  
+  @Override
+  public CsdlFunctionImport getFunctionImport(FullQualifiedName 
entityContainer, String functionImportName)
+      throws ODataException {
+    
+    
+    return super.getFunctionImport(entityContainer, functionImportName);
+  }
+  
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3584e1d7/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/FilterValidator.java
----------------------------------------------------------------------
diff --git 
a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/FilterValidator.java
 
b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/FilterValidator.java
index 02cf29e..fa0e537 100644
--- 
a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/FilterValidator.java
+++ 
b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/testutil/FilterValidator.java
@@ -31,12 +31,14 @@ import org.apache.olingo.commons.api.edm.FullQualifiedName;
 import org.apache.olingo.server.api.ODataApplicationException;
 import org.apache.olingo.server.api.uri.UriInfo;
 import org.apache.olingo.server.api.uri.UriInfoKind;
+import org.apache.olingo.server.api.uri.UriResource;
 import 
org.apache.olingo.server.api.uri.queryoption.expression.BinaryOperatorKind;
 import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
 import 
org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitException;
 import org.apache.olingo.server.api.uri.queryoption.expression.Member;
 import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind;
 import org.apache.olingo.server.core.uri.UriInfoImpl;
+import org.apache.olingo.server.core.uri.UriResourceFunctionImpl;
 import org.apache.olingo.server.core.uri.parser.Parser;
 import org.apache.olingo.server.core.uri.parser.UriParserException;
 import org.apache.olingo.server.core.uri.parser.UriParserSemanticException;
@@ -403,15 +405,25 @@ public class FilterValidator implements TestValidator {
   public FilterValidator isParameterText(final int parameterIndex, final 
String parameterText)
       throws ExpressionVisitException, ODataApplicationException {
 
-    if (!(curExpression instanceof MethodImpl)) {
-      fail("Current expression is not a method");
-    }
-
-    MethodImpl methodCall = (MethodImpl) curExpression;
+    if (curExpression instanceof MethodImpl) {
+      MethodImpl methodCall = (MethodImpl) curExpression;
 
-    Expression parameter = methodCall.getParameters().get(parameterIndex);
-    String actualParameterText = FilterTreeToText.Serialize(parameter);
-    assertEquals(parameterText, actualParameterText);
+      Expression parameter = methodCall.getParameters().get(parameterIndex);
+      String actualParameterText = FilterTreeToText.Serialize(parameter);
+      assertEquals(parameterText, actualParameterText);
+    } else if (curExpression instanceof MemberImpl) {
+      final MemberImpl member = (MemberImpl) curExpression;
+      final List<UriResource> uriResourceParts = 
member.getResourcePath().getUriResourceParts();
+
+      if (!uriResourceParts.isEmpty() && uriResourceParts.get(0) instanceof 
UriResourceFunctionImpl) {
+        assertEquals(parameterText, ((UriResourceFunctionImpl) 
uriResourceParts.get(0)).getParameters()
+            .get(parameterIndex).getText());
+      } else {
+        fail("Current expression is not a method or function");
+      }
+    } else {
+      fail("Current expression is not a method or function");
+    }
 
     return this;
   }

Reply via email to