| package org.apache.velocity.runtime; |
| |
| /* |
| * The Apache Software License, Version 1.1 |
| * |
| * Copyright (c) 2000-2001 The Apache Software Foundation. All rights |
| * reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * |
| * 3. The end-user documentation included with the redistribution, if |
| * any, must include the following acknowlegement: |
| * "This product includes software developed by the |
| * Apache Software Foundation (http://www.apache.org/)." |
| * Alternately, this acknowlegement may appear in the software itself, |
| * if and wherever such third-party acknowlegements normally appear. |
| * |
| * 4. The names "The Jakarta Project", "Velocity", and "Apache Software |
| * Foundation" must not be used to endorse or promote products derived |
| * from this software without prior written permission. For written |
| * permission, please contact apache@apache.org. |
| * |
| * 5. Products derived from this software may not be called "Apache" |
| * nor may "Apache" appear in their names without prior written |
| * permission of the Apache Group. |
| * |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR |
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| * ==================================================================== |
| * |
| * This software consists of voluntary contributions made by many |
| * individuals on behalf of the Apache Software Foundation. For more |
| * information on the Apache Software Foundation, please see |
| * <http://www.apache.org/>. |
| */ |
| |
| import java.util.Hashtable; |
| import java.util.TreeMap; |
| |
| import java.io.StringReader; |
| import java.io.BufferedReader; |
| |
| import org.apache.velocity.Template; |
| import org.apache.velocity.runtime.directive.Directive; |
| import org.apache.velocity.runtime.directive.VelocimacroProxy; |
| import org.apache.velocity.runtime.parser.node.SimpleNode; |
| import org.apache.velocity.util.StringUtils; |
| |
| import org.apache.velocity.context.InternalContextAdapter; |
| |
| /** |
| * VelocimacroManager.java |
| * |
| * manages VMs in namespaces. Currently, there are two namespace modes |
| * supported : |
| * <ul> |
| * <li> flat namespace : all allowable VMs are in the global namespace |
| * <li> local namespace : inline VMs are added to it's own template namespace |
| * </ul> |
| * |
| * Thanks to <a href="mailto:JFernandez@viquity.com">Jose Alberto Fernandez</a> |
| * for some ideas incorporated here. |
| * |
| * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a> |
| * @author <a href="mailto:JFernandez@viquity.com">Jose Alberto Fernandez</a> |
| * @version $Id: VelocimacroManager.java,v 1.13 2001/08/13 13:58:35 geirm Exp $ |
| */ |
| public class VelocimacroManager |
| { |
| private RuntimeServices rsvc = null; |
| private static String GLOBAL_NAMESPACE = ""; |
| |
| private boolean registerFromLib = false; |
| |
| /* hash of namespace hashes */ |
| private Hashtable namespaceHash = new Hashtable(); |
| |
| /* |
| * big switch for namespaces. If true, then properties control |
| * usage. If false, no. |
| */ |
| private boolean namespacesOn = true; |
| private boolean inlineLocalMode = false; |
| |
| /** |
| * not much to do but add the global namespace to the hash |
| */ |
| VelocimacroManager( RuntimeServices rs) |
| { |
| this.rsvc = rs; |
| |
| /* |
| * add the global namespace to the namespace hash. We always have that. |
| */ |
| |
| addNamespace( GLOBAL_NAMESPACE ); |
| } |
| |
| /** |
| * adds a VM definition to the cache |
| * @return boolean if all went ok |
| */ |
| public boolean addVM(String vmName, String macroBody, String argArray[], String namespace ) |
| { |
| MacroEntry me = new MacroEntry( this, vmName, macroBody, argArray, namespace ); |
| |
| me.setFromLibrary(registerFromLib); |
| |
| if ( usingNamespaces( namespace ) ) |
| { |
| /* |
| * first, do we have a namespace hash already for this namespace? |
| * if not, add it to the namespaces, and add the VM |
| */ |
| |
| Hashtable local = getNamespace( namespace, true ); |
| local.put( (String) vmName, me ); |
| |
| return true; |
| } |
| else |
| { |
| /* |
| * otherwise, add to global template. First, check if we already have it |
| * to preserve some of the autoload information |
| */ |
| |
| MacroEntry exist = (MacroEntry) (getNamespace( GLOBAL_NAMESPACE )).get( vmName ); |
| |
| if (exist != null) |
| { |
| me.setFromLibrary( exist.getFromLibrary()); |
| } |
| |
| /* |
| * now add it |
| */ |
| |
| (getNamespace( GLOBAL_NAMESPACE )).put( vmName, me ); |
| |
| return true; |
| } |
| } |
| |
| /** |
| * gets a new living VelocimacroProxy object by the |
| * name / source template duple |
| */ |
| public VelocimacroProxy get( String vmName, String namespace ) |
| { |
| |
| if ( usingNamespaces( namespace ) ) |
| { |
| Hashtable local = getNamespace( namespace, false ); |
| |
| /* |
| * if we have macros defined for this template |
| */ |
| |
| if ( local != null) |
| { |
| MacroEntry me = (MacroEntry) local.get( vmName ); |
| |
| if (me != null) |
| { |
| return me.createVelocimacro( namespace ); |
| } |
| } |
| } |
| |
| /* |
| * if we didn't return from there, we need to simply see |
| * if it's in the global namespace |
| */ |
| |
| MacroEntry me = (MacroEntry) (getNamespace( GLOBAL_NAMESPACE )).get( vmName ); |
| |
| if (me != null) |
| { |
| return me.createVelocimacro( namespace ); |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Removes the VMs and the namespace from the manager. |
| * Used when a template is reloaded to avoid |
| * accumulating drek |
| * |
| * @param namespace namespace to dump |
| * @return boolean representing success |
| */ |
| public boolean dumpNamespace( String namespace ) |
| { |
| synchronized( this ) |
| { |
| if (usingNamespaces( namespace ) ) |
| { |
| Hashtable h = (Hashtable) namespaceHash.remove( namespace ); |
| |
| if ( h == null ) |
| return false; |
| |
| h.clear(); |
| |
| return true; |
| } |
| |
| return false; |
| } |
| } |
| |
| /** |
| * public switch to let external user of manager to control namespace |
| * usage indep of properties. That way, for example, at startup the |
| * library files are loaded into global namespace |
| */ |
| public void setNamespaceUsage( boolean b ) |
| { |
| namespacesOn = b; |
| return; |
| } |
| |
| public void setRegisterFromLib( boolean b ) |
| { |
| registerFromLib = b; |
| return; |
| } |
| |
| public void setTemplateLocalInlineVM( boolean b ) |
| { |
| inlineLocalMode = b; |
| } |
| |
| /** |
| * returns the hash for the specified namespace. Will not create a new one |
| * if it doesn't exist |
| * |
| * @param namespace name of the namespace :) |
| * @return namespace Hashtable of VMs or null if doesn't exist |
| */ |
| private Hashtable getNamespace( String namespace ) |
| { |
| return getNamespace( namespace, false ); |
| } |
| |
| /** |
| * returns the hash for the specified namespace, and if it doesn't exist |
| * will create a new one and add it to the namespaces |
| * |
| * @param namespace name of the namespace :) |
| * @param addIfNew flag to add a new namespace if it doesn't exist |
| * @return namespace Hashtable of VMs or null if doesn't exist |
| */ |
| private Hashtable getNamespace( String namespace, boolean addIfNew ) |
| { |
| Hashtable h = (Hashtable) namespaceHash.get( namespace ); |
| |
| if (h == null && addIfNew) |
| h = addNamespace( namespace ); |
| |
| return h; |
| } |
| |
| /** |
| * adds a namespace to the namespaces |
| * |
| * @param namespace name of namespace to add |
| * @return Hash added to namespaces, ready for use |
| */ |
| private Hashtable addNamespace( String namespace ) |
| { |
| Hashtable h = new Hashtable(); |
| Object oh; |
| |
| if ((oh = namespaceHash.put( namespace, h )) != null) |
| { |
| /* |
| * There was already an entry on the table, restore it! |
| * This condition should never occur, given the code |
| * and the fact that this method is private. |
| * But just in case, this way of testing for it is much |
| * more efficient than testing before hand using get(). |
| */ |
| namespaceHash.put( namespace, oh ); |
| /* |
| * Should't we be returning the old entry (oh)? |
| * The previous code was just returning null in this case. |
| */ |
| return null; |
| } |
| |
| return h; |
| } |
| |
| /** |
| * determines if currently using namespaces. |
| * |
| * @param namespace currently ignored |
| * @return true if using namespaces, false if not |
| */ |
| private boolean usingNamespaces( String namespace ) |
| { |
| /* |
| * if the big switch turns of namespaces, then ignore the rules |
| */ |
| |
| if ( !namespacesOn ) |
| return false; |
| |
| /* |
| * currently, we only support the local template namespace idea |
| */ |
| |
| if ( inlineLocalMode ) |
| return true; |
| |
| return false; |
| } |
| |
| public String getLibraryName( String vmName, String namespace ) |
| { |
| if ( usingNamespaces( namespace ) ) |
| { |
| Hashtable local = getNamespace( namespace, false ); |
| |
| /* |
| * if we have this macro defined in this namespace, then |
| * it is masking the global, library-based one, so |
| * just return null |
| */ |
| |
| if ( local != null) |
| { |
| MacroEntry me = (MacroEntry) local.get( vmName ); |
| |
| if (me != null) |
| { |
| return null; |
| } |
| } |
| } |
| |
| /* |
| * if we didn't return from there, we need to simply see |
| * if it's in the global namespace |
| */ |
| |
| MacroEntry me = (MacroEntry) (getNamespace( GLOBAL_NAMESPACE )).get( vmName ); |
| |
| if (me != null) |
| { |
| return me.getSourceTemplate(); |
| } |
| |
| return null; |
| } |
| |
| |
| /** |
| * wrapper class for holding VM information |
| */ |
| protected class MacroEntry |
| { |
| String macroname; |
| String[] argarray; |
| String macrobody; |
| String sourcetemplate; |
| SimpleNode nodeTree = null; |
| VelocimacroManager manager = null; |
| boolean fromLibrary = false; |
| |
| MacroEntry(VelocimacroManager vmm, String vmName, String macroBody, String argArray[], String sourceTemplate) |
| { |
| this.macroname = vmName; |
| this.argarray = argArray; |
| this.macrobody = macroBody; |
| this.sourcetemplate = sourceTemplate; |
| this.manager = vmm; |
| } |
| |
| public void setFromLibrary( boolean b ) |
| { |
| fromLibrary = b; |
| } |
| |
| public boolean getFromLibrary() |
| { |
| return fromLibrary; |
| } |
| |
| public SimpleNode getNodeTree() |
| { |
| return nodeTree; |
| } |
| |
| public String getSourceTemplate() |
| { |
| return sourcetemplate; |
| } |
| |
| VelocimacroProxy createVelocimacro( String namespace ) |
| { |
| VelocimacroProxy vp = new VelocimacroProxy(); |
| vp.setName( this.macroname ); |
| vp.setArgArray( this.argarray ); |
| vp.setMacrobody( this.macrobody ); |
| vp.setNodeTree( this.nodeTree); |
| vp.setNamespace( namespace ); |
| return vp; |
| } |
| |
| void setup( InternalContextAdapter ica) |
| { |
| /* |
| * if not parsed yet, parse! |
| */ |
| |
| if( nodeTree == null) |
| parseTree( ica ); |
| } |
| |
| void parseTree( InternalContextAdapter ica) |
| { |
| try |
| { |
| BufferedReader br = new BufferedReader( new StringReader( macrobody ) ); |
| |
| nodeTree = rsvc.parse( br, "VM:" + macroname ); |
| nodeTree.init(ica,null); |
| } |
| catch ( Exception e ) |
| { |
| rsvc.error("VelocimacroManager.parseTree() : exception " + macroname + |
| " : " + StringUtils.stackTrace(e)); |
| } |
| } |
| } |
| } |