KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > velocity > runtime > parser > node > ASTMethod


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

18
19 import org.apache.velocity.context.InternalContextAdapter;
20 import org.apache.velocity.runtime.parser.*;
21 import org.apache.velocity.util.introspection.IntrospectionCacheData;
22 import org.apache.velocity.util.introspection.VelMethod;
23 import org.apache.velocity.util.introspection.Info;
24
25 import org.apache.velocity.exception.MethodInvocationException;
26 import java.lang.reflect.InvocationTargetException JavaDoc;
27
28 import org.apache.velocity.app.event.EventCartridge;
29
30 /**
31  * ASTMethod.java
32  *
33  * Method support for references : $foo.method()
34  *
35  * NOTE :
36  *
37  * introspection is now done at render time.
38  *
39  * Please look at the Parser.jjt file which is
40  * what controls the generation of this class.
41  *
42  * @author <a HREF="mailto:jvanzyl@apache.org">Jason van Zyl</a>
43  * @author <a HREF="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
44  * @version $Id: ASTMethod.java,v 1.24.4.1 2004/03/03 23:22:59 geirm Exp $
45  */

46 public class ASTMethod extends SimpleNode
47 {
48     private String JavaDoc methodName = "";
49     private int paramCount = 0;
50
51     public ASTMethod(int id)
52     {
53         super(id);
54     }
55
56     public ASTMethod(Parser p, int id)
57     {
58         super(p, id);
59     }
60
61     /** Accept the visitor. **/
62     public Object JavaDoc jjtAccept(ParserVisitor visitor, Object JavaDoc data)
63     {
64         return visitor.visit(this, data);
65     }
66
67     /**
68      * simple init - init our subtree and get what we can from
69      * the AST
70      */

71     public Object JavaDoc init( InternalContextAdapter context, Object JavaDoc data)
72         throws Exception JavaDoc
73     {
74         super.init( context, data );
75
76         /*
77          * this is about all we can do
78          */

79
80         methodName = getFirstToken().image;
81         paramCount = jjtGetNumChildren() - 1;
82
83         return data;
84     }
85
86     /**
87      * invokes the method. Returns null if a problem, the
88      * actual return if the method returns something, or
89      * an empty string "" if the method returns void
90      */

91     public Object JavaDoc execute(Object JavaDoc o, InternalContextAdapter context)
92         throws MethodInvocationException
93     {
94         /*
95          * new strategy (strategery!) for introspection. Since we want
96          * to be thread- as well as context-safe, we *must* do it now,
97          * at execution time. There can be no in-node caching,
98          * but if we are careful, we can do it in the context.
99          */

100
101         VelMethod method = null;
102
103         Object JavaDoc [] params = new Object JavaDoc[paramCount];
104
105         try
106         {
107             /*
108              * check the cache
109              */

110
111             IntrospectionCacheData icd = context.icacheGet( this );
112             Class JavaDoc c = o.getClass();
113
114             /*
115              * like ASTIdentifier, if we have cache information, and the
116              * Class of Object o is the same as that in the cache, we are
117              * safe.
118              */

119
120             if ( icd != null && icd.contextData == c )
121             {
122                 /*
123                  * sadly, we do need recalc the values of the args, as this can
124                  * change from visit to visit
125                  */

126
127                 for (int j = 0; j < paramCount; j++)
128                     params[j] = jjtGetChild(j + 1).value(context);
129
130                 /*
131                  * and get the method from the cache
132                  */

133
134                 method = (VelMethod) icd.thingy;
135             }
136             else
137             {
138                 /*
139                  * otherwise, do the introspection, and then
140                  * cache it
141                  */

142
143                 for (int j = 0; j < paramCount; j++)
144                     params[j] = jjtGetChild(j + 1).value(context);
145
146                 method = rsvc.getUberspect().getMethod(o, methodName, params, new Info("",1,1));
147
148                 if (method != null)
149                 {
150                     icd = new IntrospectionCacheData();
151                     icd.contextData = c;
152                     icd.thingy = method;
153                     context.icachePut( this, icd );
154                 }
155             }
156  
157             /*
158              * if we still haven't gotten the method, either we are calling
159              * a method that doesn't exist (which is fine...) or I screwed
160              * it up.
161              */

162
163             if (method == null)
164                 return null;
165         }
166         catch( MethodInvocationException mie )
167         {
168             /*
169              * this can come from the doIntrospection(), as the arg values
170              * are evaluated to find the right method signature. We just
171              * want to propogate it here, not do anything fancy
172              */

173
174             throw mie;
175         }
176         catch( Exception JavaDoc e )
177         {
178             /*
179              * can come from the doIntropection() also, from Introspector
180              */

181
182             rsvc.error("ASTMethod.execute() : exception from introspection : " + e);
183             return null;
184         }
185
186         try
187         {
188             /*
189              * get the returned object. It may be null, and that is
190              * valid for something declared with a void return type.
191              * Since the caller is expecting something to be returned,
192              * as long as things are peachy, we can return an empty
193              * String so ASTReference() correctly figures out that
194              * all is well.
195              */

196
197             Object JavaDoc obj = method.invoke(o, params);
198             
199             if (obj == null)
200             {
201                 if( method.getReturnType() == Void.TYPE)
202                      return new String JavaDoc("");
203             }
204             
205             return obj;
206         }
207         catch( InvocationTargetException JavaDoc ite )
208         {
209             /*
210              * In the event that the invocation of the method
211              * itself throws an exception, we want to catch that
212              * wrap it, and throw. We don't log here as we want to figure
213              * out which reference threw the exception, so do that
214              * above
215              */

216
217             EventCartridge ec = context.getEventCartridge();
218
219             /*
220              * if we have an event cartridge, see if it wants to veto
221              * also, let non-Exception Throwables go...
222              */

223
224             if ( ec != null && ite.getTargetException() instanceof java.lang.Exception JavaDoc)
225             {
226                 try
227                 {
228                     return ec.methodException( o.getClass(), methodName, (Exception JavaDoc)ite.getTargetException() );
229                 }
230                 catch( Exception JavaDoc e )
231                 {
232                     throw new MethodInvocationException(
233                         "Invocation of method '"
234                         + methodName + "' in " + o.getClass()
235                         + " threw exception "
236                         + e.getClass() + " : " + e.getMessage(),
237                         e, methodName );
238                 }
239             }
240             else
241             {
242                 /*
243                  * no event cartridge to override. Just throw
244                  */

245
246                 throw new MethodInvocationException(
247                 "Invocation of method '"
248                 + methodName + "' in " + o.getClass()
249                 + " threw exception "
250                 + ite.getTargetException().getClass() + " : "
251                 + ite.getTargetException().getMessage(),
252                 ite.getTargetException(), methodName );
253             }
254         }
255         catch( Exception JavaDoc e )
256         {
257             rsvc.error("ASTMethod.execute() : exception invoking method '"
258                                + methodName + "' in " + o.getClass() + " : " + e );
259                                
260             return null;
261         }
262     }
263 }
264
Popular Tags