KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > velocity > runtime > VelocimacroManager


1 package org.apache.velocity.runtime;
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.util.Hashtable JavaDoc;
20
21 import java.io.StringReader JavaDoc;
22 import java.io.BufferedReader JavaDoc;
23
24 import org.apache.velocity.runtime.directive.VelocimacroProxy;
25 import org.apache.velocity.runtime.parser.node.SimpleNode;
26 import org.apache.velocity.util.StringUtils;
27
28 import org.apache.velocity.context.InternalContextAdapter;
29
30 /**
31  * Manages VMs in namespaces. Currently, two namespace modes are
32  * supported:
33  *
34  * <ul>
35  * <li>flat - all allowable VMs are in the global namespace</li>
36  * <li>local - inline VMs are added to it's own template namespace</li>
37  * </ul>
38  *
39  * Thanks to <a HREF="mailto:JFernandez@viquity.com">Jose Alberto Fernandez</a>
40  * for some ideas incorporated here.
41  *
42  * @author <a HREF="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
43  * @author <a HREF="mailto:JFernandez@viquity.com">Jose Alberto Fernandez</a>
44  * @version $Id: VelocimacroManager.java,v 1.17.4.1 2004/03/03 23:22:55 geirm Exp $
45  */

46 public class VelocimacroManager
47 {
48     private RuntimeServices rsvc = null;
49     private static String JavaDoc GLOBAL_NAMESPACE = "";
50
51     private boolean registerFromLib = false;
52
53     /** Hash of namespace hashes. */
54     private Hashtable JavaDoc namespaceHash = new Hashtable JavaDoc();
55     
56     /** map of names of library tempates/namespaces */
57     private Hashtable JavaDoc libraryMap = new Hashtable JavaDoc();
58     
59     /*
60      * big switch for namespaces. If true, then properties control
61      * usage. If false, no.
62      */

63     private boolean namespacesOn = true;
64     private boolean inlineLocalMode = false;
65
66     /**
67      * Adds the global namespace to the hash.
68      */

69     VelocimacroManager(RuntimeServices rs)
70     {
71         this.rsvc = rs;
72
73         /*
74          * add the global namespace to the namespace hash. We always have that.
75          */

76
77         addNamespace( GLOBAL_NAMESPACE );
78     }
79
80     /**
81      * Adds a VM definition to the cache.
82      * @return Whether everything went okay.
83      */

84     public boolean addVM(String JavaDoc vmName, String JavaDoc macroBody, String JavaDoc argArray[],
85                          String JavaDoc namespace)
86     {
87         MacroEntry me = new MacroEntry(this, vmName, macroBody, argArray,
88                                        namespace);
89
90         me.setFromLibrary(registerFromLib);
91     
92         /*
93          * the client (VMFactory) will signal to us via
94          * registerFromLib that we are in startup mode registering
95          * new VMs from libraries. Therefore, we want to
96          * addto the library map for subsequent auto reloads
97          */

98          
99         boolean isLib = true;
100         
101         if (registerFromLib)
102         {
103            libraryMap.put(namespace, namespace);
104         }
105         else
106         {
107             /*
108              * now, we first want to check to see if this namespace (template)
109              * is actually a library - if so, we need to use the global namespace
110              * we don't have to do this when registering, as namespaces should
111              * be shut off. If not, the default value is true, so we still go
112              * global
113              */

114          
115             isLib = libraryMap.containsKey(namespace);
116         }
117                
118         if ( !isLib && usingNamespaces(namespace) )
119         {
120             /*
121              * first, do we have a namespace hash already for this namespace?
122              * if not, add it to the namespaces, and add the VM
123              */

124
125             Hashtable JavaDoc local = getNamespace(namespace, true);
126             local.put((String JavaDoc) vmName, me);
127          
128             return true;
129         }
130         else
131         {
132             /*
133              * otherwise, add to global template. First, check if we
134              * already have it to preserve some of the autoload information
135              */

136
137             MacroEntry exist = (MacroEntry) getNamespace(GLOBAL_NAMESPACE).get(vmName);
138             
139             if (exist != null)
140             {
141                 me.setFromLibrary(exist.getFromLibrary());
142             }
143
144             /*
145              * now add it
146              */

147
148             getNamespace(GLOBAL_NAMESPACE).put(vmName, me);
149
150             return true;
151         }
152     }
153
154     /**
155      * gets a new living VelocimacroProxy object by the
156      * name / source template duple
157      */

158     public VelocimacroProxy get(String JavaDoc vmName, String JavaDoc namespace)
159     {
160  
161         if (usingNamespaces(namespace))
162         {
163             Hashtable JavaDoc local = getNamespace(namespace, false);
164          
165             /*
166              * if we have macros defined for this template
167              */

168
169             if (local != null)
170             {
171                 MacroEntry me = (MacroEntry) local.get(vmName);
172                
173                 if (me != null)
174                 {
175                     return me.createVelocimacro(namespace);
176                 }
177             }
178         }
179
180         /*
181          * if we didn't return from there, we need to simply see
182          * if it's in the global namespace
183          */

184         
185         MacroEntry me = (MacroEntry) getNamespace(GLOBAL_NAMESPACE).get( vmName );
186         
187         if (me != null)
188         {
189             return me.createVelocimacro(namespace);
190         }
191  
192         return null;
193     }
194
195     /**
196      * Removes the VMs and the namespace from the manager.
197      * Used when a template is reloaded to avoid
198      * accumulating drek
199      *
200      * @param namespace namespace to dump
201      * @return boolean representing success
202      */

203     public boolean dumpNamespace(String JavaDoc namespace)
204     {
205         synchronized(this)
206         {
207             if (usingNamespaces(namespace))
208             {
209                 Hashtable JavaDoc h = (Hashtable JavaDoc) namespaceHash.remove(namespace);
210
211                 if (h == null)
212                     return false;
213             
214                 h.clear();
215                
216                 return true;
217             }
218
219             return false;
220         }
221     }
222
223     /**
224      * public switch to let external user of manager to control namespace
225      * usage indep of properties. That way, for example, at startup the
226      * library files are loaded into global namespace
227      */

228     public void setNamespaceUsage(boolean b)
229     {
230         namespacesOn = b;
231     }
232
233     public void setRegisterFromLib(boolean b)
234     {
235         registerFromLib = b;
236     }
237
238     public void setTemplateLocalInlineVM(boolean b)
239     {
240         inlineLocalMode = b;
241     }
242
243     /**
244      * returns the hash for the specified namespace. Will not create a new one
245      * if it doesn't exist
246      *
247      * @param namespace name of the namespace :)
248      * @return namespace Hashtable of VMs or null if doesn't exist
249      */

250     private Hashtable JavaDoc getNamespace(String JavaDoc namespace)
251     {
252         return getNamespace(namespace, false);
253     }
254
255     /**
256      * returns the hash for the specified namespace, and if it doesn't exist
257      * will create a new one and add it to the namespaces
258      *
259      * @param namespace name of the namespace :)
260      * @param addIfNew flag to add a new namespace if it doesn't exist
261      * @return namespace Hashtable of VMs or null if doesn't exist
262      */

263     private Hashtable JavaDoc getNamespace(String JavaDoc namespace, boolean addIfNew)
264     {
265         Hashtable JavaDoc h = (Hashtable JavaDoc) namespaceHash.get(namespace);
266
267         if (h == null && addIfNew)
268         {
269             h = addNamespace(namespace);
270         }
271   
272         return h;
273     }
274
275     /**
276      * adds a namespace to the namespaces
277      *
278      * @param namespace name of namespace to add
279      * @return Hash added to namespaces, ready for use
280      */

281     private Hashtable JavaDoc addNamespace(String JavaDoc namespace)
282     {
283         Hashtable JavaDoc h = new Hashtable JavaDoc();
284         Object JavaDoc oh;
285
286         if ((oh = namespaceHash.put(namespace, h)) != null)
287         {
288           /*
289            * There was already an entry on the table, restore it!
290            * This condition should never occur, given the code
291            * and the fact that this method is private.
292            * But just in case, this way of testing for it is much
293            * more efficient than testing before hand using get().
294            */

295           namespaceHash.put(namespace, oh);
296           /*
297            * Should't we be returning the old entry (oh)?
298            * The previous code was just returning null in this case.
299            */

300           return null;
301         }
302         
303         return h;
304     }
305
306     /**
307      * determines if currently using namespaces.
308      *
309      * @param namespace currently ignored
310      * @return true if using namespaces, false if not
311      */

312     private boolean usingNamespaces(String JavaDoc namespace)
313     {
314         /*
315          * if the big switch turns of namespaces, then ignore the rules
316          */

317
318         if (!namespacesOn)
319         {
320             return false;
321         }
322
323         /*
324          * currently, we only support the local template namespace idea
325          */

326
327         if (inlineLocalMode)
328         {
329             return true;
330         }
331
332         return false;
333     }
334
335     public String JavaDoc getLibraryName(String JavaDoc vmName, String JavaDoc namespace)
336     {
337         if (usingNamespaces(namespace))
338         {
339             Hashtable JavaDoc local = getNamespace(namespace, false);
340          
341             /*
342              * if we have this macro defined in this namespace, then
343              * it is masking the global, library-based one, so
344              * just return null
345              */

346
347             if ( local != null)
348             {
349                 MacroEntry me = (MacroEntry) local.get(vmName);
350                
351                 if (me != null)
352                 {
353                     return null;
354                 }
355             }
356         }
357
358         /*
359          * if we didn't return from there, we need to simply see
360          * if it's in the global namespace
361          */

362         
363         MacroEntry me = (MacroEntry) getNamespace(GLOBAL_NAMESPACE).get(vmName);
364         
365         if (me != null)
366         {
367             return me.getSourceTemplate();
368         }
369  
370         return null;
371     }
372
373
374     /**
375      * wrapper class for holding VM information
376      */

377     protected class MacroEntry
378     {
379         String JavaDoc macroname;
380         String JavaDoc[] argarray;
381         String JavaDoc macrobody;
382         String JavaDoc sourcetemplate;
383         SimpleNode nodeTree = null;
384         VelocimacroManager manager = null;
385         boolean fromLibrary = false;
386
387         MacroEntry(VelocimacroManager vmm, String JavaDoc vmName, String JavaDoc macroBody,
388                    String JavaDoc argArray[], String JavaDoc sourceTemplate)
389         {
390             this.macroname = vmName;
391             this.argarray = argArray;
392             this.macrobody = macroBody;
393             this.sourcetemplate = sourceTemplate;
394             this.manager = vmm;
395         }
396
397         public void setFromLibrary(boolean b)
398         {
399             fromLibrary = b;
400         }
401         
402         public boolean getFromLibrary()
403         {
404             return fromLibrary;
405         }
406
407         public SimpleNode getNodeTree()
408         {
409             return nodeTree;
410         }
411
412         public String JavaDoc getSourceTemplate()
413         {
414             return sourcetemplate;
415         }
416
417         VelocimacroProxy createVelocimacro(String JavaDoc namespace)
418         {
419             VelocimacroProxy vp = new VelocimacroProxy();
420             vp.setName(this.macroname);
421             vp.setArgArray(this.argarray);
422             vp.setMacrobody(this.macrobody);
423             vp.setNodeTree(this.nodeTree);
424             vp.setNamespace(namespace);
425             return vp;
426         }
427
428         void setup( InternalContextAdapter ica)
429         {
430             /*
431              * if not parsed yet, parse!
432              */

433             
434             if( nodeTree == null)
435                 parseTree(ica);
436         }
437
438         void parseTree(InternalContextAdapter ica)
439         {
440             try
441             {
442                 BufferedReader JavaDoc br = new BufferedReader JavaDoc(new StringReader JavaDoc(macrobody));
443  
444                 nodeTree = rsvc.parse(br, "VM:" + macroname, true);
445                 nodeTree.init(ica,null);
446             }
447             catch ( Exception JavaDoc e )
448             {
449                 rsvc.error("VelocimacroManager.parseTree() : exception " +
450                            macroname + " : " + StringUtils.stackTrace(e));
451             }
452         }
453     }
454 }
455
Popular Tags