001: /* ActionNode.java
002:
003: {{IS_NOTE
004: Purpose:
005:
006: Description:
007:
008: History:
009: Sat Sep 17 15:03:33 2005, Created by tomyeh
010: }}IS_NOTE
011:
012: Copyright (C) 2004 Potix Corporation. All Rights Reserved.
013:
014: {{IS_RIGHT
015: This program is distributed under GPL Version 2.0 in the hope that
016: it will be useful, but WITHOUT ANY WARRANTY.
017: }}IS_RIGHT
018: */
019: package org.zkoss.web.servlet.dsp.impl;
020:
021: import java.lang.reflect.Method;
022: import java.util.List;
023: import java.util.LinkedList;
024: import java.util.Iterator;
025: import java.io.Writer;
026: import java.io.IOException;
027:
028: import org.zkoss.lang.D;
029: import org.zkoss.lang.Classes;
030: import org.zkoss.lang.Exceptions;
031: import org.zkoss.util.logging.Log;
032: import org.zkoss.xel.Expression;
033: import org.zkoss.xel.XelException;
034:
035: import org.zkoss.web.servlet.ServletException;
036: import org.zkoss.web.servlet.dsp.action.Action;
037:
038: /**
039: * Represents an action node.
040: *
041: * @author tomyeh
042: */
043: class ActionNode extends Node {
044: private static final Log log = Log.lookup(ActionNode.class);
045:
046: private final Class _cls;
047: private List _attrs;
048: private final int _nLines;
049:
050: /**
051: * @param nLines which line this action is located.
052: */
053: ActionNode(Class cls, int nLines) {
054: _cls = cls;
055: _nLines = nLines;
056: }
057:
058: void interpret(InterpretContext ic)
059: throws javax.servlet.ServletException, IOException {
060: final Action parent = ic.action;
061: try {
062: ic.action = newAction();
063: //1. apply attributes
064: if (_attrs != null) {
065: for (Iterator it = _attrs.iterator(); it.hasNext();)
066: ((Attr) it.next()).apply(ic, ic.action);
067: }
068:
069: //2. render
070: ic.action.render(new ActionContextImpl(ic, parent, this ,
071: _nLines), _children != null);
072: } finally {
073: ic.action = parent;
074: }
075: }
076:
077: /** Creates an instance of Action. */
078: private Action newAction() throws javax.servlet.ServletException {
079: try {
080: return (Action) _cls.newInstance();
081: } catch (Exception ex) {
082: throw new ServletException("Failed to create " + _cls
083: + ". Cause: " + Exceptions.getMessage(ex));
084: }
085: }
086:
087: /** Returns the line number */
088: int getLineNumber() {
089: return _nLines;
090: }
091:
092: /** Renders the nested fragment. */
093: void renderFragment(InterpretContext ic)
094: throws javax.servlet.ServletException, IOException {
095: if (_children == null)
096: return;
097: for (Iterator it = _children.iterator(); it.hasNext();) {
098: ((Node) it.next()).interpret(ic);
099: }
100: }
101:
102: /** Adds an attribute. */
103: void addAttribute(String nm, String val, ParseContext ctx)
104: throws NoSuchMethodException, ClassCastException,
105: XelException {
106: if (nm == null || val == null)
107: throw new IllegalArgumentException("null");
108: if (_attrs == null)
109: _attrs = new LinkedList();
110:
111: final Method mtd = (Method) Classes
112: .getAccessibleObject(_cls, nm, new Class[] { null },
113: Classes.B_SET | Classes.B_PUBLIC_ONLY
114: | Classes.B_METHOD_ONLY);
115: final Class type = mtd.getParameterTypes()[0];
116: if (val.indexOf("${") >= 0) {
117: _attrs.add(new Attr(mtd, ctx.getExpressionFactory()
118: .parseExpression(ctx, val, type)));
119: } else {
120: _attrs.add(new Attr(mtd, Classes.coerce(type, val)));
121: }
122: }
123:
124: private static class Attr {
125: private final Method _method;
126: private final Object _value;
127:
128: /**
129: * @param val the value. Either Expression or String.
130: */
131: private Attr(Method mtd, Object val) {
132: _method = mtd;
133: _value = val;
134: }
135:
136: /** Applies this attribute to the specified action. */
137: private void apply(InterpretContext ic, Action action)
138: throws javax.servlet.ServletException {
139: final Object[] args = new Object[1];
140: try {
141: if (_value instanceof Expression) {
142: args[0] = ((Expression) _value).evaluate(ic.xelc);
143: //if (D.ON && log.finerable()) log.finer("attr "+_method.getName()+"="+_value+" to "+args[0]);
144: } else {
145: args[0] = _value;
146: }
147: _method.invoke(action, args);
148: } catch (Exception ex) {
149: if (log.debugable())
150: log.debug(ex);
151: throw new ServletException("Failed to invoke "
152: + _method
153: + " with "
154: + args[0]
155: + (args[0] != null ? " @"
156: + args[0].getClass().getName() : "")
157: + ". Cause: " + ex.getClass().getName() + ", "
158: + Exceptions.getMessage(ex) + "\n"
159: + Exceptions.getBriefStackTrace(ex));
160: //Web container might not show the real cause, we have to
161: //make it part of the exception
162: }
163: }
164: }
165:
166: public String toString() {
167: return "Action[" + _cls.getName() + ']';
168: }
169: }
|