001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: * Free SoftwareFoundation, Inc.
023: * 59 Temple Place, Suite 330
024: * Boston, MA 02111-1307 USA
025: *
026: * @author Scott Ferguson
027: */
028:
029: package com.caucho.xpath.expr;
030:
031: import com.caucho.util.CharBuffer;
032: import com.caucho.util.L10N;
033: import com.caucho.xpath.Expr;
034: import com.caucho.xpath.ExprEnvironment;
035: import com.caucho.xpath.XPathException;
036:
037: import org.w3c.dom.Node;
038:
039: import java.lang.reflect.Method;
040: import java.util.ArrayList;
041:
042: /**
043: * Implements the object java extension functions.
044: */
045: public class ObjectJavaExpr extends Expr {
046: private static L10N L = new L10N(ObjectJavaExpr.class);
047:
048: private static final int J_BOOLEAN = 1;
049: private static final int J_BYTE = J_BOOLEAN + 1;
050: private static final int J_SHORT = J_BYTE + 1;
051: private static final int J_INT = J_SHORT + 1;
052: private static final int J_LONG = J_INT + 1;
053: private static final int J_FLOAT = J_LONG + 1;
054: private static final int J_DOUBLE = J_FLOAT + 1;
055: private static final int J_STRING = J_DOUBLE + 1;
056: private static final int J_OBJECT = J_STRING + 1;
057:
058: // Code of the expression defined in Expr
059: private Method method;
060:
061: private Expr objArg;
062: private ArrayList args;
063: private int[] argTypes;
064:
065: private int retType;
066:
067: /**
068: * Create a StringExpression with three arguments.
069: *
070: * @param method Java method
071: * @param args the arguments
072: */
073: public ObjectJavaExpr(Method method, Expr objArg, ArrayList args) {
074: this .method = method;
075: this .objArg = objArg;
076: this .args = args;
077:
078: argTypes = new int[args.size()];
079: Class[] paramClasses = method.getParameterTypes();
080: for (int i = 0; i < paramClasses.length; i++)
081: argTypes[i] = classToType(paramClasses[i]);
082:
083: retType = classToType(method.getReturnType());
084: }
085:
086: private int classToType(Class cl) {
087: if (boolean.class.equals(cl) || Boolean.class.equals(cl))
088: return J_BOOLEAN;
089: else if (byte.class.equals(cl) || Byte.class.equals(cl))
090: return J_BYTE;
091: else if (short.class.equals(cl) || Short.class.equals(cl))
092: return J_SHORT;
093: else if (int.class.equals(cl) || Integer.class.equals(cl))
094: return J_INT;
095: else if (long.class.equals(cl) || Long.class.equals(cl))
096: return J_LONG;
097: else if (float.class.equals(cl) || Float.class.equals(cl))
098: return J_FLOAT;
099: else if (double.class.equals(cl) || Double.class.equals(cl))
100: return J_DOUBLE;
101: else if (String.class.equals(cl))
102: return J_STRING;
103: else
104: return J_OBJECT;
105: }
106:
107: /**
108: * True if it returns a string.
109: */
110: public boolean isString() {
111: return retType == J_STRING;
112: }
113:
114: /**
115: * True if this returns a boolean.
116: */
117: public boolean isBoolean() {
118: return retType == J_BOOLEAN;
119: }
120:
121: /**
122: * True if this returns a boolean.
123: */
124: public boolean isNumber() {
125: return retType >= J_BYTE && retType <= J_DOUBLE;
126: }
127:
128: /**
129: * Evaluates the expression as an string.
130: *
131: * @param node the current node
132: * @param env the variable environment.
133: *
134: * @return the string representation of the expression.
135: */
136: public String evalString(Node node, ExprEnvironment env)
137: throws XPathException {
138: Object value = evalObject(node, env);
139:
140: return String.valueOf(value);
141: }
142:
143: /**
144: * Evaluate the expression as a boolean, i.e. evaluate it as a string
145: * and then convert it to a boolean.
146: *
147: * @param node the current node
148: * @param env the variable environment.
149: *
150: * @return the boolean representation of the expression.
151: */
152: public boolean evalBoolean(Node node, ExprEnvironment env)
153: throws XPathException {
154: return toBoolean(evalObject(node, env));
155: }
156:
157: /**
158: * Evaluate the expression as a double, i.e. evaluate it as a string
159: * and then convert it to a double.
160: *
161: * @param node the current node
162: * @param env the variable environment.
163: *
164: * @return the numeric representation of the expression.
165: */
166: public double evalNumber(Node node, ExprEnvironment env)
167: throws XPathException {
168: return toDouble(evalObject(node, env));
169: }
170:
171: /**
172: * Evaluate the expression as an object, i.e. return the string value.
173: *
174: * @param node the current node
175: * @param env the variable environment.
176: *
177: * @return the boolean representation of the expression.
178: */
179: public Object evalObject(Node node, ExprEnvironment env)
180: throws XPathException {
181: Object[] argArray = new Object[args.size()];
182:
183: Object obj = objArg.evalObject(node, env);
184:
185: if (obj == null
186: || !(method.getDeclaringClass().isAssignableFrom(obj
187: .getClass())))
188: throw new XPathException(L.l(
189: "Can't call method `{0}' on {1}.",
190: method.getName(), obj));
191:
192: for (int i = 0; i < argArray.length; i++) {
193: Expr expr = (Expr) args.get(i);
194:
195: switch (argTypes[i]) {
196: case J_BOOLEAN:
197: argArray[i] = new Boolean(expr.evalBoolean(node, env));
198: break;
199: case J_BYTE:
200: argArray[i] = new Byte((byte) expr
201: .evalNumber(node, env));
202: break;
203: case J_SHORT:
204: argArray[i] = new Short((short) expr.evalNumber(node,
205: env));
206: break;
207: case J_INT:
208: argArray[i] = new Integer((int) expr.evalNumber(node,
209: env));
210: break;
211: case J_LONG:
212: argArray[i] = new Long((long) expr
213: .evalNumber(node, env));
214: break;
215: case J_FLOAT:
216: argArray[i] = new Float((float) expr.evalNumber(node,
217: env));
218: break;
219: case J_DOUBLE:
220: argArray[i] = new Double(expr.evalNumber(node, env));
221: break;
222: case J_STRING:
223: argArray[i] = expr.evalString(node, env);
224: break;
225: default:
226: argArray[i] = expr.evalObject(node, env);
227: break;
228: }
229: }
230:
231: try {
232: return method.invoke(obj, argArray);
233: } catch (Exception e) {
234: throw new XPathException(e);
235: }
236: }
237:
238: /**
239: * Return the expression as a string. toString() returns a valid
240: * XPath expression. This lets applications like XSLT use toString()
241: * to print the string in the generated Java.
242: */
243: public String toString() {
244: CharBuffer cb = CharBuffer.allocate();
245: cb.append("java:");
246: cb.append(method.getDeclaringClass().getName());
247: cb.append(".");
248: cb.append(method.getName());
249:
250: cb.append("(");
251: cb.append(objArg);
252: for (int i = 0; i < args.size(); i++) {
253: cb.append(",");
254: cb.append(args.get(i));
255: }
256: cb.append(")");
257:
258: return cb.close();
259: }
260: }
|