blob: 79a8cb6d12f0a3e7ac159075b9b9d36afdd17556 [file] [log] [blame]
package org.apache.velocity.tools;
/*
* 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 java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.context.Context;
import org.apache.velocity.tools.config.ConfigurationUtils;
/**
* {@link Context} implementation that keeps a list of {@link Toolbox}es
* and returns them as requested, using its internal context Map as the
* dynamic properties passed to the requested tools when they are first
* created.
*
* @author Nathan Bubna
* @version $Id: ToolContext.java 511959 2007-02-26 19:24:39Z nbubna $
*/
public class ToolContext implements Context
{
public static final String PATH_KEY = "requestPath";
public static final String CONTEXT_KEY = "velocityContext";
public static final String ENGINE_KEY = "velocityEngine";
public static final String LOCALE_KEY = "locale";
public static final String LOG_KEY = "log";
public static final String TOOLKEY_KEY = "key";
public static final String CATCH_EXCEPTIONS_KEY = "catchExceptions";
private List<Toolbox> toolboxes = new ArrayList<Toolbox>();
// this is meant solely for tool setup,
// values in here are not part of the Context
private Map<String,Object> toolProps = new HashMap<String,Object>(12);
// this is only for values added during use of this context
private Map<String,Object> localContext = new HashMap<String,Object>();
private boolean userOverwrite = true;
public ToolContext()
{
// add this as a common tool property
putToolProperty(CONTEXT_KEY, this);
}
/**
* Creates an instance that automatically has the specified
* VelocityEngine and related tool properties set.
* @param engine VelocityEngine instance
*/
public ToolContext(VelocityEngine engine)
{
this();
putVelocityEngine(engine);
}
/**
* Creates an instance starting with the specified tool properties.
* @param toolProps tools properties
*/
public ToolContext(Map<String,Object> toolProps)
{
this();
if (toolProps != null)
{
this.toolProps.putAll(toolProps);
}
}
/**
* Set whether or not tool references can be overwritten within a template.
* The default value is {@code true}. Set this to false if you want to
* ensure that your tool references are never replaced within the course
* of a template.
* @param overwrite flag value
*/
public void setUserCanOverwriteTools(boolean overwrite)
{
this.userOverwrite = overwrite;
}
/**
* Default is {@code true}.
* @return flag value
* @see #setUserCanOverwriteTools
*/
public boolean getUserCanOverwriteTools()
{
return this.userOverwrite;
}
public void addToolbox(Toolbox toolbox)
{
toolboxes.add(toolbox);
}
/**
* Returns a {@link Map} of all tools available to this
* context. NOTE: this is not a cheap operation as it will
* request and initialize an instance of every available tool.
* @return aggregated toolbox of all available tools
*/
public Map<String,Object> getToolbox()
{
Map<String,Object> aggregate = new HashMap<String,Object>();
Map<String,Object> toolProps = getToolProperties();
for (Toolbox toolbox : getToolboxes())
{
aggregate.putAll(toolbox.getAll(toolProps));
}
return aggregate;
}
/**
* Gets a map of keys to classes for all available tools.
* This does not include any data nor any local context values.
* @return aggregated map of all available tools classes
*/
public Map<String,Class> getToolClassMap()
{
Map<String,Class> toolClasses = new HashMap<String,Class>();
// go thru toolboxes backwards so final map matches
// what would be found in lookups
int n = getToolboxes().size();
for (int i = n - 1; i >= 0; i--)
{
Toolbox toolbox = getToolboxes().get(i);
toolClasses.putAll(toolbox.getToolClassMap());
}
return toolClasses;
}
protected List<Toolbox> getToolboxes()
{
return this.toolboxes;
}
protected Map<String,Object> getToolProperties()
{
return this.toolProps;
}
/**
* Puts the specified VelocityEngine in the tool properties,
* as well as the Log for that engine. Last, if the specified
* engine has a MethodExceptionEventHandler configured, then
* this will automatically set {@link #CATCH_EXCEPTIONS_KEY}
* to false in the tool properties.
* @param engine VelocityEngine instance
*/
public void putVelocityEngine(VelocityEngine engine)
{
// add the engine and log as common tool properties
putToolProperty(ENGINE_KEY, engine);
putToolProperty(LOG_KEY, ConfigurationUtils.getLog(engine, "tools"));
// tell interested tools not to catch exceptions whenever there's a
// method exception event handler configured for the engine
Object ehme =
engine.getProperty(VelocityEngine.EVENTHANDLER_METHODEXCEPTION);
if (ehme != null)
{
putToolProperty(CATCH_EXCEPTIONS_KEY, Boolean.FALSE);
}
}
public Object putToolProperty(String key, Object value)
{
return toolProps.put(key, value);
}
public void putToolProperties(Map<String,Object> props)
{
if (props != null)
{
for (Map.Entry<String,Object> prop : props.entrySet())
{
putToolProperty(prop.getKey(), prop.getValue());
}
}
}
public Object put(String key, Object value)
{
return localContext.put(key, value);
}
public Object get(String key)
{
// for user overwriting, it's all a matter of which we check first
Object value = userOverwrite ? internalGet(key) : findTool(key);
if (value == null)
{
value = userOverwrite ? findTool(key) : internalGet(key);
}
return value;
}
protected Object internalGet(String key)
{
return localContext.get(key);
}
protected Object findTool(String key)
{
String path = (String)toolProps.get(PATH_KEY);
for (Toolbox toolbox : getToolboxes())
{
Object tool = toolbox.get(key, path, toolProps);
if (tool != null)
{
return tool;
}
}
return null;
}
public Set<String> keySet()
{
Set<String> keys = new HashSet<String>();
for (Toolbox toolbox : getToolboxes())
{
keys.addAll(toolbox.getKeys());
}
keys.addAll(localContext.keySet());
return keys;
}
public boolean containsKey(String key)
{
return keySet().contains(key);
}
public String[] getKeys()
{
Set<String> keys = keySet();
return keys.toArray(new String[keys.size()]);
}
public Object remove(String key)
{
//tools and their props cannot be removed
return localContext.remove(key);
}
public void putAll(Map context)
{
localContext.putAll(context);
}
}