/* ActionNode.java Purpose: Description: History: Sat Sep 17 15:03:33 2005, Created by tomyeh Copyright (C) 2004 Potix Corporation. All Rights Reserved. {{IS_RIGHT This program is distributed under LGPL Version 2.1 in the hope that it will be useful, but WITHOUT ANY WARRANTY. }}IS_RIGHT */ package org.zkoss.web.servlet.dsp.impl; import java.io.IOException; import java.lang.reflect.Method; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.zkoss.lang.Classes; import org.zkoss.web.servlet.dsp.DspException; import org.zkoss.web.servlet.dsp.action.Action; import org.zkoss.xel.Expression; import org.zkoss.xel.XelException; /** * Represents an action node. * * @author tomyeh */ class ActionNode extends Node { private static final Logger log = LoggerFactory.getLogger(ActionNode.class); private final Class<?> _cls; private List<Attr> _attrs; private final int _nLines; /** * @param nLines which line this action is located. */ ActionNode(Class<?> cls, int nLines) { _cls = cls; _nLines = nLines; } void interpret(InterpretContext ic) throws DspException, IOException { final Action parent = ic.action; try { ic.action = newAction(); //1. apply attributes if (_attrs != null) for (Attr attr : _attrs) attr.apply(ic, ic.action); //2. render ic.action.render(new ActionContextImpl(ic, parent, this, _nLines), _children != null); } finally { ic.action = parent; } } /** Creates an instance of Action. */ private Action newAction() throws DspException { try { return (Action) _cls.newInstance(); } catch (Exception ex) { log.error("", ex); //Web server might 'eat' throw DspException.Aide.wrap(ex, "Failed to create " + _cls); } } /** Returns the line number */ int getLineNumber() { return _nLines; } /** Renders the nested fragment. */ void renderFragment(InterpretContext ic) throws DspException, IOException { if (_children == null) return; for (Iterator it = _children.iterator(); it.hasNext();) { ((Node) it.next()).interpret(ic); } } /** Adds an attribute. */ void addAttribute(String nm, String val, ParseContext ctx) throws NoSuchMethodException, ClassCastException, XelException { if (nm == null || val == null) throw new IllegalArgumentException("null"); if (_attrs == null) _attrs = new LinkedList<Attr>(); final Method mtd = (Method) Classes.getAccessibleObject(_cls, nm, new Class[] { null }, Classes.B_SET | Classes.B_PUBLIC_ONLY | Classes.B_METHOD_ONLY); final Class type = mtd.getParameterTypes()[0]; if (val.indexOf("${") >= 0) { _attrs.add(new Attr(mtd, ctx.getExpressionFactory().parseExpression(ctx, val, type))); } else { _attrs.add(new Attr(mtd, Classes.coerce(type, val))); } } private static class Attr { private final Method _method; private final Object _value; /** * @param val the value. Either Expression or String. */ private Attr(Method mtd, Object val) { _method = mtd; _value = val; } /** Applies this attribute to the specified action. */ private void apply(InterpretContext ic, Action action) throws DspException { final Object[] args = new Object[1]; try { if (_value instanceof Expression) { args[0] = ((Expression) _value).evaluate(ic.xelc); //if (log.finerable()) log.finer("attr "+_method.getName()+"="+_value+" to "+args[0]); } else { args[0] = _value; } _method.invoke(action, args); } catch (Exception ex) { log.error("", ex); //Web server might 'eat' throw DspException.Aide.wrap(ex, "Failed to invoke " + _method + " with " + args[0] + (args[0] != null ? " @" + args[0].getClass().getName() : "")); } } } public String toString() { return "Action[" + _cls.getName() + ']'; } }