Canned the long unsupported webmacro stuff.

git-svn-id: https://samskivert.googlecode.com/svn/trunk@1399 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
mdb
2004-02-25 13:11:47 +00:00
parent c176b45bab
commit 37c4d465d2
11 changed files with 0 additions and 1353 deletions
-20
View File
@@ -83,14 +83,6 @@
<available property="jakarta.velocity.present"
classname="org.apache.velocity.Template" classpathref="classpath"/>
<echo message="Velocity: ${jakarta.velocity.present}"/>
<echo message=""/>
<echo message="-----------------------------------"/>
<echo message="WebMacro - http://www.webmacro.org/"/>
<echo message="-----------------------------------"/>
<available property="webmacro.present"
classname="org.webmacro.Template" classpathref="classpath"/>
<echo message="WebMacro: ${webmacro.present}"/>
</target>
<!-- combines package availability into build controls -->
@@ -153,16 +145,6 @@
</condition>
<echo message="com.samskivert.velocity: ${build.velocity}"/>
<condition property="build.webmacro">
<and>
<isset property="build.servlet"/>
<isset property="build.util"/>
<isset property="servlet2.2.present"/>
<isset property="webmacro.present"/>
</and>
</condition>
<echo message="com.samskivert.webmacro: ${build.webmacro}"/>
<condition property="build.xml">
<and>
<isset property="build.io"/>
@@ -205,7 +187,6 @@
<exclude name="com/samskivert/test/**" unless="build.test"/>
<exclude name="com/samskivert/util/**" unless="build.util"/>
<exclude name="com/samskivert/velocity/**" unless="build.velocity"/>
<exclude name="com/samskivert/webmacro/**" unless="build.webmacro"/>
<exclude name="com/samskivert/xml/**" unless="build.xml"/>
</javac>
</target>
@@ -227,7 +208,6 @@
<exclude name="com/samskivert/test/**" unless="build.test"/>
<exclude name="com/samskivert/util/**" unless="build.util"/>
<exclude name="com/samskivert/velocity/**" unless="build.velocity"/>
<exclude name="com/samskivert/webmacro/**" unless="build.webmacro"/>
<exclude name="com/samskivert/xml/**" unless="build.xml"/>
</packageset>
<bottom>Copyright &#169; 2000-${year} ${copyright.holder}.
@@ -1,189 +0,0 @@
//
// $Id: Application.java,v 1.4 2001/08/11 22:43:29 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.webmacro;
import javax.servlet.ServletContext;
import org.webmacro.servlet.WebContext;
import com.samskivert.servlet.MessageManager;
import com.samskivert.util.StringUtil;
/**
* The servlet API defines the concept of a web application and associates
* certain attributes with it like document root and so on. This
* application class extends that concept by providing a base class that
* represents the web application. The application class is responsible
* for initializing services that will be used by the application's logic
* objects as well as cleaning them up when the application is shut down.
*/
public class Application
{
/**
* This should be overridden by the application implementation to
* perform any necessary initialization.
*/
public void init (ServletContext context)
{
}
/**
* This should be overridden by the application implementation to
* perform any necessary cleanup.
*/
public void shutdown ()
{
}
/**
* Returns the message manager in effect for this application, if one
* is in effect.
*/
public MessageManager getMessageManager ()
{
return _msgmgr;
}
/**
* If an application wishes to make use of the translation facilities
* provided by the message manager, it need only provide the path to
* its message resource bundle via this member function. Using a
* message manager allows framework components like the
* <code>MsgTool</code> to make use of the application's message
* bundles.
*/
protected String getMessageBundlePath ()
{
return null;
}
/**
* A convenience function for translating messages.
*/
public final String translate (WebContext ctx, String msg)
{
return _msgmgr.getMessage(ctx.getRequest(), msg);
}
/**
* A convenience function for translating messages.
*/
public final String translate (WebContext ctx, String msg, Object arg)
{
return _msgmgr.getMessage(ctx.getRequest(), msg,
new Object[]{ arg });
}
/**
* A convenience function for translating messages.
*/
public final String translate (WebContext ctx, String msg,
Object arg1, Object arg2)
{
return _msgmgr.getMessage(ctx.getRequest(), msg,
new Object[]{ arg1, arg2 });
}
/**
* A convenience function for translating messages.
*/
public final String translate (WebContext ctx, String msg,
Object arg1, Object arg2, Object arg3)
{
return _msgmgr.getMessage(ctx.getRequest(), msg,
new Object[]{ arg1, arg2, arg3 });
}
/**
* A convenience function for translating messages.
*/
public final String translate (WebContext ctx, String msg,
Object[] args)
{
return _msgmgr.getMessage(ctx.getRequest(), msg, args);
}
/**
* Performs initializations common to all applications. We could put
* this in init() and require application derived classes to call
* super.init() but people would forget to do so and be confused.
*
* <p> The default application implementation takes the base URI and
* base package as defined in the application declaration in the
* servlet configuration and uses those to determine whether or not a
* given URI maps to this application.
*/
public void preInit (String baseURI, String basePkg)
{
// remove any trailing slash
if (baseURI.endsWith("/")) {
_baseURI = baseURI.substring(0, baseURI.length()-1);
} else {
_baseURI = baseURI;
}
// remove any trailing dot
if (basePkg.endsWith(".")) {
_basePkg = basePkg.substring(0, basePkg.length()-1);
} else {
_basePkg = basePkg;
}
// instantiate our message manager if the application wants one
String bpath = getMessageBundlePath();
if (bpath != null) {
_msgmgr = new MessageManager(bpath);
}
}
/**
* Returns true if the supplied URI should be handled by this
* application.
*/
public boolean matches (String uri)
{
return uri.startsWith(_baseURI);
}
/**
* Given a request URI this generates the classname of the logic class
* that should handle the request.
*/
public String generateClass (String uri)
{
// remove the base URI
uri = uri.substring(_baseURI.length());
// convert slashes to dots
uri = StringUtil.replace(uri, "/", ".");
// remove the trailing file extension
uri = uri.substring(0, uri.length() - FILE_EXTENSION.length());
// prepend the base package and we're all set
return _basePkg + uri;
}
protected String _baseURI;
protected String _basePkg;
protected MessageManager _msgmgr;
/**
* This is the default file extension.
*/
protected static final String FILE_EXTENSION = ".wm";
}
@@ -1,37 +0,0 @@
//
// $Id: DataValidationException.java,v 1.2 2001/08/11 22:43:29 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.webmacro;
/**
* A data validation exception is thrown when a value supplied in a form
* element is not valid. The servlet framework will substitute the message
* assosciated with this exception into the context with the key
* <code>"invalid_data"</code>. Templates should be structured so that
* this is reported to the user along with the filled out form field for
* their editing and resubmitting pleasures.
*/
public class DataValidationException extends FriendlyException
{
public DataValidationException (String message)
{
super(message);
}
}
@@ -1,424 +0,0 @@
//
// $Id: DispatcherServlet.java,v 1.13 2002/04/01 01:57:31 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.webmacro;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Properties;
import java.util.StringTokenizer;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import org.webmacro.*;
import org.webmacro.servlet.HandlerException;
import org.webmacro.servlet.WMServlet;
import org.webmacro.servlet.WebContext;
import com.samskivert.Log;
import com.samskivert.servlet.MessageManager;
import com.samskivert.servlet.RedirectException;
import com.samskivert.util.ConfigUtil;
import com.samskivert.util.StringUtil;
/**
* The dispatcher servlet builds upon WebMacro's architecture. It does so
* in the following ways:
*
* <ul>
* <li> It defines the notion of a logic object which populates the
* context with data to be used to satisfy a particular request. The logic
* is not a servlet and is therefore limited in what it can do while
* populating data. Experience dictates that ultimate flexibility leads to
* 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 .wm files to be referenced directly in the URL while
* maintaining the ability to choose a cobranded template based. The URI
* is mapped to a servlet based on some simple mapping rules. This
* provides template designers with a clearer understanding of the
* structure of a web application as well as 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
* task of authoring web applications.
* </ul>
*
* <p><b>URI to servlet mapping</b><br>
* The mapping process allows the webmacro framework to be invoked for all
* requests ending in a particular file extension (usually
* <code>.wm</code>). It is necessary to instruct your servlet engine of
* choice to invoke the <code>Dispatcher</code> servlet for all requests
* ending in that extension. For Apache/JServ this looks something like
* this:
*
* <pre>
* ApJServAction .wm /servlets/com.samskivert.webmacro.Dispatcher
* </pre>
*
* The request URI then defines the path of the webmacro template that
* will be used to satisfy the request. To understand how code is selected
* to go along with the request, let's look at an example. Consider the
* following configuration:
*
* <pre>
* applications=whowhere
* whowhere.base_uri=/whowhere
* whowhere.base_pkg=whowhere.logic
* </pre>
*
* This defines an application identified as <code>whowhere</code>. An
* application is defined by three parameters, the application identifier,
* the <code>base_uri</code>, and the <code>base_pkg</code>. The
* <code>base_uri</code> defines the prefix shared by all pages served by
* the application and which serves to identify which application to
* invoke when processing a request. The <code>base_pkg</code> is used to
* 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
* classname is resolved. Consider the following request URI:
*
* <pre>
* /whowhere/view/trips.wm
* </pre>
*
* It begins with <code>/whowhere</code> which tells the dispatcher that
* it's part of the <code>whowhere</code> application. That application's
* <code>base_uri</code> is then stripped from the URI leaving
* <code>/view/trips.wm</code>. The slashes are converted into periods to
* map directories to packages, giving us <code>view.trips.wm</code>.
* 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
* <code>whowhere.servlets.view.trips</code> (note that the classname
* <em>is</em> lowercase which is an intentional choice in resolving
* conflicting recommendations that classnames should always start with a
* capital letter and URLs should always be lowercase).
*
* <p> The template used to generate the result is loaded based on the
* full URI, essentially with a call to
* <code>getTemplate("/whowhere/view/trips.wm")</code> in this example.
* This is the place where more sophisticated cobranding support could be
* inserted in the future (ie. if I ever want to use this to develop a
* cobranded web site).
*
* <p><b>Error handling</b><br>
* The dispatcher servlet provides a common error handling mechanism. The
* design is to catch any exceptions thrown by the logic and to convert
* them into friendly error messages that are inserted into the web
* context with the key <code>"error"</code> for easy display in the
* resulting web page.
*
* <p> The process of mapping exceptions to friendly error messages is
* done using the <code>ExceptionMap</code> class. Consult its
* documentation for an explanation of how it works.
*
* @see Logic
* @see ExceptionMap
*/
public class DispatcherServlet extends WMServlet
{
public void start ()
throws ServletException
{
// Log.info("Initializing dispatcher servlet.");
// first load the properties file
Properties props = null;
try {
// load up our configuration
ClassLoader cld = DispatcherServlet.class.getClassLoader();
props = ConfigUtil.loadProperties("dispatcher.properties", cld);
} catch (IOException ioe) {
Log.warning("Failure trying to load 'dispatcher.properties': " +
ioe);
}
if (props == null) {
Log.warning("Unable to load properties for dispatcher servlet.");
Log.warning("Make sure 'dispatcher.properties' file exists " +
"somewhere in your classpath.");
props = new Properties();
}
// now parse the configuration
String apps = props.getProperty("applications");
if (apps != null) {
StringTokenizer tok = new StringTokenizer(apps);
while (tok.hasMoreTokens()) {
String appid = tok.nextToken();
String baseURI = props.getProperty(appid + ".base_uri");
String basePkg = props.getProperty(appid + ".base_pkg");
String appcl = props.getProperty(appid + ".application");
// make sure we're not missing anything
if (baseURI == null) {
Log.warning("Application '" + appid + "' missing " +
"base_uri specification.");
continue;
}
if (basePkg == null) {
Log.warning("Application '" + appid + "' missing " +
"base_pkg specification.");
continue;
}
// instantiate the specified application class
Application app;
try {
// if a custom application class was specified,
// instantiate one of those. otherwise use the default
if (appcl != null) {
Class appclass = Class.forName(appcl);
app = (Application)appclass.newInstance();
} else {
app = new Application();
}
// now initialize the applicaiton
app.preInit(baseURI, basePkg);
app.init(getServletContext());
// finally add it to our list
_apps.add(app);
} catch (Throwable t) {
Log.warning("Error instantiating custom application " +
"[class=" + appcl + "].");
Log.logStackTrace(t);
}
}
}
}
public void stop ()
{
// shutdown our applications
for (int i = 0; i < _apps.size(); i++) {
Application app = (Application)_apps.get(i);
app.shutdown();
}
}
public Template handle (WebContext ctx) throws HandlerException
{
// first we select the template
Template tmpl;
try {
tmpl = selectTemplate(ctx);
} catch (ResourceException e) {
throw new HandlerException("Unable to load template: " + e);
}
// assume an HTML response unless otherwise massaged by the logic
ctx.getResponse().setContentType("text/html");
// select the proper application for the request
String path = cleanupURI(ctx.getRequest().getRequestURI());
Application app = selectApplication(path);
String errmsg = null;
try {
// if we don't have a matching app, we'll just execute the
// template as is without first invoking a logic object
if (app != null) {
// insert the application into the web context in case the
// logic or a tool wishes to make use of it
ctx.put(APPLICATION_KEY, app);
// resolve the appropriate logic class for this URI and
// execute it if it exists
Logic logic = resolveLogic(app, path);
if (logic != null) {
logic.invoke(app, ctx);
}
}
} catch (RedirectException re) {
try {
ctx.getResponse().sendRedirect(re.getRedirectURL());
return null;
} catch (IOException ioe) {
throw new HandlerException("Unable to send redirect: " + ioe);
}
} catch (FriendlyException fe) {
// grab the error message, we'll deal with it shortly
errmsg = fe.getMessage();
} catch (Exception e) {
errmsg = ExceptionMap.getMessage(e);
Log.logStackTrace(e);
}
// if we have an error message, insert it into the template
if (errmsg != null) {
// if we have an application, try using it to localize the
// error message before we insert it
if (app != null) {
MessageManager msgmgr = app.getMessageManager();
if (msgmgr != null) {
errmsg = msgmgr.getMessage(ctx.getRequest(), errmsg);
}
}
ctx.put(ERROR_KEY, errmsg);
}
return tmpl;
}
/**
* Returns the reference to the application that is handling this
* request.
*
* @return The application in effect for this request or null if no
* application was selected to handle the request.
*/
public static Application getApplication (WebContext context)
{
return (Application)context.get(APPLICATION_KEY);
}
/**
* This method is called to select the appropriate template for this
* request. The default implementation simply loads the template using
* WebMacro's default template loading services based on the URI
* provided in the request. It is assumed that the document root is
* registered in WebMacro's search path.
*
* @param ctx The context of this request.
*
* @return The template to be used in generating the response.
*/
protected Template selectTemplate (WebContext ctx)
throws ResourceException
{
// String path = cleanupURI(ctx.getRequest().getRequestURI());
String path = ctx.getRequest().getServletPath();
// Log.info("Loading template [path=" + path + "].");
return getTemplate(path);
}
/**
* Selects and returns the matching application for this request.
*
* @return the application that should handle this request or null if
* no matching application could be found.
*/
protected Application selectApplication (String path)
{
// try to locate an application that matches this URI
for (int i = 0; i < _apps.size(); i++) {
Application app = (Application)_apps.get(i);
if (app.matches(path)) {
return app;
}
}
return null;
}
/**
* 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 (Application app, String path)
{
// look for a cached logic instance
String lclass = app.generateClass(path);
Logic logic = (Logic)_logic.get(lclass);
if (logic == null) {
try {
Class pcl = Class.forName(lclass);
logic = (Logic)pcl.newInstance();
} catch (Throwable t) {
Log.warning("Unable to instantiate logic for " +
"matching application [path=" + path +
", lclass=" + lclass + ", error=" + t + "].");
// use a dummy in it's place so that we don't sit around
// all day freaking out about our inability to instantiate
// the proper logic class
logic = new DummyLogic();
}
_logic.put(lclass, logic);
}
return logic;
}
/**
* Because the URI can actually contain the protocol and server name,
* though it commonly doesn't, we need to be sure to remove that extra
* information before we look at the URI because we only want the path
* part of the URI. The JSDK unfortunately doesn't provide an easy
* mechanism to request just the path part of the URI.
*/
protected static String cleanupURI (String uri)
{
int dsidx = uri.indexOf("//");
if (dsidx == -1) {
return uri;
}
int sidx = uri.indexOf("/", dsidx + 2);
if (sidx == -1) {
Log.warning("Malformed URI?! [uri=" + uri + "].");
return "/";
}
return uri.substring(sidx);
}
public static void main (String[] args)
{
System.out.println(cleanupURI("/whowhere/viewtrip.wm"));
System.out.println(cleanupURI("http://samskivert.com/foo/bar/baz.wm"));
System.out.println(cleanupURI("http://samskivert.com"));
System.out.println(cleanupURI("http://samskivert.com/"));
System.out.println(cleanupURI("//samskivert.com/is/this/even/legal"));
}
protected ArrayList _apps = new ArrayList();
protected HashMap _logic = new HashMap();
/** This is the key used in the context for error messages. */
protected static final String ERROR_KEY = "error";
/**
* This is the key used to store a reference back to the dispatcher
* servlet in our web context.
*/
protected static final String APPLICATION_KEY = "%_app_%";
}
@@ -1,36 +0,0 @@
//
// $Id: DummyLogic.java,v 1.3 2001/08/11 22:43:29 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.webmacro;
import org.webmacro.servlet.WebContext;
/**
* The dummy logic is used as a placeholder for URIs that match no normal
* logic or for which the matching logic could not be instantiated. It
* does nothing.
*/
public class DummyLogic implements Logic
{
public void invoke (Application app, WebContext context) throws Exception
{
// we're such a dummy that we do absolutely nothing.
}
}
@@ -1,176 +0,0 @@
//
// $Id: ExceptionMap.java,v 1.5 2001/08/11 22:43:29 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.webmacro;
import java.io.*;
import java.util.*;
import com.samskivert.Log;
import com.samskivert.util.ConfigUtil;
import com.samskivert.util.StringUtil;
/**
* The exception map is used to map exceptions to error messages based on
* a static, server-wide configuration.
*
* <p>The configuration file is 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>
* # Exception mappings (lines beginning with # are ignored)
* com.samskivert.webmacro.FriendlyException: An error occurred while \
* processing your request: {m}
*
* # 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 \
* 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>. The exceptions should be
* listed in order of most to least specific, as the first mapping for
* which the exception to report is an instance of the listed exception
* will be used.
*
* <p><em>Note:</em> These exception mappings are used for all requests
* (perhaps some day only for requests associated with a particular
* application). Regardless, this error handling mechanism should not be
* used for request specific errors. For example, an SQL exception
* reporting a duplicate key should probably be caught and reported
* specifically by the appropriate populator (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.
*
* @see DispatcherServlet
*/
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
ClassLoader cld = ExceptionMap.class.getClassLoader();
InputStream config = ConfigUtil.getStream(PROPS_NAME, cld);
if (config == null) {
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.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.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());
}
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,177 +0,0 @@
//
// $Id: FormUtil.java,v 1.6 2001/08/11 22:43:29 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.webmacro;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import com.samskivert.Log;
import com.samskivert.util.StringUtil;
import org.webmacro.servlet.WebContext;
/**
* The form util class provides handy functions for doing form-related
* stuff.
*/
public class FormUtil
{
/**
* Fetches the supplied parameter from the request and converts it to
* an integer. If the parameter does not exist or is not a well-formed
* integer, a data validation exception is thrown with the supplied
* message.
*/
public static int requireIntParameter (WebContext context, String name,
String invalidDataMessage)
throws DataValidationException
{
String value = context.getForm(name);
try {
return Integer.parseInt(value);
} catch (NumberFormatException nfe) {
throw new DataValidationException(invalidDataMessage);
}
}
/**
* Fetches the supplied parameter from the request. If the parameter
* does not exist, a data validation exception is thrown with the
* supplied message.
*/
public static String requireParameter (WebContext context, String name,
String missingDataMessage)
throws DataValidationException
{
String value = context.getForm(name);
if (StringUtil.blank(value)) {
throw new DataValidationException(missingDataMessage);
}
return value;
}
/**
* Fetches the supplied parameter from the request and converts it to
* a date. The value of the parameter should be a date formatted like
* so: 2001-12-25. If the parameter does not exist or is not a
* well-formed date, a data validation exception is thrown with the
* supplied message.
*/
public static Date requireDateParameter (WebContext context, String name,
String invalidDataMessage)
throws DataValidationException
{
return parseDateParameter(context.getForm(name), invalidDataMessage);
}
/**
* Fetches the supplied parameter from the request. If the parameter
* does not exist, either null or the empty string will be returned
* depending on the value of the <code>returnNull</code> parameter.
*/
public static String getParameter (WebContext context, String name,
boolean returnNull)
{
String value = context.getForm(name);
if (returnNull || !StringUtil.blank(value)) {
return value;
} else {
return "";
}
}
/**
* Fetches the supplied parameter from the request and converts it to
* a date. The value of the parameter should be a date formatted like
* so: 2001-12-25. If the parameter does not exist, null is
* returned. If the parameter is not a well-formed date, a data
* validation exception is thrown with the supplied message.
*/
public static Date getDateParameter (WebContext context, String name,
String invalidDataMessage)
throws DataValidationException
{
String value = context.getForm(name);
if (StringUtil.blank(value)) {
return null;
}
return parseDateParameter(value, invalidDataMessage);
}
protected static
Date parseDateParameter (String value, String invalidDataMessage)
throws DataValidationException
{
Date date = null;
try {
if (value != null) {
date = _dparser.parse(value);
}
} catch (ParseException pe) {
// fall through with date == null
Log.info("Date parsing failed: " + pe);
}
// freak out if we failed to parse the date for some reason
if (date == null) {
throw new DataValidationException(invalidDataMessage);
}
return date;
}
/**
* Returns true if the specified parameter is set in the request
* context.
*
* @return true if the specified parameter is set in the request
* context, false otherwise.
*/
public static boolean isSet (WebContext context, String name)
{
return !StringUtil.blank(context.getForm(name));
}
/**
* Returns true if the specified parameter is equal to the supplied
* value. If the parameter is not set in the request context, false is
* returned.
*
* @param context The request context.
* @param name The parameter whose value should be compared with the
* supplied value.
* @param value The value to which the parameter may be equal. This
* should not be null.
*
* @return true if the specified parameter is equal to the supplied
* parameter, false otherwise.
*/
public static boolean equals (WebContext context, String name,
String value)
{
return value.equals(context.getForm(name));
}
/** We use this to parse dates in requireDateParameter(). */
protected static SimpleDateFormat _dparser =
new SimpleDateFormat("yyyy-MM-dd");
}
@@ -1,39 +0,0 @@
//
// $Id: FriendlyException.java,v 1.3 2001/08/11 22:43:29 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.webmacro;
/**
* The friendly exception provides a mechanism by which a servlet can
* abort its processing and report a human readable error to the servlet
* framework that will be inserted into the context in the appropriate
* place so that the error message will be displayed to the user. Simply
* construct a friendly exception with the desired error message and throw
* it during the call to <code>populateContext</code>.
*
* @see DispatcherServlet
*/
public class FriendlyException extends Exception
{
public FriendlyException (String message)
{
super(message);
}
}
@@ -1,49 +0,0 @@
//
// $Id: Logic.java,v 1.3 2001/08/11 22:43:29 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.webmacro;
import org.webmacro.servlet.WebContext;
/**
* The logic class is called upon to populate the WebMacro web context,
* prior to invoking a particular WebMacro template upon it to generate a
* response page. The logic takes the place of the servlet in the standard
* WebMacro architecture and should perform all of the logic involved in
* handling a particular request.
*
* @see DispatcherServlet
*/
public interface Logic
{
/**
* Perform any necessary computation and populate the context with
* data for this request. Any exceptions that are thrown will be
* converted into friendly error messages using the exception mapping
* services.
*
* @param app The application that generated this logic instance (used
* to access application-wide resources).
* @param context The WebMacro context in scope for this request.
*
* @see ExceptionMap
*/
public void invoke (Application app, WebContext context) throws Exception;
}
@@ -1,147 +0,0 @@
//
// $Id: MsgTool.java,v 1.3 2001/08/11 22:43:29 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.webmacro;
import org.webmacro.*;
import org.webmacro.servlet.WebContext;
import org.webmacro.util.PropertyObject;
import org.webmacro.util.PropertyMethod;
import com.samskivert.Log;
import com.samskivert.servlet.MessageManager;
/**
* The message tool maps a set of appliation messages (translation
* strings) into the context so that they are available to templates that
* wish to display localized text.
*/
public class MsgTool implements ContextTool
{
/**
* Loads up the message resources and inserts them into the context.
*/
public Object init (Context ctx)
throws InvalidContextException
{
try {
WebContext wctx = (WebContext)ctx;
// get a handle on the application in effect for this request
Application app = DispatcherServlet.getApplication(wctx);
if (app == null) {
String err = "No application in effect for this request. " +
"Can't resolve messages without an application.";
throw new InvalidContextException(err);
}
// get the message manager from the application
MessageManager msgmgr = app.getMessageManager();
if (msgmgr == null) {
String err = "Application did not provide a message " +
"manager. Can't resolve messages without one.";
throw new InvalidContextException(err);
}
// then create a wrapper that allows webmacro to access it
return new Wrapper(msgmgr);
} catch (ClassCastException cce) {
throw new InvalidContextException("MsgTool requires a WebContext");
}
}
public void destroy (Object obj)
{
// nothing to clean up
}
public static class Wrapper implements PropertyObject
{
public Wrapper (MessageManager msgmgr)
{
_msgmgr = msgmgr;
}
public Object getProperty (Context context, Object[] names, int offset)
throws PropertyException, SecurityException
{
StringBuffer path = new StringBuffer();
boolean bogus = false;
int lastidx = names.length-1;
WebContext wctx = (WebContext)context;
// reconstruct the path to the property
for (int i = offset; i < names.length; i++) {
// separate components with dots
if (path.length() > 0) {
path.append(".");
}
// each name should either be a PropertyMethod or a string
// or an object that can be toString()ed
if (names[i] instanceof PropertyMethod) {
// make a note to freak out if this is anything but
// the last component of the path. we'd freak out now
// but we want to reconstruct the path so that we can
// report it in the exception that's thrown
if (i != lastidx) {
bogus = true;
}
path.append(((PropertyMethod)names[i]).getName());
} else {
path.append(names[i]);
}
}
// do any pending freaking out
if (bogus) {
throw new PropertyException("Invalid message resource " +
"path: " + path);
}
// if the last component is a property method, we want to use
// it's arguments when looking up the message
if (names[lastidx] instanceof PropertyMethod) {
PropertyMethod pm = (PropertyMethod)names[lastidx];
// we may cache message formatters later, but for now just
// use the static convenience function
Object[] args = pm.getArguments(context);
return _msgmgr.getMessage(wctx.getRequest(),
path.toString(), args);
} else {
// otherwise just look up the path
return _msgmgr.getMessage(wctx.getRequest(), path.toString());
}
}
public boolean setProperty (Context context, Object[] names, int offset,
Object value)
throws PropertyException, SecurityException
{
throw new PropertyException("Setting a message resource " +
"is not supported!");
}
protected MessageManager _msgmgr;
}
}
@@ -1,59 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
<head>
<!--
$Id: package.html,v 1.2 2001/08/12 01:45:46 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
-->
</head>
<body bgcolor="white">
Provides parts of a simple web application framework built around the
WebMacro template engine.
<p> The web application framework provided by this package is simple
and intended for use in small projects with limited scope. It is not
intended to be all things, nor to evolve into something that makes
toast. It builds upon WebMacro, a template engine whose
<a href="http://www.webmacro.org/WebMacroMotivation">philosophies</a>
about the separation of markup and code I agree with.
<p> WebMacro is designed to be used explicitly by servlets in
applications where the design is structured around the servlets
rather than the pages generated by the servlets. This is in contrast
to the JSP approach where the pages themselves dictate the structure
of the application and the servlets are automatically generated to
conform to that structure. This package provides a means by which to
automatically map serlvet-like units of code to templates in a way
akin to JSP's approach but without the combination of code and
markup.
<p>I'd document this more, but I'm probably going to start using
<a href="http://jakarta.apache.org/turbine/">Turbine</a> and abandon
this framework next time I get around to working on web
applications.
<h2>Related Documentation</h2>
<a href="http://www.webmacro.org/">WebMacro website</a>.
</body>
</html>