View Javadoc

1   /*
2    * Copyright 2002,2004 The Apache Software Foundation.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
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     // Tag interface
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     // Tag interface
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