EMMA Coverage Report (generated Tue May 18 22:13:27 CDT 2004)
[all classes][org.apache.velocity.runtime.parser.node]

COVERAGE SUMMARY FOR SOURCE FILE [ASTMethod.java]

nameclass, %method, %block, %line, %
ASTMethod.java100% (1/1)80%  (4/5)80%  (227/285)74%  (37/50)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class ASTMethod100% (1/1)80%  (4/5)80%  (227/285)74%  (37/50)
ASTMethod (int): void 0%   (0/1)0%   (0/10)0%   (0/4)
execute (Object, InternalContextAdapter): Object 100% (1/1)80%  (193/241)74%  (29/39)
ASTMethod (Parser, int): void 100% (1/1)100% (11/11)100% (4/4)
init (InternalContextAdapter, Object): Object 100% (1/1)100% (18/18)100% (4/4)
jjtAccept (ParserVisitor, Object): Object 100% (1/1)100% (5/5)100% (1/1)

1package 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 
19import org.apache.velocity.context.InternalContextAdapter;
20import org.apache.velocity.runtime.parser.*;
21import org.apache.velocity.util.introspection.IntrospectionCacheData;
22import org.apache.velocity.util.introspection.VelMethod;
23import org.apache.velocity.util.introspection.Info;
24 
25import org.apache.velocity.exception.MethodInvocationException;
26import java.lang.reflect.InvocationTargetException;
27 
28import 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 */
46public class ASTMethod extends SimpleNode
47{
48    private String 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 jjtAccept(ParserVisitor visitor, Object 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 init(  InternalContextAdapter context, Object data)
72        throws Exception
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 execute(Object 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 [] params = new Object[paramCount];
104 
105        try
106        {
107            /*
108             *   check the cache 
109             */
110 
111            IntrospectionCacheData icd =  context.icacheGet( this );
112            Class 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 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 obj = method.invoke(o, params);
198            
199            if (obj == null)
200            {
201                if( method.getReturnType() == Void.TYPE)
202                     return new String("");
203            }
204            
205            return obj;
206        }
207        catch( InvocationTargetException 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)
225            {
226                try
227                {
228                    return ec.methodException( o.getClass(), methodName, (Exception)ite.getTargetException() );
229                }
230                catch( Exception 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 e )
256        {
257            rsvc.error("ASTMethod.execute() : exception invoking method '" 
258                               + methodName + "' in " + o.getClass() + " : "  + e );
259                               
260            return null;
261        }            
262    }
263}

[all classes][org.apache.velocity.runtime.parser.node]
EMMA 2.0.4015 (stable) (C) Vladimir Roubtsov