001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * Portions Copyright Apache Software Foundation.
007: *
008: * The contents of this file are subject to the terms of either the GNU
009: * General Public License Version 2 only ("GPL") or the Common Development
010: * and Distribution License("CDDL") (collectively, the "License"). You
011: * may not use this file except in compliance with the License. You can obtain
012: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
013: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
014: * language governing permissions and limitations under the License.
015: *
016: * When distributing the software, include this License Header Notice in each
017: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
018: * Sun designates this particular file as subject to the "Classpath" exception
019: * as provided by Sun in the GPL Version 2 section of the License file that
020: * accompanied this code. If applicable, add the following below the License
021: * Header, with the fields enclosed by brackets [] replaced by your own
022: * identifying information: "Portions Copyrighted [year]
023: * [name of copyright owner]"
024: *
025: * Contributor(s):
026: *
027: * If you wish your version of this file to be governed by only the CDDL or
028: * only the GPL Version 2, indicate your decision by adding "[Contributor]
029: * elects to include this software in this distribution under the [CDDL or GPL
030: * Version 2] license." If you don't indicate a single choice of license, a
031: * recipient has the option to distribute your version of this file under
032: * either the CDDL, the GPL Version 2 or to extend the choice of license to
033: * its licensees as provided above. However, if you add GPL Version 2 code
034: * and therefore, elected the GPL Version 2 license, then the option applies
035: * only if the new code is made subject to such option by the copyright
036: * holder.
037: */
038:
039: package org.apache.taglibs.standard.lang.jstl;
040:
041: import java.beans.PropertyEditor;
042: import java.beans.PropertyEditorManager;
043:
044: /**
045: *
046: * <p>This class contains the logic for coercing data types before
047: * operators are applied to them.
048: *
049: * <p>The following is the list of rules applied for various type
050: * conversions.
051: *
052: * <ul><pre>
053: * Applying arithmetic operator
054: * Binary operator - A {+,-,*} B
055: * if A and B are null
056: * return 0
057: * if A or B is Float, Double, or String containing ".", "e", or "E"
058: * coerce both A and B to Double
059: * apply operator
060: * otherwise
061: * coerce both A and B to Long
062: * apply operator
063: * if operator results in exception (such as divide by 0), error
064: *
065: * Binary operator - A {/,div} B
066: * if A and B are null
067: * return 0
068: * otherwise
069: * coerce both A and B to Double
070: * apply operator
071: * if operator results in exception (such as divide by 0), error
072: *
073: * Binary operator - A {%,mod} B
074: * if A and B are null
075: * return 0
076: * if A or B is Float, Double, or String containing ".", "e" or "E"
077: * coerce both to Double
078: * apply operator
079: * otherwise
080: * coerce both A and B to Long
081: * apply operator
082: * if operator results in exception (such as divide by 0), error
083: *
084: * Unary minus operator - -A
085: * if A is null
086: * return 0
087: * if A is String
088: * if A contains ".", "e", or "E"
089: * coerce to Double, apply operator
090: * otherwise
091: * coerce to a Long and apply operator
092: * if A is Byte,Short,Integer,Long,Float,Double
093: * retain type, apply operator
094: * if operator results in exception, error
095: * otherwise
096: * error
097: *
098: * Applying "empty" operator - empty A
099: * if A is null
100: * return true
101: * if A is zero-length String
102: * return true
103: * if A is zero-length array
104: * return true
105: * if A is List and ((List) A).isEmpty()
106: * return true
107: * if A is Map and ((Map) A).isEmpty()
108: * return true
109: * otherwise
110: * return false
111: *
112: * Applying logical operators
113: * Binary operator - A {and,or} B
114: * coerce both A and B to Boolean, apply operator
115: * NOTE - operator stops as soon as expression can be determined, i.e.,
116: * A and B and C and D - if B is false, then only A and B is evaluated
117: * Unary not operator - not A
118: * coerce A to Boolean, apply operator
119: *
120: * Applying relational operator
121: * A {<,>,<=,>=,lt,gt,lte,gte} B
122: * if A==B
123: * if operator is >= or <=
124: * return true
125: * otherwise
126: * return false
127: * if A or B is null
128: * return false
129: * if A or B is Float or Double
130: * coerce both A and B to Double
131: * apply operator
132: * if A or B is Byte,Short,Character,Integer,Long
133: * coerce both A and B to Long
134: * apply operator
135: * if A or B is String
136: * coerce both A and B to String, compare lexically
137: * if A is Comparable
138: * if A.compareTo (B) throws exception
139: * error
140: * otherwise
141: * use result of A.compareTo(B)
142: * if B is Comparable
143: * if B.compareTo (A) throws exception
144: * error
145: * otherwise
146: * use result of B.compareTo(A)
147: * otherwise
148: * error
149: *
150: * Applying equality operator
151: * A {==,!=} B
152: * if A==B
153: * apply operator
154: * if A or B is null
155: * return false for ==, true for !=
156: * if A or B is Float or Double
157: * coerce both A and B to Double
158: * apply operator
159: * if A or B is Byte,Short,Character,Integer,Long
160: * coerce both A and B to Long
161: * apply operator
162: * if A or B is Boolean
163: * coerce both A and B to Boolean
164: * apply operator
165: * if A or B is String
166: * coerce both A and B to String, compare lexically
167: * otherwise
168: * if an error occurs while calling A.equals(B)
169: * error
170: * apply operator to result of A.equals(B)
171: *
172: * coercions
173: *
174: * coerce A to String
175: * A is String
176: * return A
177: * A is null
178: * return ""
179: * A.toString throws exception
180: * error
181: * otherwise
182: * return A.toString
183: *
184: * coerce A to primitive Number type N
185: * A is null or ""
186: * return 0
187: * A is Character
188: * convert to short, apply following rules
189: * A is Boolean
190: * error
191: * A is Number type N
192: * return A
193: * A is Number with less precision than N
194: * coerce quietly
195: * A is Number with greater precision than N
196: * coerce quietly
197: * A is String
198: * new N.valueOf(A) throws exception
199: * error
200: * return N.valueOf(A)
201: * otherwise
202: * error
203: *
204: * coerce A to Character should be
205: * A is null or ""
206: * return (char) 0
207: * A is Character
208: * return A
209: * A is Boolean
210: * error
211: * A is Number with less precision than short
212: * coerce quietly - return (char) A
213: * A is Number with greater precision than short
214: * coerce quietly - return (char) A
215: * A is String
216: * return A.charAt (0)
217: * otherwise
218: * error
219: *
220: * coerce A to Boolean
221: * A is null or ""
222: * return false
223: * A is Boolean
224: * return A
225: * A is String
226: * Boolean.valueOf(A) throws exception
227: * error
228: * return Boolean.valueOf(A)
229: * otherwise
230: * error
231: *
232: * coerce A to any other type T
233: * A is null
234: * return null
235: * A is assignable to T
236: * coerce quietly
237: * A is String
238: * T has no PropertyEditor
239: * if A is "", return null
240: * otherwise error
241: * T's PropertyEditor throws exception
242: * if A is "", return null
243: * otherwise error
244: * otherwise
245: * apply T's PropertyEditor
246: * otherwise
247: * error
248: * </pre></ul>
249: *
250: * @author Nathan Abramson - Art Technology Group
251: * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: tcfujii $
252: **/
253:
254: public class Coercions {
255: //-------------------------------------
256: /**
257: *
258: * Coerces the given value to the specified class.
259: **/
260: public static Object coerce(Object pValue, Class pClass,
261: Logger pLogger) throws ELException {
262: if (pClass == String.class) {
263: return coerceToString(pValue, pLogger);
264: } else if (isPrimitiveNumberClass(pClass)) {
265: return coerceToPrimitiveNumber(pValue, pClass, pLogger);
266: } else if (pClass == Character.class
267: || pClass == Character.TYPE) {
268: return coerceToCharacter(pValue, pLogger);
269: } else if (pClass == Boolean.class || pClass == Boolean.TYPE) {
270: return coerceToBoolean(pValue, pLogger);
271: } else {
272: return coerceToObject(pValue, pClass, pLogger);
273: }
274: }
275:
276: //-------------------------------------
277: /**
278: *
279: * Returns true if the given class is Byte, Short, Integer, Long,
280: * Float, Double
281: **/
282: static boolean isPrimitiveNumberClass(Class pClass) {
283: return pClass == Byte.class || pClass == Byte.TYPE
284: || pClass == Short.class || pClass == Short.TYPE
285: || pClass == Integer.class || pClass == Integer.TYPE
286: || pClass == Long.class || pClass == Long.TYPE
287: || pClass == Float.class || pClass == Float.TYPE
288: || pClass == Double.class || pClass == Double.TYPE;
289: }
290:
291: //-------------------------------------
292: /**
293: *
294: * Coerces the specified value to a String
295: **/
296: public static String coerceToString(Object pValue, Logger pLogger)
297: throws ELException {
298: if (pValue == null) {
299: return "";
300: } else if (pValue instanceof String) {
301: return (String) pValue;
302: } else {
303: try {
304: return pValue.toString();
305: } catch (Exception exc) {
306: if (pLogger.isLoggingError()) {
307: pLogger.logError(Constants.TOSTRING_EXCEPTION, exc,
308: pValue.getClass().getName());
309: }
310: return "";
311: }
312: }
313: }
314:
315: //-------------------------------------
316: /**
317: *
318: * Coerces a value to the given primitive number class
319: **/
320: public static Number coerceToPrimitiveNumber(Object pValue,
321: Class pClass, Logger pLogger) throws ELException {
322: if (pValue == null || "".equals(pValue)) {
323: return coerceToPrimitiveNumber(0, pClass);
324: } else if (pValue instanceof Character) {
325: char val = ((Character) pValue).charValue();
326: return coerceToPrimitiveNumber((short) val, pClass);
327: } else if (pValue instanceof Boolean) {
328: if (pLogger.isLoggingError()) {
329: pLogger.logError(Constants.BOOLEAN_TO_NUMBER, pValue,
330: pClass.getName());
331: }
332: return coerceToPrimitiveNumber(0, pClass);
333: } else if (pValue.getClass() == pClass) {
334: return (Number) pValue;
335: } else if (pValue instanceof Number) {
336: return coerceToPrimitiveNumber((Number) pValue, pClass);
337: } else if (pValue instanceof String) {
338: try {
339: return coerceToPrimitiveNumber((String) pValue, pClass);
340: } catch (Exception exc) {
341: if (pLogger.isLoggingError()) {
342: pLogger.logError(
343: Constants.STRING_TO_NUMBER_EXCEPTION,
344: (String) pValue, pClass.getName());
345: }
346: return coerceToPrimitiveNumber(0, pClass);
347: }
348: } else {
349: if (pLogger.isLoggingError()) {
350: pLogger.logError(Constants.COERCE_TO_NUMBER, pValue
351: .getClass().getName(), pClass.getName());
352: }
353: return coerceToPrimitiveNumber(0, pClass);
354: }
355: }
356:
357: //-------------------------------------
358: /**
359: *
360: * Coerces a value to an Integer, returning null if the coercion
361: * isn't possible.
362: **/
363: public static Integer coerceToInteger(Object pValue, Logger pLogger)
364: throws ELException {
365: if (pValue == null) {
366: return null;
367: } else if (pValue instanceof Character) {
368: return PrimitiveObjects
369: .getInteger((int) (((Character) pValue).charValue()));
370: } else if (pValue instanceof Boolean) {
371: if (pLogger.isLoggingWarning()) {
372: pLogger.logWarning(Constants.BOOLEAN_TO_NUMBER, pValue,
373: Integer.class.getName());
374: }
375: return PrimitiveObjects.getInteger(((Boolean) pValue)
376: .booleanValue() ? 1 : 0);
377: } else if (pValue instanceof Integer) {
378: return (Integer) pValue;
379: } else if (pValue instanceof Number) {
380: return PrimitiveObjects.getInteger(((Number) pValue)
381: .intValue());
382: } else if (pValue instanceof String) {
383: try {
384: return Integer.valueOf((String) pValue);
385: } catch (Exception exc) {
386: if (pLogger.isLoggingWarning()) {
387: pLogger.logWarning(
388: Constants.STRING_TO_NUMBER_EXCEPTION,
389: (String) pValue, Integer.class.getName());
390: }
391: return null;
392: }
393: } else {
394: if (pLogger.isLoggingWarning()) {
395: pLogger.logWarning(Constants.COERCE_TO_NUMBER, pValue
396: .getClass().getName(), Integer.class.getName());
397: }
398: return null;
399: }
400: }
401:
402: //-------------------------------------
403: /**
404: *
405: * Coerces a long to the given primitive number class
406: **/
407: static Number coerceToPrimitiveNumber(long pValue, Class pClass)
408: throws ELException {
409: if (pClass == Byte.class || pClass == Byte.TYPE) {
410: return PrimitiveObjects.getByte((byte) pValue);
411: } else if (pClass == Short.class || pClass == Short.TYPE) {
412: return PrimitiveObjects.getShort((short) pValue);
413: } else if (pClass == Integer.class || pClass == Integer.TYPE) {
414: return PrimitiveObjects.getInteger((int) pValue);
415: } else if (pClass == Long.class || pClass == Long.TYPE) {
416: return PrimitiveObjects.getLong((long) pValue);
417: } else if (pClass == Float.class || pClass == Float.TYPE) {
418: return PrimitiveObjects.getFloat((float) pValue);
419: } else if (pClass == Double.class || pClass == Double.TYPE) {
420: return PrimitiveObjects.getDouble((double) pValue);
421: } else {
422: return PrimitiveObjects.getInteger(0);
423: }
424: }
425:
426: //-------------------------------------
427: /**
428: *
429: * Coerces a double to the given primitive number class
430: **/
431: static Number coerceToPrimitiveNumber(double pValue, Class pClass)
432: throws ELException {
433: if (pClass == Byte.class || pClass == Byte.TYPE) {
434: return PrimitiveObjects.getByte((byte) pValue);
435: } else if (pClass == Short.class || pClass == Short.TYPE) {
436: return PrimitiveObjects.getShort((short) pValue);
437: } else if (pClass == Integer.class || pClass == Integer.TYPE) {
438: return PrimitiveObjects.getInteger((int) pValue);
439: } else if (pClass == Long.class || pClass == Long.TYPE) {
440: return PrimitiveObjects.getLong((long) pValue);
441: } else if (pClass == Float.class || pClass == Float.TYPE) {
442: return PrimitiveObjects.getFloat((float) pValue);
443: } else if (pClass == Double.class || pClass == Double.TYPE) {
444: return PrimitiveObjects.getDouble((double) pValue);
445: } else {
446: return PrimitiveObjects.getInteger(0);
447: }
448: }
449:
450: //-------------------------------------
451: /**
452: *
453: * Coerces a Number to the given primitive number class
454: **/
455: static Number coerceToPrimitiveNumber(Number pValue, Class pClass)
456: throws ELException {
457: if (pClass == Byte.class || pClass == Byte.TYPE) {
458: return PrimitiveObjects.getByte(pValue.byteValue());
459: } else if (pClass == Short.class || pClass == Short.TYPE) {
460: return PrimitiveObjects.getShort(pValue.shortValue());
461: } else if (pClass == Integer.class || pClass == Integer.TYPE) {
462: return PrimitiveObjects.getInteger(pValue.intValue());
463: } else if (pClass == Long.class || pClass == Long.TYPE) {
464: return PrimitiveObjects.getLong(pValue.longValue());
465: } else if (pClass == Float.class || pClass == Float.TYPE) {
466: return PrimitiveObjects.getFloat(pValue.floatValue());
467: } else if (pClass == Double.class || pClass == Double.TYPE) {
468: return PrimitiveObjects.getDouble(pValue.doubleValue());
469: } else {
470: return PrimitiveObjects.getInteger(0);
471: }
472: }
473:
474: //-------------------------------------
475: /**
476: *
477: * Coerces a String to the given primitive number class
478: **/
479: static Number coerceToPrimitiveNumber(String pValue, Class pClass)
480: throws ELException {
481: if (pClass == Byte.class || pClass == Byte.TYPE) {
482: return Byte.valueOf(pValue);
483: } else if (pClass == Short.class || pClass == Short.TYPE) {
484: return Short.valueOf(pValue);
485: } else if (pClass == Integer.class || pClass == Integer.TYPE) {
486: return Integer.valueOf(pValue);
487: } else if (pClass == Long.class || pClass == Long.TYPE) {
488: return Long.valueOf(pValue);
489: } else if (pClass == Float.class || pClass == Float.TYPE) {
490: return Float.valueOf(pValue);
491: } else if (pClass == Double.class || pClass == Double.TYPE) {
492: return Double.valueOf(pValue);
493: } else {
494: return PrimitiveObjects.getInteger(0);
495: }
496: }
497:
498: //-------------------------------------
499: /**
500: *
501: * Coerces a value to a Character
502: **/
503: public static Character coerceToCharacter(Object pValue,
504: Logger pLogger) throws ELException {
505: if (pValue == null || "".equals(pValue)) {
506: return PrimitiveObjects.getCharacter((char) 0);
507: } else if (pValue instanceof Character) {
508: return (Character) pValue;
509: } else if (pValue instanceof Boolean) {
510: if (pLogger.isLoggingError()) {
511: pLogger
512: .logError(Constants.BOOLEAN_TO_CHARACTER,
513: pValue);
514: }
515: return PrimitiveObjects.getCharacter((char) 0);
516: } else if (pValue instanceof Number) {
517: return PrimitiveObjects
518: .getCharacter((char) ((Number) pValue).shortValue());
519: } else if (pValue instanceof String) {
520: String str = (String) pValue;
521: return PrimitiveObjects.getCharacter(str.charAt(0));
522: } else {
523: if (pLogger.isLoggingError()) {
524: pLogger.logError(Constants.COERCE_TO_CHARACTER, pValue
525: .getClass().getName());
526: }
527: return PrimitiveObjects.getCharacter((char) 0);
528: }
529: }
530:
531: //-------------------------------------
532: /**
533: *
534: * Coerces a value to a Boolean
535: **/
536: public static Boolean coerceToBoolean(Object pValue, Logger pLogger)
537: throws ELException {
538: if (pValue == null || "".equals(pValue)) {
539: return Boolean.FALSE;
540: } else if (pValue instanceof Boolean) {
541: return (Boolean) pValue;
542: } else if (pValue instanceof String) {
543: String str = (String) pValue;
544: try {
545: return Boolean.valueOf(str);
546: } catch (Exception exc) {
547: if (pLogger.isLoggingError()) {
548: pLogger.logError(Constants.STRING_TO_BOOLEAN, exc,
549: (String) pValue);
550: }
551: return Boolean.FALSE;
552: }
553: } else {
554: if (pLogger.isLoggingError()) {
555: pLogger.logError(Constants.COERCE_TO_BOOLEAN, pValue
556: .getClass().getName());
557: }
558: return Boolean.TRUE;
559: }
560: }
561:
562: //-------------------------------------
563: /**
564: *
565: * Coerces a value to the specified Class that is not covered by any
566: * of the above cases
567: **/
568: public static Object coerceToObject(Object pValue, Class pClass,
569: Logger pLogger) throws ELException {
570: if (pValue == null) {
571: return null;
572: } else if (pClass.isAssignableFrom(pValue.getClass())) {
573: return pValue;
574: } else if (pValue instanceof String) {
575: String str = (String) pValue;
576: PropertyEditor pe = PropertyEditorManager
577: .findEditor(pClass);
578: if (pe == null) {
579: if ("".equals(str)) {
580: return null;
581: } else {
582: if (pLogger.isLoggingError()) {
583: pLogger.logError(Constants.NO_PROPERTY_EDITOR,
584: str, pClass.getName());
585: }
586: return null;
587: }
588: }
589: try {
590: pe.setAsText(str);
591: return pe.getValue();
592: } catch (IllegalArgumentException exc) {
593: if ("".equals(str)) {
594: return null;
595: } else {
596: if (pLogger.isLoggingError()) {
597: pLogger.logError(
598: Constants.PROPERTY_EDITOR_ERROR, exc,
599: pValue, pClass.getName());
600: }
601: return null;
602: }
603: }
604: } else {
605: if (pLogger.isLoggingError()) {
606: pLogger.logError(Constants.COERCE_TO_OBJECT, pValue
607: .getClass().getName(), pClass.getName());
608: }
609: return null;
610: }
611: }
612:
613: //-------------------------------------
614: // Applying operators
615: //-------------------------------------
616: /**
617: *
618: * Performs all of the necessary type conversions, then calls on the
619: * appropriate operator.
620: **/
621: public static Object applyArithmeticOperator(Object pLeft,
622: Object pRight, ArithmeticOperator pOperator, Logger pLogger)
623: throws ELException {
624: if (pLeft == null && pRight == null) {
625: if (pLogger.isLoggingWarning()) {
626: pLogger.logWarning(Constants.ARITH_OP_NULL, pOperator
627: .getOperatorSymbol());
628: }
629: return PrimitiveObjects.getInteger(0);
630: }
631:
632: else if (isFloatingPointType(pLeft)
633: || isFloatingPointType(pRight)
634: || isFloatingPointString(pLeft)
635: || isFloatingPointString(pRight)) {
636: double left = coerceToPrimitiveNumber(pLeft, Double.class,
637: pLogger).doubleValue();
638: double right = coerceToPrimitiveNumber(pRight,
639: Double.class, pLogger).doubleValue();
640: return PrimitiveObjects.getDouble(pOperator.apply(left,
641: right, pLogger));
642: }
643:
644: else {
645: long left = coerceToPrimitiveNumber(pLeft, Long.class,
646: pLogger).longValue();
647: long right = coerceToPrimitiveNumber(pRight, Long.class,
648: pLogger).longValue();
649: return PrimitiveObjects.getLong(pOperator.apply(left,
650: right, pLogger));
651: }
652: }
653:
654: //-------------------------------------
655: /**
656: *
657: * Performs all of the necessary type conversions, then calls on the
658: * appropriate operator.
659: **/
660: public static Object applyRelationalOperator(Object pLeft,
661: Object pRight, RelationalOperator pOperator, Logger pLogger)
662: throws ELException {
663: if (isFloatingPointType(pLeft) || isFloatingPointType(pRight)) {
664: double left = coerceToPrimitiveNumber(pLeft, Double.class,
665: pLogger).doubleValue();
666: double right = coerceToPrimitiveNumber(pRight,
667: Double.class, pLogger).doubleValue();
668: return PrimitiveObjects.getBoolean(pOperator.apply(left,
669: right, pLogger));
670: }
671:
672: else if (isIntegerType(pLeft) || isIntegerType(pRight)) {
673: long left = coerceToPrimitiveNumber(pLeft, Long.class,
674: pLogger).longValue();
675: long right = coerceToPrimitiveNumber(pRight, Long.class,
676: pLogger).longValue();
677: return PrimitiveObjects.getBoolean(pOperator.apply(left,
678: right, pLogger));
679: }
680:
681: else if (pLeft instanceof String || pRight instanceof String) {
682: String left = coerceToString(pLeft, pLogger);
683: String right = coerceToString(pRight, pLogger);
684: return PrimitiveObjects.getBoolean(pOperator.apply(left,
685: right, pLogger));
686: }
687:
688: else if (pLeft instanceof Comparable) {
689: try {
690: int result = ((Comparable) pLeft).compareTo(pRight);
691: return PrimitiveObjects.getBoolean(pOperator.apply(
692: result, -result, pLogger));
693: } catch (Exception exc) {
694: if (pLogger.isLoggingError()) {
695: pLogger.logError(Constants.COMPARABLE_ERROR, exc,
696: pLeft.getClass().getName(),
697: (pRight == null) ? "null" : pRight
698: .getClass().getName(), pOperator
699: .getOperatorSymbol());
700: }
701: return Boolean.FALSE;
702: }
703: }
704:
705: else if (pRight instanceof Comparable) {
706: try {
707: int result = ((Comparable) pRight).compareTo(pLeft);
708: return PrimitiveObjects.getBoolean(pOperator.apply(
709: -result, result, pLogger));
710: } catch (Exception exc) {
711: if (pLogger.isLoggingError()) {
712: pLogger.logError(Constants.COMPARABLE_ERROR, exc,
713: pRight.getClass().getName(),
714: (pLeft == null) ? "null" : pLeft.getClass()
715: .getName(), pOperator
716: .getOperatorSymbol());
717: }
718: return Boolean.FALSE;
719: }
720: }
721:
722: else {
723: if (pLogger.isLoggingError()) {
724: pLogger.logError(Constants.ARITH_OP_BAD_TYPE, pOperator
725: .getOperatorSymbol(), pLeft.getClass()
726: .getName(), pRight.getClass().getName());
727: }
728: return Boolean.FALSE;
729: }
730: }
731:
732: //-------------------------------------
733: /**
734: *
735: * Performs all of the necessary type conversions, then calls on the
736: * appropriate operator.
737: **/
738: public static Object applyEqualityOperator(Object pLeft,
739: Object pRight, EqualityOperator pOperator, Logger pLogger)
740: throws ELException {
741: if (pLeft == pRight) {
742: return PrimitiveObjects.getBoolean(pOperator.apply(true,
743: pLogger));
744: }
745:
746: else if (pLeft == null || pRight == null) {
747: return PrimitiveObjects.getBoolean(pOperator.apply(false,
748: pLogger));
749: }
750:
751: else if (isFloatingPointType(pLeft)
752: || isFloatingPointType(pRight)) {
753: double left = coerceToPrimitiveNumber(pLeft, Double.class,
754: pLogger).doubleValue();
755: double right = coerceToPrimitiveNumber(pRight,
756: Double.class, pLogger).doubleValue();
757: return PrimitiveObjects.getBoolean(pOperator.apply(
758: left == right, pLogger));
759: }
760:
761: else if (isIntegerType(pLeft) || isIntegerType(pRight)) {
762: long left = coerceToPrimitiveNumber(pLeft, Long.class,
763: pLogger).longValue();
764: long right = coerceToPrimitiveNumber(pRight, Long.class,
765: pLogger).longValue();
766: return PrimitiveObjects.getBoolean(pOperator.apply(
767: left == right, pLogger));
768: }
769:
770: else if (pLeft instanceof Boolean || pRight instanceof Boolean) {
771: boolean left = coerceToBoolean(pLeft, pLogger)
772: .booleanValue();
773: boolean right = coerceToBoolean(pRight, pLogger)
774: .booleanValue();
775: return PrimitiveObjects.getBoolean(pOperator.apply(
776: left == right, pLogger));
777: }
778:
779: else if (pLeft instanceof String || pRight instanceof String) {
780: String left = coerceToString(pLeft, pLogger);
781: String right = coerceToString(pRight, pLogger);
782: return PrimitiveObjects.getBoolean(pOperator.apply(left
783: .equals(right), pLogger));
784: }
785:
786: else {
787: try {
788: return PrimitiveObjects.getBoolean(pOperator.apply(
789: pLeft.equals(pRight), pLogger));
790: } catch (Exception exc) {
791: if (pLogger.isLoggingError()) {
792: pLogger.logError(Constants.ERROR_IN_EQUALS, exc,
793: pLeft.getClass().getName(), pRight
794: .getClass().getName(), pOperator
795: .getOperatorSymbol());
796: }
797: return Boolean.FALSE;
798: }
799: }
800: }
801:
802: //-------------------------------------
803: /**
804: *
805: * Returns true if the given Object is of a floating point type
806: **/
807: public static boolean isFloatingPointType(Object pObject) {
808: return pObject != null
809: && isFloatingPointType(pObject.getClass());
810: }
811:
812: //-------------------------------------
813: /**
814: *
815: * Returns true if the given class is of a floating point type
816: **/
817: public static boolean isFloatingPointType(Class pClass) {
818: return pClass == Float.class || pClass == Float.TYPE
819: || pClass == Double.class || pClass == Double.TYPE;
820: }
821:
822: //-------------------------------------
823: /**
824: *
825: * Returns true if the given string might contain a floating point
826: * number - i.e., it contains ".", "e", or "E"
827: **/
828: public static boolean isFloatingPointString(Object pObject) {
829: if (pObject instanceof String) {
830: String str = (String) pObject;
831: int len = str.length();
832: for (int i = 0; i < len; i++) {
833: char ch = str.charAt(i);
834: if (ch == '.' || ch == 'e' || ch == 'E') {
835: return true;
836: }
837: }
838: return false;
839: } else {
840: return false;
841: }
842: }
843:
844: //-------------------------------------
845: /**
846: *
847: * Returns true if the given Object is of an integer type
848: **/
849: public static boolean isIntegerType(Object pObject) {
850: return pObject != null && isIntegerType(pObject.getClass());
851: }
852:
853: //-------------------------------------
854: /**
855: *
856: * Returns true if the given class is of an integer type
857: **/
858: public static boolean isIntegerType(Class pClass) {
859: return pClass == Byte.class || pClass == Byte.TYPE
860: || pClass == Short.class || pClass == Short.TYPE
861: || pClass == Character.class
862: || pClass == Character.TYPE || pClass == Integer.class
863: || pClass == Integer.TYPE || pClass == Long.class
864: || pClass == Long.TYPE;
865: }
866:
867: //-------------------------------------
868:
869: }
|