craigmcc 02/03/04 20:23:57 Modified: src/example/org/apache/struts/webapp/example Constants.java EditRegistrationAction.java EditSubscriptionAction.java LogonAction.java RegistrationForm.java SaveRegistrationAction.java SaveSubscriptionAction.java Subscription.java User.java web/example subscription.jsp web/example/WEB-INF struts-config.xml Added: src/example/org/apache/struts/webapp/example UserDatabase.java src/example/org/apache/struts/webapp/example/memory MemoryDatabasePlugIn.java MemorySubscription.java MemoryUser.java MemoryUserDatabase.java Log: Update the canonical Struts example webapp to use a DAO to interface to the user database, with the possibility of substituting a different implementation in that can talk to a real database. NOTE: Conversion to use commons logging is not complete -- I wanted to get the basic functionality in first. Revision Changes Path 1.3 +7 -7 jakarta-struts/src/example/org/apache/struts/webapp/example/Constants.java Index: Constants.java =================================================================== RCS file: /home/cvs/jakarta-struts/src/example/org/apache/struts/webapp/example/Constants.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- Constants.java 14 Apr 2001 12:53:07 -0000 1.2 +++ Constants.java 5 Mar 2002 04:23:56 -0000 1.3 @@ -1,13 +1,13 @@ /* - * $Header: /home/cvs/jakarta-struts/src/example/org/apache/struts/webapp/example/Constants.java,v 1.2 2001/04/14 12:53:07 rleland Exp $ - * $Revision: 1.2 $ - * $Date: 2001/04/14 12:53:07 $ + * $Header: /home/cvs/jakarta-struts/src/example/org/apache/struts/webapp/example/Constants.java,v 1.3 2002/03/05 04:23:56 craigmcc Exp $ + * $Revision: 1.3 $ + * $Date: 2002/03/05 04:23:56 $ * * ==================================================================== * * The Apache Software License, Version 1.1 * - * Copyright (c) 1999-2001 The Apache Software Foundation. All rights + * Copyright (c) 1999-2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without @@ -67,7 +67,7 @@ * Manifest constants for the example application. * * @author Craig R. McClanahan - * @version $Revision: 1.2 $ $Date: 2001/04/14 12:53:07 $ + * @version $Revision: 1.3 $ $Date: 2002/03/05 04:23:56 $ */ public final class Constants { @@ -80,8 +80,8 @@ /** - * The application scope attribute under which our Hashtable of - * Users is stored. + * The application scope attribute under which our user database + * is stored. */ public static final String DATABASE_KEY = "database"; 1.5 +9 -9 jakarta-struts/src/example/org/apache/struts/webapp/example/EditRegistrationAction.java Index: EditRegistrationAction.java =================================================================== RCS file: /home/cvs/jakarta-struts/src/example/org/apache/struts/webapp/example/EditRegistrationAction.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- EditRegistrationAction.java 13 Jan 2002 00:25:35 -0000 1.4 +++ EditRegistrationAction.java 5 Mar 2002 04:23:56 -0000 1.5 @@ -1,13 +1,13 @@ /* - * $Header: /home/cvs/jakarta-struts/src/example/org/apache/struts/webapp/example/EditRegistrationAction.java,v 1.4 2002/01/13 00:25:35 craigmcc Exp $ - * $Revision: 1.4 $ - * $Date: 2002/01/13 00:25:35 $ + * $Header: /home/cvs/jakarta-struts/src/example/org/apache/struts/webapp/example/EditRegistrationAction.java,v 1.5 2002/03/05 04:23:56 craigmcc Exp $ + * $Revision: 1.5 $ + * $Date: 2002/03/05 04:23:56 $ * * ==================================================================== * * The Apache Software License, Version 1.1 * - * Copyright (c) 1999-2001 The Apache Software Foundation. All rights + * Copyright (c) 1999-2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without @@ -87,7 +87,7 @@ * User (if any). * * @author Craig R. McClanahan - * @version $Revision: 1.4 $ $Date: 2002/01/13 00:25:35 $ + * @version $Revision: 1.5 $ $Date: 2002/03/05 04:23:56 $ */ public final class EditRegistrationAction extends Action { @@ -108,14 +108,14 @@ * @param request The HTTP request we are processing * @param response The HTTP response we are creating * - * @exception IOException if an input/output error occurs - * @exception ServletException if a servlet exception occurs + * @exception Exception if the application business logic throws + * an exception */ - public ActionForward perform(ActionMapping mapping, + public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException { + throws Exception { // Extract attributes we will need Locale locale = getLocale(request); 1.5 +46 -39 jakarta-struts/src/example/org/apache/struts/webapp/example/EditSubscriptionAction.java Index: EditSubscriptionAction.java =================================================================== RCS file: /home/cvs/jakarta-struts/src/example/org/apache/struts/webapp/example/EditSubscriptionAction.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- EditSubscriptionAction.java 13 Jan 2002 00:25:35 -0000 1.4 +++ EditSubscriptionAction.java 5 Mar 2002 04:23:56 -0000 1.5 @@ -1,7 +1,7 @@ /* - * $Header: /home/cvs/jakarta-struts/src/example/org/apache/struts/webapp/example/EditSubscriptionAction.java,v 1.4 2002/01/13 00:25:35 craigmcc Exp $ - * $Revision: 1.4 $ - * $Date: 2002/01/13 00:25:35 $ + * $Header: /home/cvs/jakarta-struts/src/example/org/apache/struts/webapp/example/EditSubscriptionAction.java,v 1.5 2002/03/05 04:23:56 craigmcc Exp $ + * $Revision: 1.5 $ + * $Date: 2002/03/05 04:23:56 $ * * ==================================================================== * @@ -86,7 +86,7 @@ * <code>SubscriptionForm</code> from the currently specified subscription. * * @author Craig R. McClanahan - * @version $Revision: 1.4 $ $Date: 2002/01/13 00:25:35 $ + * @version $Revision: 1.5 $ $Date: 2002/03/05 04:23:56 $ */ public final class EditSubscriptionAction extends Action { @@ -107,84 +107,91 @@ * @param request The HTTP request we are processing * @param response The HTTP response we are creating * - * @exception IOException if an input/output error occurs - * @exception ServletException if a servlet exception occurs + * @exception Exception if the application business logic throws + * an exception */ - public ActionForward perform(ActionMapping mapping, + public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException { + throws Exception { // Extract attributes we will need Locale locale = getLocale(request); MessageResources messages = getResources(); HttpSession session = request.getSession(); String action = request.getParameter("action"); - if (action == null) + if (action == null) { action = "Create"; + } String host = request.getParameter("host"); - if (servlet.getDebug() >= 1) + if (servlet.getDebug() >= 1) { servlet.log("EditSubscriptionAction: Processing " + action + " action"); + } // Is there a currently logged on user? User user = (User) session.getAttribute(Constants.USER_KEY); if (user == null) { - if (servlet.getDebug() >= 1) + if (servlet.getDebug() >= 1) { servlet.log(" User is not logged on in session " + session.getId()); + } return (mapping.findForward("logon")); } // Identify the relevant subscription - Subscription subscription = null; - if (action.equals("Create")) { - subscription = new Subscription(); - subscription.setUser(user); - } else { - subscription = user.findSubscription(host); - } - if (subscription == null) { - if (servlet.getDebug() >= 1) + Subscription subscription = + user.findSubscription(request.getParameter("host")); + if ((subscription == null) && !action.equals("Create")) { + if (servlet.getDebug() >= 1) { servlet.log(" No subscription for user " + user.getUsername() + " and host " + host); + } return (mapping.findForward("failure")); } - session.setAttribute(Constants.SUBSCRIPTION_KEY, subscription); + if (subscription != null) { + session.setAttribute(Constants.SUBSCRIPTION_KEY, subscription); + } // Populate the subscription form if (form == null) { - if (servlet.getDebug() >= 1) + if (servlet.getDebug() >= 1) { servlet.log(" Creating new SubscriptionForm bean under key " + mapping.getAttribute()); + } form = new SubscriptionForm(); - if ("request".equals(mapping.getScope())) + if ("request".equals(mapping.getScope())) { request.setAttribute(mapping.getAttribute(), form); - else + } else { session.setAttribute(mapping.getAttribute(), form); + } } SubscriptionForm subform = (SubscriptionForm) form; subform.setAction(action); - if (servlet.getDebug() >= 1) - servlet.log(" Populating form from " + subscription); - try { - PropertyUtils.copyProperties(subform, subscription); - subform.setAction(action); - } catch (InvocationTargetException e) { - Throwable t = e.getTargetException(); - if (t == null) - t = e; - servlet.log("SubscriptionForm.populate", t); - throw new ServletException("SubscriptionForm.populate", t); - } catch (Throwable t) { - servlet.log("SubscriptionForm.populate", t); - throw new ServletException("SubscriptionForm.populate", t); + if (!action.equals("Create")) { + if (servlet.getDebug() >= 1) { + servlet.log(" Populating form from " + subscription); + } + try { + PropertyUtils.copyProperties(subform, subscription); + subform.setAction(action); + } catch (InvocationTargetException e) { + Throwable t = e.getTargetException(); + if (t == null) + t = e; + servlet.log("SubscriptionForm.populate", t); + throw new ServletException("SubscriptionForm.populate", t); + } catch (Throwable t) { + servlet.log("SubscriptionForm.populate", t); + throw new ServletException("SubscriptionForm.populate", t); + } } // Forward control to the edit subscription page - if (servlet.getDebug() >= 1) + if (servlet.getDebug() >= 1) { servlet.log(" Forwarding to 'success' page"); + } return (mapping.findForward("success")); } 1.5 +8 -10 jakarta-struts/src/example/org/apache/struts/webapp/example/LogonAction.java Index: LogonAction.java =================================================================== RCS file: /home/cvs/jakarta-struts/src/example/org/apache/struts/webapp/example/LogonAction.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- LogonAction.java 17 Jan 2002 00:15:05 -0000 1.4 +++ LogonAction.java 5 Mar 2002 04:23:56 -0000 1.5 @@ -1,7 +1,7 @@ /* - * $Header: /home/cvs/jakarta-struts/src/example/org/apache/struts/webapp/example/LogonAction.java,v 1.4 2002/01/17 00:15:05 craigmcc Exp $ - * $Revision: 1.4 $ - * $Date: 2002/01/17 00:15:05 $ + * $Header: /home/cvs/jakarta-struts/src/example/org/apache/struts/webapp/example/LogonAction.java,v 1.5 2002/03/05 04:23:56 craigmcc Exp $ + * $Revision: 1.5 $ + * $Date: 2002/03/05 04:23:56 $ * * ==================================================================== * @@ -64,7 +64,6 @@ import java.io.IOException; -import java.util.Hashtable; import java.util.Locale; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; @@ -87,7 +86,7 @@ * Implementation of <strong>Action</strong> that validates a user logon. * * @author Craig R. McClanahan - * @version $Revision: 1.4 $ $Date: 2002/01/17 00:15:05 $ + * @version $Revision: 1.5 $ $Date: 2002/03/05 04:23:56 $ */ public final class LogonAction extends Action { @@ -127,13 +126,13 @@ PropertyUtils.getSimpleProperty(form, "username"); String password = (String) PropertyUtils.getSimpleProperty(form, "password"); - Hashtable database = (Hashtable) + UserDatabase database = (UserDatabase) servlet.getServletContext().getAttribute(Constants.DATABASE_KEY); if (database == null) errors.add(ActionErrors.GLOBAL_ERROR, new ActionError("error.database.missing")); else { - user = getUser(database, username, password); + user = getUser(database, username); if ((user != null) && !user.getPassword().equals(password)) user = null; if (user == null) @@ -177,11 +176,10 @@ * * @param database Database in which to look up the user * @param username Username specified on the logon form - * @param password Password specified on the logon form * * @exception AppException if a business logic rule is violated */ - public User getUser(Hashtable database, String username, String password) + public User getUser(UserDatabase database, String username) throws AppException { // Force an ArithmeticException which can be handled explicitly @@ -195,7 +193,7 @@ } // Look up and return the specified user - return ((User) database.get(username)); + return ((User) database.findUser(username)); } 1.3 +12 -12 jakarta-struts/src/example/org/apache/struts/webapp/example/RegistrationForm.java Index: RegistrationForm.java =================================================================== RCS file: /home/cvs/jakarta-struts/src/example/org/apache/struts/webapp/example/RegistrationForm.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- RegistrationForm.java 14 Apr 2001 12:53:08 -0000 1.2 +++ RegistrationForm.java 5 Mar 2002 04:23:56 -0000 1.3 @@ -1,13 +1,13 @@ /* - * $Header: /home/cvs/jakarta-struts/src/example/org/apache/struts/webapp/example/RegistrationForm.java,v 1.2 2001/04/14 12:53:08 rleland Exp $ - * $Revision: 1.2 $ - * $Date: 2001/04/14 12:53:08 $ + * $Header: /home/cvs/jakarta-struts/src/example/org/apache/struts/webapp/example/RegistrationForm.java,v 1.3 2002/03/05 04:23:56 craigmcc Exp $ + * $Revision: 1.3 $ + * $Date: 2002/03/05 04:23:56 $ * * ==================================================================== * * The Apache Software License, Version 1.1 * - * Copyright (c) 1999-2001 The Apache Software Foundation. All rights + * Copyright (c) 1999-2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without @@ -71,18 +71,18 @@ /** - * Form bean for the user registration page. This form has the following fields, - * with default values in square brackets: + * Form bean for the user registration page. This form has the following + * fields, with default values in square brackets: * <ul> - * <li><b>action</b> - The maintenance action we are performing (Create, Delete, - * or Edit). + * <li><b>action</b> - The maintenance action we are performing (Create, + * Delete, or Edit). * <li><b>fromAddress</b> - The EMAIL address of the sender, to be included * on sent messages. [REQUIRED] * <li><b>fullName</b> - The full name of the sender, to be included on * sent messages. [REQUIRED] * <li><b>password</b> - The password used by this user to log on. - * <li><b>password2</b> - The confirmation password, which must match the password - * when changing or setting. + * <li><b>password2</b> - The confirmation password, which must match + * the password when changing or setting. * <li><b>replyToAddress</b> - The "Reply-To" address to be included on * sent messages. [Same as from address] * <li><b>username</b> - The registered username, which must be unique. @@ -90,13 +90,13 @@ * </ul> * * @author Craig R. McClanahan - * @version $Revision: 1.2 $ $Date: 2001/04/14 12:53:08 $ + * @version $Revision: 1.3 $ $Date: 2002/03/05 04:23:56 $ */ public final class RegistrationForm extends ActionForm { - // --------------------------------------------------- Instance Variables + // ----------------------------------------------------- Instance Variables /** 1.5 +38 -30 jakarta-struts/src/example/org/apache/struts/webapp/example/SaveRegistrationAction.java Index: SaveRegistrationAction.java =================================================================== RCS file: /home/cvs/jakarta-struts/src/example/org/apache/struts/webapp/example/SaveRegistrationAction.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- SaveRegistrationAction.java 13 Jan 2002 00:25:35 -0000 1.4 +++ SaveRegistrationAction.java 5 Mar 2002 04:23:56 -0000 1.5 @@ -1,13 +1,13 @@ /* - * $Header: /home/cvs/jakarta-struts/src/example/org/apache/struts/webapp/example/SaveRegistrationAction.java,v 1.4 2002/01/13 00:25:35 craigmcc Exp $ - * $Revision: 1.4 $ - * $Date: 2002/01/13 00:25:35 $ + * $Header: /home/cvs/jakarta-struts/src/example/org/apache/struts/webapp/example/SaveRegistrationAction.java,v 1.5 2002/03/05 04:23:56 craigmcc Exp $ + * $Revision: 1.5 $ + * $Date: 2002/03/05 04:23:56 $ * * ==================================================================== * * The Apache Software License, Version 1.1 * - * Copyright (c) 1999-2001 The Apache Software Foundation. All rights + * Copyright (c) 1999-2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without @@ -66,7 +66,6 @@ import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.Locale; -import java.util.Hashtable; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -89,7 +88,7 @@ * registration is created, the user is also implicitly logged on. * * @author Craig R. McClanahan - * @version $Revision: 1.4 $ $Date: 2002/01/13 00:25:35 $ + * @version $Revision: 1.5 $ $Date: 2002/03/05 04:23:56 $ */ public final class SaveRegistrationAction extends Action { @@ -110,14 +109,14 @@ * @param request The HTTP request we are processing * @param response The HTTP response we are creating * - * @exception IOException if an input/output error occurs - * @exception ServletException if a servlet exception occurs + * @exception Exception if the application business logic throws + * an exception */ - public ActionForward perform(ActionMapping mapping, + public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException { + throws Exception { // Extract attributes and parameters we will need Locale locale = getLocale(request); @@ -125,13 +124,15 @@ HttpSession session = request.getSession(); RegistrationForm regform = (RegistrationForm) form; String action = request.getParameter("action"); - if (action == null) + if (action == null) { action = "Create"; - Hashtable database = (Hashtable) + } + UserDatabase database = (UserDatabase) servlet.getServletContext().getAttribute(Constants.DATABASE_KEY); - if (servlet.getDebug() >= 1) + if (servlet.getDebug() >= 1) { servlet.log("SaveRegistrationAction: Processing " + action + " action"); + } // Is there a currently logged on user (unless creating)? User user = (User) session.getAttribute(Constants.USER_KEY); @@ -144,11 +145,10 @@ // Was this transaction cancelled? if (isCancelled(request)) { - if (servlet.getDebug() >= 1) + if (servlet.getDebug() >= 1) { servlet.log(" Transaction '" + action + "' was cancelled"); - if (mapping.getAttribute() != null) - session.removeAttribute(mapping.getAttribute()); + } session.removeAttribute(Constants.SUBSCRIPTION_KEY); return (mapping.findForward("success")); } @@ -158,30 +158,35 @@ if (servlet.getDebug() >= 1) { servlet.log(" Checking transactional control token"); } - if (!isTokenValid(request)) + if (!isTokenValid(request)) { errors.add(ActionErrors.GLOBAL_ERROR, new ActionError("error.transaction.token")); + } resetToken(request); // Validate the request parameters specified by the user - if (servlet.getDebug() >= 1) + if (servlet.getDebug() >= 1) { servlet.log(" Performing extra validations"); + } String value = null; value = regform.getUsername(); if (("Create".equals(action)) && - (database.get(value) != null)) + (database.findUser(value) != null)) { errors.add("username", new ActionError("error.username.unique", regform.getUsername())); + } if ("Create".equals(action)) { value = regform.getPassword(); - if ((value == null) || (value.length() <1)) + if ((value == null) || (value.length() <1)) { errors.add("password", new ActionError("error.password.required")); + } value = regform.getPassword2(); - if ((value == null) || (value.length() < 1)) + if ((value == null) || (value.length() < 1)) { errors.add("password2", new ActionError("error.password2.required")); + } } // Report any errors we have discovered back to the original form @@ -192,20 +197,22 @@ } // Update the user's persistent profile information - if ("Create".equals(action)) { - user = new User(); - user.setUsername(regform.getUsername()); - } try { + if ("Create".equals(action)) { + user = database.createUser(regform.getUsername()); + } String oldPassword = user.getPassword(); PropertyUtils.copyProperties(user, regform); if ((regform.getPassword() == null) || - (regform.getPassword().length() < 1)) + (regform.getPassword().length() < 1)) { user.setPassword(oldPassword); + } + database.save(); } catch (InvocationTargetException e) { Throwable t = e.getTargetException(); - if (t == null) + if (t == null) { t = e; + } servlet.log("Registration.populate", t); throw new ServletException("Registration.populate", t); } catch (Throwable t) { @@ -216,11 +223,11 @@ // Log the user in if appropriate if ("Create".equals(action)) { - database.put(user.getUsername(), user); session.setAttribute(Constants.USER_KEY, user); - if (servlet.getDebug() >= 1) + if (servlet.getDebug() >= 1) { servlet.log(" User '" + user.getUsername() + "' logged on in session " + session.getId()); + } } // Remove the obsolete form bean @@ -232,8 +239,9 @@ } // Forward control to the specified success URI - if (servlet.getDebug() >= 1) + if (servlet.getDebug() >= 1) { servlet.log(" Forwarding to success page"); + } return (mapping.findForward("success")); } 1.5 +36 -30 jakarta-struts/src/example/org/apache/struts/webapp/example/SaveSubscriptionAction.java Index: SaveSubscriptionAction.java =================================================================== RCS file: /home/cvs/jakarta-struts/src/example/org/apache/struts/webapp/example/SaveSubscriptionAction.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- SaveSubscriptionAction.java 13 Jan 2002 00:25:35 -0000 1.4 +++ SaveSubscriptionAction.java 5 Mar 2002 04:23:56 -0000 1.5 @@ -1,13 +1,13 @@ /* - * $Header: /home/cvs/jakarta-struts/src/example/org/apache/struts/webapp/example/SaveSubscriptionAction.java,v 1.4 2002/01/13 00:25:35 craigmcc Exp $ - * $Revision: 1.4 $ - * $Date: 2002/01/13 00:25:35 $ + * $Header: /home/cvs/jakarta-struts/src/example/org/apache/struts/webapp/example/SaveSubscriptionAction.java,v 1.5 2002/03/05 04:23:56 craigmcc Exp $ + * $Revision: 1.5 $ + * $Date: 2002/03/05 04:23:56 $ * * ==================================================================== * * The Apache Software License, Version 1.1 * - * Copyright (c) 1999-2001 The Apache Software Foundation. All rights + * Copyright (c) 1999-2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without @@ -66,7 +66,6 @@ import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.Locale; -import java.util.Hashtable; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -88,7 +87,7 @@ * updates the mail subscription entered by the user. * * @author Craig R. McClanahan - * @version $Revision: 1.4 $ $Date: 2002/01/13 00:25:35 $ + * @version $Revision: 1.5 $ $Date: 2002/03/05 04:23:56 $ */ public final class SaveSubscriptionAction extends Action { @@ -109,14 +108,14 @@ * @param request The HTTP request we are processing * @param response The HTTP response we are creating * - * @exception IOException if an input/output error occurs - * @exception ServletException if a servlet exception occurs + * @exception Exception if the application business logic throws + * an exception */ - public ActionForward perform(ActionMapping mapping, + public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException { + throws Exception { // Extract attributes and parameters we will need Locale locale = getLocale(request); @@ -124,11 +123,13 @@ HttpSession session = request.getSession(); SubscriptionForm subform = (SubscriptionForm) form; String action = request.getParameter("action"); - if (action == null) + if (action == null) { action = "?"; - if (servlet.getDebug() >= 1) + } + if (servlet.getDebug() >= 1) { servlet.log("SaveSubscriptionAction: Processing " + action + " action"); + } // Is there a currently logged on user? User user = (User) session.getAttribute(Constants.USER_KEY); @@ -139,9 +140,23 @@ return (mapping.findForward("logon")); } + // Was this transaction cancelled? + if (isCancelled(request)) { + if (servlet.getDebug() >= 1) { + servlet.log(" Transaction '" + action + + "' was cancelled"); + } + session.removeAttribute(Constants.SUBSCRIPTION_KEY); + return (mapping.findForward("success")); + } + // Is there a related Subscription object? Subscription subscription = (Subscription) session.getAttribute(Constants.SUBSCRIPTION_KEY); + if ("Create".equals(action)) { + subscription = + user.createSubscription(request.getParameter("host")); + } if (subscription == null) { servlet.log(" Missing subscription for user '" + user.getUsername() + "'"); @@ -150,27 +165,15 @@ return (null); } - // Was this transaction cancelled? - if (isCancelled(request)) { - if (servlet.getDebug() >= 1) - servlet.log(" Transaction '" + action + - "' was cancelled"); - if (mapping.getAttribute() != null) - session.removeAttribute(mapping.getAttribute()); - session.removeAttribute(Constants.SUBSCRIPTION_KEY); - return (mapping.findForward("success")); - } - // Was this transaction a Delete? if (action.equals("Delete")) { - if (servlet.getDebug() >= 1) + if (servlet.getDebug() >= 1) { servlet.log(" Deleting mail server '" + subscription.getHost() + "' for user '" + user.getUsername() + "'"); - subscription.setHost(null); - subscription.setUser(null); - if (mapping.getAttribute() != null) - session.removeAttribute(mapping.getAttribute()); + } + user.removeSubscription(subscription); + user.getDatabase().save(); session.removeAttribute(Constants.SUBSCRIPTION_KEY); return (mapping.findForward("success")); } @@ -178,10 +181,12 @@ // All required validations were done by the form itself // Update the persistent subscription information - if (servlet.getDebug() >= 1) + if (servlet.getDebug() >= 1) { servlet.log(" Populating database from form bean"); + } try { PropertyUtils.copyProperties(subscription, subform); + user.getDatabase().save(); } catch (InvocationTargetException e) { Throwable t = e.getTargetException(); if (t == null) @@ -203,8 +208,9 @@ session.removeAttribute(Constants.SUBSCRIPTION_KEY); // Forward control to the specified success URI - if (servlet.getDebug() >= 1) + if (servlet.getDebug() >= 1) { servlet.log(" Forwarding to success page"); + } return (mapping.findForward("success")); } 1.3 +20 -160 jakarta-struts/src/example/org/apache/struts/webapp/example/Subscription.java Index: Subscription.java =================================================================== RCS file: /home/cvs/jakarta-struts/src/example/org/apache/struts/webapp/example/Subscription.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- Subscription.java 14 Apr 2001 12:53:08 -0000 1.2 +++ Subscription.java 5 Mar 2002 04:23:56 -0000 1.3 @@ -1,13 +1,13 @@ /* - * $Header: /home/cvs/jakarta-struts/src/example/org/apache/struts/webapp/example/Subscription.java,v 1.2 2001/04/14 12:53:08 rleland Exp $ - * $Revision: 1.2 $ - * $Date: 2001/04/14 12:53:08 $ + * $Header: /home/cvs/jakarta-struts/src/example/org/apache/struts/webapp/example/Subscription.java,v 1.3 2002/03/05 04:23:56 craigmcc Exp $ + * $Revision: 1.3 $ + * $Date: 2002/03/05 04:23:56 $ * * ==================================================================== * * The Apache Software License, Version 1.1 * - * Copyright (c) 1999-2001 The Apache Software Foundation. All rights + * Copyright (c) 1999-2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without @@ -63,70 +63,24 @@ package org.apache.struts.webapp.example; -import java.io.Serializable; - - /** - * Object that represents a subscription of a registered user on a - * specific mail server. + * <p>A <strong>Subscription</strong> which is stored, along with the + * associated {@link User}, in a {@link UserDatabase}.</p> * * @author Craig R. McClanahan - * @version $Revision: 1.2 $ $Date: 2001/04/14 12:53:08 $ + * @version $Revision: 1.3 $ $Date: 2002/03/05 04:23:56 $ */ -public final class Subscription implements Serializable { - - - // =================================================== Instance Variables - - - /** - * Should we auto-connect at startup time? - */ - private boolean autoConnect = false; - - - /** - * The mail host for this subscription. - */ - private String host = null; +public interface Subscription { - /** - * The password (in clear text). - */ - private String password = null; - - - /** - * The subscription type ("imap" or "pop3"). - */ - private String type = "imap"; - - - /** - * The User owning this Subscription. - */ - private User user = null; - - - /** - * The username (must be unique). - */ - private String username = null; - - - // =========================================================== Properties + // ------------------------------------------------------------- Properties /** * Return the auto-connect flag. */ - public boolean getAutoConnect() { - - return (this.autoConnect); - - } + public boolean getAutoConnect(); /** @@ -134,47 +88,19 @@ * * @param autoConnect The new auto-connect flag */ - public void setAutoConnect(boolean autoConnect) { - - this.autoConnect = autoConnect; - - } + public void setAutoConnect(boolean autoConnect); /** * Return the host name. */ - public String getHost() { - - return (this.host); - - } - - - /** - * Set the host name. - * - * @param host The new host name - */ - public void setHost(String host) { - - if ((this.host != null) && (user != null)) - user.removeSubscription(this); - this.host = host; - if ((this.host != null) && (user != null)) - user.addSubscription(this); - - } + public String getHost(); /** * Return the password. */ - public String getPassword() { - - return (this.password); - - } + public String getPassword(); /** @@ -182,21 +108,13 @@ * * @param password The new password */ - public void setPassword(String password) { - - this.password = password; - - } + public void setPassword(String password); /** * Return the subscription type. */ - public String getType() { - - return (this.type); - - } + public String getType(); /** @@ -204,47 +122,19 @@ * * @param type The new subscription type */ - public void setType(String type) { - - this.type = type; - - } + public void setType(String type); /** - * Return the User owning this Subscription. + * Return the {@link User} owning this Subscription. */ - public User getUser() { - - return (this.user); - - } - - - /** - * Set the User owning this Subscription. - * - * @param user The new User - */ - public void setUser(User user) { - - if ((this.host != null) && (this.user != null)) - this.user.removeSubscription(this); - this.user = user; - if ((this.host != null) && (this.user != null)) - this.user.addSubscription(this); - - } + public User getUser(); /** * Return the username. */ - public String getUsername() { - - return (this.username); - - } + public String getUsername(); /** @@ -252,37 +142,7 @@ * * @param username The new username */ - public void setUsername(String username) { - - this.username = username; - - } - - - // ======================================================= Public Methods - - - /** - * Return a String representation of this object. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("Subscription[username="); - sb.append(username); - if (host != null) { - sb.append(", host="); - sb.append(host); - } - if (user != null) { - sb.append(", user="); - sb.append(user.getUsername()); - } - sb.append(", autoConnect="); - sb.append(autoConnect); - sb.append("]"); - return (sb.toString()); - - } + public void setUsername(String username); } 1.3 +43 -171 jakarta-struts/src/example/org/apache/struts/webapp/example/User.java Index: User.java =================================================================== RCS file: /home/cvs/jakarta-struts/src/example/org/apache/struts/webapp/example/User.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- User.java 14 Apr 2001 12:53:08 -0000 1.2 +++ User.java 5 Mar 2002 04:23:56 -0000 1.3 @@ -1,13 +1,13 @@ /* - * $Header: /home/cvs/jakarta-struts/src/example/org/apache/struts/webapp/example/User.java,v 1.2 2001/04/14 12:53:08 rleland Exp $ - * $Revision: 1.2 $ - * $Date: 2001/04/14 12:53:08 $ + * $Header: /home/cvs/jakarta-struts/src/example/org/apache/struts/webapp/example/User.java,v 1.3 2002/03/05 04:23:56 craigmcc Exp $ + * $Revision: 1.3 $ + * $Date: 2002/03/05 04:23:56 $ * * ==================================================================== * * The Apache Software License, Version 1.1 * - * Copyright (c) 1999-2001 The Apache Software Foundation. All rights + * Copyright (c) 1999-2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without @@ -63,71 +63,31 @@ package org.apache.struts.webapp.example; -import java.io.Serializable; -import java.util.Enumeration; -import java.util.Hashtable; - - /** - * Object that represents a registered user of the mail reader application. + * <p>A <strong>User</strong> which is stored, along with his or her + * associated {@link Subscription}s, in a {@link UserDatabase}.</p> * * @author Craig R. McClanahan - * @version $Revision: 1.2 $ $Date: 2001/04/14 12:53:08 $ + * @version $Revision: 1.3 $ $Date: 2002/03/05 04:23:56 $ + * @since Struts 1.1 */ -public final class User implements Serializable { - - - // =================================================== Instance Variables - - - /** - * The EMAIL address from which messages are sent. - */ - private String fromAddress = null; - - - /** - * The full name of this user, included in from addresses. - */ - private String fullName = null; +public interface User { - /** - * The password (in clear text). - */ - private String password = null; - - - /** - * The EMAIL address to which replies should be sent. - */ - private String replyToAddress = null; + // ------------------------------------------------------------- Properties /** - * The set of Subscriptions associated with this User. + * Return the {@link UserDatabase} with which we are associated. */ - private Hashtable subscriptions = new Hashtable(); - - - /** - * The username (must be unique). - */ - private String username = null; - - - // =========================================================== Properties + public UserDatabase getDatabase(); /** * Return the from address. */ - public String getFromAddress() { - - return (this.fromAddress); - - } + public String getFromAddress(); /** @@ -135,22 +95,13 @@ * * @param fromAddress The new from address */ - public void setFromAddress(String fromAddress) { - - this.fromAddress = fromAddress; - - } - + public void setFromAddress(String fromAddress); /** * Return the full name. */ - public String getFullName() { - - return (this.fullName); - - } + public String getFullName(); /** @@ -158,21 +109,13 @@ * * @param fullName The new full name */ - public void setFullName(String fullName) { - - this.fullName = fullName; - - } + public void setFullName(String fullName); /** * Return the password. */ - public String getPassword() { - - return (this.password); - - } + public String getPassword(); /** @@ -180,21 +123,13 @@ * * @param password The new password */ - public void setPassword(String password) { - - this.password = password; - - } + public void setPassword(String password); /** * Return the reply-to address. */ - public String getReplyToAddress() { - - return (this.replyToAddress); - - } + public String getReplyToAddress(); /** @@ -202,119 +137,56 @@ * * @param replyToAddress The new reply-to address */ - public void setReplyToAddress(String replyToAddress) { + public void setReplyToAddress(String replyToAddress); - this.replyToAddress = replyToAddress; - } + /** + * Find and return all {@link Subscription}s associated with this user. + * If there are none, a zero-length array is returned. + */ + public Subscription[] getSubscriptions(); /** * Return the username. */ - public String getUsername() { + public String getUsername(); - return (this.username); - } + // --------------------------------------------------------- Public Methods /** - * Set the username. + * Create and return a new {@link Subscription} associated with this + * User, for the specified host name. + * + * @param host Host name for which to create a subscription * - * @param username The new username + * @exception IllegalArgumentException if the host name is not unique + * for this user */ - public void setUsername(String username) { - - this.username = username; - - } - - - // ======================================================= Public Methods + public Subscription createSubscription(String host); /** - * Find and return the Subscription associated with the specified host. - * If none is found, return <code>null</code>. + * Find and return the {@link Subscription} associated with the specified + * host. If none is found, return <code>null</code>. * * @param host Host name to look up */ - public Subscription findSubscription(String host) { - - if (host == null) - return (null); - return ((Subscription) subscriptions.get(host)); - - } + public Subscription findSubscription(String host); /** - * Find and return all Subscriptions associated with this user. If there - * are none, a zero-length array is returned. - */ - public Subscription[] getSubscriptions() { - - synchronized (subscriptions) { - Subscription results[] = new Subscription[subscriptions.size()]; - Enumeration subs = subscriptions.elements(); - int n = 0; - while (subs.hasMoreElements()) { - results[n++] = (Subscription) subs.nextElement(); - } - return (results); - } - - } - - - /** - * Return a String representation of this object. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("User[username="); - sb.append(username); - if (fullName != null) { - sb.append(", fullName="); - sb.append(fullName); - } - if (replyToAddress != null) { - sb.append(", replyToAddres="); - sb.append(replyToAddress); - } - sb.append("]"); - return (sb.toString()); - - } - - - // ====================================================== Package Methods - - - /** - * Add the specified Subscription to the set associated with this User. + * Remove the specified {@link Subscription} from being associated + * with this User. * - * @param subscription The subscription to add - */ - void addSubscription(Subscription subscription) { - - subscriptions.put(subscription.getHost(), subscription); - - } - - - /** - * Remove the specified Subscription from the set associated with - * this User. + * @param subscription Subscription to be removed * - * @param subscription The subscription to remove + * @exception IllegalArgumentException if the specified subscription is not + * associated with this User */ - void removeSubscription(Subscription subscription) { - - subscriptions.remove(subscription.getHost()); - - } + public void removeSubscription(Subscription subscription); } 1.1 jakarta-struts/src/example/org/apache/struts/webapp/example/UserDatabase.java Index: UserDatabase.java =================================================================== /* * $Header: /home/cvs/jakarta-struts/src/example/org/apache/struts/webapp/example/UserDatabase.java,v 1.1 2002/03/05 04:23:57 craigmcc Exp $ * $Revision: 1.1 $ * $Date: 2002/03/05 04:23:57 $ * * ==================================================================== * * The Apache Software License, Version 1.1 * * Copyright (c) 1999-2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Struts", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * */ package org.apache.struts.webapp.example; /** * <p>A <strong>Data Access Object</strong> (DAO) interface describing * the available operations for retrieving and storing {@link User}s * (and their associated {@link Subscription}s) in some persistence layer * whose characteristics are not specified here. One or more implementations * will be created to perform the actual I/O that is required.</p> * * @author Craig R. McClanahan * @version $Revision: 1.1 $ $Date: 2002/03/05 04:23:57 $ * @since Struts 1.1 */ public interface UserDatabase { // --------------------------------------------------------- Public Methods /** * <p>Create and return a new {@link User} defined in this user database. * </p> * * @param username Username of the new user * * @exception IllegalArgumentExceptionif the specified username * is not unique */ public User createUser(String username); /** * <p>Finalize access to the underlying persistence layer.</p> * * @exception Exception if a database access error occurs */ public void close() throws Exception; /** * <p>Return the existing {@link User} with the specified username, * if any; otherwise return <code>null</code>.</p> * * @param username Username of the user to retrieve */ public User findUser(String username); /** * <p>Return the set of {@link User}s defined in this user database.</p> */ public User[] findUsers(); /** * <p>Initiate access to the underlying persistence layer.</p> * * @exception Exception if a database access error occurs */ public void open() throws Exception; /** * Remove the specified {@link User} from this database. * * @param user User to be removed * * @exception IllegalArgumentException if the specified user is not * associated with this database */ public void removeUser(User user); /** * <p>Save any pending changes to the underlying persistence layer.</p> * * @exception Exception if a database access error occurs */ public void save() throws Exception; } 1.1 jakarta-struts/src/example/org/apache/struts/webapp/example/memory/MemoryDatabasePlugIn.java Index: MemoryDatabasePlugIn.java =================================================================== /* * $Header: /home/cvs/jakarta-struts/src/example/org/apache/struts/webapp/example/memory/MemoryDatabasePlugIn.java,v 1.1 2002/03/05 04:23:57 craigmcc Exp $ * $Revision: 1.1 $ * $Date: 2002/03/05 04:23:57 $ * * ==================================================================== * * The Apache Software License, Version 1.1 * * Copyright (c) 1999-2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Struts", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * */ package org.apache.struts.webapp.example.memory; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import javax.servlet.ServletException; import javax.servlet.UnavailableException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.struts.action.ActionServlet; import org.apache.struts.action.PlugIn; import org.apache.struts.config.ApplicationConfig; import org.apache.struts.webapp.example.Constants; import org.apache.struts.webapp.example.Subscription; import org.apache.struts.webapp.example.User; import org.apache.struts.webapp.example.UserDatabase; /** * <p><strong>MemoryDatabasePlugIn</strong> initializes and finalizes the * persistent storage of User and Subscription information for the Struts * Demonstration Application, using an in-memory database backed by an * XML file.</p> * * <p><strong>IMPLEMENTATION WARNING</strong> - If this web application is run * from a WAR file, or in another environment where reading and writing of the * web application resource is impossible, the initial contents will be copied * to a file in the web application temporary directory provided by the * container. This is for demonstration purposes only - you should * <strong>NOT</strong> assume that files written here will survive a restart * of your servlet container.</p> * * @author Craig R. McClanahan * @version $Revision: 1.1 $ $Date: 2002/03/05 04:23:57 $ */ public final class MemoryDatabasePlugIn implements PlugIn { // ----------------------------------------------------- Instance Variables /** * The application configuration for our owning sub-application. */ private ApplicationConfig config = null; /** * The {@link MemoryUserDatabase} object we construct and make available. */ private MemoryUserDatabase database = null; /** * Logging output for this plug in instance. */ private Log log = LogFactory.getLog(this.getClass()); /** * The {@link ActionServlet} owning this application. */ private ActionServlet servlet = null; // ------------------------------------------------------------- Properties /** * The web application resource path of our persistent database * storage file. */ private String pathname = "/WEB-INF/database.xml"; public String getPathname() { return (this.pathname); } public void setPathname(String pathname) { this.pathname = pathname; } // --------------------------------------------------------- PlugIn Methods /** * Gracefully shut down this database, releasing any resources * that were allocated at initialization. */ public void destroy() { log.info("Finalizing memory database plug in"); if (database != null) { try { database.close(); } catch (Exception e) { log.error("Closing memory database", e); } } servlet.getServletContext().removeAttribute(Constants.DATABASE_KEY); database = null; servlet = null; database = null; config = null; } /** * Initialize and load our initial database from persistent storage. * * @param config The ApplicationConfig for our owning sub-application * * @exception ServletException if we cannot configure ourselves correctly */ public void init(ApplicationConfig config) throws ServletException { log.info("Initializing memory database plug in from '" + pathname + "'"); // Remember our associated configuration and servlet this.config = config; this.servlet = config.getServlet(); // Construct a new database and make it available database = new MemoryUserDatabase(); try { String path = calculatePath(); if (log.isDebugEnabled()) { log.debug(" Loading database from '" + path + "'"); } database.setPathname(path); database.open(); database.save(); } catch (Exception e) { log.error("Opening memory database", e); throw new ServletException("Cannot load database from '" + pathname + "'", e); } // Make the initialized database available servlet.getServletContext().setAttribute(Constants.DATABASE_KEY, database); } // --------------------------------------------------------- Public Methods // -------------------------------------------------------- Private Methods /** * Calculate and return an absolute pathname to the XML file to contain * our persistent storage information. * * @exception Exception if an input/output error occurs */ private String calculatePath() throws Exception { // Can we access the database via file I/O? String path = servlet.getServletContext().getRealPath(pathname); if (path != null) { return (path); } // Does a copy of this file already exist in our temporary directory File dir = (File) servlet.getServletContext().getAttribute ("javax.servlet.context.tempdir"); File file = new File(dir, "struts-example-database.xml"); if (file.exists()) { return (file.getAbsolutePath()); } // Copy the static resource to a temporary file and return its path InputStream is = servlet.getServletContext().getResourceAsStream(pathname); BufferedInputStream bis = new BufferedInputStream(is, 1024); FileOutputStream os = new FileOutputStream(file); BufferedOutputStream bos = new BufferedOutputStream(os, 1024); byte buffer[] = new byte[1024]; while (true) { int n = bis.read(buffer); if (n <= 0) { break; } bos.write(buffer, 0, n); } bos.close(); bis.close(); return (file.getAbsolutePath()); } } 1.1 jakarta-struts/src/example/org/apache/struts/webapp/example/memory/MemorySubscription.java Index: MemorySubscription.java =================================================================== /* * $Header: /home/cvs/jakarta-struts/src/example/org/apache/struts/webapp/example/memory/MemorySubscription.java,v 1.1 2002/03/05 04:23:57 craigmcc Exp $ * $Revision: 1.1 $ * $Date: 2002/03/05 04:23:57 $ * * ==================================================================== * * The Apache Software License, Version 1.1 * * Copyright (c) 1999-2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Struts", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * */ package org.apache.struts.webapp.example.memory; import org.apache.struts.webapp.example.Subscription; import org.apache.struts.webapp.example.User; /** * <p>Concrete implementation of {@link Subscription} for an in-memory * database backed by an XML data file.</p> * * @author Craig R. McClanahan * @version $Revision: 1.1 $ $Date: 2002/03/05 04:23:57 $ * @since Struts 1.1 */ public final class MemorySubscription implements Subscription { // ----------------------------------------------------------- Constructors /** * <p>Construct a new Subscription associated with the specified * {@link User}. * * @param user The user with which we are associated * @param host The mail host for this subscription */ public MemorySubscription(MemoryUser user, String host) { super(); this.user = user; this.host = host; } // ----------------------------------------------------- Instance Variables /** * The mail host for this subscription. */ private String host = null; /** * The {@link User} with which we are associated. */ private MemoryUser user = null; // ------------------------------------------------------------- Properties /** * Should we auto-connect at startup time? */ private boolean autoConnect = false; public boolean getAutoConnect() { return (this.autoConnect); } public void setAutoConnect(boolean autoConnect) { this.autoConnect = autoConnect; } /** * The mail host for this subscription. */ public String getHost() { return (this.host); } /** * The password (in clear text) for this subscription. */ private String password = null; public String getPassword() { return (this.password); } public void setPassword(String password) { this.password = password; } /** * The subscription type ("imap" or "pop3"). */ private String type = "imap"; public String getType() { return (this.type); } public void setType(String type) { this.type = type; } /** * The User owning this Subscription. */ public User getUser() { return (this.user); } /** * The username for this subscription. */ private String username = null; public String getUsername() { return (this.username); } public void setUsername(String username) { this.username = username; } // --------------------------------------------------------- Public Methods /** * Return a String representation of this object. */ public String toString() { StringBuffer sb = new StringBuffer("<subscription host=\""); sb.append(host); sb.append("\" autoConnect=\""); sb.append(autoConnect); sb.append("\""); if (password != null) { sb.append(" password=\""); sb.append(password); sb.append("\""); } if (type != null) { sb.append(" type=\""); sb.append(type); sb.append("\""); } if (username != null) { sb.append(" username=\""); sb.append(username); sb.append("\""); } sb.append(">"); return (sb.toString()); } } 1.1 jakarta-struts/src/example/org/apache/struts/webapp/example/memory/MemoryUser.java Index: MemoryUser.java =================================================================== /* * $Header: /home/cvs/jakarta-struts/src/example/org/apache/struts/webapp/example/memory/MemoryUser.java,v 1.1 2002/03/05 04:23:57 craigmcc Exp $ * $Revision: 1.1 $ * $Date: 2002/03/05 04:23:57 $ * * ==================================================================== * * The Apache Software License, Version 1.1 * * Copyright (c) 1999-2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Struts", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * */ package org.apache.struts.webapp.example.memory; import java.util.HashMap; import org.apache.struts.webapp.example.Subscription; import org.apache.struts.webapp.example.User; import org.apache.struts.webapp.example.UserDatabase; /** * <p>Concrete implementation of {@link User} for an in-memory * database backed by an XML data file.</p> * * @author Craig R. McClanahan * @version $Revision: 1.1 $ $Date: 2002/03/05 04:23:57 $ * @since Struts 1.1 */ public final class MemoryUser implements User { // ----------------------------------------------------------- Constructors /** * <p>Construct a new User associated with the specified * {@link UserDatabase}. * * @param database The user database with which we are associated * @param username The username of this user */ public MemoryUser(MemoryUserDatabase database, String username) { super(); this.database = database; this.username = username; } // ----------------------------------------------------- Instance Variables /** * The {@link UserDatabase} with which we are associated. */ private MemoryUserDatabase database = null; /** * The {@link Subscription}s for this User, keyed by hostname. */ private HashMap subscriptions = new HashMap(); /** * The username for this user. */ private String username = null; // ------------------------------------------------------------- Properties /** * The {@link UserDatabase} with which we are associated. */ public UserDatabase getDatabase() { return (this.database); } /** * The email address from which messages are sent. */ private String fromAddress = null; public String getFromAddress() { return (this.fromAddress); } public void setFromAddress(String fromAddress) { this.fromAddress = fromAddress; } /** * The full name of this user, included in from addresses. */ private String fullName = null; public String getFullName() { return (this.fullName); } public void setFullName(String fullName) { this.fullName = fullName; } /** * The password (in clear text). */ private String password = null; public String getPassword() { return (this.password); } public void setPassword(String password) { this.password = password; } /** * The EMAIL address to which replies should be sent. */ private String replyToAddress = null; public String getReplyToAddress() { return (this.replyToAddress); } public void setReplyToAddress(String replyToAddress) { this.replyToAddress = replyToAddress; } /** * Find and return all {@link Subscription}s associated with this user. * If there are none, a zero-length array is returned. */ public Subscription[] getSubscriptions() { synchronized (subscriptions) { Subscription results[] = new Subscription[subscriptions.size()]; return ((Subscription[]) subscriptions.values().toArray(results)); } } /** * The username (must be unique). */ public String getUsername() { return (this.username); } // --------------------------------------------------------- Public Methods /** * Create and return a new {@link Subscription} associated with this * User, for the specified host name. * * @param host Host name for which to create a subscription * * @exception IllegalArgumentException if the host name is not unique * for this user */ public Subscription createSubscription(String host) { synchronized (subscriptions) { if (subscriptions.get(host) != null) { throw new IllegalArgumentException("Duplicate host '" + host + "' for user '" + username + "'"); } MemorySubscription subscription = new MemorySubscription(this, host); synchronized (subscriptions) { subscriptions.put(host, subscription); } return (subscription); } } /** * Find and return the {@link Subscription} associated with the specified * host. If none is found, return <code>null</code>. * * @param host Host name to look up */ public Subscription findSubscription(String host) { synchronized (subscriptions) { return ((Subscription) subscriptions.get(host)); } } /** * Remove the specified {@link Subscription} from being associated * with this User. * * @param subscription Subscription to be removed * * @exception IllegalArgumentException if the specified subscription is not * associated with this User */ public void removeSubscription(Subscription subscription) { if (!(this == subscription.getUser())) { throw new IllegalArgumentException ("Subscription not associated with this user"); } synchronized (subscriptions) { subscriptions.remove(subscription.getHost()); } } /** * Return a String representation of this object. */ public String toString() { StringBuffer sb = new StringBuffer("<user username=\""); sb.append(username); sb.append("\""); if (fromAddress != null) { sb.append(" fromAddress=\""); sb.append(fromAddress); sb.append("\""); } if (fullName != null) { sb.append(" fullName=\""); sb.append(fullName); sb.append("\""); } if (password != null) { sb.append(" password=\""); sb.append(password); sb.append("\""); } if (replyToAddress != null) { sb.append(" replyToAddress=\""); sb.append(replyToAddress); sb.append("\""); } sb.append(">"); return (sb.toString()); } } 1.1 jakarta-struts/src/example/org/apache/struts/webapp/example/memory/MemoryUserDatabase.java Index: MemoryUserDatabase.java =================================================================== /* * $Header: /home/cvs/jakarta-struts/src/example/org/apache/struts/webapp/example/memory/MemoryUserDatabase.java,v 1.1 2002/03/05 04:23:57 craigmcc Exp $ * $Revision: 1.1 $ * $Date: 2002/03/05 04:23:57 $ * * ==================================================================== * * The Apache Software License, Version 1.1 * * Copyright (c) 1999-2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Struts", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * */ package org.apache.struts.webapp.example.memory; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.util.HashMap; import org.apache.commons.digester.Digester; import org.apache.commons.digester.ObjectCreationFactory; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.struts.webapp.example.Subscription; import org.apache.struts.webapp.example.User; import org.apache.struts.webapp.example.UserDatabase; import org.xml.sax.Attributes; /** * <p>Concrete implementation of {@link UserDatabase} for an in-memory * database backed by an XML data file.</p> * * @author Craig R. McClanahan * @version $Revision: 1.1 $ $Date: 2002/03/05 04:23:57 $ * @since Struts 1.1 */ public final class MemoryUserDatabase implements UserDatabase { // ----------------------------------------------------------- Constructors // ----------------------------------------------------- Instance Variables /** * Logging output for this user database instance. */ private Log log = LogFactory.getLog(this.getClass()); /** * The {@link User}s associated with this UserDatabase, keyed by username. */ private HashMap users = new HashMap(); // ------------------------------------------------------------- Properties /** * Absolute pathname to the persistent file we use for loading and storing * persistent data. */ private String pathname = null; private String pathnameOld = null; private String pathnameNew = null; public String getPathname() { return (this.pathname); } public void setPathname(String pathname) { this.pathname = pathname; pathnameOld = pathname + ".old"; pathnameNew = pathname + ".new"; } // --------------------------------------------------------- Public Methods /** * <p>Finalize access to the underlying persistence layer.</p> * * @exception Exception if a database access error occurs */ public void close() throws Exception { save(); } /** * <p>Create and return a new {@link User} defined in this user database. * </p> * * @param username Username of the new user * * @exception IllegalArgumentExceptionif the specified username * is not unique */ public User createUser(String username) { synchronized (users) { if (users.get(username) != null) { throw new IllegalArgumentException("Duplicate user '" + username + "'"); } if (log.isTraceEnabled()) { log.trace("Creating user '" + username + "'"); } MemoryUser user = new MemoryUser(this, username); synchronized (users) { users.put(username, user); } return (user); } } /** * <p>Return the existing {@link User} with the specified username, * if any; otherwise return <code>null</code>.</p> * * @param username Username of the user to retrieve */ public User findUser(String username) { synchronized (users) { return ((User) users.get(username)); } } /** * <p>Return the set of {@link User}s defined in this user database.</p> */ public User[] findUsers() { synchronized (users) { User results[] = new User[users.size()]; return ((User[]) users.values().toArray(results)); } } /** * <p>Initiate access to the underlying persistence layer.</p> * * @exception Exception if a database access error occurs */ public void open() throws Exception { FileInputStream fis = null; BufferedInputStream bis = null; try { // Acquire an input stream to our database file if (log.isDebugEnabled()) { log.debug("Loading database from '" + pathname + "'"); } fis = new FileInputStream(pathname); bis = new BufferedInputStream(fis); // Construct a digester to use for parsing Digester digester = new Digester(); digester.push(this); digester.setValidating(false); digester.addFactoryCreate ("database/user", new MemoryUserCreationFactory(this)); digester.addFactoryCreate ("database/user/subscription", new MemorySubscriptionCreationFactory(this)); // Parse the input stream to initialize our database digester.parse(bis); bis.close(); bis = null; fis = null; } catch (Exception e) { log.error("Loading database from '" + pathname + "':", e); throw e; } finally { if (bis != null) { try { bis.close(); } catch (Throwable t) { ; } bis = null; fis = null; } } } /** * Remove the specified {@link User} from this database. * * @param user User to be removed * * @exception IllegalArgumentException if the specified user is not * associated with this database */ public void removeUser(User user) { if (!(this == user.getDatabase())) { throw new IllegalArgumentException ("User not associated with this database"); } if (log.isTraceEnabled()) { log.trace("Removing user '" + user.getUsername() + "'"); } synchronized (users) { users.remove(user.getUsername()); } } /** * <p>Save any pending changes to the underlying persistence layer.</p> * * @exception Exception if a database access error occurs */ public void save() throws Exception { if (log.isDebugEnabled()) { log.debug("Saving database to '" + pathname + "'"); } File fileNew = new File(pathnameNew); PrintWriter writer = null; try { // Configure our PrintWriter FileOutputStream fos = new FileOutputStream(fileNew); OutputStreamWriter osw = new OutputStreamWriter(fos); writer = new PrintWriter(osw); // Print the file prolog writer.println("<?xml version='1.0'?>"); writer.println("<database>"); // Print entries for each defined user and associated subscriptions User users[] = findUsers(); for (int i = 0; i < users.length; i++) { writer.print(" "); writer.println(users[i]); Subscription subscriptions[] = users[i].getSubscriptions(); for (int j = 0; j < subscriptions.length; j++) { writer.print(" "); writer.println(subscriptions[j]); writer.print(" "); writer.println("</subscription>"); } writer.print(" "); writer.println("</user>"); } // Print the file epilog writer.println("</database>"); // Check for errors that occurred while printing if (writer.checkError()) { writer.close(); fileNew.delete(); throw new IOException ("Saving database to '" + pathname + "'"); } writer.close(); writer = null; } catch (IOException e) { if (writer != null) { writer.close(); } fileNew.delete(); throw e; } // Perform the required renames to permanently save this file File fileOrig = new File(pathname); File fileOld = new File(pathnameOld); if (fileOrig.exists()) { fileOld.delete(); if (!fileOrig.renameTo(fileOld)) { throw new IOException ("Renaming '" + pathname + "' to '" + pathnameOld + "'"); } } if (!fileNew.renameTo(fileOrig)) { if (fileOld.exists()) { fileOld.renameTo(fileOrig); } throw new IOException ("Renaming '" + pathnameNew + "' to '" + pathname + "'"); } fileOld.delete(); } } /** * Digester object creation factory for subscription instances. */ class MemorySubscriptionCreationFactory implements ObjectCreationFactory { public MemorySubscriptionCreationFactory(MemoryUserDatabase database) { this.database = database; } private MemoryUserDatabase database = null; private Digester digester = null; public Digester getDigester() { return (this.digester); } public void setDigester(Digester digester) { this.digester = digester; } public Object createObject(Attributes attributes) { String host = attributes.getValue("host"); User user = (User) digester.peek(); Subscription subscription = user.createSubscription(host); String autoConnect = attributes.getValue("autoConnect"); if (autoConnect == null) { autoConnect = "false"; } if ("true".equalsIgnoreCase(autoConnect) || "yes".equalsIgnoreCase(autoConnect)) { subscription.setAutoConnect(true); } else { subscription.setAutoConnect(false); } subscription.setPassword(attributes.getValue("password")); subscription.setType(attributes.getValue("type")); subscription.setUsername(attributes.getValue("username")); return (subscription); } } /** * Digester object creation factory for user instances. */ class MemoryUserCreationFactory implements ObjectCreationFactory { public MemoryUserCreationFactory(MemoryUserDatabase database) { this.database = database; } private MemoryUserDatabase database = null; private Digester digester = null; public Digester getDigester() { return (this.digester); } public void setDigester(Digester digester) { this.digester = digester; } public Object createObject(Attributes attributes) { String username = attributes.getValue("username"); User user = database.createUser(username); user.setFromAddress(attributes.getValue("fromAddress")); user.setFullName(attributes.getValue("fullName")); user.setPassword(attributes.getValue("password")); user.setReplyToAddress(attributes.getValue("replyToAddress")); return (user); } } 1.27 +9 -1 jakarta-struts/web/example/subscription.jsp Index: subscription.jsp =================================================================== RCS file: /home/cvs/jakarta-struts/web/example/subscription.jsp,v retrieving revision 1.26 retrieving revision 1.27 diff -u -r1.26 -r1.27 --- subscription.jsp 30 Nov 2001 02:12:00 -0000 1.26 +++ subscription.jsp 5 Mar 2002 04:23:57 -0000 1.27 @@ -51,7 +51,15 @@ <bean:message key="prompt.mailHostname"/> </th> <td align="left"> - <html:textarea property="host" cols="50" rows="1"/> + <logic:equal name="subscriptionForm" property="action" + scope="request" value="Create"> + <html:text property="host" size="50"/> + </logic:equal> + <logic:notEqual name="subscriptionForm" property="action" + scope="request" value="Create"> + <bean:write name="subscriptionForm" property="host"/> + <html:hidden property="host"/> + </logic:notEqual> </td> </tr> 1.18 +1 -2 jakarta-struts/web/example/WEB-INF/struts-config.xml Index: struts-config.xml =================================================================== RCS file: /home/cvs/jakarta-struts/web/example/WEB-INF/struts-config.xml,v retrieving revision 1.17 retrieving revision 1.18 diff -u -r1.17 -r1.18 --- struts-config.xml 27 Feb 2002 06:20:59 -0000 1.17 +++ struts-config.xml 5 Mar 2002 04:23:57 -0000 1.18 @@ -167,8 +167,7 @@ <!-- ========== Plug Ins Configuration ================================== --> - <plug-in className="org.apache.struts.webapp.example.DatabasePlugIn"> - <set-property property="debug" value="9"/> + <plug-in className="org.apache.struts.webapp.example.memory.MemoryDatabasePlugIn"> <set-property property="pathname" value="/WEB-INF/database.xml"/> </plug-in>
-- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>