You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by fm...@apache.org on 2013/07/26 13:22:15 UTC

[10/51] [partial] initial commit

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/ff2b0a0e/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/FilterParserImpl.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/FilterParserImpl.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/FilterParserImpl.java
new file mode 100644
index 0000000..cfbfb9b
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/FilterParserImpl.java
@@ -0,0 +1,856 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *        or more contributor license agreements.  See the NOTICE file
+ *        distributed with this work for additional information
+ *        regarding copyright ownership.  The ASF licenses this file
+ *        to you under the Apache License, Version 2.0 (the
+ *        "License"); you may not use this file except in compliance
+ *        with the License.  You may obtain a copy of the License at
+ * 
+ *          http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *        Unless required by applicable law or agreed to in writing,
+ *        software distributed under the License is distributed on an
+ *        "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *        KIND, either express or implied.  See the License for the
+ *        specific language governing permissions and limitations
+ *        under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.core.uri.expression;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.olingo.odata2.api.edm.EdmComplexType;
+import org.apache.olingo.odata2.api.edm.EdmEntityType;
+import org.apache.olingo.odata2.api.edm.EdmException;
+import org.apache.olingo.odata2.api.edm.EdmSimpleType;
+import org.apache.olingo.odata2.api.edm.EdmSimpleTypeKind;
+import org.apache.olingo.odata2.api.edm.EdmStructuralType;
+import org.apache.olingo.odata2.api.edm.EdmType;
+import org.apache.olingo.odata2.api.edm.EdmTyped;
+import org.apache.olingo.odata2.api.uri.expression.BinaryExpression;
+import org.apache.olingo.odata2.api.uri.expression.BinaryOperator;
+import org.apache.olingo.odata2.api.uri.expression.CommonExpression;
+import org.apache.olingo.odata2.api.uri.expression.ExpressionKind;
+import org.apache.olingo.odata2.api.uri.expression.ExpressionParserException;
+import org.apache.olingo.odata2.api.uri.expression.FilterExpression;
+import org.apache.olingo.odata2.api.uri.expression.LiteralExpression;
+import org.apache.olingo.odata2.api.uri.expression.MethodExpression;
+import org.apache.olingo.odata2.api.uri.expression.MethodOperator;
+import org.apache.olingo.odata2.api.uri.expression.UnaryExpression;
+import org.apache.olingo.odata2.api.uri.expression.UnaryOperator;
+import org.apache.olingo.odata2.core.edm.EdmBoolean;
+import org.apache.olingo.odata2.core.edm.EdmSimpleTypeFacadeImpl;
+
+/**
+ * @author SAP AG
+ */
+public class FilterParserImpl implements FilterParser {
+  /*do the static initialization*/
+  protected static Map<String, InfoBinaryOperator> availableBinaryOperators;
+  protected static Map<String, InfoMethod> availableMethods;
+  protected static Map<String, InfoUnaryOperator> availableUnaryOperators;
+
+  static {
+    initAvailTables();
+  }
+
+  /*instance attributes*/
+  protected EdmEntityType resourceEntityType = null;
+  protected TokenList tokenList = null;
+  protected String curExpression;
+
+  /**
+   * Creates a new FilterParser implementation
+   * @param resourceEntityType EntityType of the resource on which the filter is applied
+   */
+  public FilterParserImpl(final EdmEntityType resourceEntityType) {
+    this.resourceEntityType = resourceEntityType;
+  }
+
+  @Override
+  public FilterExpression parseFilterString(final String filterExpression) throws ExpressionParserException, ExpressionParserInternalError {
+    return parseFilterString(filterExpression, false);
+  }
+
+  public FilterExpression parseFilterString(final String filterExpression, final boolean allowOnlyBinary) throws ExpressionParserException, ExpressionParserInternalError {
+    CommonExpression node = null;
+    curExpression = filterExpression;
+    try {
+      // Throws TokenizerException and FilterParserException. FilterParserException is caught somewhere above 
+      tokenList = new Tokenizer(filterExpression).tokenize();
+      if (!tokenList.hasTokens()) {
+        return new FilterExpressionImpl(filterExpression);
+      }
+    } catch (TokenizerException tokenizerException) {
+      // Tested with TestParserExceptions.TestPMparseFilterString
+      throw FilterParserExceptionImpl.createERROR_IN_TOKENIZER(tokenizerException, curExpression);
+    }
+
+    try {
+      CommonExpression nodeLeft = readElement(null);
+      node = readElements(nodeLeft, 0);
+    } catch (ExpressionParserException filterParserException) {
+      // Add empty filterTree to Exception
+      // Tested for original throw point
+      filterParserException.setFilterTree(new FilterExpressionImpl(filterExpression));
+      throw filterParserException;
+    }
+
+    // Post check
+    if (tokenList.tokenCount() > tokenList.currentToken) //this indicates that not all tokens have been read
+    {
+      // Tested with TestParserExceptions.TestPMparseFilterString
+      throw FilterParserExceptionImpl.createINVALID_TRAILING_TOKEN_DETECTED_AFTER_PARSING(tokenList.elementAt(tokenList.currentToken), filterExpression);
+    }
+
+    // Create and return filterExpression node
+    if ((allowOnlyBinary == true) && (node.getEdmType() != null) && (node.getEdmType() != EdmSimpleTypeKind.Boolean.getEdmSimpleTypeInstance())) {
+      // Tested with TestParserExceptions.testAdditionalStuff CASE 9
+      throw FilterParserExceptionImpl.createTYPE_EXPECTED_AT(EdmBoolean.getInstance(), node.getEdmType(), 1, curExpression);
+    }
+
+    return new FilterExpressionImpl(filterExpression, node);
+  }
+
+  protected CommonExpression readElements(final CommonExpression leftExpression, final int priority) throws ExpressionParserException, ExpressionParserInternalError {
+    CommonExpression leftNode = leftExpression;
+    CommonExpression rightNode;
+    BinaryExpression binaryNode;
+
+    ActualBinaryOperator operator = readBinaryOperator();
+    ActualBinaryOperator nextOperator;
+
+    while ((operator != null) && (operator.getOP().getPriority() >= priority)) {
+      tokenList.next(); //eat the operator
+      rightNode = readElement(leftNode, operator); //throws FilterParserException, FilterParserInternalError
+      if (rightNode == null) {
+        // Tested with TestParserExceptions.testAdditionalStuff CASE 10
+        throw FilterParserExceptionImpl.createEXPRESSION_EXPECTED_AFTER_POS(operator.getToken().getPosition() + operator.getToken().getUriLiteral().length(), curExpression);
+      }
+      nextOperator = readBinaryOperator();
+
+      // It must be "while" because for example in "Filter=a or c eq d and e eq f"
+      // after reading the "eq" operator the "and" operator must be consumed too. This is due to the fact that "and" has a higher priority than "or" 
+      while ((nextOperator != null) && (nextOperator.getOP().getPriority() > operator.getOP().getPriority())) {
+        //recurse until the a binary operator with a lower priority is detected 
+        rightNode = readElements(rightNode, nextOperator.getOP().getPriority());
+        nextOperator = readBinaryOperator();
+      }
+
+      // Although the member operator is also a binary operator, there is some special handling in the filterTree
+      if (operator.getOP().getOperator() == BinaryOperator.PROPERTY_ACCESS) {
+        binaryNode = new MemberExpressionImpl(leftNode, rightNode);
+      } else {
+        binaryNode = new BinaryExpressionImpl(operator.getOP(), leftNode, rightNode, operator.getToken());
+      }
+
+      try {
+        validateBinaryOperatorTypes(binaryNode);
+      } catch (ExpressionParserException expressionException) {
+        // Extend the error information
+        // Tested for original throw point
+        expressionException.setFilterTree(binaryNode);
+        throw expressionException;
+      }
+
+      leftNode = binaryNode;
+      operator = readBinaryOperator();
+    }
+
+    //Add special handling for expressions like $filter=notsupportedfunction('a')
+    //If this special handling is not in place the error text would be 
+    //-->Invalid token "(" detected after parsing at position 21 in "notsupportedfunction('a')".
+    //with this special handling we ensure that the error text would be
+
+    Token token = tokenList.lookToken();
+    if (token != null) {
+      if ((leftNode.getKind() == ExpressionKind.PROPERTY) && (tokenList.lookToken().getKind() == TokenKind.OPENPAREN)) {
+        // Tested with TestParserExceptions.testAdditionalStuff CASE 2
+        throw FilterParserExceptionImpl.createINVALID_METHOD_CALL(leftNode, tokenList.lookPrevToken(), curExpression);
+      }
+    }
+
+    return leftNode;
+  }
+
+  /**
+   * Reads the content between parenthesis. Its is expected that the current token is of kind {@link TokenKind#OPENPAREN}
+   * because it MUST be check in the calling method ( when read the method name and the '(' is read).  
+   * @return An expression which reflects the content within the parenthesis
+   * @throws ExpressionParserException
+   *   While reading the elements in the parenthesis an error occurred
+   * @throws TokenizerMessage 
+   *   The next token did not match the expected token
+   */
+  protected CommonExpression readParenthesis() throws ExpressionParserException, ExpressionParserInternalError {
+    // The existing of a '(' is verified BEFORE this method is called --> so it's a internal error
+    Token openParenthesis = tokenList.expectToken(TokenKind.OPENPAREN, true);
+
+    CommonExpression firstExpression = readElement(null);
+    CommonExpression parenthesisExpression = readElements(firstExpression, 0);
+
+    // check for ')'
+    try {
+      tokenList.expectToken(TokenKind.CLOSEPAREN); //TokenizerMessage
+    } catch (TokenizerExpectError e) {
+      // Internal parsing error, even if there are no more token (then there should be a different exception).
+      // Tested with TestParserExceptions.TestPMreadParenthesis
+      throw FilterParserExceptionImpl.createMISSING_CLOSING_PHARENTHESIS(openParenthesis.getPosition(), curExpression, e);
+    }
+    return parenthesisExpression;
+  }
+
+  /**
+   * Read the parameters of a method expression
+   * @param methodInfo
+   *   Signature information about the method whose parameters should be read
+   * @param methodExpression
+   *   Method expression to which the read parameters are added 
+   * @return
+   *   The method expression input parameter 
+   * @throws ExpressionParserException
+   * @throws ExpressionParserInternalError 
+   * @throws TokenizerExpectError 
+   *   The next token did not match the expected token
+   */
+  protected MethodExpression readParameters(final InfoMethod methodInfo, final MethodExpressionImpl methodExpression, final Token methodToken) throws ExpressionParserException, ExpressionParserInternalError {
+    CommonExpression expression;
+    boolean expectAnotherExpression = false;
+    boolean readComma = true;
+
+    // The existing of a '(' is verified BEFORE this method is called --> so it's a internal error
+    Token openParenthesis = tokenList.expectToken(TokenKind.OPENPAREN, true); //throws FilterParserInternalError
+
+    Token token = tokenList.lookToken();
+    if (token == null) {
+      //Tested with TestParserExceptions.TestPMreadParameters CASE 1 e.g. "$filter=concat("
+      throw FilterParserExceptionImpl.createEXPRESSION_EXPECTED_AFTER_POS(openParenthesis, curExpression);
+    }
+
+    while (token.getKind() != TokenKind.CLOSEPAREN) {
+      if (readComma == false) {
+        //Tested with TestParserExceptions.TestPMreadParameters CASE 12 e.g. "$filter=concat('a' 'b')"
+        throw FilterParserExceptionImpl.createCOMMA_OR_CLOSING_PHARENTHESIS_EXPECTED_AFTER_POS(tokenList.lookPrevToken(), curExpression);
+      }
+      expression = readElement(null);
+      if (expression != null) {
+        expression = readElements(expression, 0);
+      }
+
+      if ((expression == null) && (expectAnotherExpression == true)) {
+        //Tested with TestParserExceptions.TestPMreadParameters CASE 4 e.g. "$filter=concat(,"
+        throw FilterParserExceptionImpl.createEXPRESSION_EXPECTED_AFTER_POS(token, curExpression);
+      } else if (expression != null) //parameter list may be empty
+      {
+        methodExpression.appendParameter(expression);
+      }
+
+      token = tokenList.lookToken();
+      if (token == null) {
+        //Tested with TestParserExceptions.TestPMreadParameters CASE 2 e.g. "$filter=concat(123"
+        throw FilterParserExceptionImpl.createCOMMA_OR_CLOSING_PHARENTHESIS_EXPECTED_AFTER_POS(tokenList.lookPrevToken(), curExpression);
+      }
+
+      if (token.getKind() == TokenKind.COMMA) {
+        expectAnotherExpression = true;
+        if (expression == null) {
+          //Tested with TestParserExceptions.TestPMreadParameters CASE 3 e.g. "$filter=concat(,"
+          throw FilterParserExceptionImpl.createEXPRESSION_EXPECTED_AT_POS(token, curExpression);
+        }
+
+        tokenList.expectToken(",", true);
+        readComma = true;
+      } else {
+        readComma = false;
+      }
+    }
+
+    // because the while loop above only exits if a ')' has been found it is an  
+    // internal error if there is not ')'
+    tokenList.expectToken(TokenKind.CLOSEPAREN, true);
+
+    //---check parameter count
+    int count = methodExpression.getParameters().size();
+    if ((methodInfo.getMinParameter() > -1) && (count < methodInfo.getMinParameter())) {
+      //Tested with TestParserExceptions.TestPMreadParameters CASE 12
+      throw FilterParserExceptionImpl.createMETHOD_WRONG_ARG_COUNT(methodExpression, methodToken, curExpression);
+    }
+
+    if ((methodInfo.getMaxParameter() > -1) && (count > methodInfo.getMaxParameter())) {
+      //Tested with TestParserExceptions.TestPMreadParameters CASE 15
+      throw FilterParserExceptionImpl.createMETHOD_WRONG_ARG_COUNT(methodExpression, methodToken, curExpression);
+    }
+
+    return methodExpression;
+  }
+
+  protected CommonExpression readElement(final CommonExpression leftExpression) throws ExpressionParserException, ExpressionParserInternalError {
+    return readElement(leftExpression, null);
+  }
+
+  /**
+   * Reads: Unary operators, Methods, Properties, ...
+   * but not binary operators which are handelt in {@link #readElements(CommonExpression, int)}
+   * @param leftExpression 
+   *   Used while parsing properties. In this case ( e.g. parsing "a/b") the property "a" ( as leftExpression of "/") is relevant 
+   *   to verify whether the property "b" exists inside the edm
+   * @return a CommonExpression
+   * @throws ExpressionParserException
+   * @throws ExpressionParserInternalError 
+   * @throws TokenizerMessage 
+   */
+  protected CommonExpression readElement(final CommonExpression leftExpression, final ActualBinaryOperator leftOperator) throws ExpressionParserException, ExpressionParserInternalError {
+    CommonExpression node = null;
+    Token token;
+    Token lookToken;
+    lookToken = tokenList.lookToken();
+    if (lookToken == null) {
+      return null;
+    }
+
+    switch (lookToken.getKind()) {
+    case OPENPAREN:
+      node = readParenthesis();
+      return node;
+    case CLOSEPAREN: // ')'  finishes a parenthesis (it is no extra token)" +
+    case COMMA: //. " ','  is a separator for function parameters (it is no extra token)" +
+      return null;
+    default:
+      // continue
+    }
+
+    //-->Check if the token is a unary operator
+    InfoUnaryOperator unaryOperator = isUnaryOperator(lookToken);
+    if (unaryOperator != null) {
+      return readUnaryoperator(lookToken, unaryOperator);
+    }
+
+    //---expect the look ahead token
+    token = tokenList.expectToken(lookToken.getUriLiteral(), true);
+    lookToken = tokenList.lookToken();
+
+    //-->Check if the token is a method 
+    //To avoid name clashes between method names and property names we accept here only method names if a "(" follows.
+    //Hence the parser accepts a property named "concat"
+    InfoMethod methodOperator = isMethod(token, lookToken);
+    if (methodOperator != null) {
+      return readMethod(token, methodOperator);
+    }
+
+    //-->Check if token is a terminal 
+    //is a terminal e.g. a Value like an EDM.String 'hugo' or  125L or 1.25D" 
+    if (token.getKind() == TokenKind.SIMPLE_TYPE) {
+      LiteralExpression literal = new LiteralExpressionImpl(token.getUriLiteral(), token.getJavaLiteral());
+      return literal;
+    }
+
+    //-->Check if token is a property, e.g. "name" or "address"
+    if (token.getKind() == TokenKind.LITERAL) {
+      PropertyExpressionImpl property = new PropertyExpressionImpl(token.getUriLiteral(), token.getJavaLiteral());
+      validateEdmProperty(leftExpression, property, token, leftOperator);
+      return property;
+    }
+
+    // not Tested, should not occur 
+    throw ExpressionParserInternalError.createCOMMON();
+  }
+
+  protected CommonExpression readUnaryoperator(final Token lookToken, final InfoUnaryOperator unaryOperator) throws ExpressionParserException, ExpressionParserInternalError {
+    tokenList.expectToken(lookToken.getUriLiteral(), true);
+
+    CommonExpression operand = readElement(null);
+    UnaryExpression unaryExpression = new UnaryExpressionImpl(unaryOperator, operand);
+    validateUnaryOperatorTypes(unaryExpression); //throws ExpressionInvalidOperatorTypeException
+
+    return unaryExpression;
+  }
+
+  protected CommonExpression readMethod(final Token token, final InfoMethod methodOperator) throws ExpressionParserException, ExpressionParserInternalError {
+    MethodExpressionImpl method = new MethodExpressionImpl(methodOperator);
+
+    readParameters(methodOperator, method, token);
+    validateMethodTypes(method, token); //throws ExpressionInvalidOperatorTypeException
+
+    return method;
+  }
+
+  protected ActualBinaryOperator readBinaryOperator() {
+    InfoBinaryOperator operator = null;
+    Token token = tokenList.lookToken();
+    if (token == null) {
+      return null;
+    }
+    if ((token.getKind() == TokenKind.SYMBOL) && (token.getUriLiteral().equals("/"))) {
+      operator = availableBinaryOperators.get(token.getUriLiteral());
+    } else if (token.getKind() == TokenKind.LITERAL) {
+      operator = availableBinaryOperators.get(token.getUriLiteral());
+    }
+
+    if (operator == null) {
+      return null;
+    }
+
+    return new ActualBinaryOperator(operator, token);
+  }
+
+  /**
+   * Check if a token is a UnaryOperator ( e.g. "not" or "-" ) 
+   * 
+   * @param token Token to be checked
+   *   
+   * @return
+   *   <li>An instance of {@link InfoUnaryOperator} containing information about the specific unary operator</li> 
+   *   <li><code>null</code> if the token is not an unary operator</li>
+   */
+  protected InfoUnaryOperator isUnaryOperator(final Token token) {
+    if ((token.getKind() == TokenKind.LITERAL) || (token.getKind() == TokenKind.SYMBOL)) {
+      InfoUnaryOperator operator = availableUnaryOperators.get(token.getUriLiteral());
+      return operator;
+    }
+    return null;
+  }
+
+  protected InfoMethod isMethod(final Token token, final Token lookToken) {
+    if ((lookToken != null) && (lookToken.getKind() == TokenKind.OPENPAREN)) {
+      return availableMethods.get(token.getUriLiteral());
+    }
+    return null;
+  }
+
+  protected void validateEdmProperty(final CommonExpression leftExpression, final PropertyExpressionImpl property, final Token propertyToken, final ActualBinaryOperator actBinOp) throws ExpressionParserException, ExpressionParserInternalError {
+
+    // Exist if no edm provided
+    if (resourceEntityType == null) {
+      return;
+    }
+
+    if (leftExpression == null) {
+      //e.g. "$filter=city eq 'Hong Kong'" --> "city" is checked against the resource entity type of the last URL segment 
+      validateEdmPropertyOfStructuredType(resourceEntityType, property, propertyToken);
+      return;
+    }
+    //e.g. "$filter='Hong Kong' eq address/city" --> city is "checked" against the type of the property "address".
+    //     "address" itself must be a (navigation)property of the resource entity type of the last URL segment AND
+    //     "address" must have a structural edm type
+    EdmType parentType = leftExpression.getEdmType(); //parentType point now to the type of property "address"
+
+    if ((actBinOp != null) && (actBinOp.operator.getOperator() != BinaryOperator.PROPERTY_ACCESS)) {
+      validateEdmPropertyOfStructuredType(resourceEntityType, property, propertyToken);
+      return;
+    } else {
+      if ((leftExpression.getKind() != ExpressionKind.PROPERTY) && (leftExpression.getKind() != ExpressionKind.MEMBER)) {
+        if (actBinOp != null) {
+          //Tested with TestParserExceptions.TestPMvalidateEdmProperty CASE 6
+          throw FilterParserExceptionImpl.createLEFT_SIDE_NOT_A_PROPERTY(actBinOp.token, curExpression);
+        } else {
+          // not Tested, should not occur 
+          throw ExpressionParserInternalError.createCOMMON();
+        }
+
+      }
+    }
+
+    if (parentType instanceof EdmEntityType) {
+      //e.g. "$filter='Hong Kong' eq navigationProp/city" --> "navigationProp" is a navigation property with a entity type
+      validateEdmPropertyOfStructuredType((EdmStructuralType) parentType, property, propertyToken);
+    } else if (parentType instanceof EdmComplexType) {
+      //e.g. "$filter='Hong Kong' eq address/city" --> "address" is a property with a complex type 
+      validateEdmPropertyOfStructuredType((EdmStructuralType) parentType, property, propertyToken);
+    } else {
+      //e.g. "$filter='Hong Kong' eq name/city" --> "name is of type String"
+      //Tested with TestParserExceptions.TestPMvalidateEdmProperty CASE 5
+      throw FilterParserExceptionImpl.createLEFT_SIDE_NOT_STRUCTURAL_TYPE(parentType, property, propertyToken, curExpression);
+    }
+
+    return;
+  }
+
+  protected void validateEdmPropertyOfStructuredType(final EdmStructuralType parentType, final PropertyExpressionImpl property, final Token propertyToken) throws ExpressionParserException, ExpressionParserInternalError {
+    try {
+      String propertyName = property.getUriLiteral();
+      EdmTyped edmProperty = parentType.getProperty(propertyName);
+
+      if (edmProperty != null) {
+        property.setEdmProperty(edmProperty);
+        property.setEdmType(edmProperty.getType());
+      } else {
+        //Tested with TestParserExceptions.TestPMvalidateEdmProperty CASE 3
+        throw FilterParserExceptionImpl.createPROPERTY_NAME_NOT_FOUND_IN_TYPE(parentType, property, propertyToken, curExpression);
+      }
+
+    } catch (EdmException e) {
+      // not Tested, should not occur
+      throw ExpressionParserInternalError.createERROR_ACCESSING_EDM(e);
+    }
+  }
+
+  /*
+    protected void validateEdmPropertyOfComplexType1(EdmComplexType parentType, PropertyExpressionImpl property, Token propertyToken) throws FilterParserException, FilterParserInternalError
+    {
+      try {
+        String propertyName = property.getUriLiteral();
+        EdmTyped edmProperty = parentType.getProperty(propertyName);
+
+        if (edmProperty != null)
+        {
+          property.setEdmProperty(edmProperty);
+          property.setEdmType(edmProperty.getType());
+        }
+        else
+        {
+          //Tested with TestParserExceptions.TestPMvalidateEdmProperty CASE 3
+          throw FilterParserExceptionImpl.createPROPERTY_NAME_NOT_FOUND_IN_TYPE(parentType, property, propertyToken, curExpression);
+        }
+
+      } catch (EdmException e) {
+        // not Tested, should not occur
+        throw FilterParserInternalError.createERROR_ACCESSING_EDM(e);
+      }
+    }
+
+    protected void validateEdmPropertyOfEntityType1(EdmEntityType parentType, PropertyExpressionImpl property, Token propertyToken) throws FilterParserException, FilterParserInternalError
+    {
+      try {
+        String propertyName = property.getUriLiteral();
+        EdmTyped edmProperty = parentType.getProperty(propertyName);
+
+        if (edmProperty != null)
+        {
+          property.setEdmProperty(edmProperty);
+          property.setEdmType(edmProperty.getType());
+        }
+        else
+        {
+          //Tested with TestParserExceptions.TestPMvalidateEdmProperty CASE 1
+          throw FilterParserExceptionImpl.createPROPERTY_NAME_NOT_FOUND_IN_TYPE(parentType, property, propertyToken, curExpression);
+        }
+
+      } catch (EdmException e) {
+        // not Tested, should not occur
+        throw FilterParserInternalError.createERROR_ACCESSING_EDM(e);
+      }
+    }*/
+
+  protected void validateUnaryOperatorTypes(final UnaryExpression unaryExpression) throws ExpressionParserInternalError {
+    InfoUnaryOperator unOpt = availableUnaryOperators.get(unaryExpression.getOperator().toUriLiteral());
+    EdmType operandType = unaryExpression.getOperand().getEdmType();
+
+    if ((operandType == null) && (resourceEntityType == null)) {
+      return;
+    }
+
+    List<EdmType> actualParameterTypes = new ArrayList<EdmType>();
+    actualParameterTypes.add(operandType);
+
+    ParameterSet parameterSet = unOpt.validateParameterSet(actualParameterTypes);
+    if (parameterSet != null) {
+      unaryExpression.setEdmType(parameterSet.getReturnType());
+    }
+  }
+
+  protected void validateBinaryOperatorTypes(final BinaryExpression binaryExpression) throws ExpressionParserException, ExpressionParserInternalError {
+    InfoBinaryOperator binOpt = availableBinaryOperators.get(binaryExpression.getOperator().toUriLiteral());
+
+    List<EdmType> actualParameterTypes = new ArrayList<EdmType>();
+    EdmType operand = binaryExpression.getLeftOperand().getEdmType();
+
+    if ((operand == null) && (resourceEntityType == null)) {
+      return;
+    }
+    actualParameterTypes.add(operand);
+
+    operand = binaryExpression.getRightOperand().getEdmType();
+
+    if ((operand == null) && (resourceEntityType == null)) {
+      return;
+    }
+    actualParameterTypes.add(operand);
+
+    ParameterSet parameterSet = binOpt.validateParameterSet(actualParameterTypes);
+    if (parameterSet == null) {
+      BinaryExpressionImpl binaryExpressionImpl = (BinaryExpressionImpl) binaryExpression;
+
+      // Tested with TestParserExceptions.TestPMvalidateBinaryOperator
+      throw FilterParserExceptionImpl.createINVALID_TYPES_FOR_BINARY_OPERATOR(binaryExpression.getOperator(), binaryExpression.getLeftOperand().getEdmType(), binaryExpression.getRightOperand().getEdmType(), binaryExpressionImpl.getToken(), curExpression);
+    }
+    binaryExpression.setEdmType(parameterSet.getReturnType());
+  }
+
+  protected void validateMethodTypes(final MethodExpression methodExpression, final Token methodToken) throws ExpressionParserException, ExpressionParserInternalError {
+    InfoMethod methOpt = availableMethods.get(methodExpression.getUriLiteral());
+
+    List<EdmType> actualParameterTypes = new ArrayList<EdmType>();
+
+    //If there are no parameter then don't perform a type check
+    if (methodExpression.getParameters().size() == 0) {
+      return;
+    }
+
+    for (CommonExpression parameter : methodExpression.getParameters()) {
+      //If there is not at parsing time its not possible to determine the type of eg myPropertyName.
+      //Since this should not cause validation errors null type node arguments are leading to bypass
+      //the validation
+      if ((parameter.getEdmType() == null) && (resourceEntityType == null)) {
+        return;
+      }
+      actualParameterTypes.add(parameter.getEdmType());
+    }
+
+    ParameterSet parameterSet = methOpt.validateParameterSet(actualParameterTypes);
+    //If there is not returntype then the input parameter 
+    if (parameterSet == null) {
+      // Tested with TestParserExceptions.testPMvalidateMethodTypes CASE 1
+      throw FilterParserExceptionImpl.createMETHOD_WRONG_INPUT_TYPE((MethodExpressionImpl) methodExpression, methodToken, curExpression);
+    }
+    methodExpression.setEdmType(parameterSet.getReturnType());
+  }
+
+  static void initAvailTables() {
+    Map<String, InfoBinaryOperator> lAvailableBinaryOperators = new HashMap<String, InfoBinaryOperator>();
+    Map<String, InfoMethod> lAvailableMethods = new HashMap<String, InfoMethod>();
+    Map<String, InfoUnaryOperator> lAvailableUnaryOperators = new HashMap<String, InfoUnaryOperator>();
+
+    //create type validators
+    //InputTypeValidator typeValidatorPromotion = new InputTypeValidator.TypePromotionValidator();
+    ParameterSetCombination combination = null;
+    //create type helpers
+    EdmSimpleType boolean_ = EdmSimpleTypeFacadeImpl.getEdmSimpleType(EdmSimpleTypeKind.Boolean);
+    EdmSimpleType sbyte = EdmSimpleTypeFacadeImpl.getEdmSimpleType(EdmSimpleTypeKind.SByte);
+    EdmSimpleType byte_ = EdmSimpleTypeFacadeImpl.getEdmSimpleType(EdmSimpleTypeKind.Byte);
+    EdmSimpleType int16 = EdmSimpleTypeFacadeImpl.getEdmSimpleType(EdmSimpleTypeKind.Int16);
+    EdmSimpleType int32 = EdmSimpleTypeFacadeImpl.getEdmSimpleType(EdmSimpleTypeKind.Int32);
+    EdmSimpleType int64 = EdmSimpleTypeFacadeImpl.getEdmSimpleType(EdmSimpleTypeKind.Int64);
+    EdmSimpleType single = EdmSimpleTypeFacadeImpl.getEdmSimpleType(EdmSimpleTypeKind.Single);
+    EdmSimpleType double_ = EdmSimpleTypeFacadeImpl.getEdmSimpleType(EdmSimpleTypeKind.Double);
+    EdmSimpleType decimal = EdmSimpleTypeFacadeImpl.getEdmSimpleType(EdmSimpleTypeKind.Decimal);
+    EdmSimpleType string = EdmSimpleTypeFacadeImpl.getEdmSimpleType(EdmSimpleTypeKind.String);
+    EdmSimpleType time = EdmSimpleTypeFacadeImpl.getEdmSimpleType(EdmSimpleTypeKind.Time);
+    EdmSimpleType datetime = EdmSimpleTypeFacadeImpl.getEdmSimpleType(EdmSimpleTypeKind.DateTime);
+    EdmSimpleType datetimeoffset = EdmSimpleTypeFacadeImpl.getEdmSimpleType(EdmSimpleTypeKind.DateTimeOffset);
+    EdmSimpleType guid = EdmSimpleTypeFacadeImpl.getEdmSimpleType(EdmSimpleTypeKind.Guid);
+    EdmSimpleType binary = EdmSimpleTypeFacadeImpl.getEdmSimpleType(EdmSimpleTypeKind.Binary);
+
+    //---Memeber member access---
+    lAvailableBinaryOperators.put("/", new InfoBinaryOperator(BinaryOperator.PROPERTY_ACCESS, "Primary", 100, new ParameterSetCombination.PSCReturnTypeEqLastParameter()));//todo fix this
+
+    //---Multiplicative---
+    combination = new ParameterSetCombination.PSCflex();
+    combination.add(new ParameterSet(sbyte, sbyte, sbyte));
+    combination.add(new ParameterSet(byte_, byte_, byte_));
+    combination.add(new ParameterSet(int16, int16, int16));
+    combination.add(new ParameterSet(int32, int32, int32));
+    combination.add(new ParameterSet(int64, int64, int64));
+    combination.add(new ParameterSet(single, single, single));
+    combination.add(new ParameterSet(double_, double_, double_));
+
+    combination.add(new ParameterSet(decimal, decimal, decimal));
+
+    lAvailableBinaryOperators.put(BinaryOperator.MUL.toUriLiteral(), new InfoBinaryOperator(BinaryOperator.MUL, "Multiplicative", 60, combination));
+    lAvailableBinaryOperators.put(BinaryOperator.DIV.toUriLiteral(), new InfoBinaryOperator(BinaryOperator.DIV, "Multiplicative", 60, combination));
+    lAvailableBinaryOperators.put(BinaryOperator.MODULO.toUriLiteral(), new InfoBinaryOperator(BinaryOperator.MODULO, "Multiplicative", 60, combination));
+
+    //---Additive---
+    combination = new ParameterSetCombination.PSCflex();
+    combination.add(new ParameterSet(sbyte, sbyte, sbyte));
+    combination.add(new ParameterSet(byte_, byte_, byte_));
+    combination.add(new ParameterSet(int16, int16, int16));
+    combination.add(new ParameterSet(int32, int32, int32));
+    combination.add(new ParameterSet(int64, int64, int64));
+    combination.add(new ParameterSet(single, single, single));
+    combination.add(new ParameterSet(double_, double_, double_));
+    combination.add(new ParameterSet(decimal, decimal, decimal));
+
+    lAvailableBinaryOperators.put(BinaryOperator.ADD.toUriLiteral(), new InfoBinaryOperator(BinaryOperator.ADD, "Additive", 50, combination));
+    lAvailableBinaryOperators.put(BinaryOperator.SUB.toUriLiteral(), new InfoBinaryOperator(BinaryOperator.SUB, "Additive", 50, combination));
+
+    //---Relational---
+    combination = new ParameterSetCombination.PSCflex();
+    combination.add(new ParameterSet(boolean_, string, string));
+    combination.add(new ParameterSet(boolean_, time, time));
+    combination.add(new ParameterSet(boolean_, datetime, datetime));
+    combination.add(new ParameterSet(boolean_, datetimeoffset, datetimeoffset));
+    combination.add(new ParameterSet(boolean_, guid, guid));
+    combination.add(new ParameterSet(boolean_, sbyte, sbyte));
+    combination.add(new ParameterSet(boolean_, byte_, byte_));
+    combination.add(new ParameterSet(boolean_, int16, int16));
+    combination.add(new ParameterSet(boolean_, int32, int32));
+    combination.add(new ParameterSet(boolean_, int64, int64));
+    combination.add(new ParameterSet(boolean_, single, single));
+    combination.add(new ParameterSet(boolean_, double_, double_));
+    combination.add(new ParameterSet(boolean_, decimal, decimal));
+    combination.add(new ParameterSet(boolean_, binary, binary));
+
+    lAvailableBinaryOperators.put(BinaryOperator.LT.toUriLiteral(), new InfoBinaryOperator(BinaryOperator.LT, "Relational", 40, combination));
+    lAvailableBinaryOperators.put(BinaryOperator.GT.toUriLiteral(), new InfoBinaryOperator(BinaryOperator.GT, "Relational", 40, combination));
+    lAvailableBinaryOperators.put(BinaryOperator.GE.toUriLiteral(), new InfoBinaryOperator(BinaryOperator.GE, "Relational", 40, combination));
+    lAvailableBinaryOperators.put(BinaryOperator.LE.toUriLiteral(), new InfoBinaryOperator(BinaryOperator.LE, "Relational", 40, combination));
+
+    //---Equality---
+    //combination = new ParameterSetCombination.PSCflex();
+    combination.addFirst(new ParameterSet(boolean_, boolean_, boolean_));
+    /*combination.add(new ParameterSet(boolean_, string, string));
+    combination.add(new ParameterSet(boolean_, time, time));
+    combination.add(new ParameterSet(boolean_, datetime, datetime));
+    combination.add(new ParameterSet(boolean_, datetimeoffset, datetimeoffset));
+    combination.add(new ParameterSet(boolean_, guid, guid));
+    combination.add(new ParameterSet(boolean_, sbyte, sbyte));
+    combination.add(new ParameterSet(boolean_, byte_, byte_));
+    combination.add(new ParameterSet(boolean_, int16, int16));
+    combination.add(new ParameterSet(boolean_, int32, int32));
+    combination.add(new ParameterSet(boolean_, int64, int64));
+    combination.add(new ParameterSet(boolean_, single, single));
+    combination.add(new ParameterSet(boolean_, double_, double_));
+    combination.add(new ParameterSet(boolean_, decimal, decimal));
+    combination.add(new ParameterSet(boolean_, binary, binary));*/
+
+    lAvailableBinaryOperators.put(BinaryOperator.EQ.toUriLiteral(), new InfoBinaryOperator(BinaryOperator.EQ, "Equality", 30, combination));
+    lAvailableBinaryOperators.put(BinaryOperator.NE.toUriLiteral(), new InfoBinaryOperator(BinaryOperator.NE, "Equality", 30, combination));
+
+    //"---Conditinal AND---
+    combination = new ParameterSetCombination.PSCflex();
+    combination.add(new ParameterSet(boolean_, boolean_, boolean_));
+
+    lAvailableBinaryOperators.put(BinaryOperator.AND.toUriLiteral(), new InfoBinaryOperator(BinaryOperator.AND, "Conditinal", 20, combination));
+
+    //---Conditinal OR---
+    combination = new ParameterSetCombination.PSCflex();
+    combination.add(new ParameterSet(boolean_, boolean_, boolean_));
+
+    lAvailableBinaryOperators.put(BinaryOperator.OR.toUriLiteral(), new InfoBinaryOperator(BinaryOperator.OR, "Conditinal", 10, combination));
+
+    //endswith
+    combination = new ParameterSetCombination.PSCflex();
+    combination.add(new ParameterSet(boolean_, string, string));
+    lAvailableMethods.put(MethodOperator.ENDSWITH.toUriLiteral(), new InfoMethod(MethodOperator.ENDSWITH, 2, 2, combination));
+
+    //indexof
+    combination = new ParameterSetCombination.PSCflex();
+    combination.add(new ParameterSet(int32, string, string));
+    lAvailableMethods.put(MethodOperator.INDEXOF.toUriLiteral(), new InfoMethod(MethodOperator.INDEXOF, 2, 2, combination));
+
+    //startswith
+    combination = new ParameterSetCombination.PSCflex();
+    combination.add(new ParameterSet(boolean_, string, string));
+    lAvailableMethods.put(MethodOperator.STARTSWITH.toUriLiteral(), new InfoMethod(MethodOperator.STARTSWITH, 2, 2, combination));
+
+    //tolower
+    combination = new ParameterSetCombination.PSCflex();
+    combination.add(new ParameterSet(string, string));
+    lAvailableMethods.put(MethodOperator.TOLOWER.toUriLiteral(), new InfoMethod(MethodOperator.TOLOWER, combination));
+
+    //toupper
+    combination = new ParameterSetCombination.PSCflex();
+    combination.add(new ParameterSet(string, string));
+    lAvailableMethods.put(MethodOperator.TOUPPER.toUriLiteral(), new InfoMethod(MethodOperator.TOUPPER, combination));
+
+    //trim
+    combination = new ParameterSetCombination.PSCflex();
+    combination.add(new ParameterSet(string, string));
+    lAvailableMethods.put(MethodOperator.TRIM.toUriLiteral(), new InfoMethod(MethodOperator.TRIM, combination));
+
+    //substring
+    combination = new ParameterSetCombination.PSCflex();
+    combination.add(new ParameterSet(string, string, int32));
+    combination.add(new ParameterSet(string, string, int32, int32));
+    lAvailableMethods.put(MethodOperator.SUBSTRING.toUriLiteral(), new InfoMethod(MethodOperator.SUBSTRING, 1, -1, combination));
+
+    //substringof
+    combination = new ParameterSetCombination.PSCflex();
+    combination.add(new ParameterSet(boolean_, string, string));
+    lAvailableMethods.put(MethodOperator.SUBSTRINGOF.toUriLiteral(), new InfoMethod(MethodOperator.SUBSTRINGOF, 1, -1, combination));
+
+    //concat
+    combination = new ParameterSetCombination.PSCflex();
+    combination.add(new ParameterSet(string, string, string).setFurtherType(string));
+    lAvailableMethods.put(MethodOperator.CONCAT.toUriLiteral(), new InfoMethod(MethodOperator.CONCAT, 2, -1, combination));
+
+    //length
+    combination = new ParameterSetCombination.PSCflex();
+    combination.add(new ParameterSet(int32, string));
+    lAvailableMethods.put(MethodOperator.LENGTH.toUriLiteral(), new InfoMethod(MethodOperator.LENGTH, combination));
+
+    //year
+    combination = new ParameterSetCombination.PSCflex();
+    combination.add(new ParameterSet(int32, datetime));
+    lAvailableMethods.put(MethodOperator.YEAR.toUriLiteral(), new InfoMethod(MethodOperator.YEAR, combination));
+
+    //month
+    combination = new ParameterSetCombination.PSCflex();
+    combination.add(new ParameterSet(int32, datetime));
+    lAvailableMethods.put(MethodOperator.MONTH.toUriLiteral(), new InfoMethod(MethodOperator.MONTH, combination));
+
+    //day
+    combination = new ParameterSetCombination.PSCflex();
+    combination.add(new ParameterSet(int32, datetime));
+    lAvailableMethods.put(MethodOperator.DAY.toUriLiteral(), new InfoMethod(MethodOperator.DAY, combination));
+
+    //hour
+    combination = new ParameterSetCombination.PSCflex();
+    combination.add(new ParameterSet(int32, datetime));
+    combination.add(new ParameterSet(int32, time));
+    combination.add(new ParameterSet(int32, datetimeoffset));
+    lAvailableMethods.put(MethodOperator.HOUR.toUriLiteral(), new InfoMethod(MethodOperator.HOUR, combination));
+
+    //minute
+    combination = new ParameterSetCombination.PSCflex();
+    combination.add(new ParameterSet(int32, datetime));
+    combination.add(new ParameterSet(int32, time));
+    combination.add(new ParameterSet(int32, datetimeoffset));
+    lAvailableMethods.put(MethodOperator.MINUTE.toUriLiteral(), new InfoMethod(MethodOperator.MINUTE, combination));
+
+    //second
+    combination = new ParameterSetCombination.PSCflex();
+    combination.add(new ParameterSet(int32, datetime));
+    combination.add(new ParameterSet(int32, time));
+    combination.add(new ParameterSet(int32, datetimeoffset));
+    lAvailableMethods.put(MethodOperator.SECOND.toUriLiteral(), new InfoMethod(MethodOperator.SECOND, combination));
+
+    //round
+    combination = new ParameterSetCombination.PSCflex();
+    combination.add(new ParameterSet(decimal, decimal));
+    combination.add(new ParameterSet(double_, double_));
+    lAvailableMethods.put(MethodOperator.ROUND.toUriLiteral(), new InfoMethod(MethodOperator.ROUND, combination));
+
+    //ceiling
+    combination = new ParameterSetCombination.PSCflex();
+    combination.add(new ParameterSet(decimal, decimal));
+    combination.add(new ParameterSet(double_, double_));
+    lAvailableMethods.put(MethodOperator.CEILING.toUriLiteral(), new InfoMethod(MethodOperator.CEILING, combination));
+
+    //floor
+    combination = new ParameterSetCombination.PSCflex();
+    combination.add(new ParameterSet(decimal, decimal));
+    combination.add(new ParameterSet(double_, double_));
+    lAvailableMethods.put(MethodOperator.FLOOR.toUriLiteral(), new InfoMethod(MethodOperator.FLOOR, combination));
+
+    //---unary---
+
+    //minus
+    combination = new ParameterSetCombination.PSCflex();
+    combination.add(new ParameterSet(sbyte, sbyte));
+    combination.add(new ParameterSet(byte_, byte_));
+    combination.add(new ParameterSet(int16, int16));
+    combination.add(new ParameterSet(int32, int32));
+    combination.add(new ParameterSet(int64, int64));
+    combination.add(new ParameterSet(single, single));
+    combination.add(new ParameterSet(double_, double_));
+    combination.add(new ParameterSet(decimal, decimal));
+
+    //minus
+    lAvailableUnaryOperators.put(UnaryOperator.MINUS.toUriLiteral(), new InfoUnaryOperator(UnaryOperator.MINUS, "minus", combination));
+
+    //not
+    combination = new ParameterSetCombination.PSCflex();
+    combination.add(new ParameterSet(boolean_, boolean_));
+    lAvailableUnaryOperators.put(UnaryOperator.NOT.toUriLiteral(), new InfoUnaryOperator(UnaryOperator.NOT, "not", combination));
+
+    availableBinaryOperators = Collections.unmodifiableMap(lAvailableBinaryOperators);
+    availableMethods = Collections.unmodifiableMap(lAvailableMethods);
+    availableUnaryOperators = Collections.unmodifiableMap(lAvailableUnaryOperators);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/ff2b0a0e/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/InfoBinaryOperator.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/InfoBinaryOperator.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/InfoBinaryOperator.java
new file mode 100644
index 0000000..fdcf225
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/InfoBinaryOperator.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *        or more contributor license agreements.  See the NOTICE file
+ *        distributed with this work for additional information
+ *        regarding copyright ownership.  The ASF licenses this file
+ *        to you under the Apache License, Version 2.0 (the
+ *        "License"); you may not use this file except in compliance
+ *        with the License.  You may obtain a copy of the License at
+ * 
+ *          http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *        Unless required by applicable law or agreed to in writing,
+ *        software distributed under the License is distributed on an
+ *        "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *        KIND, either express or implied.  See the License for the
+ *        specific language governing permissions and limitations
+ *        under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.core.uri.expression;
+
+import java.util.List;
+
+import org.apache.olingo.odata2.api.edm.EdmType;
+import org.apache.olingo.odata2.api.uri.expression.BinaryOperator;
+
+/**
+ * Describes a binary operator which is allowed in OData expressions
+ * @author SAP AG
+ */
+class InfoBinaryOperator {
+  private BinaryOperator operator;
+  private String category;
+  private String syntax;
+  private int priority;
+  ParameterSetCombination combination;
+
+  public InfoBinaryOperator(final BinaryOperator operator, final String category, final int priority, final ParameterSetCombination combination) {
+    this.operator = operator;
+    this.category = category;
+    syntax = operator.toUriLiteral();
+    this.priority = priority;
+    this.combination = combination;
+  }
+
+  public String getCategory() {
+    return category;
+  }
+
+  public String getSyntax() {
+    return syntax;
+  }
+
+  public BinaryOperator getOperator() {
+    return operator;
+  }
+
+  public int getPriority() {
+    return priority;
+  }
+
+  public ParameterSet validateParameterSet(final List<EdmType> actualParameterTypes) throws ExpressionParserInternalError {
+    return combination.validate(actualParameterTypes);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/ff2b0a0e/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/InfoMethod.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/InfoMethod.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/InfoMethod.java
new file mode 100644
index 0000000..38778f3
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/InfoMethod.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *        or more contributor license agreements.  See the NOTICE file
+ *        distributed with this work for additional information
+ *        regarding copyright ownership.  The ASF licenses this file
+ *        to you under the Apache License, Version 2.0 (the
+ *        "License"); you may not use this file except in compliance
+ *        with the License.  You may obtain a copy of the License at
+ * 
+ *          http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *        Unless required by applicable law or agreed to in writing,
+ *        software distributed under the License is distributed on an
+ *        "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *        KIND, either express or implied.  See the License for the
+ *        specific language governing permissions and limitations
+ *        under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.core.uri.expression;
+
+import java.util.List;
+
+import org.apache.olingo.odata2.api.edm.EdmType;
+import org.apache.olingo.odata2.api.uri.expression.MethodOperator;
+
+/**
+ * Describes a method expression which is allowed in OData expressions
+ * @author SAP AG
+ */
+class InfoMethod {
+
+  public MethodOperator method;
+  public String syntax;
+  public int minParameter;
+  public int maxParameter;
+  ParameterSetCombination combination;
+
+  public InfoMethod(final MethodOperator method, final ParameterSetCombination combination) {
+    this.method = method;
+    syntax = method.toUriLiteral();
+    minParameter = 1;
+    maxParameter = 1;
+    this.combination = combination;
+  }
+
+  public InfoMethod(final MethodOperator method, final int minParameters, final int maxParameters, final ParameterSetCombination combination) {
+    this.method = method;
+    syntax = method.toUriLiteral();
+    minParameter = minParameters;
+    maxParameter = maxParameters;
+    this.combination = combination;
+  }
+
+  public InfoMethod(final MethodOperator method, final String string, final int minParameters, final int maxParameters, final ParameterSetCombination combination) {
+    this.method = method;
+    syntax = string;
+    minParameter = minParameters;
+    maxParameter = maxParameters;
+    this.combination = combination;
+  }
+
+  public MethodOperator getMethod() {
+    return method;
+  }
+
+  public String getSyntax() {
+    return syntax;
+  }
+
+  public int getMinParameter() {
+    return minParameter;
+  }
+
+  public int getMaxParameter() {
+    return maxParameter;
+  }
+
+  public ParameterSet validateParameterSet(final List<EdmType> actualParameterTypes) throws ExpressionParserInternalError {
+    return combination.validate(actualParameterTypes);
+  }
+
+  /**
+   * Returns the EdmType of the returned value of a Method
+   * If a method may have different return types (depending on the input type) null will be returned. 
+   */
+  public EdmType getReturnType() {
+    return combination.getReturnType();
+
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/ff2b0a0e/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/InfoUnaryOperator.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/InfoUnaryOperator.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/InfoUnaryOperator.java
new file mode 100644
index 0000000..16463d9
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/InfoUnaryOperator.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *        or more contributor license agreements.  See the NOTICE file
+ *        distributed with this work for additional information
+ *        regarding copyright ownership.  The ASF licenses this file
+ *        to you under the Apache License, Version 2.0 (the
+ *        "License"); you may not use this file except in compliance
+ *        with the License.  You may obtain a copy of the License at
+ * 
+ *          http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *        Unless required by applicable law or agreed to in writing,
+ *        software distributed under the License is distributed on an
+ *        "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *        KIND, either express or implied.  See the License for the
+ *        specific language governing permissions and limitations
+ *        under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.core.uri.expression;
+
+import java.util.List;
+
+import org.apache.olingo.odata2.api.edm.EdmType;
+import org.apache.olingo.odata2.api.uri.expression.UnaryOperator;
+
+/**
+ * Describes a unary operator which is allowed in OData expressions
+ * @author SAP AG
+ */
+class InfoUnaryOperator {
+  UnaryOperator operator;
+  private String category;
+  private String syntax;
+  ParameterSetCombination combination;
+
+  public InfoUnaryOperator(final UnaryOperator operator, final String category, final ParameterSetCombination combination) {
+    this.operator = operator;
+    this.category = category;
+    syntax = operator.toUriLiteral();
+    this.combination = combination;
+  }
+
+  public String getCategory() {
+    return category;
+  }
+
+  public String getSyntax() {
+    return syntax;
+  }
+
+  public UnaryOperator getOperator() {
+    return operator;
+  }
+
+  public ParameterSet validateParameterSet(final List<EdmType> actualParameterTypes) throws ExpressionParserInternalError {
+    return combination.validate(actualParameterTypes);
+  }
+
+  /**
+   * Returns the EdmType of the returned value of a Method
+   * If a method may have different return types (depending on the input type) null will be returned. 
+   */
+  /*
+  public EdmType getReturnType()
+  {
+  int parameterCount = allowedParameterTypes.size();
+  if (parameterCount == 0)
+   return null;
+
+  if (parameterCount == 1)
+   return allowedParameterTypes.get(0).getReturnType();
+
+  //There are more than 1 possible return type, check if they are equal, if not return null.
+  EdmType returnType = allowedParameterTypes.get(0).getReturnType();
+  for (int i = 1; i < parameterCount; i++)
+   if (returnType != allowedParameterTypes.get(i))
+     return null;
+
+  return returnType;
+  }*/
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/ff2b0a0e/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/InputTypeValidator.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/InputTypeValidator.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/InputTypeValidator.java
new file mode 100644
index 0000000..246b769
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/InputTypeValidator.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *        or more contributor license agreements.  See the NOTICE file
+ *        distributed with this work for additional information
+ *        regarding copyright ownership.  The ASF licenses this file
+ *        to you under the Apache License, Version 2.0 (the
+ *        "License"); you may not use this file except in compliance
+ *        with the License.  You may obtain a copy of the License at
+ * 
+ *          http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *        Unless required by applicable law or agreed to in writing,
+ *        software distributed under the License is distributed on an
+ *        "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *        KIND, either express or implied.  See the License for the
+ *        specific language governing permissions and limitations
+ *        under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.core.uri.expression;
+
+import java.util.List;
+
+import org.apache.olingo.odata2.api.edm.EdmType;
+
+public interface InputTypeValidator {
+
+  public EdmType validateParameterSet(List<ParameterSet> allowedParameterTypes, List<EdmType> actualParameterTypes) throws ExpressionParserInternalError;
+
+  public static class TypePromotionValidator implements InputTypeValidator {
+
+    @Override
+    public EdmType validateParameterSet(final List<ParameterSet> allowedParameterTypes, final List<EdmType> actualParameterTypes) throws ExpressionParserInternalError {
+      //first check for exact parameter combination
+      for (ParameterSet parameterSet : allowedParameterTypes) {
+        boolean s = parameterSet.equals(actualParameterTypes, false);
+        if (s) {
+          return parameterSet.getReturnType();
+        }
+      }
+
+      //first check for parameter combination with promotion
+      for (ParameterSet parameterSet : allowedParameterTypes) {
+        boolean s = parameterSet.equals(actualParameterTypes, true);
+        if (s) {
+          return parameterSet.getReturnType();
+        }
+      }
+      return null;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/ff2b0a0e/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/JsonVisitor.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/JsonVisitor.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/JsonVisitor.java
new file mode 100644
index 0000000..48bb8fe
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/JsonVisitor.java
@@ -0,0 +1,227 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *        or more contributor license agreements.  See the NOTICE file
+ *        distributed with this work for additional information
+ *        regarding copyright ownership.  The ASF licenses this file
+ *        to you under the Apache License, Version 2.0 (the
+ *        "License"); you may not use this file except in compliance
+ *        with the License.  You may obtain a copy of the License at
+ * 
+ *          http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *        Unless required by applicable law or agreed to in writing,
+ *        software distributed under the License is distributed on an
+ *        "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *        KIND, either express or implied.  See the License for the
+ *        specific language governing permissions and limitations
+ *        under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.core.uri.expression;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.List;
+
+import org.apache.olingo.odata2.api.edm.Edm;
+import org.apache.olingo.odata2.api.edm.EdmException;
+import org.apache.olingo.odata2.api.edm.EdmLiteral;
+import org.apache.olingo.odata2.api.edm.EdmType;
+import org.apache.olingo.odata2.api.edm.EdmTyped;
+import org.apache.olingo.odata2.api.uri.expression.BinaryExpression;
+import org.apache.olingo.odata2.api.uri.expression.BinaryOperator;
+import org.apache.olingo.odata2.api.uri.expression.CommonExpression;
+import org.apache.olingo.odata2.api.uri.expression.ExpressionVisitor;
+import org.apache.olingo.odata2.api.uri.expression.FilterExpression;
+import org.apache.olingo.odata2.api.uri.expression.LiteralExpression;
+import org.apache.olingo.odata2.api.uri.expression.MemberExpression;
+import org.apache.olingo.odata2.api.uri.expression.MethodExpression;
+import org.apache.olingo.odata2.api.uri.expression.MethodOperator;
+import org.apache.olingo.odata2.api.uri.expression.OrderByExpression;
+import org.apache.olingo.odata2.api.uri.expression.OrderExpression;
+import org.apache.olingo.odata2.api.uri.expression.PropertyExpression;
+import org.apache.olingo.odata2.api.uri.expression.SortOrder;
+import org.apache.olingo.odata2.api.uri.expression.UnaryExpression;
+import org.apache.olingo.odata2.api.uri.expression.UnaryOperator;
+import org.apache.olingo.odata2.core.ep.util.JsonStreamWriter;
+
+/**
+ * @author SAP AG
+ */
+public class JsonVisitor implements ExpressionVisitor {
+
+  @Override
+  public Object visitFilterExpression(final FilterExpression filterExpression, final String expressionString, final Object expression) {
+    return expression;
+  }
+
+  @Override
+  public Object visitBinary(final BinaryExpression binaryExpression, final BinaryOperator operator, final Object leftSide, final Object rightSide) {
+    try {
+      StringWriter writer = new StringWriter();
+      JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
+      jsonStreamWriter.beginObject()
+          .namedStringValueRaw("nodeType", binaryExpression.getKind().toString()).separator()
+          .namedStringValue("operator", operator.toUriLiteral()).separator()
+          .namedStringValueRaw("type", getType(binaryExpression)).separator()
+          .name("left").unquotedValue(leftSide.toString()).separator()
+          .name("right").unquotedValue(rightSide.toString())
+          .endObject();
+      writer.flush();
+      return writer.toString();
+    } catch (final IOException e) {
+      return null;
+    }
+  }
+
+  @Override
+  public Object visitOrderByExpression(final OrderByExpression orderByExpression, final String expressionString, final List<Object> orders) {
+    try {
+      StringWriter writer = new StringWriter();
+      JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
+      jsonStreamWriter.beginObject()
+          .namedStringValueRaw("nodeType", "order collection").separator()
+          .name("orders")
+          .beginArray();
+      boolean first = true;
+      for (final Object order : orders) {
+        if (first) {
+          first = false;
+        } else {
+          jsonStreamWriter.separator();
+        }
+        jsonStreamWriter.unquotedValue(order.toString());
+      }
+      jsonStreamWriter.endArray()
+          .endObject();
+      writer.flush();
+      return writer.toString();
+    } catch (final IOException e) {
+      return null;
+    }
+  }
+
+  @Override
+  public Object visitOrder(final OrderExpression orderExpression, final Object filterResult, final SortOrder sortOrder) {
+    try {
+      StringWriter writer = new StringWriter();
+      JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
+      jsonStreamWriter.beginObject()
+          .namedStringValueRaw("nodeType", orderExpression.getKind().toString()).separator()
+          .namedStringValueRaw("sortorder", sortOrder.toString()).separator()
+          .name("expression").unquotedValue(filterResult.toString())
+          .endObject();
+      writer.flush();
+      return writer.toString();
+    } catch (final IOException e) {
+      return null;
+    }
+  }
+
+  @Override
+  public Object visitLiteral(final LiteralExpression literal, final EdmLiteral edmLiteral) {
+    try {
+      StringWriter writer = new StringWriter();
+      JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
+      jsonStreamWriter.beginObject()
+          .namedStringValueRaw("nodeType", literal.getKind().toString()).separator()
+          .namedStringValueRaw("type", getType(literal)).separator()
+          .namedStringValue("value", edmLiteral.getLiteral())
+          .endObject();
+      writer.flush();
+      return writer.toString();
+    } catch (final IOException e) {
+      return null;
+    }
+  }
+
+  @Override
+  public Object visitMethod(final MethodExpression methodExpression, final MethodOperator method, final List<Object> parameters) {
+    try {
+      StringWriter writer = new StringWriter();
+      JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
+      jsonStreamWriter.beginObject()
+          .namedStringValueRaw("nodeType", methodExpression.getKind().toString()).separator()
+          .namedStringValueRaw("operator", method.toUriLiteral()).separator()
+          .namedStringValueRaw("type", getType(methodExpression)).separator()
+          .name("parameters")
+          .beginArray();
+      boolean first = true;
+      for (Object parameter : parameters) {
+        if (first) {
+          first = false;
+        } else {
+          jsonStreamWriter.separator();
+        }
+        jsonStreamWriter.unquotedValue(parameter.toString());
+      }
+      jsonStreamWriter.endArray()
+          .endObject();
+      writer.flush();
+      return writer.toString();
+    } catch (final IOException e) {
+      return null;
+    }
+  }
+
+  @Override
+  public Object visitMember(final MemberExpression memberExpression, final Object path, final Object property) {
+    try {
+      StringWriter writer = new StringWriter();
+      JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
+      jsonStreamWriter.beginObject()
+          .namedStringValueRaw("nodeType", memberExpression.getKind().toString()).separator()
+          .namedStringValueRaw("type", getType(memberExpression)).separator()
+          .name("source").unquotedValue(path.toString()).separator()
+          .name("path").unquotedValue(property.toString())
+          .endObject();
+      writer.flush();
+      return writer.toString();
+    } catch (final IOException e) {
+      return null;
+    }
+  }
+
+  @Override
+  public Object visitProperty(final PropertyExpression propertyExpression, final String uriLiteral, final EdmTyped edmProperty) {
+    try {
+      StringWriter writer = new StringWriter();
+      JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
+      jsonStreamWriter.beginObject()
+          .namedStringValueRaw("nodeType", propertyExpression.getKind().toString()).separator()
+          .namedStringValue("name", uriLiteral).separator()
+          .namedStringValueRaw("type", getType(propertyExpression))
+          .endObject();
+      writer.flush();
+      return writer.toString();
+    } catch (final IOException e) {
+      return null;
+    }
+  }
+
+  @Override
+  public Object visitUnary(final UnaryExpression unaryExpression, final UnaryOperator operator, final Object operand) {
+    try {
+      StringWriter writer = new StringWriter();
+      JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
+      jsonStreamWriter.beginObject()
+          .namedStringValueRaw("nodeType", unaryExpression.getKind().toString()).separator()
+          .namedStringValueRaw("operator", operator.toUriLiteral()).separator()
+          .namedStringValueRaw("type", getType(unaryExpression)).separator()
+          .name("operand").unquotedValue(operand.toString())
+          .endObject();
+      writer.flush();
+      return writer.toString();
+    } catch (final IOException e) {
+      return null;
+    }
+  }
+
+  private static String getType(final CommonExpression expression) {
+    try {
+      final EdmType type = expression.getEdmType();
+      return type == null ? null : type.getNamespace() + Edm.DELIMITER + type.getName();
+    } catch (final EdmException e) {
+      return "EdmException occurred: " + e.getMessage();
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/ff2b0a0e/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/LiteralExpressionImpl.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/LiteralExpressionImpl.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/LiteralExpressionImpl.java
new file mode 100644
index 0000000..bc41e28
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/LiteralExpressionImpl.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *        or more contributor license agreements.  See the NOTICE file
+ *        distributed with this work for additional information
+ *        regarding copyright ownership.  The ASF licenses this file
+ *        to you under the Apache License, Version 2.0 (the
+ *        "License"); you may not use this file except in compliance
+ *        with the License.  You may obtain a copy of the License at
+ * 
+ *          http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *        Unless required by applicable law or agreed to in writing,
+ *        software distributed under the License is distributed on an
+ *        "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *        KIND, either express or implied.  See the License for the
+ *        specific language governing permissions and limitations
+ *        under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.core.uri.expression;
+
+import org.apache.olingo.odata2.api.edm.EdmLiteral;
+import org.apache.olingo.odata2.api.edm.EdmType;
+import org.apache.olingo.odata2.api.uri.expression.CommonExpression;
+import org.apache.olingo.odata2.api.uri.expression.ExpressionKind;
+import org.apache.olingo.odata2.api.uri.expression.ExpressionVisitor;
+import org.apache.olingo.odata2.api.uri.expression.LiteralExpression;
+
+public class LiteralExpressionImpl implements LiteralExpression {
+
+  private EdmType edmType;
+  private EdmLiteral edmLiteral;
+  private String uriLiteral;
+
+  public LiteralExpressionImpl(final String uriLiteral, final EdmLiteral javaLiteral) {
+    this.uriLiteral = uriLiteral;
+    edmLiteral = javaLiteral;
+    edmType = edmLiteral.getType();
+  }
+
+  @Override
+  public EdmType getEdmType() {
+    return edmType;
+  }
+
+  @Override
+  public CommonExpression setEdmType(final EdmType edmType) {
+    this.edmType = edmType;
+    return this;
+  }
+
+  @Override
+  public ExpressionKind getKind() {
+    return ExpressionKind.LITERAL;
+  }
+
+  @Override
+  public String getUriLiteral() {
+    return uriLiteral;
+  }
+
+  @Override
+  public Object accept(final ExpressionVisitor visitor) {
+    Object ret = visitor.visitLiteral(this, edmLiteral);
+    return ret;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/ff2b0a0e/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/MemberExpressionImpl.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/MemberExpressionImpl.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/MemberExpressionImpl.java
new file mode 100644
index 0000000..b4d5ed8
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/MemberExpressionImpl.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *        or more contributor license agreements.  See the NOTICE file
+ *        distributed with this work for additional information
+ *        regarding copyright ownership.  The ASF licenses this file
+ *        to you under the Apache License, Version 2.0 (the
+ *        "License"); you may not use this file except in compliance
+ *        with the License.  You may obtain a copy of the License at
+ * 
+ *          http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *        Unless required by applicable law or agreed to in writing,
+ *        software distributed under the License is distributed on an
+ *        "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *        KIND, either express or implied.  See the License for the
+ *        specific language governing permissions and limitations
+ *        under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.core.uri.expression;
+
+import org.apache.olingo.odata2.api.edm.EdmType;
+import org.apache.olingo.odata2.api.exception.ODataApplicationException;
+import org.apache.olingo.odata2.api.uri.expression.BinaryExpression;
+import org.apache.olingo.odata2.api.uri.expression.BinaryOperator;
+import org.apache.olingo.odata2.api.uri.expression.CommonExpression;
+import org.apache.olingo.odata2.api.uri.expression.ExceptionVisitExpression;
+import org.apache.olingo.odata2.api.uri.expression.ExpressionKind;
+import org.apache.olingo.odata2.api.uri.expression.ExpressionVisitor;
+import org.apache.olingo.odata2.api.uri.expression.MemberExpression;
+
+/**
+ * @author SAP AG
+ */
+public class MemberExpressionImpl implements BinaryExpression, MemberExpression {
+  CommonExpression path;
+  CommonExpression property;
+  EdmType edmType;
+
+  public MemberExpressionImpl(final CommonExpression path, final CommonExpression property) {
+    this.path = path;
+    this.property = property;
+    edmType = property.getEdmType();
+  }
+
+  @Override
+  public CommonExpression getPath() {
+    return path;
+  }
+
+  @Override
+  public CommonExpression getProperty() {
+    return property;
+  }
+
+  @Override
+  public EdmType getEdmType() {
+    return edmType;
+  }
+
+  @Override
+  public CommonExpression setEdmType(final EdmType edmType) {
+    this.edmType = edmType;
+    return this;
+  }
+
+  @Override
+  public BinaryOperator getOperator() {
+    return BinaryOperator.PROPERTY_ACCESS;
+  }
+
+  @Override
+  public ExpressionKind getKind() {
+    return ExpressionKind.MEMBER;
+  }
+
+  @Override
+  public String getUriLiteral() {
+    return BinaryOperator.PROPERTY_ACCESS.toUriLiteral();
+  }
+
+  @Override
+  public Object accept(final ExpressionVisitor visitor) throws ExceptionVisitExpression, ODataApplicationException {
+    Object retSource = path.accept(visitor);
+    Object retPath = property.accept(visitor);
+
+    Object ret = visitor.visitMember(this, retSource, retPath);
+    return ret;
+  }
+
+  @Override
+  public CommonExpression getLeftOperand() {
+    return path;
+  }
+
+  @Override
+  public CommonExpression getRightOperand() {
+    return property;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/ff2b0a0e/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/MethodExpressionImpl.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/MethodExpressionImpl.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/MethodExpressionImpl.java
new file mode 100644
index 0000000..26a8ba4
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/MethodExpressionImpl.java
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *        or more contributor license agreements.  See the NOTICE file
+ *        distributed with this work for additional information
+ *        regarding copyright ownership.  The ASF licenses this file
+ *        to you under the Apache License, Version 2.0 (the
+ *        "License"); you may not use this file except in compliance
+ *        with the License.  You may obtain a copy of the License at
+ * 
+ *          http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *        Unless required by applicable law or agreed to in writing,
+ *        software distributed under the License is distributed on an
+ *        "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *        KIND, either express or implied.  See the License for the
+ *        specific language governing permissions and limitations
+ *        under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.core.uri.expression;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.olingo.odata2.api.edm.EdmType;
+import org.apache.olingo.odata2.api.exception.ODataApplicationException;
+import org.apache.olingo.odata2.api.uri.expression.CommonExpression;
+import org.apache.olingo.odata2.api.uri.expression.ExceptionVisitExpression;
+import org.apache.olingo.odata2.api.uri.expression.ExpressionKind;
+import org.apache.olingo.odata2.api.uri.expression.ExpressionVisitor;
+import org.apache.olingo.odata2.api.uri.expression.MethodExpression;
+import org.apache.olingo.odata2.api.uri.expression.MethodOperator;
+
+/**
+ * @author SAP AG
+ */
+public class MethodExpressionImpl implements MethodExpression {
+
+  private InfoMethod infoMethod;
+  private EdmType returnType;
+  private List<CommonExpression> actualParameters;
+
+  public MethodExpressionImpl(final InfoMethod infoMethod) {
+    this.infoMethod = infoMethod;
+    returnType = infoMethod.getReturnType();
+    actualParameters = new ArrayList<CommonExpression>();
+  }
+
+  @Override
+  public EdmType getEdmType() {
+    return returnType;
+  }
+
+  @Override
+  public CommonExpression setEdmType(final EdmType edmType) {
+    returnType = edmType;
+    return this;
+  }
+
+  @Override
+  public MethodOperator getMethod() {
+    return infoMethod.getMethod();
+  }
+
+  public InfoMethod getMethodInfo() {
+    return infoMethod;
+  }
+
+  @Override
+  public List<CommonExpression> getParameters() {
+    return actualParameters;
+  }
+
+  @Override
+  public int getParameterCount() {
+    return actualParameters.size();
+  }
+
+  /**
+   * @param expression
+   * @return A self reference for method chaining" 
+   */
+  public MethodExpressionImpl appendParameter(final CommonExpression expression) {
+    actualParameters.add(expression);
+    return this;
+  }
+
+  @Override
+  public ExpressionKind getKind() {
+    return ExpressionKind.METHOD;
+  }
+
+  @Override
+  public String getUriLiteral() {
+    return infoMethod.getSyntax();
+  }
+
+  @Override
+  public Object accept(final ExpressionVisitor visitor) throws ExceptionVisitExpression, ODataApplicationException {
+    ArrayList<Object> retParameters = new ArrayList<Object>();
+    for (CommonExpression parameter : actualParameters) {
+      Object retParameter = parameter.accept(visitor);
+      retParameters.add(retParameter);
+    }
+
+    Object ret = visitor.visitMethod(this, getMethod(), retParameters);
+    return ret;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/ff2b0a0e/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/OrderByExpressionImpl.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/OrderByExpressionImpl.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/OrderByExpressionImpl.java
new file mode 100644
index 0000000..7e28dc2
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/OrderByExpressionImpl.java
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *        or more contributor license agreements.  See the NOTICE file
+ *        distributed with this work for additional information
+ *        regarding copyright ownership.  The ASF licenses this file
+ *        to you under the Apache License, Version 2.0 (the
+ *        "License"); you may not use this file except in compliance
+ *        with the License.  You may obtain a copy of the License at
+ * 
+ *          http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *        Unless required by applicable law or agreed to in writing,
+ *        software distributed under the License is distributed on an
+ *        "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *        KIND, either express or implied.  See the License for the
+ *        specific language governing permissions and limitations
+ *        under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.core.uri.expression;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.olingo.odata2.api.edm.EdmType;
+import org.apache.olingo.odata2.api.exception.ODataApplicationException;
+import org.apache.olingo.odata2.api.uri.expression.CommonExpression;
+import org.apache.olingo.odata2.api.uri.expression.ExceptionVisitExpression;
+import org.apache.olingo.odata2.api.uri.expression.ExpressionKind;
+import org.apache.olingo.odata2.api.uri.expression.ExpressionVisitor;
+import org.apache.olingo.odata2.api.uri.expression.OrderByExpression;
+import org.apache.olingo.odata2.api.uri.expression.OrderExpression;
+
+/**
+ * @author SAP AG
+ */
+public class OrderByExpressionImpl implements OrderByExpression {
+  private String orderbyString;
+
+  List<OrderExpression> orders;
+
+  public OrderByExpressionImpl(final String orderbyString) {
+    this.orderbyString = orderbyString;
+    orders = new ArrayList<OrderExpression>();
+  }
+
+  @Override
+  public String getExpressionString() {
+    return orderbyString;
+  }
+
+  @Override
+  public List<OrderExpression> getOrders() {
+    return orders;
+  }
+
+  @Override
+  public int getOrdersCount() {
+    return orders.size();
+  }
+
+  public void addOrder(final OrderExpression orderNode) {
+    orders.add(orderNode);
+  }
+
+  @Override
+  public ExpressionKind getKind() {
+    return ExpressionKind.ORDERBY;
+  }
+
+  @Override
+  public EdmType getEdmType() {
+    return null;
+  }
+
+  @Override
+  public CommonExpression setEdmType(final EdmType edmType) {
+    return this;
+  }
+
+  @Override
+  public String getUriLiteral() {
+    return orderbyString;
+  }
+
+  @Override
+  public Object accept(final ExpressionVisitor visitor) throws ExceptionVisitExpression, ODataApplicationException {
+    ArrayList<Object> retParameters = new ArrayList<Object>();
+    for (OrderExpression order : orders) {
+      Object retParameter = order.accept(visitor);
+      retParameters.add(retParameter);
+    }
+
+    Object ret = visitor.visitOrderByExpression(this, orderbyString, retParameters);
+    return ret;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/ff2b0a0e/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/OrderByParser.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/OrderByParser.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/OrderByParser.java
new file mode 100644
index 0000000..c1ab197
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/OrderByParser.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *        or more contributor license agreements.  See the NOTICE file
+ *        distributed with this work for additional information
+ *        regarding copyright ownership.  The ASF licenses this file
+ *        to you under the Apache License, Version 2.0 (the
+ *        "License"); you may not use this file except in compliance
+ *        with the License.  You may obtain a copy of the License at
+ * 
+ *          http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *        Unless required by applicable law or agreed to in writing,
+ *        software distributed under the License is distributed on an
+ *        "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *        KIND, either express or implied.  See the License for the
+ *        specific language governing permissions and limitations
+ *        under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.core.uri.expression;
+
+import org.apache.olingo.odata2.api.exception.ODataMessageException;
+import org.apache.olingo.odata2.api.uri.expression.ExpressionParserException;
+import org.apache.olingo.odata2.api.uri.expression.OrderByExpression;
+
+/**
+ * Interface which defines a method for parsing a $orderby expression to allow different parser implementations
+ * <p>
+ * The current expression parser supports expressions as defined in the OData specification 2.0 with the following restrictions
+ *   - the methods "cast", "isof" and "replace" are not supported
+ *   
+ * The expression parser can be used with providing an Entity Data Model (EDM) an without providing it.
+ *  <p>When a EDM is provided the expression parser will be as strict as possible. That means:
+ *  <li>All properties used in the expression must be defined inside the EDM</li>
+ *  <li>The types of EDM properties will be checked against the lists of allowed type per method, binary- and unary operator</li>
+ *  </p>
+ *  <p>If no EDM is provided the expression parser performs a lax validation
+ *  <li>The properties used in the expression are not looked up inside the EDM and the type of the expression node representing the 
+ *      property will be "null"</li>
+ *  <li>Expression node with EDM-types which are "null" are not considered during the parameter type validation, to the return type of the parent expression node will
+ *  also become "null"</li>
+ *  
+ * @author SAP AG
+ */
+public interface OrderByParser {
+  /**
+   * Parses a $orderby expression string and creates an $orderby expression tree
+   * @param orderByExpression
+   *   The $orderby expression string ( for example "name asc" ) to be parsed
+   * @return
+   *    The $orderby expression tree
+   * @throws ExpressionParserException
+   *   Exception thrown due to errors while parsing the $orderby expression string 
+   * @throws ODataMessageException
+   *   Used for extensibility
+   */
+  abstract OrderByExpression parseOrderByString(String orderByExpression) throws ExpressionParserException, ODataMessageException;
+}