/* 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() + ']';
}
}