0001: /*
0002: * The Apache Software License, Version 1.1
0003: *
0004: * Copyright (c) 1999 The Apache Software Foundation. All rights
0005: * reserved.
0006: *
0007: * Redistribution and use in source and binary forms, with or without
0008: * modification, are permitted provided that the following conditions
0009: * are met:
0010: *
0011: * 1. Redistributions of source code must retain the above copyright
0012: * notice, this list of conditions and the following disclaimer.
0013: *
0014: * 2. Redistributions in binary form must reproduce the above copyright
0015: * notice, this list of conditions and the following disclaimer in
0016: * the documentation and/or other materials provided with the
0017: * distribution.
0018: *
0019: * 3. The end-user documentation included with the redistribution, if
0020: * any, must include the following acknowlegement:
0021: * "This product includes software developed by the
0022: * Apache Software Foundation (http://www.apache.org/)."
0023: * Alternately, this acknowlegement may appear in the software itself,
0024: * if and wherever such third-party acknowlegements normally appear.
0025: *
0026: * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
0027: * Foundation" must not be used to endorse or promote products derived
0028: * from this software without prior written permission. For written
0029: * permission, please contact apache@apache.org.
0030: *
0031: * 5. Products derived from this software may not be called "Apache"
0032: * nor may "Apache" appear in their names without prior written
0033: * permission of the Apache Group.
0034: *
0035: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0036: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0037: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0038: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
0039: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0040: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0041: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0042: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0043: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
0044: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
0045: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0046: * SUCH DAMAGE.
0047: * ====================================================================
0048: *
0049: * This software consists of voluntary contributions made by many
0050: * individuals on behalf of the Apache Software Foundation. For more
0051: * information on the Apache Software Foundation, please see
0052: * <http://www.apache.org/>.
0053: *
0054: */
0055:
0056: package org.jbpm.jpdl.el.impl;
0057:
0058: import java.beans.PropertyEditor;
0059: import java.beans.PropertyEditorManager;
0060: import java.math.BigInteger;
0061: import java.math.BigDecimal;
0062:
0063: import org.jbpm.jpdl.el.ELException;
0064:
0065: /**
0066: *
0067: * <p>This class contains the logic for coercing data types before
0068: * operators are applied to them.
0069: *
0070: * <p>The following is the list of rules applied for various type
0071: * conversions.
0072: *
0073: * <ul><pre>
0074: * Applying arithmetic operator
0075: * Binary operator - A {+,-,*} B
0076: * if A and B are null
0077: * return 0
0078: * if A or B is BigDecimal, coerce both to BigDecimal and then:
0079: * if operator is +, return <code>A.add(B)</code>
0080: * if operator is -, return <code>A.subtract(B)</code>
0081: * if operator is *, return <code>A.multiply(B)</code>
0082: * if A or B is Float, Double, or String containing ".", "e", or "E"
0083: * if A or B is BigInteger, coerce both A and B to BigDecimal and apply operator
0084: * coerce both A and B to Double and apply operator
0085: * if A or B is BigInteger, coerce both to BigInteger and then:
0086: * if operator is +, return <code>A.add(B)</code>
0087: * if operator is -, return <code>A.subtract(B)</code>
0088: * if operator is *, return <code>A.multiply(B)</code>
0089: * otherwise
0090: * coerce both A and B to Long
0091: * apply operator
0092: * if operator results in exception (such as divide by 0), error
0093: *
0094: * Binary operator - A {/,div} B
0095: * if A and B are null
0096: * return 0
0097: * if A or B is a BigDecimal or BigInteger, coerce both to BigDecimal and
0098: * return <code>A.divide(B, BigDecimal.ROUND_HALF_UP)</code>
0099: * otherwise
0100: * coerce both A and B to Double
0101: * apply operator
0102: * if operator results in exception (such as divide by 0), error
0103: *
0104: * Binary operator - A {%,mod} B
0105: * if A and B are null
0106: * return 0
0107: * if A or B is BigDecimal, Float, Double, or String containing ".", "e" or "E"
0108: * coerce both to Double
0109: * apply operator
0110: * if A or B is BigInteger, coerce both to BigInteger and return
0111: * <code>A.remainder(B)</code>
0112: * otherwise
0113: * coerce both A and B to Long
0114: * apply operator
0115: * if operator results in exception (such as divide by 0), error
0116: *
0117: * Unary minus operator - -A
0118: * if A is null
0119: * return 0
0120: * if A is BigInteger or BigDecimal, return <code>A.negate()</code>
0121: * if A is String
0122: * if A contains ".", "e", or "E"
0123: * coerce to Double, apply operator
0124: * otherwise
0125: * coerce to a Long and apply operator
0126: * if A is Byte,Short,Integer,Long,Float,Double
0127: * retain type, apply operator
0128: * if operator results in exception, error
0129: * otherwise
0130: * error
0131: *
0132: * Applying "empty" operator - empty A
0133: * if A is null
0134: * return true
0135: * if A is zero-length String
0136: * return true
0137: * if A is zero-length array
0138: * return true
0139: * if A is List and ((List) A).isEmpty()
0140: * return true
0141: * if A is Map and ((Map) A).isEmpty()
0142: * return true
0143: * if A is Collection an ((Collection) A).isEmpty()
0144: * return true
0145: * otherwise
0146: * return false
0147: *
0148: * Applying logical operators
0149: * Binary operator - A {and,or} B
0150: * coerce both A and B to Boolean, apply operator
0151: * NOTE - operator stops as soon as expression can be determined, i.e.,
0152: * A and B and C and D - if B is false, then only A and B is evaluated
0153: * Unary not operator - not A
0154: * coerce A to Boolean, apply operator
0155: *
0156: * Applying relational operator
0157: * A {<,>,<=,>=,lt,gt,lte,gte} B
0158: * if A==B
0159: * if operator is >= or <=
0160: * return true
0161: * otherwise
0162: * return false
0163: * if A or B is null
0164: * return false
0165: * if A or B is BigDecimal, coerce both A and B to BigDecimal and use the
0166: * return value of <code>A.compareTo(B)</code>
0167: * if A or B is Float or Double
0168: * coerce both A and B to Double
0169: * apply operator
0170: * if A or B is BigInteger, coerce both A and B to BigInteger and use the
0171: * return value of <code>A.compareTo(B)</code>
0172: * if A or B is Byte,Short,Character,Integer,Long
0173: * coerce both A and B to Long
0174: * apply operator
0175: * if A or B is String
0176: * coerce both A and B to String, compare lexically
0177: * if A is Comparable
0178: * if A.compareTo (B) throws exception
0179: * error
0180: * otherwise
0181: * use result of A.compareTo(B)
0182: * if B is Comparable
0183: * if B.compareTo (A) throws exception
0184: * error
0185: * otherwise
0186: * use result of B.compareTo(A)
0187: * otherwise
0188: * error
0189: *
0190: * Applying equality operator
0191: * A {==,!=} B
0192: * if A==B
0193: * apply operator
0194: * if A or B is null
0195: * return false for ==, true for !=
0196: * if A or B is BigDecimal, coerce both A and B to BigDecimal and then:
0197: * if operator is == or eq, return <code>A.equals(B)</code>
0198: * if operator is != or ne, return <code>!A.equals(B)</code>
0199: * if A or B is Float or Double
0200: * coerce both A and B to Double
0201: * apply operator
0202: * if A or B is BigInteger, coerce both A and B to BigInteger and then:
0203: * if operator is == or eq, return <code>A.equals(B)</code>
0204: * if operator is != or ne, return <code>!A.equals(B)</code>
0205: * if A or B is Byte,Short,Character,Integer,Long
0206: * coerce both A and B to Long
0207: * apply operator
0208: * if A or B is Boolean
0209: * coerce both A and B to Boolean
0210: * apply operator
0211: * if A or B is String
0212: * coerce both A and B to String, compare lexically
0213: * otherwise
0214: * if an error occurs while calling A.equals(B)
0215: * error
0216: * apply operator to result of A.equals(B)
0217: *
0218: * coercions
0219: *
0220: * coerce A to String
0221: * A is String
0222: * return A
0223: * A is null
0224: * return ""
0225: * A.toString throws exception
0226: * error
0227: * otherwise
0228: * return A.toString
0229: *
0230: * coerce A to Number type N
0231: * A is null or ""
0232: * return 0
0233: * A is Character
0234: * convert to short, apply following rules
0235: * A is Boolean
0236: * error
0237: * A is Number type N
0238: * return A
0239: * A is Number, coerce quietly to type N using the following algorithm
0240: * If N is BigInteger
0241: * If A is BigDecimal, return <code>A.toBigInteger()</code>
0242: * Otherwise, return <code>BigInteger.valueOf(A.longValue())</code>
0243: * if N is BigDecimal
0244: * If A is a BigInteger, return <code>new BigDecimal(A)</code>
0245: * Otherwise, return <code>new BigDecimal(A.doubleValue())</code>
0246: * If N is Byte, return <code>new Byte(A.byteValue())</code>
0247: * If N is Short, return <code>new Short(A.shortValue())</code>
0248: * If N is Integer, return <code>new Integer(A.integerValue())</code>
0249: * If N is Long, return <code>new Long(A.longValue())</code>
0250: * If N is Float, return <code>new Float(A.floatValue())</code>
0251: * If N is Double, return <code>new Double(A.doubleValue())</code>
0252: * otherwise ERROR
0253: * A is String
0254: * If N is BigDecimal then:
0255: * If <code>new BigDecimal(A)</code> throws an exception then ERROR
0256: * Otherwise, return <code>new BigDecimal(A)</code>
0257: * If N is BigInteger then:
0258: * If <code>new BigInteger(A)</code> throws an exception, then ERROR
0259: * Otherwise, return <code>new BigInteger(A)</code>
0260: * new <code>N.valueOf(A)</code> throws exception
0261: * error
0262: * return <code>N.valueOf(A)</code>
0263: * otherwise
0264: * error
0265: *
0266: * coerce A to Character should be
0267: * A is null or ""
0268: * return (char) 0
0269: * A is Character
0270: * return A
0271: * A is Boolean
0272: * error
0273: * A is Number with less precision than short
0274: * coerce quietly - return (char) A
0275: * A is Number with greater precision than short
0276: * coerce quietly - return (char) A
0277: * A is String
0278: * return A.charAt (0)
0279: * otherwise
0280: * error
0281: *
0282: * coerce A to Boolean
0283: * A is null or ""
0284: * return false
0285: * A is Boolean
0286: * return A
0287: * A is String
0288: * Boolean.valueOf(A) throws exception
0289: * error
0290: * return Boolean.valueOf(A)
0291: * otherwise
0292: * error
0293: *
0294: * coerce A to any other type T
0295: * A is null
0296: * return null
0297: * A is assignable to T
0298: * coerce quietly
0299: * A is String
0300: * T has no PropertyEditor
0301: * if A is "", return null
0302: * otherwise error
0303: * T's PropertyEditor throws exception
0304: * if A is "", return null
0305: * otherwise error
0306: * otherwise
0307: * apply T's PropertyEditor
0308: * otherwise
0309: * error
0310: * </pre></ul>
0311: *
0312: * @author Nathan Abramson - Art Technology Group
0313: * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author$
0314: **/
0315:
0316: public class Coercions {
0317: private static final Number ZERO = new Integer(0);
0318:
0319: //-------------------------------------
0320: /**
0321: *
0322: * Coerces the given value to the specified class.
0323: **/
0324: public static Object coerce(Object pValue, Class pClass,
0325: Logger pLogger) throws ELException {
0326: if (pClass == String.class) {
0327: return coerceToString(pValue, pLogger);
0328: } else if (isNumberClass(pClass)) {
0329: return coerceToPrimitiveNumber(pValue, pClass, pLogger);
0330: } else if (pClass == Character.class
0331: || pClass == Character.TYPE) {
0332: return coerceToCharacter(pValue, pLogger);
0333: } else if (pClass == Boolean.class || pClass == Boolean.TYPE) {
0334: return coerceToBoolean(pValue, pLogger);
0335: } else {
0336: return coerceToObject(pValue, pClass, pLogger);
0337: }
0338: }
0339:
0340: //-------------------------------------
0341: /**
0342: *
0343: * Returns true if the given class is Byte, Short, Integer, Long,
0344: * Float, Double, BigInteger, or BigDecimal
0345: **/
0346: static boolean isNumberClass(Class pClass) {
0347: return pClass == Byte.class || pClass == Byte.TYPE
0348: || pClass == Short.class || pClass == Short.TYPE
0349: || pClass == Integer.class || pClass == Integer.TYPE
0350: || pClass == Long.class || pClass == Long.TYPE
0351: || pClass == Float.class || pClass == Float.TYPE
0352: || pClass == Double.class || pClass == Double.TYPE
0353: || pClass == BigInteger.class
0354: || pClass == BigDecimal.class;
0355: }
0356:
0357: //-------------------------------------
0358: /**
0359: *
0360: * Coerces the specified value to a String
0361: **/
0362: public static String coerceToString(Object pValue, Logger pLogger)
0363: throws ELException {
0364: if (pValue == null) {
0365: return "";
0366: } else if (pValue instanceof String) {
0367: return (String) pValue;
0368: } else {
0369: try {
0370: return pValue.toString();
0371: } catch (Exception exc) {
0372: if (pLogger.isLoggingError()) {
0373: pLogger.logError(Constants.TOSTRING_EXCEPTION, exc,
0374: pValue.getClass().getName());
0375: }
0376: return "";
0377: }
0378: }
0379: }
0380:
0381: //-------------------------------------
0382: /**
0383: *
0384: * Coerces a value to the given primitive number class
0385: **/
0386: public static Number coerceToPrimitiveNumber(Object pValue,
0387: Class pClass, Logger pLogger) throws ELException {
0388: if (pValue == null || "".equals(pValue)) {
0389: return coerceToPrimitiveNumber(ZERO, pClass);
0390: } else if (pValue instanceof Character) {
0391: char val = ((Character) pValue).charValue();
0392: return coerceToPrimitiveNumber(new Short((short) val),
0393: pClass);
0394: } else if (pValue instanceof Boolean) {
0395: if (pLogger.isLoggingError()) {
0396: pLogger.logError(Constants.BOOLEAN_TO_NUMBER, pValue,
0397: pClass.getName());
0398: }
0399: return coerceToPrimitiveNumber(ZERO, pClass);
0400: } else if (pValue.getClass() == pClass) {
0401: return (Number) pValue;
0402: } else if (pValue instanceof Number) {
0403: return coerceToPrimitiveNumber((Number) pValue, pClass);
0404: } else if (pValue instanceof String) {
0405: try {
0406: return coerceToPrimitiveNumber((String) pValue, pClass);
0407: } catch (Exception exc) {
0408: if (pLogger.isLoggingError()) {
0409: pLogger.logError(
0410: Constants.STRING_TO_NUMBER_EXCEPTION,
0411: (String) pValue, pClass.getName());
0412: }
0413: return coerceToPrimitiveNumber(ZERO, pClass);
0414: }
0415: } else {
0416: if (pLogger.isLoggingError()) {
0417: pLogger.logError(Constants.COERCE_TO_NUMBER, pValue
0418: .getClass().getName(), pClass.getName());
0419: }
0420: return coerceToPrimitiveNumber(0, pClass);
0421: }
0422: }
0423:
0424: //-------------------------------------
0425: /**
0426: *
0427: * Coerces a value to an Integer, returning null if the coercion
0428: * isn't possible.
0429: **/
0430: public static Integer coerceToInteger(Object pValue, Logger pLogger)
0431: throws ELException {
0432: if (pValue == null) {
0433: return null;
0434: } else if (pValue instanceof Character) {
0435: return PrimitiveObjects
0436: .getInteger((int) (((Character) pValue).charValue()));
0437: } else if (pValue instanceof Boolean) {
0438: if (pLogger.isLoggingWarning()) {
0439: pLogger.logWarning(Constants.BOOLEAN_TO_NUMBER, pValue,
0440: Integer.class.getName());
0441: }
0442: return PrimitiveObjects.getInteger(((Boolean) pValue)
0443: .booleanValue() ? 1 : 0);
0444: } else if (pValue instanceof Integer) {
0445: return (Integer) pValue;
0446: } else if (pValue instanceof Number) {
0447: return PrimitiveObjects.getInteger(((Number) pValue)
0448: .intValue());
0449: } else if (pValue instanceof String) {
0450: try {
0451: return Integer.valueOf((String) pValue);
0452: } catch (Exception exc) {
0453: if (pLogger.isLoggingWarning()) {
0454: pLogger.logWarning(
0455: Constants.STRING_TO_NUMBER_EXCEPTION,
0456: (String) pValue, Integer.class.getName());
0457: }
0458: return null;
0459: }
0460: } else {
0461: if (pLogger.isLoggingWarning()) {
0462: pLogger.logWarning(Constants.COERCE_TO_NUMBER, pValue
0463: .getClass().getName(), Integer.class.getName());
0464: }
0465: return null;
0466: }
0467: }
0468:
0469: //-------------------------------------
0470: /**
0471: *
0472: * Coerces a long to the given primitive number class
0473: **/
0474: static Number coerceToPrimitiveNumber(long pValue, Class pClass)
0475: throws ELException {
0476: if (pClass == Byte.class || pClass == Byte.TYPE) {
0477: return PrimitiveObjects.getByte((byte) pValue);
0478: } else if (pClass == Short.class || pClass == Short.TYPE) {
0479: return PrimitiveObjects.getShort((short) pValue);
0480: } else if (pClass == Integer.class || pClass == Integer.TYPE) {
0481: return PrimitiveObjects.getInteger((int) pValue);
0482: } else if (pClass == Long.class || pClass == Long.TYPE) {
0483: return PrimitiveObjects.getLong(pValue);
0484: } else if (pClass == Float.class || pClass == Float.TYPE) {
0485: return PrimitiveObjects.getFloat((float) pValue);
0486: } else if (pClass == Double.class || pClass == Double.TYPE) {
0487: return PrimitiveObjects.getDouble((double) pValue);
0488: } else {
0489: return PrimitiveObjects.getInteger(0);
0490: }
0491: }
0492:
0493: //-------------------------------------
0494: /**
0495: *
0496: * Coerces a double to the given primitive number class
0497: **/
0498: static Number coerceToPrimitiveNumber(double pValue, Class pClass)
0499: throws ELException {
0500: if (pClass == Byte.class || pClass == Byte.TYPE) {
0501: return PrimitiveObjects.getByte((byte) pValue);
0502: } else if (pClass == Short.class || pClass == Short.TYPE) {
0503: return PrimitiveObjects.getShort((short) pValue);
0504: } else if (pClass == Integer.class || pClass == Integer.TYPE) {
0505: return PrimitiveObjects.getInteger((int) pValue);
0506: } else if (pClass == Long.class || pClass == Long.TYPE) {
0507: return PrimitiveObjects.getLong((long) pValue);
0508: } else if (pClass == Float.class || pClass == Float.TYPE) {
0509: return PrimitiveObjects.getFloat((float) pValue);
0510: } else if (pClass == Double.class || pClass == Double.TYPE) {
0511: return PrimitiveObjects.getDouble(pValue);
0512: } else {
0513: return PrimitiveObjects.getInteger(0);
0514: }
0515: }
0516:
0517: //-------------------------------------
0518: /**
0519: *
0520: * Coerces a Number to the given primitive number class
0521: **/
0522: static Number coerceToPrimitiveNumber(Number pValue, Class pClass)
0523: throws ELException {
0524: if (pClass == Byte.class || pClass == Byte.TYPE) {
0525: return PrimitiveObjects.getByte(pValue.byteValue());
0526: } else if (pClass == Short.class || pClass == Short.TYPE) {
0527: return PrimitiveObjects.getShort(pValue.shortValue());
0528: } else if (pClass == Integer.class || pClass == Integer.TYPE) {
0529: return PrimitiveObjects.getInteger(pValue.intValue());
0530: } else if (pClass == Long.class || pClass == Long.TYPE) {
0531: return PrimitiveObjects.getLong(pValue.longValue());
0532: } else if (pClass == Float.class || pClass == Float.TYPE) {
0533: return PrimitiveObjects.getFloat(pValue.floatValue());
0534: } else if (pClass == Double.class || pClass == Double.TYPE) {
0535: return PrimitiveObjects.getDouble(pValue.doubleValue());
0536: } else if (pClass == BigInteger.class) {
0537: if (pValue instanceof BigDecimal)
0538: return ((BigDecimal) pValue).toBigInteger();
0539: else
0540: return BigInteger.valueOf(pValue.longValue());
0541: } else if (pClass == BigDecimal.class) {
0542: if (pValue instanceof BigInteger)
0543: return new BigDecimal((BigInteger) pValue);
0544: else
0545: return new BigDecimal(pValue.doubleValue());
0546: } else {
0547: return PrimitiveObjects.getInteger(0);
0548: }
0549: }
0550:
0551: //-------------------------------------
0552: /**
0553: *
0554: * Coerces a String to the given primitive number class
0555: **/
0556: static Number coerceToPrimitiveNumber(String pValue, Class pClass)
0557: throws ELException {
0558: if (pClass == Byte.class || pClass == Byte.TYPE) {
0559: return Byte.valueOf(pValue);
0560: } else if (pClass == Short.class || pClass == Short.TYPE) {
0561: return Short.valueOf(pValue);
0562: } else if (pClass == Integer.class || pClass == Integer.TYPE) {
0563: return Integer.valueOf(pValue);
0564: } else if (pClass == Long.class || pClass == Long.TYPE) {
0565: return Long.valueOf(pValue);
0566: } else if (pClass == Float.class || pClass == Float.TYPE) {
0567: return Float.valueOf(pValue);
0568: } else if (pClass == Double.class || pClass == Double.TYPE) {
0569: return Double.valueOf(pValue);
0570: } else if (pClass == BigInteger.class) {
0571: return new BigInteger(pValue);
0572: } else if (pClass == BigDecimal.class) {
0573: return new BigDecimal(pValue);
0574: } else {
0575: return PrimitiveObjects.getInteger(0);
0576: }
0577: }
0578:
0579: //-------------------------------------
0580: /**
0581: *
0582: * Coerces a value to a Character
0583: **/
0584: public static Character coerceToCharacter(Object pValue,
0585: Logger pLogger) throws ELException {
0586: if (pValue == null || "".equals(pValue)) {
0587: return PrimitiveObjects.getCharacter((char) 0);
0588: } else if (pValue instanceof Character) {
0589: return (Character) pValue;
0590: } else if (pValue instanceof Boolean) {
0591: if (pLogger.isLoggingError()) {
0592: pLogger
0593: .logError(Constants.BOOLEAN_TO_CHARACTER,
0594: pValue);
0595: }
0596: return PrimitiveObjects.getCharacter((char) 0);
0597: } else if (pValue instanceof Number) {
0598: return PrimitiveObjects
0599: .getCharacter((char) ((Number) pValue).shortValue());
0600: } else if (pValue instanceof String) {
0601: String str = (String) pValue;
0602: return PrimitiveObjects.getCharacter(str.charAt(0));
0603: } else {
0604: if (pLogger.isLoggingError()) {
0605: pLogger.logError(Constants.COERCE_TO_CHARACTER, pValue
0606: .getClass().getName());
0607: }
0608: return PrimitiveObjects.getCharacter((char) 0);
0609: }
0610: }
0611:
0612: //-------------------------------------
0613: /**
0614: *
0615: * Coerces a value to a Boolean
0616: **/
0617: public static Boolean coerceToBoolean(Object pValue, Logger pLogger)
0618: throws ELException {
0619: if (pValue == null || "".equals(pValue)) {
0620: return Boolean.FALSE;
0621: } else if (pValue instanceof Boolean) {
0622: return (Boolean) pValue;
0623: } else if (pValue instanceof String) {
0624: String str = (String) pValue;
0625: try {
0626: return Boolean.valueOf(str);
0627: } catch (Exception exc) {
0628: if (pLogger.isLoggingError()) {
0629: pLogger.logError(Constants.STRING_TO_BOOLEAN, exc,
0630: (String) pValue);
0631: }
0632: return Boolean.FALSE;
0633: }
0634: } else {
0635: if (pLogger.isLoggingError()) {
0636: pLogger.logError(Constants.COERCE_TO_BOOLEAN, pValue
0637: .getClass().getName());
0638: }
0639: return Boolean.TRUE;
0640: }
0641: }
0642:
0643: //-------------------------------------
0644: /**
0645: *
0646: * Coerces a value to the specified Class that is not covered by any
0647: * of the above cases
0648: **/
0649: public static Object coerceToObject(Object pValue, Class pClass,
0650: Logger pLogger) throws ELException {
0651: if (pValue == null) {
0652: return null;
0653: } else if (pClass.isAssignableFrom(pValue.getClass())) {
0654: return pValue;
0655: } else if (pValue instanceof String) {
0656: String str = (String) pValue;
0657: PropertyEditor pe = PropertyEditorManager
0658: .findEditor(pClass);
0659: if (pe == null) {
0660: if ("".equals(str)) {
0661: return null;
0662: } else {
0663: if (pLogger.isLoggingError()) {
0664: pLogger.logError(Constants.NO_PROPERTY_EDITOR,
0665: str, pClass.getName());
0666: }
0667: return null;
0668: }
0669: }
0670: try {
0671: pe.setAsText(str);
0672: return pe.getValue();
0673: } catch (IllegalArgumentException exc) {
0674: if ("".equals(str)) {
0675: return null;
0676: } else {
0677: if (pLogger.isLoggingError()) {
0678: pLogger.logError(
0679: Constants.PROPERTY_EDITOR_ERROR, exc,
0680: pValue, pClass.getName());
0681: }
0682: return null;
0683: }
0684: }
0685: } else {
0686: if (pLogger.isLoggingError()) {
0687: pLogger.logError(Constants.COERCE_TO_OBJECT, pValue
0688: .getClass().getName(), pClass.getName());
0689: }
0690: return null;
0691: }
0692: }
0693:
0694: //-------------------------------------
0695: // Applying operators
0696: //-------------------------------------
0697: /**
0698: *
0699: * Performs all of the necessary type conversions, then calls on the
0700: * appropriate operator.
0701: **/
0702: public static Object applyArithmeticOperator(Object pLeft,
0703: Object pRight, ArithmeticOperator pOperator, Logger pLogger)
0704: throws ELException {
0705: if (pLeft == null && pRight == null) {
0706: if (pLogger.isLoggingWarning()) {
0707: pLogger.logWarning(Constants.ARITH_OP_NULL, pOperator
0708: .getOperatorSymbol());
0709: }
0710: return PrimitiveObjects.getInteger(0);
0711: }
0712:
0713: else if (isBigDecimal(pLeft) || isBigDecimal(pRight)) {
0714: BigDecimal left = (BigDecimal) coerceToPrimitiveNumber(
0715: pLeft, BigDecimal.class, pLogger);
0716: BigDecimal right = (BigDecimal) coerceToPrimitiveNumber(
0717: pRight, BigDecimal.class, pLogger);
0718: return pOperator.apply(left, right);
0719: }
0720:
0721: else if (isFloatingPointType(pLeft)
0722: || isFloatingPointType(pRight)
0723: || isFloatingPointString(pLeft)
0724: || isFloatingPointString(pRight)) {
0725: if (isBigInteger(pLeft) || isBigInteger(pRight)) {
0726: BigDecimal left = (BigDecimal) coerceToPrimitiveNumber(
0727: pLeft, BigDecimal.class, pLogger);
0728: BigDecimal right = (BigDecimal) coerceToPrimitiveNumber(
0729: pRight, BigDecimal.class, pLogger);
0730: return pOperator.apply(left, right);
0731: } else {
0732: double left = coerceToPrimitiveNumber(pLeft,
0733: Double.class, pLogger).doubleValue();
0734: double right = coerceToPrimitiveNumber(pRight,
0735: Double.class, pLogger).doubleValue();
0736: return PrimitiveObjects.getDouble(pOperator.apply(left,
0737: right));
0738: }
0739: }
0740:
0741: else if (isBigInteger(pLeft) || isBigInteger(pRight)) {
0742: BigInteger left = (BigInteger) coerceToPrimitiveNumber(
0743: pLeft, BigInteger.class, pLogger);
0744: BigInteger right = (BigInteger) coerceToPrimitiveNumber(
0745: pRight, BigInteger.class, pLogger);
0746: return pOperator.apply(left, right);
0747: }
0748:
0749: else {
0750: long left = coerceToPrimitiveNumber(pLeft, Long.class,
0751: pLogger).longValue();
0752: long right = coerceToPrimitiveNumber(pRight, Long.class,
0753: pLogger).longValue();
0754: return PrimitiveObjects.getLong(pOperator
0755: .apply(left, right));
0756: }
0757: }
0758:
0759: //-------------------------------------
0760: /**
0761: *
0762: * Performs all of the necessary type conversions, then calls on the
0763: * appropriate operator.
0764: **/
0765: public static Object applyRelationalOperator(Object pLeft,
0766: Object pRight, RelationalOperator pOperator, Logger pLogger)
0767: throws ELException {
0768: if (isBigDecimal(pLeft) || isBigDecimal(pRight)) {
0769: BigDecimal left = (BigDecimal) coerceToPrimitiveNumber(
0770: pLeft, BigDecimal.class, pLogger);
0771: BigDecimal right = (BigDecimal) coerceToPrimitiveNumber(
0772: pRight, BigDecimal.class, pLogger);
0773: return PrimitiveObjects.getBoolean(pOperator.apply(left,
0774: right));
0775: }
0776:
0777: else if (isFloatingPointType(pLeft)
0778: || isFloatingPointType(pRight)) {
0779: double left = coerceToPrimitiveNumber(pLeft, Double.class,
0780: pLogger).doubleValue();
0781: double right = coerceToPrimitiveNumber(pRight,
0782: Double.class, pLogger).doubleValue();
0783: return PrimitiveObjects.getBoolean(pOperator.apply(left,
0784: right));
0785: }
0786:
0787: else if (isBigInteger(pLeft) || isBigInteger(pRight)) {
0788: BigInteger left = (BigInteger) coerceToPrimitiveNumber(
0789: pLeft, BigInteger.class, pLogger);
0790: BigInteger right = (BigInteger) coerceToPrimitiveNumber(
0791: pRight, BigInteger.class, pLogger);
0792: return PrimitiveObjects.getBoolean(pOperator.apply(left,
0793: right));
0794: }
0795:
0796: else if (isIntegerType(pLeft) || isIntegerType(pRight)) {
0797: long left = coerceToPrimitiveNumber(pLeft, Long.class,
0798: pLogger).longValue();
0799: long right = coerceToPrimitiveNumber(pRight, Long.class,
0800: pLogger).longValue();
0801: return PrimitiveObjects.getBoolean(pOperator.apply(left,
0802: right));
0803: }
0804:
0805: else if (pLeft instanceof String || pRight instanceof String) {
0806: String left = coerceToString(pLeft, pLogger);
0807: String right = coerceToString(pRight, pLogger);
0808: return PrimitiveObjects.getBoolean(pOperator.apply(left,
0809: right));
0810: }
0811:
0812: else if (pLeft instanceof Comparable) {
0813: try {
0814: int result = ((Comparable) pLeft).compareTo(pRight);
0815: return PrimitiveObjects.getBoolean(pOperator.apply(
0816: result, -result));
0817: } catch (Exception exc) {
0818: if (pLogger.isLoggingError()) {
0819: pLogger.logError(Constants.COMPARABLE_ERROR, exc,
0820: pLeft.getClass().getName(),
0821: (pRight == null) ? "null" : pRight
0822: .getClass().getName(), pOperator
0823: .getOperatorSymbol());
0824: }
0825: return Boolean.FALSE;
0826: }
0827: }
0828:
0829: else if (pRight instanceof Comparable) {
0830: try {
0831: int result = ((Comparable) pRight).compareTo(pLeft);
0832: return PrimitiveObjects.getBoolean(pOperator.apply(
0833: -result, result));
0834: } catch (Exception exc) {
0835: if (pLogger.isLoggingError()) {
0836: pLogger.logError(Constants.COMPARABLE_ERROR, exc,
0837: pRight.getClass().getName(),
0838: (pLeft == null) ? "null" : pLeft.getClass()
0839: .getName(), pOperator
0840: .getOperatorSymbol());
0841: }
0842: return Boolean.FALSE;
0843: }
0844: }
0845:
0846: else {
0847: if (pLogger.isLoggingError()) {
0848: pLogger.logError(Constants.ARITH_OP_BAD_TYPE, pOperator
0849: .getOperatorSymbol(), pLeft.getClass()
0850: .getName(), pRight.getClass().getName());
0851: }
0852: return Boolean.FALSE;
0853: }
0854: }
0855:
0856: //-------------------------------------
0857: /**
0858: *
0859: * Performs all of the necessary type conversions, then calls on the
0860: * appropriate operator.
0861: **/
0862: public static Object applyEqualityOperator(Object pLeft,
0863: Object pRight, EqualityOperator pOperator, Logger pLogger)
0864: throws ELException {
0865: if (pLeft == pRight) {
0866: return PrimitiveObjects.getBoolean(pOperator.apply(true,
0867: pLogger));
0868: }
0869:
0870: else if (pLeft == null || pRight == null) {
0871: return PrimitiveObjects.getBoolean(pOperator.apply(false,
0872: pLogger));
0873: }
0874:
0875: else if (isBigDecimal(pLeft) || isBigDecimal(pRight)) {
0876: BigDecimal left = (BigDecimal) coerceToPrimitiveNumber(
0877: pLeft, BigDecimal.class, pLogger);
0878: BigDecimal right = (BigDecimal) coerceToPrimitiveNumber(
0879: pRight, BigDecimal.class, pLogger);
0880: return PrimitiveObjects.getBoolean(pOperator.apply(left
0881: .equals(right), pLogger));
0882: }
0883:
0884: else if (isFloatingPointType(pLeft)
0885: || isFloatingPointType(pRight)) {
0886: double left = coerceToPrimitiveNumber(pLeft, Double.class,
0887: pLogger).doubleValue();
0888: double right = coerceToPrimitiveNumber(pRight,
0889: Double.class, pLogger).doubleValue();
0890: return PrimitiveObjects.getBoolean(pOperator.apply(
0891: left == right, pLogger));
0892: }
0893:
0894: else if (isBigInteger(pLeft) || isBigInteger(pRight)) {
0895: BigInteger left = (BigInteger) coerceToPrimitiveNumber(
0896: pLeft, BigInteger.class, pLogger);
0897: BigInteger right = (BigInteger) coerceToPrimitiveNumber(
0898: pRight, BigInteger.class, pLogger);
0899: return PrimitiveObjects.getBoolean(pOperator.apply(left
0900: .equals(right), pLogger));
0901: }
0902:
0903: else if (isIntegerType(pLeft) || isIntegerType(pRight)) {
0904: long left = coerceToPrimitiveNumber(pLeft, Long.class,
0905: pLogger).longValue();
0906: long right = coerceToPrimitiveNumber(pRight, Long.class,
0907: pLogger).longValue();
0908: return PrimitiveObjects.getBoolean(pOperator.apply(
0909: left == right, pLogger));
0910: }
0911:
0912: else if (pLeft instanceof Boolean || pRight instanceof Boolean) {
0913: boolean left = coerceToBoolean(pLeft, pLogger)
0914: .booleanValue();
0915: boolean right = coerceToBoolean(pRight, pLogger)
0916: .booleanValue();
0917: return PrimitiveObjects.getBoolean(pOperator.apply(
0918: left == right, pLogger));
0919: }
0920:
0921: else if (pLeft instanceof String || pRight instanceof String) {
0922: String left = coerceToString(pLeft, pLogger);
0923: String right = coerceToString(pRight, pLogger);
0924: return PrimitiveObjects.getBoolean(pOperator.apply(left
0925: .equals(right), pLogger));
0926: }
0927:
0928: else {
0929: try {
0930: return PrimitiveObjects.getBoolean(pOperator.apply(
0931: pLeft.equals(pRight), pLogger));
0932: } catch (Exception exc) {
0933: if (pLogger.isLoggingError()) {
0934: pLogger.logError(Constants.ERROR_IN_EQUALS, exc,
0935: pLeft.getClass().getName(), pRight
0936: .getClass().getName(), pOperator
0937: .getOperatorSymbol());
0938: }
0939: return Boolean.FALSE;
0940: }
0941: }
0942: }
0943:
0944: //-------------------------------------
0945: /**
0946: *
0947: * Returns true if the given Object is of a floating point type
0948: **/
0949: public static boolean isFloatingPointType(Object pObject) {
0950: return pObject != null
0951: && isFloatingPointType(pObject.getClass());
0952: }
0953:
0954: //-------------------------------------
0955: /**
0956: *
0957: * Returns true if the given class is of a floating point type
0958: **/
0959: public static boolean isFloatingPointType(Class pClass) {
0960: return pClass == Float.class || pClass == Float.TYPE
0961: || pClass == Double.class || pClass == Double.TYPE;
0962: }
0963:
0964: //-------------------------------------
0965: /**
0966: *
0967: * Returns true if the given string might contain a floating point
0968: * number - i.e., it contains ".", "e", or "E"
0969: **/
0970: public static boolean isFloatingPointString(Object pObject) {
0971: if (pObject instanceof String) {
0972: String str = (String) pObject;
0973: int len = str.length();
0974: for (int i = 0; i < len; i++) {
0975: char ch = str.charAt(i);
0976: if (ch == '.' || ch == 'e' || ch == 'E') {
0977: return true;
0978: }
0979: }
0980: return false;
0981: } else {
0982: return false;
0983: }
0984: }
0985:
0986: //-------------------------------------
0987: /**
0988: *
0989: * Returns true if the given Object is of an integer type
0990: **/
0991: public static boolean isIntegerType(Object pObject) {
0992: return pObject != null && isIntegerType(pObject.getClass());
0993: }
0994:
0995: //-------------------------------------
0996: /**
0997: *
0998: * Returns true if the given class is of an integer type
0999: **/
1000: public static boolean isIntegerType(Class pClass) {
1001: return pClass == Byte.class || pClass == Byte.TYPE
1002: || pClass == Short.class || pClass == Short.TYPE
1003: || pClass == Character.class
1004: || pClass == Character.TYPE || pClass == Integer.class
1005: || pClass == Integer.TYPE || pClass == Long.class
1006: || pClass == Long.TYPE;
1007: }
1008:
1009: //-------------------------------------
1010:
1011: /**
1012: * Returns true if the given object is BigInteger.
1013: * @param pObject - Object to evaluate
1014: * @return - true if the given object is BigInteger
1015: */
1016: public static boolean isBigInteger(Object pObject) {
1017: return pObject != null && pObject instanceof BigInteger;
1018: }
1019:
1020: /**
1021: * Returns true if the given object is BigDecimal.
1022: * @param pObject - Object to evaluate
1023: * @return - true if the given object is BigDecimal
1024: */
1025: public static boolean isBigDecimal(Object pObject) {
1026: return pObject != null && pObject instanceof BigDecimal;
1027: }
1028: }
|