/* * SessionBean.java * * This work is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2 of the License, * or (at your option) any later version. * * This work 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 * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA * * Copyright (c) 2004-2006 Per Cederberg. All rights reserved. */ package org.liquidsite.app.template; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import freemarker.template.TemplateBooleanModel; import freemarker.template.TemplateHashModel; import freemarker.template.TemplateMethodModel; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; import freemarker.template.TemplateScalarModel; import freemarker.template.TemplateSequenceModel; import org.liquidsite.core.web.RequestSession; /** * A user session bean. This class is used to access and manipulate * session data from the template data model. * * @author Per Cederberg, <per at percederberg dot net> * @version 1.0 */ public class SessionBean extends TemplateBean implements TemplateHashModel { /** * The session data attribute. */ private static final String DATA_ATTRIBUTE = "template.data"; /** * Creates a new session template bean. * * @param context the bean context */ SessionBean(BeanContext context) { super(context); } /** * Returns the request session. * * @return the request session */ private RequestSession getSession() { return getContextRequest().getSession(); } /** * Checks if the session data hash model is empty. * * @return false as the hash model can always be extended */ public boolean isEmpty() { return false; } /** * Returns a session data value as a template model. * * @param name the data key name * * @return the template model object */ public TemplateModel get(String name) { Object obj; HashMap map; // Handle default methods & properties if (name.equals("clear")) { return new TemplateMethodModel() { public Object exec(List args) { clear(); return NOTHING; } }; } else if (name.equals("create")) { return new TemplateMethodModel() { public Object exec(List args) { create(); return NOTHING; } }; } else if (name.equals("destroy")) { return new TemplateMethodModel() { public Object exec(List args) { destroy(); return NOTHING; } }; } else if (name.equals("exists")) { if (getContextRequest().hasSession()) { return TemplateBooleanModel.TRUE; } else { return TemplateBooleanModel.FALSE; } } // Handle hash values obj = getSession().getAttribute(DATA_ATTRIBUTE); if (obj instanceof HashMap) { map = (HashMap) obj; } else { map = new HashMap(); getSession().setAttribute(DATA_ATTRIBUTE, map); } return new SessionDataBean(map, name, -1); } /** * Clears all the data in the user session. */ public void clear() { getSession().setAttribute(DATA_ATTRIBUTE, null); } /** * Creates a user session if none existed previously. */ public void create() { getSession(); } /** * Destroys the user session. This is identical to logging out the * user. */ public void destroy() { getSession().invalidate(); } /** * The session data model bean. This bean wraps all the session * data hierachy. The objects can be treated as scalars, hashes or * sequences, mostly interchangably. This class really represents * a pointer to the data, making it possible to modify or remove * data via this bean. * * @author Per Cederberg, <per at percederberg dot net> * @version 1.0 */ public class SessionDataBean implements TemplateScalarModel, TemplateHashModel, TemplateSequenceModel { /** * The parent hash map, containing this value. This references * is required in order to manipulate or remove the data. */ private HashMap parent; /** * The data key name in the parent hash map. */ private String key; /** * The array index in the data, if it represents an ArrayList. * This value is set to -1 if no array index has been * specified, which can be interpreted as an implicit 0. */ private int index; /** * Creates a new session data bean. * * @param parent the parent hash map * @param key the data key name in the hash map * @param index the array index, or -1 for none */ SessionDataBean(HashMap parent, String key, int index) { this.parent = parent; this.key = key; this.index = index; } /** * Returns the session data value as a string. If the value * pointed to is a hash map, an empty string will be returned. * If the value is a list, the first value in the list will be * returned. * * @return the session data value as a string * * @throws TemplateModelException if this object points to an * index that has been removed */ public String getAsString() throws TemplateModelException { Object obj = parent.get(key); ArrayList list; String message; if (obj instanceof String && index < 1) { return (String) obj; } else if (obj instanceof ArrayList) { list = (ArrayList) obj; if (index < 0 && list.size() > 0) { obj = list.get(0); } else if (index >= 0 && index < list.size()) { obj = list.get(index); } else { message = "index " + index + " has been removed"; throw new TemplateModelException(message); } if (obj instanceof String) { return (String) obj; } } return ""; } /** * Checks if the hash model is empty. * * @return false as the hash model can always be extended */ public boolean isEmpty() { return false; } /** * Returns a session data value from a hash key name. The * value will always be returned as another instance of this * class. If the value in this object isn't a hash map, it * will be created and any previous string value discarded. If * the value in this object is an array list, the first * element in the list will be used implicitly. * * @param name the session data key name * * @return the template model object, or * NOTHING if the object points to a removed index */ public TemplateModel get(String name) { Object obj = parent.get(key); HashMap map; ArrayList list; // Handle methods if (name.equals("add")) { return new TemplateMethodModel() { public Object exec(List args) throws TemplateModelException { if (args.size() <= 0) { add(new HashMap()); } else { add(args.get(0)); } return NOTHING; } }; } else if (name.equals("remove")) { return new TemplateMethodModel() { public Object exec(List args) { remove(); return NOTHING; } }; } // Handle hash values if (obj instanceof HashMap) { map = (HashMap) obj; } else if (obj instanceof ArrayList) { list = (ArrayList) obj; if (index < 0 && list.size() > 0) { obj = list.get(0); } else if (index >= 0 && index < list.size()) { obj = list.get(index); } else { return NOTHING; } if (obj instanceof HashMap) { map = (HashMap) obj; } else { map = new HashMap(); if (index < 0) { list.add(0, map); } else { list.add(index, map); } } } else { map = new HashMap(); parent.put(key, map); } return new SessionDataBean(map, name, -1); } /** * Returns a session data value from an array index. The value * will always be returned as another instance of this class. * If the value in this object isn't an array, the only index * allowed will be zero. Otherwise, only valid indices are * allowed, or an index out of bounds exception will be * launched. * * @param index the session data index * * @return the template model object, or * NOTHING if the index was out of bounds * * @throws TemplateModelException if a double index * indirection was attempted */ public TemplateModel get(int index) throws TemplateModelException { Object obj = parent.get(key); ArrayList list; String message; if (this.index >= 0) { message = "multiple indexes are not supported"; throw new TemplateModelException(message); } if (obj instanceof String && index == 0) { return new SessionDataBean(parent, key, index); } else if (obj instanceof HashMap && index == 0) { return new SessionDataBean(parent, key, index); } else if (obj instanceof ArrayList) { list = (ArrayList) obj; if (index >= 0 && index < list.size()) { return new SessionDataBean(parent, key, index); } } return NOTHING; } /** * Returns the size of the session data value list. If the * value in this object isn't a list, zero or one will be * returned depending on whether it exists or not. * * @return the size of the session data value list */ public int size() { Object obj = parent.get(key); if (this.index >= 0) { return 0; } if (obj instanceof String) { return 1; } else if (obj instanceof HashMap) { return 1; } else if (obj instanceof ArrayList) { return ((ArrayList) obj).size(); } else { return 0; } } /** * Adds a value to this session data object. If the object * already contains a value, it will be converted to a list * and the new value will be added last. * * @param value the data value to add * * @throws TemplateModelException if an attempt was made to * add values to a specific index */ public void add(Object value) throws TemplateModelException { Object obj = parent.get(key); ArrayList list; String message; if (index >= 0) { message = "cannot add values to a specific index"; throw new TemplateModelException(message); } if (obj == null) { parent.put(key, value); } else if (obj instanceof ArrayList) { list = (ArrayList) obj; list.add(value); } else { list = new ArrayList(); list.add(obj); list.add(value); parent.put(key, list); } } /** * Removes this session data object. If the object points to * an index in a list, only the specified index will be * removed. */ public void remove() { Object obj = parent.get(key); ArrayList list; if (index >= 0 && obj instanceof ArrayList) { list = (ArrayList) obj; if (index < list.size()) { list.remove(index); } } else { parent.remove(key); } } } }