All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.velocity.runtime.VelocimacroManager Maven / Gradle / Ivy

The newest version!
package org.apache.velocity.runtime;

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

import org.apache.velocity.Template;
import org.apache.velocity.exception.VelocityException;
import org.apache.velocity.runtime.directive.Macro;
import org.apache.velocity.runtime.directive.VelocimacroProxy;
import org.apache.velocity.runtime.parser.node.Node;
import org.apache.velocity.runtime.parser.node.SimpleNode;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Manages VMs in namespaces.  Currently, two namespace modes are
 * supported:
 *
 * 
    *
  • flat - all allowable VMs are in the global namespace
  • *
  • local - inline VMs are added to it's own template namespace
  • *
* * Thanks to Jose Alberto Fernandez * for some ideas incorporated here. * * @author Geir Magnusson Jr. * @author Jose Alberto Fernandez * @version $Id$ */ public class VelocimacroManager { private boolean registerFromLib = false; /** reference to global namespace hash */ private final Map globalNamespace; /** set of names of library templates/namespaces */ private final Map libraries = new ConcurrentHashMap<>(17, 0.5f, 20); private RuntimeServices rsvc = null; /* * big switch for namespaces. If true, then properties control * usage. If false, no. */ private boolean namespacesOn = true; private boolean inlineLocalMode = false; private boolean inlineReplacesGlobal = false; /** * Adds the global namespace to the hash. */ VelocimacroManager(RuntimeServices rsvc) { /* * add the global namespace to the namespace hash. We always have that. */ globalNamespace = new ConcurrentHashMap<>(101, 0.5f, 20); this.rsvc = rsvc; } /** * Adds a VM definition to the cache. * * Called by VelocimacroFactory.addVelociMacro (after parsing and discovery in Macro directive) * * @param vmName Name of the new VelociMacro. * @param macroBody String representation of the macro body. * @param macroArgs Array of macro arguments, containing the * #macro() arguments and default values. the 0th is the name. * @param definingTemplate The template from which this macro has been loaded. * @param canReplaceGlobalMacro whether this macro can replace a global macro * @return Whether everything went okay. */ public boolean addVM(final String vmName, final Node macroBody, List macroArgs, final Template definingTemplate, boolean canReplaceGlobalMacro) { if (macroBody == null) { // happens only if someone uses this class without the Macro directive // and provides a null value as an argument throw new VelocityException("Null AST for "+vmName+" in " + definingTemplate.getName()); } MacroEntry me = new MacroEntry(vmName, macroBody, macroArgs, definingTemplate.getName(), rsvc); me.setFromLibrary(registerFromLib); /* * the client (VMFactory) will signal to us via * registerFromLib that we are in startup mode registering * new VMs from libraries. Therefore, we want to * addto the library map for subsequent auto reloads */ boolean isLib = true; MacroEntry exist = globalNamespace.get(vmName); if (registerFromLib) { libraries.put(definingTemplate.getName(), definingTemplate); } else { /* * now, we first want to check to see if this namespace (template) * is actually a library - if so, we need to use the global namespace * we don't have to do this when registering, as namespaces should * be shut off. If not, the default value is true, so we still go * global */ isLib = libraries.containsKey(definingTemplate.getName()); } if ( !isLib && usingNamespaces() ) { definingTemplate.getMacros().put(vmName, me); } else { /* * otherwise, add to global template. First, check if we * already have it to preserve some of the autoload information */ if (exist != null) { me.setFromLibrary(exist.getFromLibrary()); } /* * now add it */ globalNamespace.put(vmName, me); } return true; } /** * Gets a VelocimacroProxy object by the name / source template duple. * * @param vmName Name of the VelocityMacro to look up. * @param renderingTemplate Template we are currently rendering. * @param template Source Template. * @return A proxy representing the Macro. */ public VelocimacroProxy get(final String vmName, final Template renderingTemplate, final Template template) { if( inlineReplacesGlobal && renderingTemplate != null ) { /* * if VM_PERM_ALLOW_INLINE_REPLACE_GLOBAL is true (local macros can * override global macros) and we know which template we are rendering at the * moment, check if local namespace contains a macro we are looking for * if so, return it instead of the global one */ MacroEntry me = (MacroEntry)renderingTemplate.getMacros().get(vmName); if( me != null ) { return me.getProxy(); } } if( usingNamespaces() && template != null ) { MacroEntry me = (MacroEntry)template.getMacros().get(vmName); if( template.getMacros().size() > 0 && me != null ) { return me.getProxy(); } } MacroEntry me = globalNamespace.get(vmName); if (me != null) { return me.getProxy(); } return null; } /** * 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 * * @param namespaceOn True if namespaces should be used. */ public void setNamespaceUsage(final boolean namespaceOn) { this.namespacesOn = namespaceOn; } /** * Should macros registered from Libraries be marked special? * @param registerFromLib True if macros from Libs should be marked. */ public void setRegisterFromLib(final boolean registerFromLib) { this.registerFromLib = registerFromLib; } /** * Should macros from the same template be inlined? * * @param inlineLocalMode True if macros should be inlined on the same template. */ public void setTemplateLocalInlineVM(final boolean inlineLocalMode) { this.inlineLocalMode = inlineLocalMode; } /** * determines if currently using namespaces. * * @return true if using namespaces, false if not */ private boolean usingNamespaces() { /* * if the big switch turns of namespaces, then ignore the rules */ if (!namespacesOn) { return false; } /* * currently, we only support the local template namespace idea */ return inlineLocalMode; } /** * Return the library name for a given macro. * @param vmName Name of the Macro to look up. * @param template Template * @return The name of the library which registered this macro in a namespace. */ public String getLibraryName(final String vmName, Template template) { if (usingNamespaces()) { /* * if we have this macro defined in this namespace, then * it is masking the global, library-based one, so * just return null */ MacroEntry me = (MacroEntry)template.getMacros().get(vmName); if( me != null ) return null; } MacroEntry me = globalNamespace.get(vmName); if (me != null) { return me.getSourceTemplate(); } return null; } /** * @param is * @since 1.6 */ public void setInlineReplacesGlobal(boolean is) { inlineReplacesGlobal = is; } /** * wrapper class for holding VM information */ private static class MacroEntry { private final String sourceTemplate; private boolean fromLibrary = false; private VelocimacroProxy vp; private MacroEntry(final String vmName, final Node macro, List macroArgs, final String sourceTemplate, RuntimeServices rsvc) { this.sourceTemplate = sourceTemplate; vp = new VelocimacroProxy(); vp.init(rsvc); vp.setName(vmName); vp.setMacroArgs(macroArgs); vp.setNodeTree((SimpleNode)macro); vp.setLocation(macro.getLine(), macro.getColumn(), macro.getTemplate()); } /** * Has the macro been registered from a library. * @param fromLibrary True if the macro was registered from a Library. */ public void setFromLibrary(final boolean fromLibrary) { this.fromLibrary = fromLibrary; } /** * Returns true if the macro was registered from a library. * @return True if the macro was registered from a library. */ public boolean getFromLibrary() { return fromLibrary; } public String getSourceTemplate() { return sourceTemplate; } VelocimacroProxy getProxy() { return vp; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy