Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/apache/commons/el/Coercions.java


1   /*
2    * The Apache Software License, Version 1.1
3    *
4    * Copyright (c) 1999 The Apache Software Foundation.  All rights 
5    * reserved.
6    *
7    * Redistribution and use in source and binary forms, with or without
8    * modification, are permitted provided that the following conditions
9    * are met:
10   *
11   * 1. Redistributions of source code must retain the above copyright
12   *    notice, this list of conditions and the following disclaimer. 
13   *
14   * 2. Redistributions in binary form must reproduce the above copyright
15   *    notice, this list of conditions and the following disclaimer in
16   *    the documentation and/or other materials provided with the
17   *    distribution.
18   *
19   * 3. The end-user documentation included with the redistribution, if
20   *    any, must include the following acknowlegement:  
21   *       "This product includes software developed by the 
22   *        Apache Software Foundation (http://www.apache.org/)."
23   *    Alternately, this acknowlegement may appear in the software itself,
24   *    if and wherever such third-party acknowlegements normally appear.
25   *
26   * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
27   *    Foundation" must not be used to endorse or promote products derived
28   *    from this software without prior written permission. For written 
29   *    permission, please contact apache@apache.org.
30   *
31   * 5. Products derived from this software may not be called "Apache"
32   *    nor may "Apache" appear in their names without prior written
33   *    permission of the Apache Group.
34   *
35   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46   * SUCH DAMAGE.
47   * ====================================================================
48   *
49   * This software consists of voluntary contributions made by many
50   * individuals on behalf of the Apache Software Foundation.  For more
51   * information on the Apache Software Foundation, please see
52   * <http://www.apache.org/>.
53   *
54   */ 
55  
56  package org.apache.commons.el;
57  
58  import java.beans.PropertyEditor;
59  import java.beans.PropertyEditorManager;
60  import java.math.BigInteger;
61  import java.math.BigDecimal;
62  import javax.servlet.jsp.el.ELException;
63  
64  /**
65   *
66   * <p>This class contains the logic for coercing data types before
67   * operators are applied to them.
68   *
69   * <p>The following is the list of rules applied for various type
70   * conversions.
71   *
72   * <ul><pre>
73   * Applying arithmetic operator
74   *   Binary operator - A {+,-,*} B
75   *     if A and B are null
76   *       return 0
77   *     if A or B is BigDecimal, coerce both to BigDecimal and then:
78   *       if operator is +, return <code>A.add(B)</code>
79   *       if operator is -, return <code>A.subtract(B)</code>
80   *       if operator is *, return <code>A.multiply(B)</code>
81   *     if A or B is Float, Double, or String containing ".", "e", or "E"
82   *       if A or B is BigInteger, coerce both A and B to BigDecimal and apply operator
83   *       coerce both A and B to Double and apply operator
84   *     if A or B is BigInteger, coerce both to BigInteger and then:
85   *       if operator is +, return <code>A.add(B)</code>
86   *       if operator is -, return <code>A.subtract(B)</code>
87   *       if operator is *, return <code>A.multiply(B)</code>
88   *     otherwise
89   *       coerce both A and B to Long
90   *       apply operator
91   *     if operator results in exception (such as divide by 0), error
92   * 
93   *   Binary operator - A {/,div} B
94   *     if A and B are null
95   *       return 0
96   *     if A or B is a BigDecimal or BigInteger, coerce both to BigDecimal and
97   *      return <code>A.divide(B, BigDecimal.ROUND_HALF_UP)</code>
98   *     otherwise
99   *       coerce both A and B to Double
100  *       apply operator
101  *     if operator results in exception (such as divide by 0), error
102  * 
103  *   Binary operator - A {%,mod} B
104  *     if A and B are null
105  *       return 0
106  *     if A or B is BigDecimal, Float, Double, or String containing ".", "e" or "E"
107  *       coerce both to Double
108  *       apply operator
109  *     if A or B is BigInteger, coerce both to BigInteger and return
110  *      <code>A.remainder(B)</code>
111  *     otherwise
112  *       coerce both A and B to Long
113  *       apply operator
114  *     if operator results in exception (such as divide by 0), error
115  * 
116  *   Unary minus operator - -A
117  *     if A is null
118  *       return 0
119  *     if A is BigInteger or BigDecimal, return <code>A.negate()</code>
120  *     if A is String
121  *       if A contains ".", "e", or "E"
122  *         coerce to Double, apply operator
123  *       otherwise
124  *         coerce to a Long and apply operator
125  *     if A is Byte,Short,Integer,Long,Float,Double
126  *       retain type, apply operator
127  *     if operator results in exception, error
128  *     otherwise
129  *       error
130  *
131  * Applying "empty" operator - empty A
132  *   if A is null
133  *     return true
134  *   if A is zero-length String
135  *     return true
136  *   if A is zero-length array
137  *     return true
138  *   if A is List and ((List) A).isEmpty()
139  *     return true
140  *   if A is Map and ((Map) A).isEmpty()
141  *     return true
142  *   if A is Collection an ((Collection) A).isEmpty()
143  *     return true
144  *   otherwise
145  *     return false
146  * 
147  * Applying logical operators
148  *   Binary operator - A {and,or} B
149  *     coerce both A and B to Boolean, apply operator
150  *   NOTE - operator stops as soon as expression can be determined, i.e.,
151  *     A and B and C and D - if B is false, then only A and B is evaluated
152  *   Unary not operator - not A
153  *     coerce A to Boolean, apply operator
154  * 
155  * Applying relational operator
156  *   A {<,>,<=,>=,lt,gt,lte,gte} B
157  *     if A==B
158  *       if operator is >= or <=
159  *         return true
160  *       otherwise
161  *         return false
162  *     if A or B is null
163  *       return false
164  *     if A or B is BigDecimal, coerce both A and B to BigDecimal and use the
165  *      return value of <code>A.compareTo(B)</code>
166  *     if A or B is Float or Double
167  *       coerce both A and B to Double
168  *       apply operator
169  *     if A or B is BigInteger, coerce both A and B to BigInteger and use the
170  *      return value of <code>A.compareTo(B)</code>
171  *     if A or B is Byte,Short,Character,Integer,Long
172  *       coerce both A and B to Long
173  *       apply operator
174  *     if A or B is String
175  *       coerce both A and B to String, compare lexically
176  *     if A is Comparable
177  *       if A.compareTo (B) throws exception
178  *         error
179  *       otherwise
180  *         use result of A.compareTo(B)
181  *     if B is Comparable
182  *       if B.compareTo (A) throws exception
183  *         error
184  *       otherwise
185  *         use result of B.compareTo(A)
186  *     otherwise
187  *       error
188  * 
189  * Applying equality operator
190  *   A {==,!=} B
191  *     if A==B
192  *       apply operator
193  *     if A or B is null
194  *       return false for ==, true for !=
195  *     if A or B is BigDecimal, coerce both A and B to BigDecimal and then:
196  *       if operator is == or eq, return <code>A.equals(B)</code>
197  *       if operator is != or ne, return <code>!A.equals(B)</code>
198  *     if A or B is Float or Double
199  *       coerce both A and B to Double
200  *       apply operator
201  *     if A or B is BigInteger, coerce both A and B to BigInteger and then:
202  *       if operator is == or eq, return <code>A.equals(B)</code>
203  *       if operator is != or ne, return <code>!A.equals(B)</code>
204  *     if A or B is Byte,Short,Character,Integer,Long
205  *       coerce both A and B to Long
206  *       apply operator
207  *     if A or B is Boolean
208  *       coerce both A and B to Boolean
209  *       apply operator
210  *     if A or B is String
211  *       coerce both A and B to String, compare lexically
212  *     otherwise
213  *       if an error occurs while calling A.equals(B)
214  *         error
215  *       apply operator to result of A.equals(B)
216  * 
217  * coercions
218  * 
219  *   coerce A to String
220  *     A is String
221  *       return A
222  *     A is null
223  *       return ""
224  *     A.toString throws exception
225  *       error
226  *     otherwise
227  *       return A.toString
228  * 
229  *   coerce A to Number type N
230  *     A is null or ""
231  *       return 0
232  *     A is Character
233  *       convert to short, apply following rules
234  *     A is Boolean
235  *       error
236  *     A is Number type N
237  *       return A
238  *     A is Number, coerce quietly to type N using the following algorithm
239  *         If N is BigInteger
240  *             If A is BigDecimal, return <code>A.toBigInteger()</code>
241  *             Otherwise, return <code>BigInteger.valueOf(A.longValue())</code>
242  *        if N is BigDecimal
243  *             If A is a BigInteger, return <code>new BigDecimal(A)</code>
244  *             Otherwise, return <code>new BigDecimal(A.doubleValue())</code>
245  *        If N is Byte, return <code>new Byte(A.byteValue())</code>
246  *        If N is Short, return <code>new Short(A.shortValue())</code>
247  *        If N is Integer, return <code>new Integer(A.integerValue())</code>
248  *        If N is Long, return <code>new Long(A.longValue())</code>
249  *        If N is Float, return <code>new Float(A.floatValue())</code>
250  *        If N is Double, return <code>new Double(A.doubleValue())</code>
251  *        otherwise ERROR
252  *     A is String
253  *       If N is BigDecimal then:
254  *            If <code>new BigDecimal(A)</code> throws an exception then ERROR
255  *            Otherwise, return <code>new BigDecimal(A)</code>
256  *       If N is BigInteger then:
257  *            If <code>new BigInteger(A)</code> throws an exception, then ERROR
258  *            Otherwise, return <code>new BigInteger(A)</code>
259  *       new <code>N.valueOf(A)</code> throws exception
260  *         error
261  *       return <code>N.valueOf(A)</code>
262  *     otherwise
263  *       error
264  * 
265  *   coerce A to Character should be
266  *     A is null or ""
267  *       return (char) 0
268  *     A is Character
269  *       return A
270  *     A is Boolean
271  *       error
272  *     A is Number with less precision than short
273  *       coerce quietly - return (char) A
274  *     A is Number with greater precision than short
275  *       coerce quietly - return (char) A
276  *     A is String
277  *       return A.charAt (0)
278  *     otherwise
279  *       error
280  * 
281  *   coerce A to Boolean
282  *     A is null or ""
283  *       return false
284  *     A is Boolean
285  *       return A
286  *     A is String
287  *       Boolean.valueOf(A) throws exception
288  *         error
289  *       return Boolean.valueOf(A)
290  *     otherwise
291  *       error
292  * 
293  *   coerce A to any other type T
294  *     A is null
295  *       return null
296  *     A is assignable to T
297  *       coerce quietly
298  *     A is String
299  *       T has no PropertyEditor
300  *         if A is "", return null
301  *         otherwise error
302  *       T's PropertyEditor throws exception
303  *         if A is "", return null
304  *         otherwise error
305  *       otherwise
306  *         apply T's PropertyEditor
307  *     otherwise
308  *       error
309  * </pre></ul>
310  *
311  * @author Nathan Abramson - Art Technology Group
312  * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: luehe $
313  **/
314 
315 public class Coercions
316 {
317    private static final Number ZERO = new Integer(0);
318   //-------------------------------------
319   /**
320    *
321    * Coerces the given value to the specified class.
322    **/
323   public static Object coerce (Object pValue,
324              Class pClass,
325              Logger pLogger)
326     throws ELException
327   {
328     if (pClass == String.class) {
329       return coerceToString (pValue, pLogger);
330     }
331     else if (isNumberClass (pClass)) {
332       return coerceToPrimitiveNumber (pValue, pClass, pLogger);
333     }
334     else if (pClass == Character.class ||
335        pClass == Character.TYPE) {
336       return coerceToCharacter (pValue, pLogger);
337     }
338     else if (pClass == Boolean.class ||
339        pClass == Boolean.TYPE) {
340       return coerceToBoolean (pValue, pLogger);
341     }
342     else {
343       return coerceToObject (pValue, pClass, pLogger);
344     }
345   }
346 
347   //-------------------------------------
348   /**
349    *
350    * Returns true if the given class is Byte, Short, Integer, Long,
351    * Float, Double, BigInteger, or BigDecimal
352    **/
353   static boolean isNumberClass (Class pClass)
354   {
355     return
356       pClass == Byte.class ||
357       pClass == Byte.TYPE ||
358       pClass == Short.class ||
359       pClass == Short.TYPE ||
360       pClass == Integer.class ||
361       pClass == Integer.TYPE ||
362       pClass == Long.class ||
363       pClass == Long.TYPE ||
364       pClass == Float.class ||
365       pClass == Float.TYPE ||
366       pClass == Double.class ||
367       pClass == Double.TYPE ||
368       pClass == BigInteger.class ||
369       pClass == BigDecimal.class;
370   }
371 
372   //-------------------------------------
373   /**
374    *
375    * Coerces the specified value to a String
376    **/
377   public static String coerceToString (Object pValue,
378                Logger pLogger)
379     throws ELException
380   {
381     if (pValue == null) {
382       return "";
383     }
384     else if (pValue instanceof String) {
385       return (String) pValue;
386     }
387     else {
388       try {
389   return pValue.toString ();
390       }
391       catch (Exception exc) {
392   if (pLogger.isLoggingError ()) {
393     pLogger.logError (Constants.TOSTRING_EXCEPTION,
394           exc,
395           pValue.getClass ().getName ());
396   }
397   return "";
398       }
399     }
400   }
401 
402   //-------------------------------------
403   /**
404    *
405    * Coerces a value to the given primitive number class
406    **/
407   public static Number coerceToPrimitiveNumber (Object pValue,
408             Class pClass,
409             Logger pLogger)
410     throws ELException
411   {
412     if (pValue == null ||
413   "".equals (pValue)) {
414       return coerceToPrimitiveNumber (ZERO, pClass);
415     }
416     else if (pValue instanceof Character) {
417       char val = ((Character) pValue).charValue ();
418       return coerceToPrimitiveNumber (new Short((short) val), pClass);
419     }
420     else if (pValue instanceof Boolean) {
421       if (pLogger.isLoggingError ()) {
422   pLogger.logError (Constants.BOOLEAN_TO_NUMBER,
423         pValue,
424         pClass.getName ());
425       }
426       return coerceToPrimitiveNumber (ZERO, pClass);
427     }
428     else if (pValue.getClass () == pClass) {
429       return (Number) pValue;
430     }
431     else if (pValue instanceof Number) {
432       return coerceToPrimitiveNumber ((Number) pValue, pClass);
433     }
434     else if (pValue instanceof String) {
435       try {
436   return coerceToPrimitiveNumber ((String) pValue, pClass);
437       }
438       catch (Exception exc) {
439   if (pLogger.isLoggingError ()) {
440     pLogger.logError
441       (Constants.STRING_TO_NUMBER_EXCEPTION,
442        (String) pValue,
443        pClass.getName ());
444   }
445   return coerceToPrimitiveNumber (ZERO, pClass);
446       }
447     }
448     else {
449       if (pLogger.isLoggingError ()) {
450   pLogger.logError
451     (Constants.COERCE_TO_NUMBER,
452      pValue.getClass ().getName (),
453      pClass.getName ());
454       }
455       return coerceToPrimitiveNumber (0, pClass);
456     }
457   }
458 
459   //-------------------------------------
460   /**
461    *
462    * Coerces a value to an Integer, returning null if the coercion
463    * isn't possible.
464    **/
465   public static Integer coerceToInteger (Object pValue,
466            Logger pLogger)
467     throws ELException
468   {
469     if (pValue == null) {
470       return null;
471     }
472     else if (pValue instanceof Character) {
473       return PrimitiveObjects.getInteger 
474   ((int) (((Character) pValue).charValue ()));
475     }
476     else if (pValue instanceof Boolean) {
477       if (pLogger.isLoggingWarning ()) {
478   pLogger.logWarning (Constants.BOOLEAN_TO_NUMBER,
479           pValue,
480           Integer.class.getName ());
481       }
482       return PrimitiveObjects.getInteger
483   (((Boolean) pValue).booleanValue () ? 1 : 0);
484     }
485     else if (pValue instanceof Integer) {
486       return (Integer) pValue;
487     }
488     else if (pValue instanceof Number) {
489       return PrimitiveObjects.getInteger (((Number) pValue).intValue ());
490     }
491     else if (pValue instanceof String) {
492       try {
493   return Integer.valueOf ((String) pValue);
494       }
495       catch (Exception exc) {
496   if (pLogger.isLoggingWarning ()) {
497     pLogger.logWarning
498       (Constants.STRING_TO_NUMBER_EXCEPTION,
499        (String) pValue,
500        Integer.class.getName ());
501   }
502   return null;
503       }
504     }
505     else {
506       if (pLogger.isLoggingWarning ()) {
507   pLogger.logWarning
508     (Constants.COERCE_TO_NUMBER,
509      pValue.getClass ().getName (),
510      Integer.class.getName ());
511       }
512       return null;
513     }
514   }
515 
516   //-------------------------------------
517   /**
518    *
519    * Coerces a long to the given primitive number class
520    **/
521   static Number coerceToPrimitiveNumber (long pValue,
522            Class pClass)
523     throws ELException
524   {
525     if (pClass == Byte.class || pClass == Byte.TYPE) {
526       return PrimitiveObjects.getByte ((byte) pValue);
527     }
528     else if (pClass == Short.class || pClass == Short.TYPE) {
529       return PrimitiveObjects.getShort ((short) pValue);
530     }
531     else if (pClass == Integer.class || pClass == Integer.TYPE) {
532       return PrimitiveObjects.getInteger ((int) pValue);
533     }
534     else if (pClass == Long.class || pClass == Long.TYPE) {
535       return PrimitiveObjects.getLong (pValue);
536     }
537     else if (pClass == Float.class || pClass == Float.TYPE) {
538       return PrimitiveObjects.getFloat ((float) pValue);
539     }
540     else if (pClass == Double.class || pClass == Double.TYPE) {
541       return PrimitiveObjects.getDouble ((double) pValue);
542     }
543     else {
544       return PrimitiveObjects.getInteger (0);
545     }
546   }
547 
548   //-------------------------------------
549   /**
550    *
551    * Coerces a double to the given primitive number class
552    **/
553   static Number coerceToPrimitiveNumber (double pValue,
554            Class pClass)
555     throws ELException
556   {
557     if (pClass == Byte.class || pClass == Byte.TYPE) {
558       return PrimitiveObjects.getByte ((byte) pValue);
559     }
560     else if (pClass == Short.class || pClass == Short.TYPE) {
561       return PrimitiveObjects.getShort ((short) pValue);
562     }
563     else if (pClass == Integer.class || pClass == Integer.TYPE) {
564       return PrimitiveObjects.getInteger ((int) pValue);
565     }
566     else if (pClass == Long.class || pClass == Long.TYPE) {
567       return PrimitiveObjects.getLong ((long) pValue);
568     }
569     else if (pClass == Float.class || pClass == Float.TYPE) {
570       return PrimitiveObjects.getFloat ((float) pValue);
571     }
572     else if (pClass == Double.class || pClass == Double.TYPE) {
573       return PrimitiveObjects.getDouble (pValue);
574     }
575     else {
576       return PrimitiveObjects.getInteger (0);
577     }
578   }
579 
580   //-------------------------------------
581   /**
582    *
583    * Coerces a Number to the given primitive number class
584    **/
585   static Number coerceToPrimitiveNumber (Number pValue,
586            Class pClass)
587     throws ELException
588   {
589     if (pClass == Byte.class || pClass == Byte.TYPE) {
590       return PrimitiveObjects.getByte (pValue.byteValue ());
591     }
592     else if (pClass == Short.class || pClass == Short.TYPE) {
593       return PrimitiveObjects.getShort (pValue.shortValue ());
594     }
595     else if (pClass == Integer.class || pClass == Integer.TYPE) {
596       return PrimitiveObjects.getInteger (pValue.intValue ());
597     }
598     else if (pClass == Long.class || pClass == Long.TYPE) {
599       return PrimitiveObjects.getLong (pValue.longValue ());
600     }
601     else if (pClass == Float.class || pClass == Float.TYPE) {
602       return PrimitiveObjects.getFloat (pValue.floatValue ());
603     }
604     else if (pClass == Double.class || pClass == Double.TYPE) {
605       return PrimitiveObjects.getDouble (pValue.doubleValue ());
606     }
607     else if (pClass == BigInteger.class) {
608         if (pValue instanceof BigDecimal)
609             return ((BigDecimal) pValue).toBigInteger();
610         else
611             return BigInteger.valueOf(pValue.longValue());
612     }
613     else if (pClass == BigDecimal.class) {
614         if (pValue instanceof BigInteger)
615             return new BigDecimal((BigInteger) pValue);
616         else
617             return new BigDecimal(pValue.doubleValue());
618     }
619     else {
620       return PrimitiveObjects.getInteger (0);
621     }
622   }
623 
624   //-------------------------------------
625   /**
626    *
627    * Coerces a String to the given primitive number class
628    **/
629   static Number coerceToPrimitiveNumber (String pValue,
630            Class pClass)
631     throws ELException
632   {
633     if (pClass == Byte.class || pClass == Byte.TYPE) {
634       return Byte.valueOf (pValue);
635     }
636     else if (pClass == Short.class || pClass == Short.TYPE) {
637       return Short.valueOf (pValue);
638     }
639     else if (pClass == Integer.class || pClass == Integer.TYPE) {
640       return Integer.valueOf (pValue);
641     }
642     else if (pClass == Long.class || pClass == Long.TYPE) {
643       return Long.valueOf (pValue);
644     }
645     else if (pClass == Float.class || pClass == Float.TYPE) {
646       return Float.valueOf (pValue);
647     }
648     else if (pClass == Double.class || pClass == Double.TYPE) {
649       return Double.valueOf (pValue);
650     }
651     else if (pClass == BigInteger.class) {
652         return new BigInteger(pValue);
653     }
654     else if (pClass == BigDecimal.class) {
655         return new BigDecimal(pValue);
656     }
657     else {
658       return PrimitiveObjects.getInteger (0);
659     }
660   }
661 
662   //-------------------------------------
663   /**
664    *
665    * Coerces a value to a Character
666    **/
667   public static Character coerceToCharacter (Object pValue,
668                Logger pLogger)
669     throws ELException
670   {
671     if (pValue == null ||
672   "".equals (pValue)) {
673       return PrimitiveObjects.getCharacter ((char) 0);
674     }
675     else if (pValue instanceof Character) {
676       return (Character) pValue;
677     }
678     else if (pValue instanceof Boolean) {
679       if (pLogger.isLoggingError ()) {
680   pLogger.logError (Constants.BOOLEAN_TO_CHARACTER, pValue);
681       }
682       return PrimitiveObjects.getCharacter ((char) 0);
683     }
684     else if (pValue instanceof Number) {
685       return PrimitiveObjects.getCharacter 
686   ((char) ((Number) pValue).shortValue ());
687     }
688     else if (pValue instanceof String) {
689       String str = (String) pValue;
690       return PrimitiveObjects.getCharacter (str.charAt (0));
691     }
692     else {
693       if (pLogger.isLoggingError ()) {
694   pLogger.logError
695     (Constants.COERCE_TO_CHARACTER,
696      pValue.getClass ().getName ());
697       }
698       return PrimitiveObjects.getCharacter ((char) 0);
699     }
700   }
701 
702   //-------------------------------------
703   /**
704    *
705    * Coerces a value to a Boolean
706    **/
707   public static Boolean coerceToBoolean (Object pValue,
708            Logger pLogger)
709     throws ELException
710   {
711     if (pValue == null ||
712   "".equals (pValue)) {
713       return Boolean.FALSE;
714     }
715     else if (pValue instanceof Boolean) {
716       return (Boolean) pValue;
717     }
718     else if (pValue instanceof String) {
719       String str = (String) pValue;
720       try {
721   return Boolean.valueOf (str);
722       }
723       catch (Exception exc) {
724   if (pLogger.isLoggingError ()) {
725     pLogger.logError
726       (Constants.STRING_TO_BOOLEAN,
727        exc,
728        (String) pValue);
729   }
730   return Boolean.FALSE;
731       }
732     }
733     else {
734       if (pLogger.isLoggingError ()) {
735   pLogger.logError
736     (Constants.COERCE_TO_BOOLEAN,
737      pValue.getClass ().getName ());
738       }
739       return Boolean.TRUE;
740     }
741   }
742 
743   //-------------------------------------
744   /**
745    *
746    * Coerces a value to the specified Class that is not covered by any
747    * of the above cases
748    **/
749   public static Object coerceToObject (Object pValue,
750                Class pClass,
751                Logger pLogger)
752     throws ELException
753   {
754     if (pValue == null) {
755       return null;
756     }
757     else if (pClass.isAssignableFrom (pValue.getClass ())) {
758       return pValue;
759     }
760     else if (pValue instanceof String) {
761       String str = (String) pValue;
762       PropertyEditor pe = PropertyEditorManager.findEditor (pClass);
763       if (pe == null) {
764   if ("".equals (str)) {
765     return null;
766   }
767   else {
768     if (pLogger.isLoggingError ()) {
769       pLogger.logError
770         (Constants.NO_PROPERTY_EDITOR,
771          str,
772          pClass.getName ());
773     }
774     return null;
775   }
776       }
777       try {
778   pe.setAsText (str);
779   return pe.getValue ();
780       }
781       catch (IllegalArgumentException exc) {
782   if ("".equals (str)) {
783     return null;
784   }
785   else {
786     if (pLogger.isLoggingError ()) {
787       pLogger.logError
788         (Constants.PROPERTY_EDITOR_ERROR,
789          exc,
790          pValue,
791          pClass.getName ());
792     }
793     return null;
794   }
795       }
796     }
797     else {
798       if (pLogger.isLoggingError ()) {
799   pLogger.logError
800     (Constants.COERCE_TO_OBJECT,
801      pValue.getClass ().getName (),
802      pClass.getName ());
803       }
804       return null;
805     }
806   }
807 
808   //-------------------------------------
809   // Applying operators
810   //-------------------------------------
811   /**
812    *
813    * Performs all of the necessary type conversions, then calls on the
814    * appropriate operator.
815    **/
816   public static Object applyArithmeticOperator 
817     (Object pLeft,
818      Object pRight,
819      ArithmeticOperator pOperator,
820      Logger pLogger)
821     throws ELException
822   {
823     if (pLeft == null &&
824   pRight == null) {
825       if (pLogger.isLoggingWarning ()) {
826   pLogger.logWarning
827     (Constants.ARITH_OP_NULL,
828      pOperator.getOperatorSymbol ());
829       }
830       return PrimitiveObjects.getInteger (0);
831     }
832 
833     else if (isBigDecimal(pLeft) || isBigDecimal(pRight)) {
834         BigDecimal left = (BigDecimal)
835             coerceToPrimitiveNumber(pLeft, BigDecimal.class, pLogger);
836         BigDecimal right = (BigDecimal)
837             coerceToPrimitiveNumber(pRight, BigDecimal.class, pLogger);
838         return pOperator.apply(left, right);
839     }
840 
841     else if (isFloatingPointType(pLeft) ||
842         isFloatingPointType(pRight) ||
843         isFloatingPointString(pLeft) ||
844         isFloatingPointString(pRight)) {
845         if (isBigInteger(pLeft) || isBigInteger(pRight)) {
846             BigDecimal left = (BigDecimal)
847                 coerceToPrimitiveNumber(pLeft, BigDecimal.class, pLogger);
848             BigDecimal right = (BigDecimal)
849                 coerceToPrimitiveNumber(pRight, BigDecimal.class, pLogger);
850             return pOperator.apply(left, right);
851         } else {
852             double left =
853                 coerceToPrimitiveNumber(pLeft, Double.class, pLogger).
854                 doubleValue();
855             double right =
856                 coerceToPrimitiveNumber(pRight, Double.class, pLogger).
857                 doubleValue();
858             return
859                 PrimitiveObjects.getDouble(pOperator.apply(left, right));
860         }
861     }
862 
863     else if (isBigInteger(pLeft) || isBigInteger(pRight)) {
864         BigInteger left = (BigInteger)
865             coerceToPrimitiveNumber(pLeft, BigInteger.class, pLogger);
866         BigInteger right = (BigInteger)
867             coerceToPrimitiveNumber(pRight, BigInteger.class, pLogger);
868         return pOperator.apply(left, right);
869     }
870 
871     else {
872       long left =
873   coerceToPrimitiveNumber (pLeft, Long.class, pLogger).
874   longValue ();
875       long right =
876   coerceToPrimitiveNumber (pRight, Long.class, pLogger).
877   longValue ();
878       return
879   PrimitiveObjects.getLong (pOperator.apply (left, right));
880     }
881   }
882 
883   //-------------------------------------
884   /**
885    *
886    * Performs all of the necessary type conversions, then calls on the
887    * appropriate operator.
888    **/
889   public static Object applyRelationalOperator 
890     (Object pLeft,
891      Object pRight,
892      RelationalOperator pOperator,
893      Logger pLogger)
894     throws ELException
895   {
896     if (isBigDecimal(pLeft) || isBigDecimal(pRight)) {
897         BigDecimal left = (BigDecimal)
898             coerceToPrimitiveNumber(pLeft, BigDecimal.class, pLogger);
899         BigDecimal right = (BigDecimal)
900             coerceToPrimitiveNumber(pRight, BigDecimal.class, pLogger);
901         return PrimitiveObjects.getBoolean(pOperator.apply(left, right));
902     }
903 
904     else if (isFloatingPointType (pLeft) ||
905   isFloatingPointType (pRight)) {
906       double left =
907   coerceToPrimitiveNumber (pLeft, Double.class, pLogger).
908   doubleValue ();
909       double right =
910   coerceToPrimitiveNumber (pRight, Double.class, pLogger).
911   doubleValue ();
912       return 
913   PrimitiveObjects.getBoolean (pOperator.apply (left, right));
914     }
915 
916     else if (isBigInteger(pLeft) || isBigInteger(pRight)) {
917         BigInteger left = (BigInteger)
918             coerceToPrimitiveNumber(pLeft, BigInteger.class, pLogger);
919         BigInteger right = (BigInteger)
920             coerceToPrimitiveNumber(pRight, BigInteger.class, pLogger);
921         return PrimitiveObjects.getBoolean(pOperator.apply(left, right));
922     }
923 
924     else if (isIntegerType (pLeft) ||
925        isIntegerType (pRight)) {
926       long left =
927   coerceToPrimitiveNumber (pLeft, Long.class, pLogger).
928   longValue ();
929       long right =
930   coerceToPrimitiveNumber (pRight, Long.class, pLogger).
931   longValue ();
932       return
933   PrimitiveObjects.getBoolean (pOperator.apply (left, right));
934     }
935 
936     else if (pLeft instanceof String ||
937        pRight instanceof String) {
938       String left = coerceToString (pLeft, pLogger);
939       String right = coerceToString (pRight, pLogger);
940       return
941   PrimitiveObjects.getBoolean (pOperator.apply (left, right));
942     }
943 
944     else if (pLeft instanceof Comparable) {
945       try {
946   int result = ((Comparable) pLeft).compareTo (pRight);
947   return
948     PrimitiveObjects.getBoolean 
949     (pOperator.apply (result, -result));
950       }
951       catch (Exception exc) {
952   if (pLogger.isLoggingError ()) {
953     pLogger.logError
954       (Constants.COMPARABLE_ERROR,
955        exc,
956        pLeft.getClass ().getName (),
957        (pRight == null) ? "null" : pRight.getClass ().getName (),
958        pOperator.getOperatorSymbol ());
959   }
960   return Boolean.FALSE;
961       }
962     }
963 
964     else if (pRight instanceof Comparable) {
965       try {
966   int result = ((Comparable) pRight).compareTo (pLeft);
967   return
968     PrimitiveObjects.getBoolean 
969     (pOperator.apply (-result, result));
970       }
971       catch (Exception exc) {
972   if (pLogger.isLoggingError ()) {
973     pLogger.logError
974       (Constants.COMPARABLE_ERROR,
975        exc,
976        pRight.getClass ().getName (),
977        (pLeft == null) ? "null" : pLeft.getClass ().getName (),
978        pOperator.getOperatorSymbol ());
979   }
980   return Boolean.FALSE;
981       }
982     }
983 
984     else {
985       if (pLogger.isLoggingError ()) {
986   pLogger.logError
987     (Constants.ARITH_OP_BAD_TYPE,
988      pOperator.getOperatorSymbol (),
989      pLeft.getClass ().getName (),
990      pRight.getClass ().getName ());
991       }
992       return Boolean.FALSE;
993     }
994   }
995 
996   //-------------------------------------
997   /**
998    *
999    * Performs all of the necessary type conversions, then calls on the
1000   * appropriate operator.
1001   **/
1002  public static Object applyEqualityOperator 
1003    (Object pLeft,
1004     Object pRight,
1005     EqualityOperator pOperator,
1006     Logger pLogger)
1007    throws ELException
1008  {
1009    if (pLeft == pRight) {
1010      return PrimitiveObjects.getBoolean (pOperator.apply (true, pLogger));
1011    }
1012
1013    else if (pLeft == null ||
1014       pRight == null) {
1015      return PrimitiveObjects.getBoolean (pOperator.apply (false, pLogger));
1016    }
1017
1018    else if (isBigDecimal(pLeft) || isBigDecimal(pRight)) {
1019        BigDecimal left = (BigDecimal)
1020            coerceToPrimitiveNumber(pLeft, BigDecimal.class, pLogger);
1021        BigDecimal right = (BigDecimal)
1022            coerceToPrimitiveNumber(pRight, BigDecimal.class, pLogger);
1023        return PrimitiveObjects.getBoolean(pOperator.apply(left.equals(right), pLogger));
1024    }
1025
1026    else if (isFloatingPointType (pLeft) ||
1027       isFloatingPointType (pRight)) {
1028      double left =
1029  coerceToPrimitiveNumber (pLeft, Double.class, pLogger).
1030  doubleValue ();
1031      double right =
1032  coerceToPrimitiveNumber (pRight, Double.class, pLogger).
1033  doubleValue ();
1034      return 
1035  PrimitiveObjects.getBoolean 
1036  (pOperator.apply (left == right, pLogger));
1037    }
1038
1039    else if (isBigInteger(pLeft) || isBigInteger(pRight)) {
1040        BigInteger left = (BigInteger)
1041            coerceToPrimitiveNumber(pLeft, BigInteger.class, pLogger);
1042        BigInteger right = (BigInteger)
1043            coerceToPrimitiveNumber(pRight, BigInteger.class, pLogger);
1044        return PrimitiveObjects.getBoolean(pOperator.apply(left.equals(right), pLogger));
1045    }
1046
1047    else if (isIntegerType (pLeft) ||
1048       isIntegerType (pRight)) {
1049      long left =
1050  coerceToPrimitiveNumber (pLeft, Long.class, pLogger).
1051  longValue ();
1052      long right =
1053  coerceToPrimitiveNumber (pRight, Long.class, pLogger).
1054  longValue ();
1055      return
1056  PrimitiveObjects.getBoolean 
1057  (pOperator.apply (left == right, pLogger));
1058    }
1059
1060    else if (pLeft instanceof Boolean ||
1061       pRight instanceof Boolean) {
1062      boolean left = coerceToBoolean (pLeft, pLogger).booleanValue ();
1063      boolean right = coerceToBoolean (pRight, pLogger).booleanValue ();
1064      return
1065  PrimitiveObjects.getBoolean 
1066  (pOperator.apply (left == right, pLogger));
1067    }
1068
1069    else if (pLeft instanceof String ||
1070       pRight instanceof String) {
1071      String left = coerceToString (pLeft, pLogger);
1072      String right = coerceToString (pRight, pLogger);
1073      return
1074  PrimitiveObjects.getBoolean 
1075  (pOperator.apply (left.equals (right), pLogger));
1076    }
1077
1078    else {
1079      try {
1080      return
1081  PrimitiveObjects.getBoolean
1082  (pOperator.apply (pLeft.equals (pRight), pLogger));
1083      }
1084      catch (Exception exc) {
1085  if (pLogger.isLoggingError ()) {
1086    pLogger.logError
1087      (Constants.ERROR_IN_EQUALS,
1088       exc,
1089       pLeft.getClass ().getName (),
1090       pRight.getClass ().getName (),
1091       pOperator.getOperatorSymbol ());
1092  }
1093  return Boolean.FALSE;
1094      }
1095    }
1096  }
1097
1098  //-------------------------------------
1099  /**
1100   *
1101   * Returns true if the given Object is of a floating point type
1102   **/
1103  public static boolean isFloatingPointType (Object pObject)
1104  {
1105    return 
1106      pObject != null &&
1107      isFloatingPointType (pObject.getClass ());
1108  }
1109
1110  //-------------------------------------
1111  /**
1112   *
1113   * Returns true if the given class is of a floating point type
1114   **/
1115  public static boolean isFloatingPointType (Class pClass)
1116  {
1117    return
1118      pClass == Float.class ||
1119      pClass == Float.TYPE ||
1120      pClass == Double.class ||
1121      pClass == Double.TYPE;
1122  }
1123
1124  //-------------------------------------
1125  /**
1126   *
1127   * Returns true if the given string might contain a floating point
1128   * number - i.e., it contains ".", "e", or "E"
1129   **/
1130  public static boolean isFloatingPointString (Object pObject)
1131  {
1132    if (pObject instanceof String) {
1133      String str = (String) pObject;
1134      int len = str.length ();
1135      for (int i = 0; i < len; i++) {
1136  char ch = str.charAt (i);
1137  if (ch == '.' ||
1138      ch == 'e' ||
1139      ch == 'E') {
1140    return true;
1141  }
1142      }
1143      return false;
1144    }
1145    else {
1146      return false;
1147    }
1148  }
1149
1150  //-------------------------------------
1151  /**
1152   *
1153   * Returns true if the given Object is of an integer type
1154   **/
1155  public static boolean isIntegerType (Object pObject)
1156  {
1157    return 
1158      pObject != null &&
1159      isIntegerType (pObject.getClass ());
1160  }
1161
1162  //-------------------------------------
1163  /**
1164   *
1165   * Returns true if the given class is of an integer type
1166   **/
1167  public static boolean isIntegerType (Class pClass)
1168  {
1169    return
1170      pClass == Byte.class ||
1171      pClass == Byte.TYPE ||
1172      pClass == Short.class ||
1173      pClass == Short.TYPE ||
1174      pClass == Character.class ||
1175      pClass == Character.TYPE ||
1176      pClass == Integer.class ||
1177      pClass == Integer.TYPE ||
1178      pClass == Long.class ||
1179      pClass == Long.TYPE;
1180  }
1181
1182  //-------------------------------------
1183
1184  /**
1185   * Returns true if the given object is BigInteger.
1186   * @param pObject - Object to evaluate
1187   * @return - true if the given object is BigInteger
1188   */
1189  public static boolean isBigInteger(Object pObject) {
1190      return
1191          pObject != null && pObject instanceof BigInteger;
1192  }
1193
1194  /**
1195   * Returns true if the given object is BigDecimal.
1196   * @param pObject - Object to evaluate
1197   * @return - true if the given object is BigDecimal
1198   */
1199  public static boolean isBigDecimal(Object pObject) {
1200      return
1201          pObject != null && pObject instanceof BigDecimal;
1202  }
1203}