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"; + } + +}
