Return-Path: Delivered-To: apmail-commons-commits-archive@minotaur.apache.org Received: (qmail 81559 invoked from network); 13 Jun 2009 17:45:39 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 13 Jun 2009 17:45:39 -0000 Received: (qmail 62479 invoked by uid 500); 13 Jun 2009 17:45:50 -0000 Delivered-To: apmail-commons-commits-archive@commons.apache.org Received: (qmail 62378 invoked by uid 500); 13 Jun 2009 17:45:50 -0000 Mailing-List: contact commits-help@commons.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@commons.apache.org Delivered-To: mailing list commits@commons.apache.org Received: (qmail 62369 invoked by uid 99); 13 Jun 2009 17:45:50 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Sat, 13 Jun 2009 17:45:50 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Sat, 13 Jun 2009 17:45:46 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 365E523888D8; Sat, 13 Jun 2009 17:45:26 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r784442 [3/4] - in /commons/proper/jexl/branches/2.0: ./ src/java/org/apache/commons/jexl/ src/java/org/apache/commons/jexl/logging/ src/java/org/apache/commons/jexl/parser/ src/java/org/apache/commons/jexl/util/ src/java/org/apache/commons... Date: Sat, 13 Jun 2009 17:45:24 -0000 To: commits@commons.apache.org From: grobmeier@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20090613174526.365E523888D8@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Modified: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlArithmetic.java URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlArithmetic.java?rev=784442&r1=784441&r2=784442&view=diff ============================================================================== --- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlArithmetic.java (original) +++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlArithmetic.java Sat Jun 13 17:45:23 2009 @@ -1,301 +1,655 @@ -/* - * 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.commons.jexl; - -import java.math.BigDecimal; -import java.math.BigInteger; - -import org.apache.commons.jexl.util.Coercion; - -/** - * Perform arithmetic. - * @since 2.0 - */ -class JexlArithmetic implements Arithmetic { - - /** - * Add two values together. - * Rules are:
    - *
  1. If both are null, result is 0
  2. - *
  3. If either are floating point numbers, coerce to BigDecimals - * and add together
  4. - *
  5. Else treat as BigIntegers and add together
  6. - *
  7. If either numeric add fails on coercion to the appropriate type, - * treat as Strings and do concatenation
  8. - *
- * @param left first value - * @param right second value - * @return left + right. - */ - public Object add(Object left, Object right) { - if (left == null && right == null) { - return new Long(0); - } - - try { - if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) { - double l = Coercion.coercedouble(left); - double r = Coercion.coercedouble(right); - return new Double(l + r); - } - - // if both are bigintegers use that type - if (left instanceof BigInteger && right instanceof BigInteger) { - BigInteger l = Coercion.coerceBigInteger(left); - BigInteger r = Coercion.coerceBigInteger(right); - return l.add(r); - } - - // if either are bigdecimal use that type - if (left instanceof BigDecimal || right instanceof BigDecimal) { - BigDecimal l = Coercion.coerceBigDecimal(left); - BigDecimal r = Coercion.coerceBigDecimal(right); - return l.add(r); - } - - // otherwise treat as integers - BigInteger l = Coercion.coerceBigInteger(left); - BigInteger r = Coercion.coerceBigInteger(right); - BigInteger result = l.add(r); - BigInteger maxLong = BigInteger.valueOf(Long.MAX_VALUE); - if (result.compareTo(maxLong) <= 0) { - return new Long(result.longValue()); - } - return result; - } catch (java.lang.NumberFormatException nfe) { - // Well, use strings! - return left.toString().concat(right.toString()); - } - } - - /** - * Divide the left value by the right. - * Rules are:
    - *
  1. If both are null, result is 0
  2. - *
  3. Treat as BigDecimals and divide
  4. - *
- * @param left first value - * @param right second value - * @return left - right. - */ - public Object divide(Object left, Object right) { - if (left == null && right == null) { - return new Long(0); - } - - // if both are bigintegers use that type - if (left instanceof BigInteger && right instanceof BigInteger) { - BigInteger l = Coercion.coerceBigInteger(left); - BigInteger r = Coercion.coerceBigInteger(right); - if (r.compareTo(BigInteger.valueOf(0)) == 0) { - return r; - } - return l.divide(r); - } - - // if either are bigdecimal use that type - if (left instanceof BigDecimal || right instanceof BigDecimal) { - BigDecimal l = Coercion.coerceBigDecimal(left); - BigDecimal r = Coercion.coerceBigDecimal(right); - if (r.compareTo(BigDecimal.valueOf(0)) == 0) { - return r; - } - return l.divide(r, BigDecimal.ROUND_HALF_UP); - } - - double l = Coercion.coercedouble(left); - double r = Coercion.coercedouble(right); - if (r == 0) { - return new Double(r); - } - return new Double(l / r); - - } - - /** - * left value mod right. - * Rules are:
    - *
  1. If both are null, result is 0
  2. - *
  3. Treat both as BigIntegers and perform modulus
  4. - *
- * @param left first value - * @param right second value - * @return left mod right. - */ - public Object mod(Object left, Object right) { - if (left == null && right == null) { - return new Long(0); - } - - if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) { - double l = Coercion.coercedouble(left); - double r = Coercion.coercedouble(right); - return new Double(l % r); - } - - // if both are bigintegers use that type - if (left instanceof BigInteger && right instanceof BigInteger) { - BigInteger l = Coercion.coerceBigInteger(left); - BigInteger r = Coercion.coerceBigInteger(right); - if (r.compareTo(BigInteger.valueOf(0)) == 0) { - return r; - } - return l.mod(r); - } - - // if either are bigdecimal use that type - if (left instanceof BigDecimal || right instanceof BigDecimal) { - BigDecimal l = Coercion.coerceBigDecimal(left); - BigDecimal r = Coercion.coerceBigDecimal(right); - if (r.compareTo(BigDecimal.valueOf(0)) == 0) { - return r; - } - BigInteger intDiv = l.divide(r, BigDecimal.ROUND_HALF_UP).toBigInteger(); - BigInteger intValue = (r.multiply(new BigDecimal(intDiv))).toBigInteger(); - BigDecimal remainder = new BigDecimal(l.subtract(new BigDecimal(intValue)).toBigInteger()); - return remainder; - } - - // otherwise treat as integers - BigInteger l = Coercion.coerceBigInteger(left); - BigInteger r = Coercion.coerceBigInteger(right); - BigInteger result = l.mod(r); - BigInteger maxLong = BigInteger.valueOf(Long.MAX_VALUE); - if (result.compareTo(maxLong) <= 0) { - return new Long(result.longValue()); - } - return result; - } - - /** - * Multiply the left value by the right. - * Rules are:
    - *
  1. If both are null, result is 0
  2. - *
  3. If either are floating point numbers, coerce to BigDecimals - * and multiply
  4. - *
  5. Else treat as BigIntegers and multiply
  6. - *
  7. If either numeric operation fails on coercion to the appropriate type, - * treat as Strings and do concatenation
  8. - *
- * @param left first value - * @param right second value - * @return left * right. - */ - public Object multiply(Object left, Object right) { - if (left == null && right == null) { - return new Long(0); - } - - if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) { - double l = Coercion.coercedouble(left); - double r = Coercion.coercedouble(right); - return new Double(l * r); - } - - // if both are bigintegers use that type - if (left instanceof BigInteger && right instanceof BigInteger) { - BigInteger l = Coercion.coerceBigInteger(left); - BigInteger r = Coercion.coerceBigInteger(right); - return l.multiply(r); - } - - // if either are bigdecimal use that type - if (left instanceof BigDecimal || right instanceof BigDecimal) { - BigDecimal l = Coercion.coerceBigDecimal(left); - BigDecimal r = Coercion.coerceBigDecimal(right); - return l.multiply(r); - } - - // otherwise treat as integers - BigInteger l = Coercion.coerceBigInteger(left); - BigInteger r = Coercion.coerceBigInteger(right); - BigInteger result = l.multiply(r); - BigInteger maxLong = BigInteger.valueOf(Long.MAX_VALUE); - if (result.compareTo(maxLong) <= 0) { - return new Long(result.longValue()); - } - return result; - } - - /** - * Subtract the right value from the left. - * Rules are:
    - *
  1. If both are null, result is 0
  2. - *
  3. If either are floating point numbers, coerce to BigDecimals - * and subtract
  4. - *
  5. Else treat as BigIntegers and subtract
  6. - *
  7. If either numeric operation fails on coercion to the appropriate type, - * treat as Strings and do concatenation
  8. - *
- * @param left first value - * @param right second value - * @return left + right. - */ - public Object subtract(Object left, Object right) { - if (left == null && right == null) { - return new Long(0); - } - - if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) { - double l = Coercion.coercedouble(left); - double r = Coercion.coercedouble(right); - return new Double(l - r); - } - - // if both are bigintegers use that type - if (left instanceof BigInteger && right instanceof BigInteger) { - BigInteger l = Coercion.coerceBigInteger(left); - BigInteger r = Coercion.coerceBigInteger(right); - return l.subtract(r); - } - - // if either are bigdecimal use that type - if (left instanceof BigDecimal || right instanceof BigDecimal) { - BigDecimal l = Coercion.coerceBigDecimal(left); - BigDecimal r = Coercion.coerceBigDecimal(right); - return l.subtract(r); - } - - // otherwise treat as integers - BigInteger l = Coercion.coerceBigInteger(left); - BigInteger r = Coercion.coerceBigInteger(right); - BigInteger result = l.subtract(r); - BigInteger maxLong = BigInteger.valueOf(Long.MAX_VALUE); - if (result.compareTo(maxLong) <= 0) { - return new Long(result.longValue()); - } - return result; - } - - /** - * Test if the passed value is a floating point number, i.e. a float, double - * or string with ( "." | "E" | "e"). - * - * @param val the object to be tested - * @return true if it is, false otherwise. - */ - private boolean isFloatingPointNumber(Object val) { - if (val instanceof Float || val instanceof Double) { - return true; - } - if (val instanceof String) { - String string = (String) val; - return string.indexOf(".") != -1 || string.indexOf("e") != -1 || string.indexOf("E") != -1; - } - return false; - } -} +/* + * 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.commons.jexl; + +import java.math.BigDecimal; +import java.math.BigInteger; + +/** + * Perform arithmetic. + * @since 2.0 + */ +class JexlArithmetic implements Arithmetic { + + /** + * Add two values together. + * Rules are:
    + *
  1. If both are null, result is 0
  2. + *
  3. If either are floating point numbers, coerce to BigDecimals + * and add together
  4. + *
  5. Else treat as BigIntegers and add together
  6. + *
  7. If either numeric add fails on coercion to the appropriate type, + * treat as Strings and do concatenation
  8. + *
+ * @param left first value + * @param right second value + * @return left + right. + */ + public Object add(Object left, Object right) { + if (left == null && right == null) { + return new Long(0); + } + + try { + if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) { + double l = toDouble(left); + double r = toDouble(right); + return new Double(l + r); + } + + // if both are bigintegers use that type + if (left instanceof BigInteger && right instanceof BigInteger) { + BigInteger l = toBigInteger(left); + BigInteger r = toBigInteger(right); + return l.add(r); + } + + // if either are bigdecimal use that type + if (left instanceof BigDecimal || right instanceof BigDecimal) { + BigDecimal l = toBigDecimal(left); + BigDecimal r = toBigDecimal(right); + return l.add(r); + } + + // otherwise treat as integers + BigInteger l = toBigInteger(left); + BigInteger r = toBigInteger(right); + BigInteger result = l.add(r); + BigInteger maxLong = BigInteger.valueOf(Long.MAX_VALUE); + if (result.compareTo(maxLong) <= 0) { + return new Long(result.longValue()); + } + return result; + } catch (java.lang.NumberFormatException nfe) { + // Well, use strings! + return left.toString().concat(right.toString()); + } + } + + /** + * Divide the left value by the right. + * Rules are:
    + *
  1. If both are null, result is 0
  2. + *
  3. Treat as BigDecimals and divide
  4. + *
+ * @param left first value + * @param right second value + * @return left - right. + */ + public Object divide(Object left, Object right) { + if (left == null && right == null) { + return new Long(0); + } + + // if both are bigintegers use that type + if (left instanceof BigInteger && right instanceof BigInteger) { + BigInteger l = toBigInteger(left); + BigInteger r = toBigInteger(right); + if (r.compareTo(BigInteger.valueOf(0)) == 0) { + return r; + } + return l.divide(r); + } + + // if either are bigdecimal use that type + if (left instanceof BigDecimal || right instanceof BigDecimal) { + BigDecimal l = toBigDecimal(left); + BigDecimal r = toBigDecimal(right); + if (r.compareTo(BigDecimal.valueOf(0)) == 0) { + return r; + } + return l.divide(r, BigDecimal.ROUND_HALF_UP); + } + + double l = toDouble(left); + double r = toDouble(right); + if (r == 0) { + return new Double(r); + } + return new Double(l / r); + + } + + /** + * left value mod right. + * Rules are:
    + *
  1. If both are null, result is 0
  2. + *
  3. Treat both as BigIntegers and perform modulus
  4. + *
+ * @param left first value + * @param right second value + * @return left mod right. + */ + public Object mod(Object left, Object right) { + if (left == null && right == null) { + return new Long(0); + } + + if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) { + double l = toDouble(left); + double r = toDouble(right); + return new Double(l % r); + } + + // if both are bigintegers use that type + if (left instanceof BigInteger && right instanceof BigInteger) { + BigInteger l = toBigInteger(left); + BigInteger r = toBigInteger(right); + if (r.compareTo(BigInteger.valueOf(0)) == 0) { + return r; + } + return l.mod(r); + } + + // if either are bigdecimal use that type + if (left instanceof BigDecimal || right instanceof BigDecimal) { + BigDecimal l = toBigDecimal(left); + BigDecimal r = toBigDecimal(right); + if (r.compareTo(BigDecimal.valueOf(0)) == 0) { + return r; + } + BigInteger intDiv = l.divide(r, BigDecimal.ROUND_HALF_UP).toBigInteger(); + BigInteger intValue = (r.multiply(new BigDecimal(intDiv))).toBigInteger(); + BigDecimal remainder = new BigDecimal(l.subtract(new BigDecimal(intValue)).toBigInteger()); + return remainder; + } + + // otherwise treat as integers + BigInteger l = toBigInteger(left); + BigInteger r = toBigInteger(right); + BigInteger result = l.mod(r); + BigInteger maxLong = BigInteger.valueOf(Long.MAX_VALUE); + if (result.compareTo(maxLong) <= 0) { + return new Long(result.longValue()); + } + return result; + } + + /** + * Multiply the left value by the right. + * Rules are:
    + *
  1. If both are null, result is 0
  2. + *
  3. If either are floating point numbers, coerce to BigDecimals + * and multiply
  4. + *
  5. Else treat as BigIntegers and multiply
  6. + *
  7. If either numeric operation fails on coercion to the appropriate type, + * treat as Strings and do concatenation
  8. + *
+ * @param left first value + * @param right second value + * @return left * right. + */ + public Object multiply(Object left, Object right) { + if (left == null && right == null) { + return new Long(0); + } + + if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) { + double l = toDouble(left); + double r = toDouble(right); + return new Double(l * r); + } + + // if both are bigintegers use that type + if (left instanceof BigInteger && right instanceof BigInteger) { + BigInteger l = toBigInteger(left); + BigInteger r = toBigInteger(right); + return l.multiply(r); + } + + // if either are bigdecimal use that type + if (left instanceof BigDecimal || right instanceof BigDecimal) { + BigDecimal l = toBigDecimal(left); + BigDecimal r = toBigDecimal(right); + return l.multiply(r); + } + + // otherwise treat as integers + BigInteger l = toBigInteger(left); + BigInteger r = toBigInteger(right); + BigInteger result = l.multiply(r); + BigInteger maxLong = BigInteger.valueOf(Long.MAX_VALUE); + if (result.compareTo(maxLong) <= 0) { + return new Long(result.longValue()); + } + return result; + } + + /** + * Subtract the right value from the left. + * Rules are:
    + *
  1. If both are null, result is 0
  2. + *
  3. If either are floating point numbers, coerce to BigDecimals + * and subtract
  4. + *
  5. Else treat as BigIntegers and subtract
  6. + *
  7. If either numeric operation fails on coercion to the appropriate type, + * treat as Strings and do concatenation
  8. + *
+ * @param left first value + * @param right second value + * @return left + right. + */ + public Object subtract(Object left, Object right) { + if (left == null && right == null) { + return new Long(0); + } + + if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) { + double l = toDouble(left); + double r = toDouble(right); + return new Double(l - r); + } + + // if both are bigintegers use that type + if (left instanceof BigInteger && right instanceof BigInteger) { + BigInteger l = toBigInteger(left); + BigInteger r = toBigInteger(right); + return l.subtract(r); + } + + // if either are bigdecimal use that type + if (left instanceof BigDecimal || right instanceof BigDecimal) { + BigDecimal l = toBigDecimal(left); + BigDecimal r = toBigDecimal(right); + return l.subtract(r); + } + + // otherwise treat as integers + BigInteger l = toBigInteger(left); + BigInteger r = toBigInteger(right); + BigInteger result = l.subtract(r); + BigInteger maxLong = BigInteger.valueOf(Long.MAX_VALUE); + if (result.compareTo(maxLong) <= 0) { + return new Long(result.longValue()); + } + return result; + } + + /** + * Test if left and right are equal. + * + * @param left first value + * @param right second value + * @return test result. + */ + public boolean equals(Object left, Object right) { + if (left == null && right == null) { + /* + * if both are null L == R + */ + return true; + } else if (left == null || right == null) { + /* + * we know both aren't null, therefore L != R + */ + return false; + } else if (left.getClass().equals(right.getClass())) { + return left.equals(right); + } else if (left instanceof BigDecimal || right instanceof BigDecimal) { + return toBigDecimal(left).compareTo(toBigDecimal(right)) == 0; + } else if (isFloatingPointType(left, right)) { + return toDouble(left) == toDouble(right); + } else if (left instanceof Number || right instanceof Number || left instanceof Character + || right instanceof Character) { + return toLong(left) == toLong(right); + } else if (left instanceof Boolean || right instanceof Boolean) { + return toBoolean(left) == toBoolean(right); + } else if (left instanceof java.lang.String || right instanceof String) { + return left.toString().equals(right.toString()); + } + + return left.equals(right); + } + + + /** + * Test if left < right. + * + * @param left first value + * @param right second value + * @return test result. + */ + public boolean lessThan(Object left, Object right) { + if ((left == right) || (left == null) || (right == null)) { + return false; + } else if (isFloatingPoint(left) || isFloatingPoint(right)) { + double leftDouble = toDouble(left); + double rightDouble = toDouble(right); + + return leftDouble < rightDouble; + } else if (left instanceof BigDecimal || right instanceof BigDecimal) { + BigDecimal l = toBigDecimal(left); + BigDecimal r = toBigDecimal(right); + return l.compareTo(r) < 0; + } else if (isNumberable(left) || isNumberable(right)) { + long leftLong = toLong(left); + long rightLong = toLong(right); + + return leftLong < rightLong; + } else if (left instanceof String || right instanceof String) { + String leftString = left.toString(); + String rightString = right.toString(); + + return leftString.compareTo(rightString) < 0; + } else if (left instanceof Comparable) { + return ((Comparable) left).compareTo(right) < 0; + } else if (right instanceof Comparable) { + return ((Comparable) right).compareTo(left) > 0; + } + + throw new IllegalArgumentException("Invalid comparison : comparing cardinality for left: " + left + + " and right: " + right); + + } + + /** + * Test if left > right. + * + * @param left first value + * @param right second value + * @return test result. + */ + public boolean greaterThan(Object left, Object right) { + if (left == null || right == null) { + return false; + } + return !equals(left, right) && !lessThan(left, right); + } + + /** + * Test if left <= right. + * + * @param left first value + * @param right second value + * @return test result. + */ + public boolean lessThanOrEqual(Object left, Object right) { + return equals(left, right) || lessThan(left, right); + } + + /** + * Test if left >= right. + * + * @param left first value + * @param right second value + * @return test result. + */ + public boolean greaterThanOrEqual(Object left, Object right) { + return equals(left, right) || greaterThan(left, right); + } + + + + /** + * Test if either left or right are either a Float or Double. + * @param left one object to test + * @param right the other + * @return the result of the test. + */ + private boolean isFloatingPointType(Object left, Object right) { + return left instanceof Float || left instanceof Double || right instanceof Float || right instanceof Double; + } + + /** + * Test if the passed value is a floating point number, i.e. a float, double + * or string with ( "." | "E" | "e"). + * + * @param val the object to be tested + * @return true if it is, false otherwise. + */ + private boolean isFloatingPointNumber(Object val) { + if (val instanceof Float || val instanceof Double) { + return true; + } + if (val instanceof String) { + String string = (String) val; + return string.indexOf(".") != -1 || string.indexOf("e") != -1 || string.indexOf("E") != -1; + } + return false; + } + + /** + * Coerce to a boolean (not a java.lang.Boolean). + * + * @param val Object to be coerced. + * @return The Boolean coerced value, or false if none possible. + */ + public boolean toBoolean(Object val) { + if (val == null) { + return false; + } else if (val instanceof Boolean) { + return ((Boolean) val).booleanValue(); + } else if (val instanceof String) { + return Boolean.valueOf((String) val).booleanValue(); + } + // TODO: is this a reasonable default? + return false; + } + + /** + * Coerce to a Integer. + * + * @param val Object to be coerced. + * @return The Integer coerced value. + */ + public int toInteger(Object val) { + if (val == null) { + return 0; + } else if (val instanceof String) { + if ("".equals(val)) { + return 0; + } + return Integer.parseInt((String) val); + } else if (val instanceof Character) { + return ((Character) val).charValue(); + } else if (val instanceof Boolean) { + throw new IllegalArgumentException("Boolean->Integer coercion exception"); + } else if (val instanceof Number) { + return ((Number) val).intValue(); + } + + throw new IllegalArgumentException("Integer coercion exception, don't know how to convert " + val); + } + + + /** + * Coerce to a long (not a java.lang.Long). + * + * @param val Object to be coerced. + * @return The Long coerced value. + */ + public long toLong(Object val) { + if (val == null) { + return 0; + } else if (val instanceof String) { + if ("".equals(val)) { + return 0; + } + return Long.parseLong((String) val); + } else if (val instanceof Character) { + return ((Character) val).charValue(); + } else if (val instanceof Boolean) { + throw new NumberFormatException("Boolean->Long coercion exception"); + } else if (val instanceof Number) { + return ((Number) val).longValue(); + } + + throw new NumberFormatException("Long coercion exception for '" + val + "'"); + } + + /** + * Get a BigInteger from the object passed. + * Null and empty string maps to zero. + * @param val the object to be coerced. + * @return a BigDecimal. + */ + public BigInteger toBigInteger(Object val) { + if (val instanceof BigInteger) { + return (BigInteger) val; + } else if (val == null) { + return BigInteger.valueOf(0); + } else if (val instanceof String) { + String string = (String) val; + if ("".equals(string.trim())) { + return BigInteger.valueOf(0); + } + return new BigInteger(string); + } else if (val instanceof Number) { + return new BigInteger(val.toString()); + } else if (val instanceof Character) { + int i = ((Character) val).charValue(); + return BigInteger.valueOf(i); + } + + throw new IllegalArgumentException("BigInteger coercion. Can't coerce type " + val.getClass().getName()); + } + + /** + * Get a BigDecimal from the object passed. + * Null and empty string maps to zero. + * @param val the object to be coerced. + * @return a BigDecimal. + */ + public BigDecimal toBigDecimal(Object val) { + if (val instanceof BigDecimal) { + return (BigDecimal) val; + } else if (val == null) { + return BigDecimal.valueOf(0); + } else if (val instanceof String) { + String string = (String) val; + if ("".equals(string.trim())) { + return BigDecimal.valueOf(0); + } + return new BigDecimal(string); + } else if (val instanceof Number) { + return new BigDecimal(val.toString()); + } else if (val instanceof Character) { + int i = ((Character) val).charValue(); + return new BigDecimal(i); + } + + throw new IllegalArgumentException("BigDecimal coercion. Can't coerce type " + val.getClass().getName()); + } + + /** + * Coerce to a double. + * + * @param val Object to be coerced. + * @return The Double coerced value. + */ + public double toDouble(Object val) { + if (val == null) { + return 0; + } else if (val instanceof String) { + String string = (String) val; + if ("".equals(string.trim())) { + return 0; + } + // the spec seems to be iffy about this. Going to give it a wack anyway + return Double.parseDouble(string); + } else if (val instanceof Character) { + int i = ((Character) val).charValue(); + + return i; + } else if (val instanceof Double) { + return ((Double) val).doubleValue(); + } else if (val instanceof Number) { + //The below construct is used rather than ((Number)val).doubleValue() to ensure + //equality between comparing new Double( 6.4 / 3 ) and the jexl expression of 6.4 / 3 + return Double.parseDouble(String.valueOf(val)); + } else if (val instanceof Boolean) { + throw new IllegalArgumentException("Boolean->Double coercion exception"); + } + + throw new IllegalArgumentException("Double coercion exception, don't know how to convert " + val); + } + /** + * Is Object a floating point number. + * + * @param o Object to be analyzed. + * @return true if it is a Float or a Double. + */ + public static boolean isFloatingPoint(final Object o) { + return o instanceof Float || o instanceof Double; + } + + /** + * Is Object a whole number. + * + * @param o Object to be analyzed. + * @return true if Integer, Long, Byte, Short or Character. + */ + public static boolean isNumberable(final Object o) { + return o instanceof Integer + || o instanceof Long + || o instanceof Byte + || o instanceof Short + || o instanceof Character; + } + + /** + * Given a Number, return back the value using the smallest type the result + * will fit into. This works hand in hand with parameter 'widening' in java + * method calls, e.g. a call to substring(int,int) with an int and a long + * will fail, but a call to substring(int,int) with an int and a short will + * succeed. + * + * @param original the original number. + * @return a value of the smallest type the original number will fit into. + * @since 1.1 + */ + public Number narrow(Number original) { + if (original == null) { + return original; + } + Number result = original; + if (original instanceof BigDecimal) { + BigDecimal bigd = (BigDecimal) original; + // if it's bigger than a double it can't be narrowed + if (bigd.compareTo(new BigDecimal(Double.MAX_VALUE)) > 0) { + return original; + } + } + if (original instanceof Double || original instanceof Float || original instanceof BigDecimal) { + double value = original.doubleValue(); + if (value <= Float.MAX_VALUE && value >= Float.MIN_VALUE) { + result = new Float(result.floatValue()); + } + // else it fits in a double only + } else { + if (original instanceof BigInteger) { + BigInteger bigi = (BigInteger) original; + // if it's bigger than a Long it can't be narrowed + if (bigi.compareTo(new BigInteger(String.valueOf(Long.MAX_VALUE))) > 0) { + return original; + } + } + long value = original.longValue(); + if (value <= Byte.MAX_VALUE && value >= Byte.MIN_VALUE) { + // it will fit in a byte + result = new Byte((byte) value); + } else if (value <= Short.MAX_VALUE && value >= Short.MIN_VALUE) { + result = new Short((short) value); + } else if (value <= Integer.MAX_VALUE && value >= Integer.MIN_VALUE) { + result = new Integer((int) value); + } + // else it fits in a long + } + return result; + } + +} Added: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlEngine.java URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlEngine.java?rev=784442&view=auto ============================================================================== --- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlEngine.java (added) +++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlEngine.java Sat Jun 13 17:45:23 2009 @@ -0,0 +1,271 @@ +/* + * 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.commons.jexl; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.StringReader; +import java.net.URL; +import java.net.URLConnection; +import java.util.logging.Logger; +import java.util.logging.Level; + +import org.apache.commons.jexl.logging.LogManager; +import org.apache.commons.jexl.parser.ParseException; +import org.apache.commons.jexl.parser.Parser; +import org.apache.commons.jexl.parser.SimpleNode; +import org.apache.commons.jexl.parser.TokenMgrError; +import org.apache.commons.jexl.parser.ASTJexlScript; +import org.apache.commons.jexl.util.Introspector; +import org.apache.commons.jexl.util.introspection.Uberspect; + +/** + *

+ * Creates Expression and Script objects. + * Determines the behavior of Expressions & Scripts during their evaluation wrt: + * - introspection + * - arithmetic & comparison + * - error reporting + * - logging + *

+ */ +public class JexlEngine { + /** + * The Uberspect & Arithmetic + */ + protected final Uberspect uberspect; + protected final Arithmetic arithmetic; + /** + * The Log to which all JexlEngine messages will be logged. + */ + protected final Logger LOG; + /** + * The singleton ExpressionFactory also holds a single instance of + * {@link Parser}. + * When parsing expressions, ExpressionFactory synchronizes on Parser. + */ + protected final Parser parser = new Parser(new StringReader(";")); //$NON-NLS-1$ + + /** + * Whether expressions evaluated by this engine will throw exceptions or + * return null + */ + boolean silent = true; + /** + * ExpressionFactory & ScriptFactory need a singleton and this is the package + * instance fulfilling that pattern. + */ + static final JexlEngine DEFAULT = new JexlEngine(); + + /** + * Creates a default engine + */ + public JexlEngine() { + this(null, null, null); + } + + /** + * Creates a JEXL engine using the provided {@link Uberspect}, (@link Arithmetic) and logger. + * @param uberspect to allow different introspection behaviour + * @param arithmetic to allow different arithmetic behaviour + * @param log the logger for various messages + */ + public JexlEngine(Uberspect uberspect, Arithmetic arithmetic, Logger log) { + this.uberspect = uberspect == null? Introspector.getUberspect() : uberspect; + this.arithmetic = arithmetic == null? new JexlArithmetic() : arithmetic; + this.LOG = log == null? LogManager.getLogger("org.apache.commons.jexl.JexlEngine") : log; + } + + /** + * Sets whether this engine throws JexlException during evaluation. + * @param silent true means no JexlException will occur, false allows them + */ + public void setSilent(boolean silent) { + this.silent = silent; + } + + /** + * Checks whether this engine throws JexlException during evaluation. + */ + public boolean isSilent() { + return this.silent; + } + + /** + * Creates an Expression from a String containing valid + * JEXL syntax. This method parses the expression which + * must contain either a reference or an expression. + * @param expression A String containing valid JEXL syntax + * @return An Expression object which can be evaluated with a JexlContext + * @throws ParseException An exception can be thrown if there is a problem + * parsing this expression, or if the expression is neither an + * expression or a reference. + */ + public Expression createExpression(String expression) + throws ParseException { + String expr = cleanExpression(expression); + + // Parse the Expression + SimpleNode tree; + synchronized (parser) { + if (LOG != null) + LOG.finest("Parsing expression: " + expr); + try { + tree = parser.parse(new StringReader(expr)); + } catch (TokenMgrError tme) { + throw new ParseException(tme.getMessage()); + } catch (ParseException e) { + throw e; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + if (LOG != null && tree.jjtGetNumChildren() > 1 && LOG.isLoggable(Level.WARNING)) { + LOG.warning("The JEXL Expression created will be a reference" + + " to the first expression from the supplied script: \"" + + expression + "\" "); + } + + // Must be a simple reference, expression, statement or if, otherwise + // throw an exception. + SimpleNode node = (SimpleNode) tree.jjtGetChild(0); + + return new ExpressionImpl(this, expression, node); + } + + /** + * Creates a Script from a String containing valid JEXL syntax. + * This method parses the script which validates the syntax. + * + * @param scriptText A String containing valid JEXL syntax + * @return A {@link Script} which can be executed with a + * {@link JexlContext}. + * @throws Exception An exception can be thrown if there is a + * problem parsing the script. + */ + public Script createScript(String scriptText) throws Exception { + String cleanText = cleanExpression(scriptText); + SimpleNode script; + // Parse the Expression + synchronized (parser) { + if (LOG != null) + LOG.finest("Parsing script: " + cleanText); + try { + script = parser.parse(new StringReader(cleanText)); + } catch (TokenMgrError tme) { + throw new ParseException(tme.getMessage()); + } + } + if (script instanceof ASTJexlScript) { + return new ScriptImpl(this, cleanText, (ASTJexlScript) script); + } else { + throw new IllegalStateException("Parsed script is not " + + "an ASTJexlScript"); + } + } + + /** + * Creates a Script from a {@link File} containing valid JEXL syntax. + * This method parses the script and validates the syntax. + * + * @param scriptFile A {@link File} containing valid JEXL syntax. + * Must not be null. Must be a readable file. + * @return A {@link Script} which can be executed with a + * {@link JexlContext}. + * @throws Exception An exception can be thrown if there is a problem + * parsing the script. + */ + public Script createScript(File scriptFile) throws Exception { + if (scriptFile == null) { + throw new NullPointerException("scriptFile is null"); + } + if (!scriptFile.canRead()) { + throw new IOException("Can't read scriptFile (" + + scriptFile.getCanonicalPath() + ")"); + } + BufferedReader reader = new BufferedReader(new FileReader(scriptFile)); + return createScript(readerToString(reader)); + + } + + /** + * Creates a Script from a {@link URL} containing valid JEXL syntax. + * This method parses the script and validates the syntax. + * + * @param scriptUrl A {@link URL} containing valid JEXL syntax. + * Must not be null. Must be a readable file. + * @return A {@link Script} which can be executed with a + * {@link JexlContext}. + * @throws Exception An exception can be thrown if there is a problem + * parsing the script. + */ + public Script createScript(URL scriptUrl) throws Exception { + if (scriptUrl == null) { + throw new NullPointerException("scriptUrl is null"); + } + URLConnection connection = scriptUrl.openConnection(); + + BufferedReader reader = new BufferedReader( + new InputStreamReader(connection.getInputStream())); + return createScript(readerToString(reader)); + } + + /** + * Creates an interpreter + */ + protected Interpreter createInterpreter(JexlContext context) { + return new Interpreter(uberspect, arithmetic, context); + } + /** + * Trims the expression and adds a semi-colon if missing. + * @param expression to clean + * @return trimmed expression ending in a semi-colon + */ + protected String cleanExpression(String expression) { + String expr = expression.trim(); + if (!expr.endsWith(";")) { + expr += ";"; + } + return expr; + } + + /** + * Read a buffered reader into a StringBuffer and return a String with + * the contents of the reader. + * @param reader to be read. + * @return the contents of the reader as a String. + * @throws IOException on any error reading the reader. + */ + protected static String readerToString(BufferedReader reader) + throws IOException { + StringBuffer buffer = new StringBuffer(); + try { + String line; + while ((line = reader.readLine()) != null) { + buffer.append(line).append('\n'); + } + return buffer.toString(); + } finally { + reader.close(); + } + + } +} Added: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlException.java URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlException.java?rev=784442&view=auto ============================================================================== --- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlException.java (added) +++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlException.java Sat Jun 13 17:45:23 2009 @@ -0,0 +1,78 @@ +/* + * 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.commons.jexl; + +import org.apache.commons.jexl.parser.Node; + +/** + * Wraps any error that might occur during interpretation of a script or expression. + */ +public class JexlException extends RuntimeException { + Node mark; + + public JexlException(Node node, String msg) { + super(msg); + } + + public JexlException(Node node, String msg, Throwable cause) { + super(msg, cause); + mark = node; + } + + /** + * Gets information about the cause of this error. + * The returned string represents the outermost expression in error. + * The info parameter, an int[2] optionally provided by the caller, will be filled with the begin/end offset characters of the precise error's trigger. + * @param info character offset interval of the precise node triggering the error + * @return a string representation of the offending expression, the empty string if it could not be determined + */ + public String getInfo(int[] info) { + Debugger dbg = new Debugger(); + if (dbg.debug(mark)) { + if (info != null && info.length >= 2) { + info[0] = dbg.start(); + info[1] = dbg.end(); + } + return dbg.data(); + } + return ""; + } + + /** + * Detailed info message about this error. + * Format is "@[begin,end]: string \n msg" where: + * - begin, end are character offsets in the string for the precise location of the error + * - string is the string representation of the offending expression + * - msg is the actual explanation message for this error + * @return this error as a string + */ + public String toString() { + Debugger dbg = new Debugger(); + StringBuilder msg = new StringBuilder(); + if (dbg.debug(mark)) { + msg.append("@["); + msg.append(dbg.start()); + msg.append(","); + msg.append(dbg.end()); + msg.append("]: "); + msg.append(dbg.data()); + msg.append("\n"); + } + msg.append(super.toString()); + return msg.toString(); + } +} Modified: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/ScriptFactory.java URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/ScriptFactory.java?rev=784442&r1=784441&r2=784442&view=diff ============================================================================== --- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/ScriptFactory.java (original) +++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/ScriptFactory.java Sat Jun 13 17:45:23 2009 @@ -16,25 +16,15 @@ */ package org.apache.commons.jexl; -import java.io.BufferedReader; import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.io.InputStreamReader; import java.io.StringReader; import java.net.URL; -import java.net.URLConnection; -import org.apache.commons.jexl.parser.ASTJexlScript; -import org.apache.commons.jexl.parser.ParseException; import org.apache.commons.jexl.parser.Parser; -import org.apache.commons.jexl.parser.SimpleNode; -import org.apache.commons.jexl.parser.TokenMgrError; -import org.apache.commons.jexl.util.Introspector; -import org.apache.commons.jexl.util.introspection.Uberspect; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; + /** *

* Creates {@link Script}s. To create a JEXL Script, pass @@ -76,19 +66,9 @@ * Private constructor, the single instance is always obtained * with a call to getInstance(). */ - private ScriptFactory() { - this(Introspector.getUberspect()); - } + private ScriptFactory() {} /** - * Create a script factory with an alternate {@link Uberspect}. - * @param uberspect the uberspect implementation. - */ - public ScriptFactory(Uberspect uberspect) { - parser.setUberspect(uberspect); - } - - /** * Returns the single instance of ScriptFactory. * @return the instance of ScriptFactory. */ @@ -107,7 +87,7 @@ * problem parsing the script. */ public static Script createScript(String scriptText) throws Exception { - return getInstance().createNewScript(scriptText); + return JexlEngine.DEFAULT.createScript(scriptText); } /** @@ -122,16 +102,7 @@ * parsing the script. */ public static Script createScript(File scriptFile) throws Exception { - if (scriptFile == null) { - throw new NullPointerException("scriptFile is null"); - } - if (!scriptFile.canRead()) { - throw new IOException("Can't read scriptFile (" - + scriptFile.getCanonicalPath() + ")"); - } - BufferedReader reader = new BufferedReader(new FileReader(scriptFile)); - return createScript(readerToString(reader)); - + return JexlEngine.DEFAULT.createScript(scriptFile); } /** @@ -146,81 +117,7 @@ * parsing the script. */ public static Script createScript(URL scriptUrl) throws Exception { - if (scriptUrl == null) { - throw new NullPointerException("scriptUrl is null"); - } - URLConnection connection = scriptUrl.openConnection(); - - BufferedReader reader = new BufferedReader( - new InputStreamReader(connection.getInputStream())); - return createScript(readerToString(reader)); - } - - /** - * Creates a new Script based on the string. - * - * @param scriptText valid Jexl script - * @return Script a new script - * @throws Exception for a variety of reasons - mostly malformed scripts - */ - protected Script createNewScript(String scriptText) throws Exception { - String cleanText = cleanScript(scriptText); - SimpleNode script; - // Parse the Expression - synchronized (parser) { - log.debug("Parsing script: " + cleanText); - try { - script = parser.parse(new StringReader(cleanText)); - } catch (TokenMgrError tme) { - throw new ParseException(tme.getMessage()); - } - } - if (script instanceof ASTJexlScript) { - Interpreter interpreter = new Interpreter( - null, - Introspector.getUberspect(), - new JexlArithmetic()); - return new ScriptImpl(cleanText, (ASTJexlScript) script, interpreter); - } else { - throw new IllegalStateException("Parsed script is not " - + "an ASTJexlScript"); - } - } - - /** - * @todo move to ParseUtils? - * Trims the expression and adds a semi-colon if missing. - * @param script to clean - * @return trimmed expression ending in a semi-colon - */ - private String cleanScript(String script) { - String expr = script.trim(); - if (!expr.endsWith(";")) { - expr += ";"; - } - return expr; - } - - /** - * Read a buffered reader into a StringBuffer and return a String with - * the contents of the reader. - * @param reader to be read. - * @return the contents of the reader as a String. - * @throws IOException on any error reading the reader. - */ - private static String readerToString(BufferedReader reader) - throws IOException { - StringBuffer buffer = new StringBuffer(); - try { - String line; - while ((line = reader.readLine()) != null) { - buffer.append(line).append('\n'); - } - return buffer.toString(); - } finally { - reader.close(); - } - + return JexlEngine.DEFAULT.createScript(scriptUrl); } } Modified: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/ScriptImpl.java URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/ScriptImpl.java?rev=784442&r1=784441&r2=784442&view=diff ============================================================================== --- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/ScriptImpl.java (original) +++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/ScriptImpl.java Sat Jun 13 17:45:23 2009 @@ -24,13 +24,12 @@ * @since 1.1 */ class ScriptImpl implements Script { - + /** The engine for this expression. */ + protected final JexlEngine jexl; /** text of the script. */ private final String text; /** syntax tree. */ private final ASTJexlScript parsedScript; - /** The interpreter of the expression. */ - protected Interpreter interpreter; /** * Create a new Script from the given string and parsed syntax. @@ -38,17 +37,18 @@ * @param scriptTree the parsed script. * @param interp the interpreter to evaluate the expression */ - public ScriptImpl(String scriptText, ASTJexlScript scriptTree, Interpreter interp) { + public ScriptImpl(JexlEngine engine, String scriptText, ASTJexlScript scriptTree) { text = scriptText; parsedScript = scriptTree; - interpreter = interp; + jexl = engine; } /** * {@inheritDoc} */ public Object execute(JexlContext context) throws Exception { - return interpreter.interpret(parsedScript, context); + Interpreter interpreter = jexl.createInterpreter(context); + return interpreter.interpret(parsedScript, jexl.isSilent()); } /** Added: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/logging/LogManager.java URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/logging/LogManager.java?rev=784442&view=auto ============================================================================== --- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/logging/LogManager.java (added) +++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/logging/LogManager.java Sat Jun 13 17:45:23 2009 @@ -0,0 +1,30 @@ +/* + * 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.commons.jexl.logging; + +/** + * A local log manager class to allow diverting JUL logging without adding dependency upfront. + * + */ +public class LogManager { + static public java.util.logging.Logger getLogger(String name) { + return java.util.logging.Logger.getLogger(name); + } + static public void update() { + //noop; + } +} Modified: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/JEXLNode.java URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/JEXLNode.java?rev=784442&r1=784441&r2=784442&view=diff ============================================================================== --- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/JEXLNode.java (original) +++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/JEXLNode.java Sat Jun 13 17:45:23 2009 @@ -1,36 +1,36 @@ -/* - * 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.commons.jexl.parser; - -/** - * Base class for parser nodes - holds an 'image' of the token for later use. - * - * @since 2.0 - */ -class JEXLNode { - - /** - * Create the interpreter with the default settings. - */ - public JEXLNode() { - } - - // CSOFF: VisibilityModifier - /** token value. */ - public String image; +/* + * 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.commons.jexl.parser; + +/** + * Base class for parser nodes - holds an 'image' of the token for later use. + * + * @since 2.0 + */ +abstract class JEXLNode { + + /** + * Create the interpreter with the default settings. + */ + public JEXLNode() { + } + + // CSOFF: VisibilityModifier + /** token value. */ + public String image; } \ No newline at end of file Modified: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/Parser.jjt URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/Parser.jjt?rev=784442&r1=784441&r2=784442&view=diff ============================================================================== --- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/Parser.jjt (original) +++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/Parser.jjt Sat Jun 13 17:45:23 2009 @@ -46,20 +46,6 @@ public class Parser { - - /** TODO: The uberspect belongs in the interpreter's implementation */ - private Uberspect uberspect; - - public void setUberspect(Uberspect uberspect) - { - this.uberspect = uberspect; - } - - protected Uberspect getUberspect() - { - return uberspect; - } - public SimpleNode parse(Reader reader) throws Exception { @@ -146,21 +132,16 @@ void Expression() : {} { - LOOKAHEAD( PrimaryExpression() "=" ) + LOOKAHEAD( Reference() "=" ) Assignment() | ConditionalOrExpression() } -/* - * WTF? How is the LHS of the assignment a 'PrimaryExpression'? - * This includes Literal, Null, String literal etc... - */ -void Assignment() #Assignment(2) : -{} +void Assignment() #Assignment(2) : {} { - PrimaryExpression() "=" Expression() + Reference() "=" Expression() } void ConditionalOrExpression() #void : @@ -172,6 +153,11 @@ | "or" ConditionalAndExpression() #OrNode(2) )* + ( + "?" Expression() ":" Expression() #TernaryNode(3) + | + "?:" Expression() #TernaryNode(2) + )? } void ConditionalAndExpression() #void : @@ -380,7 +366,7 @@ | LOOKAHEAD( Reference() ";" ) ReferenceExpression() | - LOOKAHEAD( PrimaryExpression() "=" ) StatementExpression() + LOOKAHEAD( Reference() "=" ) StatementExpression() | ExpressionExpression() | Modified: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/VisitorAdapter.java URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/VisitorAdapter.java?rev=784442&r1=784441&r2=784442&view=diff ============================================================================== --- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/VisitorAdapter.java (original) +++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/VisitorAdapter.java Sat Jun 13 17:45:23 2009 @@ -1,298 +1,304 @@ -/* - * 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.commons.jexl.parser; - -/** - * Implementation of the ParserVisitor that dumps the current node and it's - * children and then visits them. - * - * @since 2.0 - */ -public class VisitorAdapter implements ParserVisitor { - - /** {@inheritDoc} */ - public Object visit(ASTAddNode node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTAndNode node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTArrayAccess node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTAssignment node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTBitwiseAndNode node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTBitwiseComplNode node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTBitwiseOrNode node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTBitwiseXorNode node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTBlock node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTDivNode node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTEmptyFunction node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTEQNode node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTExpression node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTExpressionExpression node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTFalseNode node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTFloatLiteral node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTForeachStatement node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTGENode node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTGTNode node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTIdentifier node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTIfStatement node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTIntegerLiteral node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTJexlScript node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTLENode node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTLTNode node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTMapEntry node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTMapLiteral node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTMethod node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTModNode node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTMulNode node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTNENode node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTNotNode node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTNullLiteral node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTOrNode node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTReference node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTReferenceExpression node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTSizeFunction node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTSizeMethod node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTStatementExpression node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTStringLiteral node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTSubtractNode node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTTrueNode node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTUnaryMinusNode node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(ASTWhileStatement node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - - /** {@inheritDoc} */ - public Object visit(SimpleNode node, Object data) { - node.dump(" "); - return node.childrenAccept(this, data); - } - +/* + * 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.commons.jexl.parser; + +/** + * Implementation of the ParserVisitor that dumps the current node and it's + * children and then visits them. + * + * @since 2.0 + */ +public class VisitorAdapter implements ParserVisitor { + + /** {@inheritDoc} */ + public Object visit(ASTAddNode node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTAndNode node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTArrayAccess node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTAssignment node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTBitwiseAndNode node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTBitwiseComplNode node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTBitwiseOrNode node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTBitwiseXorNode node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTBlock node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTDivNode node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTEmptyFunction node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTEQNode node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTExpression node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTExpressionExpression node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTFalseNode node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTFloatLiteral node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTForeachStatement node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTGENode node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTGTNode node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTIdentifier node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTIfStatement node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTIntegerLiteral node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTJexlScript node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTLENode node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTLTNode node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTMapEntry node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTMapLiteral node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTMethod node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTModNode node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTMulNode node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTNENode node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTNotNode node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTNullLiteral node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTOrNode node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTReference node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTReferenceExpression node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTSizeFunction node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTSizeMethod node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTStatementExpression node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTStringLiteral node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTSubtractNode node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTTernaryNode node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTTrueNode node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTUnaryMinusNode node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(ASTWhileStatement node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + + /** {@inheritDoc} */ + public Object visit(SimpleNode node, Object data) { + node.dump(" "); + return node.childrenAccept(this, data); + } + } \ No newline at end of file Modified: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/BooleanPropertyExecutor.java URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/BooleanPropertyExecutor.java?rev=784442&r1=784441&r2=784442&view=diff ============================================================================== --- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/BooleanPropertyExecutor.java (original) +++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/BooleanPropertyExecutor.java Sat Jun 13 17:45:23 2009 @@ -57,19 +57,15 @@ protected void discover(Class clazz, String property) { try { char c; - StringBuffer sb; - - Object[] params = {}; - /* * now look for a boolean isFoo */ - sb = new StringBuffer("is"); + StringBuilder sb = new StringBuilder("is"); sb.append(property); methodUsed = sb.toString(); - method = introspector.getMethod(clazz, methodUsed, params); + method = introspector.getMethod(clazz, methodUsed, EMPTY_PARAMS); if (null == method) { c = sb.charAt(2); @@ -81,7 +77,7 @@ } methodUsed = sb.toString(); - method = introspector.getMethod(clazz, methodUsed, params); + method = introspector.getMethod(clazz, methodUsed, EMPTY_PARAMS); } if (method != null) { @@ -101,7 +97,7 @@ } catch (RuntimeException e) { throw e; } catch (Exception e) { - rlog.error("PROGRAMMER ERROR : BooleanPropertyExector() : " + e, e); + rlog.error("PROGRAMMER ERROR : BooleanPropertyExector()", e); } } } Modified: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/Coercion.java URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/Coercion.java?rev=784442&r1=784441&r2=784442&view=diff ============================================================================== --- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/Coercion.java (original) +++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/Coercion.java Sat Jun 13 17:45:23 2009 @@ -27,6 +27,27 @@ */ public class Coercion { +} +class noCoercion { + + public boolean toBoolean(Object arg) { + return coerceboolean(arg); + } + public int toInteger(Object arg) { + return coerceinteger(arg); + } + public long toLong(Object arg) { + return coerceLong(arg); + } + public double toDouble(Object arg) { + return coercedouble(arg); + } + public java.math.BigInteger toBigInteger(Object arg) { + return coerceBigInteger(arg); + } + public java.math.BigDecimal toBigDecimal(Object arg) { + return coerceBigDecimal(arg); + } /** * Coerce to a boolean (not a java.lang.Boolean). *