/* * FreeMarker: a tool that allows Java programs to generate HTML * output using templates. * Copyright (C) 1998-2005 Benjamin Geer * Email: beroul@users.sourceforge.net * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ package freemarker.template; import java.io.Serializable; import java.util.HashMap; import java.util.Map; /** * <p> * Wraps a template hash model with a template model root. The hash model can be * accessed transparently from the root of this model. Any local variables are * stored within a <code>HashMap</code>. Anything that doesn't exist within the * <code>HashMap</code> is automatically forwarded to the wrapped hash model. * Local variables are counted as being any variables added using the * {@link #put put()} method. * </p> * * <p> * Use this class when your template model (the hash model) is shared across * several template calls, possibly multithreaded, and you want to be sure that * the model isn't inadvertantly changed between calls. * </p> * * <p> * To do this for multithreaded calls, create a separate * <code>RootModelWrapper</code> object for each template call, passing in the * data model you want to be left unchanged. Then, call your templates with each * <code>RootModelWrapper</code> object as your root data model. * </p> * * <p> * To do this for synchronous calls, it is sufficient to create one * <code>RootModelWrapper</code> object, passing in the data model you want to * be left unchanged. Then, call your templates with the * <code>RootModelWrapper</code> object as your root data model, and call the * {@link #reset} method between each template call. * </p> * * <p> * This class was previously in the <code>freemarker.ext.misc</code> package. * </p> * * @version $Id: RootModelWrapper.java 1189 2005-10-16 01:53:54Z run2000 $ * @since 1.8 * @see LocalModelWrapper */ public class RootModelWrapper implements TemplateModelRoot, Serializable { /** * The map containing temporary values for the root model. * * @serial a <code>Map</code> containing any values added to the template * model at run time. */ protected Map rootModel; /** * The underlying template hash being wrapped. * * @serial the underlying <code>TemplateHashModel</code> being wrapped by * this wrapper object */ protected TemplateHashModel hashModel; /** Class UUID for serialization. */ private static final long serialVersionUID = 5887349023424507785L; /** * Create a new <code>RootModelWrapper</code> with the given hash model as * the model to be wrapped. * * @param hashModel * the hash model to be wrapped */ public RootModelWrapper(TemplateHashModel hashModel) { this.hashModel = hashModel; rootModel = new HashMap(); } /** * Retrieve a template model for the given key, if one exists. First, look * at the local storage to see if we have an entry. If so, return the local * entry. Otherwise, forward the call to the wrapped hash model. * * @param key * the name of the value to be returned * @return a TemplateModel for the corresponding key, if one exists, * otherwise <code>null</code> * @throws TemplateModelException * there was a problem with the underlying hash model */ public TemplateModel get(String key) throws TemplateModelException { if (rootModel.containsKey(key)) { return (TemplateModel) rootModel.get(key); } return hashModel.get(key); } /** * Returns whether we have a completely empty model. If the local storage is * non-empty, return <code>false</code>. Otherwise, forward the call to the * wrapped hash model. * * @return <code>true</code> if the model is empty, otherwise * <code>false</code> * @throws TemplateModelException * there was a problem with underlying hash model */ public boolean isEmpty() throws TemplateModelException { if (rootModel.isEmpty()) { return hashModel.isEmpty(); } return false; } /** * Put the given template model into local storage with the given key. * * @param key * the name of the model to be stored * @param model * the model being stored locally */ public void put(String key, TemplateModel model) { rootModel.put(key, model); } /** * <p> * Remove the named model from local storage. * </p> * * <p> * Note that we don't attempt to block access to the hash model when we * remove a key. This is because the only time a "remove" call is performed * is when the template engine is sure that there was no underlying data for * that key to begin with. * </p> * * @param key * the name of the model to be removed */ public void remove(String key) { rootModel.remove(key); } /** * Clear all the local variables from the local storage, and just provide * pass-through access to the wrapped hash model. */ public void reset() { rootModel.clear(); } /** * Returns a string representation of the object. * * @return a string representation of the object. */ public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append("RootModelWrapper, "); buffer.append(rootModel.size()); buffer.append(" local items."); return buffer.toString(); } }