0001: /*
0002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
0003: *
0004: * This file is part of Resin(R) Open Source
0005: *
0006: * Each copy or derived work must preserve the copyright notice and this
0007: * notice unmodified.
0008: *
0009: * Resin Open Source is free software; you can redistribute it and/or modify
0010: * it under the terms of the GNU General Public License as published by
0011: * the Free Software Foundation; either version 2 of the License, or
0012: * (at your option) any later version.
0013: *
0014: * Resin Open Source is distributed in the hope that it will be useful,
0015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
0017: * of NON-INFRINGEMENT. See the GNU General Public License for more
0018: * details.
0019: *
0020: * You should have received a copy of the GNU General Public License
0021: * along with Resin Open Source; if not, write to the
0022: *
0023: * Free Software Foundation, Inc.
0024: * 59 Temple Place, Suite 330
0025: * Boston, MA 02111-1307 USA
0026: *
0027: * @author Scott Ferguson
0028: */
0029:
0030: package com.caucho.el;
0031:
0032: import com.caucho.config.types.Period;
0033: import com.caucho.util.BeanUtil;
0034: import com.caucho.util.IntMap;
0035: import com.caucho.util.L10N;
0036: import com.caucho.vfs.ReadStream;
0037: import com.caucho.vfs.WriteStream;
0038:
0039: import javax.el.ELContext;
0040: import javax.el.ELException;
0041: import javax.el.MethodInfo;
0042: import javax.el.PropertyNotFoundException;
0043: import javax.el.PropertyNotWritableException;
0044: import javax.el.ValueExpression;
0045: import javax.servlet.jsp.JspWriter;
0046: import javax.servlet.jsp.JspException;
0047: import java.io.IOException;
0048: import java.io.Reader;
0049: import java.io.Writer;
0050: import java.lang.reflect.InvocationTargetException;
0051: import java.lang.reflect.Method;
0052: import java.math.BigDecimal;
0053: import java.math.BigInteger;
0054: import java.util.HashMap;
0055: import java.util.Map;
0056: import java.util.logging.Level;
0057: import java.util.logging.Logger;
0058:
0059: /**
0060: * Abstract implementation class for an expression.
0061: */
0062: public abstract class Expr extends ValueExpression {
0063: protected static final Logger log = Logger.getLogger(Expr.class
0064: .getName());
0065: protected static final L10N L = new L10N(Expr.class);
0066:
0067: private static final Character NULL_CHAR = new Character((char) 0);
0068:
0069: private static final long DAY = 24L * 3600L * 1000L;
0070:
0071: private static final BigDecimal BIG_DECIMAL_ZERO = new BigDecimal(
0072: "0");
0073:
0074: private static final BigInteger BIG_INTEGER_ZERO = new BigInteger(
0075: "0");
0076:
0077: private static final HashMap<Class, CoerceType> _coerceMap = new HashMap<Class, CoerceType>();
0078:
0079: // lexeme codes
0080: final static int ADD = 1;
0081: final static int SUB = ADD + 1;
0082: final static int MUL = SUB + 1;
0083: final static int DIV = MUL + 1;
0084: final static int MOD = DIV + 1;
0085: final static int EQ = MOD + 1;
0086: final static int NE = EQ + 1;
0087: final static int LT = NE + 1;
0088: final static int LE = LT + 1;
0089: final static int GT = LE + 1;
0090: final static int GE = GT + 1;
0091: final static int AND = GE + 1;
0092: final static int OR = AND + 1;
0093:
0094: final static int NOT = OR + 1;
0095: final static int MINUS = NOT + 1;
0096: final static int EMPTY = MINUS + 1;
0097:
0098: final static int OBJECT = 0;
0099: final static int BOOLEAN = OBJECT + 1;
0100: final static int BYTE = BOOLEAN + 1;
0101: final static int SHORT = BYTE + 1;
0102: final static int INT = SHORT + 1;
0103: final static int LONG = INT + 1;
0104: final static int FLOAT = LONG + 1;
0105: final static int DOUBLE = FLOAT + 1;
0106:
0107: final static int BOOLEAN_OBJ = DOUBLE + 1;
0108: final static int BYTE_OBJ = BOOLEAN_OBJ + 1;
0109: final static int SHORT_OBJ = BYTE_OBJ + 1;
0110: final static int INT_OBJ = SHORT_OBJ + 1;
0111: final static int LONG_OBJ = INT_OBJ + 1;
0112: final static int FLOAT_OBJ = LONG_OBJ + 1;
0113: final static int DOUBLE_OBJ = FLOAT_OBJ + 1;
0114:
0115: final static int STRING = DOUBLE_OBJ + 1;
0116:
0117: final static IntMap _typeMap = new IntMap();
0118:
0119: /**
0120: * Returns true if the expression is constant.
0121: */
0122: public boolean isConstant() {
0123: return false;
0124: }
0125:
0126: /**
0127: * Returns true if the expression is read-only.
0128: */
0129: public boolean isReadOnly(ELContext env) {
0130: return true;
0131: }
0132:
0133: /**
0134: * Returns true if the expression is literal text
0135: */
0136: public boolean isLiteralText() {
0137: return false;
0138: }
0139:
0140: /**
0141: * Creates a field reference using this expression as the base object.
0142: *
0143: * @param field the expression for the field.
0144: */
0145: public Expr createField(Expr field) {
0146: return new ArrayResolverExpr(this , field);
0147: }
0148:
0149: /**
0150: * Creates a field reference using this expression as the base object.
0151: *
0152: * @param field the string reference for the field.
0153: */
0154: public Expr createField(String field) {
0155: return createField(new StringLiteral(field));
0156: }
0157:
0158: /**
0159: * Creates a method call using this as the <code>obj.method</code>
0160: * expression
0161: *
0162: * @param args the arguments for the method
0163: */
0164: public Expr createMethod(Expr[] args) {
0165: return new FunctionExpr(this , args);
0166: }
0167:
0168: /**
0169: * Evaluates the expression, returning an object.
0170: *
0171: * @param env the variable environment
0172: *
0173: * @return the value of the expression as an object
0174: */
0175: abstract public Object getValue(ELContext env) throws ELException;
0176:
0177: /**
0178: * Evaluates the expression, returning an object.
0179: *
0180: * @param env the variable environment
0181: *
0182: * @return the value of the expression as an object
0183: */
0184: public MethodInfo getMethodInfo(ELContext env, Class<?> returnType,
0185: Class<?>[] argTypes) throws ELException {
0186: throw new ELException(L.l(
0187: "'{0}' is an illegal method expression." + getClass(),
0188: toString()));
0189: }
0190:
0191: /**
0192: * Evaluates the expression, returning an object.
0193: *
0194: * @param env the variable environment
0195: *
0196: * @return the value of the expression as an object
0197: */
0198: public Object invoke(ELContext env, Class<?>[] argTypes,
0199: Object[] args) throws ELException {
0200: throw new ELException(L.l(
0201: "'{0}' is an illegal method expression." + getClass(),
0202: toString()));
0203: }
0204:
0205: /**
0206: * Evaluates the expression, returning an object.
0207: *
0208: * @param env the variable environment
0209: *
0210: * @return the value of the expression as an object
0211: */
0212: public final Object evalObject(ELContext env) throws ELException {
0213: return getValue(env);
0214: }
0215:
0216: /**
0217: * Evaluate the expression, knowing the value should be a boolean.
0218: *
0219: * @param env the variable environment
0220: *
0221: * @return the value of the expression as a boolean
0222: */
0223: public boolean evalBoolean(ELContext env) throws ELException {
0224: return toBoolean(getValue(env), env);
0225: }
0226:
0227: /**
0228: * Evaluate the expression, knowing the value should be a double.
0229: *
0230: * @param env the variable environment
0231: *
0232: * @return the value of the expression as a double
0233: */
0234: public double evalDouble(ELContext env) throws ELException {
0235: return toDouble(getValue(env), env);
0236: }
0237:
0238: /**
0239: * Evaluate the expression, knowing the value should be a long
0240: *
0241: * @param env the variable environment
0242: *
0243: * @return the value of the expression as a double
0244: */
0245: public long evalLong(ELContext env) throws ELException {
0246: return toLong(getValue(env), env);
0247: }
0248:
0249: /**
0250: * Evaluate the expression, knowing the value should be a string
0251: *
0252: * @param env the variable environment
0253: *
0254: * @return the value of the expression as a string
0255: */
0256: public String evalString(ELContext env) throws ELException {
0257: return toString(getValue(env), env);
0258: }
0259:
0260: /**
0261: * Evaluate the expression, knowing the value should be a string
0262: *
0263: * @param env the variable environment
0264: *
0265: * @return the value of the expression as a string
0266: */
0267: public String evalStringWithNull(ELContext env) throws ELException {
0268: return toStringWithNull(getValue(env), env);
0269: }
0270:
0271: /**
0272: * Evaluate the expression, knowing the value should be a string
0273: *
0274: * @param env the variable environment
0275: *
0276: * @return the value of the expression as a string
0277: */
0278: public char evalCharacter(ELContext env) throws ELException {
0279: return toCharacter(getValue(env), env);
0280: }
0281:
0282: /**
0283: * Evaluate the expression, knowing the value should be a period
0284: *
0285: * @param env the variable environment
0286: *
0287: * @return the value of the expression as a period
0288: */
0289: public long evalPeriod(ELContext env) throws ELException {
0290: try {
0291: Object obj = getValue(env);
0292:
0293: if (obj instanceof Number)
0294: return 1000L * ((Number) obj).longValue();
0295: else
0296: return Period.toPeriod(toString(obj, env));
0297: } catch (Exception e) {
0298: throw new ELException(e.getMessage());
0299: }
0300:
0301: }
0302:
0303: /**
0304: * Evaluate the expression, knowing the value should be a BigInteger.
0305: *
0306: * @param env the variable environment
0307: *
0308: * @return the value of the expression as a BigInteger
0309: */
0310: public BigInteger evalBigInteger(ELContext env) throws ELException {
0311: return toBigInteger(getValue(env), env);
0312: }
0313:
0314: /**
0315: * Evaluate the expression, knowing the value should be a BigDecimal.
0316: *
0317: * @param env the variable environment
0318: *
0319: * @return the value of the expression as a BigDecimal
0320: */
0321: public BigDecimal evalBigDecimal(ELContext env) throws ELException {
0322: return toBigDecimal(getValue(env), env);
0323: }
0324:
0325: /**
0326: * Evaluates the expression, setting an object.
0327: *
0328: * @param env the variable environment
0329: *
0330: * @return the value of the expression as an object
0331: */
0332: @Override
0333: public void setValue(ELContext env, Object value)
0334: throws PropertyNotFoundException,
0335: PropertyNotWritableException, ELException {
0336: throw new PropertyNotWritableException(getClass().getName()
0337: + ": " + toString());
0338: }
0339:
0340: /**
0341: * Evaluates directly to the output. The method returns true
0342: * if the default value should be printed instead.
0343: *
0344: * @param out the output writer
0345: * @param env the variable environment
0346: * @param escapeXml if true, escape reserved XML
0347: *
0348: * @return true if the object is null, otherwise false
0349: */
0350: public boolean print(WriteStream out, ELContext env,
0351: boolean escapeXml) throws IOException, ELException {
0352: Object obj = getValue(env);
0353:
0354: if (obj == null)
0355: return true;
0356: else if (escapeXml) {
0357: toStreamEscaped(out, obj);
0358: return false;
0359: } else {
0360: toStream(out, obj);
0361: return false;
0362: }
0363: }
0364:
0365: /**
0366: * Evaluates directly to the output. The method returns true
0367: * if the default value should be printed instead.
0368: *
0369: * @param out the output writer
0370: * @param env the variable environment
0371: * @param escapeXml if true, escape reserved XML
0372: *
0373: * @return true if the object is null, otherwise false
0374: */
0375: public boolean print(JspWriter out, ELContext env, boolean escapeXml)
0376: throws IOException, ELException {
0377: //try {
0378:
0379: Object obj = getValue(env);
0380:
0381: if (obj == null)
0382: return true;
0383: else if (escapeXml) {
0384: toStreamEscaped(out, obj);
0385: return false;
0386: } else {
0387: toStream(out, obj);
0388: return false;
0389: }
0390:
0391: /*
0392: } catch (ELException e) {
0393: // jsp/3253
0394:
0395: log.log(Level.WARNING, e.toString(), e);
0396: return false;
0397: }
0398: */
0399: }
0400:
0401: /**
0402: * Generates the code to regenerate the expression.
0403: *
0404: * @param os the stream to the *.java page
0405: */
0406: public void printCreate(WriteStream os) throws IOException {
0407: throw new UnsupportedOperationException(getClass().getName());
0408: }
0409:
0410: //
0411: // EL methods
0412: //
0413:
0414: @Override
0415: public String getExpressionString() {
0416: return toString();
0417: }
0418:
0419: @Override
0420: public Class<?> getExpectedType() {
0421: return Object.class;
0422: }
0423:
0424: @Override
0425: public Class<?> getType(ELContext context)
0426: throws PropertyNotFoundException, ELException {
0427: Object value = getValue(context);
0428:
0429: if (value == null)
0430: return null;
0431: else
0432: return value.getClass();
0433: }
0434:
0435: //
0436: // Static convenience methods
0437: //
0438:
0439: /**
0440: * Returns true for a double or double-equivalent.
0441: */
0442: public static boolean isDouble(Object o) {
0443: if (o instanceof Double)
0444: return true;
0445: else if (o instanceof Float)
0446: return true;
0447: else if (!(o instanceof String))
0448: return false;
0449: else {
0450: String s = (String) o;
0451: int len = s.length();
0452:
0453: for (int i = 0; i < len; i++) {
0454: char ch = s.charAt(i);
0455:
0456: if (ch == '.' || ch == 'e' || ch == 'E')
0457: return true;
0458: }
0459:
0460: return false;
0461: }
0462: }
0463:
0464: /**
0465: * Converts some unknown value to a string.
0466: *
0467: * @param value the value to be converted.
0468: *
0469: * @return the string-converted value.
0470: */
0471: public static String toStringWithNull(Object value, ELContext env) {
0472: if (value == null || value instanceof String)
0473: return (String) value;
0474: else
0475: return value.toString();
0476: }
0477:
0478: /**
0479: * Converts some unknown value to a string.
0480: *
0481: * @param value the value to be converted.
0482: *
0483: * @return the string-converted value.
0484: */
0485: public static String toString(Object value, ELContext env) {
0486: if (value == null)
0487: return "";
0488: else if (value instanceof String)
0489: return (String) value;
0490: else
0491: return value.toString();
0492: }
0493:
0494: /**
0495: * Converts some unknown value to a string.
0496: *
0497: * @param value the value to be converted.
0498: *
0499: * @return the string-converted value.
0500: */
0501: public static String toString(long value, ELContext env) {
0502: return String.valueOf(value);
0503: }
0504:
0505: /**
0506: * Converts some unknown value to a string.
0507: *
0508: * @param value the value to be converted.
0509: *
0510: * @return the string-converted value.
0511: */
0512: public static String toString(double value, ELContext env) {
0513: return String.valueOf(value);
0514: }
0515:
0516: /**
0517: * Converts some unknown value to a string.
0518: *
0519: * @param value the value to be converted.
0520: *
0521: * @return the string-converted value.
0522: */
0523: public static String toString(boolean value, ELContext env) {
0524: return String.valueOf(value);
0525: }
0526:
0527: /**
0528: * Converts some unknown value to a string.
0529: *
0530: * @param value the value to be converted.
0531: *
0532: * @return the string-converted value.
0533: */
0534: public static String toString(char value, ELContext env) {
0535: return String.valueOf(value);
0536: }
0537:
0538: /**
0539: * Converts some unknown value to a string.
0540: *
0541: * @param value the value to be converted.
0542: *
0543: * @return the string-converted value.
0544: */
0545: public static char toCharacter(Object value, ELContext env)
0546: throws ELException {
0547: if (value == null)
0548: return (char) 0;
0549: else if (value instanceof Character) {
0550: return ((Character) value).charValue();
0551: } else if (value instanceof String) {
0552: String s = (String) value;
0553:
0554: if (s == null || s.length() == 0)
0555: return (char) 0;
0556: else
0557: return s.charAt(0);
0558: } else if (value instanceof Number) {
0559: Number number = (Number) value;
0560:
0561: return (char) number.intValue();
0562: } else if (value instanceof Boolean) {
0563: ELException e = new ELException(L.l(
0564: "can't convert {0} to character.", value.getClass()
0565: .getName()));
0566:
0567: throw e;
0568: /*
0569: error(e, env);
0570:
0571: return (char) 0;
0572: */
0573: } else
0574: return (char) toLong(value, env);
0575: }
0576:
0577: /**
0578: * Converts some unknown value to a boolean.
0579: *
0580: * @param value the value to be converted.
0581: *
0582: * @return the boolean-converted value.
0583: */
0584: public static boolean toBoolean(Object value, ELContext env)
0585: throws ELException {
0586: if (value == null || value.equals(""))
0587: return false;
0588: else if (value instanceof Boolean)
0589: return ((Boolean) value).booleanValue();
0590: else if (value instanceof String)
0591: return value.equals("true") || value.equals("yes");
0592: else {
0593: ELException e = new ELException(L.l(
0594: "can't convert {0} to boolean.", value.getClass()
0595: .getName()));
0596:
0597: // jsp/18s1
0598: throw e;
0599: /*
0600: error(e, env);
0601:
0602: return false;
0603: */
0604: }
0605: }
0606:
0607: /**
0608: * Converts some unknown value to a double.
0609: *
0610: * @param value the value to be converted.
0611: *
0612: * @return the double-converted value.
0613: */
0614: public static double toDouble(Object value, ELContext env)
0615: throws ELException {
0616: if (value == null)
0617: return 0;
0618: else if (value instanceof Number) {
0619: double dValue = ((Number) value).doubleValue();
0620:
0621: if (Double.isNaN(dValue))
0622: return 0;
0623: else
0624: return dValue;
0625: } else if (value.equals(""))
0626: return 0;
0627: else if (value instanceof String) {
0628: double dValue = Double.parseDouble((String) value);
0629:
0630: if (Double.isNaN(dValue))
0631: return 0;
0632: else
0633: return dValue;
0634: } else if (value instanceof Character) {
0635: // jsp/18s7
0636: return ((Character) value).charValue();
0637: } else {
0638: ELException e = new ELException(L.l(
0639: "can't convert {0} to double.", value.getClass()
0640: .getName()));
0641:
0642: // error(e, env);
0643:
0644: // return 0;
0645:
0646: throw e;
0647: }
0648: }
0649:
0650: /**
0651: * Converts some unknown value to a big decimal
0652: *
0653: * @param value the value to be converted.
0654: *
0655: * @return the BigDecimal-converted value.
0656: */
0657: public static BigDecimal toBigDecimal(Object value, ELContext env)
0658: throws ELException {
0659: if (value == null)
0660: return BIG_DECIMAL_ZERO;
0661: else if (value instanceof BigDecimal)
0662: return (BigDecimal) value;
0663: else if (value instanceof Number) {
0664: double dValue = ((Number) value).doubleValue();
0665:
0666: return new BigDecimal(dValue);
0667: } else if (value.equals(""))
0668: return BIG_DECIMAL_ZERO;
0669: else if (value instanceof String) {
0670: return new BigDecimal((String) value);
0671: } else if (value instanceof Character) {
0672: return new BigDecimal(((Character) value).charValue());
0673: } else {
0674: ELException e = new ELException(L.l(
0675: "can't convert {0} to BigDecimal.", value
0676: .getClass().getName()));
0677:
0678: error(e, env);
0679:
0680: return BIG_DECIMAL_ZERO;
0681: }
0682: }
0683:
0684: /**
0685: * Converts some unknown value to a big integer
0686: *
0687: * @param value the value to be converted.
0688: *
0689: * @return the BigInteger-converted value.
0690: */
0691: public static BigInteger toBigInteger(Object value, ELContext env)
0692: throws ELException {
0693: if (value == null)
0694: return BIG_INTEGER_ZERO;
0695: else if (value instanceof BigInteger)
0696: return (BigInteger) value;
0697: else if (value instanceof Number) {
0698: // return new BigInteger(value.toString());
0699: return new BigDecimal(value.toString()).toBigInteger();
0700: } else if (value.equals(""))
0701: return BIG_INTEGER_ZERO;
0702: else if (value instanceof String) {
0703: return new BigInteger((String) value);
0704: } else if (value instanceof Character) {
0705: return new BigInteger(String
0706: .valueOf((int) ((Character) value).charValue()));
0707: } else {
0708: ELException e = new ELException(L.l(
0709: "can't convert {0} to BigInteger.", value
0710: .getClass().getName()));
0711:
0712: error(e, env);
0713:
0714: return BIG_INTEGER_ZERO;
0715: }
0716: }
0717:
0718: /**
0719: * Converts some unknown value to a long.
0720: *
0721: * @param value the value to be converted.
0722: *
0723: * @return the long-converted value.
0724: */
0725: public static long toLong(Object value, ELContext env)
0726: throws ELException {
0727: if (value == null)
0728: return 0;
0729: else if (value instanceof Number)
0730: return ((Number) value).longValue();
0731: else if (value.equals(""))
0732: return 0;
0733: else if (value instanceof String) {
0734: try {
0735: return (long) Double.parseDouble((String) value);
0736: } catch (Exception e) {
0737: throw new ELException(e);
0738: }
0739: } else if (value instanceof Character) {
0740: // jsp/18s6
0741: return ((Character) value).charValue();
0742: } else {
0743: ELException e = new ELException(L.l(
0744: "can't convert {0} to long.", value.getClass()
0745: .getName()));
0746:
0747: // error(e, env);
0748:
0749: // return 0;
0750:
0751: throw e;
0752: }
0753: }
0754:
0755: /**
0756: * Write to the stream.
0757: *
0758: * @param out the output stream
0759: * @param value the value to be written.
0760: *
0761: * @return true for null
0762: */
0763: public static boolean toStream(JspWriter out, Object value,
0764: boolean isEscaped) throws IOException {
0765: if (value == null)
0766: return true;
0767:
0768: if (isEscaped)
0769: toStreamEscaped(out, value);
0770: else
0771: toStream(out, value);
0772:
0773: return false;
0774: }
0775:
0776: /**
0777: * Write to the stream.
0778: *
0779: * @param out the output stream
0780: * @param value the value to be written.
0781: */
0782: public static void toStream(WriteStream out, Object value)
0783: throws IOException {
0784: if (value == null)
0785: return;
0786: else if (value instanceof String)
0787: out.print((String) value);
0788: else if (value instanceof Reader) {
0789: out.writeStream((Reader) value);
0790: } else
0791: out.print(value.toString());
0792: }
0793:
0794: /**
0795: * Write to the stream.
0796: *
0797: * @param out the output stream
0798: * @param value the value to be written.
0799: */
0800: public static void toStream(JspWriter out, Object value)
0801: throws IOException {
0802: if (value == null)
0803: return;
0804: else if (value instanceof String)
0805: out.print((String) value);
0806: else if (value instanceof Reader) {
0807: Reader reader = (Reader) value;
0808: int ch;
0809:
0810: while ((ch = reader.read()) > 0) {
0811: out.print((char) ch);
0812: }
0813: } else
0814: out.print(value.toString());
0815: }
0816:
0817: /**
0818: * Write to the *.java stream escaping Java reserved characters.
0819: *
0820: * @param out the output stream to the *.java code.
0821: *
0822: * @param value the value to be converted.
0823: */
0824: public static void printEscapedString(WriteStream os, String string)
0825: throws IOException {
0826: int length = string.length();
0827: for (int i = 0; i < length; i++) {
0828: char ch = string.charAt(i);
0829:
0830: switch (ch) {
0831: case '\\':
0832: os.print("\\\\");
0833: break;
0834: case '\n':
0835: os.print("\\n");
0836: break;
0837: case '\r':
0838: os.print("\\r");
0839: break;
0840: case '\"':
0841: os.print("\\\"");
0842: break;
0843: default:
0844: os.print((char) ch);
0845: break;
0846: }
0847: }
0848: }
0849:
0850: /**
0851: * Write to the stream.
0852: *
0853: * @param out the output stream
0854: * @param value the value to be written.
0855: */
0856: public static void toStreamEscaped(Writer out, Object value)
0857: throws IOException {
0858: if (value == null)
0859: return;
0860: else if (value instanceof Reader) {
0861: toStreamEscaped(out, (Reader) value);
0862: return;
0863: }
0864:
0865: String string = value.toString();
0866: int length = string.length();
0867: for (int i = 0; i < length; i++) {
0868: int ch = string.charAt(i);
0869:
0870: switch (ch) {
0871: case '<':
0872: out.write("<");
0873: break;
0874: case '>':
0875: out.write(">");
0876: break;
0877: case '&':
0878: out.write("&");
0879: break;
0880: case '\'':
0881: out.write("'");
0882: break;
0883: case '"':
0884: out.write(""");
0885: break;
0886: default:
0887: out.write((char) ch);
0888: break;
0889: }
0890: }
0891: }
0892:
0893: /**
0894: * Write to the stream escaping XML reserved characters.
0895: *
0896: * @param out the output stream.
0897: * @param value the value to be converted.
0898: */
0899: public static void toStreamEscaped(WriteStream out, Object value)
0900: throws IOException {
0901: if (value == null)
0902: return;
0903:
0904: String string = value.toString();
0905: int length = string.length();
0906: for (int i = 0; i < length; i++) {
0907: int ch = string.charAt(i);
0908:
0909: switch (ch) {
0910: case '<':
0911: out.print("<");
0912: break;
0913: case '>':
0914: out.print(">");
0915: break;
0916: case '&':
0917: out.print("&");
0918: break;
0919: case '\'':
0920: out.print("'");
0921: break;
0922: case '"':
0923: out.print(""");
0924: break;
0925: default:
0926: out.print((char) ch);
0927: break;
0928: }
0929: }
0930: }
0931:
0932: /**
0933: * Write to the stream escaping XML reserved characters.
0934: *
0935: * @param out the output stream.
0936: * @param value the value to be converted.
0937: */
0938: public static void toStreamEscaped(Writer out, Reader in)
0939: throws IOException {
0940: if (in == null)
0941: return;
0942:
0943: int ch;
0944: while ((ch = in.read()) >= 0) {
0945: switch (ch) {
0946: case '<':
0947: out.write("<");
0948: break;
0949: case '>':
0950: out.write(">");
0951: break;
0952: case '&':
0953: out.write("&");
0954: break;
0955: case '\'':
0956: out.write("'");
0957: break;
0958: case '"':
0959: out.write(""");
0960: break;
0961: default:
0962: out.write((char) ch);
0963: break;
0964: }
0965: }
0966: }
0967:
0968: /**
0969: * Write to the *.java stream escaping Java reserved characters.
0970: *
0971: * @param out the output stream to the *.java code.
0972: *
0973: * @param value the value to be converted.
0974: */
0975: public static void printEscaped(WriteStream os, ReadStream is)
0976: throws IOException {
0977: int ch;
0978:
0979: while ((ch = is.readChar()) >= 0) {
0980: switch (ch) {
0981: case '\\':
0982: os.print("\\\\");
0983: break;
0984: case '\n':
0985: os.print("\\n");
0986: break;
0987: case '\r':
0988: os.print("\\r");
0989: break;
0990: case '\"':
0991: os.print("\\\"");
0992: break;
0993: default:
0994: os.print((char) ch);
0995: break;
0996: }
0997: }
0998: }
0999:
1000: // XXX: does this belong in JSP?
1001: public static void setProperty(Object target, String property,
1002: Object value) throws ELException, JspException {
1003: if (target instanceof Map) {
1004: Map<String, Object> map = (Map) target;
1005:
1006: if (value != null)
1007: map.put(property, value);
1008: else
1009: map.remove(property);
1010: } else if (target != null) {
1011: Method method = null;
1012:
1013: try {
1014: method = BeanUtil.getSetMethod(target.getClass(),
1015: property);
1016: } catch (Exception e) {
1017: throw new JspException(e);
1018: }
1019:
1020: if (method == null)
1021: throw new JspException(L.l(
1022: "can't find property `{0}' in `{1}'", property,
1023: target.getClass()));
1024:
1025: Class type = method.getParameterTypes()[0];
1026:
1027: try {
1028: int code = _typeMap.get(type);
1029:
1030: switch (code) {
1031: case BOOLEAN:
1032: value = toBoolean(value, null) ? Boolean.TRUE
1033: : Boolean.FALSE;
1034: break;
1035:
1036: case BYTE:
1037: value = new Byte((byte) toLong(value, null));
1038: break;
1039:
1040: case SHORT:
1041: value = new Short((short) toLong(value, null));
1042: break;
1043:
1044: case INT:
1045: value = new Integer((int) toLong(value, null));
1046: break;
1047:
1048: case LONG:
1049: value = new Long((long) toLong(value, null));
1050: break;
1051:
1052: case FLOAT:
1053: value = new Float((float) toDouble(value, null));
1054: break;
1055:
1056: case DOUBLE:
1057: value = new Double((double) toDouble(value, null));
1058: break;
1059:
1060: case BOOLEAN_OBJ:
1061: if (value != null)
1062: value = toBoolean(value, null) ? Boolean.TRUE
1063: : Boolean.FALSE;
1064: break;
1065:
1066: case BYTE_OBJ:
1067: if (value != null)
1068: value = new Byte((byte) toLong(value, null));
1069: break;
1070:
1071: case SHORT_OBJ:
1072: if (value != null)
1073: value = new Short((short) toLong(value, null));
1074: break;
1075:
1076: case INT_OBJ:
1077: if (value != null)
1078: value = new Integer((int) toLong(value, null));
1079: break;
1080:
1081: case LONG_OBJ:
1082: if (value != null)
1083: value = new Long((long) toLong(value, null));
1084: break;
1085:
1086: case FLOAT_OBJ:
1087: if (value != null)
1088: value = new Float((float) toDouble(value, null));
1089: break;
1090:
1091: case DOUBLE_OBJ:
1092: if (value != null)
1093: value = new Double((double) toDouble(value,
1094: null));
1095: break;
1096:
1097: case STRING:
1098: if (value != null)
1099: value = String.valueOf(value);
1100: break;
1101:
1102: default:
1103: break;
1104: }
1105:
1106: method.invoke(target, new Object[] { value });
1107: } catch (Exception e) {
1108: throw new JspException(e);
1109: }
1110: } else {
1111: // jsp/1c2l and JSTL TCK for exception type
1112: throw new javax.servlet.jsp.JspException(L
1113: .l("null is an invalid c:set target value."));
1114: }
1115: }
1116:
1117: protected static boolean isDoubleString(Object obj) {
1118: if (!(obj instanceof String))
1119: return false;
1120:
1121: String s = (String) obj;
1122:
1123: int len = s.length();
1124: for (int i = 0; i < len; i++) {
1125: char ch = s.charAt(i);
1126:
1127: if (ch == '.' || ch == 'e' || ch == 'E')
1128: return true;
1129: }
1130:
1131: return false;
1132: }
1133:
1134: public static Object coerceToType(Object obj, Class<?> targetType)
1135: throws ELException {
1136: CoerceType type = _coerceMap.get(targetType);
1137:
1138: if (type == null)
1139: return obj;
1140:
1141: switch (type) {
1142: case BOOLEAN:
1143: return Expr.toBoolean(obj, null) ? Boolean.FALSE
1144: : Boolean.TRUE;
1145: case CHARACTER:
1146: return Expr.toCharacter(obj, null);
1147: case BYTE:
1148: return new Byte((byte) Expr.toLong(obj, null));
1149: case SHORT:
1150: return new Short((short) Expr.toLong(obj, null));
1151: case INTEGER:
1152: return new Integer((int) Expr.toLong(obj, null));
1153: case LONG:
1154: return new Long(Expr.toLong(obj, null));
1155: case FLOAT:
1156: return new Float((float) Expr.toDouble(obj, null));
1157: case DOUBLE:
1158: return new Double(Expr.toDouble(obj, null));
1159: case STRING:
1160: if (obj == null)
1161: return "";
1162: else
1163: return obj.toString();
1164: case BIG_DECIMAL:
1165: return Expr.toBigDecimal(obj, null);
1166: case BIG_INTEGER:
1167: return Expr.toBigInteger(obj, null);
1168: }
1169:
1170: return null;
1171: }
1172:
1173: /**
1174: * Returns an error object
1175: */
1176: public static Object error(Throwable e, ELContext env)
1177: throws ELException {
1178: if (env == null) {
1179: // jsp/1b56
1180: throw new ELException(e);
1181: } else if (env instanceof ExprEnv
1182: && ((ExprEnv) env).isIgnoreException()) {
1183: log.log(Level.FINE, e.toString(), e);
1184:
1185: return null;
1186: } else if (e instanceof RuntimeException)
1187: throw (RuntimeException) e;
1188: else
1189: throw new ELException(e);
1190: }
1191:
1192: public int hashCode() {
1193: return toString().hashCode();
1194: }
1195:
1196: public boolean equals(Object o) {
1197: if (this == o)
1198: return true;
1199: else if (!(o instanceof Expr))
1200: return false;
1201:
1202: return toString().equals(o.toString());
1203: }
1204:
1205: abstract public String toString();
1206:
1207: /**
1208: * Returns an error object
1209: */
1210: public static Object invocationError(Throwable e)
1211: throws ELException {
1212: if (e instanceof InvocationTargetException
1213: && e.getCause() != null)
1214: e = e.getCause();
1215:
1216: if (e instanceof RuntimeException)
1217: throw (RuntimeException) e;
1218: else if (e instanceof Error)
1219: throw (Error) e;
1220: else
1221: throw new ELException(e);
1222: }
1223:
1224: private enum CoerceType {
1225: BOOLEAN, CHARACTER, STRING, INTEGER, DOUBLE, LONG, FLOAT, SHORT, BYTE, BIG_INTEGER, BIG_DECIMAL, VOID
1226: };
1227:
1228: static {
1229: _coerceMap.put(boolean.class, CoerceType.BOOLEAN);
1230: _coerceMap.put(Boolean.class, CoerceType.BOOLEAN);
1231:
1232: _coerceMap.put(byte.class, CoerceType.BYTE);
1233: _coerceMap.put(Byte.class, CoerceType.BYTE);
1234:
1235: _coerceMap.put(short.class, CoerceType.SHORT);
1236: _coerceMap.put(Short.class, CoerceType.SHORT);
1237:
1238: _coerceMap.put(int.class, CoerceType.INTEGER);
1239: _coerceMap.put(Integer.class, CoerceType.INTEGER);
1240:
1241: _coerceMap.put(long.class, CoerceType.LONG);
1242: _coerceMap.put(Long.class, CoerceType.LONG);
1243:
1244: _coerceMap.put(float.class, CoerceType.FLOAT);
1245: _coerceMap.put(Float.class, CoerceType.FLOAT);
1246:
1247: _coerceMap.put(double.class, CoerceType.DOUBLE);
1248: _coerceMap.put(Double.class, CoerceType.DOUBLE);
1249:
1250: _coerceMap.put(char.class, CoerceType.CHARACTER);
1251: _coerceMap.put(Character.class, CoerceType.CHARACTER);
1252:
1253: _coerceMap.put(String.class, CoerceType.STRING);
1254:
1255: _coerceMap.put(BigDecimal.class, CoerceType.BIG_DECIMAL);
1256: _coerceMap.put(BigInteger.class, CoerceType.BIG_INTEGER);
1257:
1258: _coerceMap.put(void.class, CoerceType.VOID);
1259: }
1260:
1261: static {
1262: _typeMap.put(boolean.class, BOOLEAN);
1263: _typeMap.put(byte.class, BYTE);
1264: _typeMap.put(short.class, SHORT);
1265: _typeMap.put(int.class, INT);
1266: _typeMap.put(long.class, LONG);
1267: _typeMap.put(float.class, FLOAT);
1268: _typeMap.put(double.class, DOUBLE);
1269:
1270: _typeMap.put(Boolean.class, BOOLEAN_OBJ);
1271: _typeMap.put(Byte.class, BYTE_OBJ);
1272: _typeMap.put(Short.class, SHORT_OBJ);
1273: _typeMap.put(Integer.class, INT_OBJ);
1274: _typeMap.put(Long.class, LONG_OBJ);
1275: _typeMap.put(Float.class, FLOAT_OBJ);
1276: _typeMap.put(Double.class, DOUBLE_OBJ);
1277:
1278: _typeMap.put(String.class, STRING);
1279: }
1280: }
|