You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@struts.apache.org by cr...@apache.org on 2002/03/05 05:23:57 UTC

cvs commit: jakarta-struts/web/example/WEB-INF struts-config.xml

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 apache@apache.org.
   *
   * 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 apache@apache.org.
   *
   * 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 apache@apache.org.
   *
   * 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 apache@apache.org.
   *
   * 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 apache@apache.org.
   *
   * 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:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>