You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by js...@apache.org on 2001/10/30 12:14:31 UTC

cvs commit: jakarta-commons-sandbox/messenger/src/webapp/web/jms time.jsp

jstrachan    01/10/30 03:14:31

  Modified:    messenger TODO.txt build.xml
               messenger/src/conf subscribe.xml
               messenger/src/java/org/apache/commons/messagelet
                        ManagerServlet.java
               messenger/src/java/org/apache/commons/messagelet/impl
                        HttpMessageletRequestImpl.java
                        HttpServletRequestImpl.java
                        MessageletRequestImpl.java ServletRequestImpl.java
               messenger/src/webapp/conf subscriptions.xml
               messenger/src/webapp/web/jms time.jsp
  Added:       messenger/src/java/org/apache/commons/messagelet/impl
                        HttpSessionImpl.java
                        MessageHttpServletDispatcher.java RequestUtil.java
  Log:
  Added support for using HttpServlets, such as JSP, to dispatch JMS messages to for further processing
  
  Revision  Changes    Path
  1.4       +5 -0      jakarta-commons-sandbox/messenger/TODO.txt
  
  Index: TODO.txt
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/messenger/TODO.txt,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- TODO.txt	2001/10/26 14:34:57	1.3
  +++ TODO.txt	2001/10/30 11:14:30	1.4
  @@ -1,6 +1,11 @@
   Project To Do List
   ==================
   
  +* When using JSP to process JMS messages it might be nice to provide
  +  the Messenger and original Message as request Attributes that the JSP
  +  could use directly, without requiring to cast the request and response.
  +
  +
   * Allow the replyTo destination and Messenger to be overridden 
     in the XML deployment configuration for Messagelets and Servlets.
   
  
  
  
  1.22      +2 -2      jakarta-commons-sandbox/messenger/build.xml
  
  Index: build.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/messenger/build.xml,v
  retrieving revision 1.21
  retrieving revision 1.22
  diff -u -r1.21 -r1.22
  --- build.xml	2001/10/30 08:55:47	1.21
  +++ build.xml	2001/10/30 11:14:30	1.22
  @@ -1,4 +1,4 @@
  -<!-- $Id: build.xml,v 1.21 2001/10/30 08:55:47 jstrachan Exp $ -->
  +<!-- $Id: build.xml,v 1.22 2001/10/30 11:14:30 jstrachan Exp $ -->
   <project name="messenger" default="test" basedir=".">
   
      <!-- patternset describing files to be copied from the doc directory -->
  @@ -219,7 +219,7 @@
                srcdir="${source.src.java}"
                classpath="${classpath}"
                debug="false"
  -             deprecation="true"
  +             deprecation="false"
                optimize="true"/>
      </target>
   
  
  
  
  1.3       +2 -0      jakarta-commons-sandbox/messenger/src/conf/subscribe.xml
  
  Index: subscribe.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/messenger/src/conf/subscribe.xml,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- subscribe.xml	2001/10/12 16:37:08	1.2
  +++ subscribe.xml	2001/10/30 11:14:31	1.3
  @@ -1,6 +1,8 @@
   <?xml version="1.0" encoding="UTF-8"?>
   <subscriptions>
   
  +  <!-- An example of how subscriptions can look... -->
  +
     <subscription messenger="queue" destination="my.queue" selector="b='12'">
   
       <!-- the output will reply to the original message -->
  
  
  
  1.8       +13 -4     jakarta-commons-sandbox/messenger/src/java/org/apache/commons/messagelet/ManagerServlet.java
  
  Index: ManagerServlet.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/messenger/src/java/org/apache/commons/messagelet/ManagerServlet.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- ManagerServlet.java	2001/10/26 11:52:16	1.7
  +++ ManagerServlet.java	2001/10/30 11:14:31	1.8
  @@ -5,7 +5,7 @@
    * version 1.1, a copy of which has been included with this distribution in
    * the LICENSE file.
    * 
  - * $Id: ManagerServlet.java,v 1.7 2001/10/26 11:52:16 jstrachan Exp $
  + * $Id: ManagerServlet.java,v 1.8 2001/10/30 11:14:31 jstrachan Exp $
    */
   package org.apache.commons.messagelet;
   
  @@ -23,6 +23,7 @@
   import javax.servlet.ServletResponse;
   
   import org.apache.commons.messagelet.impl.MessageServletDispatcher;
  +import org.apache.commons.messagelet.impl.MessageHttpServletDispatcher;
   import org.apache.commons.messagelet.impl.Subscription;
   import org.apache.commons.messagelet.impl.SubscriptionDigester;
   import org.apache.commons.messagelet.impl.SubscriptionList;
  @@ -34,7 +35,7 @@
     * and use of MessageListener beans for a given ServletContext.</p>
     *
     * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
  -  * @version $Revision: 1.7 $
  +  * @version $Revision: 1.8 $
     */
   public class ManagerServlet extends GenericServlet {
   
  @@ -42,7 +43,10 @@
       private static final String KEY_SUBSCRIPTIONLIST = SubscriptionList.class.getName();
       private static final String KEY_CONNECTIONS = "connections";
       private static final String KEY_SUBSCRIPTIONS = "subscriptions";
  -    
  +
  +    /** Should HTTP servlets be used or generic servlets. If true then JSP can be dispatched to easily */
  +    private static final boolean USE_HTTP_SERVLETS = true;
  +
       public ManagerServlet() {
       }
       
  @@ -134,7 +138,12 @@
           MessageListener listener = null;
           String servlet = subscription.getServlet();
           if ( servlet != null ) {
  -            listener = new MessageServletDispatcher( servlet );
  +            if ( USE_HTTP_SERVLETS ) {
  +                listener = new MessageHttpServletDispatcher( servlet );
  +            }
  +            else {
  +                listener = new MessageServletDispatcher( servlet );
  +            }
           }
           else {
               listener = subscription.getMessageListener();
  
  
  
  1.2       +4 -76     jakarta-commons-sandbox/messenger/src/java/org/apache/commons/messagelet/impl/HttpMessageletRequestImpl.java
  
  Index: HttpMessageletRequestImpl.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/messenger/src/java/org/apache/commons/messagelet/impl/HttpMessageletRequestImpl.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- HttpMessageletRequestImpl.java	2001/10/29 22:32:47	1.1
  +++ HttpMessageletRequestImpl.java	2001/10/30 11:14:31	1.2
  @@ -5,7 +5,7 @@
    * version 1.1, a copy of which has been included with this distribution in
    * the LICENSE file.
    * 
  - * $Id: HttpMessageletRequestImpl.java,v 1.1 2001/10/29 22:32:47 jstrachan Exp $
  + * $Id: HttpMessageletRequestImpl.java,v 1.2 2001/10/30 11:14:31 jstrachan Exp $
    */
   package org.apache.commons.messagelet.impl;
   
  @@ -35,14 +35,12 @@
     * the request as if it were a HTTP request.</p>
     *
     * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
  -  * @version $Revision: 1.1 $
  +  * @version $Revision: 1.2 $
     */
   public class HttpMessageletRequestImpl extends HttpServletRequestWrapper implements MessageletRequest {
   
       /** The Message which caused this request */
       private Message message;
  -    /** The parameters of this request or null if they have not been parsed yet */
  -    private Map parameters;
       /** The stream to read the body of the current Message */
       private ServletInputStream stream;
       
  @@ -52,7 +50,6 @@
   
       public void setMessage(Message message) throws JMSException {
           this.message = message;
  -        this.parameters = null;
           this.stream = createInputStream();
       }
       
  @@ -76,79 +73,10 @@
           return new BufferedReader( new InputStreamReader( stream ) );
       }
   
  -
  -    /**
  -     * Return the value of the specified request parameter, if any; otherwise,
  -     * return <code>null</code>.  If there is more than one value defined,
  -     * return only the first one.
  -     *
  -     * @param name Name of the desired request parameter
  -     */
  -    public String getParameter(String name) {
  -
  -        parseParameters();
  -        String values[] = (String[]) parameters.get(name);
  -        if (values != null)
  -            return (values[0]);
  -        else
  -            return (null);
  -
  -    }
  -
  -
  -    /**
  -     * Returns a <code>Map</code> of the parameters of this request.
  -     * Request parameters are extra information sent with the request.
  -     * For HTTP servlets, parameters are contained in the query string
  -     * or posted form data.
  -     *
  -     * @return A <code>Map</code> containing parameter names as keys
  -     *  and parameter values as map values.
  -     */
  -    public Map getParameterMap() {
  -        parseParameters();
  -        return parameters;
  -    }
  -
  -
  -    /**
  -     * Return the names of all defined request parameters for this request.
  -     */
  -    public Enumeration getParameterNames() {
  -        parseParameters();
  -        return new IteratorEnumeration(parameters.keySet().iterator());
  -    }
  -
  -
  -    /**
  -     * Return the defined values for the specified request parameter, if any;
  -     * otherwise, return <code>null</code>.
  -     *
  -     * @param name Name of the desired request parameter
  -     */
  -    public String[] getParameterValues(String name) {
  -        parseParameters();
  -        String values[] = (String[]) parameters.get(name);
  -        if (values != null)
  -            return (values);
  -        else
  -            return (null);
  -    }
  -
  -
  +    
  +    
       // Implementation methods
       //-------------------------------------------------------------------------    
  -
  -
  -    /**
  -     * Parse the parameters of this request, if it has not already occurred.
  -     */
  -    protected void parseParameters() {
  -        if (parameters == null) {
  -            Map map = new HashMap();
  -            parameters = Collections.unmodifiableMap( map );
  -        }
  -    }
       
       protected ServletInputStream createInputStream() throws JMSException {
           if ( message instanceof TextMessage ) {
  
  
  
  1.2       +42 -6     jakarta-commons-sandbox/messenger/src/java/org/apache/commons/messagelet/impl/HttpServletRequestImpl.java
  
  Index: HttpServletRequestImpl.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/messenger/src/java/org/apache/commons/messagelet/impl/HttpServletRequestImpl.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- HttpServletRequestImpl.java	2001/10/29 22:32:47	1.1
  +++ HttpServletRequestImpl.java	2001/10/30 11:14:31	1.2
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-commons-sandbox/messenger/src/java/org/apache/commons/messagelet/impl/HttpServletRequestImpl.java,v 1.1 2001/10/29 22:32:47 jstrachan Exp $
  - * $Revision: 1.1 $
  - * $Date: 2001/10/29 22:32:47 $
  + * $Header: /home/cvs/jakarta-commons-sandbox/messenger/src/java/org/apache/commons/messagelet/impl/HttpServletRequestImpl.java,v 1.2 2001/10/30 11:14:31 jstrachan Exp $
  + * $Revision: 1.2 $
  + * $Date: 2001/10/30 11:14:31 $
    *
    * ====================================================================
    *
  @@ -96,7 +96,7 @@
    *
    * @author Craig R. McClanahan
    * @author James Strachan
  - * @version $Revision: 1.1 $ $Date: 2001/10/29 22:32:47 $
  + * @version $Revision: 1.2 $ $Date: 2001/10/30 11:14:31 $
    */
   
   public class HttpServletRequestImpl extends ServletRequestImpl implements HttpServletRequest {
  @@ -190,7 +190,7 @@
       /**
        * The currently active session for this request.
        */
  -    protected HttpSession session = null;
  +    protected HttpSessionImpl session = null;
   
   
       /**
  @@ -198,6 +198,11 @@
        */
       protected Principal userPrincipal = null;
   
  +    
  +    /**
  +     * The parameters 
  +     */
  +    private Map parameters = null;
   
   
       // --------------------------------------------------------- Public Methods
  @@ -332,6 +337,7 @@
       public void setQueryString(String query) {
   
           this.queryString = query;
  +        this.parameters = null;
   
       }
   
  @@ -574,6 +580,30 @@
   
   
       /**
  +     * Returns a <code>Map</code> of the parameters of this request.
  +     * Request parameters are extra information sent with the request.
  +     * For HTTP servlets, parameters are contained in the query string
  +     * or posted form data.
  +     *
  +     * @return A <code>Map</code> containing parameter names as keys
  +     *  and parameter values as map values.
  +     */
  +    public Map getParameterMap() {
  +        if ( parameters == null ) {
  +            parameters = new HashMap();
  +            if ( queryString != null ) {
  +                try {
  +                    RequestUtil.parseParameters(parameters, queryString, getCharacterEncoding());
  +                }
  +                catch (UnsupportedEncodingException e) {
  +                    servletContext.log( "Could not parse query string: " + queryString, e);
  +                }
  +            }
  +        }
  +        return parameters;
  +    }
  +
  +    /**
        * Return the path information associated with this Request.
        */
       public String getPathInfo() {
  @@ -709,8 +739,14 @@
        * @param create Create a new session if one does not exist
        */
       public HttpSession getSession(boolean create) {
  -        return (null);
  -
  +        // Return the current session if it exists and is valid
  +        if ((session != null) && !session.isValid())
  +            session = null;
  +        
  +        if ( create && session == null) {
  +            session = new HttpSessionImpl( servletContext );
  +        }
  +        return session;
       }
   
   
  
  
  
  1.4       +2 -75     jakarta-commons-sandbox/messenger/src/java/org/apache/commons/messagelet/impl/MessageletRequestImpl.java
  
  Index: MessageletRequestImpl.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/messenger/src/java/org/apache/commons/messagelet/impl/MessageletRequestImpl.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- MessageletRequestImpl.java	2001/10/29 22:32:47	1.3
  +++ MessageletRequestImpl.java	2001/10/30 11:14:31	1.4
  @@ -5,7 +5,7 @@
    * version 1.1, a copy of which has been included with this distribution in
    * the LICENSE file.
    * 
  - * $Id: MessageletRequestImpl.java,v 1.3 2001/10/29 22:32:47 jstrachan Exp $
  + * $Id: MessageletRequestImpl.java,v 1.4 2001/10/30 11:14:31 jstrachan Exp $
    */
   package org.apache.commons.messagelet.impl;
   
  @@ -34,14 +34,12 @@
     * a JMS Message source.</p>
     *
     * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
  -  * @version $Revision: 1.3 $
  +  * @version $Revision: 1.4 $
     */
   public class MessageletRequestImpl extends ServletRequestWrapper implements MessageletRequest {
   
       /** The Message which caused this request */
       private Message message;
  -    /** The parameters of this request or null if they have not been parsed yet */
  -    private Map parameters;
       /** The stream to read the body of the current Message */
       private ServletInputStream stream;
       
  @@ -51,7 +49,6 @@
   
       public void setMessage(Message message) throws JMSException {
           this.message = message;
  -        this.parameters = null;
           this.stream = createInputStream();
       }
       
  @@ -75,80 +72,10 @@
           return new BufferedReader( new InputStreamReader( stream ) );
       }
   
  -
  -    /**
  -     * Return the value of the specified request parameter, if any; otherwise,
  -     * return <code>null</code>.  If there is more than one value defined,
  -     * return only the first one.
  -     *
  -     * @param name Name of the desired request parameter
  -     */
  -    public String getParameter(String name) {
  -
  -        parseParameters();
  -        String values[] = (String[]) parameters.get(name);
  -        if (values != null)
  -            return (values[0]);
  -        else
  -            return (null);
  -
  -    }
  -
  -
  -    /**
  -     * Returns a <code>Map</code> of the parameters of this request.
  -     * Request parameters are extra information sent with the request.
  -     * For HTTP servlets, parameters are contained in the query string
  -     * or posted form data.
  -     *
  -     * @return A <code>Map</code> containing parameter names as keys
  -     *  and parameter values as map values.
  -     */
  -    public Map getParameterMap() {
  -        parseParameters();
  -        return parameters;
  -    }
  -
  -
  -    /**
  -     * Return the names of all defined request parameters for this request.
  -     */
  -    public Enumeration getParameterNames() {
  -        parseParameters();
  -        return new IteratorEnumeration(parameters.keySet().iterator());
  -    }
  -
  -
  -    /**
  -     * Return the defined values for the specified request parameter, if any;
  -     * otherwise, return <code>null</code>.
  -     *
  -     * @param name Name of the desired request parameter
  -     */
  -    public String[] getParameterValues(String name) {
  -        parseParameters();
  -        String values[] = (String[]) parameters.get(name);
  -        if (values != null)
  -            return (values);
  -        else
  -            return (null);
  -    }
  -
  -
       // Implementation methods
       //-------------------------------------------------------------------------    
   
   
  -    /**
  -     * Parse the parameters of this request, if it has not already occurred.
  -     */
  -    protected void parseParameters() {
  -        if (parameters == null) {
  -            Map map = new HashMap();
  -            parameters = Collections.unmodifiableMap( map );
  -        }
  -    }
  -    
       protected ServletInputStream createInputStream() throws JMSException {
           if ( message instanceof TextMessage ) {
               TextMessage textMessage = (TextMessage) message;
  
  
  
  1.3       +30 -8     jakarta-commons-sandbox/messenger/src/java/org/apache/commons/messagelet/impl/ServletRequestImpl.java
  
  Index: ServletRequestImpl.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/messenger/src/java/org/apache/commons/messagelet/impl/ServletRequestImpl.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- ServletRequestImpl.java	2001/10/29 22:32:47	1.2
  +++ ServletRequestImpl.java	2001/10/30 11:14:31	1.3
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-commons-sandbox/messenger/src/java/org/apache/commons/messagelet/impl/ServletRequestImpl.java,v 1.2 2001/10/29 22:32:47 jstrachan Exp $
  - * $Revision: 1.2 $
  - * $Date: 2001/10/29 22:32:47 $
  + * $Header: /home/cvs/jakarta-commons-sandbox/messenger/src/java/org/apache/commons/messagelet/impl/ServletRequestImpl.java,v 1.3 2001/10/30 11:14:31 jstrachan Exp $
  + * $Revision: 1.3 $
  + * $Date: 2001/10/30 11:14:31 $
    *
    * ====================================================================
    *
  @@ -92,7 +92,7 @@
    *
    * @author Craig R. McClanahan
    * @author James Strachan
  - * @version $Revision: 1.2 $ $Date: 2001/10/29 22:32:47 $
  + * @version $Revision: 1.3 $ $Date: 2001/10/30 11:14:31 $
    */
   
   public class ServletRequestImpl implements ServletRequest {
  @@ -464,8 +464,10 @@
        */
       public String getCharacterEncoding() {
   
  -      return (this.characterEncoding);
  -
  +        if (characterEncoding== null) {
  +            characterEncoding= "ISO-8859-1";
  +        }
  +        return (this.characterEncoding);
       }
   
   
  @@ -628,8 +630,6 @@
   
           if (reader == null) {
               String encoding = getCharacterEncoding();
  -            if (encoding == null)
  -                encoding = "ISO-8859-1";
               InputStreamReader isr =
                   new InputStreamReader(createInputStream(), encoding);
               reader = new BufferedReader(isr);
  @@ -795,8 +795,30 @@
   
           // Save the validated encoding
           this.characterEncoding = enc;
  +    }
  +
  +    /**
  +     * Log a message to the current ServletContext
  +     *
  +     * @param message Message to be logged
  +     */
  +    protected void log(String message) {
  +
  +        servletContext.log(message);
   
       }
   
  +
  +    /**
  +     * Log a message to the current ServletContext
  +     *
  +     * @param message Message to be logged
  +     * @param throwable Associated exception
  +     */
  +    protected void log(String message, Throwable throwable) {
  +
  +        servletContext.log(message, throwable);
  +
  +    }
   
   }
  
  
  
  1.1                  jakarta-commons-sandbox/messenger/src/java/org/apache/commons/messagelet/impl/HttpSessionImpl.java
  
  Index: HttpSessionImpl.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons-sandbox/messenger/src/java/org/apache/commons/messagelet/impl/HttpSessionImpl.java,v 1.1 2001/10/30 11:14:31 jstrachan Exp $
   * $Revision: 1.1 $
   * $Date: 2001/10/30 11:14:31 $
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 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", "Tomcat", 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/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */
  
  
  package org.apache.commons.messagelet.impl;
  
  
  import java.beans.PropertyChangeListener;
  import java.beans.PropertyChangeSupport;
  import java.io.IOException;
  import java.io.NotSerializableException;
  import java.io.ObjectInputStream;
  import java.io.ObjectOutputStream;
  import java.io.Serializable;
  import java.security.Principal;
  import java.util.ArrayList;
  import java.util.Enumeration;
  import java.util.HashMap;
  import java.util.Iterator;
  import javax.servlet.ServletContext;
  import javax.servlet.ServletException;
  import javax.servlet.http.HttpSession;
  import javax.servlet.http.HttpSessionActivationListener;
  import javax.servlet.http.HttpSessionAttributeListener;
  import javax.servlet.http.HttpSessionBindingEvent;
  import javax.servlet.http.HttpSessionBindingListener;
  import javax.servlet.http.HttpSessionContext;
  import javax.servlet.http.HttpSessionEvent;
  import javax.servlet.http.HttpSessionListener;
  
  import org.apache.commons.collections.IteratorEnumeration;
  
  /**
   * Based on the Catalina StandardSession class.
   * Standard implementation of the <b>HttpSession</b> interface.  This object is
   * serializable, so that it can be stored in persistent storage or transferred
   * to a different JVM for distributable session support.
   * <p>
   *
   * @author Craig R. McClanahan
   * @author Sean Legassick
   * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
   * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
   * @version $Revision: 1.1 $ $Date: 2001/10/30 11:14:31 $
   */
  
  public class HttpSessionImpl implements HttpSession, Serializable {
  
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * The dummy attribute value serialized when a NotSerializableException is
       * encountered in <code>writeObject()</code>.
       */
      private static final String NOT_SERIALIZED =
          "___NOT_SERIALIZABLE_EXCEPTION___";
  
  
      /**
       * The collection of user data attributes associated with this Session.
       */
      private HashMap attributes = new HashMap();
  
  
      /**
       * The authentication type used to authenticate our cached Principal,
       * if any.  NOTE:  This value is not included in the serialized
       * version of this object.
       */
      private transient String authType = null;
  
  
      /**
       * The time this session was created, in milliseconds since midnight,
       * January 1, 1970 GMT.
       */
      private long creationTime = 0L;
  
  
      /**
       * The debugging detail level for this component.  NOTE:  This value
       * is not included in the serialized version of this object.
       */
      private transient int debug = 0;
  
  
      /**
       * We are currently processing a session expiration, so bypass
       * certain IllegalStateException tests.  NOTE:  This value is not
       * included in the serialized version of this object.
       */
      private transient boolean expiring = false;
  
  
      /**
       * The session identifier of this Session.
       */
      private String id = null;
  
  
  
      /**
       * The last accessed time for this Session.
       */
      private long lastAccessedTime = creationTime;
  
  
      /**
       * The session event listeners for this Session.
       */
      private transient ArrayList listeners = new ArrayList();
  
  
  
      /**
       * The maximum time interval, in seconds, between client requests before
       * the servlet container may invalidate this session.  A negative time
       * indicates that the session should never time out.
       */
      private int maxInactiveInterval = -1;
  
  
      /**
       * Flag indicating whether this session is new or not.
       */
      private boolean isNew = false;
  
  
      /**
       * Flag indicating whether this session is valid or not.
       */
      private boolean isValid = false;
  
  
      /**
       * Internal notes associated with this session by Catalina components
       * and event listeners.  <b>IMPLEMENTATION NOTE:</b> This object is
       * <em>not</em> saved and restored across session serializations!
       */
      private transient HashMap notes = new HashMap();
  
  
      /**
       * The authenticated Principal associated with this session, if any.
       * <b>IMPLEMENTATION NOTE:</b>  This object is <i>not</i> saved and
       * restored across session serializations!
       */
      private transient Principal principal = null;
  
  
      /**
       * The property change support for this component.  NOTE:  This value
       * is not included in the serialized version of this object.
       */
      private transient PropertyChangeSupport support =
          new PropertyChangeSupport(this);
  
  
      /**
       * The current accessed time for this session.
       */
      private long thisAccessedTime = creationTime;
  
      /**
       * The ServletContext 
       */
      protected ServletContext servletContext;
  
      /**
       * Is this session distributable. If so then 
       * its values must be Serializable.
       */
      private boolean distributable = false;
      
      
      public HttpSessionImpl(ServletContext servletContext) {
          this.servletContext = servletContext;
      }
  
      // ----------------------------------------------------- Session Properties
  
  
      /**
       * Return the authentication type used to authenticate our cached
       * Principal, if any.
       */
      public String getAuthType() {
  
          return (this.authType);
  
      }
  
  
      /**
       * Set the authentication type used to authenticate our cached
       * Principal, if any.
       *
       * @param authType The new cached authentication type
       */
      public void setAuthType(String authType) {
  
          String oldAuthType = this.authType;
          this.authType = authType;
          support.firePropertyChange("authType", oldAuthType, this.authType);
  
      }
  
  
      /**
       * Set the creation time for this session.  This method is called by the
       * Manager when an existing Session instance is reused.
       *
       * @param time The new creation time
       */
      public void setCreationTime(long time) {
  
          this.creationTime = time;
          this.lastAccessedTime = time;
          this.thisAccessedTime = time;
  
      }
  
  
      /**
       * Return the session identifier for this session.
       */
      public String getId() {
  
          return (this.id);
  
      }
  
  
      /**
       * Set the session identifier for this session.
       *
       * @param id The new session identifier
       */
      public void setId(String id) {
  
          this.id = id;
  
          // Notify interested session event listeners
          ///fireSessionEvent(Session.SESSION_CREATED_EVENT, null);
  
      }
  
  
      /**
       * Return the last time the client sent a request associated with this
       * session, as the number of milliseconds since midnight, January 1, 1970
       * GMT.  Actions that your application takes, such as getting or setting
       * a value associated with the session, do not affect the access time.
       */
      public long getLastAccessedTime() {
  
          return (this.lastAccessedTime);
  
      }
  
  
      /**
       * Return the maximum time interval, in seconds, between client requests
       * before the servlet container will invalidate the session.  A negative
       * time indicates that the session should never time out.
       *
       * @exception IllegalStateException if this method is called on
       *  an invalidated session
       */
      public int getMaxInactiveInterval() {
  
          if (!isValid) {
              throw new IllegalStateException( "Cannot call getMaxInactiveInterval on an invalidated session" );
          }
  
          return (this.maxInactiveInterval);
  
      }
  
  
      /**
       * Set the maximum time interval, in seconds, between client requests
       * before the servlet container will invalidate the session.  A negative
       * time indicates that the session should never time out.
       *
       * @param interval The new maximum interval
       */
      public void setMaxInactiveInterval(int interval) {
  
          this.maxInactiveInterval = interval;
  
      }
  
  
      /**
       * Set the <code>isNew</code> flag for this session.
       *
       * @param isNew The new value for the <code>isNew</code> flag
       */
      public void setNew(boolean isNew) {
  
          this.isNew = isNew;
  
      }
  
  
      /**
       * Return the authenticated Principal that is associated with this Session.
       * This provides an <code>Authenticator</code> with a means to cache a
       * previously authenticated Principal, and avoid potentially expensive
       * <code>Realm.authenticate()</code> calls on every request.  If there
       * is no current associated Principal, return <code>null</code>.
       */
      public Principal getPrincipal() {
  
          return (this.principal);
  
      }
  
  
      /**
       * Set the authenticated Principal that is associated with this Session.
       * This provides an <code>Authenticator</code> with a means to cache a
       * previously authenticated Principal, and avoid potentially expensive
       * <code>Realm.authenticate()</code> calls on every request.
       *
       * @param principal The new Principal, or <code>null</code> if none
       */
      public void setPrincipal(Principal principal) {
  
          Principal oldPrincipal = this.principal;
          this.principal = principal;
          support.firePropertyChange("principal", oldPrincipal, this.principal);
  
      }
  
  
  
      /**
       * Return the <code>isValid</code> flag for this session.
       */
      public boolean isValid() {
  
          return (this.isValid);
  
      }
  
  
      /**
       * Set the <code>isValid</code> flag for this session.
       *
       * @param isValid The new value for the <code>isValid</code> flag
       */
      public void setValid(boolean isValid) {
  
          this.isValid = isValid;
      }
  
  
      // ------------------------------------------------- Session Public Methods
  
  
      /**
       * Update the accessed time information for this session.  This method
       * should be called by the context when a request comes in for a particular
       * session, even if the application does not reference it.
       */
      public void access() {
  
          this.isNew = false;
          this.lastAccessedTime = this.thisAccessedTime;
          this.thisAccessedTime = System.currentTimeMillis();
  
      }
  
  
  
      /**
       * Perform the internal processing required to invalidate this session,
       * without triggering an exception if the session has already expired.
       */
      public void expire() {
  
          // Mark this session as "being expired" if needed
          if (expiring)
              return;
          expiring = true;
          setValid(false);
  
          // Unbind any objects associated with this session
          String keys[] = keys();
          for (int i = 0; i < keys.length; i++)
              removeAttribute(keys[i]);
  
          // Notify interested session event listeners
          //fireSessionEvent(Session.SESSION_DESTROYED_EVENT, null);
  
          // We have completed expire of this session
          expiring = false;
      }
  
  
      /**
       * Perform the internal processing required to passivate
       * this session.
       */
      public void passivate() {
  
          // Notify ActivationListeners
          HttpSessionEvent event = null;
          String keys[] = keys();
          for (int i = 0; i < keys.length; i++) {
              Object attribute = getAttribute(keys[i]);
              if (attribute instanceof HttpSessionActivationListener) {
                  if (event == null)
                      event = new HttpSessionEvent(this);
                  // FIXME: Should we catch throwables?
                  ((HttpSessionActivationListener)attribute).sessionWillPassivate(event);
              }
          }
  
      }
  
  
      /**
       * Perform internal processing required to activate this
       * session.
       */
      public void activate() {
  
          // Notify ActivationListeners
          HttpSessionEvent event = null;
          String keys[] = keys();
          for (int i = 0; i < keys.length; i++) {
              Object attribute = getAttribute(keys[i]);
              if (attribute instanceof HttpSessionActivationListener) {
                  if (event == null)
                      event = new HttpSessionEvent(this);
                  // FIXME: Should we catch throwables?
                  ((HttpSessionActivationListener)attribute).sessionDidActivate(event);
              }
          }
  
      }
  
  
      /**
       * Return the object bound with the specified name to the internal notes
       * for this session, or <code>null</code> if no such binding exists.
       *
       * @param name Name of the note to be returned
       */
      public Object getNote(String name) {
  
          synchronized (notes) {
              return (notes.get(name));
          }
  
      }
  
  
      /**
       * Return an Iterator containing the String names of all notes bindings
       * that exist for this session.
       */
      public Iterator getNoteNames() {
  
          synchronized (notes) {
              return (notes.keySet().iterator());
          }
  
      }
  
  
      /**
       * Release all object references, and initialize instance variables, in
       * preparation for reuse of this object.
       */
      public void recycle() {
  
          // Reset the instance variables associated with this Session
          attributes.clear();
          setAuthType(null);
          creationTime = 0L;
          expiring = false;
          id = null;
          lastAccessedTime = 0L;
          maxInactiveInterval = -1;
          setPrincipal(null);
          isNew = false;
          isValid = false;
      }
  
  
      /**
       * Remove any object bound to the specified name in the internal notes
       * for this session.
       *
       * @param name Name of the note to be removed
       */
      public void removeNote(String name) {
  
          synchronized (notes) {
              notes.remove(name);
          }
  
      }
  
  
  
      /**
       * Bind an object to a specified name in the internal notes associated
       * with this session, replacing any existing binding for this name.
       *
       * @param name Name to which the object should be bound
       * @param value Object to be bound to the specified name
       */
      public void setNote(String name, Object value) {
  
          synchronized (notes) {
              notes.put(name, value);
          }
  
      }
  
  
      /**
       * Return a string representation of this object.
       */
      public String toString() {
  
          StringBuffer sb = new StringBuffer();
          sb.append("StandardSession[");
          sb.append(id);
          sb.append("]");
          return (sb.toString());
  
      }
  
  
      // ------------------------------------------------ Session Package Methods
  
  
      /**
       * Read a serialized version of the contents of this session object from
       * the specified object input stream, without requiring that the
       * StandardSession itself have been serialized.
       *
       * @param stream The object input stream to read from
       *
       * @exception ClassNotFoundException if an unknown class is specified
       * @exception IOException if an input/output error occurs
       */
      void readObjectData(ObjectInputStream stream)
          throws ClassNotFoundException, IOException {
  
          readObject(stream);
  
      }
  
  
      /**
       * Write a serialized version of the contents of this session object to
       * the specified object output stream, without requiring that the
       * StandardSession itself have been serialized.
       *
       * @param stream The object output stream to write to
       *
       * @exception IOException if an input/output error occurs
       */
      void writeObjectData(ObjectOutputStream stream)
          throws IOException {
  
          writeObject(stream);
  
      }
  
  
      // ------------------------------------------------- HttpSession Properties
  
  
      /**
       * Return the time when this session was created, in milliseconds since
       * midnight, January 1, 1970 GMT.
       *
       * @exception IllegalStateException if this method is called on an
       *  invalidated session
       */
      public long getCreationTime() {
  
          if (!isValid) {
              throw new IllegalStateException( "Cannot call getCreationTime() on invalidated session" );
          }
  
          return (this.creationTime);
  
      }
  
  
      /**
       * Return the ServletContext to which this session belongs.
       */
      public ServletContext getServletContext() {
          return servletContext;
  
      }
  
  
      /**
       * Return the session context with which this session is associated.
       *
       * @deprecated As of Version 2.1, this method is deprecated and has no
       *  replacement.  It will be removed in a future version of the
       *  Java Servlet API.
       */
      public HttpSessionContext getSessionContext() {
  
          return null;
  
      }
  
  
      // ----------------------------------------------HttpSession Public Methods
  
  
      /**
       * Return the object bound with the specified name in this session, or
       * <code>null</code> if no object is bound with that name.
       *
       * @param name Name of the attribute to be returned
       *
       * @exception IllegalStateException if this method is called on an
       *  invalidated session
       */
      public Object getAttribute(String name) {
  
          if (!isValid) {
              throw new IllegalStateException( "Cannot call getAttribute() on invalidated session" );
          }
  
          synchronized (attributes) {
              return (attributes.get(name));
          }
  
      }
  
  
      /**
       * Return an <code>Enumeration</code> of <code>String</code> objects
       * containing the names of the objects bound to this session.
       *
       * @exception IllegalStateException if this method is called on an
       *  invalidated session
       */
      public Enumeration getAttributeNames() {
  
          if (!isValid) {
              throw new IllegalStateException( "Cannot call getAttributeNames() on invalidated session" );
          }
  
          synchronized (attributes) {
              return (new IteratorEnumeration(attributes.keySet().iterator()));
          }
  
      }
  
  
      /**
       * Return the object bound with the specified name in this session, or
       * <code>null</code> if no object is bound with that name.
       *
       * @param name Name of the value to be returned
       *
       * @exception IllegalStateException if this method is called on an
       *  invalidated session
       *
       * @deprecated As of Version 2.2, this method is replaced by
       *  <code>getAttribute()</code>
       */
      public Object getValue(String name) {
  
          return (getAttribute(name));
  
      }
  
  
      /**
       * Return the set of names of objects bound to this session.  If there
       * are no such objects, a zero-length array is returned.
       *
       * @exception IllegalStateException if this method is called on an
       *  invalidated session
       *
       * @deprecated As of Version 2.2, this method is replaced by
       *  <code>getAttributeNames()</code>
       */
      public String[] getValueNames() {
  
          if (!isValid) {
              throw new IllegalStateException( "Cannot call getValueNames() on invalidated session" );
          }
  
          return (keys());
  
      }
  
  
      /**
       * Invalidates this session and unbinds any objects bound to it.
       *
       * @exception IllegalStateException if this method is called on
       *  an invalidated session
       */
      public void invalidate() {
  
          if (!isValid) {
              throw new IllegalStateException( "Cannot call invalidate() on invalidated session" );
          }
  
          // Cause this session to expire
          expire();
  
      }
  
  
      /**
       * Return <code>true</code> if the client does not yet know about the
       * session, or if the client chooses not to join the session.  For
       * example, if the server used only cookie-based sessions, and the client
       * has disabled the use of cookies, then a session would be new on each
       * request.
       *
       * @exception IllegalStateException if this method is called on an
       *  invalidated session
       */
      public boolean isNew() {
  
          if (!isValid) {
              throw new IllegalStateException( "Cannot call isNew() on invalidated session" );
          }
  
          return (this.isNew);
  
      }
  
  
      /**
       * Bind an object to this session, using the specified name.  If an object
       * of the same name is already bound to this session, the object is
       * replaced.
       * <p>
       * After this method executes, and if the object implements
       * <code>HttpSessionBindingListener</code>, the container calls
       * <code>valueBound()</code> on the object.
       *
       * @param name Name to which the object is bound, cannot be null
       * @param value Object to be bound, cannot be null
       *
       * @exception IllegalStateException if this method is called on an
       *  invalidated session
       *
       * @deprecated As of Version 2.2, this method is replaced by
       *  <code>setAttribute()</code>
       */
      public void putValue(String name, Object value) {
  
          setAttribute(name, value);
  
      }
  
  
      /**
       * Remove the object bound with the specified name from this session.  If
       * the session does not have an object bound with this name, this method
       * does nothing.
       * <p>
       * After this method executes, and if the object implements
       * <code>HttpSessionBindingListener</code>, the container calls
       * <code>valueUnbound()</code> on the object.
       *
       * @param name Name of the object to remove from this session.
       *
       * @exception IllegalStateException if this method is called on an
       *  invalidated session
       */
      public void removeAttribute(String name) {
  
          // Validate our current state
          if (!expiring && !isValid) { 
              throw new IllegalStateException( "Cannot call removeAttribute() on an invalidated session" );
          }
  
          // Remove this attribute from our collection
          Object value = null;
          boolean found = false;
          synchronized (attributes) {
              found = attributes.containsKey(name);
              if (found) {
                  value = attributes.get(name);
                  attributes.remove(name);
              } else {
                  return;
              }
          }
  /*
          // Call the valueUnbound() method if necessary
          HttpSessionBindingEvent event =
            new HttpSessionBindingEvent((HttpSession) this, name, value);
          if ((value != null) &&
              (value instanceof HttpSessionBindingListener))
              ((HttpSessionBindingListener) value).valueUnbound(event);
  
          // Notify interested application event listeners
          StandardContext context = (StandardContext) manager.getContainer();
          Object listeners[] = context.getApplicationListeners();
          if (listeners == null)
              return;
          for (int i = 0; i < listeners.length; i++) {
              if (!(listeners[i] instanceof HttpSessionAttributeListener))
                  continue;
              HttpSessionAttributeListener listener =
                  (HttpSessionAttributeListener) listeners[i];
              try {
                  context.fireContainerEvent("beforeSessionAttributeRemoved",
                                             listener);
                  listener.attributeRemoved(event);
                  context.fireContainerEvent("afterSessionAttributeRemoved",
                                             listener);
              } catch (Throwable t) {
                  context.fireContainerEvent("afterSessionAttributeRemoved",
                                             listener);
                  // FIXME - should we do anything besides log these?
                  log( "Exception firing attribute event", t);
              }
          }
  */
      }
  
  
      /**
       * Remove the object bound with the specified name from this session.  If
       * the session does not have an object bound with this name, this method
       * does nothing.
       * <p>
       * After this method executes, and if the object implements
       * <code>HttpSessionBindingListener</code>, the container calls
       * <code>valueUnbound()</code> on the object.
       *
       * @param name Name of the object to remove from this session.
       *
       * @exception IllegalStateException if this method is called on an
       *  invalidated session
       *
       * @deprecated As of Version 2.2, this method is replaced by
       *  <code>removeAttribute()</code>
       */
      public void removeValue(String name) {
  
          removeAttribute(name);
  
      }
  
  
      /**
       * Bind an object to this session, using the specified name.  If an object
       * of the same name is already bound to this session, the object is
       * replaced.
       * <p>
       * After this method executes, and if the object implements
       * <code>HttpSessionBindingListener</code>, the container calls
       * <code>valueBound()</code> on the object.
       *
       * @param name Name to which the object is bound, cannot be null
       * @param value Object to be bound, cannot be null
       *
       * @exception IllegalArgumentException if an attempt is made to add a
       *  non-serializable object in an environment marked distributable.
       * @exception IllegalStateException if this method is called on an
       *  invalidated session
       */
      public void setAttribute(String name, Object value) {
  
          // Name cannot be null
          if (name == null) {
              throw new IllegalArgumentException( "Attribute name cannot be null" );
          }
  
          // Null value is the same as removeAttribute()
          if (value == null) {
              removeAttribute(name);
              return;
          }
  
          // Validate our current state
          if (!isValid) {
              throw new IllegalStateException( "You cannot call this method on an invalidated session" );
          }
          if (distributable &&
              !(value instanceof Serializable)) {
              throw new IllegalArgumentException( "Attribute value must be Serializable" );
          }
  
          // Replace or add this attribute
          Object unbound = null;
          synchronized (attributes) {
              unbound = attributes.get(name);
              attributes.put(name, value);
          }
  
          // Call the valueUnbound() method if necessary
          if ((unbound != null) &&
              (unbound instanceof HttpSessionBindingListener)) {
              ((HttpSessionBindingListener) unbound).valueUnbound
                (new HttpSessionBindingEvent((HttpSession) this, name));
          }
  
          // Call the valueBound() method if necessary
          HttpSessionBindingEvent event = null;
          if (unbound != null)
              event = new HttpSessionBindingEvent
                  ((HttpSession) this, name, unbound);
          else
              event = new HttpSessionBindingEvent
                  ((HttpSession) this, name, value);
          if (value instanceof HttpSessionBindingListener)
              ((HttpSessionBindingListener) value).valueBound(event);
  
          // Notify interested application event listeners
  /*        
          StandardContext context = (StandardContext) manager.getContainer();
          Object listeners[] = context.getApplicationListeners();
          if (listeners == null)
              return;
          for (int i = 0; i < listeners.length; i++) {
              if (!(listeners[i] instanceof HttpSessionAttributeListener))
                  continue;
              HttpSessionAttributeListener listener =
                  (HttpSessionAttributeListener) listeners[i];
              try {
                  if (unbound != null) {
                      context.fireContainerEvent("beforeSessionAttributeReplaced",
                                                 listener);
                      listener.attributeReplaced(event);
                      context.fireContainerEvent("afterSessionAttributeReplaced",
                                                 listener);
                  } else {
                      context.fireContainerEvent("beforeSessionAttributeAdded",
                                                 listener);
                      listener.attributeAdded(event);
                      context.fireContainerEvent("afterSessionAttributeAdded",
                                                 listener);
                  }
              } catch (Throwable t) {
                  if (unbound != null)
                      context.fireContainerEvent("afterSessionAttributeReplaced",
                                                 listener);
                  else
                      context.fireContainerEvent("afterSessionAttributeAdded",
                                                 listener);
                  // FIXME - should we do anything besides log these?
                  log( "Exception firing attribute event", t);
              }
          }
  */
      }
  
  
      // -------------------------------------------- HttpSession Private Methods
  
  
      /**
       * Read a serialized version of this session object from the specified
       * object input stream.
       * <p>
       * <b>IMPLEMENTATION NOTE</b>:  The reference to the owning Manager
       * is not restored by this method, and must be set explicitly.
       *
       * @param stream The input stream to read from
       *
       * @exception ClassNotFoundException if an unknown class is specified
       * @exception IOException if an input/output error occurs
       */
      private void readObject(ObjectInputStream stream)
          throws ClassNotFoundException, IOException {
  
          // Deserialize the scalar instance variables (except Manager)
          authType = null;        // Transient only
          creationTime = ((Long) stream.readObject()).longValue();
          lastAccessedTime = ((Long) stream.readObject()).longValue();
          maxInactiveInterval = ((Integer) stream.readObject()).intValue();
          isNew = ((Boolean) stream.readObject()).booleanValue();
          isValid = ((Boolean) stream.readObject()).booleanValue();
          thisAccessedTime = ((Long) stream.readObject()).longValue();
          principal = null;        // Transient only
          setId((String) stream.readObject());
          if (debug >= 2)
              log("readObject() loading session " + id);
  
          // Deserialize the attribute count and attribute values
          if (attributes == null)
              attributes = new HashMap();
          int n = ((Integer) stream.readObject()).intValue();
          boolean isValidSave = isValid;
          isValid = true;
          for (int i = 0; i < n; i++) {
              String name = (String) stream.readObject();
              Object value = (Object) stream.readObject();
              if ((value instanceof String) && (value.equals(NOT_SERIALIZED)))
                  continue;
              if (debug >= 2)
                  log("  loading attribute '" + name +
                      "' with value '" + value + "'");
              synchronized (attributes) {
                  attributes.put(name, value);
              }
          }
          isValid = isValidSave;
  
      }
  
  
      /**
       * Write a serialized version of this session object to the specified
       * object output stream.
       * <p>
       * <b>IMPLEMENTATION NOTE</b>:  The owning Manager will not be stored
       * in the serialized representation of this Session.  After calling
       * <code>readObject()</code>, you must set the associated Manager
       * explicitly.
       * <p>
       * <b>IMPLEMENTATION NOTE</b>:  Any attribute that is not Serializable
       * will be unbound from the session, with appropriate actions if it
       * implements HttpSessionBindingListener.  If you do not want any such
       * attributes, be sure the <code>distributable</code> property of the
       * associated Manager is set to <code>true</code>.
       *
       * @param stream The output stream to write to
       *
       * @exception IOException if an input/output error occurs
       */
      private void writeObject(ObjectOutputStream stream) throws IOException {
  
          // Write the scalar instance variables (except Manager)
          stream.writeObject(new Long(creationTime));
          stream.writeObject(new Long(lastAccessedTime));
          stream.writeObject(new Integer(maxInactiveInterval));
          stream.writeObject(new Boolean(isNew));
          stream.writeObject(new Boolean(isValid));
          stream.writeObject(new Long(thisAccessedTime));
          stream.writeObject(id);
          if (debug >= 2)
              log("writeObject() storing session " + id);
  
          // Accumulate the names of serializable and non-serializable attributes
          String keys[] = keys();
          ArrayList saveNames = new ArrayList();
          ArrayList saveValues = new ArrayList();
          ArrayList unbinds = new ArrayList();
          for (int i = 0; i < keys.length; i++) {
              Object value = null;
              synchronized (attributes) {
                  value = attributes.get(keys[i]);
              }
              if (value == null)
                  continue;
              else if (value instanceof Serializable) {
                  saveNames.add(keys[i]);
                  saveValues.add(value);
              } else
                  unbinds.add(keys[i]);
          }
  
          // Serialize the attribute count and the Serializable attributes
          int n = saveNames.size();
          stream.writeObject(new Integer(n));
          for (int i = 0; i < n; i++) {
              stream.writeObject((String) saveNames.get(i));
              try {
                  stream.writeObject(saveValues.get(i));
                  if (debug >= 2)
                      log("  storing attribute '" + saveNames.get(i) +
                          "' with value '" + saveValues.get(i) + "'");
              } catch (NotSerializableException e) {
                  log( "Session is not serializable for attribute name: " + saveNames.get(i) + " and session id: " + id, e);
                  stream.writeObject(NOT_SERIALIZED);
                  if (debug >= 2)
                      log("  storing attribute '" + saveNames.get(i) +
                          "' with value NOT_SERIALIZED");
                  unbinds.add(saveNames.get(i));
              }
          }
  
          // Unbind the non-Serializable attributes
          Iterator names = unbinds.iterator();
          while (names.hasNext()) {
              removeAttribute((String) names.next());
          }
  
      }
  
  
      // -------------------------------------------------------- Private Methods
  
  
      /**
       * Notify all session event listeners that a particular event has
       * occurred for this Session.  The default implementation performs
       * this notification synchronously using the calling thread.
       *
       * @param type Event type
       * @param data Event data
       */
      public void fireSessionEvent(String type, Object data) {
  /*    
          if (listeners.size() < 1)
              return;
          SessionEvent event = new SessionEvent(this, type, data);
          SessionListener list[] = new SessionListener[0];
          synchronized (listeners) {
              list = (SessionListener[]) listeners.toArray(list);
          }
          for (int i = 0; i < list.length; i++)
              ((SessionListener) list[i]).sessionEvent(event);
  */
      }
  
  
      /**
       * Return the names of all currently defined session attributes
       * as an array of Strings.  If there are no defined attributes, a
       * zero-length array is returned.
       */
      private String[] keys() {
  
          String results[] = new String[0];
          synchronized (attributes) {
              return ((String[]) attributes.keySet().toArray(results));
          }
  
      }
  
  
      /**
       * Log a message to the current ServletContext
       *
       * @param message Message to be logged
       */
      protected void log(String message) {
  
          servletContext.log(message);
  
      }
  
  
      /**
       * Log a message to the current ServletContext
       *
       * @param message Message to be logged
       * @param throwable Associated exception
       */
      protected void log(String message, Throwable throwable) {
  
          servletContext.log(message, throwable);
  
      }
  
  
  }
  
  
  
  1.1                  jakarta-commons-sandbox/messenger/src/java/org/apache/commons/messagelet/impl/MessageHttpServletDispatcher.java
  
  Index: MessageHttpServletDispatcher.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   * 
   * $Id: MessageHttpServletDispatcher.java,v 1.1 2001/10/30 11:14:31 jstrachan Exp $
   */
  package org.apache.commons.messagelet.impl;
  
  import javax.jms.Destination;
  import javax.jms.Message;
  import javax.jms.MessageListener;
  import javax.jms.JMSException;
  import javax.servlet.ServletContext;
  import javax.servlet.ServletException;
  
  import org.apache.commons.messagelet.MessageDrivenObjectSupport;
  import org.apache.commons.messenger.Messenger;
  import org.apache.commons.messenger.MessengerListener;
  
  /** <p><code>MessageHttpServletDispatcher</code> dispatches JMS Messages
    * into a HttpServlet for procesing.</p>
    *
    * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
    * @version $Revision: 1.1 $
    */
  public class MessageHttpServletDispatcher extends MessageDrivenObjectSupport implements MessengerListener {
  
      /**
       * The HttpServletRequest object we will pass to the servlet engine
       */
      private HttpMessageletRequestImpl request;
  
      /**
       * The HttpServletResponse object we will pass to the servlet engine
       */
      private HttpMessageletResponseImpl response;
      
      /** 
       * The reply to messenger
       */
      private Messenger messenger;
      
      /** Holds value of property path. */
      private String path;    
  
      
      public MessageHttpServletDispatcher() {
          //request.setResponse(response);
          //response.setRequest(request);        
      }
  
      public MessageHttpServletDispatcher(String path) {
          this();
          this.path = path;
      }
  
      
      public void init() throws ServletException {
          request = new HttpMessageletRequestImpl( createHttpServletRequest() );
          response = new HttpMessageletResponseImpl( new HttpServletResponseImpl() );
      }
      
      // MessengerListener methods
      //-------------------------------------------------------------------------        
      public void setMessenger(Messenger messenger) {
          response.setReplyMessenger( messenger );
      }
  
      /**
       * Process the incoming JMS Message.
       *
       * @param message is the message to be processed
       */
      public void onMessage(Message message) {
          try {
              response.setReplyToDestination( message.getJMSReplyTo() );
          }
          catch (JMSException e) {
              log( "Could not find JMS replyTo destination", e );
              response.setReplyToDestination( null );
          }
              
          // Ask our Container to process this request
          try {
              // initialise the request
              request.setMessage( message );
              response.reset();
              
              // dispatch the servlet
              getServletContext().getRequestDispatcher( getPath() ).include(request, response);
              
              // finish up the response, sending a reply if necessary
              response.finish();
          } 
          catch (Throwable e) {
              handleException( message, e );
          }
      }
  
      
      // Properties
      //-------------------------------------------------------------------------        
      /** Getter for property path.
       * @return Value of property path.
       */ 
      public String getPath() {
          return path;
      }
      
      /** Setter for property path.
       * @param path New value of property path.
       */
      public void setPath(String path) {
          this.path = path;
          
          //request.setRequestURI(path);
      }
      
      
      
      // Implementation methods
      //-------------------------------------------------------------------------        
      protected void handleException(Message message, Throwable t) {
          log( "Caught exception processing message: " + message, t);
      }
      
      protected HttpServletRequestImpl createHttpServletRequest() {
          HttpServletRequestImpl request = new HttpServletRequestImpl( getServletContext() );
          request.setRequestURI( path );
          int idx = path.indexOf( '?' );
          if ( idx >= 0 ) {
              request.setQueryString( path.substring( idx + 1 ) );
              request.setPathInfo( path.substring( 0, idx ) );        
          }
          return request;
      }
  }
  
  
  
  1.1                  jakarta-commons-sandbox/messenger/src/java/org/apache/commons/messagelet/impl/RequestUtil.java
  
  Index: RequestUtil.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons-sandbox/messenger/src/java/org/apache/commons/messagelet/impl/RequestUtil.java,v 1.1 2001/10/30 11:14:31 jstrachan Exp $
   * $Revision: 1.1 $
   * $Date: 2001/10/30 11:14:31 $
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 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", "Tomcat", 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/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */
  
  
  package org.apache.commons.messagelet.impl;
  
  import java.io.UnsupportedEncodingException;
  import java.text.SimpleDateFormat;
  import java.util.ArrayList;
  import java.util.Date;
  import java.util.Map;
  import java.util.TimeZone;
  import javax.servlet.http.Cookie;
  
  
  /**
   * General purpose request parsing and encoding utility methods.
   *
   * @author Craig R. McClanahan
   * @author Tim Tye
   * @version $Revision: 1.1 $ $Date: 2001/10/30 11:14:31 $
   */
  
  public final class RequestUtil {
  
  
      /**
       * The DateFormat to use for generating readable dates in cookies.
       */
      private static SimpleDateFormat format =
          new SimpleDateFormat(" EEEE, dd-MMM-yy kk:mm:ss zz");
  
      static {
          format.setTimeZone(TimeZone.getTimeZone("GMT"));
      }
  
  
      /**
       * Encode a cookie as per RFC 2109.  The resulting string can be used
       * as the value for a <code>Set-Cookie</code> header.
       *
       * @param cookie The cookie to encode.
       * @return A string following RFC 2109.
       */
      public static String encodeCookie(Cookie cookie) {
  
          StringBuffer buf = new StringBuffer( cookie.getName() );
          buf.append("=");
          buf.append(cookie.getValue());
  
          if (cookie.getComment() != null) {
              buf.append("; Comment=\"");
              buf.append(cookie.getComment());
              buf.append("\"");
          }
  
          if (cookie.getDomain() != null) {
              buf.append("; Domain=\"");
              buf.append(cookie.getDomain());
              buf.append("\"");
          }
  
          long age = cookie.getMaxAge();
          if (cookie.getMaxAge() >= 0) {
              buf.append("; Max-Age=\"");
              buf.append(cookie.getMaxAge());
              buf.append("\"");
          }
  
          if (cookie.getPath() != null) {
              buf.append("; Path=\"");
              buf.append(cookie.getPath());
              buf.append("\"");
          }
  
          if (cookie.getSecure()) {
              buf.append("; Secure");
          }
  
          if (cookie.getVersion() > 0) {
              buf.append("; Version=\"");
              buf.append(cookie.getVersion());
              buf.append("\"");
          }
  
          return (buf.toString());
      }
  
  
      /**
       * Filter the specified message string for characters that are sensitive
       * in HTML.  This avoids potential attacks caused by including JavaScript
       * codes in the request URL that is often reported in error messages.
       *
       * @param message The message string to be filtered
       */
      public static String filter(String message) {
  
          if (message == null)
              return (null);
  
          char content[] = new char[message.length()];
          message.getChars(0, message.length(), content, 0);
          StringBuffer result = new StringBuffer(content.length + 50);
          for (int i = 0; i < content.length; i++) {
              switch (content[i]) {
              case '<':
                  result.append("&lt;");
                  break;
              case '>':
                  result.append("&gt;");
                  break;
              case '&':
                  result.append("&amp;");
                  break;
              case '"':
                  result.append("&quot;");
                  break;
              default:
                  result.append(content[i]);
              }
          }
          return (result.toString());
  
      }
  
  
      /**
       * Normalize a relative URI path that may have relative values ("/./",
       * "/../", and so on ) it it.  <strong>WARNING</strong> - This method is
       * useful only for normalizing application-generated paths.  It does not
       * try to perform security checks for malicious input.
       *
       * @param path Relative path to be normalized
       */
      public static String normalize(String path) {
  
          if (path == null)
              return null;
  
          // Create a place for the normalized path
          String normalized = path;
  
          if (normalized.equals("/."))
              return "/";
  
          // Add a leading "/" if necessary
          if (!normalized.startsWith("/"))
              normalized = "/" + normalized;
  
          // Resolve occurrences of "//" in the normalized path
          while (true) {
              int index = normalized.indexOf("//");
              if (index < 0)
                  break;
              normalized = normalized.substring(0, index) +
                  normalized.substring(index + 1);
          }
  
          // Resolve occurrences of "/./" in the normalized path
          while (true) {
              int index = normalized.indexOf("/./");
              if (index < 0)
                  break;
              normalized = normalized.substring(0, index) +
                  normalized.substring(index + 2);
          }
  
          // Resolve occurrences of "/../" in the normalized path
          while (true) {
              int index = normalized.indexOf("/../");
              if (index < 0)
                  break;
              if (index == 0)
                  return (null);  // Trying to go outside our context
              int index2 = normalized.lastIndexOf('/', index - 1);
              normalized = normalized.substring(0, index2) +
                  normalized.substring(index + 3);
          }
  
          // Return the normalized path that we have completed
          return (normalized);
  
      }
  
  
      /**
       * Parse the character encoding from the specified content type header.
       * If the content type is null, or there is no explicit character encoding,
       * <code>null</code> is returned.
       *
       * @param contentType a content type header
       */
      public static String parseCharacterEncoding(String contentType) {
  
          if (contentType == null)
              return (null);
          int start = contentType.indexOf("charset=");
          if (start < 0)
              return (null);
          String encoding = contentType.substring(start + 8);
          int end = encoding.indexOf(';');
          if (end >= 0)
              encoding = encoding.substring(0, end);
          encoding = encoding.trim();
          if ((encoding.length() > 2) && (encoding.startsWith("\""))
              && (encoding.endsWith("\"")))
              encoding = encoding.substring(1, encoding.length() - 1);
          return (encoding.trim());
  
      }
  
  
      /**
       * Parse a cookie header into an array of cookies according to RFC 2109.
       *
       * @param header Value of an HTTP "Cookie" header
       */
      public static Cookie[] parseCookieHeader(String header) {
  
          if ((header == null) || (header.length() < 1))
              return (new Cookie[0]);
  
          ArrayList cookies = new ArrayList();
          while (header.length() > 0) {
              int semicolon = header.indexOf(';');
              if (semicolon < 0)
                  semicolon = header.length();
              if (semicolon == 0)
                  break;
              String token = header.substring(0, semicolon);
              if (semicolon < header.length())
                  header = header.substring(semicolon + 1);
              else
                  header = "";
              try {
                  int equals = token.indexOf('=');
                  if (equals > 0) {
                      String name = URLDecode(token.substring(0, equals).trim());
                      String value = URLDecode(token.substring(equals+1).trim());
                      cookies.add(new Cookie(name, value));
                  }
              } catch (Throwable e) {
                  ;
              }
          }
  
          return ((Cookie[]) cookies.toArray(new Cookie[cookies.size()]));
  
      }
  
  
      /**
       * Append request parameters from the specified String to the specified
       * Map.  It is presumed that the specified Map is not accessed from any
       * other thread, so no synchronization is performed.
       * <p>
       * <strong>IMPLEMENTATION NOTE</strong>:  URL decoding is performed
       * individually on the parsed name and value elements, rather than on
       * the entire query string ahead of time, to properly deal with the case
       * where the name or value includes an encoded "=" or "&" character
       * that would otherwise be interpreted as a delimiter.
       *
       * @param map Map that accumulates the resulting parameters
       * @param data Input string containing request parameters
       * @param urlParameters true if we're parsing parameters on the URL
       *
       * @exception IllegalArgumentException if the data is malformed
       */
      public static void parseParameters(Map map, String data, String encoding)
          throws UnsupportedEncodingException {
  
          if ((data != null) && (data.length() > 0)) {
              int len = data.length();
              byte[] bytes = new byte[len];
              data.getBytes(0, len, bytes, 0);
              parseParameters(map, bytes, encoding);
          }
  
      }
  
  
      /**
       * Decode and return the specified URL-encoded String.
       * When the byte array is converted to a string, the system default
       * character encoding is used...  This may be different than some other
       * servers.
       *
       * @param str The url-encoded string
       *
       * @exception IllegalArgumentException if a '%' character is not followed
       * by a valid 2-digit hexadecimal number
       */
      public static String URLDecode(String str) {
  
          return URLDecode(str, null);
  
      }
  
  
      /**
       * Decode and return the specified URL-encoded String.
       *
       * @param str The url-encoded string
       * @param enc The encoding to use; if null, the default encoding is used
       * @exception IllegalArgumentException if a '%' character is not followed
       * by a valid 2-digit hexadecimal number
       */
      public static String URLDecode(String str, String enc) {
  
          if (str == null)
              return (null);
  
          int len = str.length();
          byte[] bytes = new byte[len];
          str.getBytes(0, len, bytes, 0);
  
          return URLDecode(bytes, enc);
  
      }
  
  
      /**
       * Decode and return the specified URL-encoded byte array.
       *
       * @param bytes The url-encoded byte array
       * @exception IllegalArgumentException if a '%' character is not followed
       * by a valid 2-digit hexadecimal number
       */
      public static String URLDecode(byte[] bytes) {
          return URLDecode(bytes, null);
      }
  
  
      /**
       * Decode and return the specified URL-encoded byte array.
       *
       * @param bytes The url-encoded byte array
       * @param enc The encoding to use; if null, the default encoding is used
       * @exception IllegalArgumentException if a '%' character is not followed
       * by a valid 2-digit hexadecimal number
       */
      public static String URLDecode(byte[] bytes, String enc) {
  
          if (bytes == null)
              return (null);
  
          int len = bytes.length;
          int ix = 0;
          int ox = 0;
          while (ix < len) {
              byte b = bytes[ix++];     // Get byte to test
              if (b == '+') {
                  b = (byte)' ';
              } else if (b == '%') {
                  b = (byte) ((convertHexDigit(bytes[ix++]) << 4)
                              + convertHexDigit(bytes[ix++]));
              }
              bytes[ox++] = b;
          }
          if (enc != null) {
              try {
                  return new String(bytes, 0, ox, enc);
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
          return new String(bytes, 0, ox);
  
      }
  
  
      /**
       * Convert a byte character value to hexidecimal digit value.
       *
       * @param b the character value byte
       */
      private static byte convertHexDigit( byte b ) {
          if ((b >= '0') && (b <= '9')) return (byte)(b - '0');
          if ((b >= 'a') && (b <= 'f')) return (byte)(b - 'a' + 10);
          if ((b >= 'A') && (b <= 'F')) return (byte)(b - 'A' + 10);
          return 0;
      }
  
  
      /**
       * Put name value pair in map.
       *
       * @param b the character value byte
       *
       * Put name and value pair in map.  When name already exist, add value
       * to array of values.
       */
      private static void putMapEntry( Map map, String name, String value) {
          String[] newValues = null;
          String[] oldValues = (String[]) map.get(name);
          if (oldValues == null) {
              newValues = new String[1];
              newValues[0] = value;
          } else {
              newValues = new String[oldValues.length + 1];
              System.arraycopy(oldValues, 0, newValues, 0, oldValues.length);
              newValues[oldValues.length] = value;
          }
          map.put(name, newValues);
      }
  
  
      /**
       * Append request parameters from the specified String to the specified
       * Map.  It is presumed that the specified Map is not accessed from any
       * other thread, so no synchronization is performed.
       * <p>
       * <strong>IMPLEMENTATION NOTE</strong>:  URL decoding is performed
       * individually on the parsed name and value elements, rather than on
       * the entire query string ahead of time, to properly deal with the case
       * where the name or value includes an encoded "=" or "&" character
       * that would otherwise be interpreted as a delimiter.
       *
       * NOTE: byte array data is modified by this method.  Caller beware.
       *
       * @param map Map that accumulates the resulting parameters
       * @param data Input string containing request parameters
       * @param encoding Encoding to use for converting hex
       *
       * @exception UnsupportedEncodingException if the data is malformed
       */
      public static void parseParameters(Map map, byte[] data, String encoding)
          throws UnsupportedEncodingException {
  
          if (data != null && data.length > 0) {
              int    pos = 0;
              int    ix = 0;
              int    ox = 0;
              String key = null;
              String value = null;
              while (ix < data.length) {
                  byte c = data[ix++];
                  switch ((char) c) {
                  case '&':
                      value = new String(data, 0, ox, encoding);
                      if (key != null) {
                          putMapEntry(map, key, value);
                          key = null;
                      }
                      ox = 0;
                      break;
                  case '=':
                      key = new String(data, 0, ox, encoding);
                      ox = 0;
                      break;
                  case '+':
                      data[ox++] = (byte)' ';
                      break;
                  case '%':
                      data[ox++] = (byte)((convertHexDigit(data[ix++]) << 4)
                                      + convertHexDigit(data[ix++]));
                      break;
                  default:
                      data[ox++] = c;
                  }
              }
              //The last value does not end in '&'.  So save it now.
              if (key != null) {
                  value = new String(data, 0, ox, encoding);
                  putMapEntry(map, key, value);
              }
          }
  
      }
  
  
  
  }
  
  
  
  
  1.6       +1 -1      jakarta-commons-sandbox/messenger/src/webapp/conf/subscriptions.xml
  
  Index: subscriptions.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/messenger/src/webapp/conf/subscriptions.xml,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- subscriptions.xml	2001/10/26 14:27:26	1.5
  +++ subscriptions.xml	2001/10/30 11:14:31	1.6
  @@ -14,7 +14,7 @@
     </subscription>
     
     <subscription messenger="queue" destination="echo.jsp">
  -    <servlet>/jms/time.jsp</servlet>
  +    <servlet>/jms/time.jsp?a=1&amp;b=2</servlet>
     </subscription>
     
   </subscriptions>
  
  
  
  1.2       +5 -5      jakarta-commons-sandbox/messenger/src/webapp/web/jms/time.jsp
  
  Index: time.jsp
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/messenger/src/webapp/web/jms/time.jsp,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- time.jsp	2001/10/26 11:52:17	1.1
  +++ time.jsp	2001/10/30 11:14:31	1.2
  @@ -1,5 +1,5 @@
  -<%
  -  System.out.println( "Evaluating the time.jsp file at: " + new java.util.Date() );
  -%>
  -
  -<time><%= new java.util.Date() %></time>
  +<echo>
  +  <time><%= new java.util.Date() %></time>
  +  <a><%= request.getParameter( "a" )%></a>
  +  <b><%= request.getParameter( "b" )%></b>
  +</echo>
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>