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

COVERAGE SUMMARY FOR SOURCE FILE [VelocimacroFactory.java]

nameclass, %method, %block, %line, %
VelocimacroFactory.java67%  (2/3)100% (18/18)76%  (508/666)79%  (117.1/149)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class VelocimacroFactory100% (1/1)100% (17/17)76%  (502/660)78%  (116.1/148)
getVelocimacro (String, String): Directive 100% (1/1)21%  (22/105)23%  (5.4/23)
canAddVelocimacro (String, String): boolean 100% (1/1)49%  (33/68)54%  (7/13)
isVelocimacro (String, String): boolean 100% (1/1)79%  (19/24)88%  (4.4/5)
initVelocimacro (): void 100% (1/1)90%  (217/242)90%  (48.6/54)
addVelocimacro (String, String, String [], String): boolean 100% (1/1)92%  (111/121)88%  (15.8/18)
VelocimacroFactory (RuntimeServices): void 100% (1/1)100% (42/42)100% (13/13)
dumpVMNamespace (String): boolean 100% (1/1)100% (5/5)100% (1/1)
getAutoload (): boolean 100% (1/1)100% (3/3)100% (1/1)
getBlather (): boolean 100% (1/1)100% (3/3)100% (1/1)
getTemplateLocalInline (): boolean 100% (1/1)100% (3/3)100% (1/1)
logVMMessageInfo (String): void 100% (1/1)100% (8/8)100% (3/3)
logVMMessageWarn (String): void 100% (1/1)100% (8/8)100% (3/3)
setAddMacroPermission (boolean): boolean 100% (1/1)100% (8/8)100% (3/3)
setAutoload (boolean): void 100% (1/1)100% (4/4)100% (2/2)
setBlather (boolean): void 100% (1/1)100% (4/4)100% (2/2)
setReplacementPermission (boolean): boolean 100% (1/1)100% (8/8)100% (3/3)
setTemplateLocalInline (boolean): void 100% (1/1)100% (4/4)100% (2/2)
     
class VelocimacroFactory$10%   (0/1)100% (0/0)100% (0/0)100% (0/0)
     
class VelocimacroFactory$Twonk100% (1/1)100% (1/1)100% (6/6)100% (1/1)
VelocimacroFactory$Twonk (VelocimacroFactory): void 100% (1/1)100% (6/6)100% (1/1)

1package org.apache.velocity.runtime;
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.Template;
20import org.apache.velocity.runtime.directive.Directive;
21import org.apache.velocity.runtime.directive.VelocimacroProxy;
22 
23import java.util.Vector;
24import java.util.Map;
25import java.util.HashMap;
26 
27/**
28 *  VelocimacroFactory.java
29 *
30 *   manages the set of VMs in a running Velocity engine.
31 *
32 * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
33 * @version $Id: VelocimacroFactory.java,v 1.17.4.1 2004/03/03 23:22:55 geirm Exp $ 
34 */
35public class VelocimacroFactory
36{
37    /**
38     *  runtime services for this instance
39     */
40    private RuntimeServices rsvc = null;
41 
42    /**
43     *  VMManager : deal with namespace management
44     *  and actually keeps all the VM definitions
45     */
46    private VelocimacroManager vmManager = null;
47 
48    /**
49     *  determines if replacement of global VMs are allowed
50     *  controlled by  VM_PERM_ALLOW_INLINE_REPLACE_GLOBAL
51     */
52    private boolean replaceAllowed = false;
53 
54    /**
55     *  controls if new VMs can be added.  Set by
56     *  VM_PERM_ALLOW_INLINE  Note the assumption that only
57     *  through inline defs can this happen.
58     *  additions through autoloaded VMs is allowed
59     */
60    private boolean addNewAllowed = true;
61 
62    /**
63     *  sets if template-local namespace in used
64     */
65    private boolean templateLocal = false;
66 
67    /**
68     *  controls log output
69     */
70    private boolean blather = false;
71 
72    /**
73     *  determines if the libraries are auto-loaded
74     *  when they change
75     */
76    private boolean autoReloadLibrary = false;
77 
78    /**
79     *  vector of the library names
80     */
81    private Vector macroLibVec = null;
82 
83    /**
84     *  map of the library Template objects
85     *  used for reload determination
86     */
87    private Map libModMap;
88 
89    /**
90     *  CTOR : requires a runtime services from now
91     *  on
92     */
93    public VelocimacroFactory( RuntimeServices rs )
94    {
95        this.rsvc = rs;
96 
97        /*
98         *  we always access in a synchronized(), so we 
99         *  can use an unsynchronized hashmap
100         */
101        libModMap = new HashMap();
102        vmManager = new VelocimacroManager( rsvc );
103    }
104 
105    /**
106     *  initialize the factory - setup all permissions
107     *  load all global libraries.
108     */
109    public void initVelocimacro()
110    {
111        /*
112         *  maybe I'm just paranoid...
113         */
114        synchronized( this )
115        {
116            /*
117             *   allow replacements while we add the libraries, if exist
118             */
119            setReplacementPermission( true );
120            setBlather( true );
121 
122            logVMMessageInfo("Velocimacro : initialization starting.");
123 
124            /*
125             *  add all library macros to the global namespace
126             */
127            
128            vmManager.setNamespaceUsage( false );
129        
130            /*
131             *  now, if there is a global or local libraries specified, use them.
132             *  All we have to do is get the template. The template will be parsed;
133             *  VM's  are added during the parse phase
134             */
135 
136             Object libfiles = rsvc.getProperty( RuntimeConstants.VM_LIBRARY );
137           
138             if( libfiles != null)
139             {         
140                 if (libfiles instanceof Vector)
141                 {
142                     macroLibVec = (Vector) libfiles;
143                 }
144                 else if (libfiles instanceof String)
145                 { 
146                     macroLibVec = new Vector();
147                     macroLibVec.addElement( libfiles );
148                 }
149                 
150                 for( int i = 0; i < macroLibVec.size(); i++)
151                 {
152                     String lib = (String) macroLibVec.elementAt(i);
153                 
154                     /*
155                      * only if it's a non-empty string do we bother
156                      */
157 
158                     if (lib != null && !lib.equals(""))
159                     {
160                         /*
161                          *  let the VMManager know that the following is coming
162                          *  from libraries - need to know for auto-load
163                          */
164 
165                         vmManager.setRegisterFromLib( true );
166 
167                         logVMMessageInfo("Velocimacro : adding VMs from " +
168                             "VM library template : " + lib  );
169 
170                         try 
171                         {
172                             Template template = rsvc.getTemplate( lib );
173 
174                             /*
175                              *  save the template.  This depends on the assumption
176                              *  that the Template object won't change - currently
177                              *  this is how the Resource manager works
178                              */
179 
180                             Twonk twonk = new Twonk();
181                             twonk.template = template;
182                             twonk.modificationTime = template.getLastModified();
183                             libModMap.put( lib, twonk );                         
184                         } 
185                         catch (Exception e)
186                         {
187                             logVMMessageInfo("Velocimacro : error using  VM " +
188                                              "library template " + lib + " : " + e );
189                         }
190 
191                         logVMMessageInfo("Velocimacro :  VM library template " +
192                                 "macro registration complete." );
193            
194                         vmManager.setRegisterFromLib( false );
195                     }
196                 }
197             }
198 
199            /*
200             *   now, the permissions
201             */
202            
203            /*
204             *  allowinline : anything after this will be an inline macro, I think
205             *  there is the question if a #include is an inline, and I think so
206             *
207             *  default = true
208             */
209            setAddMacroPermission( true );
210                        
211            if ( !rsvc.getBoolean(  RuntimeConstants.VM_PERM_ALLOW_INLINE, true) )
212            {
213                setAddMacroPermission( false );
214                
215                logVMMessageInfo("Velocimacro : allowInline = false : VMs can not " +
216                    "be defined inline in templates");
217            }
218            else
219            {
220                logVMMessageInfo("Velocimacro : allowInline = true : VMs can be " +
221                    "defined inline in templates");
222            }
223 
224            /*
225             *  allowInlineToReplaceGlobal : allows an inline VM , if allowed at all,
226             *  to replace an existing global VM
227             *
228             *  default = false
229             */
230            setReplacementPermission( false );
231            
232            if ( rsvc.getBoolean(  
233                 RuntimeConstants.VM_PERM_ALLOW_INLINE_REPLACE_GLOBAL, false) )
234            {
235                setReplacementPermission( true );
236                
237                logVMMessageInfo("Velocimacro : allowInlineToOverride = true : VMs " +
238                    "defined inline may replace previous VM definitions");
239            }
240            else
241            {
242                logVMMessageInfo("Velocimacro : allowInlineToOverride = false : VMs " +
243                    "defined inline may NOT replace previous VM definitions");
244            }
245 
246            /*
247             * now turn on namespace handling as far as permissions allow in the 
248             * manager, and also set it here for gating purposes
249             */
250            vmManager.setNamespaceUsage( true );
251 
252            /*
253             *  template-local inline VM mode : default is off
254             */
255            setTemplateLocalInline( rsvc.getBoolean(
256                RuntimeConstants.VM_PERM_INLINE_LOCAL, false) );
257        
258            if ( getTemplateLocalInline() )
259            {
260                logVMMessageInfo("Velocimacro : allowInlineLocal = true : VMs " +
261                    "defined inline will be local to their defining template only.");
262            }
263            else
264            {
265                logVMMessageInfo("Velocimacro : allowInlineLocal = false : VMs " +
266                    "defined inline will be  global in scope if allowed.");
267            }
268 
269            vmManager.setTemplateLocalInlineVM( getTemplateLocalInline() );
270 
271            /*
272             *  general message switch.  default is on
273             */
274            setBlather( rsvc.getBoolean( RuntimeConstants.VM_MESSAGES_ON, true ));
275        
276            if (getBlather())
277            {
278                logVMMessageInfo("Velocimacro : messages on  : VM system " +
279                    "will output logging messages");
280            }
281            else
282            {
283                logVMMessageInfo("Velocimacro : messages off : VM system will be quiet");
284            }
285 
286            /*
287             *  autoload VM libraries
288             */
289            setAutoload( rsvc.getBoolean( RuntimeConstants.VM_LIBRARY_AUTORELOAD, false ));
290        
291            if (getAutoload())
292            {
293                logVMMessageInfo("Velocimacro : autoload on  : VM system " +
294                                 "will automatically reload global library macros");
295            }
296            else
297            {
298                logVMMessageInfo("Velocimacro : autoload off  : VM system " +
299                                 "will not automatically reload global library macros");
300            }
301 
302            rsvc.info("Velocimacro : initialization complete.");
303        }
304    
305        return;
306    }
307 
308    /**
309     *  adds a macro to the factory. 
310     */
311    public boolean addVelocimacro( String name, String macroBody,  
312            String argArray[], String sourceTemplate )
313    {
314        /*
315         * maybe we should throw an exception, maybe just tell 
316         * the caller like this...
317         * 
318         * I hate this : maybe exceptions are in order here...
319         */
320        if ( name == null ||   macroBody == null || argArray == null || 
321                sourceTemplate == null )
322        {
323            logVMMessageWarn("Velocimacro : VM addition rejected : " +
324                "programmer error : arg null"  );
325            
326            return false;
327        }
328        
329        /*
330         *  see if the current ruleset allows this addition
331         */
332 
333        if (!canAddVelocimacro( name, sourceTemplate ))
334        {
335            return false;
336        }
337 
338        /*
339         *  seems like all is good.  Lets do it.
340         */
341        synchronized( this ) 
342        {
343            vmManager.addVM( name, macroBody, argArray, sourceTemplate );
344        }
345 
346        /*
347         *  if we are to blather, blather...
348         */
349        if ( blather)
350        {
351            String s = "#" +  argArray[0];
352            s += "(";
353        
354            for( int i=1; i < argArray.length; i++)
355            {
356                s += " ";
357                s += argArray[i];
358            }
359 
360            s += " ) : source = ";
361            s += sourceTemplate;
362            
363           logVMMessageInfo( "Velocimacro : added new VM : " + s );
364        }
365 
366        return true;
367    }
368 
369    /**
370     *  determines if a given macro/namespace (name, source) combo is allowed
371     *  to be added
372     *
373     *  @param name Name of VM to add
374     *  @param sourceTemplate Source template that contains the defintion of the VM
375     *  @return true if it is allowed to be added, false otherwise
376     */
377    private boolean canAddVelocimacro( String name, String sourceTemplate)
378    {
379        /*
380         *  short circuit and do it if autoloader is on, and the
381         *  template is one of the library templates
382         */
383        
384        if ( getAutoload() )
385        {
386            /*
387             *  see if this is a library template
388             */
389 
390            for( int i = 0; i < macroLibVec.size(); i++)
391            {
392                String lib = (String) macroLibVec.elementAt(i);
393 
394                if (lib.equals( sourceTemplate ) )
395                {
396                    return true;
397                }
398            }
399        }
400 
401           
402        /*
403         * maybe the rules should be in manager?  I dunno. It's to manage 
404         * the namespace issues first, are we allowed to add VMs at all? 
405         * This trumps all.
406         */
407        if (!addNewAllowed)
408        {
409            logVMMessageWarn("Velocimacro : VM addition rejected : " + name + 
410                " : inline VMs not allowed."  );
411            
412            return false;
413        }
414 
415        /*
416         *  are they local in scope?  Then it is ok to add.
417         */
418        if (!templateLocal)
419        {
420            /* 
421             * otherwise, if we have it already in global namespace, and they can't replace
422             * since local templates are not allowed, the global namespace is implied.
423             *  remember, we don't know anything about namespace managment here, so lets
424             *  note do anything fancy like trying to give it the global namespace here
425             *
426             *  so if we have it, and we aren't allowed to replace, bail
427             */
428            if ( isVelocimacro( name, sourceTemplate ) && !replaceAllowed )
429            {
430                logVMMessageWarn("Velocimacro : VM addition rejected : "
431                    + name + " : inline not allowed to replace existing VM"  );
432                return false;
433            }
434        }
435        
436        return true;
437    }
438 
439    /**
440     *  localization of the logging logic
441     */
442    private void logVMMessageInfo( String s )
443    {
444        if (blather)
445            rsvc.info( s );
446    }
447 
448    /**
449     *  localization of the logging logic
450     */
451    private void logVMMessageWarn( String s )
452    {
453        if (blather)
454            rsvc.warn( s );
455    }
456      
457    /**
458     *  Tells the world if a given directive string is a Velocimacro
459     */
460    public boolean isVelocimacro( String vm , String sourceTemplate )
461    {
462        synchronized(this)
463        {
464            /*
465             * first we check the locals to see if we have 
466             * a local definition for this template
467             */
468            if (vmManager.get( vm, sourceTemplate ) != null)
469                return true;
470        }
471        return false;
472    }
473 
474    /**
475     *  actual factory : creates a Directive that will
476     *  behave correctly wrt getting the framework to 
477     *  dig out the correct # of args
478     */
479    public Directive getVelocimacro( String vmName, String sourceTemplate )
480    {
481        VelocimacroProxy vp = null;
482 
483        synchronized( this ) 
484        {
485            /*
486             *  don't ask - do
487             */
488 
489            vp = vmManager.get( vmName, sourceTemplate);
490 
491            /*
492             *  if this exists, and autoload is on, we need to check
493             *  where this VM came from
494             */
495 
496            if ( vp != null && getAutoload() ) 
497            {    
498                /*
499                 *  see if this VM came from a library.  Need to pass sourceTemplate
500                 *  in the event namespaces are set, as it could be masked by local
501                 */
502                
503                String lib = vmManager.getLibraryName( vmName, sourceTemplate );
504 
505                if (lib != null)
506                {
507                    try 
508                    {
509                        /*
510                         *  get the template from our map
511                         */
512 
513                        Twonk tw = (Twonk) libModMap.get( lib );
514                        
515                        if ( tw != null)
516                        {
517                            Template template = tw.template;
518                            
519                            /*
520                             *  now, compare the last modified time of the resource
521                             *  with the last modified time of the template
522                             *  if the file has changed, then reload. Otherwise, we should
523                             *  be ok.
524                             */
525 
526                            long tt = tw.modificationTime;
527                            long ft = template.getResourceLoader().getLastModified( template );
528 
529                            if ( ft > tt )
530                            {
531                                logVMMessageInfo("Velocimacro : autoload reload for VMs from " +
532                                                 "VM library template : " + lib  );
533             
534                                /*
535                                 *  when there are VMs in a library that invoke each other,
536                                 *  there are calls into getVelocimacro() from the init() 
537                                 *  process of the VM directive.  To stop the infinite loop
538                                 *  we save the current time reported by the resource loader
539                                 *  and then be honest when the reload is complete
540                                 */
541                                 
542                                tw.modificationTime = ft;
543                                                                       
544                                template = rsvc.getTemplate( lib );
545 
546                                /*
547                                 * and now we be honest
548                                 */
549 
550                                tw.template = template;
551                                tw.modificationTime = template.getLastModified();
552 
553                                /*
554                                 *  note that we don't need to put this twonk back 
555                                 *  into the map, as we can just use the same reference
556                                 *  and this block is synchronized
557                                 */                                  
558                             }
559                         } 
560                    }
561                    catch (Exception e)
562                    {
563                        logVMMessageInfo("Velocimacro : error using  VM " +
564                                         "library template " + lib + " : " + e );
565                    }
566 
567                    /*
568                     *  and get again
569                     */
570 
571                    vp = vmManager.get( vmName, sourceTemplate);
572                }
573            }
574        }
575        
576        return vp;
577    }
578 
579    /**
580     *  tells the vmManager to dump the specified namespace
581     */
582    public boolean dumpVMNamespace( String namespace )
583    {
584        return vmManager.dumpNamespace( namespace );
585    }
586 
587    /**
588     *  sets permission to have VMs local in scope to their declaring template
589     *  note that this is really taken care of in the VMManager class, but
590     *  we need it here for gating purposes in addVM
591     *  eventually, I will slide this all into the manager, maybe.
592     */   
593    private void setTemplateLocalInline( boolean b )
594    {
595        templateLocal = b;
596    }
597 
598    private boolean getTemplateLocalInline()
599    {
600        return templateLocal;
601    }
602 
603    /**
604     *   sets the permission to add new macros
605     */
606    private boolean setAddMacroPermission( boolean arg )
607    {
608        boolean b = addNewAllowed;
609        
610        addNewAllowed = arg;
611        return b;
612    }
613 
614    /**
615     *    sets the permission for allowing addMacro() calls to 
616     *    replace existing VM's
617     */
618    private boolean setReplacementPermission( boolean arg )
619    {
620        boolean b = replaceAllowed;
621        replaceAllowed = arg;
622        return b;
623    }
624 
625    /**
626     *  set output message mode 
627     */
628    private void setBlather( boolean b )
629    {
630        blather = b;
631    }
632 
633    /**
634     * get output message mode
635     */
636    private boolean getBlather()
637    {
638        return blather;
639    }
640 
641    /**
642     *  set the switch for automatic reloading of
643     *  global library-based VMs
644     */
645    private void setAutoload( boolean b)
646    {
647        autoReloadLibrary = b;
648    }
649    
650    /**
651     *  get the switch for automatic reloading of
652     *  global library-based VMs
653     */
654    private boolean getAutoload()
655    {
656        return autoReloadLibrary;
657    }
658 
659    /**
660     * small continer class to hold the duple
661     * of a template and modification time.
662     * We keep the modification time so we can 
663     * 'override' it on a reload to prevent
664     * recursive reload due to inter-calling
665     * VMs in a library
666     */
667    private class Twonk
668    {
669        public Template template;
670        public long modificationTime;
671    }
672}
673 
674 
675 
676 
677 
678 
679 

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