You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by ch...@apache.org on 2015/02/20 14:34:14 UTC

[3/4] olingo-odata4 git commit: [OLINGO-545] OrderBy and Filter System Query Option evaluation added to TecScenario

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/0e6c9a11/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/operand/TypedOperand.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/operand/TypedOperand.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/operand/TypedOperand.java
new file mode 100644
index 0000000..23037b6
--- /dev/null
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/operand/TypedOperand.java
@@ -0,0 +1,199 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.olingo.server.tecsvc.processor.expression.operand;
+
+import java.math.BigDecimal;
+import java.util.Locale;
+
+import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
+import org.apache.olingo.commons.api.edm.EdmProperty;
+import org.apache.olingo.commons.api.edm.EdmType;
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmByte;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmDecimal;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmDouble;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmInt16;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmInt32;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmInt64;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmSByte;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmSingle;
+import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.tecsvc.processor.expression.primitive.EdmNull;
+
+public class TypedOperand extends VisitorOperand {
+
+  final private EdmType type;
+  final private EdmProperty edmProperty;
+
+  public TypedOperand(Object value, EdmType type) {
+    super(value);
+    this.type = type;
+    this.edmProperty = null;
+  }
+
+  public TypedOperand(Object value, EdmType type, EdmProperty edmProperty) {
+    super(value);
+    this.type = type;
+    this.edmProperty = edmProperty;
+  }
+
+  @Override
+  public TypedOperand asTypedOperand() throws ODataApplicationException {
+    if (!isNull() && value.getClass() != getDefaultType((EdmPrimitiveType) type)) {
+      return asTypedOperand((EdmPrimitiveType) type);
+    }
+    return this;
+  }
+
+  @Override
+  public TypedOperand asTypedOperand(EdmPrimitiveType... asTypes) throws ODataApplicationException {
+    if (type.equals(EdmNull.getInstance())) {
+      return this;
+    } else if (isNull()) {
+      return new TypedOperand(null, asTypes[0]);
+    }
+
+    Object newValue = null;
+    for (EdmPrimitiveType asType : asTypes) {
+      // Use BigDecimal for unlimited precision
+      if (asType.equals(EdmDouble.getInstance())
+          || asType.equals(EdmSingle.getInstance())
+          || asType.equals(EdmDecimal.getInstance())) {
+        
+        try {
+          newValue = new BigDecimal(value.toString());
+        } catch(NumberFormatException e) {
+          // Nothing to do
+        }
+      } else {
+        // Use type conversion of EdmPrimitive types
+        try {
+          final String literal = getLiteral(value);
+          newValue = tryCast(literal, (EdmPrimitiveType) type);
+        } catch (EdmPrimitiveTypeException e) {
+          // Nothing to do
+        }
+      }
+
+      if (newValue != null) {
+        return new TypedOperand(newValue, asType);
+      }
+    }
+
+    throw new ODataApplicationException("Cast failed ", HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT);
+  }
+
+  public TypedOperand castToCommonType(VisitorOperand otherOperand) throws ODataApplicationException {
+    final TypedOperand other = otherOperand.asTypedOperand();
+    final EdmType oType = other.getType();
+
+    // Make sure that the EDM type is equals, check also the java type.
+    // So it is possible, that there is an conversation even if the same
+    // EdmType is provided.
+    // For example consider an Edm16 (internal Integer) and Edm16(internal
+    // Short)
+    // shortInstance.equals(intInstance) will always be false!
+    if (type == oType && value != null && other.getValue() != null
+        && value.getClass() == other.getValue().getClass()) {
+      return this;
+    } else if (isNullLiteral() || other.isNullLiteral()) {
+      return this;
+    }
+
+    if (type.equals(EdmDouble.getInstance()) || oType.equals(EdmDouble.getInstance())) {
+      return asTypedOperand(EdmDouble.getInstance());
+    } else if (type.equals(EdmSingle.getInstance()) || oType.equals(EdmSingle.getInstance())) {
+      return asTypedOperand(EdmSingle.getInstance());
+    } else if (type.equals(EdmDecimal.getInstance()) || oType.equals(EdmDecimal.getInstance())) {
+      return asTypedOperand(EdmDecimal.getInstance());
+    } else if (type.equals(EdmInt64.getInstance()) || oType.equals(EdmInt64.getInstance())) {
+      return asTypedOperand(EdmInt64.getInstance());
+    } else if (type.equals(EdmInt32.getInstance()) || oType.equals(EdmInt32.getInstance())) {
+      return asTypedOperand(EdmInt32.getInstance());
+    } else if (type.equals(EdmInt16.getInstance()) || oType.equals(equals(EdmInt16.getInstance()))) {
+      return asTypedOperand(EdmInt16.getInstance());
+    } else {
+      return asTypedOperand((EdmPrimitiveType) type);
+    }
+  }
+
+  public EdmType getType() {
+    return type;
+  }
+
+  public <T> T getTypedValue(Class<T> clazz) {
+    return clazz.cast(value);
+  }
+
+  public boolean isNullLiteral() {
+    return type.equals(EdmNull.getInstance());
+  }
+
+  public boolean isNull() {
+    return isNullLiteral() || value == null;
+  }
+
+  public boolean isIntegerType() {
+    return is(EdmByte.getInstance(),
+        EdmSByte.getInstance(),
+        EdmInt16.getInstance(),
+        EdmInt32.getInstance(),
+        EdmInt64.getInstance());
+  }
+
+  public boolean isDecimalType() {
+    return is(EdmSingle.getInstance(),
+        EdmDouble.getInstance(),
+        EdmDecimal.getInstance());
+  }
+
+  public boolean is(EdmPrimitiveType... types) {
+    if (isNullLiteral()) {
+      return true;
+    }
+
+    for (EdmPrimitiveType type : types) {
+      if (type.equals(this.type)) {
+        return true;
+      }
+    }
+
+    return false;
+  }
+
+  @Override
+  public EdmProperty getEdmProperty() {
+    return edmProperty;
+  }
+
+  private String getLiteral(Object value) throws EdmPrimitiveTypeException {
+    final EdmProperty edmProperty = getEdmProperty();
+    String uriLiteral = null;
+
+    if (edmProperty != null) {
+      uriLiteral = ((EdmPrimitiveType) type).valueToString(value, edmProperty.isNullable(), edmProperty.getMaxLength(),
+          edmProperty.getPrecision(), edmProperty.getScale(), edmProperty.isUnicode());
+    } else {
+      uriLiteral = ((EdmPrimitiveType) type).valueToString(value, null, null, null, null, null);
+    }
+
+    return ((EdmPrimitiveType) type).toUriLiteral(uriLiteral);
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/0e6c9a11/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/operand/UntypedOperand.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/operand/UntypedOperand.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/operand/UntypedOperand.java
new file mode 100644
index 0000000..fa82c09
--- /dev/null
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/operand/UntypedOperand.java
@@ -0,0 +1,155 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.olingo.server.tecsvc.processor.expression.operand;
+
+import java.util.Locale;
+
+import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
+import org.apache.olingo.commons.api.edm.EdmProperty;
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmByte;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmDate;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmDateTimeOffset;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmDecimal;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmDouble;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmDuration;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmInt16;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmInt32;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmInt64;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmSByte;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmSingle;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmString;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmTime;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmTimeOfDay;
+import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.tecsvc.processor.expression.primitive.EdmNull;
+
+public class UntypedOperand extends VisitorOperand {
+
+  public UntypedOperand(final String literal) {
+    super(literal);
+  }
+
+  @Override
+  public TypedOperand asTypedOperand() throws ODataApplicationException {
+    return determineType();
+  }
+
+  @Override
+  public TypedOperand asTypedOperand(final EdmPrimitiveType... types) throws ODataApplicationException {
+    final String literal = (String) value;
+    Object newValue = null;
+
+    // First try the null literal
+    if ((newValue = tryCast(literal, EdmNull.getInstance())) != null) {
+      return new TypedOperand(newValue, EdmNull.getInstance());
+    }
+
+    // Than try the given types
+    for (EdmPrimitiveType type : types) {
+      newValue = tryCast(literal, type);
+
+      if (newValue != null) {
+        return new TypedOperand(newValue, type);
+      }
+    }
+
+    throw new ODataApplicationException("Cast failed", HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode(),
+        Locale.ROOT);
+  }
+
+  public TypedOperand determineType() throws ODataApplicationException {
+    final String literal = (String) value;
+    Object newValue = null;
+
+    // Null literal
+    if ((newValue = tryCast(literal, EdmNull.getInstance())) != null) {
+      return new TypedOperand(newValue, EdmNull.getInstance());
+    }
+
+    // String
+    if ((newValue = tryCast(literal, EdmString.getInstance())) != null) {
+      return new TypedOperand(newValue, EdmString.getInstance());
+    }
+
+    // Date
+    if ((newValue = tryCast(literal, EdmDateTimeOffset.getInstance())) != null) {
+      return new TypedOperand(newValue, EdmDateTimeOffset.getInstance());
+    }
+
+    if ((newValue = tryCast(literal, EdmDate.getInstance())) != null) {
+      return new TypedOperand(newValue, EdmDate.getInstance());
+    }
+
+    if ((newValue = tryCast(literal, EdmTimeOfDay.getInstance())) != null) {
+      return new TypedOperand(newValue, EdmTimeOfDay.getInstance());
+    }
+
+    if ((newValue = tryCast(literal, EdmTime.getInstance())) != null) {
+      return new TypedOperand(newValue, EdmTime.getInstance());
+    }
+
+    if ((newValue = tryCast(literal, EdmDuration.getInstance())) != null) {
+      return new TypedOperand(newValue, EdmDuration.getInstance());
+    }
+
+    // Integer
+    if ((newValue = tryCast(literal, EdmSByte.getInstance())) != null) {
+      return new TypedOperand(newValue, EdmSByte.getInstance());
+    }
+
+    if ((newValue = tryCast(literal, EdmByte.getInstance())) != null) {
+      return new TypedOperand(newValue, EdmByte.getInstance());
+    }
+
+    if ((newValue = tryCast(literal, EdmInt16.getInstance())) != null) {
+      return new TypedOperand(newValue, EdmInt16.getInstance());
+    }
+
+    if ((newValue = tryCast(literal, EdmInt32.getInstance())) != null) {
+      return new TypedOperand(newValue, EdmInt32.getInstance());
+    }
+
+    if ((newValue = tryCast(literal, EdmInt64.getInstance())) != null) {
+      return new TypedOperand(newValue, EdmInt64.getInstance());
+    }
+
+    // Decimal
+    if ((newValue = tryCast(literal, EdmDecimal.getInstance())) != null) {
+      return new TypedOperand(newValue, EdmDecimal.getInstance());
+    }
+
+    // Float
+    if ((newValue = tryCast(literal, EdmSingle.getInstance())) != null) {
+      return new TypedOperand(newValue, EdmSingle.getInstance());
+    }
+
+    if ((newValue = tryCast(literal, EdmDouble.getInstance())) != null) {
+      return new TypedOperand(newValue, EdmDouble.getInstance());
+    }
+
+    throw new ODataApplicationException("Could not determine type for literal " + literal,
+        HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode(), Locale.ROOT);
+  }
+
+  @Override
+  public EdmProperty getEdmProperty() {
+    return null;
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/0e6c9a11/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/operand/VisitorOperand.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/operand/VisitorOperand.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/operand/VisitorOperand.java
new file mode 100644
index 0000000..02f6fb0
--- /dev/null
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/operand/VisitorOperand.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.olingo.server.tecsvc.processor.expression.operand;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.HashMap;
+
+import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
+import org.apache.olingo.commons.api.edm.EdmProperty;
+import org.apache.olingo.commons.api.edm.EdmType;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmByte;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmDecimal;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmDouble;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmInt16;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmInt32;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmInt64;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmSByte;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmSingle;
+import org.apache.olingo.server.api.ODataApplicationException;
+
+public abstract class VisitorOperand {
+  final static private HashMap<EdmType, Class<?>> defaultTypeMapping = new HashMap<EdmType, Class<?>>();
+  protected Object value;
+
+  static {
+    defaultTypeMapping.put(EdmByte.getInstance(), BigInteger.class);
+    defaultTypeMapping.put(EdmSByte.getInstance(), BigInteger.class);
+    defaultTypeMapping.put(EdmInt16.getInstance(), BigInteger.class);
+    defaultTypeMapping.put(EdmInt32.getInstance(), BigInteger.class);
+    defaultTypeMapping.put(EdmInt64.getInstance(), BigInteger.class);
+
+    defaultTypeMapping.put(EdmSingle.getInstance(), BigDecimal.class);
+    defaultTypeMapping.put(EdmDouble.getInstance(), BigDecimal.class);
+    defaultTypeMapping.put(EdmDecimal.getInstance(), BigDecimal.class);
+  }
+
+  public VisitorOperand(Object value) {
+    this.value = value;
+  }
+
+  public abstract TypedOperand asTypedOperand() throws ODataApplicationException;
+
+  public abstract TypedOperand asTypedOperand(EdmPrimitiveType... types) throws ODataApplicationException;
+
+  public abstract EdmProperty getEdmProperty();
+
+  public Object getValue() {
+    return value;
+  }
+
+  protected Object castTo(final String value, EdmPrimitiveType type) throws EdmPrimitiveTypeException {
+    final EdmProperty edmProperty = getEdmProperty();
+
+    if (edmProperty != null) {
+      return type.valueOfString(value, edmProperty.isNullable(), edmProperty.getMaxLength(),
+          edmProperty.getPrecision(), edmProperty.getScale(),
+          edmProperty.isUnicode(), getDefaultType(type));
+    } else {
+      return type.valueOfString(value, null, null, null, null, null, getDefaultType(type));
+    }
+  }
+
+  protected Class<?> getDefaultType(EdmPrimitiveType type) {
+    return defaultTypeMapping.get(type) != null ? defaultTypeMapping.get(type) : type.getDefaultType();
+  }
+
+  protected Object tryCast(final String literal, final EdmPrimitiveType type) {
+    try {
+      return castTo(type.fromUriLiteral(literal), type);
+    } catch (EdmPrimitiveTypeException e) {
+      return null;
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/0e6c9a11/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/operation/BinaryOperator.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/operation/BinaryOperator.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/operation/BinaryOperator.java
new file mode 100644
index 0000000..f41e798
--- /dev/null
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/operation/BinaryOperator.java
@@ -0,0 +1,318 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.olingo.server.tecsvc.processor.expression.operation;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.sql.Timestamp;
+import java.util.Calendar;
+import java.util.Locale;
+
+import org.apache.olingo.commons.api.edm.EdmType;
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmBoolean;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmByte;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmDate;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmDateTimeOffset;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmDouble;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmDuration;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmInt16;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmInt32;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmInt64;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmSByte;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmSingle;
+import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.api.uri.queryoption.expression.BinaryOperatorKind;
+import org.apache.olingo.server.tecsvc.processor.expression.operand.TypedOperand;
+import org.apache.olingo.server.tecsvc.processor.expression.operand.VisitorOperand;
+import org.apache.olingo.server.tecsvc.processor.expression.primitive.EdmNull;
+
+public class BinaryOperator {
+  private static final int FACTOR_SECOND_INT = 1000;
+  private static final BigDecimal FACTOR_SECOND = new BigDecimal(1000);
+  private static final BigInteger EDM_SBYTE_MIN = BigInteger.valueOf(Byte.MIN_VALUE);
+  private static final BigInteger EDN_SBYTE_MAX = BigInteger.valueOf(Byte.MAX_VALUE);
+  private static final BigInteger EDM_BYTE_MIN = BigInteger.ZERO;
+  private static final BigInteger EDM_BYTE_MAX = BigInteger.valueOf(((Byte.MAX_VALUE * 2) + 1));
+  private static final BigInteger EDM_INT16_MIN = BigInteger.valueOf(Short.MIN_VALUE);
+  private static final BigInteger EDM_INT16_MAX = BigInteger.valueOf(Short.MAX_VALUE);
+  private static final BigInteger EDM_INT32_MIN = BigInteger.valueOf(Integer.MIN_VALUE);
+  private static final BigInteger EDM_INT32_MAX = BigInteger.valueOf(Integer.MAX_VALUE);
+  private static final BigInteger EDM_INT64_MIN = BigInteger.valueOf(Long.MIN_VALUE);
+  private static final BigInteger EDM_INT64_MAX = BigInteger.valueOf(Long.MAX_VALUE);
+  private static final BigDecimal EDM_SINGLE_MIN = BigDecimal.valueOf(Float.MIN_VALUE);
+  private static final BigDecimal EDM_SINGLE_MAX = BigDecimal.valueOf(Float.MAX_VALUE);
+
+  private static final int EQUALS = 0;
+  private static final int LESS_THAN = -1;
+  private static final int GREATER_THAN = 1;
+
+  private TypedOperand right;
+  private TypedOperand left;
+
+  public BinaryOperator(final VisitorOperand leftOperand, final VisitorOperand rightOperand)
+      throws ODataApplicationException {
+    left = leftOperand.asTypedOperand();
+    right = rightOperand.asTypedOperand();
+
+    left = left.castToCommonType(right);
+    right = right.castToCommonType(left);
+  }
+
+  public VisitorOperand andOperator() throws ODataApplicationException {
+    Boolean result = null;
+    if (left.is(EdmBoolean.getInstance()) && right.is(EdmBoolean.getInstance())) {
+      if (Boolean.TRUE.equals(left.getValue()) && Boolean.TRUE.equals(right.getValue())) {
+        result = true;
+      } else if (Boolean.FALSE.equals(left.getValue()) || Boolean.FALSE.equals(right.getValue())) {
+        result = false;
+      }
+
+      return new TypedOperand(result, EdmBoolean.getInstance());
+    } else {
+      throw new ODataApplicationException("Add operator needs two binary operands",
+          HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT);
+    }
+  }
+
+  public VisitorOperand orOperator() throws ODataApplicationException {
+    Boolean result = null;
+    if (left.is(EdmBoolean.getInstance()) && right.is(EdmBoolean.getInstance())) {
+      if (Boolean.TRUE.equals(left.getValue()) || Boolean.TRUE.equals(right.getValue())) {
+        result = true;
+      } else if (Boolean.FALSE.equals(left.getValue()) && Boolean.FALSE.equals(right.getValue())) {
+        result = false;
+      }
+
+      return new TypedOperand(result, EdmBoolean.getInstance());
+    } else {
+      throw new ODataApplicationException("Or operator needs two binary operands",
+          HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT);
+    }
+  }
+
+  public VisitorOperand equalsOperator() {
+    final boolean result = isBinaryComparisonNecessary() && binaryComparison(EQUALS);
+    return new TypedOperand(result, EdmBoolean.getInstance());
+  }
+
+  public VisitorOperand notEqualsOperator() {
+    final VisitorOperand equalsOperator = equalsOperator();
+    return new TypedOperand(!(Boolean) equalsOperator.getValue(), EdmBoolean.getInstance());
+  }
+
+  private boolean isBinaryComparisonNecessary() {
+    // binaryComparison() need to be called, if both operand are either null or not null
+    return !(left.isNull() ^ right.isNull());
+  }
+
+  public VisitorOperand greaterEqualsOperator() {
+    final boolean result = isBinaryComparisonNecessary() && binaryComparison(GREATER_THAN, EQUALS);
+    return new TypedOperand(result, EdmBoolean.getInstance());
+  }
+
+  public VisitorOperand greaterThanOperator() {
+    final boolean result = isBinaryComparisonNecessary() && binaryComparison(GREATER_THAN);
+    return new TypedOperand(result, EdmBoolean.getInstance());
+  }
+
+  public VisitorOperand lessEqualsOperator() {
+    final boolean result = isBinaryComparisonNecessary() && binaryComparison(LESS_THAN, EQUALS);
+    return new TypedOperand(result, EdmBoolean.getInstance());
+  }
+
+  public VisitorOperand lessThanOperator() {
+    final boolean result = isBinaryComparisonNecessary() && binaryComparison(LESS_THAN);
+    return new TypedOperand(result, EdmBoolean.getInstance());
+  }
+
+  private boolean binaryComparison(int... expect) {
+    int result;
+
+    if (left.isNull() && right.isNull()) {
+      result = 0; // null is equals to null
+    } else {
+      // left and right are not null!
+      if (left.isIntegerType()) {
+        result = left.getTypedValue(BigInteger.class).compareTo(right.getTypedValue(BigInteger.class));
+      } else if (left.isDecimalType()) {
+        result = left.getTypedValue(BigDecimal.class).compareTo(right.getTypedValue(BigDecimal.class));
+      } else {
+        result = left.getValue().equals(right.getValue()) ? 0 : 1;
+      }
+    }
+    for (int expectedValue : expect) {
+      if (expectedValue == result) {
+        return true;
+      }
+    }
+
+    return false;
+  }
+
+  public VisitorOperand arithmeticOperator(BinaryOperatorKind operator) throws ODataApplicationException {
+    if (left.isNull() || right.isNull()) {
+      return new TypedOperand(new Object(), EdmNull.getInstance());
+    } else {
+      if (left.isIntegerType()) {
+        final BigInteger result = integerArithmeticOperation(operator);
+        return new TypedOperand(result, determineResultType(result, left));
+      } else if (left.isDecimalType()) {
+        final BigDecimal result = decimalArithmeticOperation(operator);
+        return new TypedOperand(result, determineResultType(result, left));
+      } else if (left.is(EdmDate.getInstance(), EdmDuration.getInstance(), EdmDateTimeOffset.getInstance())) {
+        return dateArithmeticOperation(operator);
+      } else {
+        throw new ODataApplicationException("Invalid type", HttpStatusCode.BAD_REQUEST.getStatusCode(),
+            Locale.ROOT);
+      }
+    }
+  }
+
+  private EdmType determineResultType(final Number arithmeticResult, TypedOperand leftOperand) {
+    // Left and right operand have the same typed, so it is enough to check the type of the left operand
+    if (leftOperand.isDecimalType()) {
+      final BigDecimal value = (BigDecimal) arithmeticResult;
+      if (value.compareTo(EDM_SINGLE_MIN) >= 0 && value.compareTo(EDM_SINGLE_MAX) <= 0) {
+        return EdmSingle.getInstance();
+      } else {
+        return EdmDouble.getInstance();
+      }
+    } else {
+      final BigInteger value = (BigInteger) arithmeticResult;
+
+      if (value.compareTo(EDN_SBYTE_MAX) <= 0 && value.compareTo(EDM_SBYTE_MIN) >= 0) {
+        return EdmSByte.getInstance();
+      }
+      if (value.compareTo(EDM_BYTE_MAX) <= 0 && value.compareTo(EDM_BYTE_MIN) >= 0) {
+        return EdmByte.getInstance();
+      }
+      if (value.compareTo(EDM_INT16_MAX) <= 0 && value.compareTo(EDM_INT16_MIN) >= 0) {
+        return EdmInt16.getInstance();
+      }
+      if (value.compareTo(EDM_INT32_MAX) <= 0 && value.compareTo(EDM_INT32_MIN) >= 0) {
+        return EdmInt32.getInstance();
+      }
+      if (value.compareTo(EDM_INT64_MAX) <= 0 && value.compareTo(EDM_INT64_MIN) >= 0) {
+        return EdmInt64.getInstance();
+      }
+      // Choose double instead single because precision is higher (52 bits instead of 23)
+      return EdmDouble.getInstance();
+    }
+  }
+
+  private VisitorOperand dateArithmeticOperation(BinaryOperatorKind operator) throws ODataApplicationException {
+    VisitorOperand result = null;
+
+    if (left.is(EdmDate.getInstance())) {
+      if (right.is(EdmDate.getInstance()) && operator == BinaryOperatorKind.SUB) {
+        long millis = left.getTypedValue(Calendar.class).getTimeInMillis()
+            - left.getTypedValue(Calendar.class).getTimeInMillis();
+
+        result = new TypedOperand(new BigDecimal(millis).divide(FACTOR_SECOND), EdmDuration.getInstance());
+      } else if (right.is(EdmDuration.getInstance()) && operator == BinaryOperatorKind.ADD) {
+        long millis = left.getTypedValue(Calendar.class).getTimeInMillis()
+            + (right.getTypedValue(BigDecimal.class).longValue() * FACTOR_SECOND_INT);
+
+        result = new TypedOperand(new Timestamp(millis), EdmDateTimeOffset.getInstance());
+      } else if (right.is(EdmDuration.getInstance()) && operator == BinaryOperatorKind.SUB) {
+        long millis = left.getTypedValue(Calendar.class).getTimeInMillis()
+            - (right.getTypedValue(BigDecimal.class).longValue() * FACTOR_SECOND_INT);
+
+        result = new TypedOperand(new Timestamp(millis), EdmDateTimeOffset.getInstance());
+      }
+    } else if (left.is(EdmDuration.getInstance())) {
+      if (right.is(EdmDuration.getInstance()) && operator == BinaryOperatorKind.ADD) {
+        long seconds = left.getTypedValue(BigDecimal.class).longValue()
+            + right.getTypedValue(BigDecimal.class).longValue();
+
+        result = new TypedOperand(new BigDecimal(seconds), EdmDuration.getInstance());
+      } else if (right.is(EdmDuration.getInstance()) && operator == BinaryOperatorKind.SUB) {
+        long seconds = left.getTypedValue(BigDecimal.class).longValue()
+            - right.getTypedValue(BigDecimal.class).longValue();
+
+        result = new TypedOperand(new BigDecimal(seconds), EdmDuration.getInstance());
+      }
+    } else if (left.is(EdmDateTimeOffset.getInstance())) {
+      if (right.is(EdmDuration.getInstance()) && operator == BinaryOperatorKind.ADD) {
+        long millis = left.getTypedValue(Timestamp.class).getTime()
+            + (right.getTypedValue(BigDecimal.class).longValue() * FACTOR_SECOND_INT);
+
+        result = new TypedOperand(new Timestamp(millis), EdmDateTimeOffset.getInstance());
+      } else if (right.is(EdmDuration.getInstance()) && operator == BinaryOperatorKind.SUB) {
+        long millis = left.getTypedValue(Timestamp.class).getTime()
+            - (right.getTypedValue(BigDecimal.class).longValue() * FACTOR_SECOND_INT);
+
+        result = new TypedOperand(new Timestamp(millis), EdmDateTimeOffset.getInstance());
+      } else if (right.is(EdmDateTimeOffset.getInstance()) && operator == BinaryOperatorKind.SUB) {
+        long millis = left.getTypedValue(Timestamp.class).getTime()
+            - right.getTypedValue(Timestamp.class).getTime();
+
+        result = new TypedOperand(new BigDecimal(millis).divide(FACTOR_SECOND), EdmDuration.getInstance());
+      }
+    }
+
+    if (result == null) {
+      throw new ODataApplicationException("Invalid operation / operand", HttpStatusCode.BAD_REQUEST.getStatusCode(),
+          Locale.ROOT);
+    } else {
+      return result;
+    }
+  }
+
+  private BigDecimal decimalArithmeticOperation(BinaryOperatorKind operator) throws ODataApplicationException {
+    final BigDecimal left = this.left.getTypedValue(BigDecimal.class);
+    final BigDecimal right = this.right.getTypedValue(BigDecimal.class);
+
+    switch (operator) {
+    case ADD:
+      return left.add(right);
+    case DIV:
+      return left.divide(left);
+    case MUL:
+      return left.multiply(right);
+    case SUB:
+      return left.subtract(right);
+    default:
+      throw new ODataApplicationException("Operator not valid", HttpStatusCode.BAD_REQUEST.getStatusCode(),
+          Locale.ROOT);
+    }
+  }
+
+  private BigInteger integerArithmeticOperation(BinaryOperatorKind operator) throws ODataApplicationException {
+    final BigInteger left = this.left.getTypedValue(BigInteger.class);
+    final BigInteger right = this.right.getTypedValue(BigInteger.class);
+
+    switch (operator) {
+    case ADD:
+      return left.add(right);
+    case DIV:
+      return left.divide(right);
+    case MUL:
+      return left.multiply(right);
+    case SUB:
+      return left.subtract(right);
+    case MOD:
+      return left.mod(right);
+    default:
+      throw new ODataApplicationException("Operator not valid", HttpStatusCode.BAD_REQUEST.getStatusCode(),
+          Locale.ROOT);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/0e6c9a11/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/operation/MethodCallOperator.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/operation/MethodCallOperator.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/operation/MethodCallOperator.java
new file mode 100644
index 0000000..ece4df4
--- /dev/null
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/operation/MethodCallOperator.java
@@ -0,0 +1,334 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.olingo.server.tecsvc.processor.expression.operation;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.math.MathContext;
+import java.math.RoundingMode;
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.List;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
+import org.apache.olingo.commons.api.edm.EdmType;
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmBoolean;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmDate;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmDateTimeOffset;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmDecimal;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmInt32;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmString;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmTimeOfDay;
+import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.tecsvc.processor.expression.operand.TypedOperand;
+import org.apache.olingo.server.tecsvc.processor.expression.operand.VisitorOperand;
+
+public class MethodCallOperator {
+
+  final private List<VisitorOperand> parameters;
+
+  public MethodCallOperator(List<VisitorOperand> parameters) {
+    this.parameters = parameters;
+  }
+
+  public VisitorOperand endsWith() throws ODataApplicationException {
+    return stringFunction(new StringFunction() {
+      @Override
+      public Object perform(List<String> params) {
+        return params.get(0).endsWith(params.get(1));
+      }
+    }, EdmBoolean.getInstance());
+  }
+
+  public VisitorOperand indexOf() throws ODataApplicationException {
+    return stringFunction(new StringFunction() {
+      @Override
+      public Object perform(List<String> params) {
+        return params.get(0).indexOf(params.get(1));
+      }
+    }, EdmInt32.getInstance());
+  }
+
+  public VisitorOperand startsWith() throws ODataApplicationException {
+    return stringFunction(new StringFunction() {
+      @Override
+      public Object perform(List<String> params) {
+        return params.get(0).startsWith(params.get(1));
+      }
+    }, EdmBoolean.getInstance());
+  }
+
+  public VisitorOperand toLower() throws ODataApplicationException {
+    return stringFunction(new StringFunction() {
+      @Override
+      public Object perform(List<String> params) {
+        return params.get(0).toLowerCase();
+      }
+    }, EdmString.getInstance());
+  }
+
+  public VisitorOperand toUpper() throws ODataApplicationException {
+    return stringFunction(new StringFunction() {
+      @Override
+      public Object perform(List<String> params) {
+        return params.get(0).toUpperCase();
+      }
+    }, EdmString.getInstance());
+  }
+
+  public VisitorOperand trim() throws ODataApplicationException {
+    return stringFunction(new StringFunction() {
+      @Override
+      public Object perform(List<String> params) {
+        return params.get(0).trim();
+      }
+    }, EdmString.getInstance());
+  }
+
+  public VisitorOperand substring() throws ODataApplicationException {
+    final TypedOperand valueOperand = parameters.get(0).asTypedOperand();
+    final TypedOperand startOperand = parameters.get(1).asTypedOperand();
+
+    if (valueOperand.isNull() || startOperand.isNull()) {
+      return new TypedOperand(null, EdmString.getInstance());
+    } else if (valueOperand.is(EdmString.getInstance()) && startOperand.isIntegerType()) {
+      final String value = valueOperand.getTypedValue(String.class);
+      final BigInteger start = startOperand.getTypedValue(BigInteger.class);
+      int end = value.length();
+
+      if (parameters.size() == 3) {
+        final TypedOperand lengthOperand = parameters.get(2).asTypedOperand();
+
+        if (lengthOperand.isNull()) {
+          return new TypedOperand(null, EdmString.getInstance());
+        } else if (lengthOperand.isIntegerType()) {
+          end = Math.min(start.add(lengthOperand.getTypedValue(BigInteger.class)).intValue(), value.length());
+        } else {
+          throw new ODataApplicationException("Third substring parameter should be Edm.Int32",
+              HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT);
+        }
+      }
+
+      return new TypedOperand(value.substring(Math.min(start.intValue(), value.length()), end),
+          EdmString.getInstance());
+    } else {
+      throw new ODataApplicationException("Substring has invalid parameters. First parameter should be Edm.String,"
+          + " second parameter should be Edm.Int32", HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT);
+    }
+  }
+
+  public VisitorOperand contains() throws ODataApplicationException {
+    return stringFunction(new StringFunction() {
+      @Override
+      public Object perform(List<String> params) {
+        return params.get(0).contains(params.get(1));
+      }
+    }, EdmBoolean.getInstance());
+  }
+
+  public VisitorOperand concat() throws ODataApplicationException {
+    return stringFunction(new StringFunction() {
+      @Override
+      public Object perform(List<String> params) {
+        return params.get(0) + params.get(1);
+      }
+    }, EdmString.getInstance());
+  }
+
+  public VisitorOperand length() throws ODataApplicationException {
+    return stringFunction(new StringFunction() {
+      @Override
+      public Object perform(List<String> params) {
+        return params.get(0).length();
+      }
+    }, EdmInt32.getInstance());
+  }
+
+  public VisitorOperand year() throws ODataApplicationException {
+    return dateFunction(new DateFunction() {
+      @Override
+      public Object perform(Calendar calendar, TypedOperand operand) {
+        return calendar.get(Calendar.YEAR);
+      }
+    }, EdmInt32.getInstance(), EdmDateTimeOffset.getInstance(), EdmDate.getInstance());
+  }
+
+  public VisitorOperand month() throws ODataApplicationException {
+    return dateFunction(new DateFunction() {
+      @Override
+      public Object perform(Calendar calendar, TypedOperand operand) {
+        // Month is 0-based!
+        return calendar.get(Calendar.MONTH) + 1;
+      }
+    }, EdmInt32.getInstance(), EdmDateTimeOffset.getInstance(), EdmDate.getInstance());
+  }
+
+  public VisitorOperand day() throws ODataApplicationException {
+    return dateFunction(new DateFunction() {
+      @Override
+      public Object perform(Calendar calendar, TypedOperand operand) {
+        return calendar.get(Calendar.DAY_OF_MONTH);
+      }
+    }, EdmInt32.getInstance(), EdmDateTimeOffset.getInstance(), EdmDate.getInstance());
+  }
+
+  public VisitorOperand hour() throws ODataApplicationException {
+    return dateFunction(new DateFunction() {
+      @Override
+      public Object perform(Calendar calendar, TypedOperand operand) {
+        return calendar.get(Calendar.HOUR_OF_DAY);
+      }
+    }, EdmInt32.getInstance(), EdmDateTimeOffset.getInstance(), EdmTimeOfDay.getInstance());
+  }
+
+  public VisitorOperand minute() throws ODataApplicationException {
+    return dateFunction(new DateFunction() {
+      @Override
+      public Object perform(Calendar calendar, TypedOperand operand) {
+        return calendar.get(Calendar.MINUTE);
+      }
+    }, EdmInt32.getInstance(), EdmDateTimeOffset.getInstance(), EdmTimeOfDay.getInstance());
+  }
+
+  public VisitorOperand second() throws ODataApplicationException {
+    return dateFunction(new DateFunction() {
+      @Override
+      public Object perform(Calendar calendar, TypedOperand operand) {
+        return calendar.get(Calendar.SECOND);
+      }
+    }, EdmInt32.getInstance(), EdmDateTimeOffset.getInstance(), EdmTimeOfDay.getInstance());
+  }
+
+  public VisitorOperand fractionalseconds() throws ODataApplicationException {
+    return dateFunction(new DateFunction() {
+      @Override
+      public Object perform(Calendar calendar, TypedOperand operand) {
+        if (operand.getValue() instanceof Timestamp) {
+          return new BigDecimal(operand.getTypedValue(Timestamp.class).getNanos()).divide(BigDecimal
+              .valueOf(1000 * 1000 * 1000));
+        } else {
+          return new BigDecimal(calendar.get(Calendar.MILLISECOND)).divide(BigDecimal.valueOf(1000));
+        }
+      }
+    }, EdmDecimal.getInstance(), EdmDateTimeOffset.getInstance(), EdmTimeOfDay.getInstance());
+  }
+
+  public VisitorOperand round() throws ODataApplicationException {
+    final TypedOperand operand = parameters.get(0).asTypedOperand();
+    if (operand.isNull()) {
+      return operand;
+    } else if (operand.isDecimalType()) {
+      return new TypedOperand(operand.getTypedValue(BigDecimal.class).round(new MathContext(1, RoundingMode.HALF_UP)),
+          operand.getType());
+    } else {
+      throw new ODataApplicationException("Invalid type", HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT);
+    }
+  }
+
+  public VisitorOperand floor() throws ODataApplicationException {
+    final TypedOperand operand = parameters.get(0).asTypedOperand();
+    if (operand.isNull()) {
+      return operand;
+    } else if (operand.isDecimalType()) {
+      return new TypedOperand(operand.getTypedValue(BigDecimal.class).round(new MathContext(1, RoundingMode.FLOOR)),
+          operand.getType());
+    } else {
+      throw new ODataApplicationException("Invalid type", HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT);
+    }
+  }
+
+  public VisitorOperand ceiling() throws ODataApplicationException {
+    final TypedOperand operand = parameters.get(0).asTypedOperand();
+    if (operand.isNull()) {
+      return operand;
+    } else if (operand.isDecimalType()) {
+      return new TypedOperand(operand.getTypedValue(BigDecimal.class).round(new MathContext(1, RoundingMode.CEILING)),
+          operand.getType());
+    } else {
+      throw new ODataApplicationException("Invalid type", HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT);
+    }
+  }
+
+  private interface StringFunction {
+    Object perform(List<String> params);
+  }
+
+  private interface DateFunction {
+    Object perform(Calendar calendar, TypedOperand operand);
+  }
+
+  private VisitorOperand dateFunction(DateFunction f, EdmType returnType, EdmPrimitiveType... expectedTypes)
+      throws ODataApplicationException {
+    final TypedOperand operand = parameters.get(0).asTypedOperand();
+
+    if (operand.is(expectedTypes)) {
+      if (!operand.isNull()) {
+        Calendar calendar = null;
+        if (operand.is(EdmDate.getInstance())) {
+          calendar = operand.getTypedValue(Calendar.class);
+        } else if (operand.is(EdmDateTimeOffset.getInstance())) {
+          final Timestamp timestamp = operand.getTypedValue(Timestamp.class);
+          calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
+          calendar.setTimeInMillis(timestamp.getTime());
+        } else if (operand.is(EdmTimeOfDay.getInstance())) {
+          calendar = operand.getTypedValue(Calendar.class);
+        } else {
+          throw new ODataApplicationException("Invalid type", HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT);
+        }
+
+        return new TypedOperand(f.perform(calendar, operand), returnType);
+      } else {
+        return new TypedOperand(null, returnType);
+      }
+    } else {
+      throw new ODataApplicationException("Invalid type", HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT);
+    }
+  }
+
+  private VisitorOperand stringFunction(StringFunction f, EdmType returnValue) throws ODataApplicationException {
+    List<String> stringParameters = getParametersAsString();
+    if (stringParameters.contains(null)) {
+      return new TypedOperand(null, returnValue);
+    } else {
+      return new TypedOperand(f.perform(stringParameters), returnValue);
+    }
+  }
+
+  private List<String> getParametersAsString() throws ODataApplicationException {
+    List<String> result = new ArrayList<String>();
+
+    for (VisitorOperand param : parameters) {
+      TypedOperand operand = param.asTypedOperand();
+      if (operand.isNull()) {
+        result.add(null);
+      } else if (operand.is(EdmString.getInstance())) {
+        result.add(operand.getTypedValue(String.class));
+      } else {
+        throw new ODataApplicationException("Invalid parameter. Expected Edm.String", HttpStatusCode.BAD_REQUEST
+            .getStatusCode(), Locale.ROOT);
+      }
+    }
+
+    return result;
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/0e6c9a11/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/operation/UnaryOperator.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/operation/UnaryOperator.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/operation/UnaryOperator.java
new file mode 100644
index 0000000..b0b5435
--- /dev/null
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/operation/UnaryOperator.java
@@ -0,0 +1,63 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.olingo.server.tecsvc.processor.expression.operation;
+
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Locale;
+
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmBoolean;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmDuration;
+import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.tecsvc.processor.expression.operand.TypedOperand;
+import org.apache.olingo.server.tecsvc.processor.expression.operand.VisitorOperand;
+
+public class UnaryOperator {
+  final private TypedOperand operand;
+
+  public UnaryOperator(VisitorOperand operand) throws ODataApplicationException {
+    this.operand = operand.asTypedOperand();
+  }
+
+  public VisitorOperand minusOperation() throws ODataApplicationException {
+    if (operand.isNull()) {
+      return operand;
+    } else if (operand.isIntegerType()) {
+      return new TypedOperand(operand.getTypedValue(BigInteger.class).negate(), operand.getType());
+    } else if (operand.isDecimalType() || operand.is(EdmDuration.getInstance())) {
+      return new TypedOperand(operand.getTypedValue(BigDecimal.class).negate(), operand.getType());
+    } else {
+      throw new ODataApplicationException("Unsupported type", HttpStatusCode.BAD_REQUEST.getStatusCode(),
+          Locale.ROOT);
+    }
+  }
+
+  public VisitorOperand notOperation() throws ODataApplicationException {
+    if (operand.isNull()) {
+      return operand;
+    } else if (operand.is(EdmBoolean.getInstance())) {
+      return new TypedOperand(!operand.getTypedValue(Boolean.class), operand.getType());
+    } else {
+      throw new ODataApplicationException("Unsupported type", HttpStatusCode.BAD_REQUEST.getStatusCode(),
+          Locale.ROOT);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/0e6c9a11/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/primitive/EdmNull.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/primitive/EdmNull.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/primitive/EdmNull.java
new file mode 100644
index 0000000..02b624d
--- /dev/null
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/expression/primitive/EdmNull.java
@@ -0,0 +1,58 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.olingo.server.tecsvc.processor.expression.primitive;
+
+import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
+import org.apache.olingo.commons.core.edm.primitivetype.SingletonPrimitiveType;
+
+
+public final class EdmNull extends SingletonPrimitiveType {
+  
+  private static final EdmNull instance = new EdmNull();
+  
+  public static EdmNull getInstance() {
+    return instance;
+  }
+  
+  @Override
+  public Class<?> getDefaultType() {
+    return Object.class;
+  }
+
+  @Override
+  protected <T> T internalValueOfString(String value, Boolean isNullable, Integer maxLength, Integer precision,
+      Integer scale, Boolean isUnicode, Class<T> returnType) throws EdmPrimitiveTypeException {
+    if (!value.equals("null")) {
+      throw new EdmPrimitiveTypeException("The literal '" + value + "' has illegal content.");
+    }
+
+    if (returnType.isAssignableFrom(Object.class)) {
+      return returnType.cast(new Object());
+    } else {
+      throw new ClassCastException("unsupported return type " + returnType.getSimpleName());
+    }
+  }
+
+  @Override
+  protected <T> String internalValueToString(T value, Boolean isNullable, Integer maxLength, Integer precision,
+      Integer scale, Boolean isUnicode) throws EdmPrimitiveTypeException {
+    return "null";
+  }
+
+}