1 package org.apache.velocity.runtime.directive;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.BufferedReader;
23 import java.io.IOException;
24 import java.io.StringReader;
25 import java.io.Writer;
26 import java.util.HashMap;
27
28 import org.apache.commons.lang.StringUtils;
29 import org.apache.velocity.context.InternalContextAdapter;
30 import org.apache.velocity.context.VMContext;
31 import org.apache.velocity.exception.MethodInvocationException;
32 import org.apache.velocity.exception.TemplateInitException;
33 import org.apache.velocity.runtime.RuntimeConstants;
34 import org.apache.velocity.runtime.RuntimeServices;
35 import org.apache.velocity.runtime.parser.ParserTreeConstants;
36 import org.apache.velocity.runtime.parser.Token;
37 import org.apache.velocity.runtime.parser.node.ASTDirective;
38 import org.apache.velocity.runtime.parser.node.Node;
39 import org.apache.velocity.runtime.parser.node.SimpleNode;
40 import org.apache.velocity.runtime.visitor.VMReferenceMungeVisitor;
41
42
43
44
45
46
47
48
49
50 public class VelocimacroProxy extends Directive
51 {
52 private String macroName = "";
53 private String macroBody = "";
54 private String[] argArray = null;
55 private SimpleNode nodeTree = null;
56 private int numMacroArgs = 0;
57 private String namespace = "";
58
59 private boolean init = false;
60 private String[] callingArgs;
61 private int[] callingArgTypes;
62 private HashMap proxyArgHash = new HashMap();
63
64 private boolean strictArguments;
65
66
67
68
69
70 public String getName()
71 {
72 return macroName;
73 }
74
75
76
77
78
79
80 public int getType()
81 {
82 return LINE;
83 }
84
85
86
87
88
89 public void setName( String name )
90 {
91 macroName = name;
92 }
93
94
95
96
97
98 public void setArgArray( String [] arr )
99 {
100 argArray = arr;
101
102
103
104
105
106
107 numMacroArgs = argArray.length - 1;
108 }
109
110
111
112
113 public void setNodeTree( SimpleNode tree )
114 {
115 nodeTree = tree;
116 }
117
118
119
120
121
122 public int getNumArgs()
123 {
124 return numMacroArgs;
125 }
126
127
128
129
130
131
132
133 public void setMacrobody( String mb )
134 {
135 macroBody = mb;
136 }
137
138
139
140
141 public void setNamespace( String ns )
142 {
143 this.namespace = ns;
144 }
145
146
147
148
149
150
151
152
153
154
155 public boolean render( InternalContextAdapter context, Writer writer, Node node)
156 throws IOException, MethodInvocationException
157 {
158 try
159 {
160
161
162
163
164
165 if (nodeTree != null)
166 {
167 if ( !init )
168 {
169 nodeTree.init( context, rsvc);
170 init = true;
171 }
172
173
174
175
176
177 VMContext vmc = new VMContext( context, rsvc );
178
179 for( int i = 1; i < argArray.length; i++)
180 {
181
182
183
184
185
186 VMProxyArg arg = (VMProxyArg) proxyArgHash.get( argArray[i] );
187 vmc.addVMProxyArg( arg );
188 }
189
190
191
192
193
194 nodeTree.render( vmc, writer );
195 }
196 else
197 {
198 rsvc.getLog().error("VM error " + macroName + ". Null AST");
199 }
200 }
201
202
203
204
205 catch( MethodInvocationException e )
206 {
207 throw e;
208 }
209
210
211
212
213 catch( RuntimeException e )
214 {
215 throw e;
216 }
217
218 catch ( Exception e )
219 {
220
221 rsvc.getLog().error("VelocimacroProxy.render() : exception VM = #" +
222 macroName + "()", e);
223 }
224
225 return true;
226 }
227
228
229
230
231
232
233
234
235
236
237 public void init( RuntimeServices rs, InternalContextAdapter context, Node node)
238 throws TemplateInitException
239 {
240 super.init( rs, context, node );
241
242
243
244
245 strictArguments = rs.getConfiguration().getBoolean(RuntimeConstants.VM_ARGUMENTS_STRICT,false);
246
247
248
249
250
251 int i = node.jjtGetNumChildren();
252
253
254
255
256
257 if ( getNumArgs() != i )
258 {
259
260
261
262
263
264
265
266 for (Node parent = node.jjtGetParent(); parent != null; )
267 {
268 if ((parent instanceof ASTDirective) &&
269 StringUtils.equals(((ASTDirective) parent).getDirectiveName(), "macro"))
270 {
271 return;
272 }
273 parent = parent.jjtGetParent();
274 }
275
276 String errormsg = "VM #" + macroName + ": error : too " +
277 ((getNumArgs() > i) ? "few" : "many") +
278 " arguments to macro. Wanted " + getNumArgs() +
279 " got " + i;
280
281 if (strictArguments)
282 {
283
284
285
286
287 throw new TemplateInitException(errormsg,
288 context.getCurrentTemplateName(),
289 0,
290 0);
291 }
292 else
293 {
294 rsvc.getLog().error(errormsg);
295 return;
296 }
297 }
298
299
300
301
302
303 callingArgs = getArgArray( node );
304
305
306
307
308
309 setupMacro( callingArgs, callingArgTypes );
310 }
311
312
313
314
315
316
317
318
319 public boolean setupMacro( String[] callArgs, int[] callArgTypes )
320 {
321 setupProxyArgs( callArgs, callArgTypes );
322 parseTree( callArgs );
323
324 return true;
325 }
326
327
328
329
330
331
332 private void parseTree( String[] callArgs )
333 {
334 try
335 {
336 BufferedReader br = new BufferedReader( new StringReader( macroBody ) );
337
338
339
340
341
342 nodeTree = rsvc.parse( br, namespace, false );
343
344
345
346
347
348
349
350
351
352
353 HashMap hm = new HashMap();
354
355 for( int i = 1; i < argArray.length; i++)
356 {
357 String arg = callArgs[i-1];
358
359
360
361
362
363
364
365 if (arg.charAt(0) == '$')
366 {
367 hm.put( argArray[i], arg );
368 }
369 }
370
371
372
373
374
375
376 VMReferenceMungeVisitor v = new VMReferenceMungeVisitor( hm );
377 nodeTree.jjtAccept( v, null );
378 }
379
380
381
382 catch( RuntimeException e )
383 {
384 throw e;
385 }
386 catch ( Exception e )
387 {
388 rsvc.getLog().error("VelocimacroManager.parseTree() : exception " +
389 macroName, e);
390 }
391 }
392
393 private void setupProxyArgs( String[] callArgs, int [] callArgTypes )
394 {
395
396
397
398
399 for( int i = 1; i < argArray.length; i++)
400 {
401 VMProxyArg arg = new VMProxyArg( rsvc, argArray[i], callArgs[i-1], callArgTypes[i-1] );
402 proxyArgHash.put( argArray[i], arg );
403 }
404 }
405
406
407
408
409
410
411 private String[] getArgArray( Node node )
412 {
413 int numArgs = node.jjtGetNumChildren();
414
415 String args[] = new String[ numArgs ];
416 callingArgTypes = new int[numArgs];
417
418
419
420
421 int i = 0;
422 Token t = null;
423 Token tLast = null;
424
425 while( i < numArgs )
426 {
427 args[i] = "";
428
429
430
431
432
433 callingArgTypes[i] = node.jjtGetChild(i).getType();
434
435
436 if (false && node.jjtGetChild(i).getType() == ParserTreeConstants.JJTSTRINGLITERAL )
437 {
438 args[i] += node.jjtGetChild(i).getFirstToken().image.substring(1, node.jjtGetChild(i).getFirstToken().image.length() - 1);
439 }
440 else
441 {
442
443
444
445 t = node.jjtGetChild(i).getFirstToken();
446 tLast = node.jjtGetChild(i).getLastToken();
447
448 while( t != tLast )
449 {
450 args[i] += t.image;
451 t = t.next;
452 }
453
454
455
456
457 args[i] += t.image;
458 }
459 i++;
460 }
461 return args;
462 }
463 }
464
465
466
467
468
469
470
471
472
473