1 package org.apache.velocity.runtime;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.StringReader;
23 import java.util.HashMap;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Vector;
27 import java.util.ArrayList;
28
29 import org.apache.commons.lang.StringUtils;
30 import org.apache.velocity.Template;
31 import org.apache.velocity.exception.VelocityException;
32 import org.apache.velocity.runtime.directive.Directive;
33 import org.apache.velocity.runtime.directive.Macro;
34 import org.apache.velocity.runtime.directive.VelocimacroProxy;
35 import org.apache.velocity.runtime.log.LogDisplayWrapper;
36 import org.apache.velocity.runtime.parser.ParseException;
37 import org.apache.velocity.runtime.parser.node.Node;
38
39
40
41
42
43
44
45
46
47 public class VelocimacroFactory
48 {
49
50
51
52 private final RuntimeServices rsvc;
53
54
55
56
57 private final LogDisplayWrapper log;
58
59
60
61
62
63 private VelocimacroManager vmManager = null;
64
65
66
67
68
69 private boolean replaceAllowed = false;
70
71
72
73
74
75
76
77 private boolean addNewAllowed = true;
78
79
80
81
82 private boolean templateLocal = false;
83
84
85
86
87
88 private boolean autoReloadLibrary = false;
89
90
91
92
93 private List macroLibVec = null;
94
95
96
97
98
99 private Map libModMap;
100
101
102
103
104
105
106 public VelocimacroFactory(final RuntimeServices rsvc)
107 {
108 this.rsvc = rsvc;
109 this.log = new LogDisplayWrapper(rsvc.getLog(), "Velocimacro : ",
110 rsvc.getBoolean(RuntimeConstants.VM_MESSAGES_ON, true));
111
112
113
114
115
116 libModMap = new HashMap();
117 vmManager = new VelocimacroManager(rsvc);
118 }
119
120
121
122
123
124 public void initVelocimacro()
125 {
126
127
128
129 synchronized(this)
130 {
131 log.trace("initialization starting.");
132
133
134
135
136 setReplacementPermission(true);
137
138
139
140
141
142 vmManager.setNamespaceUsage(false);
143
144
145
146
147
148
149
150 Object libfiles = rsvc.getProperty(RuntimeConstants.VM_LIBRARY);
151
152 if (libfiles == null)
153 {
154 log.debug("\"" + RuntimeConstants.VM_LIBRARY +
155 "\" is not set. Trying default library: " +
156 RuntimeConstants.VM_LIBRARY_DEFAULT);
157
158
159 if (rsvc.getLoaderNameForResource(RuntimeConstants.VM_LIBRARY_DEFAULT) != null)
160 {
161 libfiles = RuntimeConstants.VM_LIBRARY_DEFAULT;
162 }
163 else
164 {
165 log.debug("Default library not found.");
166 }
167 }
168
169 if(libfiles != null)
170 {
171 macroLibVec = new ArrayList();
172 if (libfiles instanceof Vector)
173 {
174 macroLibVec.addAll((Vector)libfiles);
175 }
176 else if (libfiles instanceof String)
177 {
178 macroLibVec.add(libfiles);
179 }
180
181 for(int i = 0, is = macroLibVec.size(); i < is; i++)
182 {
183 String lib = (String) macroLibVec.get(i);
184
185
186
187
188
189 if (StringUtils.isNotEmpty(lib))
190 {
191
192
193
194
195
196 vmManager.setRegisterFromLib(true);
197
198 log.debug("adding VMs from VM library : " + lib);
199
200 try
201 {
202 Template template = rsvc.getTemplate(lib);
203
204
205
206
207
208
209
210 Twonk twonk = new Twonk();
211 twonk.template = template;
212 twonk.modificationTime = template.getLastModified();
213 libModMap.put(lib, twonk);
214 }
215 catch (Exception e)
216 {
217 String msg = "Velocimacro : Error using VM library : " + lib;
218 log.error(true, msg, e);
219 throw new VelocityException(msg, e);
220 }
221
222 log.trace("VM library registration complete.");
223
224 vmManager.setRegisterFromLib(false);
225 }
226 }
227 }
228
229
230
231
232
233
234
235
236
237
238
239
240 setAddMacroPermission(true);
241
242 if (!rsvc.getBoolean( RuntimeConstants.VM_PERM_ALLOW_INLINE, true))
243 {
244 setAddMacroPermission(false);
245
246 log.debug("allowInline = false : VMs can NOT be defined inline in templates");
247 }
248 else
249 {
250 log.debug("allowInline = true : VMs can be defined inline in templates");
251 }
252
253
254
255
256
257
258
259 setReplacementPermission(false);
260
261 if (rsvc.getBoolean(
262 RuntimeConstants.VM_PERM_ALLOW_INLINE_REPLACE_GLOBAL, false))
263 {
264 setReplacementPermission(true);
265
266 log.debug("allowInlineToOverride = true : VMs " +
267 "defined inline may replace previous VM definitions");
268 }
269 else
270 {
271 log.debug("allowInlineToOverride = false : VMs " +
272 "defined inline may NOT replace previous VM definitions");
273 }
274
275
276
277
278
279 vmManager.setNamespaceUsage(true);
280
281
282
283
284 setTemplateLocalInline(rsvc.getBoolean(
285 RuntimeConstants.VM_PERM_INLINE_LOCAL, false));
286
287 if (getTemplateLocalInline())
288 {
289 log.debug("allowInlineLocal = true : VMs " +
290 "defined inline will be local to their defining template only.");
291 }
292 else
293 {
294 log.debug("allowInlineLocal = false : VMs " +
295 "defined inline will be global in scope if allowed.");
296 }
297
298 vmManager.setTemplateLocalInlineVM(getTemplateLocalInline());
299
300
301
302
303 setAutoload(rsvc.getBoolean(RuntimeConstants.VM_LIBRARY_AUTORELOAD, false));
304
305 if (getAutoload())
306 {
307 log.debug("autoload on : VM system " +
308 "will automatically reload global library macros");
309 }
310 else
311 {
312 log.debug("autoload off : VM system " +
313 "will not automatically reload global library macros");
314 }
315
316 log.trace("Velocimacro : initialization complete.");
317 }
318 }
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333 public boolean addVelocimacro(String name, String macroBody,
334 String argArray[], String sourceTemplate)
335 {
336
337
338
339
340
341
342
343
344 if (name == null || macroBody == null || argArray == null ||
345 sourceTemplate == null)
346 {
347 String msg = "VM '"+name+"' addition rejected : ";
348 if (name == null)
349 {
350 msg += "name";
351 }
352 else if (macroBody == null)
353 {
354 msg += "macroBody";
355 }
356 else if (argArray == null)
357 {
358 msg += "argArray";
359 }
360 else
361 {
362 msg += "sourceTemplate";
363 }
364 msg += " argument was null";
365 log.error(msg);
366 throw new NullPointerException(msg);
367 }
368
369
370
371
372
373 if (!canAddVelocimacro(name, sourceTemplate))
374 {
375 return false;
376 }
377
378 synchronized (this)
379 {
380 try
381 {
382 Node macroRootNode = rsvc.parse(new StringReader(macroBody), sourceTemplate);
383
384 vmManager.addVM(name, macroRootNode, argArray, sourceTemplate, replaceAllowed);
385 }
386 catch (ParseException ex)
387 {
388
389 throw new RuntimeException(ex.toString());
390 }
391 }
392
393 if (log.isDebugEnabled())
394 {
395 StringBuffer msg = new StringBuffer("added ");
396 Macro.macroToString(msg, argArray);
397 msg.append(" : source = ").append(sourceTemplate);
398 log.debug(msg.toString());
399 }
400
401 return true;
402 }
403
404
405
406
407
408
409
410
411
412
413
414 public boolean addVelocimacro(String name, Node macroBody,
415 String argArray[], String sourceTemplate)
416 {
417
418
419
420
421
422
423
424
425
426
427 if (name == null || macroBody == null || argArray == null ||
428 sourceTemplate == null)
429 {
430 String msg = "VM '"+name+"' addition rejected : ";
431 if (name == null)
432 {
433 msg += "name";
434 }
435 else if (macroBody == null)
436 {
437 msg += "macroBody";
438 }
439 else if (argArray == null)
440 {
441 msg += "argArray";
442 }
443 else
444 {
445 msg += "sourceTemplate";
446 }
447 msg += " argument was null";
448 log.error(msg);
449 throw new NullPointerException(msg);
450 }
451
452
453
454
455
456 if (!canAddVelocimacro(name, sourceTemplate))
457 {
458 return false;
459 }
460
461 synchronized(this)
462 {
463 vmManager.addVM(name, macroBody, argArray, sourceTemplate, replaceAllowed);
464 }
465 return(true);
466 }
467
468
469
470
471
472
473
474
475
476
477 private synchronized boolean canAddVelocimacro(String name, String sourceTemplate)
478 {
479
480
481
482
483
484 if (autoReloadLibrary && (macroLibVec != null))
485 {
486 if( macroLibVec.contains(sourceTemplate) )
487 return true;
488 }
489
490
491
492
493
494
495
496 if (!addNewAllowed)
497 {
498 log.warn("VM addition rejected : "+name+" : inline VMs not allowed.");
499 return false;
500 }
501
502
503
504
505 if (!templateLocal)
506 {
507
508
509
510
511
512
513
514
515 if (!replaceAllowed && isVelocimacro(name, sourceTemplate))
516 {
517
518
519
520
521
522 if (log.isDebugEnabled())
523 log.debug("VM addition rejected : "+name+" : inline not allowed to replace existing VM");
524 return false;
525 }
526 }
527
528 return true;
529 }
530
531
532
533
534
535
536
537 public boolean isVelocimacro(String vm, String sourceTemplate)
538 {
539
540 return(vmManager.get(vm, sourceTemplate) != null);
541 }
542
543
544
545
546
547
548
549
550
551 public Directive getVelocimacro(String vmName, String sourceTemplate)
552 {
553 return(getVelocimacro(vmName, sourceTemplate, null));
554 }
555
556
557
558
559 public Directive getVelocimacro(String vmName, String sourceTemplate, String renderingTemplate)
560 {
561 VelocimacroProxy vp = null;
562
563 vp = vmManager.get(vmName, sourceTemplate, renderingTemplate);
564
565
566
567
568
569 if (vp != null && autoReloadLibrary )
570 {
571 synchronized (this)
572 {
573
574
575
576
577
578 String lib = vmManager.getLibraryName(vmName, sourceTemplate);
579
580 if (lib != null)
581 {
582 try
583 {
584
585
586
587
588 Twonk tw = (Twonk) libModMap.get(lib);
589
590 if (tw != null)
591 {
592 Template template = tw.template;
593
594
595
596
597
598
599
600 long tt = tw.modificationTime;
601 long ft = template.getResourceLoader().getLastModified(template);
602
603 if (ft > tt)
604 {
605 log.debug("auto-reloading VMs from VM library : " + lib);
606
607
608
609
610
611
612
613
614
615 tw.modificationTime = ft;
616
617 template = rsvc.getTemplate(lib);
618
619
620
621
622
623 tw.template = template;
624 tw.modificationTime = template.getLastModified();
625
626
627
628
629
630
631 }
632 }
633 }
634 catch (Exception e)
635 {
636 String msg = "Velocimacro : Error using VM library : " + lib;
637 log.error(true, msg, e);
638 throw new VelocityException(msg, e);
639 }
640
641 vp = vmManager.get(vmName, sourceTemplate, renderingTemplate);
642 }
643 }
644 }
645
646 return vp;
647 }
648
649
650
651
652
653
654
655 public boolean dumpVMNamespace(String namespace)
656 {
657 return vmManager.dumpNamespace(namespace);
658 }
659
660
661
662
663
664
665 private void setTemplateLocalInline(boolean b)
666 {
667 templateLocal = b;
668 }
669
670 private boolean getTemplateLocalInline()
671 {
672 return templateLocal;
673 }
674
675
676
677
678 private boolean setAddMacroPermission(final boolean addNewAllowed)
679 {
680 boolean b = this.addNewAllowed;
681 this.addNewAllowed = addNewAllowed;
682 return b;
683 }
684
685
686
687
688 private boolean setReplacementPermission(boolean arg)
689 {
690 boolean b = replaceAllowed;
691 replaceAllowed = arg;
692 vmManager.setInlineReplacesGlobal(arg);
693 return b;
694 }
695
696
697
698
699
700 private void setAutoload(boolean b)
701 {
702 autoReloadLibrary = b;
703 }
704
705
706
707
708
709 private boolean getAutoload()
710 {
711 return autoReloadLibrary;
712 }
713
714
715
716
717
718
719
720
721
722 private static class Twonk
723 {
724
725 public Template template;
726
727
728 public long modificationTime;
729 }
730 }
731
732
733
734
735
736
737