blob: c9520333a9b468a2701972af4c1410f54862cd97 [file] [log] [blame]
package org.apache.turbine.services.pull.util;
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2001-2003 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 acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" and
* "Apache Turbine" 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",
* "Apache Turbine", nor may "Apache" appear in their name, without
* prior written permission of the Apache Software Foundation.
*
* 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.io.FileInputStream;
import java.util.Properties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.turbine.Turbine;
import org.apache.turbine.om.security.User;
import org.apache.turbine.services.pull.ApplicationTool;
import org.apache.turbine.services.pull.TurbinePull;
import org.apache.turbine.util.RunData;
import org.apache.turbine.util.ServerData;
import org.apache.turbine.util.uri.DataURI;
/**
* UIManager.java
* <br>
* Manages all UI elements for a Turbine Application. Any
* UI element can be accessed in any template using the
* $ui handle (assuming you use the default PullService
* configuration). So, for example, you could access
* the background colour for your pages by using
* $ui.bgcolor
* <p>
* <h3>Questions:</h3>
* What is the best way to allow an application
* to be skinned. And how to allow the flexible
* altering of a particular UI element in certain
* parts of the template hierarchy. For example
* on one section of your site you might like
* a certain bgcolor, on another part of your
* site you might want another. How can be let
* the designer specify these properties and
* still use the single $app.ui.bgcolor in
* all the templates.
* <p>
* It would also be very cool to use some form
* of inheritence for UI elements. Say a $ui.bgcolor
* is used in a template where the bgcolor is not
* set for that part of hierarch, it would be cool
* if it could find the setting for the bgcolor
* in the parent directory. So you could override
* a UI element where you wanted and the system
* would fall back to the parent when necessary.
* <p>
* How to specify skins, how to deal with images,
* how could this be handled with a web app.
* <p>
*
* This is an application pull tool for the template system. You should <b>not</b>
* use it in a normal application!
*
*
* @author <a href="mailto:jvanzyl@periapt.com">Jason van Zyl</a>
* @author <a href="mailto:james_coltman@majorband.co.uk">James Coltman</a>
* @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
* @version $Id$
*/
public class UIManager implements ApplicationTool
{
/** Logging */
private static Log log = LogFactory.getLog(UIManager.class);
/**
* The location of the skins within the application
* resources directory.
*/
private static final String SKINS_DIRECTORY = "/ui/skins";
/**
* The name of the directory where images are
* stored for this skin.
*/
private static final String IMAGES_DIRECTORY = "/images";
/**
* Property tag for the skin that is to be
* used for the web application.
*/
private static final String SKIN_PROPERTY = "tool.ui.skin";
/**
* Default skin name. This name actually represents
* a directory in the WEBAPP/resources/ui/skins
* directory. There is a file called skin.props
* which actually contains the name/value pairs.
*/
private static final String SKIN_PROPERTY_DEFAULT = "default";
/**
* Attribute name of skinName value in User's temp hashmap.
*/
private static final String SKIN_ATTRIBUTE =
UIManager.class.getName()+ ".skin";
/**
* The actual skin being used for the webapp.
*/
private String skinName;
/**
* The skins directory.
*/
private String skinsDirectory;
/**
* The file within the skin directory that actually
* contains the name/value pairs for the skin.
*/
private static final String SKIN_PROPS_FILE = "skin.props";
/**
* The file name for the skin style sheet.
*/
private static final String SKIN_CSS_FILE = "skin.css";
/**
* This the resources directory relative to the
* webapp context. Used for constructing correct
* URIs for retrieving images in image().
*/
private String resourcesDirectory;
/**
* Properties to hold the name/value pairs
* for the skin.
*/
private Properties skinProperties;
/**
* Initialize the UIManager object.
*
* @param data This is null, RunData or User depending upon specified tool scope.
*/
public void init(Object data)
{
/**
* Store the resources directory for use in image().
*/
resourcesDirectory = TurbinePull.getResourcesDirectory();
if (data == null)
{
log.debug("UI Manager scope is global");
setSkin();
}
else if (data instanceof RunData)
{
log.debug("UI Manager scope is request");
setSkin((RunData) data);
}
else if (data instanceof User)
{
log.debug("UI Manager scope is session");
setSkin((User) data);
}
skinsDirectory =
TurbinePull.getAbsolutePathToResourcesDirectory() + SKINS_DIRECTORY;
loadSkin();
}
/**
* This lets the tool know that it should be
* refreshed. The tool can perform whatever actions
* are necessary to refresh itself. This is necessary
* for sane development where you probably want the
* tools to refresh themselves on every request.
*/
public void refresh()
{
log.debug("Refreshing UI manager");
loadSkin();
}
/**
* Retrieve a property from the properties held
* within the properties file for this skin.
*/
public String get(String key)
{
return skinProperties.getProperty(key);
}
/**
* Retrieve the skin name.
*/
public String getSkin()
{
return skinName;
}
/**
* Retrieve the URL for an image that is part
* of a skin. The images are stored in the
* WEBAPP/resources/ui/skins/&lt;SKIN&gt;/images
* directory.
*
* Use this if for some reason your server name,
* server scheme, or server port change on a
* per request basis. I'm not sure if this
* would happend in a load balanced situation.
* I think in most cases the image(String image)
* method would probably be enough, but I'm not
* absolutely positive.
*/
public String image(String imageId, RunData data)
{
DataURI du = new DataURI(data);
StringBuffer sb = new StringBuffer();
sb.append(resourcesDirectory).
append(SKINS_DIRECTORY).
append("/").
append(getSkin()).
append(IMAGES_DIRECTORY).
append("/").
append(imageId);
du.setScriptName(sb.toString());
return du.getAbsoluteLink();
}
/**
* Retrieve the URL for an image that is part
* of a skin. The images are stored in the
* WEBAPP/resources/ui/skins/&lt;SKIN&gt;/images
* directory.
*/
public String image(String imageId)
{
ServerData sd = Turbine.getDefaultServerData();
DataURI du = new DataURI(sd);
StringBuffer sb = new StringBuffer();
sb.append(resourcesDirectory).
append(SKINS_DIRECTORY).
append("/").
append(getSkin()).
append(IMAGES_DIRECTORY).
append("/").
append(imageId);
du.setScriptName(sb.toString());
return du.getAbsoluteLink();
}
/**
* Retrieve the URL for the style sheet that is part
* of a skin. The style is stored in the
* WEBAPP/resources/ui/skins/&lt;SKIN&gt; directory with the
* filename skin.css
*
* Use this if for some reason your server name,
* server scheme, or server port change on a
* per request basis. I'm not sure if this
* would happend in a load balanced situation.
* I think in most cases the style()
* method would probably be enough, but I'm not
* absolutely positive.
*/
public String getStylecss(RunData data)
{
DataURI du = new DataURI(data);
StringBuffer sb = new StringBuffer();
sb.append(resourcesDirectory).
append(SKINS_DIRECTORY).
append("/").
append(getSkin()).
append("/").
append(SKIN_CSS_FILE);
du.setScriptName(sb.toString());
return du.getAbsoluteLink();
}
/**
* Retrieve the URL for the style sheet that is part
* of a skin. The style is stored in the
* WEBAPP/resources/ui/skins/&lt;SKIN&gt; directory with the
* filename skin.css
*/
public String getStylecss()
{
ServerData sd = Turbine.getDefaultServerData();
DataURI du = new DataURI(sd);
StringBuffer sb = new StringBuffer();
sb.append(resourcesDirectory).
append(SKINS_DIRECTORY).
append("/").
append(getSkin()).
append("/").
append(SKIN_CSS_FILE);
du.setScriptName(sb.toString());
return du.getAbsoluteLink();
}
/**
* Load the specified skin. In development mode
* this may occur frequently as the skin properties
* are being changed.
*/
private void loadSkin()
{
skinProperties = new Properties();
try
{
FileInputStream is = new FileInputStream(
skinsDirectory + "/" + getSkin() + "/" + SKIN_PROPS_FILE);
skinProperties.load(is);
}
catch (Exception e)
{
log.error("Cannot load skin: " + skinName);
}
}
/**
* Set the skin name to the skin from the TR.props
* file. If the property is not present use the
* default skin.
*/
public void setSkin()
{
this.skinName = Turbine.getConfiguration()
.getString(SKIN_PROPERTY,
SKIN_PROPERTY_DEFAULT);
}
/**
* Set the skin name to the specified skin.
*
* @param skinName the skin name to use.
*/
public void setSkin(String skinName)
{
this.skinName = skinName;
}
/**
* Set the skin name when the tool is configured to be
* loaded on a per-request basis. By default it calls getSkin
* to return the skin specified in TR.properties. Developers can
* write a subclass of UIManager that overrides this method to
* determine the skin to use based on information held in the request.
*
* @param data a RunData instance
*/
protected void setSkin(RunData data)
{
setSkin();
}
/**
* Set the skin name when the tool is configured to be
* loaded on a per-session basis. It the user's temp hashmap contains
* a value in the attribute specified by the String constant SKIN_ATTRIBUTE
* then that is returned. Otherwise it calls getSkin to return the skin
* specified in TR.properties.
*
* @param user a User instance
*/
protected void setSkin(User user)
{
if (user.getTemp(SKIN_ATTRIBUTE) == null)
{
setSkin();
}
else
{
setSkin((String) user.getTemp(SKIN_ATTRIBUTE));
}
}
/**
* Set the skin name user's temp hashmap for the current session.
*
* @param user a User instance
* @param skin the skin name for the session
*/
public static void setSkin(User user, String skin)
{
user.setTemp(SKIN_ATTRIBUTE, skin);
}
}