Added the code that actually maps exceptions to error messages.
git-svn-id: https://samskivert.googlecode.com/svn/trunk@45 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
//
|
||||
// $Id: ExceptionMap.java,v 1.1 2001/02/13 20:00:28 mdb Exp $
|
||||
|
||||
package com.samskivert.webmacro;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
/**
|
||||
* The exception map is used to load the exception to error message
|
||||
* mapping information and to look up the appropriate response for a given
|
||||
* exception instance.
|
||||
*
|
||||
* @see FriendlyServlet
|
||||
*/
|
||||
public class ExceptionMap
|
||||
{
|
||||
/**
|
||||
* Searches for the <code>exceptionmap.properties</code> file in the
|
||||
* classpath and loads it. If the file could not be found, an error is
|
||||
* reported and a default set of mappings is used.
|
||||
*/
|
||||
public static synchronized void init ()
|
||||
{
|
||||
// only initialize ourselves once
|
||||
if (_keys != null) {
|
||||
return;
|
||||
} else {
|
||||
_keys = new ArrayList();
|
||||
_values = new ArrayList();
|
||||
}
|
||||
|
||||
// first try loading the properties file without a leading slash
|
||||
InputStream config = getStream(PROPS_NAME);
|
||||
if (config == null) {
|
||||
// some JVMs require the leading slash, some don't
|
||||
config = getStream("/" + PROPS_NAME);
|
||||
}
|
||||
|
||||
// still no props, then we complain
|
||||
if (config == null) {
|
||||
Log.log.warning("Unable to load " + PROPS_NAME +
|
||||
" from CLASSPATH.");
|
||||
|
||||
} else {
|
||||
// otherwise process ye old config file.
|
||||
try {
|
||||
// we'll do some serious jiggery pokery to leverage the
|
||||
// parsing implementation provided by
|
||||
// java.util.Properties. god bless method overloading
|
||||
Properties loader = new Properties() {
|
||||
public Object put (Object key, Object value)
|
||||
{
|
||||
_keys.add(key);
|
||||
_values.add(value);
|
||||
return key;
|
||||
}
|
||||
};
|
||||
loader.load(config);
|
||||
|
||||
// now cruise through and resolve the exceptions named as
|
||||
// keys and throw out any that don't appear to exist
|
||||
for (int i = 0; i < _keys.size(); i++) {
|
||||
String exclass = (String)_keys.get(i);
|
||||
try {
|
||||
Class cl = Class.forName(exclass);
|
||||
// replace the string with the class object
|
||||
_keys.set(i, cl);
|
||||
|
||||
} catch (Throwable t) {
|
||||
Log.log.warning("Unable to resolve exception " +
|
||||
"class. [class=" + exclass +
|
||||
", error=" + t + "].");
|
||||
_keys.remove(i);
|
||||
_values.remove(i);
|
||||
i--; // back on up a notch
|
||||
}
|
||||
}
|
||||
|
||||
} catch (IOException ioe) {
|
||||
Log.log.warning("Error reading exception mapping file: " +
|
||||
ioe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up the supplied exception in the map and returns the most
|
||||
* specific error message available for exceptions of that class.
|
||||
*
|
||||
* @param ex The exception to resolve into an error message.
|
||||
*
|
||||
* @return The error message to which this exception maps (properly
|
||||
* populated with the message associated with this exception
|
||||
* instance).
|
||||
*/
|
||||
public static String getMessage (Throwable ex)
|
||||
{
|
||||
String msg = DEFAULT_ERROR_MSG;
|
||||
|
||||
for (int i = 0; i < _keys.size(); i++) {
|
||||
Class cl = (Class)_keys.get(i);
|
||||
if (cl.isInstance(ex)) {
|
||||
msg = (String)_values.get(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return StringUtil.replace(msg, MESSAGE_MARKER, ex.getMessage());
|
||||
}
|
||||
|
||||
protected static InputStream getStream (String path)
|
||||
{
|
||||
// first try using the classloader that loaded us
|
||||
Class c = ExceptionMap.class;
|
||||
InputStream in = c.getResourceAsStream(path);
|
||||
if (null == in) {
|
||||
// if that didn't work, try the system classloader
|
||||
c = Class.class;
|
||||
in = c.getResourceAsStream(path);
|
||||
}
|
||||
return in;
|
||||
}
|
||||
|
||||
public static void main (String[] args)
|
||||
{
|
||||
ExceptionMap map = new ExceptionMap();
|
||||
System.out.println(map.getMessage(new Exception("Test error")));
|
||||
}
|
||||
|
||||
protected static List _keys;
|
||||
protected static List _values;
|
||||
|
||||
// initialize ourselves
|
||||
static { init(); }
|
||||
|
||||
protected static final String PROPS_NAME = "exceptionmap.properties";
|
||||
protected static final String DEFAULT_ERROR_MSG = "Error: {m}.";
|
||||
protected static final String MESSAGE_MARKER = "{m}";
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// $Id: FriendlyServlet.java,v 1.1 2001/02/13 18:49:41 mdb Exp $
|
||||
// $Id: FriendlyServlet.java,v 1.2 2001/02/13 20:00:28 mdb Exp $
|
||||
|
||||
package com.samskivert.webmacro;
|
||||
|
||||
@@ -25,23 +25,41 @@ import org.webmacro.servlet.*;
|
||||
* webmacro procedure.
|
||||
*
|
||||
* <p> The process of mapping exceptions to friendly error messages is
|
||||
* done through a properties file loaded via the classpath. The properties
|
||||
* file should be named 'exceptionmap.properties' and placed in a
|
||||
* directory contained in the classpath of the JVM in which the servlet is
|
||||
* executed. The file should contain mappings from exception classes to
|
||||
* friendly error messages. For example:
|
||||
* done through a configuration file loaded via the classpath. The file
|
||||
* should be named <code>exceptionmap.properties</code> and placed in the
|
||||
* classpath of the JVM in which the servlet is executed. The file should
|
||||
* contain colon-separated mappings from exception classes to friendly
|
||||
* error messages. For example:
|
||||
*
|
||||
* <pre>
|
||||
* com.samskivert.webmacro.FriendlyException = An error occurred while \
|
||||
* # Exception mappings (lines beginning with # are ignored)
|
||||
* com.samskivert.webmacro.FriendlyException: An error occurred while \
|
||||
* processing your request: {m}
|
||||
* java.sql.SQLException = The database is currently unavailable. Please \
|
||||
*
|
||||
* # lines ending with \ are continued on the next line
|
||||
* java.sql.SQLException: The database is currently unavailable. Please \
|
||||
* try your request again later.
|
||||
* java.lang.Exception = An unexpected error occurred while processing \
|
||||
*
|
||||
* java.lang.Exception: An unexpected error occurred while processing \
|
||||
* your request. Please try again later.
|
||||
* </pre>
|
||||
*
|
||||
* The message associated with the exception will be substituted into the
|
||||
* error string in place of <code>{m}</code>.
|
||||
* error string in place of <code>{m}</code>. The exceptions should be
|
||||
* listed in order of most specific to least specific, for the first
|
||||
* mapping for which the exception to report is an instance of the
|
||||
* exception in the left hand side will be used.
|
||||
*
|
||||
* <em>Note:</em> These exception mappings are used for all servlets
|
||||
* (perhaps some day only for servlets associated with a particular
|
||||
* application identifier). Regardless, this error handling mechanism
|
||||
* should not be used for servlet specific errors. For example, an SQL
|
||||
* exception reporting a duplicate key should probably be caught and
|
||||
* reported specifically by the servlet (it can still leverage the pattern
|
||||
* of inserting the error message into the context as
|
||||
* <code>"error"</code>) rather than relying on the default SQL exception
|
||||
* error message which is not likely to be meaningful for such a
|
||||
* situation.
|
||||
*/
|
||||
public abstract class FriendlyServlet extends WMServlet
|
||||
{
|
||||
@@ -59,6 +77,7 @@ public abstract class FriendlyServlet extends WMServlet
|
||||
try {
|
||||
populateContext(ctx, tmpl);
|
||||
} catch (Exception e) {
|
||||
ctx.put(ERROR_KEY, ExceptionMap.getMessage(e));
|
||||
}
|
||||
|
||||
return tmpl;
|
||||
@@ -87,4 +106,7 @@ public abstract class FriendlyServlet extends WMServlet
|
||||
*/
|
||||
protected abstract void populateContext (WebContext ctx, Template tmpl)
|
||||
throws Exception;
|
||||
|
||||
/** This is the key used in the context for error messages. */
|
||||
protected static final String ERROR_KEY = "error";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// $Id: Log.java,v 1.1 2001/02/13 20:00:28 mdb Exp $
|
||||
|
||||
package com.samskivert.webmacro;
|
||||
|
||||
/**
|
||||
* A placeholder class that contains a reference to the log object used by
|
||||
* the webmacro package.
|
||||
*/
|
||||
public class Log
|
||||
{
|
||||
public static com.samskivert.util.Log log =
|
||||
new com.samskivert.util.Log("com.samskivert.webmacro");
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
#
|
||||
# $Id: Makefile,v 1.1 2001/02/13 18:49:41 mdb Exp $
|
||||
# $Id: Makefile,v 1.2 2001/02/13 20:00:28 mdb Exp $
|
||||
|
||||
ROOT = ../../..
|
||||
|
||||
SRCS = \
|
||||
ExceptionMap.java \
|
||||
FriendlyException.java \
|
||||
FriendlyServlet.java \
|
||||
Log.java \
|
||||
|
||||
include $(ROOT)/build/Makefile.java
|
||||
|
||||
Reference in New Issue
Block a user