Many changes to provide site-specific resource loading (we're almost
there) and to bring things up to date with some Velocity changes Geir made at my prompting. git-svn-id: https://samskivert.googlecode.com/svn/trunk@428 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// $Id: Application.java,v 1.4 2001/11/02 00:58:22 mdb Exp $
|
// $Id: Application.java,v 1.5 2001/11/06 04:49:32 mdb Exp $
|
||||||
//
|
//
|
||||||
// samskivert library - useful routines for java programs
|
// samskivert library - useful routines for java programs
|
||||||
// Copyright (C) 2001 Michael Bayne
|
// Copyright (C) 2001 Michael Bayne
|
||||||
@@ -38,10 +38,63 @@ import com.samskivert.util.StringUtil;
|
|||||||
public class Application
|
public class Application
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* This should be overridden by the application implementation to
|
* Performs initializations common to all applications. Applications
|
||||||
* perform any necessary initialization.
|
* should override {@link #willInit} to perform initializations that
|
||||||
|
* need to take place before the common initialization (which includes
|
||||||
|
* the creation of the site identifier and message manager) and should
|
||||||
|
* override {@link #didInit} to perform initializations that need to
|
||||||
|
* take place after the common initialization (like passing the
|
||||||
|
* application to entities that might turn around and request a
|
||||||
|
* reference to our site identifier).
|
||||||
|
*
|
||||||
|
* @param context the servlet context in which this application is
|
||||||
|
* operating.
|
||||||
|
* @param logicPkg the base package for all of the logic
|
||||||
|
* implementations for this application.
|
||||||
*/
|
*/
|
||||||
public void init (ServletContext context)
|
public void init (ServletContext context, String logicPkg)
|
||||||
|
{
|
||||||
|
// keep this around for later
|
||||||
|
_context = context;
|
||||||
|
|
||||||
|
// let the derived application do pre-init stuff
|
||||||
|
willInit();
|
||||||
|
|
||||||
|
// remove any trailing dot
|
||||||
|
if (logicPkg.endsWith(".")) {
|
||||||
|
_logicPkg = logicPkg.substring(0, logicPkg.length()-1);
|
||||||
|
} else {
|
||||||
|
_logicPkg = logicPkg;
|
||||||
|
}
|
||||||
|
|
||||||
|
// instantiate our message manager if the application wants one
|
||||||
|
String bpath = getMessageBundlePath();
|
||||||
|
if (bpath != null) {
|
||||||
|
_msgmgr = new MessageManager(bpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create our site identifier
|
||||||
|
_siteIdent = createSiteIdentifier(_context);
|
||||||
|
|
||||||
|
// let the derived application do post-init stuff
|
||||||
|
didInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This should be overridden by the application implementation to
|
||||||
|
* invoke any necessary pre-initialization code. They should be sure
|
||||||
|
* to call <code>super.willInit()</code>.
|
||||||
|
*/
|
||||||
|
protected void willInit ()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This should be overridden by the application implementation to
|
||||||
|
* invoke any necessary post-initialization code. They should be sure
|
||||||
|
* to call <code>super.didInit()</code>.
|
||||||
|
*/
|
||||||
|
protected void didInit ()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,6 +106,15 @@ public class Application
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a reference to the servlet context in which this
|
||||||
|
* application is operating.
|
||||||
|
*/
|
||||||
|
public ServletContext getServletContext ()
|
||||||
|
{
|
||||||
|
return _context;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the message manager in effect for this application, if one
|
* Returns the message manager in effect for this application, if one
|
||||||
* is in effect.
|
* is in effect.
|
||||||
@@ -144,34 +206,6 @@ public class Application
|
|||||||
return _msgmgr.getMessage(ctx.getRequest(), msg, args);
|
return _msgmgr.getMessage(ctx.getRequest(), msg, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs initializations common to all applications. We could put
|
|
||||||
* this in {@link #init} and require application derived classes to
|
|
||||||
* call <code>super.init()</code> but we want it to happen after the
|
|
||||||
* application initializes itself.
|
|
||||||
*
|
|
||||||
* @param logicPkg the base package for all of the logic
|
|
||||||
* implementations for this application.
|
|
||||||
*/
|
|
||||||
protected void postInit (ServletContext ctx, String logicPkg)
|
|
||||||
{
|
|
||||||
// remove any trailing dot
|
|
||||||
if (logicPkg.endsWith(".")) {
|
|
||||||
_logicPkg = logicPkg.substring(0, logicPkg.length()-1);
|
|
||||||
} else {
|
|
||||||
_logicPkg = logicPkg;
|
|
||||||
}
|
|
||||||
|
|
||||||
// instantiate our message manager if the application wants one
|
|
||||||
String bpath = getMessageBundlePath();
|
|
||||||
if (bpath != null) {
|
|
||||||
_msgmgr = new MessageManager(bpath);
|
|
||||||
}
|
|
||||||
|
|
||||||
// create our site identifier
|
|
||||||
_siteIdent = createSiteIdentifier(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given the servlet path (the part of the URI after the context path)
|
* Given the servlet path (the part of the URI after the context path)
|
||||||
* this generates the classname of the logic class that should handle
|
* this generates the classname of the logic class that should handle
|
||||||
@@ -190,6 +224,10 @@ public class Application
|
|||||||
return _logicPkg + path;
|
return _logicPkg + path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** A reference to the servlet context in which this application is
|
||||||
|
* operating. */
|
||||||
|
protected ServletContext _context;
|
||||||
|
|
||||||
/** The prefix that we use to generate fully qualified logic class
|
/** The prefix that we use to generate fully qualified logic class
|
||||||
* names. */
|
* names. */
|
||||||
protected String _logicPkg;
|
protected String _logicPkg;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// $Id: DispatcherServlet.java,v 1.8 2001/11/02 18:46:48 mdb Exp $
|
// $Id: DispatcherServlet.java,v 1.9 2001/11/06 04:49:32 mdb Exp $
|
||||||
//
|
//
|
||||||
// samskivert library - useful routines for java programs
|
// samskivert library - useful routines for java programs
|
||||||
// Copyright (C) 2001 Michael Bayne
|
// Copyright (C) 2001 Michael Bayne
|
||||||
@@ -35,12 +35,14 @@ import org.apache.velocity.app.Velocity;
|
|||||||
import org.apache.velocity.context.Context;
|
import org.apache.velocity.context.Context;
|
||||||
import org.apache.velocity.exception.ParseErrorException;
|
import org.apache.velocity.exception.ParseErrorException;
|
||||||
import org.apache.velocity.exception.ResourceNotFoundException;
|
import org.apache.velocity.exception.ResourceNotFoundException;
|
||||||
|
import org.apache.velocity.runtime.RuntimeSingleton;
|
||||||
import org.apache.velocity.servlet.VelocityServlet;
|
import org.apache.velocity.servlet.VelocityServlet;
|
||||||
|
|
||||||
import com.samskivert.Log;
|
import com.samskivert.Log;
|
||||||
|
|
||||||
import com.samskivert.servlet.MessageManager;
|
import com.samskivert.servlet.MessageManager;
|
||||||
import com.samskivert.servlet.RedirectException;
|
import com.samskivert.servlet.RedirectException;
|
||||||
|
import com.samskivert.servlet.SiteIdentifier;
|
||||||
import com.samskivert.servlet.util.ExceptionMap;
|
import com.samskivert.servlet.util.ExceptionMap;
|
||||||
import com.samskivert.servlet.util.FriendlyException;
|
import com.samskivert.servlet.util.FriendlyException;
|
||||||
|
|
||||||
@@ -162,16 +164,13 @@ public class DispatcherServlet extends VelocityServlet
|
|||||||
/**
|
/**
|
||||||
* Initialize ourselves and our application.
|
* Initialize ourselves and our application.
|
||||||
*/
|
*/
|
||||||
public void init (ServletConfig config)
|
protected void initVelocity (ServletConfig config)
|
||||||
throws ServletException
|
throws ServletException
|
||||||
{
|
{
|
||||||
super.init(config);
|
|
||||||
|
|
||||||
// Log.info("Initializing dispatcher servlet.");
|
|
||||||
|
|
||||||
// load up our application configuration
|
// load up our application configuration
|
||||||
try {
|
try {
|
||||||
String appcl = config.getInitParameter(APP_CLASS_PROPS_KEY);
|
String appcl = config.getInitParameter(APP_CLASS_PROPS_KEY);
|
||||||
|
Log.info("Creating application [class=" + appcl + "].");
|
||||||
if (appcl == null) {
|
if (appcl == null) {
|
||||||
_app = new Application();
|
_app = new Application();
|
||||||
} else {
|
} else {
|
||||||
@@ -184,21 +183,17 @@ public class DispatcherServlet extends VelocityServlet
|
|||||||
if (StringUtil.blank(logicPkg)) {
|
if (StringUtil.blank(logicPkg)) {
|
||||||
logicPkg = "";
|
logicPkg = "";
|
||||||
}
|
}
|
||||||
_app.init(getServletContext());
|
_app.init(getServletContext(), logicPkg);
|
||||||
_app.postInit(getServletContext(), logicPkg);
|
|
||||||
|
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
Log.warning("Error instantiating application.");
|
Log.warning("Error instantiating application.");
|
||||||
Log.logStackTrace(t);
|
Log.logStackTrace(t);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// documentation inherited
|
// stick the application into the Velocity application context
|
||||||
protected void initVelocity (ServletConfig config)
|
Velocity.setApplicationContext(_app);
|
||||||
throws ServletException
|
|
||||||
{
|
// now let velocity initialize itself
|
||||||
// stick the servlet context into the Velocity application context
|
|
||||||
Velocity.setApplicationContext(getServletContext());
|
|
||||||
super.initVelocity(config);
|
super.initVelocity(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,13 +214,20 @@ public class DispatcherServlet extends VelocityServlet
|
|||||||
*/
|
*/
|
||||||
public Template handleRequest (HttpServletRequest req,
|
public Template handleRequest (HttpServletRequest req,
|
||||||
HttpServletResponse rsp,
|
HttpServletResponse rsp,
|
||||||
Context ctx) throws Exception
|
Context ctx)
|
||||||
|
throws Exception
|
||||||
{
|
{
|
||||||
InvocationContext ictx = (InvocationContext)ctx;
|
InvocationContext ictx = (InvocationContext)ctx;
|
||||||
String errmsg = null;
|
String errmsg = null;
|
||||||
|
|
||||||
// first we select the template
|
// obtain the siteid for this request and stuff that into the
|
||||||
Template tmpl = selectTemplate(ictx);
|
// context
|
||||||
|
SiteIdentifier ident = _app.getSiteIdentifier();
|
||||||
|
int siteId = ident.identifySite(req);
|
||||||
|
ctx.put("__siteid__", new Integer(siteId));
|
||||||
|
|
||||||
|
// then select the template
|
||||||
|
Template tmpl = selectTemplate(siteId, ictx);
|
||||||
|
|
||||||
// assume an HTML response unless otherwise massaged by the logic
|
// assume an HTML response unless otherwise massaged by the logic
|
||||||
rsp.setContentType("text/html");
|
rsp.setContentType("text/html");
|
||||||
@@ -313,12 +315,16 @@ public class DispatcherServlet extends VelocityServlet
|
|||||||
*
|
*
|
||||||
* @return The template to be used in generating the response.
|
* @return The template to be used in generating the response.
|
||||||
*/
|
*/
|
||||||
protected Template selectTemplate (InvocationContext ctx)
|
protected Template selectTemplate (int siteId, InvocationContext ctx)
|
||||||
throws ResourceNotFoundException, ParseErrorException, Exception
|
throws ResourceNotFoundException, ParseErrorException, Exception
|
||||||
{
|
{
|
||||||
|
// create a site resource key based on the template path and the
|
||||||
|
// id of the site through which this request was made
|
||||||
String path = ctx.getRequest().getServletPath();
|
String path = ctx.getRequest().getServletPath();
|
||||||
// Log.info("Loading template [path=" + path + "].");
|
SiteResourceKey key = new SiteResourceKey(siteId, path);
|
||||||
return getTemplate(path);
|
|
||||||
|
// Log.info("Loading template [key=" + key + "].");
|
||||||
|
return RuntimeSingleton.getRuntimeServices().getTemplate(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,170 @@
|
|||||||
|
//
|
||||||
|
// $Id: ImportDirective.java,v 1.1 2001/11/06 04:49:32 mdb Exp $
|
||||||
|
//
|
||||||
|
// samskivert library - useful routines for java programs
|
||||||
|
// Copyright (C) 2001 Michael Bayne
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Lesser General Public License as published
|
||||||
|
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
package com.samskivert.velocity;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Writer;
|
||||||
|
|
||||||
|
import org.apache.velocity.context.InternalContextAdapter;
|
||||||
|
|
||||||
|
import org.apache.velocity.Template;
|
||||||
|
import org.apache.velocity.runtime.RuntimeConstants;
|
||||||
|
import org.apache.velocity.runtime.directive.Directive;
|
||||||
|
import org.apache.velocity.runtime.parser.node.Node;
|
||||||
|
import org.apache.velocity.runtime.parser.node.SimpleNode;
|
||||||
|
import org.apache.velocity.runtime.resource.Resource;
|
||||||
|
|
||||||
|
import org.apache.velocity.exception.MethodInvocationException;
|
||||||
|
import org.apache.velocity.exception.ParseErrorException;
|
||||||
|
import org.apache.velocity.exception.ResourceNotFoundException;
|
||||||
|
|
||||||
|
import com.samskivert.servlet.SiteIdentifier;
|
||||||
|
import com.samskivert.util.StringUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pluggable directive that handles the #import() statement in VTL. Import
|
||||||
|
* is like #parse() except that it creates a {@link SiteResourceKey} based
|
||||||
|
* on information from the current request when fetching the imported
|
||||||
|
* template.
|
||||||
|
*/
|
||||||
|
public class ImportDirective extends Directive
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Returns name of this directive.
|
||||||
|
*/
|
||||||
|
public String getName ()
|
||||||
|
{
|
||||||
|
return "import";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return type of this directive.
|
||||||
|
*/
|
||||||
|
public int getType ()
|
||||||
|
{
|
||||||
|
return LINE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads and renders the imported template.
|
||||||
|
*/
|
||||||
|
public boolean render (
|
||||||
|
InternalContextAdapter context, Writer writer, Node node)
|
||||||
|
throws IOException, ResourceNotFoundException, ParseErrorException,
|
||||||
|
MethodInvocationException
|
||||||
|
{
|
||||||
|
// make sure an argument was supplied to the directive
|
||||||
|
if (node.jjtGetChild(0) == null) {
|
||||||
|
rsvc.error("#import() error : null argument");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure that argument has a value
|
||||||
|
Object value = node.jjtGetChild(0).value(context);
|
||||||
|
if (value == null) {
|
||||||
|
rsvc.error("#import() error : null argument");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// obtain the path to the desired template
|
||||||
|
String path = value.toString();
|
||||||
|
|
||||||
|
// make sure we haven't exceeded the configured parse depth
|
||||||
|
Object[] templateStack = context.getTemplateNameStack();
|
||||||
|
int maxlen = rsvc.getInt(
|
||||||
|
RuntimeConstants.PARSE_DIRECTIVE_MAXDEPTH, 20);
|
||||||
|
if (templateStack.length >= maxlen) {
|
||||||
|
rsvc.error("Max recursion depth reached (" + maxlen + "). " +
|
||||||
|
"File stack: " +
|
||||||
|
StringUtil.toString(templateStack) + ".");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// inherit the current encoding if there is a current template,
|
||||||
|
// otherwise use the configured encoding
|
||||||
|
String encoding = null;
|
||||||
|
Resource current = context.getCurrentResource();
|
||||||
|
if (current != null) {
|
||||||
|
encoding = current.getEncoding();
|
||||||
|
} else {
|
||||||
|
encoding = (String)
|
||||||
|
rsvc.getProperty(RuntimeConstants.INPUT_ENCODING);
|
||||||
|
}
|
||||||
|
|
||||||
|
// construct the template key based on the desired path and the
|
||||||
|
// site information in the current context. the siteid was shoved
|
||||||
|
// into the context by the dispatcher servlet. this is a hack, i
|
||||||
|
// know, but i couldn't convince the velocity peeps that we should
|
||||||
|
// have access to a request context in places like this
|
||||||
|
Object siteIdVal = context.get("__siteid__");
|
||||||
|
int siteId = SiteIdentifier.DEFAULT_SITE_ID;
|
||||||
|
try {
|
||||||
|
siteId = ((Integer)siteIdVal).intValue();
|
||||||
|
} catch (Exception e) {
|
||||||
|
rsvc.error("#import() error: No siteId information in context.");
|
||||||
|
}
|
||||||
|
Object tkey = new SiteResourceKey(siteId, path);
|
||||||
|
|
||||||
|
// locate the requested template
|
||||||
|
Template t = null;
|
||||||
|
try {
|
||||||
|
t = rsvc.getTemplate(tkey, encoding);
|
||||||
|
|
||||||
|
} catch (ResourceNotFoundException rnfe) {
|
||||||
|
rsvc.error("#import(): cannot find template '" + tkey +
|
||||||
|
"', called from template " +
|
||||||
|
context.getCurrentTemplateName() +
|
||||||
|
" at (" + getLine() + ", " + getColumn() + ")");
|
||||||
|
throw rnfe;
|
||||||
|
|
||||||
|
} catch (ParseErrorException pee) {
|
||||||
|
rsvc.error("#import(): syntax error in #import()-ed template '" +
|
||||||
|
tkey + "', called from template " +
|
||||||
|
context.getCurrentTemplateName() +
|
||||||
|
" at (" + getLine() + ", " + getColumn() + ")");
|
||||||
|
throw pee;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
rsvc.error("#import(): Error [path=" + tkey +
|
||||||
|
", error=" + e + "].");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// finally render the template
|
||||||
|
try {
|
||||||
|
context.pushCurrentTemplateName(path);
|
||||||
|
((SimpleNode)t.getData()).render(context, writer);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
// we want to pass method invocation exceptions through
|
||||||
|
if (e instanceof MethodInvocationException) {
|
||||||
|
throw (MethodInvocationException)e;
|
||||||
|
}
|
||||||
|
rsvc.error("Exception rendering #import(" + path + "): " + e);
|
||||||
|
return false;
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
context.popCurrentTemplateName();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
+19
-1
@@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// $Id: ServletContextResourceLoader.java,v 1.2 2001/11/02 02:30:24 mdb Exp $
|
// $Id: ServletContextResourceLoader.java,v 1.3 2001/11/06 04:49:32 mdb Exp $
|
||||||
//
|
//
|
||||||
// samskivert library - useful routines for java programs
|
// samskivert library - useful routines for java programs
|
||||||
// Copyright (C) 2001 Michael Bayne
|
// Copyright (C) 2001 Michael Bayne
|
||||||
@@ -38,6 +38,24 @@ import org.apache.velocity.runtime.resource.loader.ResourceLoader;
|
|||||||
*/
|
*/
|
||||||
public class ServletContextResourceLoader extends ResourceLoader
|
public class ServletContextResourceLoader extends ResourceLoader
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* When used with the default Velocity resource manager, we are
|
||||||
|
* constructed with our zero-argument constructor and later
|
||||||
|
* initialized via {@link #init}.
|
||||||
|
*/
|
||||||
|
public ServletContextResourceLoader ()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When used with the {@link SiteResourceManager} we are constructed
|
||||||
|
* with our servlet context reference and not later initialized.
|
||||||
|
*/
|
||||||
|
public ServletContextResourceLoader (ServletContext sctx)
|
||||||
|
{
|
||||||
|
_sctx = sctx;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by Velocity to initialize this resource loader.
|
* Called by Velocity to initialize this resource loader.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -0,0 +1,182 @@
|
|||||||
|
//
|
||||||
|
// $Id: SiteJarResourceLoader.java,v 1.1 2001/11/06 04:49:32 mdb Exp $
|
||||||
|
//
|
||||||
|
// samskivert library - useful routines for java programs
|
||||||
|
// Copyright (C) 2001 Michael Bayne
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Lesser General Public License as published
|
||||||
|
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
package com.samskivert.velocity;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import javax.servlet.ServletContext;
|
||||||
|
|
||||||
|
import org.apache.commons.collections.ExtendedProperties;
|
||||||
|
import org.apache.velocity.exception.ResourceNotFoundException;
|
||||||
|
import org.apache.velocity.runtime.RuntimeServices;
|
||||||
|
import org.apache.velocity.runtime.resource.Resource;
|
||||||
|
import org.apache.velocity.runtime.resource.loader.ResourceLoader;
|
||||||
|
|
||||||
|
import com.samskivert.Log;
|
||||||
|
import com.samskivert.servlet.SiteIdentifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Velocity resource loader that loads resources from site-specific jar
|
||||||
|
* files. This cannot be used with the default Velocity resource manager,
|
||||||
|
* but is used by the {@link SiteResourceManager} which automatically
|
||||||
|
* handles the creation and use of this resource loader.
|
||||||
|
*
|
||||||
|
* @see com.samskivert.servlet.SiteResourceLoader
|
||||||
|
*/
|
||||||
|
public class SiteResourceLoader extends ResourceLoader
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Constructs a site resource loader that will use the specified site
|
||||||
|
* identifier to map site ids to site strings.
|
||||||
|
*/
|
||||||
|
public SiteResourceLoader (SiteIdentifier ident, ServletContext context)
|
||||||
|
{
|
||||||
|
// naming conflict... alas.
|
||||||
|
_loader = new com.samskivert.servlet.SiteResourceLoader(
|
||||||
|
ident, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is not called.
|
||||||
|
*/
|
||||||
|
public void init (ExtendedProperties config)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the input stream that can be used to load the named
|
||||||
|
* resource.
|
||||||
|
*
|
||||||
|
* @param resourceKey the locator key for the resource to be loaded.
|
||||||
|
*
|
||||||
|
* @return an input stream that can be used to read the resource.
|
||||||
|
*
|
||||||
|
* @exception ResourceNotFoundException if the resource was not found.
|
||||||
|
*/
|
||||||
|
public InputStream getResourceStream (Object resourceKey)
|
||||||
|
throws ResourceNotFoundException
|
||||||
|
{
|
||||||
|
SiteResourceKey skey = castKey(resourceKey);
|
||||||
|
if (skey == null) {
|
||||||
|
String errmsg = "Cannot use SiteResourceLoader without " +
|
||||||
|
"loading resources with SiteResourceKey instances.";
|
||||||
|
throw new ResourceNotFoundException(errmsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// load it on up
|
||||||
|
try {
|
||||||
|
InputStream stream = _loader.getResourceAsStream(
|
||||||
|
skey.getSiteId(), skey.getPath(), false);
|
||||||
|
if (stream == null) {
|
||||||
|
String errmsg = "Unable to load resource via " +
|
||||||
|
"site-specific jar file [key=" + skey + "].";
|
||||||
|
throw new ResourceNotFoundException(errmsg);
|
||||||
|
}
|
||||||
|
return stream;
|
||||||
|
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
throw new ResourceNotFoundException(ioe.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Things won't ever be modified when loaded from the servlet context
|
||||||
|
* because they came from the webapp .war file and if that is
|
||||||
|
* reloaded, everything will be thrown away and started afresh.
|
||||||
|
*/
|
||||||
|
public boolean isSourceModified (Resource resource)
|
||||||
|
{
|
||||||
|
SiteResourceKey skey = castKey(resource.getKey());
|
||||||
|
if (skey == null) {
|
||||||
|
// return false if we were supplied with a bogus key
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the resource is for the default site, it is never considered
|
||||||
|
// to be modified
|
||||||
|
int siteId = skey.getSiteId();
|
||||||
|
if (siteId == SiteIdentifier.DEFAULT_SITE_ID) {
|
||||||
|
return false;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// otherwise compare the last modified time of the loaded
|
||||||
|
// resource with the last modified time of the associated
|
||||||
|
// site-specific jar file
|
||||||
|
try {
|
||||||
|
return (resource.getLastModified() <
|
||||||
|
_loader.getLastModified(siteId));
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
Log.warning("Failure obtaining last modified time of " +
|
||||||
|
"site-specific jar file [siteId=" + siteId +
|
||||||
|
", error=" + ioe + "].");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Things won't ever be modified when loaded from the servlet context
|
||||||
|
* because they came from the webapp .war file and if that is
|
||||||
|
* reloaded, everything will be thrown away and started afresh. So we
|
||||||
|
* can punt here and return zero.
|
||||||
|
*/
|
||||||
|
public long getLastModified (Resource resource)
|
||||||
|
{
|
||||||
|
SiteResourceKey skey = castKey(resource.getKey());
|
||||||
|
if (skey == null) {
|
||||||
|
// return 0 if we were supplied with a bogus key
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the resource is for the default site, it is never considered
|
||||||
|
// to be modified
|
||||||
|
int siteId = skey.getSiteId();
|
||||||
|
if (siteId == SiteIdentifier.DEFAULT_SITE_ID) {
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// otherwise return the last modified time of the associated
|
||||||
|
// site-specific jar file
|
||||||
|
try {
|
||||||
|
return _loader.getLastModified(siteId);
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
Log.warning("Failure obtaining last modified time of " +
|
||||||
|
"site-specific jar file [siteId=" + siteId +
|
||||||
|
", error=" + ioe + "].");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Casts the supplied resource key to a {@link SiteResourceKey} and
|
||||||
|
* returns it iff it is an instance of such. Returns null otherwise.
|
||||||
|
*/
|
||||||
|
protected SiteResourceKey castKey (Object resourceKey)
|
||||||
|
{
|
||||||
|
return (resourceKey instanceof SiteResourceKey) ?
|
||||||
|
(SiteResourceKey)resourceKey : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A reference to the site resource loader through which we'll load
|
||||||
|
* things. */
|
||||||
|
protected com.samskivert.servlet.SiteResourceLoader _loader;
|
||||||
|
}
|
||||||
@@ -0,0 +1,180 @@
|
|||||||
|
//
|
||||||
|
// $Id: SiteResourceKey.java,v 1.1 2001/11/06 04:49:32 mdb Exp $
|
||||||
|
//
|
||||||
|
// samskivert library - useful routines for java programs
|
||||||
|
// Copyright (C) 2001 Michael Bayne
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Lesser General Public License as published
|
||||||
|
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
package com.samskivert.velocity;
|
||||||
|
|
||||||
|
import com.samskivert.servlet.SiteIdentifier;
|
||||||
|
import com.samskivert.util.IntListUtil;
|
||||||
|
import com.samskivert.util.StringUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The site resource key is used as a key for resources that can be used
|
||||||
|
* for one or more sites. A resource always has the same path, but can be
|
||||||
|
* valid for a single site, or multiple sites and the set of sites for
|
||||||
|
* which a resource is valid can change without impacting the key's hash
|
||||||
|
* value.
|
||||||
|
*/
|
||||||
|
public class SiteResourceKey
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Constructs a new site resource key for the specified resource,
|
||||||
|
* loaded via the specified site.
|
||||||
|
*/
|
||||||
|
public SiteResourceKey (int siteId, String path)
|
||||||
|
{
|
||||||
|
_path = path;
|
||||||
|
_sites = new int[] { siteId };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resource keys that contain only a single site id will return that
|
||||||
|
* site id as their primary. Those that contain multiple sites are
|
||||||
|
* assumed to reference default resources (which may be applicable to
|
||||||
|
* multiple sites) in which case the default site id is returned.
|
||||||
|
*/
|
||||||
|
public int getSiteId ()
|
||||||
|
{
|
||||||
|
return (_sites.length == 1 ? _sites[0] :
|
||||||
|
SiteIdentifier.DEFAULT_SITE_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the path to the resource referenced by this site resource
|
||||||
|
* key.
|
||||||
|
*/
|
||||||
|
public String getPath ()
|
||||||
|
{
|
||||||
|
return _path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this resource key contains the specified site in
|
||||||
|
* its site set.
|
||||||
|
*/
|
||||||
|
public boolean containsSite (int siteId)
|
||||||
|
{
|
||||||
|
return IntListUtil.contains(_sites, siteId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a site to this site resource key. The resource to which this
|
||||||
|
* key maps is assumed to be valid for the added site.
|
||||||
|
*/
|
||||||
|
public void addSite (int siteId)
|
||||||
|
{
|
||||||
|
// sanity check
|
||||||
|
if (siteId == 0) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Site IDs cannot have the value 0.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the site to the list only if it's not already there
|
||||||
|
int[] sites = IntListUtil.testAndAdd(_sites, siteId);
|
||||||
|
if (sites != null) {
|
||||||
|
_sites = sites;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a site from this site resource key. The resource to which
|
||||||
|
* this key maps is no longer assumed to be valid for the removed
|
||||||
|
* site.
|
||||||
|
*/
|
||||||
|
public boolean removeSite (int siteId)
|
||||||
|
{
|
||||||
|
// sanity check
|
||||||
|
if (siteId == 0) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Site IDs cannot have the value 0.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove the site from the list
|
||||||
|
return (IntListUtil.remove(_sites, siteId) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We hash to the hash value of our path.
|
||||||
|
*/
|
||||||
|
public int hashCode ()
|
||||||
|
{
|
||||||
|
return _path.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Two site resource keys are equal if the paths are the same and at
|
||||||
|
* least one site id overlaps between the two keys. Most equality
|
||||||
|
* comparisons will involve one multi-site key and one key that
|
||||||
|
* contains only a single site.
|
||||||
|
*/
|
||||||
|
public boolean equals (Object other)
|
||||||
|
{
|
||||||
|
if (other instanceof SiteResourceKey) {
|
||||||
|
SiteResourceKey okey = (SiteResourceKey)other;
|
||||||
|
|
||||||
|
// make sure the paths match
|
||||||
|
if (!_path.equals(okey._path)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// select the key with fewer sites in its sites array to be in
|
||||||
|
// the outer loop
|
||||||
|
int[] s1 = _sites;
|
||||||
|
int[] s2 = okey._sites;
|
||||||
|
if (s2.length < s1.length) {
|
||||||
|
s1 = s2;
|
||||||
|
s2 = _sites;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i1 = 0; i1 < s1.length; i1++) {
|
||||||
|
for (int i2 = 0; i2 < s2.length; i2++) {
|
||||||
|
if (s1[i1] == s2[i2]) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The string representation of a resource key is just the path so
|
||||||
|
* that it is backwards compatible with older resource loaders.
|
||||||
|
*/
|
||||||
|
public String toString ()
|
||||||
|
{
|
||||||
|
return _path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string description of this object.
|
||||||
|
*/
|
||||||
|
public String description ()
|
||||||
|
{
|
||||||
|
return ("[path=" + _path +
|
||||||
|
", sites=" + StringUtil.toString(_sites) + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The path to the resource. */
|
||||||
|
protected String _path;
|
||||||
|
|
||||||
|
/** The sites for which this resource is valid. */
|
||||||
|
protected int[] _sites;
|
||||||
|
}
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
//
|
||||||
|
// $Id: SiteResourceManager.java,v 1.1 2001/11/06 04:49:32 mdb Exp $
|
||||||
|
//
|
||||||
|
// samskivert library - useful routines for java programs
|
||||||
|
// Copyright (C) 2001 Michael Bayne
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Lesser General Public License as published
|
||||||
|
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
package com.samskivert.velocity;
|
||||||
|
|
||||||
|
import javax.servlet.ServletContext;
|
||||||
|
|
||||||
|
import org.apache.velocity.exception.ParseErrorException;
|
||||||
|
import org.apache.velocity.exception.ResourceNotFoundException;
|
||||||
|
import org.apache.velocity.runtime.RuntimeServices;
|
||||||
|
import org.apache.velocity.runtime.resource.Resource;
|
||||||
|
import org.apache.velocity.runtime.resource.ResourceFactory;
|
||||||
|
import org.apache.velocity.runtime.resource.ResourceManagerImpl;
|
||||||
|
import org.apache.velocity.runtime.resource.loader.ResourceLoader;
|
||||||
|
|
||||||
|
import com.samskivert.Log;
|
||||||
|
import com.samskivert.servlet.SiteIdentifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A resource manager implementation for Velocity that first loads site
|
||||||
|
* specific resources (via the {@link SiteResourceLoader}), but falls back
|
||||||
|
* to default resources if no site-specific resource loader is available.
|
||||||
|
*
|
||||||
|
* <p> If this resource manager is to be used, resources must be fetched
|
||||||
|
* using {@likn SiteResourceKey} objects as keys rather than simple
|
||||||
|
* strings.
|
||||||
|
*/
|
||||||
|
public class SiteResourceManager extends ResourceManagerImpl
|
||||||
|
{
|
||||||
|
public void initialize (RuntimeServices rsvc)
|
||||||
|
throws Exception
|
||||||
|
{
|
||||||
|
super.initialize(rsvc);
|
||||||
|
|
||||||
|
// the web framework was kind enough to slip this into the runtime
|
||||||
|
// instance when it started up
|
||||||
|
Application app = (Application)rsvc.getApplicationContext();
|
||||||
|
if (app == null) {
|
||||||
|
rsvc.warn("SiteResourceManager: Application reference " +
|
||||||
|
"was not supplied as application context. A " +
|
||||||
|
"user of the site resource manager must supply " +
|
||||||
|
"a reference to the Application instance via " +
|
||||||
|
"Velocity.setApplicationContext().");
|
||||||
|
}
|
||||||
|
|
||||||
|
// get handles on the good stuff
|
||||||
|
_sctx = app.getServletContext();
|
||||||
|
_ident = app.getSiteIdentifier();
|
||||||
|
|
||||||
|
// create our resource loaders
|
||||||
|
_siteLoader = new SiteResourceLoader(_ident, _sctx);
|
||||||
|
_contextLoader = new ServletContextResourceLoader(_sctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Resource loadResource(
|
||||||
|
Object resourceKey, int resourceType, String encoding)
|
||||||
|
throws ResourceNotFoundException, ParseErrorException, Exception
|
||||||
|
{
|
||||||
|
// create a blank new resource
|
||||||
|
Resource resource =
|
||||||
|
ResourceFactory.getResource(resourceKey, resourceType);
|
||||||
|
resource.setRuntimeServices(rsvc);
|
||||||
|
resource.setKey(resourceKey);
|
||||||
|
resource.setEncoding(encoding);
|
||||||
|
|
||||||
|
// if the resource was requested using a site resource key, we can
|
||||||
|
// attempt to load a site-specific version
|
||||||
|
if (resourceKey instanceof SiteResourceKey) {
|
||||||
|
SiteResourceKey rkey = (SiteResourceKey)resourceKey;
|
||||||
|
Log.info("Looking for site-specific version of " +
|
||||||
|
rkey.description() + ".");
|
||||||
|
|
||||||
|
// make sure the site we're loading for is not the default
|
||||||
|
// site, in which case we want to skip to the second resource
|
||||||
|
// loader directly
|
||||||
|
if (rkey.getSiteId() != SiteIdentifier.DEFAULT_SITE_ID) {
|
||||||
|
// try loading it via the site-specific resource loader
|
||||||
|
try {
|
||||||
|
resolveResource(resource, _siteLoader);
|
||||||
|
Log.info("Loaded site-specific [key=" + resourceKey + "].");
|
||||||
|
} catch (ResourceNotFoundException rnfe) {
|
||||||
|
// nothing to worry about here
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// try the servlet context loader if we didn't find a
|
||||||
|
// site-specific resource
|
||||||
|
if (resource.getData() == null) {
|
||||||
|
resolveResource(resource, _contextLoader);
|
||||||
|
Log.info("Loaded default [key=" + resourceKey + "].");
|
||||||
|
}
|
||||||
|
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void resolveResource (Resource resource, ResourceLoader loader)
|
||||||
|
throws ResourceNotFoundException, ParseErrorException, Exception
|
||||||
|
{
|
||||||
|
resource.setResourceLoader(loader);
|
||||||
|
resource.process();
|
||||||
|
resource.setLastModified(loader.getLastModified(resource));
|
||||||
|
resource.setModificationCheckInterval(
|
||||||
|
loader.getModificationCheckInterval());
|
||||||
|
resource.touch();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A reference to the servlet context through which we'll load
|
||||||
|
* default resources. */
|
||||||
|
protected ServletContext _sctx;
|
||||||
|
|
||||||
|
/** A reference to the site identifier in use by the application. */
|
||||||
|
protected SiteIdentifier _ident;
|
||||||
|
|
||||||
|
/** We use this to load site-specific resources. */
|
||||||
|
protected SiteResourceLoader _siteLoader;
|
||||||
|
|
||||||
|
/** We use this to load default resources. */
|
||||||
|
protected ServletContextResourceLoader _contextLoader;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user