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

COVERAGE SUMMARY FOR SOURCE FILE [VelocimacroProxy.java]

nameclass, %method, %block, %line, %
VelocimacroProxy.java100% (1/1)87%  (13/15)85%  (358/420)89%  (75/84)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class VelocimacroProxy100% (1/1)87%  (13/15)85%  (358/420)89%  (75/84)
getName (): String 0%   (0/1)0%   (0/3)0%   (0/1)
getType (): int 0%   (0/1)0%   (0/2)0%   (0/1)
render (InternalContextAdapter, Writer, Node): boolean 100% (1/1)59%  (54/92)69%  (11/16)
parseTree (String []): void 100% (1/1)78%  (63/81)85%  (11/13)
init (RuntimeServices, InternalContextAdapter, Node): void 100% (1/1)98%  (56/57)100% (8/8)
VelocimacroProxy (): void 100% (1/1)100% (29/29)100% (9/9)
getArgArray (Node): String [] 100% (1/1)100% (78/78)100% (17/17)
getNumArgs (): int 100% (1/1)100% (3/3)100% (1/1)
setArgArray (String []): void 100% (1/1)100% (11/11)100% (3/3)
setMacrobody (String): void 100% (1/1)100% (4/4)100% (2/2)
setName (String): void 100% (1/1)100% (4/4)100% (2/2)
setNamespace (String): void 100% (1/1)100% (4/4)100% (2/2)
setNodeTree (SimpleNode): void 100% (1/1)100% (4/4)100% (2/2)
setupMacro (String [], int []): boolean 100% (1/1)100% (9/9)100% (3/3)
setupProxyArgs (String [], int []): void 100% (1/1)100% (39/39)100% (4/4)

1package org.apache.velocity.runtime.directive;
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 java.io.Writer;
20import java.io.IOException;
21import java.io.BufferedReader;
22import java.io.StringReader;
23 
24import java.util.HashMap;
25 
26import org.apache.velocity.context.InternalContextAdapter;
27import org.apache.velocity.context.VMContext;
28 
29import org.apache.velocity.runtime.visitor.VMReferenceMungeVisitor;
30import org.apache.velocity.runtime.RuntimeServices;
31import org.apache.velocity.runtime.parser.node.Node;
32import org.apache.velocity.runtime.parser.Token;
33import org.apache.velocity.runtime.parser.ParserTreeConstants;
34import org.apache.velocity.runtime.parser.node.SimpleNode;
35import org.apache.velocity.util.StringUtils;
36 
37import org.apache.velocity.exception.MethodInvocationException;
38 
39/**
40 *  VelocimacroProxy.java
41 *
42 *   a proxy Directive-derived object to fit with the current directive system
43 *
44 * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
45 * @version $Id: VelocimacroProxy.java,v 1.27.4.1 2004/03/03 23:22:56 geirm Exp $ 
46 */
47public class VelocimacroProxy extends Directive
48{
49    private String macroName = "";
50    private String macroBody = "";
51    private String[] argArray = null;
52    private SimpleNode nodeTree = null;
53    private int numMacroArgs = 0;
54    private String namespace = "";
55 
56    private boolean init = false;
57    private String[] callingArgs;
58    private int[]  callingArgTypes;
59    private HashMap proxyArgHash = new HashMap();
60 
61 
62    /**
63     * Return name of this Velocimacro.
64     */
65    public String getName() 
66    { 
67        return  macroName; 
68    }
69    
70    /**
71     * Velocimacros are always LINE
72     * type directives.
73     */
74    public int getType()
75    { 
76        return LINE; 
77    }
78 
79    /**
80     *   sets the directive name of this VM
81     */
82    public void setName( String name )
83    {
84        macroName = name;
85    }
86   
87    /**
88     *  sets the array of arguments specified in the macro definition
89     */
90    public void setArgArray( String [] arr )
91    {
92        argArray = arr;
93 
94        /*
95         *  get the arg count from the arg array.  remember that the arg array 
96         *  has the macro name as it's 0th element
97         */
98 
99        numMacroArgs = argArray.length - 1;
100    }
101 
102    public void setNodeTree( SimpleNode tree )
103    {
104        nodeTree = tree;
105    }
106 
107    /**
108     *  returns the number of ars needed for this VM
109     */
110    public int getNumArgs()
111    {
112        return numMacroArgs;
113    }
114 
115    /**
116     *   Sets the orignal macro body.  This is simply the cat of the macroArray, but the 
117     *   Macro object creates this once during parsing, and everyone shares it.
118     *   Note : it must not be modified.
119     */
120    public void setMacrobody( String mb )
121    {
122        macroBody = mb;
123    }
124 
125    public void setNamespace( String ns )
126    {
127        this.namespace = ns;
128    }
129 
130    /**
131     *   Renders the macro using the context
132     */
133    public boolean render( InternalContextAdapter context, Writer writer, Node node)
134        throws IOException, MethodInvocationException
135    {
136        try 
137        {
138            /*
139             *  it's possible the tree hasn't been parsed yet, so get 
140             *  the VMManager to parse and init it
141             */
142       
143            if (nodeTree != null)
144            {
145                if ( !init )
146                {
147                    nodeTree.init( context, rsvc);
148                    init = true;
149                }
150                
151                /*
152                 *  wrap the current context and add the VMProxyArg objects
153                 */
154 
155                VMContext vmc = new VMContext( context, rsvc );
156 
157                for( int i = 1; i < argArray.length; i++)
158                {
159                    /*
160                     *  we can do this as VMProxyArgs don't change state. They change
161                     *  the context.
162                     */
163 
164                    VMProxyArg arg = (VMProxyArg) proxyArgHash.get( argArray[i] ); 
165                    vmc.addVMProxyArg( arg );
166                }
167         
168                /*
169                 *  now render the VM
170                 */
171 
172                nodeTree.render( vmc, writer );               
173            }
174            else
175            {
176                rsvc.error( "VM error : " + macroName + ". Null AST");
177            }
178        } 
179        catch ( Exception e ) 
180        {
181            /*
182             *  if it's a MIE, it came from the render.... throw it...
183             */
184 
185            if ( e instanceof MethodInvocationException)
186            {
187                throw (MethodInvocationException) e;
188            }
189 
190            rsvc.error("VelocimacroProxy.render() : exception VM = #" + macroName + 
191            "() : "  + StringUtils.stackTrace(e));
192        }
193 
194        return true;
195    }
196 
197    /**
198     *   The major meat of VelocimacroProxy, init() checks the # of arguments, patches the
199     *   macro body, renders the macro into an AST, and then inits the AST, so it is ready 
200     *   for quick rendering.  Note that this is only AST dependant stuff. Not context.
201     */
202    public void init( RuntimeServices rs, InternalContextAdapter context, Node node) 
203       throws Exception
204    {
205        super.init( rs, context, node );
206 
207        /*
208         *  how many args did we get?
209         */
210       
211        int i  = node.jjtGetNumChildren();
212        
213        /*
214         *  right number of args?
215         */        
216     
217        if ( getNumArgs() != i ) 
218        {
219            rsvc.error("VM #" + macroName + ": error : too " 
220                       + ( (getNumArgs() > i) ? "few" : "many") + " arguments to macro. Wanted " 
221                       + getNumArgs() + " got " + i );
222 
223            return;
224        }
225 
226        /*
227         *  get the argument list to the instance use of the VM
228         */
229 
230         callingArgs = getArgArray( node );
231       
232        /*
233         *  now proxy each arg in the context
234         */
235 
236         setupMacro( callingArgs, callingArgTypes );
237         return;
238    }
239 
240    /**
241     *  basic VM setup.  Sets up the proxy args for this
242     *  use, and parses the tree
243     */
244    public boolean setupMacro( String[] callArgs, int[] callArgTypes )
245    {
246        setupProxyArgs( callArgs, callArgTypes );
247        parseTree( callArgs );
248 
249        return true;
250    }
251 
252    /**
253     *   parses the macro.  We need to do this here, at init time, or else
254     *   the local-scope template feature is hard to get to work :)
255     */
256    private void parseTree( String[] callArgs )
257    {
258        try 
259        {                
260            BufferedReader br = new BufferedReader( new StringReader( macroBody ) );
261 
262            /*
263             *  now parse the macro - and don't dump the namespace
264             */
265 
266            nodeTree = rsvc.parse( br, namespace, false );
267 
268            /*
269             *  now, to make null references render as proper schmoo
270             *  we need to tweak the tree and change the literal of
271             *  the appropriate references
272             *
273             *  we only do this at init time, so it's the overhead
274             *  is irrelevant
275             */
276 
277            HashMap hm = new HashMap();
278 
279            for( int i = 1; i < argArray.length; i++)
280            {
281                String arg = callArgs[i-1];
282 
283                /*
284                 *  if the calling arg is indeed a reference
285                 *  then we add to the map.  We ignore other
286                 *  stuff
287                 */
288 
289                if (arg.charAt(0) == '$')
290                {
291                    hm.put( argArray[i], arg );
292                }
293            }
294 
295            /*
296             *  now make one of our reference-munging visitor, and 
297             *  let 'er rip
298             */
299 
300            VMReferenceMungeVisitor v = new VMReferenceMungeVisitor( hm );
301            nodeTree.jjtAccept( v, null );
302        } 
303        catch ( Exception e ) 
304        {
305            rsvc.error("VelocimacroManager.parseTree() : exception " + macroName + 
306                          " : "  + StringUtils.stackTrace(e));
307        }
308    }
309  
310    private void setupProxyArgs( String[] callArgs, int [] callArgTypes )
311    {
312        /*
313         * for each of the args, make a ProxyArg
314         */
315 
316        for( int i = 1; i < argArray.length; i++)
317        {
318            VMProxyArg arg = new VMProxyArg( rsvc, argArray[i], callArgs[i-1], callArgTypes[i-1] );
319            proxyArgHash.put( argArray[i], arg );
320        }
321    }
322  
323    /**
324     *   gets the args to the VM from the instance-use AST
325     */
326    private String[] getArgArray( Node node )
327    {
328        int numArgs = node.jjtGetNumChildren();
329        
330        String args[] = new String[ numArgs ];
331        callingArgTypes = new int[numArgs];
332 
333        /*
334         *  eat the args
335         */
336        int i = 0;
337        Token t = null;
338        Token tLast = null;
339    
340        while( i <  numArgs ) 
341        {
342            args[i] = "";
343            /*
344             *  we want string literalss to lose the quotes.  #foo( "blargh" ) should have 'blargh' patched 
345             *  into macro body.  So for each arg in the use-instance, treat the stringlierals specially...
346             */
347 
348            callingArgTypes[i] = node.jjtGetChild(i).getType();
349 
350           
351            if (false &&  node.jjtGetChild(i).getType() == ParserTreeConstants.JJTSTRINGLITERAL )
352            {
353                args[i] += node.jjtGetChild(i).getFirstToken().image.substring(1, node.jjtGetChild(i).getFirstToken().image.length() - 1);
354            }
355            else
356            {
357                /*
358                 *  just wander down the token list, concatenating everything together
359                 */
360                t = node.jjtGetChild(i).getFirstToken();
361                tLast = node.jjtGetChild(i).getLastToken();
362 
363                while( t != tLast ) 
364                {
365                    args[i] += t.image;
366                    t = t.next;
367                }
368 
369                /*
370                 *  don't forget the last one... :)
371                 */
372                args[i] += t.image;
373            }
374            i++;
375         }
376        return args;
377    }
378}
379 
380 
381 
382 
383 
384 
385 
386 
387 
388 

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