1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.commons.jelly.tags.core;
17
18 import java.lang.reflect.InvocationTargetException;
19 import java.lang.reflect.Method;
20 import java.util.ArrayList;
21 import java.util.List;
22
23 import org.apache.commons.jelly.JellyTagException;
24 import org.apache.commons.jelly.MissingAttributeException;
25 import org.apache.commons.jelly.TagSupport;
26 import org.apache.commons.jelly.XMLOutput;
27 import org.apache.commons.jelly.util.ClassLoaderUtils;
28
29 /***
30 * A Tag which can invoke a static method on a class, without an
31 * instance of the class being needed.
32 * <p>
33 * Like the {@link InvokeTag}, this tag can take a set of
34 * arguments using the {@link ArgTag}.
35 * </p>
36 * <p>
37 * The following attributes are required:<br />
38 * <ul>
39 * <li>var - The variable to assign the return of the method call to</li>
40 * <li>method - The name of the static method to invoke</li>
41 * <li>className - The name of the class containing the static method</li>
42 * </ul>
43 * </p>
44 *
45 * @author <a href="mailto:robert@bull-enterprises.com>Robert McIntosh</a>
46 * @version $Revision: 155420 $
47 */
48 public class InvokeStaticTag extends TagSupport implements ArgTagParent {
49
50 /*** the variable exported */
51 private String var;
52
53 /*** the variable where the method's exception is exported */
54 private String exceptionVar;
55
56 /*** the method to invoke */
57 private String methodName;
58
59 /*** the object to invoke the method on */
60 private String className;
61
62 private List paramTypes = new ArrayList();
63 private List paramValues = new ArrayList();
64
65 public InvokeStaticTag() {
66 }
67
68 /***
69 * Sets the name of the variable exported by this tag
70 *
71 * @param var The variable name
72 */
73 public void setVar(String var) {
74 this.var = var;
75 }
76
77 /*** Sets the name of a variable that exports the exception thrown by
78 * the method's invocation (if any)
79 */
80 public void setExceptionVar(String var) {
81 this.exceptionVar = var;
82 }
83
84 /***
85 * Sets the name of the method to invoke
86 *
87 * @param method The method name
88 */
89 public void setMethod(String methodName) {
90 this.methodName = methodName;
91 }
92
93 /***
94 * Sets the fully qualified class name containing the static method
95 *
96 * @param className The name of the class
97 */
98 public void setClassName(String className) {
99 this.className = className;
100 }
101
102 /***
103 * Adds an argument to supply to the method
104 *
105 * @param type The Class type of the argument
106 * @param value The value of the argument
107 */
108 public void addArgument(Class type, Object value) {
109 paramTypes.add(type);
110 paramValues.add(value);
111 }
112
113
114
115 public void doTag(XMLOutput output) throws JellyTagException {
116 try {
117 if ( null == methodName) {
118 throw new MissingAttributeException( "method" );
119 }
120 invokeBody(output);
121
122 Object[] values = paramValues.toArray();
123 Class[] types = (Class[])(paramTypes.toArray(new Class[paramTypes.size()]));
124 Method method = loadClass().getMethod( methodName, types );
125 Object result = method.invoke( null, values );
126 if(null != var) {
127 context.setVariable(var, result);
128 }
129
130 ArgTag parentArg = (ArgTag)(findAncestorWithClass(ArgTag.class));
131 if(null != parentArg) {
132 parentArg.setValue(result);
133 }
134 }
135 catch (ClassNotFoundException e) {
136 throw createLoadClassFailedException(e);
137 }
138 catch (NoSuchMethodException e) {
139 throw createLoadClassFailedException(e);
140 }
141 catch (IllegalAccessException e) {
142 throw createLoadClassFailedException(e);
143 }
144 catch (InvocationTargetException e) {
145 if(null != exceptionVar) {
146 context.setVariable(exceptionVar,e.getTargetException());
147 } else {
148 throw new JellyTagException("method " + methodName +
149 " threw exception: "+ e.getTargetException().getMessage(),
150 e.getTargetException() );
151 }
152 }
153 finally {
154 paramTypes.clear();
155 paramValues.clear();
156 }
157 }
158
159
160
161
162 /***
163 * Loads the class using either the class loader which loaded me or the
164 * current threads context class loader
165 */
166 protected Class loadClass() throws ClassNotFoundException {
167 return ClassLoaderUtils.loadClass(className, getClass());
168 }
169
170 /***
171 * Factory method to create a new JellyTagException instance from a given
172 * failure exception
173 * @param e is the exception which occurred attempting to load the class
174 * @return JellyTagException
175 */
176 protected JellyTagException createLoadClassFailedException(Exception e) {
177 return new JellyTagException(
178 "Could not load class: " + className + ". Reason: " + e, e
179 );
180 }
181 }
182