Performance related patches
David E Jones <[email protected]> Tue, 4 Mar 2003 19:20:26 -0800
| Newsgroups | gmane.comp.java.jpublish.devel |
|---|---|
| Organization | The Open For Business Project |
| Message-ID | <[email protected]> |
I've been doing some work on performance and resource management issues, so here are some patches related to that... The most major ones are in SiteContext (just changed how RepositoryContent is instantiated), and there are more changes in RepositoryContent and just the addition of an equals method in TemplateContent. These files are current as of the most recent CVS, ie as of a few minutes ago and are merged in. This set also includes some that I sent to Anthony earlier. I expect there will be some other patches, but these are the big ones for now... If you have any questions let me know. Later, -David E. Jones
SiteContext.java
(text/x-java, 42.5 KB)
/*--
Copyright (C) 2001-2003 Aetrion LLC.
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 disclaimer that follows
these conditions in the documentation and/or other materials
provided with the distribution.
3. The name "JPublish" must not be used to endorse or promote products
derived from this software without prior written permission. For
written permission, please contact [email protected].
4. Products derived from this software may not be called "JPublish", nor
may "JPublish" appear in their name, without prior written permission
from Aetrion LLC ([email protected]).
In addition, the authors of this software request (but do not require)
that you include in the end-user documentation provided with the
redistribution and/or in the software itself an acknowledgement equivalent
to the following:
"This product includes software developed by
Aetrion LLC (http://www.aetrion.com/)."
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 AUTHOR(S) 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.
For more information on JPublish, please see <http://www.jpublish.org/>.
*/
package org.jpublish;
import java.io.File;
import java.io.InputStream;
import java.io.FileInputStream;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;
import java.util.ArrayList;
import java.util.StringTokenizer;
import javax.servlet.ServletContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.anthonyeden.lib.util.IOUtilities;
import com.anthonyeden.lib.config.Configuration;
import com.anthonyeden.lib.config.XMLConfiguration;
import com.anthonyeden.lib.config.ConfigurationException;
import com.anthonyeden.lib.resource.ResourceRecipient;
import com.anthonyeden.lib.resource.FileResourceLoader;
import org.jpublish.view.ViewRenderer;
import org.jpublish.util.MimeTypeMap;
import org.jpublish.util.PathUtilities;
import org.jpublish.util.InternalURI;
import org.jpublish.util.RepositoryURI;
import org.jpublish.util.InternalURIParser;
import org.jpublish.util.CharacterEncodingManager;
import org.jpublish.action.ActionManager;
import org.jpublish.template.TemplateContent;
import org.jpublish.repository.RepositoryContent;
/** This class contains configuration information for a particular
site. Pages are loaded and actions are executed within the
context of the site and have access to all of the methods within
this class.
<p>Instances of the SiteContext class will also reload themselves
automatically when the underlying configuration file changes.</p>
@author Anthony Eden
*/
public class SiteContext implements ResourceRecipient{
public static final String DEFAULT_PAGE_MANAGER =
"org.jpublish.page.filesystem.FileSystemPageManager";
public static final String DEFAULT_TEMPLATE_MANAGER =
"org.jpublish.template.filesystem.FileSystemTemplateManager";
public static final String DEFAULT_STATIC_RESOURCE_MANAGER =
"org.jpublish.resource.filesystem.FileSystemStaticResourceManager";
public static final String DEFAULT_VIEW_RENDERER =
"org.jpublish.view.velocity.VelocityViewRenderer";
public static final String DEFAULT_COMPONENT_MANAGER =
"org.jpublish.component.InMemoryComponentManager";
public static final String DEFAULT_PAGE_ROOT = "pages";
public static final String DEFAULT_TEMPLATE_ROOT = "templates";
public static final String DEFAULT_ACTION_ROOT = "actions";
public static final String DEFAULT_STATIC_ROOT = "static";
public static final String DEFAULT_ACTION_INDENTIFIER = "action";
public static final String DEFAULT_PAGE = "index.html";
public static final String DEFAULT_TEMPLATE = "basic";
public static final Log syslog = LogFactory.getLog("syslog");
private static Log log = LogFactory.getLog(SiteContext.class);
private File configurationFile;
private FileResourceLoader fileResourceLoader;
private File root;
private File contextRoot;
private File pageRoot;
private File templateRoot;
private File actionRoot;
private File staticRoot;
private File webInfPath;
private ServletContext servletContext;
private String actionIdentifier;
private String defaultPage = DEFAULT_PAGE;
private String defaultTemplate = DEFAULT_TEMPLATE;
private boolean protectReservedNames = false;
private boolean parameterActionsEnabled = false;
private boolean debug = false;
private List modules;
private List repositories;
private List defaultErrorHandlers;
private Map errorHandlerMap;
private Map cachedErrorHandlers;
private PageManager pageManager;
private ActionManager actionManager;
private TemplateManager templateManager;
private StaticResourceManager staticResourceManager;
private ViewRenderer viewRenderer;
private ComponentManager componentManager;
private MimeTypeMap mimeTypeMap;
private CharacterEncodingManager characterEncodingManager;
private Map attributes;
/** Construct a new SiteContext using the given File to load the
context's configuration.
@param contextRoot Get the application context root
@param configurationFile The configuration File
@throws Exception
*/
public SiteContext(File contextRoot, String configPath) throws Exception{
setContextRoot(contextRoot);
File configurationFile = new File(configPath);
if(!configurationFile.isAbsolute()){
configurationFile = new File(contextRoot,
configurationFile.getPath());
}
this.configurationFile = configurationFile;
modules = new ArrayList();
repositories = new ArrayList();
defaultErrorHandlers = new ArrayList();
errorHandlerMap = new HashMap();
cachedErrorHandlers = new HashMap();
mimeTypeMap = new MimeTypeMap();
characterEncodingManager = new CharacterEncodingManager();
attributes = new HashMap();
fileResourceLoader = new FileResourceLoader();
fileResourceLoader.loadResource(configurationFile.getAbsolutePath(),
this);
}
/** Get the configuration File.
@return The configuration File
*/
public File getConfigurationFile(){
return configurationFile;
}
public ServletContext getServletContext(){
return servletContext;
}
public void setServletContext(ServletContext servletContext){
this.servletContext = servletContext;
}
/** Return the root directory. This directory may be used as
a base path for all of the other directories required by
JPublish. If the root is not set then this method will
return the context root.
@return The root directory
*/
public File getRoot(){
if(root == null){
log.debug("Root is null - using context root instead");
return getContextRoot();
}
return root;
}
/** Set the root directory.
@param root The new root directory
*/
public void setRoot(File root){
this.root = root;
}
/** Set the root directory.
@param root The new root directory
*/
public void setRoot(String root){
if(root != null){
setRoot(new File(root));
}
}
/** Get the context root. The context root is set by the
JPublishServlet. The value is the root of the web
application context.
@return The webapp context root
*/
public File getContextRoot(){
return contextRoot;
}
/** Set the context root.
@param contextRoot The new context root
*/
public void setContextRoot(File contextRoot){
log.debug("setContextRoot(" + contextRoot + ")");
this.contextRoot = contextRoot;
}
/** Set the context root.
@param contextRoot The new context root
*/
public void setContextRoot(String contextRoot){
if(contextRoot != null){
setContextRoot(new File(contextRoot));
}
}
/** Get the directory where page configuration files are stored. Page
configurations are stored as XML files and are cached to improve
performance. The page will automatically be reloaded if it is modified.
@return The page root
*/
public File getPageRoot(){
return pageRoot;
}
/** Set the directory where page configuration files are stored. Page
configurations are stored as XML files and are cached to improve
performance. The page will automatically be reloaded if it is modified.
@param pageRoot The new page root
*/
public void setPageRoot(File pageRoot){
this.pageRoot = pageRoot;
}
/** Set the directory where page configuration files are stored. Page
configurations are stored as XML files and are cached to improve
performance. The page will automatically be reloaded if it is modified.
@param pageRoot The new page root
*/
public void setPageRoot(String pageRoot){
if(pageRoot != null){
setPageRoot(new File(pageRoot));
}
}
/** If the value of <code>getPageRoot()</code> is an absolute file
path then that value is returned, otherwise the return value is
is <code>new File(getRoot(), getPageRoot())</code>.
@return The real page root
*/
public File getRealPageRoot(){
File pageRoot = getPageRoot();
if(!pageRoot.isAbsolute()){
pageRoot = new File(getRoot(), pageRoot.getPath());
}
return pageRoot;
}
/** Get the directory where templates are stored. Templates are merged
with the runtime context to produce a final document.
@return The template root
*/
public File getTemplateRoot(){
return templateRoot;
}
/** Set the directory where templates are stored. Templates are merged
with the runtime context to produce a final document.
@param templateRoot The template root
*/
public void setTemplateRoot(File templateRoot){
this.templateRoot = templateRoot;
}
/** Set the directory where templates are stored. Templates are merged
with the runtime context to produce a final document.
@param templateRoot The template root
*/
public void setTemplateRoot(String templateRoot){
if(templateRoot != null){
setTemplateRoot(new File(templateRoot));
}
}
/** If the value of <code>getTemplateRoot()</code> is an absolute file
path then that value is returned, otherwise the return value is
is <code>new File(getRoot(), getTemplateRoot())</code>.
@return The real template root
*/
public File getRealTemplateRoot(){
File templateRoot = getTemplateRoot();
if(!templateRoot.isAbsolute()){
templateRoot = new File(getRoot(), templateRoot.getPath());
}
return templateRoot;
}
/** Get the directory where action scripts are stored. Actions stored
here are scripts written in a language supported by the BSF library.
The language's Java implementation must be included in the classpath.
@return The action root
*/
public File getActionRoot(){
return actionRoot;
}
/** Set the directory where action scripts are stored. Actions stored
here are scripts written in a language supported by the BSF library.
The language's Java implementation must be included in the classpath.
@param actionRoot The new action root
*/
public void setActionRoot(File actionRoot){
this.actionRoot = actionRoot;
}
/** Set the directory where action scripts are stored. Actions stored
here are scripts written in a language supported by the BSF library.
The language's Java implementation must be included in the classpath.
@param actionRoot The new action root
*/
public void setActionRoot(String actionRoot){
if(actionRoot != null){
setActionRoot(new File(actionRoot));
}
}
/** If the value of <code>getActionRoot()</code> is an absolute file
path then that value is returned, otherwise the return value is
is <code>new File(getRoot(), getActionRoot())</code>.
@return The real action root
*/
public File getRealActionRoot(){
File actionRoot = getActionRoot();
if(!actionRoot.isAbsolute()){
actionRoot = new File(getRoot(), actionRoot.getPath());
}
return actionRoot;
}
/** Get the directory where static files are stored. Static files are
files which are not processed by JPublish but are returned byte for
byte.
@return The root directory where static files are stored
*/
public File getStaticRoot(){
return staticRoot;
}
/** Set the directory where static files are stored. Static files are
files which are not processed by JPublish but are returned byte for
byte.
@param staticRoot The new root directory where static files are stored
*/
public void setStaticRoot(File staticRoot){
this.staticRoot = staticRoot;
}
/** Set the directory where static files are stored. Static files are
files which are not processed by JPublish but are returned byte for
byte.
@param staticRoot The path of the new root directory where static
files are stored
*/
public void setStaticRoot(String staticRoot){
if(staticRoot != null){
setStaticRoot(new File(staticRoot));
}
}
/** If the value of <code>getStaticRoot()</code> is an absolute file
path then that value is returned, otherwise the return value is
is <code>new File(getRoot(), getStaticRoot())</code>.
@return The real static root
*/
public File getRealStaticRoot(){
File staticRoot = getStaticRoot();
if(!staticRoot.isAbsolute()){
staticRoot = new File(getRoot(), staticRoot.getPath());
}
return staticRoot;
}
/** Get the File for the WEB-INF directory. This is used to locate the
classes and JARs so they are accessible to scripting languages.
@return The WEB-INF file
*/
public File getWebInfPath(){
return webInfPath;
}
/** Set the File for the WEB-INF directory.
@param webInfPath The WEB-INF file
*/
public void setWebInfPath(File webInfPath){
this.webInfPath = webInfPath;
}
/** Get the action identifier which is used to trigger parameter actions.
The default value is 'action'.
@return The action identifier
*/
public String getActionIdentifier(){
return actionIdentifier;
}
/** Set the action identifier. If this method is invoked with a null
argument then the action identifier will be reset to the default
value.
@param actionIdentifier The new action identifer or null to reset
*/
public synchronized void setActionIdentifier(String actionIdentifier){
if(actionIdentifier == null){
this.actionIdentifier = DEFAULT_ACTION_INDENTIFIER;
} else {
this.actionIdentifier = actionIdentifier;
}
}
/** Return true if parameter actions are enabled.
@return True if parameter actions are enabled
@since 1.4.1
*/
public boolean isParameterActionsEnabled(){
return parameterActionsEnabled;
}
/** Set to true to enable parameter actions. Parameter actions are disabled
by default because of the inherent security risks involved in using
them.
@param parameterActionsEnabled True to enabled parameter actions
@since 1.4.1
*/
public void setParameterActionsEnabled(boolean parameterActionsEnabled){
this.parameterActionsEnabled = parameterActionsEnabled;
}
/** Set to true to enable parameter actions. Parameter actions are disabled
by default because of the inherent security risks involved in using
them.
@param parameterActionsEnabled True to enabled parameter actions
@since 1.4.1
*/
public void setParameterActionsEnabled(String parameterActionsEnabled){
setParameterActionsEnabled("true".equals(parameterActionsEnabled));
}
/** Get the default page. This value will be used when directories
are requested. By default this returns 'index.html'.
@return The default page
*/
public String getDefaultPage(){
return defaultPage;
}
/** Set the default page. This value will be used when directories
are requested.
@param defaultPage The new default page
*/
public void setDefaultPage(String defaultPage){
this.defaultPage = defaultPage;
}
/** Get the default template. This method returns the name of the
template which will be used when no template is specified in
a page's configuration.
@return The default template
*/
public String getDefaultTemplate(){
return defaultTemplate;
}
/** Set the default template. The default template will be used when
no template is specified in a page's configuration.
@param defaultTemplate The new default template
*/
public void setDefaultTemplate(String defaultTemplate){
this.defaultTemplate = defaultTemplate;
}
/** Get the default mime type. This method delegates to the current
MimeTypeMap.
@return The default mime type
*/
public String getDefaultMimeType(){
return getMimeTypeMap().getDefaultMimeType();
}
/** Set the default mime type. This method delegates to the current
MimeTypeMap.
@param defaultMimeType The new default mime type
*/
public void setDefaultMimeType(String defaultMimeType){
getMimeTypeMap().setDefaultMimeType(defaultMimeType);
}
/** Returns true if reserved names should be protected in the
JPublishContext. This method returns false by default.
@return True if reserved names should be protected
*/
public boolean isProtectReservedNames(){
return protectReservedNames;
}
/** Set to true to protect reserved names in the JPublishContext.
@param protectReservedNames True to protect reserved names
*/
public void setProtectReservedNames(boolean protectReservedNames){
if(protectReservedNames)
log.info("Protect reserved names enabled");
this.protectReservedNames = protectReservedNames;
}
/** Set to "true" to protect reserved names in the JPublishContext.
@param protectReservedNames "true" to protect reserved names
*/
public void setProtectReservedNames(String protectReservedNames){
setProtectReservedNames("true".equals(protectReservedNames));
}
/** Return true if debugging is enabled.
@return True if debugging is enabled
*/
public boolean isDebug(){
return debug;
}
/** Set to true to enable debugging.
@param debug True to enable debugging
*/
public void setDebug(boolean debug){
if(debug)
log.info("JPublish debugging enabled.");
this.debug = debug;
}
/** Set to "true" to enable debugging.
@param debug "true" to enable debugging
*/
public void setDebug(String debug){
setDebug("true".equals(debug));
}
/** Get a List of all loaded modules.
@return List of loaded modules
*/
public List getModules(){
return modules;
}
/** Get a list of all registered repositories.
@return A list of all registered Repository objects
*/
public List getRepositories(){
return repositories;
}
/** Get a List of all error handlers for the given path. The path can
include the '*' wildcard. If there are no error handlers for the
given path then this method will return the default handlers. If
you do not want any handlers then define a error handler mapping
with no defined error handlers.
@param path The path
@return A List of error handlers
*/
public List getErrorHandlers(String path){
List errorHandlers = (List)cachedErrorHandlers.get(path);
if(errorHandlers == null){
Iterator keys = errorHandlerMap.keySet().iterator();
while(keys.hasNext()){
String key = (String)keys.next();
if(PathUtilities.match(path, key)){
errorHandlers = (List)errorHandlerMap.get(key);
cachedErrorHandlers.put(path, errorHandlers);
return errorHandlers;
}
}
return getDefaultErrorHandlers();
} else {
return errorHandlers;
}
}
/** Get the List of default error handlers. These error handlers should
be used whenever no error handlers are defined.
@return The default error handlers
*/
public List getDefaultErrorHandlers(){
return defaultErrorHandlers;
}
/** Get a Repository by name. If the repository was not registered
then this method will return null.
@param name The name of the Repository
@return The repository or null
*/
public Repository getRepository(String name){
Iterator iter = getRepositories().iterator();
while(iter.hasNext()){
Repository repository = (Repository)iter.next();
if(repository.getName().equals(name)){
return repository;
}
}
return null;
}
/** Get the site's ActionManager.
@return The ActionManager
@see org.jpublish.action.ActionManager
*/
public ActionManager getActionManager(){
return actionManager;
}
/** Get the site's PageManager.
@return The PageManager
@see org.jpublish.PageManager
*/
public PageManager getPageManager(){
return pageManager;
}
/** Get the site's TemplateManager.
@return The TemplateManager
@see org.jpublish.TemplateManager
*/
public TemplateManager getTemplateManager(){
return templateManager;
}
/** Get the site's StaticResourceManager.
@return The StaticResourceManager
@see org.jpublish.StaticResourceManager
*/
public StaticResourceManager getStaticResourceManager(){
return staticResourceManager;
}
/** Get the site's ViewRenderer which is used to render content.
@return The ViewRenderer
*/
public ViewRenderer getViewRenderer(){
return viewRenderer;
}
/** Get the site's ComponentManager.
@return The ComponentManager
@since 2.0
*/
public ComponentManager getComponentManager(){
return componentManager;
}
/** Get the site's MimeType map. Mime types can be mapped to file
suffixes.
@return The MimeTypeMap
*/
public MimeTypeMap getMimeTypeMap(){
return mimeTypeMap;
}
/** Return the CharacterEncodingManager.
@return The CharacterEncodingManager
*/
public CharacterEncodingManager getCharacterEncodingManager(){
return characterEncodingManager;
}
/** Retrieve a Content object for the specified named content. The content
name must include the origin prefix. In the case of content pulled from
a repository this would be:
<blockquote>
<code>repository:repository_name://path/to/content</code>
</blockquote>
<p>In the case of templates, this would be:</p>
<blockquote>
<code>template:/path/to/template</code>
</blockquote>
<p>Ultimately there should be a common repository system for all content
whether it be text content, templates, binary content, etc.</p>
<p>This method must return null if the named content can not be
found.</p>
@param name The content name
@return The Content object
*/
public Content getContent(String name){
try{
if (log.isDebugEnabled()) log.debug("getContent(" + name + ")");
InternalURI uri = InternalURIParser.getInstance().parse(name);
String protocol = uri.getProtocol();
if(protocol.equalsIgnoreCase("template")){
String path = uri.getPath();
if (log.isDebugEnabled()) log.debug("Looking for template: " + path);
return new TemplateContent(templateManager.getTemplate(path));
} else if(protocol.equalsIgnoreCase("repository")){
String repositoryName =
((RepositoryURI)uri).getRepositoryName();
Repository r = getRepository(repositoryName);
String path = uri.getPath();
if (log.isDebugEnabled()) log.debug("Looking for content: " + path);
return new RepositoryContent(r, path);
} else {
log.warn("Protocol " + protocol + " not supported");
return null;
}
} catch(Throwable t){
// this is necessary to support FreeMarker for the moment.
// FreeMarker adds localized parts to the file path and thus
// the file will not be found on the first try, but FreeMarker
// requires that this method return null, so voila! When they
// fix the setLocalizedLookup() method so false works I will
// probably remove this.
log.error("Error getting content: " + t.getMessage());
return null;
}
}
// Start Attribute support
/** Get the named site attribute. Returns null if there is no
site attribute for the specified name.
@param name The attribute name
@return The site attribute or null
*/
public Object getAttribute(String name){
return attributes.get(name);
}
/** Set the named site attribute.
@param name The site attribute name
@param value The site attribute value
*/
public void setAttribute(String name, Object value){
attributes.put(name, value);
}
/** Remove the named site attribute.
@param name The site attribute name
*/
public void removeAttribute(String name){
attributes.remove(name);
}
/** Get an Iterator of all names for site attributes.
@return Iterator of attribute names
*/
public Iterator getAttributeNames(){
return attributes.keySet().iterator();
}
// End Attribute support
/** Reload the site configuration. */
public void reload(){
try{
log.info("Loading site configuration.");
loadConfiguration();
log.info("Configuration loaded.");
} catch(Exception e){
e.printStackTrace();
}
}
/** Load the site configuration from the given InputStream. The
InputStream must be attached to an XML document.
@param in The InputStream
@throws Exception
*/
public void load(InputStream in) throws Exception{
log.debug("Loading configuration");
// construct the Configuration object from the stream
Configuration configuration = new XMLConfiguration(in);
// get the classloader
ClassLoader cl = Thread.currentThread().getContextClassLoader();
// construct the ActionManager
actionManager = new ActionManager(this);
// setup the ActionManager
Configuration actionManagerConfiguration = configuration.getChild(
"action-manager");
if(actionManagerConfiguration != null){
List classPathElements = actionManager.getClassPathElements();
Configuration classpathConfiguration =
actionManagerConfiguration.getChild("classpath");
Iterator pathElements =
classpathConfiguration.getChildren("pathelement").iterator();
while(pathElements.hasNext()){
Configuration pathElement = (Configuration)pathElements.next();
classPathElements.add(pathElement.getValue());
}
}
// load the PageManager
log.debug("Creating PageManager");
Configuration pageManagerConfiguration = configuration.getChild(
"page-manager");
if(pageManagerConfiguration != null){
String pageManagerClass = pageManagerConfiguration.getAttribute(
"classname");
if(pageManagerClass == null){
// handle using page-manager value as class name
pageManagerClass = pageManagerConfiguration.getValue();
log.warn("The page-manager class should now be specified " +
"using the classname attribute");
}
pageManager =
(PageManager)cl.loadClass(pageManagerClass).newInstance();
pageManager.setSiteContext(this);
pageManager.loadConfiguration(pageManagerConfiguration);
} else {
pageManager =
(PageManager)cl.loadClass(DEFAULT_PAGE_MANAGER).newInstance();
pageManager.setSiteContext(this);
}
// load the TemplateManager
log.debug("Creating TemplateManager");
Configuration templateManagerConfiguration =
configuration.getChild("template-manager");
if(templateManagerConfiguration != null){
String templateManagerClass =
templateManagerConfiguration.getAttribute("classname");
if(templateManagerClass == null){
// handle using element value as class name
templateManagerClass = templateManagerConfiguration.getValue();
log.warn("The template-manager class should now be specified " +
"using the classname attribute");
}
templateManager = (TemplateManager)cl.loadClass(
templateManagerClass).newInstance();
templateManager.setSiteContext(this);
templateManager.loadConfiguration(templateManagerConfiguration);
} else {
templateManager = (TemplateManager)cl.loadClass(
DEFAULT_TEMPLATE_MANAGER).newInstance();
templateManager.setSiteContext(this);
}
// load the StaticResourceManager
log.debug("Creating StaticResourceManager");
Configuration staticResourceManagerConfiguration =
configuration.getChild("static-resource-manager");
if(staticResourceManagerConfiguration != null){
String staticResourceManagerClass =
staticResourceManagerConfiguration.getAttribute("classname");
if(staticResourceManagerClass == null){
// handle using element value as class name
staticResourceManagerClass =
staticResourceManagerConfiguration.getValue();
log.warn("The static-resource-manager class should be " +
"specified using the classname attribute");
}
staticResourceManager = (StaticResourceManager)cl.loadClass(
staticResourceManagerClass).newInstance();
staticResourceManager.setSiteContext(this);
staticResourceManager.loadConfiguration(
staticResourceManagerConfiguration);
} else {
staticResourceManager = (StaticResourceManager)cl.loadClass(
DEFAULT_STATIC_RESOURCE_MANAGER).newInstance();
staticResourceManager.setSiteContext(this);
}
// load the ViewRenderer
log.debug("Creating ViewRenderer");
Configuration viewRendererConfiguration =
configuration.getChild("view-renderer");
if(viewRendererConfiguration != null){
String viewRendererClass =
viewRendererConfiguration.getAttribute("classname");
if(viewRendererClass == null){
// handle using element value as class name
viewRendererClass =
viewRendererConfiguration.getValue();
log.warn("The view-renderer class should be " +
"specified using the classname attribute");
}
viewRenderer = (ViewRenderer)cl.loadClass(
viewRendererClass).newInstance();
viewRenderer.setSiteContext(this);
viewRenderer.loadConfiguration(viewRendererConfiguration);
} else {
viewRenderer = (ViewRenderer)cl.loadClass(
DEFAULT_VIEW_RENDERER).newInstance();
viewRenderer.setSiteContext(this);
}
log.debug("View renderer: " + viewRenderer.getClass());
viewRenderer.init();
// load modules
Iterator moduleElements =
configuration.getChildren("module").iterator();
while(moduleElements.hasNext()){
Configuration moduleElement = (Configuration)moduleElements.next();
String className = moduleElement.getAttribute("classname");
try{
JPublishModule module =
(JPublishModule)cl.loadClass(className).newInstance();
module.init(this, moduleElement);
modules.add(module);
} catch(Exception e){
log.error("Unable to load module " + className);
e.printStackTrace();
}
}
// load repository references
Iterator repositoryElements =
configuration.getChildren("repository").iterator();
while(repositoryElements.hasNext()){
Configuration repositoryElement =
(Configuration)repositoryElements.next();
String className = repositoryElement.getAttribute("classname");
Repository repository =
(Repository)cl.loadClass(className).newInstance();
repository.setSiteContext(this);
repository.loadConfiguration(repositoryElement);
getRepositories().add(repository);
}
// load the ComponentManager
log.debug("Creating ComponentManager");
Configuration componentManagerConfiguration =
configuration.getChild("component-manager");
String componentManagerClass = null;
if(componentManagerConfiguration != null){
componentManagerClass =
componentManagerConfiguration.getAttribute("classname");
}
if(componentManagerClass == null){
componentManagerClass = DEFAULT_COMPONENT_MANAGER;
}
log.info("Component manager class: " + componentManagerClass);
componentManager = (ComponentManager)cl.loadClass(
componentManagerClass).newInstance();
componentManager.setSiteContext(this);
if(componentManagerConfiguration != null){
componentManager.loadConfiguration(componentManagerConfiguration);
}
// Configure root paths
setRoot(configuration.getChildValue("root"));
// eventually these should be moved into the configuration
// methods for the actual managers since having roots only
// makes sense there
setPageRoot(configuration.getChildValue("page-root",
DEFAULT_PAGE_ROOT));
setTemplateRoot(configuration.getChildValue("template-root",
DEFAULT_TEMPLATE_ROOT));
setActionRoot(configuration.getChildValue("action-root",
DEFAULT_ACTION_ROOT));
setStaticRoot(configuration.getChildValue("static-root",
DEFAULT_STATIC_ROOT));
setActionIdentifier(configuration.getChildValue("action-identifier"));
// Set defaults
setDefaultPage(configuration.getChildValue("default-page",
DEFAULT_PAGE));
setDefaultTemplate(configuration.getChildValue("default-template",
DEFAULT_TEMPLATE));
setDefaultMimeType(configuration.getChildValue("default-mime-type"));
// configuration JNDI settings
log.debug("Configuring JNDI");
configureJNDI(configuration.getChild("jndi"));
// protect reserved names in the context
setProtectReservedNames(configuration.getChildValue(
"protect-reserved-names", "false"));
// enable or disable parameter actions
setParameterActionsEnabled(configuration.getChildValue(
"parameter-actions-enabled", "false"));
// enable or disable debugging
setDebug(configuration.getChildValue("debug", "false"));
// load character encoding maps
log.debug("Loading CharacterEncodingMaps");
characterEncodingManager.loadConfiguration(configuration);
// load all actions
actionManager.loadConfiguration(configuration);
// load the mime type map
Iterator mimeTypeMapElements =
configuration.getChildren("mime-mapping").iterator();
while(mimeTypeMapElements.hasNext()){
Configuration mimeTypeMapElement =
(Configuration)mimeTypeMapElements.next();
String ext = mimeTypeMapElement.getAttribute("ext");
String mimeType = mimeTypeMapElement.getAttribute("mimetype");
mimeTypeMap.put(ext, mimeType);
}
// load default error handlers
Configuration defaultErrorHandlersElement =
configuration.getChild("default-error-handlers");
if(defaultErrorHandlersElement != null){
Iterator defaultErrorHandlerElements =
defaultErrorHandlersElement.getChildren(
"error-handler").iterator();
while(defaultErrorHandlerElements.hasNext()){
Configuration defaultErrorHandlerElement =
(Configuration)defaultErrorHandlerElements.next();
String className =
defaultErrorHandlerElement.getAttribute("class");
defaultErrorHandlers.add(cl.loadClass(className).newInstance());
}
}
// load error handlers
Iterator errorHandlerMapElements =
configuration.getChildren("error-handler-map").iterator();
while(errorHandlerMapElements.hasNext()){
Configuration errorHandlerMapElement =
(Configuration)errorHandlerMapElements.next();
String path = errorHandlerMapElement.getAttribute("path");
if(path == null){
throw new ConfigurationException(
"Error handler path must be defined");
}
Iterator errorHandlerElements =
errorHandlerMapElement.getChildren("error-handler").iterator();
while(errorHandlerElements.hasNext()){
Configuration errorHandlerElement =
(Configuration)errorHandlerElements.next();
String errorHandlerClass =
errorHandlerElement.getAttribute("class");
List errorHandlers = (List)errorHandlerMap.get(path);
if(errorHandlers == null){
errorHandlers = new ArrayList();
errorHandlerMap.put(path, errorHandlers);
}
errorHandlers.add(
cl.loadClass(errorHandlerClass).newInstance());
}
}
}
// private methods
/** Configure the initial JNDI context properties. If the element is null
then the property values will not be modified.
@param element The JDOM configuration element
@throws Exception
*/
private void configureJNDI(Configuration configuration) throws Exception{
if(configuration != null){
System.setProperty("java.naming.factory.initial",
configuration.getChildValue("initial-factory"));
System.setProperty("java.naming.provider.url",
configuration.getChildValue("provider"));
}
}
/** Load the configuration. This method opens the stream to the
configuration and then calls the <code>load()</code> method.
@throws Exception
*/
private void loadConfiguration() throws Exception{
InputStream in = null;
try{
log.debug("Loading configuration from: " + configurationFile);
in = new FileInputStream(configurationFile);
load(in);
} catch(Exception e){
throw e;
} finally {
IOUtilities.close(in);
}
}
}
ActionManager.java
(text/x-java, 25 KB)
/*--
Copyright (C) 2001-2003 Aetrion LLC.
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 disclaimer that follows
these conditions in the documentation and/or other materials
provided with the distribution.
3. The name "JPublish" must not be used to endorse or promote products
derived from this software without prior written permission. For
written permission, please contact [email protected].
4. Products derived from this software may not be called "JPublish", nor
may "JPublish" appear in their name, without prior written permission
from Aetrion LLC ([email protected]).
In addition, the authors of this software request (but do not require)
that you include in the end-user documentation provided with the
redistribution and/or in the software itself an acknowledgement equivalent
to the following:
"This product includes software developed by
Aetrion LLC (http://www.aetrion.com/)."
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 AUTHOR(S) 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.
For more information on JPublish, please see <http://www.jpublish.org/>.
*/
package org.jpublish.action;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.anthonyeden.lib.util.IOUtilities;
import com.anthonyeden.lib.util.LogUtilities;
import com.anthonyeden.lib.config.Configuration;
import com.anthonyeden.lib.config.ConfigurationException;
import org.jpublish.SiteContext;
import org.jpublish.JPublishModule;
import org.jpublish.JPublishContext;
import org.jpublish.util.PathUtilities;
import org.jpublish.util.FileToPathIterator;
import org.jpublish.util.BreadthFirstFileTreeIterator;
import org.jpublish.util.vfs.VFSFile;
import org.jpublish.util.vfs.VFSProvider;
import org.jpublish.util.vfs.provider.filesystem.FileSystemProvider;
/** Class which manages all actions in the JPublish framework.
@author Anthony Eden
*/
public class ActionManager{
private static Log log = LogFactory.getLog(ActionManager.class);
private Map definedActions;
private List classPathElements;
private List startupActions;
private List shutdownActions;
private List globalActions;
private List pathActions;
private List preEvaluationActions;
private List postEvaluationActions;
private SiteContext siteContext;
private VFSProvider provider;
private Map cachedScriptActions = new HashMap();
/** Construct a new ActionManager with the given SiteContext.
@param siteContext The SiteContext
*/
public ActionManager(SiteContext siteContext){
this.siteContext = siteContext;
this.definedActions = new HashMap();
this.startupActions = new ArrayList();
this.shutdownActions = new ArrayList();
this.globalActions = new ArrayList();
this.pathActions = new ArrayList();
this.preEvaluationActions = new ArrayList();
this.postEvaluationActions = new ArrayList();
this.classPathElements = new ArrayList();
}
/** Get a Map of all defined actions.
@return A Map of defined actions
*/
public Map getDefinedActions(){
return definedActions;
}
/** Add an action.
@param name The action name
@param action The Action implementation
*/
public void addAction(String name, Action action){
definedActions.put(name, action);
}
/** Remove an action.
@param name The action name
*/
public void removeAction(String name){
definedActions.remove(name);
}
/** Get the class path used by script actions for loading classes.
@return The class path
*/
public synchronized String getClassPath(){
StringBuffer buffer = new StringBuffer();
Iterator classPathElements = getClassPathElements().iterator();
while(classPathElements.hasNext()){
buffer.append(classPathElements.next().toString());
if(classPathElements.hasNext()){
buffer.append(System.getProperty("path.separator"));
}
}
return buffer.toString();
}
/** Get a list of all elements in the ActionManager class path.
@return The class path elements list
*/
public List getClassPathElements(){
return classPathElements;
}
/** Get a List of startup actions.
@return List of startup actions
*/
public List getStartupActions(){
return startupActions;
}
/** Get a List of shutdown actions.
@return List of shutdown actions
*/
public List getShutdownActions(){
return shutdownActions;
}
/** Get a List of global actions.
@return List of global actions
*/
public List getGlobalActions(){
return globalActions;
}
/** Get the List of path actions.
@return The path actions
*/
public List getPathActions(){
return pathActions;
}
/** Get the List of actions which are executed immediately
upon receipt of any request. These actions are
executed before a page search occurs.
@return The pre-evaluation actions
@since 1.3
*/
public List getPreEvaluationActions(){
return preEvaluationActions;
}
/** Get the List of actions which are executed after the
HTTP request has been completed, but before the response
is sent back to the client.
@return The post-evaluation actions
@since 1.3
*/
public List getPostEvaluationActions(){
return postEvaluationActions;
}
/** Execute all startup actions.
@throws Exception Any Exception
*/
public void executeStartupActions() throws Exception{
Iterator actions = getStartupActions().iterator();
while(actions.hasNext()){
ActionWrapper action = (ActionWrapper)actions.next();
action.execute(null);
}
}
/** Execute all shutdown actions.
@throws Exception Any Exception
*/
public void executeShutdownActions() throws Exception{
Iterator actions = getShutdownActions().iterator();
while(actions.hasNext()){
ActionWrapper action = (ActionWrapper)actions.next();
action.execute(null);
}
}
/** Execute all global actions using the given context.
@param context The current context
@throws Exception
@return Redirection URL or null
*/
public String executeGlobalActions(JPublishContext context) throws Exception{
if(context == null){
log.debug("Context is null");
}
List globalActions = getGlobalActions();
if(globalActions == null){
log.error("Global actions list is null");
throw new NullPointerException("Global actions is null");
}
Iterator actions = globalActions.iterator();
while(actions.hasNext()){
ActionWrapper action = (ActionWrapper)actions.next();
if(action == null){
log.error("Action retrieved from iterator is null");
}
action.execute(context);
String redirect = (String)context.get("redirect");
if(redirect != null){
return redirect;
}
}
return null;
}
/** Execute the path actions with the given context. If any of the
actions sets the value redirect in the context then that signals that
the servlet should redirect the request to the specified URL.
@param path The request path
@param context The current context
@return The redirect value or null
@throws Exception
*/
public String executePathActions(String path, JPublishContext context)
throws Exception{
Iterator actions = getPathActions().iterator();
while(actions.hasNext()){
ActionWrapper actionWrapper = (ActionWrapper)actions.next();
PathAction action = (PathAction)actionWrapper.getAction();
if(PathUtilities.match(path, action.getPath())){
actionWrapper.execute(context);
String redirect = (String)context.get("redirect");
if(redirect != null){
return redirect;
}
}
}
return null;
}
/** Execute pre-evaluation actions. Pre-evaluation actions are only
executed if their path argument matches the current path.
<p><b>Note:</b> Since these actions are executed prior to
locating the page the page variable is not in the context.
<p>To stop processing and return immediately, set the value
<code>stop-processing</code> in the context to a non-null value.
@param path The request path
@param context The current request context
@return True if the processing should stop
@throws Exception
@since 1.3
*/
public boolean executePreEvaluationActions(String path,
JPublishContext context) throws Exception{
Iterator actions = getPreEvaluationActions().iterator();
while(actions.hasNext()){
ActionWrapper actionWrapper = (ActionWrapper)actions.next();
PathAction action = (PathAction)actionWrapper.getAction();
if(PathUtilities.match(path, action.getPath())){
actionWrapper.execute(context);
String stopProcessingFlag =
(String)context.get("stop-processing");
if(stopProcessingFlag != null){
return true;
}
}
}
return false;
}
/** Execute post-evaluation actions.
@param path The request path
@param context The request context
@throws Exception
@since 1.3
*/
public void executePostEvaluationActions(String path,
JPublishContext context) throws Exception{
Iterator actions = getPostEvaluationActions().iterator();
while(actions.hasNext()){
ActionWrapper actionWrapper = (ActionWrapper)actions.next();
PathAction action = (PathAction)actionWrapper.getAction();
if(PathUtilities.match(path, action.getPath())){
actionWrapper.execute(context);
//String redirect = (String)context.get("redirect");
//if(redirect != null){
// return redirect;
//}
}
}
}
/** Execute the named action with the given context. If the action sets
the value redirect in the context then that signals that the servlet
should redirect the request to the specified URL.
@param name The action name
@param context The current context
@return The redirect value or null
@throws Exception
*/
public String execute(String name, JPublishContext context) throws
Exception{
log.debug("Executing action: " + name);
Action action = findAction(name);
if(action != null){
action.execute(context, null);
String redirect = (String)context.get("redirect");
log.debug("Action redirect: " + redirect);
if(redirect != null){
return redirect;
}
}
return null;
}
/** Return the text for the specified script action.
@param name The script name
@return The script action text
@throws IOException
*/
public String getScriptActionText(String name) throws IOException{
File actionRoot = siteContext.getRealActionRoot();
File actionFile = new File(actionRoot, name);
StringWriter writer = null;
FileReader reader = null;
try{
writer = new StringWriter();
reader = new FileReader(actionFile);
int c = -1;
while((c = reader.read()) != -1){
writer.write((char)c);
}
return writer.toString();
} finally {
IOUtilities.close(writer);
IOUtilities.close(reader);
}
}
/** Set the text for the specified script action.
@param name The script action name
@param scriptActionText The script action text
@throws IOException
*/
public void setScriptActionText(String name, String scriptActionText)
throws IOException{
File actionRoot = siteContext.getRealActionRoot();
File actionFile = new File(actionRoot, name);
PrintWriter writer = null;
try{
writer = new PrintWriter(new FileWriter(actionFile));
writer.print(scriptActionText);
} finally {
IOUtilities.close(writer);
}
}
/** Remove the named script action.
@param name The name
*/
public void removeScriptAction(String name){
File actionRoot = siteContext.getRealActionRoot();
File actionFile = new File(actionRoot, name);
actionFile.delete();
}
/** Make the directory for the specified path. Parent directories
will also be created if they do not exist.
@param path The directory path
*/
public void makeDirectory(String path){
File file = new File(siteContext.getRealActionRoot(), path);
file.mkdirs();
}
/** Remove the directory for the specified path. The directory
must be empty.
@param path The path
@throws Exception
*/
public void removeDirectory(String path) throws Exception{
log.info("Remove directory: " + path);
File file = new File(siteContext.getRealActionRoot(), path);
log.debug("Deleting file: " + file.getAbsolutePath());
if(file.isDirectory()){
file.delete();
} else {
throw new Exception("Path is not a directory: " + path);
}
}
/** Get the Virtual File System root file. The Virtual File System
provides a datasource-independent way of navigating through all
items known to the StaticResourceManager.
@return The root VFSFile
@throws Exception
*/
public VFSFile getVFSRoot() throws Exception{
if(provider == null){
provider = new FileSystemProvider(siteContext.getRealActionRoot());
}
return provider.getRoot();
}
/** Find an action with the given name. The name may be the name of an
action registered with the ActionManager at startup, an action from a
module, a partial file path rooted in the action root directory or a
fully qualified Java class.
@param name The name of the action
@return The action
@throws ActionNotFoundException If the action is not found
*/
public Action findAction(String name){
// look in registered classes first
log.debug("Looking for registered action.");
Action action = (Action)definedActions.get(name);
if(action != null){
log.debug("Registered action found.");
return action;
}
// look in modules
log.debug("Looking for action in modules.");
Iterator modules = siteContext.getModules().iterator();
while(modules.hasNext()){
JPublishModule module = (JPublishModule)modules.next();
action = (Action)(module.getDefinedActions().get(name));
if(action != null){
log.debug("Action found in module.");
return action;
}
}
// look in the action directory for scripts
action = (Action) cachedScriptActions.get(name);
if (action != null) {
log.debug("Action found in script actions cache.");
return action;
}
log.debug("Looking for action in action root.");
File actionRoot = siteContext.getRealActionRoot();
log.debug("Action root: " + actionRoot);
File actionFile = new File(actionRoot, name);
if(actionFile.exists()){
log.debug("Action found [" + actionFile + "]");
action = new ScriptAction(siteContext, actionFile);
cachedScriptActions.put(name, action);
return action;
}
// look in classpath
try{
log.debug("Looking for action in the classpath.");
ClassLoader cl = Thread.currentThread().getContextClassLoader();
action = (Action)cl.loadClass(name).newInstance();
return action;
} catch(Exception e){
throw new ActionNotFoundException(e, name);
}
}
/** Load the ActionManager's configuration from the given configuration
object.
@param configuration The configuration object
@throws ConfigurationException
*/
public void loadConfiguration(Configuration configuration) throws
ConfigurationException{
try{
// load action definitions
Iterator defineActionElements = configuration.getChildren(
"define-action").iterator();
while(defineActionElements.hasNext()){
Configuration defineActionElement =
(Configuration)defineActionElements.next();
String name = defineActionElement.getAttribute("name");
String className =
defineActionElement.getAttribute("classname");
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Action action = (Action)cl.loadClass(className).newInstance();
log.debug("Defined action: " + name + " [" + className + "]");
definedActions.put(name, action);
}
// load startup actions
Iterator startupActionElements =
configuration.getChildren("startup-action").iterator();
while(startupActionElements.hasNext()){
Configuration startupActionElement =
(Configuration)startupActionElements.next();
String name = startupActionElement.getAttribute("name");
startupActions.add(new ActionWrapper(findAction(name),
startupActionElement));
}
// load shutdown actions
Iterator shutdownActionElements =
configuration.getChildren("shutdown-action").iterator();
while(shutdownActionElements.hasNext()){
Configuration shutdownActionElement =
(Configuration)shutdownActionElements.next();
String name = shutdownActionElement.getAttribute("name");
shutdownActions.add(new ActionWrapper(findAction(name),
shutdownActionElement));
}
// load global actions
log.debug("Configuring global actions");
Iterator globalActionElements =
configuration.getChildren("global-action").iterator();
while(globalActionElements.hasNext()){
Configuration globalActionElement =
(Configuration)globalActionElements.next();
String name = globalActionElement.getAttribute("name");
log.debug("Finding global action '" + name + "'");
Action action = findAction(name);
if(action == null){
log.error("No action '" + name + "' found");
} else {
log.debug("Action '" + name + "' found");
globalActions.add(new ActionWrapper(action,
globalActionElement));
}
}
// load path actions
Iterator pathActionElements =
configuration.getChildren("path-action").iterator();
while(pathActionElements.hasNext()){
Configuration pathActionElement =
(Configuration)pathActionElements.next();
String name = pathActionElement.getAttribute("name");
String path = pathActionElement.getAttribute("path");
// debugging
/*
HashMap data = new HashMap();
data.put("path", path);
data.put("action", name);
LogUtilities.debug(log, "Registered path action.", data);
*/
pathActions.add(new ActionWrapper(
new PathAction(path, findAction(name)), pathActionElement));
}
// load pre-evaluation actions
Iterator preEvaluationActionElements =
configuration.getChildren("pre-evaluation-action").iterator();
while(preEvaluationActionElements.hasNext()){
Configuration preEvaluationActionElement =
(Configuration)preEvaluationActionElements.next();
String name = preEvaluationActionElement.getAttribute("name");
String path = preEvaluationActionElement.getAttribute("path");
// debugging
/*
HashMap data = new HashMap();
data.put("path", path);
data.put("action", name);
LogUtilities.debug(log, "Registered pre-evaluation action.", data);
*/
preEvaluationActions.add(new ActionWrapper(
new PathAction(path, findAction(name)),
preEvaluationActionElement));
}
// load post-evaluation actions
Iterator postEvaluationActionElements =
configuration.getChildren("post-evaluation-action").iterator();
while(postEvaluationActionElements.hasNext()){
Configuration postEvaluationActionElement =
(Configuration)postEvaluationActionElements.next();
String name = postEvaluationActionElement.getAttribute("name");
String path = postEvaluationActionElement.getAttribute("path");
// debugging
/*
HashMap data = new HashMap();
data.put("path", path);
data.put("action", name);
LogUtilities.debug(log, "Registered post-evaluation action.", data);
*/
postEvaluationActions.add(new ActionWrapper(
new PathAction(path, findAction(name)),
postEvaluationActionElement));
}
} catch(Exception e){
throw new ConfigurationException(e);
}
}
/** Get an Iterator of paths of action scripts which are known to the
ActionManager.
@return An iterator of paths
@throws Exception
*/
public Iterator getPaths() throws Exception{
return getPaths("");
}
/** Get an Iterator of paths of action scripts which are known to the
ActionManager, starting from the specified base path.
@param base The base path
@return An iterator of paths
@throws Exception
*/
public Iterator getPaths(String base) throws Exception{
File actionRoot = siteContext.getRealActionRoot();
File baseFile = new File(actionRoot, base);
return new FileToPathIterator(baseFile.toString(),
new BreadthFirstFileTreeIterator(baseFile));
}
}
ScriptAction.java
(text/x-java, 8.5 KB)
/*--
Copyright (C) 2001-2003 Aetrion LLC.
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 disclaimer that follows
these conditions in the documentation and/or other materials
provided with the distribution.
3. The name "JPublish" must not be used to endorse or promote products
derived from this software without prior written permission. For
written permission, please contact [email protected].
4. Products derived from this software may not be called "JPublish", nor
may "JPublish" appear in their name, without prior written permission
from Aetrion LLC ([email protected]).
In addition, the authors of this software request (but do not require)
that you include in the end-user documentation provided with the
redistribution and/or in the software itself an acknowledgement equivalent
to the following:
"This product includes software developed by
Aetrion LLC (http://www.aetrion.com/)."
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 AUTHOR(S) 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.
For more information on JPublish, please see <http://www.jpublish.org/>.
*/
package org.jpublish.action;
import java.io.File;
import java.io.FileReader;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.ibm.bsf.BSFManager;
import com.ibm.bsf.BSFException;
import com.ibm.bsf.util.IOUtils;
import com.ibm.bsf.util.CodeBuffer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.anthonyeden.lib.config.Configuration;
import org.jpublish.Page;
import org.jpublish.SiteContext;
import org.jpublish.JPublishContext;
import org.jpublish.util.CustomClassLoader;
/** An action which is implemented in a BSF supported scripting language.
Script actions have access to several varibles:
<p>These are always available:</p>
<p>
<b>site</b> - The SiteContext<br>
<b>syslog</b> - Standard logging stream (Log4J Category)<br>
</p>
<p>If there is a context defined when the action is executed (all
actions excluding startup actions):</p>
<p>
<b>context</b> - The current context<br>
<b>application</b> - The ServletContext<br>
<b>request</b> - The HTTP request<br>
<b>response</b> - The HTTP response<br>
<b>session</b> - The HTTP session<br>
<b>page</b> - The Page object<br>
</p>
@author Anthony Eden
*/
public class ScriptAction implements Action{
private static Log log = LogFactory.getLog(ScriptAction.class);
private SiteContext siteContext;
private File script;
private String scriptLang = null;
private long timeLastLoaded = 0;
private String scriptString = null;
/** Construct a new ScriptAction for the given script. The path to the
script should be an absolute path.
@param siteContext The SiteContext
@param script The path to the script
*/
public ScriptAction(SiteContext siteContext, String script){
this(siteContext, new File(script));
}
/** Construct a new ScriptAction for the given script.
@param siteContext The SiteContext
@param script The file representing the script
*/
public ScriptAction(SiteContext siteContext, File script){
this.siteContext = siteContext;
this.script = script;
log.debug("Creating new ScriptAction for " + script.getName());
}
/** Execute the action script represented by this ScriptAction.
@param context The current context
@param configuration The configuration object
@throws Exception
*/
public void execute(JPublishContext context, Configuration configuration)
throws Exception{
log.debug("Executing script: " + script);
//ClassLoader cl = Thread.currentThread().getContextClassLoader();
BSFManager bsfManager = new BSFManager();
//bsfManager.setClassPath(siteContext.getActionManager().getClassPath());
//bsfManager.setClassLoader(new CustomClassLoader(cl));
// expose standard items in the context
if(context != null){
ServletContext application =
(ServletContext)context.get("application");
HttpServletRequest request =
(HttpServletRequest)context.get("request");
HttpServletResponse response =
(HttpServletResponse)context.get("response");
HttpSession session = (HttpSession)context.get("session");
Page page = (Page)context.get("page");
// expose the context
bsfManager.declareBean("context", context, JPublishContext.class);
// expose the context. The variable name vc should be considered
// deprecated
bsfManager.declareBean("vc", context, JPublishContext.class);
// expose the page object.
if(page == null){
log.debug("Page request is null");
} else {
bsfManager.declareBean("page", page, Page.class);
}
// expose standard HttpServlet objects
if(request == null){
log.debug("HTTP request is null");
} else {
bsfManager.declareBean("request", request,
HttpServletRequest.class);
}
if(response == null){
log.debug("HTTP response is null");
} else {
bsfManager.declareBean("response", response,
HttpServletResponse.class);
}
if(session == null){
log.debug("HTTP session is null");
} else {
bsfManager.declareBean("session", session, HttpSession.class);
}
if(application == null){
log.debug("ServletContext is null");
} else {
bsfManager.declareBean("application", application,
ServletContext.class);
}
}
// these objects are exposed regardless if there is a context
// object or not. In other words they are accesible to startup
// actions
bsfManager.declareBean("syslog", SiteContext.syslog, Log.class);
if(siteContext == null){
log.debug("SiteContext is null");
} else {
bsfManager.declareBean("site", siteContext, SiteContext.class);
}
if(configuration == null){
log.debug("Configuration is null");
} else {
bsfManager.declareBean("configuration", configuration,
Configuration.class);
}
if (scriptLang == null) scriptLang = BSFManager.getLangFromFilename(script.getName());
boolean reloadScript = false;
long scriptLastModified = script.lastModified();
if (scriptLastModified > timeLastLoaded) {
log.debug("Loading updated or new script: " + script.getName());
reloadScript = true;
}
if (reloadScript || scriptString == null) {
synchronized (this) {
if (reloadScript || scriptString == null) {
timeLastLoaded = System.currentTimeMillis();
scriptString = IOUtils.getStringFromReader(new FileReader(script));
}
}
}
bsfManager.exec(scriptLang, script.getName(), 0, 0, scriptString);
}
}
PageInstance.java
(text/x-java, 12.7 KB)
/*--
Copyright (C) 2001-2003 Aetrion LLC.
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 disclaimer that follows
these conditions in the documentation and/or other materials
provided with the distribution.
3. The name "JPublish" must not be used to endorse or promote products
derived from this software without prior written permission. For
written permission, please contact [email protected].
4. Products derived from this software may not be called "JPublish", nor
may "JPublish" appear in their name, without prior written permission
from Aetrion LLC ([email protected]).
In addition, the authors of this software request (but do not require)
that you include in the end-user documentation provided with the
redistribution and/or in the software itself an acknowledgement equivalent
to the following:
"This product includes software developed by
Aetrion LLC (http://www.aetrion.com/)."
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 AUTHOR(S) 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.
For more information on JPublish, please see <http://www.jpublish.org/>.
*/
package org.jpublish.page;
import java.io.File;
import java.io.Writer;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;
import java.util.List;
import java.util.Locale;
import java.util.HashMap;
import java.util.Iterator;
import java.util.ArrayList;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.anthonyeden.lib.config.Configuration;
import com.anthonyeden.lib.config.XMLConfiguration;
import com.anthonyeden.lib.config.ConfigurationException;
import org.jpublish.Page;
import org.jpublish.SiteContext;
import org.jpublish.JPublishContext;
import org.jpublish.action.Action;
import org.jpublish.action.ScriptAction;
import org.jpublish.action.ActionWrapper;
/** A representation of a single web page. A page is defined by an XML
document in the pages directory. Each page has a template associated
with the page and can have 0 or more actions attached to the page.
<p>Actions attached to a page will be triggered each time the page
is requested. Actions will be triggered in the order that they are
listed within the Page's configuration.</p>
<p>There should only be a single PageInstance in memory for each path.
Each PageInstance is actually wrapped in a Page class which provides
request-specific features.
@author Anthony Eden
*/
public class PageInstance{
private static Log log = LogFactory.getLog(PageInstance.class);
private SiteContext siteContext;
private List pageActions;
private String path;
private String pageName;
private String pageType;
private String templateName;
private Map properties;
/** Construct a new Page for the given path. The name of the page is
the last part of the path (i.e. the file component) without the
dot ending. The page type is the dot-ending.
@param siteContext The SiteContext
@param path The request path
@param pageName The name of the page
@param pageType The page type
*/
public PageInstance(SiteContext siteContext, String path, String pageName,
String pageType){
this.siteContext = siteContext;
this.path = path;
this.pageName = pageName;
this.pageType = pageType;
this.pageActions = new ArrayList();
this.templateName = siteContext.getDefaultTemplate();
this.properties = new HashMap();
}
/** Get the request path.
@return The request path
*/
public String getPath(){
return path;
}
/** Get the page name.
@return The page name
*/
public String getPageName(){
return pageName;
}
/** Get the page type.
@return The page type
*/
public String getPageType(){
return pageType;
}
/** Return the page title. Initially the page title is extracted from
the page's definition document, however it can be set programtically
at runtime.
<p>This method is deprecated. Use getProperty("title") instead and
include a property named title in the page configuration file. The
old <title> element and this method will be removed for the
1.0 release.
@deprecated Use getProperty("title") instead
@return The page title
*/
public String getTitle(){
String title = getProperty("Title");
if(title == null){
title = getProperty("title");
}
return title;
}
/** Set the title. This will temporarily alter the page's title.
<p>This method is deprecated. The old <title> element
and this method will be removed for the 1.0 release.
@deprecated
@param title The page title
*/
public void setTitle(String title){
if(title != null){
log.debug("setTitle(" + title + ")");
setProperty("title", title, null);
}
}
/** Get the full template file name, with the .suffix attached.
@return The full template name
*/
public String getFullTemplateName(){
return templateName + "." + pageType;
}
/** Get the template name. If the template name is not specified in the
page configuration then the default template as specified in the
SiteContext will be used.
@return The template name
*/
public String getTemplateName(){
return templateName;
}
/** Set the template name. Invoking this method with a null value will
reset the template to the default template as specified in the
SiteContext.
@param templateName The new template name or null to reset
*/
public synchronized void setTemplateName(String templateName){
log.debug("setTemplateName(" + templateName + ")");
if(templateName == null){
templateName = siteContext.getDefaultTemplate();
log.debug("Using default template: " + templateName);
}
this.templateName = templateName;
}
/** Get a List of page actions. To add an action to the page just add
the action to this List. Page actions are triggered each time the
page is requested.
@return A List of page actions
*/
public List getPageActions(){
return pageActions;
}
/** Get the named page property using the default Locale. If the
property is not found then return null.
@param name The property name
@return The value or null
*/
public String getProperty(String name){
return getProperty(name, Locale.getDefault());
}
/** Get the Locale-specific value for the given named property. If
the property is not found then return null. This method will try to
find the most suitable locale by searching the property values in the
following manner:
<p>
language + "_" + country + "_" + variant<br>
language + "_" + country<br>
langauge<br>
""
</p>
@param name The property name
@param locale The locale
@return The value
*/
public String getProperty(String name, Locale locale){
log.debug("Get property [name=" + name + ",locale=" + locale + "]");
PageProperty property = (PageProperty)properties.get(name);
if(property != null){
return property.getValue(locale);
} else {
return null;
}
}
/** Get the named property. This method is equivilent to the
<code>getProperty(name)</code> method. This method is provided
as a convenience to view code.
@param name The property name
@return The value
*/
public String get(String name){
log.debug("get(" + name + ") called to retrieve property");
return getProperty(name);
}
/** Execute the page actions using the given context.
@param context The current context
@return A redirection value or null if there is no redirection
@throws Exception Any Exception which occurs while executing the action
*/
public String executeActions(JPublishContext context) throws Exception{
Iterator pageActions = getPageActions().iterator();
while(pageActions.hasNext()){
((ActionWrapper)pageActions.next()).execute(context);
String redirect = (String)context.get("redirect");
if(redirect != null){
return redirect;
}
}
return null;
}
/** Load the page configuration from the page's XML stream.
@param in The InputStream
@throws Exception Any exception
*/
public synchronized void load(InputStream in) throws Exception{
log.debug("Loading page.");
Configuration configuration = new XMLConfiguration(in);
loadConfiguration(configuration);
}
/** Load the page configuration from the given Configuration object.
@param configuration The Configuration object
@throws ConfigurationException
*/
public synchronized void loadConfiguration(Configuration configuration)
throws ConfigurationException{
setTitle(configuration.getChildValue("title"));
setTemplateName(configuration.getChildValue("template"));
// load page actions
log.debug("Looping through page-action elements.");
Iterator pageActionElements =
configuration.getChildren("page-action").iterator();
while(pageActionElements.hasNext()){
Configuration pageActionElement =
(Configuration)pageActionElements.next();
String name = pageActionElement.getAttribute("name");
// Removed for version 2.x
if(name == null){
name = pageActionElement.getValue();
}
if(name == null){
throw new ConfigurationException(
"Error configuring page-action.");
}
Action action = siteContext.getActionManager().findAction(name);
if(action == null){
throw new ConfigurationException(
"Action " + name + " not defined");
}
pageActions.add(new ActionWrapper(action, pageActionElement));
}
// load page properties
log.debug("Loading page properties");
Iterator propertyElements =
configuration.getChildren("property").iterator();
while(propertyElements.hasNext()){
Configuration propertyElement =
(Configuration)propertyElements.next();
setProperty(propertyElement.getAttribute("name"),
propertyElement.getValue(),
propertyElement.getAttribute("locale"));
}
}
/** Set the property value.
@param name The property name
@param value The value
@param locale The locale String or null
*/
private void setProperty(String name, String value, String locale){
log.debug("setProperty() [name=" + name + ",value=" + value +
",locale=" + locale);
PageProperty property = (PageProperty)properties.get(name);
if(property == null){
// named property not in property map
property = new PageProperty(name);
properties.put(name, property);
}
property.setValue(value, locale);
}
}
RepositoryContent.java
(text/x-java, 6.4 KB)
/*--
Copyright (C) 2001-2003 Aetrion LLC.
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 disclaimer that follows
these conditions in the documentation and/or other materials
provided with the distribution.
3. The name "JPublish" must not be used to endorse or promote products
derived from this software without prior written permission. For
written permission, please contact [email protected].
4. Products derived from this software may not be called "JPublish", nor
may "JPublish" appear in their name, without prior written permission
from Aetrion LLC ([email protected]).
In addition, the authors of this software request (but do not require)
that you include in the end-user documentation provided with the
redistribution and/or in the software itself an acknowledgement equivalent
to the following:
"This product includes software developed by
Aetrion LLC (http://www.aetrion.com/)."
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 AUTHOR(S) 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.
For more information on JPublish, please see <http://www.jpublish.org/>.
*/
package org.jpublish.repository;
import java.io.Reader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.io.ByteArrayInputStream;
import java.io.UnsupportedEncodingException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jpublish.Content;
import org.jpublish.Repository;
/** Interface which represents a single item of content. This interface
is read-only.
@author Anthony Eden
@since 2.0
*/
public class RepositoryContent implements Content{
private static final Log log = LogFactory.getLog(RepositoryContent.class);
private Repository repository = null;
private String path = null;
private String data = null;
private long lastModified = -1;
/** Construct a new RepositoryContent object.
@param repository The Repository used to load the content
@param path The path to the content in the repository
*/
public RepositoryContent(Repository repository, String path) {
this.repository = repository;
this.path = path;
this.data = null;
this.lastModified = -1;
}
/** Construct a new RepositoryContent object.
@param data The data
@param lastModified The last modified time
*/
public RepositoryContent(String data, long lastModified) {
this.data = data;
this.lastModified = lastModified;
}
/** Get the last-modified time of the content or -1 if it is not known.
@return The last modified time
*/
public long getLastModified(){
if (this.repository != null) {
try {
return this.repository.getLastModified(this.path);
} catch (Exception e) {
log.warn("Could not getLastModified time from repository (returning -1): " + e.toString());
return -1;
}
}
return lastModified;
}
/** Get an InputStream for reading the content data.
@return The content InputStream
*/
public InputStream getInputStream(){
if (this.repository != null) {
try {
return this.repository.getInputStream(this.path);
} catch (Exception e) {
log.warn("Could not getInputStream from repository (returning null): " + e.toString());
return null;
}
}
return new ByteArrayInputStream(data.getBytes());
}
/** Get a Reader for reading the content data.
@return The content Reader
*/
public Reader getReader(){
return getReader(null);
}
/** Get a Reader for reading the content data with the specified content
encoding.
@param encoding The content encoding
@return The Reader
*/
public Reader getReader(String encoding){
InputStream repInputStrem = null;
if (repository != null) {
try {
repInputStrem = repository.getInputStream(path);
} catch (Exception e) {
log.warn("Could not getInputStream from repository (returning null): " + e.toString());
return null;
}
}
if(encoding == null){
if (repository != null) return new InputStreamReader(repInputStrem);
return new StringReader(data);
} else {
try{
if (repository != null) return new InputStreamReader(repInputStrem, encoding);
return new StringReader(new String(data.getBytes(), encoding));
} catch(UnsupportedEncodingException e){
log.warn("Unsupported encoding " + encoding + "; using default encoding");
if (repository != null) return new InputStreamReader(repInputStrem);
return new StringReader(data);
}
}
}
public boolean equals(Object obj) {
Content passed = (Content) obj;
long thisLastModified = this.getLastModified();
long passedLastModified = passed.getLastModified();
if (thisLastModified == passedLastModified) {
return true;
}
log.debug("Passed content not equal: thisLastModified=" + thisLastModified + ", passedLastModified=" + passedLastModified);
return false;
}
}
TemplateContent.java
(text/x-java, 4.6 KB)
/*--
Copyright (C) 2001-2003 Aetrion LLC.
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 disclaimer that follows
these conditions in the documentation and/or other materials
provided with the distribution.
3. The name "JPublish" must not be used to endorse or promote products
derived from this software without prior written permission. For
written permission, please contact [email protected].
4. Products derived from this software may not be called "JPublish", nor
may "JPublish" appear in their name, without prior written permission
from Aetrion LLC ([email protected]).
In addition, the authors of this software request (but do not require)
that you include in the end-user documentation provided with the
redistribution and/or in the software itself an acknowledgement equivalent
to the following:
"This product includes software developed by
Aetrion LLC (http://www.aetrion.com/)."
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 AUTHOR(S) 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.
For more information on JPublish, please see <http://www.jpublish.org/>.
*/
package org.jpublish.template;
import java.io.Reader;
import java.io.InputStream;
import java.io.StringReader;
import java.io.ByteArrayInputStream;
import java.io.UnsupportedEncodingException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jpublish.Template;
import org.jpublish.Content;
/** An implementation of the Content interface which provides the data of
a Template object.
@author Anthony Eden
@since 2.0
*/
public class TemplateContent implements Content{
private static final Log log = LogFactory.getLog(TemplateContent.class);
private Template template;
/** Construct a new TemplateContent object.
@param template The template
*/
public TemplateContent(Template template){
this.template = template;
}
/** Get an InputStream for reading the content data.
@return The content InputStream
*/
public InputStream getInputStream(){
return new ByteArrayInputStream(template.getText().getBytes());
}
/** Get the template reader.
@return The template reader
*/
public Reader getReader(){
return getReader(null);
}
/** Get the template reader using the specified encoding.
@param The content encoding
@return The Reader
*/
public Reader getReader(String encoding){
if(encoding == null){
return new StringReader(template.getText());
} else {
try {
return new StringReader(
new String(template.getText().getBytes(), encoding));
} catch (UnsupportedEncodingException e){
log.warn("Unsupported encoding " + encoding +
"; using default encoding");
return new StringReader(template.getText());
}
}
}
/** Get the last modified time of the template.
@return The last modified time
*/
public long getLastModified(){
return template.getLastModified();
}
public boolean equals(Object obj) {
Content passed = (Content) obj;
long thisLastModified = this.getLastModified();
long passedLastModified = passed.getLastModified();
if (thisLastModified == passedLastModified) {
return true;
}
log.debug("Passed content not equal: thisLastModified=" + thisLastModified + ", passedLastModified=" + passedLastModified);
return false;
}
}
FreeMarkerViewRenderer.java
(text/x-java, 6.3 KB)
/*--
Copyright (C) 2001-2003 Aetrion LLC.
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 disclaimer that follows
these conditions in the documentation and/or other materials
provided with the distribution.
3. The name "JPublish" must not be used to endorse or promote products
derived from this software without prior written permission. For
written permission, please contact [email protected].
4. Products derived from this software may not be called "JPublish", nor
may "JPublish" appear in their name, without prior written permission
from Aetrion LLC ([email protected]).
In addition, the authors of this software request (but do not require)
that you include in the end-user documentation provided with the
redistribution and/or in the software itself an acknowledgement equivalent
to the following:
"This product includes software developed by
Aetrion LLC (http://www.aetrion.com/)."
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 AUTHOR(S) 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.
For more information on JPublish, please see <http://www.jpublish.org/>.
*/
package org.jpublish.view.freemarker;
import java.io.Reader;
import java.io.Writer;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import freemarker.template.Template;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.anthonyeden.lib.config.Configuration;
import com.anthonyeden.lib.config.ConfigurationException;
import org.jpublish.Page;
import org.jpublish.SiteContext;
import org.jpublish.JPublishContext;
import org.jpublish.view.ViewRenderer;
import org.jpublish.view.ViewRenderException;
/** ViewRenderer which uses the FreeMarker template engine.
@author Anthony Eden
@since 2.0
*/
public class FreeMarkerViewRenderer implements ViewRenderer{
private static final Log log = LogFactory.getLog(
FreeMarkerViewRenderer.class);
protected SiteContext siteContext;
protected JPublishTemplateLoader templateLoader;
protected freemarker.template.Configuration fmConfig;
/** Construct a new FreeMarkerViewRenderer. */
public FreeMarkerViewRenderer(){
}
/** Set the SiteContext.
@param siteContext The SiteContext
*/
public void setSiteContext(SiteContext siteContext){
this.siteContext = siteContext;
}
/** Initialize the ViewRenderer.
@throws Exception Any Exception
*/
public void init() throws Exception{
fmConfig = new freemarker.template.Configuration();
templateLoader = new JPublishTemplateLoader();
templateLoader.setSiteContext(siteContext);
fmConfig.setTemplateLoader(templateLoader);
fmConfig.setLocalizedLookup(false);
}
/** Render the view. This method will reparse the template text each time
it is called.
@param context The JPublishContext
@param path The path to the template
@param in The Reader to read view template from
@param out The Writer to write the rendered view
@throws IOException
@throws ViewRenderException
*/
public void render(JPublishContext context, String path, Reader in,
Writer out) throws IOException, ViewRenderException{
log.debug("render(" + path + ")");
try{
Page page = (Page)context.get(JPublishContext.JPUBLISH_PAGE);
Object viewContext = createViewContext(context, path);
Template template = fmConfig.getTemplate(path, page.getLocale());
template.process(viewContext, out);
} catch(IOException e){
throw e;
} catch(Exception e){
throw new ViewRenderException(e);
}
}
/** Render the view.
@param context The JPublishContext
@param path The path to the template
@param in The InputStream to read view template from
@param out The OutputStream to write the rendered view
@throws IOException
@throws ViewRenderException
*/
public void render(JPublishContext context, String path, InputStream in,
OutputStream out) throws IOException, ViewRenderException{
render(context, path, new InputStreamReader(in),
new OutputStreamWriter(out));
}
/** Load the configuration for the view.
@param configuration The configuration object
*/
public void loadConfiguration(Configuration configuration)
throws ConfigurationException{
}
/** Create the 'root' context for the template engine. This method can be
overridden in subclasses in case the viewContext needs to be populated
with additional values. The default implementation wraps the existing
JPublishContext in a class which is useable by FreeMarker.
@param context The JPublishContext
@param path The path to the template
@return Object The 'root' template context
@throws ViewRenderException
*/
protected Object createViewContext(JPublishContext context,
String path) throws ViewRenderException{
FreeMarkerViewContext viewContext =
new FreeMarkerViewContext(context);
return viewContext;
}
}
JPublishTemplateLoader.java
(text/x-java, 4.4 KB)
/*--
Copyright (C) 2001-2003 Aetrion LLC.
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 disclaimer that follows
these conditions in the documentation and/or other materials
provided with the distribution.
3. The name "JPublish" must not be used to endorse or promote products
derived from this software without prior written permission. For
written permission, please contact [email protected].
4. Products derived from this software may not be called "JPublish", nor
may "JPublish" appear in their name, without prior written permission
from Aetrion LLC ([email protected]).
In addition, the authors of this software request (but do not require)
that you include in the end-user documentation provided with the
redistribution and/or in the software itself an acknowledgement equivalent
to the following:
"This product includes software developed by
Aetrion LLC (http://www.aetrion.com/)."
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 AUTHOR(S) 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.
For more information on JPublish, please see <http://www.jpublish.org/>.
*/
package org.jpublish.view.freemarker;
import java.io.Reader;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import freemarker.cache.TemplateLoader;
import org.jpublish.Content;
import org.jpublish.SiteContext;
import org.jpublish.ContentNotFoundException;
/** Implementation of the FreeMarker TemplateLoader interface.
@author Anthony Eden
@since 2.0
*/
public class JPublishTemplateLoader implements TemplateLoader{
private static final Log log =
LogFactory.getLog(JPublishTemplateLoader.class);
private SiteContext siteContext;
/** Construct a new JPublishTemplateLoader. */
public JPublishTemplateLoader(){
}
/** Set the SiteContext.
@param siteContext The SiteContext
*/
public void setSiteContext(SiteContext siteContext){
this.siteContext = siteContext;
}
/** Find the template source.
@param name The template name
@return The source object
*/
public Object findTemplateSource(String name){
if (log.isDebugEnabled()) log.debug("findTemplateSource(" + name + ")");
Object content = siteContext.getContent(name);
if (log.isDebugEnabled()) log.debug("findTemplateSource() content: " + content);
return content;
}
/** Get the last modified time of the template source.
@param templateSource The source
@return The last modified time
*/
public long getLastModified(Object templateSource){
log.debug("getLastModified() invoked");
long lastModified = ((Content)templateSource).getLastModified();
log.debug("Last modified time: " + lastModified);
return lastModified;
}
/** Get the template source reader.
@param templateSource The source
@param encoding The character encoding
@return The Reader
*/
public Reader getReader(Object templateSource, String encoding){
log.debug("getReader() invoked");
return ((Content)templateSource).getReader(encoding);
}
/** Close the specified template source.
@param templateSource The template source
*/
public void closeTemplateSource(Object templateSource){
// currently no-op. Cleanup needed?
}
}