KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > velocity > runtime > directive > Macro


1 package org.apache.velocity.runtime.directive;
2
3 /*
4  * Copyright 2000-2002,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 java.io.Writer JavaDoc;
20 import java.io.IOException JavaDoc;
21
22 import java.util.List JavaDoc;
23 import java.util.ArrayList JavaDoc;
24
25 import org.apache.velocity.context.InternalContextAdapter;
26
27 import org.apache.velocity.runtime.parser.node.Node;
28 import org.apache.velocity.runtime.parser.node.NodeUtils;
29 import org.apache.velocity.runtime.parser.Token;
30 import org.apache.velocity.runtime.parser.ParseException;
31 import org.apache.velocity.runtime.parser.ParserTreeConstants;
32 import org.apache.velocity.runtime.RuntimeServices;
33
34 /**
35  * Macro.java
36  *
37  * Macro implements the macro definition directive of VTL.
38  *
39  * example :
40  *
41  * #macro( isnull $i )
42  * #if( $i )
43  * $i
44  * #end
45  * #end
46  *
47  * This object is used at parse time to mainly process and register the
48  * macro. It is used inline in the parser when processing a directive.
49  *
50  * @author <a HREF="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
51  * @version $Id: Macro.java,v 1.16.4.1 2004/03/03 23:22:56 geirm Exp $
52  */

53 public class Macro extends Directive
54 {
55     private static boolean debugMode = false;
56
57     /**
58      * Return name of this directive.
59      */

60     public String JavaDoc getName()
61     {
62         return "macro";
63     }
64     
65     /**
66      * Return type of this directive.
67      */

68     public int getType()
69     {
70         return BLOCK;
71     }
72     
73     /**
74      * render() doesn't do anything in the final output rendering.
75      * There is no output from a #macro() directive.
76      */

77     public boolean render(InternalContextAdapter context,
78                            Writer JavaDoc writer, Node node)
79         throws IOException JavaDoc
80     {
81         /*
82          * do nothing : We never render. The VelocimacroProxy object does that
83          */

84
85         return true;
86     }
87  
88     public void init(RuntimeServices rs, InternalContextAdapter context,
89                      Node node)
90        throws Exception JavaDoc
91     {
92         super.init(rs, context, node);
93
94         /*
95          * again, don't do squat. We want the AST of the macro
96          * block to hang off of this but we don't want to
97          * init it... it's useless...
98          */

99      
100         return;
101     }
102
103     /**
104      * Used by Parser.java to process VMs withing the parsing process
105      *
106      * processAndRegister() doesn't actually render the macro to the output
107      * Processes the macro body into the internal representation used by the
108      * VelocimacroProxy objects, and if not currently used, adds it
109      * to the macro Factory
110      */

111     public static void processAndRegister(RuntimeServices rs, Node node,
112                                           String JavaDoc sourceTemplate)
113         throws IOException JavaDoc, ParseException
114     {
115         /*
116          * There must be at least one arg to #macro,
117          * the name of the VM. Note that 0 following
118          * args is ok for naming blocks of HTML
119          */

120
121         int numArgs = node.jjtGetNumChildren();
122
123         /*
124          * this number is the # of args + 1. The + 1
125          * is for the block tree
126          */

127
128         if (numArgs < 2)
129         {
130             
131             /*
132              * error - they didn't name the macro or
133              * define a block
134              */

135             
136             rs.error("#macro error : Velocimacro must have name as 1st " +
137                 "argument to #macro(). #args = " + numArgs);
138
139             throw new MacroParseException("First argument to #macro() must be " +
140                     " macro name.");
141         }
142
143         /*
144          * lets make sure that the first arg is an ASTWord
145          */

146
147         int firstType = node.jjtGetChild(0).getType();
148
149         if(firstType != ParserTreeConstants.JJTWORD)
150         {
151             Token t = node.jjtGetChild(0).getFirstToken();
152
153             throw new MacroParseException("First argument to #macro() must be a"
154                     + " token without surrounding \' or \", which specifies"
155                     + " the macro name. Currently it is a "
156                     + ParserTreeConstants.jjtNodeName[firstType]);
157
158         }
159
160         /*
161          * get the arguments to the use of the VM
162          */

163
164         String JavaDoc argArray[] = getArgArray(node);
165      
166         /*
167          * now, try and eat the code block. Pass the root.
168          */

169         
170         List JavaDoc macroArray =
171             getASTAsStringArray(node.jjtGetChild(numArgs - 1));
172   
173         /*
174          * make a big string out of our macro
175          */

176   
177         StringBuffer JavaDoc temp = new StringBuffer JavaDoc();
178
179         for (int i=0; i < macroArray.size(); i++)
180         {
181             temp.append(macroArray.get(i));
182         }
183
184         String JavaDoc macroBody = temp.toString();
185    
186         /*
187          * now, try to add it. The Factory controls permissions,
188          * so just give it a whack...
189          */

190
191         boolean bRet = rs.addVelocimacro(argArray[0], macroBody,
192                         argArray, sourceTemplate);
193
194         return;
195     }
196
197   
198     /**
199      * creates an array containing the literal
200      * strings in the macro arguement
201      */

202     private static String JavaDoc[] getArgArray(Node node)
203     {
204         /*
205          * remember : this includes the block tree
206          */

207         
208         int numArgs = node.jjtGetNumChildren();
209     
210         numArgs--; // avoid the block tree...
211

212         String JavaDoc argArray[] = new String JavaDoc[numArgs];
213     
214         int i = 0;
215     
216         /*
217          * eat the args
218          */

219     
220         while (i < numArgs)
221         {
222             argArray[i] = node.jjtGetChild(i).getFirstToken().image;
223
224             /*
225              * trim off the leading $ for the args after the macro name.
226              * saves everyone else from having to do it
227              */

228
229             if (i > 0)
230             {
231                 if (argArray[i].startsWith("$"))
232                 {
233                     argArray[i] = argArray[i]
234                         .substring(1, argArray[i].length());
235                 }
236             }
237
238             i++;
239         }
240     
241         if (debugMode)
242         {
243             System.out.println("Macro.getArgArray() : #args = " + numArgs);
244             System.out.print(argArray[0] + "(");
245         
246             for (i = 1; i < numArgs; i++)
247             {
248                 System.out.print(" " + argArray[i]);
249             }
250
251             System.out.println(" )");
252         }
253     
254         return argArray;
255     }
256
257     /**
258      * Returns an array of the literal rep of the AST
259      */

260     private static List JavaDoc getASTAsStringArray(Node rootNode)
261     {
262         /*
263          * this assumes that we are passed in the root
264          * node of the code block
265          */

266     
267         Token t = rootNode.getFirstToken();
268         Token tLast = rootNode.getLastToken();
269
270         /*
271          * now, run down the part of the tree bounded by
272          * our first and last tokens
273          */

274
275         ArrayList JavaDoc list = new ArrayList JavaDoc();
276
277         t = rootNode.getFirstToken();
278
279         while (t != tLast)
280         {
281             list.add(NodeUtils.tokenLiteral(t));
282             t = t.next;
283         }
284
285         /*
286          * make sure we get the last one...
287          */

288
289         list.add(NodeUtils.tokenLiteral(t));
290
291         return list;
292     }
293 }
294
Popular Tags