Deprecation begone!

git-svn-id: https://samskivert.googlecode.com/svn/trunk@2138 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
mdb
2007-07-25 23:30:07 +00:00
parent 023384ead1
commit e021e82865
22 changed files with 398 additions and 282 deletions
+1 -3
View File
@@ -57,8 +57,7 @@
<!-- build the java class files --> <!-- build the java class files -->
<target name="compile" depends="prepare,compute-builds"> <target name="compile" depends="prepare,compute-builds">
<javac srcdir="${src.dir}" destdir="${deploy.dir}/classes" includeAntRuntime="false" <javac srcdir="${src.dir}" destdir="${deploy.dir}/classes" includeAntRuntime="false"
debug="on" optimize="${build.optimize}" deprecation="off" debug="on" optimize="${build.optimize}" source="1.5" target="1.5" encoding="utf-8">
source="1.5" target="1.5" encoding="utf-8">
<classpath refid="classpath"/> <classpath refid="classpath"/>
<exclude name="com/samskivert/io/**" unless="build.io"/> <exclude name="com/samskivert/io/**" unless="build.io"/>
<exclude name="com/samskivert/jdbc/**" unless="build.jdbc"/> <exclude name="com/samskivert/jdbc/**" unless="build.jdbc"/>
@@ -73,7 +72,6 @@
<exclude name="com/samskivert/xml/**" unless="build.xml"/> <exclude name="com/samskivert/xml/**" unless="build.xml"/>
<compilerarg value="-Xlint"/> <compilerarg value="-Xlint"/>
<compilerarg value="-Xlint:-serial"/> <compilerarg value="-Xlint:-serial"/>
<compilerarg value="-Xlint:-deprecation"/>
</javac> </javac>
</target> </target>
@@ -57,23 +57,9 @@ public interface DatabaseLiaison
*/ */
public boolean isTransientException (SQLException sqe); public boolean isTransientException (SQLException sqe);
/**
* Returns the value of an <code>AUTO_INCREMENT</code> column for the last row insertion. This
* is MySQL specific, but exists here for now until we sort out a general purpose mechanism for
* assigning unique ids.
*
* Note: More general purpose: {@link #lastInsertedId(Connection, String, String)
*
* @return the most recent ID generated by an insert into an <code>AUTO_INCREMENT</code> table
* or -1 if it could not be obtained.
*/
@Deprecated
public int lastInsertedId (Connection conn)
throws SQLException;
/** /**
* This method initializes the column value auto-generator described in {@link * This method initializes the column value auto-generator described in {@link
* #lastInsertedId(Connection, String, String)}. * #lastInsertedId}.
*/ */
public void initializeGenerator ( public void initializeGenerator (
Connection conn, String table, String column, int first, int step) Connection conn, String table, String column, int first, int step)
@@ -47,7 +47,7 @@ public class DefaultLiaison extends BaseLiaison
return false; return false;
} }
// from DatabaseLiaison @SuppressWarnings("deprecation") // from DatabaseLiaison
public int lastInsertedId (Connection conn) throws SQLException public int lastInsertedId (Connection conn) throws SQLException
{ {
return -1; return -1;
@@ -65,7 +65,7 @@ public abstract class JORARepository extends SimpleRepository
throws SQLException, PersistenceException throws SQLException, PersistenceException
{ {
table.insert(conn, object); table.insert(conn, object);
return liaison.lastInsertedId(conn); return liaison.lastInsertedId(conn, table.getName(), "TODO");
} }
}); });
} }
@@ -265,7 +265,7 @@ public abstract class JORARepository extends SimpleRepository
{ {
if (table.update(conn, object) == 0) { if (table.update(conn, object) == 0) {
table.insert(conn, object); table.insert(conn, object);
return liaison.lastInsertedId(conn); return liaison.lastInsertedId(conn, table.getName(), "TODO");
} }
return -1; return -1;
} }
+3 -10
View File
@@ -47,16 +47,9 @@ public class MySQLLiaison extends BaseLiaison
public boolean isTransientException (SQLException sqe) public boolean isTransientException (SQLException sqe)
{ {
String msg = sqe.getMessage(); String msg = sqe.getMessage();
return (msg != null && return (msg != null && (msg.indexOf("Lost connection") != -1 ||
(msg.indexOf("Lost connection") != -1 || msg.indexOf("link failure") != -1 ||
msg.indexOf("link failure") != -1 || msg.indexOf("Broken pipe") != -1));
msg.indexOf("Broken pipe") != -1));
}
// from DatabaseLiaison
public int lastInsertedId (Connection conn) throws SQLException
{
return lastInsertedId(conn, null, null);
} }
// from DatabaseLiaison // from DatabaseLiaison
@@ -49,13 +49,6 @@ public class PostgreSQLLiaison extends BaseLiaison
msg.indexOf("An I/O error occured while sending to the backend") != -1); msg.indexOf("An I/O error occured while sending to the backend") != -1);
} }
// from DatabaseLiaison
public int lastInsertedId (Connection conn) throws SQLException
{
throw new SQLException(
"No backwards-compatible lastInsertedId() support for PostgreSQL in this code.");
}
// from DatabaseLiaison // from DatabaseLiaison
public int lastInsertedId (Connection conn, String table, String column) throws SQLException public int lastInsertedId (Connection conn, String table, String column) throws SQLException
{ {
@@ -27,6 +27,7 @@ import java.sql.SQLException;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import com.samskivert.io.PersistenceException; import com.samskivert.io.PersistenceException;
import com.samskivert.util.ArrayUtil; import com.samskivert.util.ArrayUtil;
@@ -50,7 +51,7 @@ import com.samskivert.jdbc.depot.expression.ValueExp;
* Provides a base for classes that provide access to persistent objects. Also defines the * Provides a base for classes that provide access to persistent objects. Also defines the
* mechanism by which all persistent queries and updates are routed through the distributed cache. * mechanism by which all persistent queries and updates are routed through the distributed cache.
*/ */
public class DepotRepository public abstract class DepotRepository
{ {
/** /**
* Creates a repository with the supplied connection provider and its own private persistence * Creates a repository with the supplied connection provider and its own private persistence
@@ -59,6 +60,7 @@ public class DepotRepository
protected DepotRepository (ConnectionProvider conprov) protected DepotRepository (ConnectionProvider conprov)
{ {
_ctx = new PersistenceContext(getClass().getName(), conprov); _ctx = new PersistenceContext(getClass().getName(), conprov);
_ctx.repositoryCreated(this);
} }
/** /**
@@ -67,8 +69,14 @@ public class DepotRepository
protected DepotRepository (PersistenceContext context) protected DepotRepository (PersistenceContext context)
{ {
_ctx = context; _ctx = context;
_ctx.repositoryCreated(this);
} }
/**
* Adds the persistent classes used by this repository to the supplied set.
*/
protected abstract void getManagedRecords (Set<Class<? extends PersistentRecord>> classes);
/** /**
* Loads the persistent object that matches the specified primary key. * Loads the persistent object that matches the specified primary key.
*/ */
@@ -20,8 +20,11 @@
package com.samskivert.jdbc.depot; package com.samskivert.jdbc.depot;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@@ -393,6 +396,29 @@ public class PersistenceContext
listenerSet.add(listener); listenerSet.add(listener);
} }
/**
* Iterates over all {@link PersistentRecord} classes managed by this context and initializes
* their {@link DepotMarshaller}. This forces migrations to run and the database schema to be
* created.
*/
public void initializeManagedRecords ()
throws PersistenceException
{
for (Class<? extends PersistentRecord> rclass : _managedRecords) {
getMarshaller(rclass);
}
}
/**
* Called when a depot repository is created. We register all persistent record classes used by
* the repository so that systems that desire it can force the resolution of all database
* tables rather than allowing resolution to happen on demand.
*/
protected void repositoryCreated (DepotRepository repo)
{
repo.getManagedRecords(_managedRecords);
}
/** /**
* Looks up and creates, but does not initialize, the marshaller for the specified Entity * Looks up and creates, but does not initialize, the marshaller for the specified Entity
* type. * type.
@@ -474,4 +500,16 @@ public class PersistenceContext
protected Map<Class<?>, DepotMarshaller<?>> _marshallers = protected Map<Class<?>, DepotMarshaller<?>> _marshallers =
new HashMap<Class<?>, DepotMarshaller<?>>(); new HashMap<Class<?>, DepotMarshaller<?>>();
/**
* The set of persistent records for which this context is responsible. This data is used by
* {@link #initializeManagedRecords} to force migration/schema initialization.
*/
protected Set<Class<? extends PersistentRecord>> _managedRecords =
new HashSet<Class<? extends PersistentRecord>>();
/**
* A collection of all {@link PersistenceContext} objects in existence.
*/
protected static List<PersistenceContext> _contexts = new ArrayList<PersistenceContext>();
} }
@@ -22,10 +22,12 @@ package com.samskivert.jdbc.depot.tests;
import java.sql.Date; import java.sql.Date;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.util.Set;
import com.samskivert.jdbc.ConnectionProvider; import com.samskivert.jdbc.ConnectionProvider;
import com.samskivert.jdbc.StaticConnectionProvider; import com.samskivert.jdbc.StaticConnectionProvider;
import com.samskivert.jdbc.depot.DepotRepository; import com.samskivert.jdbc.depot.DepotRepository;
import com.samskivert.jdbc.depot.PersistentRecord;
/** /**
* A test tool for the Depot repository services. * A test tool for the Depot repository services.
@@ -59,4 +61,10 @@ public class TestRepository extends DepotRepository
{ {
super(conprov); super(conprov);
} }
@Override // from DepotRepository
protected void getManagedRecords (Set<Class<? extends PersistentRecord>> classes)
{
classes.add(TestRecord.class);
}
} }
@@ -254,7 +254,7 @@ public class JDBCTableSiteIdentifier implements SiteIdentifier
if (1 != stmt.executeUpdate()) { if (1 != stmt.executeUpdate()) {
throw new PersistenceException("Not inserted " + site); throw new PersistenceException("Not inserted " + site);
} }
site.siteId = liaison.lastInsertedId(conn); site.siteId = liaison.lastInsertedId(conn, "sites", "siteId");
} finally { } finally {
JDBCUtil.close(stmt); JDBCUtil.close(stmt);
@@ -420,7 +420,7 @@ public class UserRepository extends JORARepository
try { try {
_utable.insert(conn, user); _utable.insert(conn, user);
// update the userid now that it's known // update the userid now that it's known
user.userId = liaison.lastInsertedId(conn); user.userId = liaison.lastInsertedId(conn, _utable.getName(), "userId");
// nothing to return // nothing to return
return null; return null;
@@ -34,6 +34,7 @@ public class SmartPolygon extends Polygon
* Returns the internally cached bounds rectangle for this polygon. * Returns the internally cached bounds rectangle for this polygon.
* <em>Don't modify it!</em> * <em>Don't modify it!</em>
*/ */
@SuppressWarnings("deprecation")
public Rectangle getBoundingBox () public Rectangle getBoundingBox ()
{ {
return (bounds == null) ? super.getBoundingBox() : bounds; return (bounds == null) ? super.getBoundingBox() : bounds;
@@ -553,10 +553,11 @@ public class TGraphics2D extends Graphics2D
return _primary.toString(); return _primary.toString();
} }
@SuppressWarnings("deprecation")
public Rectangle getClipRect () public Rectangle getClipRect ()
{ {
// getClipRect is deprecated, but getClipBounds is the new way // getClipRect is deprecated, but getClipBounds is the new way to do the same thing. We
// to do the same thing. We call that to avoid deprecation warnings. // call that to avoid deprecation warnings.
return _primary.getClipBounds(); return _primary.getClipBounds();
} }
@@ -62,6 +62,6 @@ public class AdjustTestApp
frame.getContentPane().add(RuntimeAdjust.createAdjustEditor(), BorderLayout.CENTER); frame.getContentPane().add(RuntimeAdjust.createAdjustEditor(), BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack(); frame.pack();
frame.show(); frame.setVisible(true);
} }
} }
@@ -143,7 +143,7 @@ public class LabelDemo extends JPanel
LabelDemo demo = new LabelDemo(); LabelDemo demo = new LabelDemo();
frame.getContentPane().add(demo); frame.getContentPane().add(demo);
frame.pack(); frame.pack();
frame.show(); frame.setVisible(true);
} }
protected Label[] _labels = new Label[10]; protected Label[] _labels = new Label[10];
@@ -59,6 +59,6 @@ public class TestComboButtonBox
ComboButtonBox box = new ComboButtonBox(ComboButtonBox.HORIZONTAL, model); ComboButtonBox box = new ComboButtonBox(ComboButtonBox.HORIZONTAL, model);
frame.getContentPane().add(box); frame.getContentPane().add(box);
frame.pack(); frame.pack();
frame.show(); frame.setVisible(true);
} }
} }
@@ -3,7 +3,7 @@
// //
// samskivert library - useful routines for java programs // samskivert library - useful routines for java programs
// Copyright (C) 2001-2007 Michael Bayne // Copyright (C) 2001-2007 Michael Bayne
// //
// This library is free software; you can redistribute it and/or modify it // 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 // 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 // by the Free Software Foundation; either version 2.1 of the License, or
@@ -21,26 +21,33 @@
package com.samskivert.velocity; package com.samskivert.velocity;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Properties; import java.util.Properties;
import java.util.logging.Level;
import javax.servlet.ServletConfig; import javax.servlet.ServletConfig;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.apache.velocity.Template; import org.apache.velocity.Template;
import org.apache.velocity.context.Context; import org.apache.velocity.context.Context;
import org.apache.velocity.exception.MethodInvocationException;
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.io.VelocityWriter;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.RuntimeSingleton; import org.apache.velocity.runtime.RuntimeSingleton;
import org.apache.velocity.servlet.VelocityServlet; import org.apache.velocity.util.SimplePool;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.event.EventCartridge; import org.apache.velocity.app.event.EventCartridge;
import org.apache.velocity.app.event.MethodExceptionEventHandler; import org.apache.velocity.app.event.MethodExceptionEventHandler;
import com.samskivert.Log;
import com.samskivert.servlet.HttpErrorException; import com.samskivert.servlet.HttpErrorException;
import com.samskivert.servlet.MessageManager; import com.samskivert.servlet.MessageManager;
import com.samskivert.servlet.RedirectException; import com.samskivert.servlet.RedirectException;
@@ -51,46 +58,39 @@ import com.samskivert.servlet.util.FriendlyException;
import com.samskivert.util.ConfigUtil; import com.samskivert.util.ConfigUtil;
import com.samskivert.util.StringUtil; import com.samskivert.util.StringUtil;
import static com.samskivert.Log.log;
/** /**
* The dispatcher servlet builds upon Velocity's architecture. It does so * The dispatcher servlet builds upon Velocity's architecture. It does so in the following ways:
* in the following ways:
* *
* <ul> * <ul> <li> It defines the notion of a logic object which populates the context with data to be
* <li> It defines the notion of a logic object which populates the * used to satisfy a particular request. The logic is not a servlet and is therefore limited in
* context with data to be used to satisfy a particular request. The logic * what it can do while populating data. Experience dictates that ultimate flexibility leads to bad
* is not a servlet and is therefore limited in what it can do while * design decisions and that this is a place where that sort of thing can be comfortably nipped in
* populating data. Experience dictates that ultimate flexibility leads to * the bud. <br><br>
* bad design decisions and that this is a place where that sort of thing
* can be comfortably nipped in the bud. <br><br>
* *
* <li> It allows template files to be referenced directly in the URL * <li> It allows template files to be referenced directly in the URL while maintaining the ability
* while maintaining the ability to choose a cobranded template based on * to choose a cobranded template based on information in the request. The URI is mapped to a
* information in the request. The URI is mapped to a servlet based on * servlet based on some simple mapping rules. This provides template designers with a clearer
* some simple mapping rules. This provides template designers with a * understanding of the structure of a web application as well as with an easy way to test their
* clearer understanding of the structure of a web application as well as * templates in the absence of an associated servlet. <br><br>
* with an easy way to test their templates in the absence of an
* associated servlet. <br><br>
* *
* <li> It provides a common error handling paradigm that simplifies the * <li> It provides a common error handling paradigm that simplifies the task of authoring web
* task of authoring web applications. * applications.
* </ul> * </ul>
* *
* <p><b>URI to servlet mapping</b><br> * <p><b>URI to servlet mapping</b><br> The mapping process allows the Velocity framework to be
* The mapping process allows the Velocity framework to be invoked for all * invoked for all requests ending in a particular file extension (usually <code>.wm</code>). It is
* requests ending in a particular file extension (usually * necessary to instruct your servlet engine of choice to invoke the <code>DispatcherServlet</code>
* <code>.wm</code>). It is necessary to instruct your servlet engine of * for all requests ending in that extension. For Apache/JServ this looks something like this:
* choice to invoke the <code>DispatcherServlet</code> for all requests
* ending in that extension. For Apache/JServ this looks something like
* this:
* *
* <pre> * <pre>
* ApJServAction .wm /servlets/com.samskivert.velocity.Dispatcher * ApJServAction .wm /servlets/com.samskivert.velocity.Dispatcher
* </pre> * </pre>
* *
* The request URI then defines the path of the template that will be used * The request URI then defines the path of the template that will be used to satisfy the
* to satisfy the request. To understand how code is selected to go along * request. To understand how code is selected to go along with the request, let's look at an
* with the request, let's look at an example. Consider the following * example. Consider the following configuration:
* configuration:
* *
* <pre> * <pre>
* applications=whowhere * applications=whowhere
@@ -98,48 +98,44 @@ import com.samskivert.util.StringUtil;
* whowhere.base_pkg=whowhere.logic * whowhere.base_pkg=whowhere.logic
* </pre> * </pre>
* *
* This defines an application identified as <code>whowhere</code>. An * This defines an application identified as <code>whowhere</code>. An application is defined by
* application is defined by three parameters, the application identifier, * three parameters, the application identifier, the <code>base_uri</code>, and the
* the <code>base_uri</code>, and the <code>base_pkg</code>. The * <code>base_pkg</code>. The <code>base_uri</code> defines the prefix shared by all pages served
* <code>base_uri</code> defines the prefix shared by all pages served by * by the application and which serves to identify which application to invoke when processing a
* the application and which serves to identify which application to * request. The <code>base_pkg</code> is used to construct the logic classname based on the URI and
* invoke when processing a request. The <code>base_pkg</code> is used to * the <code>base_uri</code> parameter.
* construct the logic classname based on the URI and the
* <code>base_uri</code> parameter.
* *
* <p> Now let's look at a sample request to determine how the logic * <p> Now let's look at a sample request to determine how the logic classname is
* classname is resolved. Consider the following request URI: * resolved. Consider the following request URI:
* *
* <pre> * <pre>
* /whowhere/view/trips.wm * /whowhere/view/trips.wm
* </pre> * </pre>
* *
* It begins with <code>/whowhere</code> which tells the dispatcher that * It begins with <code>/whowhere</code> which tells the dispatcher that it's part of the
* it's part of the <code>whowhere</code> application. That application's * <code>whowhere</code> application. That application's <code>base_uri</code> is then stripped
* <code>base_uri</code> is then stripped from the URI leaving * from the URI leaving <code>/view/trips.wm</code>. The slashes are converted into periods to map
* <code>/view/trips.wm</code>. The slashes are converted into periods to * directories to packages, giving us <code>view.trips.wm</code>. Finally, the
* map directories to packages, giving us <code>view.trips.wm</code>. * <code>base_pkg</code> is prepended and the trailing <code>.wm</code> extension removed.
* Finally, the <code>base_pkg</code> is prepended and the trailing
* <code>.wm</code> extension removed.
* *
* <p> Thus the class invoked to populate the context for this request is * <p> Thus the class invoked to populate the context for this request is
* <code>whowhere.servlets.view.trips</code> (note that the classname * <code>whowhere.servlets.view.trips</code> (note that the classname <em>is</em> lowercase which
* <em>is</em> lowercase which is an intentional choice in resolving * is an intentional choice in resolving conflicting recommendations that classnames should always
* conflicting recommendations that classnames should always start with a * start with a capital letter and URLs should always be lowercase).
* capital letter and URLs should always be lowercase).
* *
* <p> The template used to generate the result is loaded based on the * <p> The template used to generate the result is loaded based on the full URI, essentially with a
* full URI, essentially with a call to * call to <code>getTemplate("/whowhere/view/trips.wm")</code> in this example. This is the place
* <code>getTemplate("/whowhere/view/trips.wm")</code> in this example. * where more sophisticated cobranding support could be inserted in the future (ie. if I ever want
* This is the place where more sophisticated cobranding support could be * to use this to develop a cobranded web site).
* inserted in the future (ie. if I ever want to use this to develop a
* cobranded web site).
* *
* @see Logic * @see Logic
*/ */
public class DispatcherServlet extends VelocityServlet public class DispatcherServlet extends HttpServlet
implements MethodExceptionEventHandler implements MethodExceptionEventHandler
{ {
/** The HTTP content type context key. */
public static final String CONTENT_TYPE = "default.contentType";
/** /**
* Performs various initialization. * Performs various initialization.
*/ */
@@ -148,29 +144,6 @@ public class DispatcherServlet extends VelocityServlet
{ {
super.init(config); super.init(config);
// determine the character set we'll use
_charset = config.getInitParameter(CHARSET_KEY);
if (_charset == null) {
_charset = "UTF-8";
}
}
/**
* Clean up after ourselves and our application.
*/
public void destroy ()
{
super.destroy();
// shutdown our application
_app.shutdown();
}
/**
* Initialize ourselves and our application.
*/
protected void initVelocity (ServletConfig config)
throws ServletException
{
// load up our application configuration // load up our application configuration
try { try {
String appcl = config.getInitParameter(APP_CLASS_KEY); String appcl = config.getInitParameter(APP_CLASS_KEY);
@@ -187,26 +160,62 @@ public class DispatcherServlet extends VelocityServlet
StringUtil.isBlank(logicPkg) ? "" : logicPkg); StringUtil.isBlank(logicPkg) ? "" : logicPkg);
} catch (Throwable t) { } catch (Throwable t) {
Log.warning("Error instantiating application."); throw new ServletException("Error instantiating Application: " + t, t);
Log.logStackTrace(t);
} }
// now let velocity initialize itself try {
super.initVelocity(config); Velocity.init(loadConfiguration(config));
} catch (Exception e) {
throw new ServletException("Error initializing Velocity: " + e, e);
}
_defaultContentType = RuntimeSingleton.getString(CONTENT_TYPE, DEFAULT_CONTENT_TYPE);
// determine the character set we'll use
_charset = config.getInitParameter(CHARSET_KEY);
if (_charset == null) {
_charset = "UTF-8";
}
} }
/** /**
* We load our velocity properties from the classpath rather than from * Handles HTTP <code>GET</code> requests by calling {@link #doRequest()}.
* a file. */
public void doGet (HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
doRequest(request, response);
}
/**
* Handles HTTP <code>POST</code> requests by calling {@link #doRequest()}.
*/
public void doPost (HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
doRequest(request, response);
}
/**
* Clean up after ourselves and our application.
*/
public void destroy ()
{
super.destroy();
// shutdown our application
_app.shutdown();
}
/**
* We load our velocity properties from the classpath rather than from a file.
*/ */
protected Properties loadConfiguration (ServletConfig config) protected Properties loadConfiguration (ServletConfig config)
throws IOException throws IOException
{ {
String propsPath = config.getInitParameter(INIT_PROPS_KEY); String propsPath = config.getInitParameter(INIT_PROPS_KEY);
if (propsPath == null) { if (propsPath == null) {
throw new IOException(INIT_PROPS_KEY + " must point to " + throw new IOException(INIT_PROPS_KEY + " must point to the velocity properties file " +
"the velocity properties file in " + "in the servlet configuration.");
"the servlet configuration.");
} }
// config util loads properties files from the classpath // config util loads properties files from the classpath
@@ -230,16 +239,15 @@ public class DispatcherServlet extends VelocityServlet
if (props.getProperty("file.resource.loader.path") == null) { if (props.getProperty("file.resource.loader.path") == null) {
SiteResourceLoader siteLoader = _app.getSiteResourceLoader(); SiteResourceLoader siteLoader = _app.getSiteResourceLoader();
if (siteLoader != null) { if (siteLoader != null) {
Log.info("Velocity loading templates from site loader."); log.info("Velocity loading templates from site loader.");
props.setProperty(RuntimeSingleton.RESOURCE_MANAGER_CLASS, props.setProperty(RuntimeSingleton.RESOURCE_MANAGER_CLASS,
SiteResourceManager.class.getName()); SiteResourceManager.class.getName());
_usingSiteLoading = true; _usingSiteLoading = true;
} else { } else {
// otherwise use a servlet context resource loader // otherwise use a servlet context resource loader
Log.info("Velocity loading templates from servlet context."); log.info("Velocity loading templates from servlet context.");
props.setProperty( props.setProperty(RuntimeSingleton.RESOURCE_MANAGER_CLASS,
RuntimeSingleton.RESOURCE_MANAGER_CLASS, ServletContextResourceManager.class.getName());
ServletContextResourceManager.class.getName());
} }
} }
@@ -247,21 +255,18 @@ public class DispatcherServlet extends VelocityServlet
props.setProperty("userdirective", ImportDirective.class.getName()); props.setProperty("userdirective", ImportDirective.class.getName());
// configure the servlet context logger // configure the servlet context logger
props.setProperty(RuntimeSingleton.RUNTIME_LOG_LOGSYSTEM_CLASS, props.put(RuntimeSingleton.RUNTIME_LOG_LOGSYSTEM, new ServletContextLogger());
ServletContextLogger.class.getName());
// now return our augmented properties // now return our augmented properties
return props; return props;
} }
/** /**
* Loads up the template appropriate for this request, locates and * Loads up the template appropriate for this request, locates and invokes any associated logic
* invokes any associated logic class and finally returns the prepared * class and finally returns the prepared template which will be merged with the prepared
* template which will be merged with the prepared context. * context.
*/ */
public Template handleRequest (HttpServletRequest req, public Template handleRequest (HttpServletRequest req, HttpServletResponse rsp, Context ctx)
HttpServletResponse rsp,
Context ctx)
throws Exception throws Exception
{ {
InvocationContext ictx = (InvocationContext)ctx; InvocationContext ictx = (InvocationContext)ctx;
@@ -416,9 +421,8 @@ public class DispatcherServlet extends VelocityServlet
public Object methodException (Class clazz, String method, Exception e) public Object methodException (Class clazz, String method, Exception e)
throws Exception throws Exception
{ {
Log.warning("Exception [class=" + clazz.getName() + log.log(Level.WARNING, "Exception [class=" + clazz.getName() +
", method=" + method + "]."); ", method=" + method + "].", e);
Log.logStackTrace(e);
return ""; return "";
} }
@@ -435,19 +439,67 @@ public class DispatcherServlet extends VelocityServlet
} }
/** /**
* We override this to create a context of our own devising. * Handles all requests (by default).
*
* @param request HttpServletRequest object containing client request.
* @param response HttpServletResponse object for the response.
*/ */
protected Context createContext (HttpServletRequest req, protected void doRequest (HttpServletRequest request, HttpServletResponse response)
HttpServletResponse rsp) throws ServletException, IOException
{ {
return new InvocationContext(req, rsp); Context context = null;
try {
context = new InvocationContext(request, response);
setContentType(request, response);
Template template = handleRequest(request, response, context);
if (template != null) {
mergeTemplate(template, context, response);
}
} catch (Exception e) {
log.log(Level.WARNING, "doRequest failed [uri=" + request.getRequestURI() + "].", e);
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
}
} }
/** /**
* This method is called to select the appropriate template for this * Sets the content type of the response, defaulting to {@link #defaultContentType} if not
* request. The default implementation simply loads the template using * overriden. Delegates to {@link #chooseCharacterEncoding(HttpServletRequest)} to select the
* Velocity's default template loading services based on the URI * appropriate character encoding.
* provided in the request. */
protected void setContentType (HttpServletRequest request, HttpServletResponse response)
{
String contentType = _defaultContentType;
int index = contentType.lastIndexOf(';') + 1;
if (index <= 0 || (index < contentType.length() &&
contentType.indexOf("charset", index) == -1)) {
// append the character encoding which we'd like to use
String encoding = chooseCharacterEncoding(request);
if (!DEFAULT_OUTPUT_ENCODING.equalsIgnoreCase(encoding)) {
contentType += "; charset=" + encoding;
}
}
response.setContentType(contentType);
}
/**
* Chooses the output character encoding to be used as the value for the "charset=" portion of
* the HTTP Content-Type header (and thus returned by
* <code>response.getCharacterEncoding()</code>). Called by {@link #setContentType} if an
* encoding isn't already specified by Content-Type. By default, chooses the value of
* RuntimeSingleton's <code>output.encoding</code> property.
*/
protected String chooseCharacterEncoding (HttpServletRequest request)
{
return RuntimeSingleton.getString(
RuntimeConstants.OUTPUT_ENCODING, DEFAULT_OUTPUT_ENCODING);
}
/**
* This method is called to select the appropriate template for this request. The default
* implementation simply loads the template using Velocity's default template loading services
* based on the URI provided in the request.
* *
* @param ctx The context of this request. * @param ctx The context of this request.
* *
@@ -458,20 +510,62 @@ public class DispatcherServlet extends VelocityServlet
{ {
String path = ctx.getRequest().getServletPath(); String path = ctx.getRequest().getServletPath();
if (_usingSiteLoading) { if (_usingSiteLoading) {
// if we're using site resource loading, we need to prefix the path // if we're using site resource loading, we need to prefix the path with the site
// with the site identifier // identifier
path = siteId + ":" + path; path = siteId + ":" + path;
} }
// Log.info("Loading template [path=" + path + "]."); // log.info("Loading template [path=" + path + "].");
return RuntimeSingleton.getTemplate(path); return RuntimeSingleton.getTemplate(path);
} }
/** /**
* This method is called to select the appropriate logic for this * Merges the template with the context.
* request URI.
* *
* @return The logic to be used in generating the response or null if * @param template template object returned by the {@link #handleRequest} method.
* no logic could be matched. * @param context context created by the {@link #createContext} method.
* @param response servlet reponse (use this to get the output stream or writer).
*/
protected void mergeTemplate (Template template, Context context, HttpServletResponse response)
throws ResourceNotFoundException, ParseErrorException, MethodInvocationException,
IOException, UnsupportedEncodingException, Exception
{
ServletOutputStream output = response.getOutputStream();
// ASSUMPTION: response.setContentType() has been called.
String encoding = response.getCharacterEncoding();
VelocityWriter vw = null;
try {
vw = (VelocityWriter)_writerPool.get();
if (vw == null) {
vw = new VelocityWriter(new OutputStreamWriter(output, encoding), 4 * 1024, true);
} else {
vw.recycle(new OutputStreamWriter(output, encoding));
}
template.merge(context, vw);
} finally {
if (vw != null) {
try {
// flush and put back into the pool don't close to allow us to play nicely with
// others.
vw.flush();
} catch (IOException e) {
// do nothing
}
// Clear the VelocityWriter's reference to its internal OutputStreamWriter to allow
// the latter to be GC'd while vw is pooled.
vw.recycle(null);
_writerPool.put(vw);
}
}
}
/**
* This method is called to select the appropriate logic for this request URI.
*
* @return The logic to be used in generating the response or null if no logic could be
* matched.
*/ */
protected Logic resolveLogic (String path) protected Logic resolveLogic (String path)
{ {
@@ -488,14 +582,12 @@ public class DispatcherServlet extends VelocityServlet
// nothing interesting to report // nothing interesting to report
} catch (Throwable t) { } catch (Throwable t) {
Log.warning("Unable to instantiate logic for application " + log.log(Level.WARNING, "Unable to instantiate logic for application [path=" + path +
"[path=" + path + ", lclass=" + lclass + "]."); ", lclass=" + lclass + "].", t);
Log.logStackTrace(t);
} }
// if something failed, use a dummy in it's place so that we // if something failed, use a dummy in it's place so that we don't sit around all day
// don't sit around all day freaking out about our inability // freaking out about our inability to instantiate the proper logic class
// to instantiate the proper logic class
if (logic == null) { if (logic == null) {
logic = new DummyLogic(); logic = new DummyLogic();
} }
@@ -519,13 +611,20 @@ public class DispatcherServlet extends VelocityServlet
/** Set to true if we're using the {@link SiteResourceLoader}. */ /** Set to true if we're using the {@link SiteResourceLoader}. */
protected boolean _usingSiteLoading; protected boolean _usingSiteLoading;
/** Our default content type. */
protected String _defaultContentType;
/** A pool of VelocityWriter instances. */
protected static SimplePool _writerPool = new SimplePool(40);
/** Describes the location of our properties. */
protected static final String INIT_PROPS_KEY = "org.apache.velocity.properties";
/** This is the key used in the context for error messages. */ /** This is the key used in the context for error messages. */
protected static final String ERROR_KEY = "error"; protected static final String ERROR_KEY = "error";
/** /** This is the key used to store a reference back to the dispatcher servlet in our invocation
* This is the key used to store a reference back to the dispatcher * context. */
* servlet in our invocation context.
*/
protected static final String APPLICATION_KEY = "%_app_%"; protected static final String APPLICATION_KEY = "%_app_%";
/** The key used to store the translation tool in the context. */ /** The key used to store the translation tool in the context. */
@@ -551,4 +650,10 @@ public class DispatcherServlet extends VelocityServlet
/** The servlet parameter key specifying the default character set. */ /** The servlet parameter key specifying the default character set. */
protected static final String CHARSET_KEY = "charset"; protected static final String CHARSET_KEY = "charset";
/** The default content type for responses. */
protected static final String DEFAULT_CONTENT_TYPE = "text/html";
/** The default encoding for the output stream. */
protected static final String DEFAULT_OUTPUT_ENCODING = "ISO-8859-1";
} }
@@ -40,10 +40,9 @@ import com.samskivert.servlet.SiteIdentifier;
import com.samskivert.util.StringUtil; import com.samskivert.util.StringUtil;
/** /**
* Pluggable directive that handles the #import() statement in VTL. Import is * Pluggable directive that handles the #import() statement in VTL. Import is like #parse() except
* like #parse() except that it creates a compound key * that it creates a compound key (<code>siteId:template_path</code>) based on information from the
* (<code>siteId:template_path</code>) based on information from the current * current request when fetching the imported template.
* request when fetching the imported template.
*/ */
public class ImportDirective extends Directive public class ImportDirective extends Directive
{ {
@@ -73,14 +72,14 @@ public class ImportDirective extends Directive
{ {
// make sure an argument was supplied to the directive // make sure an argument was supplied to the directive
if (node.getChild(0) == null) { if (node.getChild(0) == null) {
rsvc.error("#import() error : null argument"); rsvc.getLog().error("#import() error : null argument");
return false; return false;
} }
// make sure that argument has a value // make sure that argument has a value
Object value = node.getChild(0).value(context); Object value = node.getChild(0).value(context);
if (value == null) { if (value == null) {
rsvc.error("#import() error : null argument"); rsvc.getLog().error("#import() error : null argument");
return false; return false;
} }
@@ -92,9 +91,8 @@ public class ImportDirective extends Directive
int maxlen = rsvc.getInt( int maxlen = rsvc.getInt(
RuntimeConstants.PARSE_DIRECTIVE_MAXDEPTH, 20); RuntimeConstants.PARSE_DIRECTIVE_MAXDEPTH, 20);
if (templateStack.length >= maxlen) { if (templateStack.length >= maxlen) {
rsvc.error("Max recursion depth reached (" + maxlen + "). " + rsvc.getLog().error("Max recursion depth reached (" + maxlen + "). " +
"File stack: " + "File stack: " + StringUtil.toString(templateStack) + ".");
StringUtil.toString(templateStack) + ".");
return false; return false;
} }
@@ -120,7 +118,7 @@ public class ImportDirective extends Directive
try { try {
siteId = ((Integer)siteIdVal).intValue(); siteId = ((Integer)siteIdVal).intValue();
} catch (Exception e) { } catch (Exception e) {
rsvc.error("#import() error: No siteId information in context."); rsvc.getLog().error("#import() error: No siteId information in context.");
} }
path = siteId + ":" + path; path = siteId + ":" + path;
} }
@@ -131,22 +129,19 @@ public class ImportDirective extends Directive
t = rsvc.getTemplate(path, encoding); t = rsvc.getTemplate(path, encoding);
} catch (ResourceNotFoundException rnfe) { } catch (ResourceNotFoundException rnfe) {
rsvc.error("#import(): cannot find template '" + path + rsvc.getLog().error("#import(): cannot find template '" + path +
"', called from template " + "', called from template " + context.getCurrentTemplateName() +
context.getCurrentTemplateName() + " at (" + getLine() + ", " + getColumn() + ")");
" at (" + getLine() + ", " + getColumn() + ")");
throw rnfe; throw rnfe;
} catch (ParseErrorException pee) { } catch (ParseErrorException pee) {
rsvc.error("#import(): syntax error in #import()-ed template '" + rsvc.getLog().error("#import(): syntax error in #import()-ed template '" + path +
path + "', called from template " + "', called from template " + context.getCurrentTemplateName() +
context.getCurrentTemplateName() + " at (" + getLine() + ", " + getColumn() + ")");
" at (" + getLine() + ", " + getColumn() + ")");
throw pee; throw pee;
} catch (Exception e) { } catch (Exception e) {
rsvc.error("#import(): Error [path=" + path + rsvc.getLog().error("#import(): Error [path=" + path + ", error=" + e + "].");
", error=" + e + "].");
return false; return false;
} }
@@ -156,7 +151,7 @@ public class ImportDirective extends Directive
((SimpleNode)t.getData()).render(context, writer); ((SimpleNode)t.getData()).render(context, writer);
} catch (Throwable th) { } catch (Throwable th) {
rsvc.error("Exception rendering #import(" + path + "): " + th); rsvc.getLog().error("Exception rendering #import(" + path + "): " + th);
// we want to pass method invocation exceptions through // we want to pass method invocation exceptions through
if (th instanceof MethodInvocationException) { if (th instanceof MethodInvocationException) {
throw (MethodInvocationException)th; throw (MethodInvocationException)th;
@@ -23,12 +23,12 @@ package com.samskivert.velocity;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
import org.apache.velocity.runtime.RuntimeServices; import org.apache.velocity.runtime.RuntimeServices;
import org.apache.velocity.runtime.log.LogSystem; import org.apache.velocity.runtime.log.LogChute;
/** /**
* Routes Velocity log messages to the servlet context. * Routes Velocity log messages to the servlet context.
*/ */
public class ServletContextLogger implements LogSystem public class ServletContextLogger implements LogChute
{ {
/** /**
* Constructs a servlet context logger that will obtain its servlet * Constructs a servlet context logger that will obtain its servlet
@@ -48,22 +48,21 @@ public class ServletContextLogger implements LogSystem
_sctx = sctx; _sctx = sctx;
} }
// documentation inherited // from interface LogChute
public void init (RuntimeServices rsvc) public void init (RuntimeServices rsvc)
{ {
// if we weren't constructed with a servlet context, try to obtain // if we weren't constructed with a servlet context, try to obtain
// one via the application context // one via the application context
if (_sctx == null) { if (_sctx == null) {
// first look for the servlet context directly // first look for the servlet context directly
_sctx = (ServletContext) _sctx = (ServletContext)rsvc.getApplicationAttribute("ServletContext");
rsvc.getApplicationAttribute("ServletContext");
} }
// if that didn't work, look for an application // if that didn't work, look for an application
if (_sctx == null) { if (_sctx == null) {
// first look for an application // first look for an application
Application app = (Application)rsvc.getApplicationAttribute( Application app = (Application)
Application.VELOCITY_ATTR_KEY); rsvc.getApplicationAttribute(Application.VELOCITY_ATTR_KEY);
if (app != null) { if (app != null) {
_sctx = app.getServletContext(); _sctx = app.getServletContext();
} }
@@ -71,22 +70,35 @@ public class ServletContextLogger implements LogSystem
// if we still don't have one, complain // if we still don't have one, complain
if (_sctx == null) { if (_sctx == null) {
rsvc.warn("ServletContextLogger: servlet context was not " + rsvc.getLog().warn("ServletContextLogger: servlet context was not supplied. A user " +
"supplied. A user of the servlet context logger must " + "of the servlet context logger must call " +
"call Velocity.setApplicationAttribute(" + "Velocity.setApplicationAttribute(\"ServletContext\", " +
"\"ServletContext\", getServletContext())."); "getServletContext()).");
} }
} }
// documentation inherited // from interface LogChute
public void logVelocityMessage (int level, String message) public void log (int level, String message)
{ {
// log only warning or above for now if (isLevelEnabled(level)) {
if (level >= LogSystem.WARN_ID) {
_sctx.log(message); _sctx.log(message);
} }
} }
// from interface LogChute
public void log (int level, String message, Throwable t)
{
if (isLevelEnabled(level)) {
_sctx.log(message, t);
}
}
// from interface LogChute
public boolean isLevelEnabled (int level)
{
return (level >= WARN_ID);
}
/** A reference to our servlet context. */ /** A reference to our servlet context. */
protected ServletContext _sctx; protected ServletContext _sctx;
} }
@@ -29,8 +29,7 @@ import org.apache.velocity.runtime.resource.Resource;
import org.apache.velocity.runtime.resource.loader.ResourceLoader; import org.apache.velocity.runtime.resource.loader.ResourceLoader;
/** /**
* A Velocity resource loader that loads resources from the servlet * A Velocity resource loader that loads resources from the servlet context.
* context.
* *
* @see ServletContext#getResource * @see ServletContext#getResource
* @see ServletContext#getResourceAsStream * @see ServletContext#getResourceAsStream
@@ -38,17 +37,16 @@ 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 * When used with the default Velocity resource manager, we are constructed with our
* constructed with our zero-argument constructor and later * zero-argument constructor and later initialized via {@link #init}.
* initialized via {@link #init}.
*/ */
public ServletContextResourceLoader () public ServletContextResourceLoader ()
{ {
} }
/** /**
* When used with the {@link SiteResourceManager} we are constructed * When used with the {@link SiteResourceManager} we are constructed with our servlet context
* with our servlet context reference and not later initialized. * reference and not later initialized.
*/ */
public ServletContextResourceLoader (ServletContext sctx) public ServletContextResourceLoader (ServletContext sctx)
{ {
@@ -60,22 +58,14 @@ public class ServletContextResourceLoader extends ResourceLoader
*/ */
public void init (ExtendedProperties config) public void init (ExtendedProperties config)
{ {
// there seems to be a tradition of logging this stuff; surely we // the web framework was kind enough to slip this into the runtime when it started up
// don't want to buck tradition, do we?
rsvc.info("ServletContextResourceLoader: initialization starting.");
// the web framework was kind enough to slip this into the runtime
// instance when it started up
_sctx = (ServletContext)rsvc.getApplicationAttribute("ServletContext"); _sctx = (ServletContext)rsvc.getApplicationAttribute("ServletContext");
if (_sctx == null) { if (_sctx == null) {
rsvc.warn("ServletContextResourceLoader: servlet context " + rsvc.getLog().warn("ServletContextResourceLoader: servlet context was not supplied " +
"was not supplied as application context. A " + "as application context. A user of the servlet context resource " +
"user of the servlet context resource loader " + "loader must call Velocity.setApplicationAttribute(" +
"must call Velocity.setApplicationAttribute(" + "\"ServletContext\", getServletContext()).");
"\"ServletContext\", getServletContext()).");
} }
rsvc.info("ServletContextResourceLoader : initialization complete.");
} }
/** /**
@@ -31,8 +31,7 @@ import org.apache.velocity.runtime.resource.ResourceManagerImpl;
import org.apache.velocity.runtime.resource.loader.ResourceLoader; import org.apache.velocity.runtime.resource.loader.ResourceLoader;
/** /**
* A resource manager implementation for Velocity that loads resources * A resource manager implementation for Velocity that loads resources from the servlet context.
* from the servlet context.
*/ */
public class ServletContextResourceManager extends ResourceManagerImpl public class ServletContextResourceManager extends ResourceManagerImpl
{ {
@@ -40,37 +39,31 @@ public class ServletContextResourceManager extends ResourceManagerImpl
throws Exception throws Exception
{ {
super.initialize(rsvc); super.initialize(rsvc);
rsvc.info("SCRM initializing."); rsvc.getLog().info("SCRM initializing.");
// the web framework was kind enough to slip this into the runtime // the web framework was kind enough to slip this into the runtime when it started up
// instance when it started up Application app = (Application)rsvc.getApplicationAttribute(Application.VELOCITY_ATTR_KEY);
Application app = (Application)rsvc.getApplicationAttribute(
Application.VELOCITY_ATTR_KEY);
if (app == null) { if (app == null) {
rsvc.warn("SCRM: No application was initialized. A user of the " + rsvc.getLog().warn("SCRM: No application was initialized. A user of the " +
"servlet context resource manager must ensure that " + "servlet context resource manager must ensure that " +
"an application is instantiated and initialized."); "an application is instantiated and initialized.");
} }
// create our resource loader // create our resource loader
_contextLoader = new ServletContextResourceLoader( _contextLoader = new ServletContextResourceLoader(app.getServletContext());
app.getServletContext());
// for now, turn caching on with the expectation that new // for now, turn caching on with the expectation that new resources of any sort will result
// resources of any sort will result in the entire web application // in the entire web application being reloaded and clearing out the cache
// being reloaded and clearing out the cache
_contextLoader.setCachingOn(true); _contextLoader.setCachingOn(true);
rsvc.info("SCRM initialization complete."); rsvc.getLog().info("SCRM initialization complete.");
} }
protected Resource loadResource( protected Resource loadResource(String resourceName, int resourceType, String encoding)
String resourceName, int resourceType, String encoding)
throws ResourceNotFoundException, ParseErrorException, Exception throws ResourceNotFoundException, ParseErrorException, Exception
{ {
// create a blank new resource // create a blank new resource
Resource resource = Resource resource = ResourceFactory.getResource(resourceName, resourceType);
ResourceFactory.getResource(resourceName, resourceType);
resource.setRuntimeServices(rsvc); resource.setRuntimeServices(rsvc);
resource.setName(resourceName); resource.setName(resourceName);
resource.setEncoding(encoding); resource.setEncoding(encoding);
@@ -78,8 +71,7 @@ public class ServletContextResourceManager extends ResourceManagerImpl
resource.setResourceLoader(_contextLoader); resource.setResourceLoader(_contextLoader);
resource.process(); resource.process();
resource.setLastModified(_contextLoader.getLastModified(resource)); resource.setLastModified(_contextLoader.getLastModified(resource));
resource.setModificationCheckInterval( resource.setModificationCheckInterval(_contextLoader.getModificationCheckInterval());
_contextLoader.getModificationCheckInterval());
resource.touch(); resource.touch();
return resource; return resource;
@@ -30,13 +30,15 @@ import org.apache.velocity.runtime.resource.ResourceFactory;
import org.apache.velocity.runtime.resource.ResourceManagerImpl; import org.apache.velocity.runtime.resource.ResourceManagerImpl;
import org.apache.velocity.runtime.resource.loader.ResourceLoader; import org.apache.velocity.runtime.resource.loader.ResourceLoader;
import com.samskivert.Log;
import com.samskivert.servlet.SiteIdentifier; import com.samskivert.servlet.SiteIdentifier;
import com.samskivert.servlet.SiteResourceLoader; import com.samskivert.servlet.SiteResourceLoader;
/** /**
* A resource manager implementation for Velocity that first loads site * A resource manager implementation for Velocity that first loads site specific resources (via the
* specific resources (via the {@link SiteJarResourceLoader}), but falls back * {@link SiteJarResourceLoader}), but falls back to default resources if no site-specific resource
* to default resources if no site-specific resource loader is available. * loader is available.
*/ */
public class SiteResourceManager extends ResourceManagerImpl public class SiteResourceManager extends ResourceManagerImpl
{ {
@@ -44,16 +46,15 @@ public class SiteResourceManager extends ResourceManagerImpl
throws Exception throws Exception
{ {
super.initialize(rsvc); super.initialize(rsvc);
rsvc.info("SiteResourceManager initializing."); Log.log.info("SiteResourceManager initializing.");
// the web framework was kind enough to slip this into the runtime // the web framework was kind enough to slip this into the runtime when it started up
// instance when it started up
Application app = (Application)rsvc.getApplicationAttribute( Application app = (Application)rsvc.getApplicationAttribute(
Application.VELOCITY_ATTR_KEY); Application.VELOCITY_ATTR_KEY);
if (app == null) { if (app == null) {
rsvc.warn("SiteResourceManager: No application was initialized. " + Log.log.warning("SiteResourceManager: No application was initialized. " +
"A user of the site resource manager must ensure that " + "A user of the site resource manager must ensure that " +
"an application is instantiated and initialized."); "an application is instantiated and initialized.");
} }
// get handles on the good stuff // get handles on the good stuff
@@ -63,33 +64,30 @@ public class SiteResourceManager extends ResourceManagerImpl
// make sure the app has a site resource loader // make sure the app has a site resource loader
SiteResourceLoader loader = app.getSiteResourceLoader(); SiteResourceLoader loader = app.getSiteResourceLoader();
if (loader == null) { if (loader == null) {
rsvc.warn("SiteResourceManager: application must be " + Log.log.warning("SiteResourceManager: application must be " +
"configured with a site-specific resource loader " + "configured with a site-specific resource loader " +
"that we can use to fetch site-specific resources."); "that we can use to fetch site-specific resources.");
} }
// create our resource loaders // create our resource loaders
_siteLoader = new SiteJarResourceLoader(loader); _siteLoader = new SiteJarResourceLoader(loader);
_contextLoader = new ServletContextResourceLoader(_sctx); _contextLoader = new ServletContextResourceLoader(_sctx);
// for now, turn caching on with the expectation that new // for now, turn caching on with the expectation that new resources of any sort will result
// resources of any sort will result in the entire web application // in the entire web application being reloaded and clearing out the cache
// being reloaded and clearing out the cache
_siteLoader.setCachingOn(true); _siteLoader.setCachingOn(true);
_contextLoader.setCachingOn(true); _contextLoader.setCachingOn(true);
rsvc.info("SiteResourceManager initialization complete."); Log.log.info("SiteResourceManager initialization complete.");
} }
protected Resource loadResource( protected Resource loadResource(String resourceName, int resourceType, String encoding)
String resourceName, int resourceType, String encoding)
throws ResourceNotFoundException, ParseErrorException, Exception throws ResourceNotFoundException, ParseErrorException, Exception
{ {
SiteKey skey = new SiteKey(resourceName); SiteKey skey = new SiteKey(resourceName);
// create a blank new resource // create a blank new resource
Resource resource = Resource resource = ResourceFactory.getResource(skey.path, resourceType);
ResourceFactory.getResource(skey.path, resourceType);
resource.setRuntimeServices(rsvc); resource.setRuntimeServices(rsvc);
resource.setEncoding(encoding); resource.setEncoding(encoding);
@@ -101,8 +99,7 @@ public class SiteResourceManager extends ResourceManagerImpl
// nothing to worry about here // nothing to worry about here
} }
// then try the servlet context loader if we didn't find a // then try the servlet context loader if we didn't find a site-specific resource
// site-specific resource
if (resource.getData() == null) { if (resource.getData() == null) {
resource.setName(skey.path); resource.setName(skey.path);
resolveResource(resource, _contextLoader); resolveResource(resource, _contextLoader);
@@ -117,8 +114,7 @@ public class SiteResourceManager extends ResourceManagerImpl
resource.setResourceLoader(loader); resource.setResourceLoader(loader);
resource.process(); resource.process();
resource.setLastModified(loader.getLastModified(resource)); resource.setLastModified(loader.getLastModified(resource));
resource.setModificationCheckInterval( resource.setModificationCheckInterval(loader.getModificationCheckInterval());
loader.getModificationCheckInterval());
resource.touch(); resource.touch();
} }