You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by bi...@apache.org on 2001/05/04 22:45:59 UTC

cvs commit: jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/startup Catalina.java

bip         01/05/04 13:45:58

  Modified:    catalina/src/share/org/apache/catalina Container.java
               catalina/src/share/org/apache/catalina/core
                        ContainerBase.java
               catalina/src/share/org/apache/catalina/session
                        PersistentManager.java PersistentManagerBase.java
               catalina/src/share/org/apache/catalina/startup Catalina.java
  Added:       catalina/src/share/org/apache/catalina Cluster.java
               catalina/src/share/org/apache/catalina/session
                        DistributedManager.java
  Log:
  Added a basic ClusterManger used from within DistributedManager
  
  Revision  Changes    Path
  1.4       +20 -4     jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/Container.java
  
  Index: Container.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/Container.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- Container.java	2001/01/23 05:05:44	1.3
  +++ Container.java	2001/05/04 20:45:36	1.4
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/Container.java,v 1.3 2001/01/23 05:05:44 remm Exp $
  - * $Revision: 1.3 $
  - * $Date: 2001/01/23 05:05:44 $
  + * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/Container.java,v 1.4 2001/05/04 20:45:36 bip Exp $
  + * $Revision: 1.4 $
  + * $Date: 2001/05/04 20:45:36 $
    *
    * ====================================================================
    *
  @@ -120,7 +120,7 @@
    *
    * @author Craig R. McClanahan
    * @author Remy Maucherat
  - * @version $Revision: 1.3 $ $Date: 2001/01/23 05:05:44 $
  + * @version $Revision: 1.4 $ $Date: 2001/05/04 20:45:36 $
    */
   
   public interface Container {
  @@ -228,6 +228,22 @@
        * @param manager The newly associated Manager
        */
       public void setManager(Manager manager);
  +
  +
  +    /**
  +     * Return the Cluster with which this Container is associated.  If there is
  +     * no associated Cluster, return the Cluster associated with our parent
  +     * Container (if any); otherwise return <code>null</code>.
  +     */
  +    public Cluster getCluster();
  +
  +
  +    /**
  +     * Set the Cluster with which this Container is associated.
  +     *
  +     * @param connector The Connector to be added
  +     */
  +    public void setCluster(Cluster cluster);
   
   
       /**
  
  
  
  1.1                  jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/Cluster.java
  
  Index: Cluster.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/Cluster.java,v 1.1 2001/05/04 20:45:35 bip Exp $
   * $Revision: 1.1 $
   * $Date: 2001/05/04 20:45:35 $
   *
   * ====================================================================
   *
   * 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.catalina;
  
  
  import java.beans.PropertyChangeListener;
  import java.util.Collection;
  import org.apache.catalina.cluster.ClusterMemberInfo;
  import org.apache.catalina.cluster.MulticastReceiver;
  import org.apache.catalina.cluster.MulticastSender;
  
  /**
   * A <b>Cluster</b> works as a Cluster client/server for the local host
   * Different Cluster implementations can be used to support Session replication
   * or weighted loadbalancing.
   *
   * @author Bip Thelin
   * @version $Revision: 1.1 $
   */
  
  public interface Cluster {
  
      // ------------------------------------------------------------- Properties
  
      /**
       * Return descriptive information about this Cluster implementation and
       * the corresponding version number, in the format
       * <code>&lt;description&gt;/&lt;version&gt;</code>.
       */
      public String getInfo();
  
      /**
       * Return the name of the cluster that this Server is currently
       * configured to operate within.
       *
       * @return The name of the cluster associated with this server
       */
      public String getClusterName();
  
      /**
       * Set the name of the cluster to join, if no cluster with
       * this name is present create one.
       *
       * @param clusterName The clustername to join
       */
      public void setClusterName(String clusterName);
  
      /**
       * Set the Container associated with our Cluster
       *
       * @param container The Container to use
       */
      public void setContainer(Container container);
  
      /**
       * Get the Container associated with our Cluster
       *
       * @return The Container associated with our Cluster
       */
      public Container getContainer();
  
      // --------------------------------------------------------- Public Methods
  
      /**
       * Returns a collection containing <code>ClusterMemberInfo</code>
       * on the remote members of this Cluster. This method does
       * not include the local host, to retrieve
       * <code>ClusterMemberInfo</code> on the local host
       * use <code>getLocalClusterInfo()</code> instead.
       *
       * @return Collection with all members in the Cluster
       */
      public Collection getRemoteClusterMembers();
  
      /**
       * Returns a <code>MulticastSender</code> which is the interface
       * to use when communicating in the Cluster. 
       *
       * @return The MulticastSender to use
       */
      public MulticastSender getMulticastSender(String senderId);
  
      /**
       * Returns a <code>MulticastReceiver</code> which is the interface
       * to use when communicating in the Cluster. 
       *
       * @return The MulticastSender to use
       */
      public MulticastReceiver getMulticastReceiver(String senderId);
  
      /**
       * Return cluster information about the local host
       *
       * @return Cluster information
       */
      public ClusterMemberInfo getLocalClusterInfo();
  }
  
  
  
  1.12      +142 -76   jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/ContainerBase.java
  
  Index: ContainerBase.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/ContainerBase.java,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- ContainerBase.java	2001/05/04 05:07:07	1.11
  +++ ContainerBase.java	2001/05/04 20:45:42	1.12
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/ContainerBase.java,v 1.11 2001/05/04 05:07:07 craigmcc Exp $
  - * $Revision: 1.11 $
  - * $Date: 2001/05/04 05:07:07 $
  + * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/ContainerBase.java,v 1.12 2001/05/04 20:45:42 bip Exp $
  + * $Revision: 1.12 $
  + * $Date: 2001/05/04 20:45:42 $
    *
    * ====================================================================
    *
  @@ -75,6 +75,7 @@
   import javax.servlet.ServletException;
   import javax.naming.directory.DirContext;
   import org.apache.naming.resources.ProxyDirContext;
  +import org.apache.catalina.Cluster;
   import org.apache.catalina.Container;
   import org.apache.catalina.ContainerEvent;
   import org.apache.catalina.ContainerListener;
  @@ -153,7 +154,7 @@
    * class comments of the implementation class.
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.11 $ $Date: 2001/05/04 05:07:07 $
  + * @version $Revision: 1.12 $ $Date: 2001/05/04 20:45:42 $
    */
   
   public abstract class ContainerBase
  @@ -204,6 +205,12 @@
        */
       protected Manager manager = null;
   
  +    
  +    /**
  +     * The cluster with which this Container is associated.
  +     */
  +    protected Cluster cluster = null;
  +
   
       /**
        * The one and only Mapper associated with this Container, if any.
  @@ -484,7 +491,61 @@
   
       }
   
  +    /**
  +     * Return the Cluster with which this Container is associated.  If there is
  +     * no associated Cluster, return the Cluster associated with our parent
  +     * Container (if any); otherwise return <code>null</code>.
  +     */
  +    public Cluster getCluster() {
  +        if (cluster != null)
  +            return (cluster);
  +
  +        if (parent != null)
  +            return (parent.getCluster());
  +
  +        return (null);
  +    }
  +
  +    /**
  +     * Set the Cluster with which this Container is associated.
  +     *
  +     * @param manager The newly associated Cluster
  +     */
  +    public synchronized void setCluster(Cluster cluster) {
  +        // Change components if necessary
  +        Cluster oldCluster = this.cluster;
  +        if (oldCluster == cluster)
  +            return;
  +        this.cluster = cluster;
  +        
  +        // Stop the old component if necessary
  +        if (started && (oldCluster != null) &&
  +            (oldCluster instanceof Lifecycle)) {
  +            try {
  +                ((Lifecycle) oldCluster).stop();
  +            } catch (LifecycleException e) {
  +                log("ContainerBase.setCluster: stop: ", e);
  +            }
  +        }
  +        
  +        // Start the new component if necessary
  +        if (cluster != null)
  +            cluster.setContainer(this);
  +
  +        if (started && (cluster != null) &&
  +            (cluster instanceof Lifecycle)) {
  +            try {
  +                ((Lifecycle) cluster).start();
  +            } catch (LifecycleException e) {
  +                log("ContainerBase.setCluster: start: ", e);
  +            }
  +        }
  +        
  +        // Report this property change to interested listeners
  +        support.firePropertyChange("cluster", oldCluster, this.cluster);
  +    }
   
  +
       /**
        * Return a name string (suitable for use by humans) that describes this
        * Container.  Within the set of child containers belonging to a particular
  @@ -1026,47 +1087,49 @@
        *  that prevents it from being started
        */
       public synchronized void start() throws LifecycleException {
  -
  -	// Validate and update our current component state
  -	if (started)
  -	    throw new LifecycleException
  -		(sm.getString("containerBase.alreadyStarted", logName()));
  -	addDefaultMapper(this.mapperClass);
  -	started = true;
  -
  -	// Start our subordinate components, if any
  -	if ((loader != null) && (loader instanceof Lifecycle))
  -	    ((Lifecycle) loader).start();
  -	if ((logger != null) && (logger instanceof Lifecycle))
  -	    ((Lifecycle) logger).start();
  -	if ((manager != null) && (manager instanceof Lifecycle))
  -	    ((Lifecycle) manager).start();
  -	if ((realm != null) && (realm instanceof Lifecycle))
  -	    ((Lifecycle) realm).start();
  -	if ((resources != null) && (resources instanceof Lifecycle))
  -	    ((Lifecycle) resources).start();
  -
  -	// Start our Mappers, if any
  -	Mapper mappers[] = findMappers();
  -	for (int i = 0; i < mappers.length; i++) {
  -	    if (mappers[i] instanceof Lifecycle)
  -		((Lifecycle) mappers[i]).start();
  -	}
  -
  -	// Start our child containers, if any
  -	Container children[] = findChildren();
  -	for (int i = 0; i < children.length; i++) {
  -	    if (children[i] instanceof Lifecycle)
  -		((Lifecycle) children[i]).start();
  -	}
   
  -	// Start the Valves in our pipeline (including the basic), if any
  +        // Validate and update our current component state
  +        if (started)
  +            throw new LifecycleException
  +                (sm.getString("containerBase.alreadyStarted", logName()));
  +        addDefaultMapper(this.mapperClass);
  +        started = true;
  +        
  +        // Start our subordinate components, if any
  +        if ((loader != null) && (loader instanceof Lifecycle))
  +            ((Lifecycle) loader).start();
  +        if ((logger != null) && (logger instanceof Lifecycle))
  +            ((Lifecycle) logger).start();
  +        if ((manager != null) && (manager instanceof Lifecycle))
  +            ((Lifecycle) manager).start();
  +        if ((cluster != null) && (cluster instanceof Lifecycle))
  +            ((Lifecycle) cluster).start();
  +        if ((realm != null) && (realm instanceof Lifecycle))
  +            ((Lifecycle) realm).start();
  +        if ((resources != null) && (resources instanceof Lifecycle))
  +            ((Lifecycle) resources).start();
  +        
  +        // Start our Mappers, if any
  +        Mapper mappers[] = findMappers();
  +        for (int i = 0; i < mappers.length; i++) {
  +            if (mappers[i] instanceof Lifecycle)
  +                ((Lifecycle) mappers[i]).start();
  +        }
  +        
  +        // Start our child containers, if any
  +        Container children[] = findChildren();
  +        for (int i = 0; i < children.length; i++) {
  +            if (children[i] instanceof Lifecycle)
  +                ((Lifecycle) children[i]).start();
  +        }
  +        
  +        // Start the Valves in our pipeline (including the basic), if any
           if (pipeline instanceof Lifecycle)
               ((Lifecycle) pipeline).start();
  -
  -	// Notify our interested LifecycleListeners
  -	lifecycle.fireLifecycleEvent(START_EVENT, null);
  -
  +        
  +        // Notify our interested LifecycleListeners
  +        lifecycle.fireLifecycleEvent(START_EVENT, null);
  +        
       }
   
   
  @@ -1078,52 +1141,55 @@
        *  that needs to be reported
        */
       public synchronized void stop() throws LifecycleException {
  -
  -	// Validate and update our current component state
  -	if (!started)
  -	    throw new LifecycleException
  -		(sm.getString("containerBase.notStarted", logName()));
  +        
  +        // Validate and update our current component state
  +        if (!started)
  +            throw new LifecycleException
  +                (sm.getString("containerBase.notStarted", logName()));
   
  -	// Notify our interested LifecycleListeners
  +        // Notify our interested LifecycleListeners
           lifecycle.fireLifecycleEvent(STOP_EVENT, null);
  -	started = false;
  -
  -	// Stop the Valves in our pipeline (including the basic), if any
  +        started = false;
  +        
  +        // Stop the Valves in our pipeline (including the basic), if any
           if (pipeline instanceof Lifecycle) {
               ((Lifecycle) pipeline).stop();
           }
  -
  -	// Stop our child containers, if any
  -	Container children[] = findChildren();
  -	for (int i = 0; i < children.length; i++) {
  +        
  +        // Stop our child containers, if any
  +        Container children[] = findChildren();
  +        for (int i = 0; i < children.length; i++) {
               if (children[i] instanceof Lifecycle)
                   ((Lifecycle) children[i]).stop();
  -	}
  -
  -	// Stop our Mappers, if any
  -	Mapper mappers[] = findMappers();
  -	for (int i = 0; i < mappers.length; i++) {
  -	    if (mappers[(mappers.length-1)-i] instanceof Lifecycle)
  -		((Lifecycle) mappers[(mappers.length-1)-i]).stop();
  -	}
  -
  -	// Stop our subordinate components, if any
  -	if ((resources != null) && (resources instanceof Lifecycle)) {
  -	    ((Lifecycle) resources).stop();
           }
  -	if ((realm != null) && (realm instanceof Lifecycle)) {
  -	    ((Lifecycle) realm).stop();
  +        
  +        // Stop our Mappers, if any
  +        Mapper mappers[] = findMappers();
  +        for (int i = 0; i < mappers.length; i++) {
  +            if (mappers[(mappers.length-1)-i] instanceof Lifecycle)
  +                ((Lifecycle) mappers[(mappers.length-1)-i]).stop();
           }
  -	if ((manager != null) && (manager instanceof Lifecycle)) {
  -	    ((Lifecycle) manager).stop();
  +        
  +        // Stop our subordinate components, if any
  +        if ((resources != null) && (resources instanceof Lifecycle)) {
  +            ((Lifecycle) resources).stop();
           }
  -	if ((logger != null) && (logger instanceof Lifecycle)) {
  -	    ((Lifecycle) logger).stop();
  +        if ((realm != null) && (realm instanceof Lifecycle)) {
  +            ((Lifecycle) realm).stop();
           }
  -	if ((loader != null) && (loader instanceof Lifecycle)) {
  -	    ((Lifecycle) loader).stop();
  +        if ((cluster != null) && (cluster instanceof Lifecycle)) {
  +            ((Lifecycle) cluster).stop();
  +        }        
  +        if ((manager != null) && (manager instanceof Lifecycle)) {
  +            ((Lifecycle) manager).stop();
           }
  -
  +        if ((logger != null) && (logger instanceof Lifecycle)) {
  +            ((Lifecycle) logger).stop();
  +        }
  +        if ((loader != null) && (loader instanceof Lifecycle)) {
  +            ((Lifecycle) loader).stop();
  +        }
  +        
       }
   
   
  
  
  
  1.9       +7 -395    jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/session/PersistentManager.java
  
  Index: PersistentManager.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/session/PersistentManager.java,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- PersistentManager.java	2001/04/17 17:07:01	1.8
  +++ PersistentManager.java	2001/05/04 20:45:48	1.9
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/session/PersistentManager.java,v 1.8 2001/04/17 17:07:01 craigmcc Exp $
  - * $Revision: 1.8 $
  - * $Date: 2001/04/17 17:07:01 $
  + * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/session/PersistentManager.java,v 1.9 2001/05/04 20:45:48 bip Exp $
  + * $Revision: 1.9 $
  + * $Date: 2001/05/04 20:45:48 $
    *
    * ====================================================================
    *
  @@ -64,37 +64,6 @@
   
   package org.apache.catalina.session;
   
  -import java.beans.PropertyChangeEvent;
  -import java.beans.PropertyChangeListener;
  -import java.beans.PropertyChangeSupport;
  -import java.io.BufferedInputStream;
  -import java.io.BufferedOutputStream;
  -import java.io.File;
  -import java.io.FileInputStream;
  -import java.io.FileNotFoundException;
  -import java.io.FileOutputStream;
  -import java.io.InputStream;
  -import java.io.IOException;
  -import java.io.ObjectInputStream;
  -import java.io.ObjectOutputStream;
  -import java.io.ObjectStreamClass;
  -import java.util.ArrayList;
  -import java.util.Iterator;
  -import javax.servlet.ServletContext;
  -import org.apache.catalina.Container;
  -import org.apache.catalina.Context;
  -import org.apache.catalina.Globals;
  -import org.apache.catalina.Lifecycle;
  -import org.apache.catalina.LifecycleEvent;
  -import org.apache.catalina.LifecycleException;
  -import org.apache.catalina.LifecycleListener;
  -import org.apache.catalina.Loader;
  -import org.apache.catalina.Manager;
  -import org.apache.catalina.Session;
  -import org.apache.catalina.Store;
  -import org.apache.catalina.util.LifecycleSupport;
  -
  -
   /**
    * Implementation of the <b>Manager</b> interface that makes use of
    * a Store to swap active Sessions to disk. It can be configured to
  @@ -106,13 +75,11 @@
    * <li>Limit the number of active sessions kept in memory by
    *     swapping less active sessions out to disk.</li>
    *
  - * @version $Revision: 1.8 $
  + * @version $Revision: 1.9 $
    * @author Kief Morris (kief@kief.com)
    */
   
  -public final class PersistentManager
  -    extends PersistentManagerBase
  -    implements Lifecycle, PropertyChangeListener, Runnable {
  +public final class PersistentManager extends PersistentManagerBase {
   
   
       // ----------------------------------------------------- Instance Variables
  @@ -125,35 +92,6 @@
   
   
       /**
  -     * Whether to save and reload sessions when the Manager <code>unload</code>
  -     * and <code>load</code> methods are called.
  -     */
  -    private boolean saveOnRestart = true;
  -    
  -    
  -    /**
  -     * How long a session must be idle before it should be backed up.
  -     * -1 means sessions won't be backed up.
  -     */
  -    private int maxIdleBackup = -1;
  -    
  -    
  -    /**
  -     * Minimum time a session must be idle before it is swapped to disk.
  -     * This overrides maxActiveSessions, to prevent thrashing if there are lots
  -     * of active sessions. Setting to -1 means it's ignored.
  -     */
  -    private int minIdleSwap = -1;
  -
  -    /**
  -     * The maximum time a session may be idle before it should be swapped
  -     * to file just on general principle. Setting this to -1 means sessions
  -     * should not be forced out.
  -     */
  -    private int maxIdleSwap = -1;
  -
  -
  -    /**
        * The descriptive name of this Manager implementation (for logging).
        */
       protected static String name = "PersistentManager";
  @@ -172,340 +110,14 @@
           return (this.info);
   
       }
  -
  -
  -    /**
  -     * Indicates how many seconds old a session can get, after its last 
  -     * use in a request, before it should be backed up to the store. -1
  -     * means sessions are not backed up.
  -     */
  -    public int getMaxIdleBackup() {
  -
  -        return maxIdleBackup;
  -
  -    }
  -    
  -    
  +   
       /**
  -     * Sets the option to back sessions up to the Store after they
  -     * are used in a request. Sessions remain available in memory
  -     * after being backed up, so they are not passivated as they are 
  -     * when swapped out. The value set indicates how old a session 
  -     * may get (since its last use) before it must be backed up: -1 
  -     * means sessions are not backed up.
  -     * <p>
  -     * Note that this is not a hard limit: sessions are checked 
  -     * against this age limit periodically according to <b>checkInterval</b>.
  -     * This value should be considered to indicate when a session is
  -     * ripe for backing up.
  -     * <p>
  -     * So it is possible that a session may be idle for maxIdleBackup +
  -     * checkInterval seconds, plus the time it takes to handle other
  -     * session expiration, swapping, etc. tasks.
  -     *
  -     * @param backup The number of seconds after their last accessed
  -     * time when they should be written to the Store. 
  -     */
  -    public void setMaxIdleBackup (int backup) {
  -
  -        if (backup == this.maxIdleBackup)
  -            return;
  -        int oldBackup = this.maxIdleBackup;
  -        this.maxIdleBackup = backup;
  -        support.firePropertyChange("maxIdleBackup",
  -                                   new Integer(oldBackup),
  -                                   new Integer(this.maxIdleBackup));
  -                                   
  -    }
  -    
  -    
  -    /**
  -     * The time in seconds after which a session should be swapped out of
  -     * memory to disk.
  -     */
  -    public int getMaxIdleSwap() {
  -
  -        return maxIdleSwap;
  -
  -    }
  -    
  -    
  -    /**
  -     * Sets the time in seconds after which a session should be swapped out of
  -     * memory to disk.
  -     */
  -    public void setMaxIdleSwap(int max) {
  -
  -        if (max == this.maxIdleSwap)
  -            return;
  -        int oldMaxIdleSwap = this.maxIdleSwap;
  -        this.maxIdleSwap = max;
  -        support.firePropertyChange("maxIdleSwap",
  -                                   new Integer(oldMaxIdleSwap),
  -                                   new Integer(this.maxIdleSwap));
  -
  -    }
  -
  -
  -    /**
  -     * The minimum time in seconds that a session must be idle before
  -     * it can be swapped out of memory, or -1 if it can be swapped out
  -     * at any time.
  -     */
  -    public int getMinIdleSwap() {
  -
  -        return minIdleSwap;
  -
  -    }
  -    
  -    
  -    /**
  -     * Sets the minimum time in seconds that a session must be idle before
  -     * it can be swapped out of memory due to maxActiveSession. Set it to -1 
  -     * if it can be swapped out at any time.
  -     */
  -    public void setMinIdleSwap(int min) {
  -
  -        if (this.minIdleSwap == min)
  -            return;
  -        int oldMinIdleSwap = this.minIdleSwap;
  -        this.minIdleSwap = min;
  -        support.firePropertyChange("minIdleSwap",
  -                                   new Integer(oldMinIdleSwap),
  -                                   new Integer(this.minIdleSwap));
  -
  -    }
  -    
  -    
  -    /**
        * Return the descriptive short name of this Manager implementation.
        */
       public String getName() {
   
           return (name);
   
  -    }
  -
  -
  -    /**
  -     * Indicates whether sessions are saved when the Manager is shut down
  -     * properly. This requires the unload() method to be called.
  -     */
  -    public boolean getSaveOnRestart() {
  -
  -        return saveOnRestart;
  -
  -    }
  -    
  -    
  -    /**
  -     * Set the option to save sessions to the Store when the Manager is
  -     * shut down, then loaded when the Manager starts again. If set to 
  -     * false, any sessions found in the Store may still be picked up when 
  -     * the Manager is started again.
  -     *
  -     * @param save true if sessions should be saved on restart, false if
  -     *     they should be ignored.
  -     */
  -    public void setSaveOnRestart(boolean saveOnRestart) {
  -
  -        if (saveOnRestart == this.saveOnRestart)
  -            return;
  -
  -        boolean oldSaveOnRestart = this.saveOnRestart;
  -        this.saveOnRestart = saveOnRestart;
  -        support.firePropertyChange("saveOnRestart",
  -                                   new Boolean(oldSaveOnRestart),
  -                                   new Boolean(this.saveOnRestart));
  -                                   
  -    }
  -    
  -    
  -    // --------------------------------------------------------- Public Methods
  -
  -
  -    /**
  -     * Called by the background thread after active sessions have
  -     * been checked for expiration, to allow sessions to be
  -     * swapped out, backed up, etc.
  -     */
  -    public void processPersistenceChecks() {
  -    
  -            processMaxIdleSwaps();
  -            processMaxActiveSwaps();
  -            processMaxIdleBackups();
  -
       }
  -
  -
  -    // ------------------------------------------------------ Lifecycle Methods
  -
  -
  -    /**
  -     * Gracefully terminate the active use of the public methods of this
  -     * component.  This method should be the last one called on a given
  -     * instance of this component.
  -     *
  -     * @exception IllegalStateException if this component has not been started
  -     * @exception LifecycleException if this component detects a fatal error
  -     *  that needs to be reported
  -     */
  -    public void stop() throws LifecycleException {
  -
  -        if (debug >= 1)
  -            log("Stopping");
  -
  -        // Validate and update our current component state
  -        if (!isStarted())
  -            throw new LifecycleException
  -                (sm.getString("standardManager.notStarted"));
  -        lifecycle.fireLifecycleEvent(STOP_EVENT, null);
  -        setStarted(false);
  -
  -        // Stop the background reaper thread
  -        threadStop();
  -
  -        if (getStore() != null && saveOnRestart) {
  -            unload();
  -        } else {
  -            // Expire all active sessions
  -            Session sessions[] = findSessions();
  -            for (int i = 0; i < sessions.length; i++) {
  -                StandardSession session = (StandardSession) sessions[i];
  -                if (!session.isValid())
  -                    continue;
  -                session.expire();
  -            }
  -        }
  -        
  -        if (getStore() != null && getStore() instanceof Lifecycle)
  -            ((Lifecycle)getStore()).stop();
  -
  -        // Require a new random number generator if we are restarted
  -        this.random = null;
  -
  -    }
  -
  -
  -    // -------------------------------------------------------- Private Methods
  -
  -
  -    /**
  -     * Swap idle sessions out to Store if they are idle too long.
  -     */
  -    private void processMaxIdleSwaps() {
  -
  -        if (!isStarted() || maxIdleSwap < 0)
  -            return;
  -
  -        Session sessions[] = findSessions();
  -        long timeNow = System.currentTimeMillis();
  -
  -        // Swap out all sessions idle longer than maxIdleSwap
  -        // FIXME: What's preventing us from mangling a session during
  -        // a request?
  -        if (maxIdleSwap >= 0) {
  -            for (int i = 0; i < sessions.length; i++) {
  -                StandardSession session = (StandardSession) sessions[i];
  -                if (!session.isValid())
  -                    continue;
  -                int timeIdle = // Truncate, do not round up
  -                    (int) ((timeNow - session.getLastAccessedTime()) / 1000L);
  -                if (timeIdle > maxIdleSwap && timeIdle > minIdleSwap) {
  -                    if (debug > 1)
  -                        log(sm.getString
  -                            ("persistentManager.swapMaxIdle", 
  -                             session.getId(), new Integer(timeIdle)));
  -                    try {
  -                        swapOut(session);
  -                    } catch (IOException e) {
  -                        ;   // This is logged in writeSession()
  -                    }
  -                }
  -            }
  -        }
  -        
  -    }
  -
  -
  -    /**
  -     * Swap idle sessions out to Store if too many are active
  -     */
  -    private void processMaxActiveSwaps() {
  -
  -        if (!isStarted() || getMaxActiveSessions() < 0)
  -            return;
  -
  -        Session sessions[] = findSessions();
  -        
  -        // FIXME: Smarter algorithm (LRU)
  -        if (getMaxActiveSessions() >= sessions.length)
  -            return;
  -
  -        if(debug > 0)
  -            log(sm.getString
  -                ("persistentManager.tooManyActive", 
  -                 new Integer(sessions.length)));
  -
  -        int toswap = sessions.length - getMaxActiveSessions();
  -        long timeNow = System.currentTimeMillis();
  -        
  -        for (int i = 0; i < sessions.length && toswap > 0; i++) {
  -            int timeIdle = // Truncate, do not round up
  -                (int) ((timeNow - sessions[i].getLastAccessedTime()) / 1000L);
  -            if (timeIdle > minIdleSwap) {
  -                if(debug > 1)
  -                    log(sm.getString
  -                        ("persistentManager.swapTooManyActive", 
  -                         sessions[i].getId(), new Integer(timeIdle)));
  -                try {
  -                    swapOut(sessions[i]);
  -                } catch (IOException e) {
  -                    ;   // This is logged in writeSession()
  -                }
  -                toswap--;
  -            }
  -        }
  -
  -    }
  -
  -
  -    /**
  -     * Back up idle sessions.
  -     */
  -    private void processMaxIdleBackups() {
  -
  -        if (!isStarted() || maxIdleBackup < 0)
  -            return;
  -        
  -        Session sessions[] = findSessions();
  -        long timeNow = System.currentTimeMillis();
  -
  -        // Back up all sessions idle longer than maxIdleBackup
  -        if (maxIdleBackup >= 0) {
  -            for (int i = 0; i < sessions.length; i++) {
  -                StandardSession session = (StandardSession) sessions[i];
  -                if (!session.isValid())
  -                    continue;
  -                int timeIdle = // Truncate, do not round up
  -                    (int) ((timeNow - session.getLastAccessedTime()) / 1000L);
  -                if (timeIdle > maxIdleBackup) {
  -                    if (debug > 1)
  -                        log(sm.getString
  -                            ("persistentManager.backupMaxIdle",
  -                            session.getId(), new Integer(timeIdle)));
  -        
  -                    try {
  -                        writeSession(session);
  -                    } catch (IOException e) {
  -                        ;   // This is logged in writeSession()
  -                    }
  -                }
  -            }
  -        }
  -
  -    }
  -
  -
  -}
  + }
   
  
  
  
  1.4       +325 -33   jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/session/PersistentManagerBase.java
  
  Index: PersistentManagerBase.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/session/PersistentManagerBase.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- PersistentManagerBase.java	2001/04/27 07:55:46	1.3
  +++ PersistentManagerBase.java	2001/05/04 20:45:49	1.4
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/session/PersistentManagerBase.java,v 1.3 2001/04/27 07:55:46 kief Exp $
  - * $Revision: 1.3 $
  - * $Date: 2001/04/27 07:55:46 $
  + * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/session/PersistentManagerBase.java,v 1.4 2001/05/04 20:45:49 bip Exp $
  + * $Revision: 1.4 $
  + * $Date: 2001/05/04 20:45:49 $
    *
    * ====================================================================
    *
  @@ -105,7 +105,7 @@
    * <code>stop()</code> methods of this class at the correct times.
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.3 $ $Date: 2001/04/27 07:55:46 $
  + * @version $Revision: 1.4 $ $Date: 2001/05/04 20:45:49 $
    */
   
   public abstract class PersistentManagerBase
  @@ -161,7 +161,7 @@
       /**
        * The background thread completion semaphore.
        */
  -    private boolean threadDone = false;
  +    protected boolean threadDone = false;
   
   
       /**
  @@ -176,6 +176,35 @@
       private Store store = null;
   
   
  +    /**
  +     * Whether to save and reload sessions when the Manager <code>unload</code>
  +     * and <code>load</code> methods are called.
  +     */
  +    private boolean saveOnRestart = true;
  +    
  +    
  +    /**
  +     * How long a session must be idle before it should be backed up.
  +     * -1 means sessions won't be backed up.
  +     */
  +    private int maxIdleBackup = -1;
  +    
  +    
  +    /**
  +     * Minimum time a session must be idle before it is swapped to disk.
  +     * This overrides maxActiveSessions, to prevent thrashing if there are lots
  +     * of active sessions. Setting to -1 means it's ignored.
  +     */
  +    private int minIdleSwap = -1;
  +
  +    /**
  +     * The maximum time a session may be idle before it should be swapped
  +     * to file just on general principle. Setting this to -1 means sessions
  +     * should not be forced out.
  +     */
  +    private int maxIdleSwap = -1;
  +
  +
       // ------------------------------------------------------------- Properties
   
   
  @@ -205,7 +234,111 @@
       }
   
   
  +
  +    /**
  +     * Indicates how many seconds old a session can get, after its last 
  +     * use in a request, before it should be backed up to the store. -1
  +     * means sessions are not backed up.
  +     */
  +    public int getMaxIdleBackup() {
  +
  +        return maxIdleBackup;
  +
  +    }
  +    
  +    
  +    /**
  +     * Sets the option to back sessions up to the Store after they
  +     * are used in a request. Sessions remain available in memory
  +     * after being backed up, so they are not passivated as they are 
  +     * when swapped out. The value set indicates how old a session 
  +     * may get (since its last use) before it must be backed up: -1 
  +     * means sessions are not backed up.
  +     * <p>
  +     * Note that this is not a hard limit: sessions are checked 
  +     * against this age limit periodically according to <b>checkInterval</b>.
  +     * This value should be considered to indicate when a session is
  +     * ripe for backing up.
  +     * <p>
  +     * So it is possible that a session may be idle for maxIdleBackup +
  +     * checkInterval seconds, plus the time it takes to handle other
  +     * session expiration, swapping, etc. tasks.
  +     *
  +     * @param backup The number of seconds after their last accessed
  +     * time when they should be written to the Store. 
  +     */
  +    public void setMaxIdleBackup (int backup) {
  +
  +        if (backup == this.maxIdleBackup)
  +            return;
  +        int oldBackup = this.maxIdleBackup;
  +        this.maxIdleBackup = backup;
  +        support.firePropertyChange("maxIdleBackup",
  +                                   new Integer(oldBackup),
  +                                   new Integer(this.maxIdleBackup));
  +                                   
  +    }
  +    
  +    
  +    /**
  +     * The time in seconds after which a session should be swapped out of
  +     * memory to disk.
  +     */
  +    public int getMaxIdleSwap() {
  +
  +        return maxIdleSwap;
  +
  +    }
  +    
  +    
  +    /**
  +     * Sets the time in seconds after which a session should be swapped out of
  +     * memory to disk.
  +     */
  +    public void setMaxIdleSwap(int max) {
  +
  +        if (max == this.maxIdleSwap)
  +            return;
  +        int oldMaxIdleSwap = this.maxIdleSwap;
  +        this.maxIdleSwap = max;
  +        support.firePropertyChange("maxIdleSwap",
  +                                   new Integer(oldMaxIdleSwap),
  +                                   new Integer(this.maxIdleSwap));
  +
  +    }
  +
  +
  +    /**
  +     * The minimum time in seconds that a session must be idle before
  +     * it can be swapped out of memory, or -1 if it can be swapped out
  +     * at any time.
  +     */
  +    public int getMinIdleSwap() {
  +
  +        return minIdleSwap;
  +
  +    }
  +    
  +    
       /**
  +     * Sets the minimum time in seconds that a session must be idle before
  +     * it can be swapped out of memory due to maxActiveSession. Set it to -1 
  +     * if it can be swapped out at any time.
  +     */
  +    public void setMinIdleSwap(int min) {
  +
  +        if (this.minIdleSwap == min)
  +            return;
  +        int oldMinIdleSwap = this.minIdleSwap;
  +        this.minIdleSwap = min;
  +        support.firePropertyChange("minIdleSwap",
  +                                   new Integer(oldMinIdleSwap),
  +                                   new Integer(this.minIdleSwap));
  +
  +    }
  +    
  +
  +    /**
        * Set the Container with which this Manager has been associated.  If
        * it is a Context (the usual case), listen for changes to the session
        * timeout property.
  @@ -326,6 +459,41 @@
       }
   
   
  +
  +    /**
  +     * Indicates whether sessions are saved when the Manager is shut down
  +     * properly. This requires the unload() method to be called.
  +     */
  +    public boolean getSaveOnRestart() {
  +
  +        return saveOnRestart;
  +
  +    }
  +    
  +    
  +    /**
  +     * Set the option to save sessions to the Store when the Manager is
  +     * shut down, then loaded when the Manager starts again. If set to 
  +     * false, any sessions found in the Store may still be picked up when 
  +     * the Manager is started again.
  +     *
  +     * @param save true if sessions should be saved on restart, false if
  +     *     they should be ignored.
  +     */
  +    public void setSaveOnRestart(boolean saveOnRestart) {
  +
  +        if (saveOnRestart == this.saveOnRestart)
  +            return;
  +
  +        boolean oldSaveOnRestart = this.saveOnRestart;
  +        this.saveOnRestart = saveOnRestart;
  +        support.firePropertyChange("saveOnRestart",
  +                                   new Boolean(oldSaveOnRestart),
  +                                   new Boolean(this.saveOnRestart));
  +                                   
  +    }
  +
  +
       // --------------------------------------------------------- Public Methods
   
   
  @@ -345,6 +513,20 @@
           }
       
       }
  +
  +
  +    /**
  +     * Called by the background thread after active sessions have
  +     * been checked for expiration, to allow sessions to be
  +     * swapped out, backed up, etc.
  +     */
  +    public void processPersistenceChecks() {
  +    
  +            processMaxIdleSwaps();
  +            processMaxActiveSwaps();
  +            processMaxIdleBackups();
  +
  +    }
       
   
       /**
  @@ -443,15 +625,6 @@
   
   
       /**
  -     * Called by the background thread after active sessions have
  -     * been checked for expiration, to allow sessions to be
  -     * swapped out, backed up, etc. This method must be implemented,
  -     * but may be empty if it isn't needed.
  -     */
  -    public abstract void processPersistenceChecks();
  -
  -
  -    /**
        * Remove this Session from the active Sessions for this Manager,
        * and from the Store.
        *
  @@ -676,34 +849,36 @@
        * @exception LifecycleException if this component detects a fatal error
        *  that needs to be reported
        */
  -    public void stop() throws LifecycleException {
  +   public void stop() throws LifecycleException {
   
           if (debug >= 1)
               log("Stopping");
   
           // Validate and update our current component state
  -        if (!started)
  +        if (!isStarted())
               throw new LifecycleException
                   (sm.getString("standardManager.notStarted"));
           lifecycle.fireLifecycleEvent(STOP_EVENT, null);
  -        started = false;
  +        setStarted(false);
   
           // Stop the background reaper thread
           threadStop();
   
  -        // Swap out all active sessions
  -        Session sessions[] = findSessions();
  -        for (int i = 0; i < sessions.length; i++) {
  -            StandardSession session = (StandardSession) sessions[i];
  -            if (!session.isValid())
  -                continue;
  -            try {
  -                swapOut(session);
  -            } catch (IOException e) {
  -                ;   // Logged upstream
  +        if (getStore() != null && saveOnRestart) {
  +            unload();
  +        } else {
  +            // Expire all active sessions
  +            Session sessions[] = findSessions();
  +            for (int i = 0; i < sessions.length; i++) {
  +                StandardSession session = (StandardSession) sessions[i];
  +                if (!session.isValid())
  +                    continue;
  +                session.expire();
               }
  -
  -       }
  +        }
  +        
  +        if (getStore() != null && getStore() instanceof Lifecycle)
  +            ((Lifecycle)getStore()).stop();
   
           // Require a new random number generator if we are restarted
           this.random = null;
  @@ -749,7 +924,7 @@
        *
        * FIXME: Probably belongs in the Session class.
        */
  -    private boolean isSessionStale(Session session, long timeNow) {
  +    protected boolean isSessionStale(Session session, long timeNow) {
   
           int maxInactiveInterval = session.getMaxInactiveInterval();
           if (maxInactiveInterval >= 0) {
  @@ -767,7 +942,7 @@
       /**
        * Invalidate all sessions that have expired.
        */
  -    private void processExpires() {
  +    protected void processExpires() {
   
           if (!started)
               return;
  @@ -787,10 +962,127 @@
   
   
       /**
  +     * Swap idle sessions out to Store if they are idle too long.
  +     */
  +    protected void processMaxIdleSwaps() {
  +
  +        if (!isStarted() || maxIdleSwap < 0)
  +            return;
  +
  +        Session sessions[] = findSessions();
  +        long timeNow = System.currentTimeMillis();
  +
  +        // Swap out all sessions idle longer than maxIdleSwap
  +        // FIXME: What's preventing us from mangling a session during
  +        // a request?
  +        if (maxIdleSwap >= 0) {
  +            for (int i = 0; i < sessions.length; i++) {
  +                StandardSession session = (StandardSession) sessions[i];
  +                if (!session.isValid())
  +                    continue;
  +                int timeIdle = // Truncate, do not round up
  +                    (int) ((timeNow - session.getLastAccessedTime()) / 1000L);
  +                if (timeIdle > maxIdleSwap && timeIdle > minIdleSwap) {
  +                    if (debug > 1)
  +                        log(sm.getString
  +                            ("persistentManager.swapMaxIdle", 
  +                             session.getId(), new Integer(timeIdle)));
  +                    try {
  +                        swapOut(session);
  +                    } catch (IOException e) {
  +                        ;   // This is logged in writeSession()
  +                    }
  +                }
  +            }
  +        }
  +        
  +    }
  +
  +
  +    /**
  +     * Swap idle sessions out to Store if too many are active
  +     */
  +    protected void processMaxActiveSwaps() {
  +
  +        if (!isStarted() || getMaxActiveSessions() < 0)
  +            return;
  +
  +        Session sessions[] = findSessions();
  +        
  +        // FIXME: Smarter algorithm (LRU)
  +        if (getMaxActiveSessions() >= sessions.length)
  +            return;
  +
  +        if(debug > 0)
  +            log(sm.getString
  +                ("persistentManager.tooManyActive", 
  +                 new Integer(sessions.length)));
  +
  +        int toswap = sessions.length - getMaxActiveSessions();
  +        long timeNow = System.currentTimeMillis();
  +        
  +        for (int i = 0; i < sessions.length && toswap > 0; i++) {
  +            int timeIdle = // Truncate, do not round up
  +                (int) ((timeNow - sessions[i].getLastAccessedTime()) / 1000L);
  +            if (timeIdle > minIdleSwap) {
  +                if(debug > 1)
  +                    log(sm.getString
  +                        ("persistentManager.swapTooManyActive", 
  +                         sessions[i].getId(), new Integer(timeIdle)));
  +                try {
  +                    swapOut(sessions[i]);
  +                } catch (IOException e) {
  +                    ;   // This is logged in writeSession()
  +                }
  +                toswap--;
  +            }
  +        }
  +
  +    }
  +
  +
  +    /**
  +     * Back up idle sessions.
  +     */
  +    protected void processMaxIdleBackups() {
  +
  +        if (!isStarted() || maxIdleBackup < 0)
  +            return;
  +        
  +        Session sessions[] = findSessions();
  +        long timeNow = System.currentTimeMillis();
  +
  +        // Back up all sessions idle longer than maxIdleBackup
  +        if (maxIdleBackup >= 0) {
  +            for (int i = 0; i < sessions.length; i++) {
  +                StandardSession session = (StandardSession) sessions[i];
  +                if (!session.isValid())
  +                    continue;
  +                int timeIdle = // Truncate, do not round up
  +                    (int) ((timeNow - session.getLastAccessedTime()) / 1000L);
  +                if (timeIdle > maxIdleBackup) {
  +                    if (debug > 1)
  +                        log(sm.getString
  +                            ("persistentManager.backupMaxIdle",
  +                            session.getId(), new Integer(timeIdle)));
  +        
  +                    try {
  +                        writeSession(session);
  +                    } catch (IOException e) {
  +                        ;   // This is logged in writeSession()
  +                    }
  +                }
  +            }
  +        }
  +
  +    }
  +
  +
  +    /**
        * Sleep for the duration specified by the <code>checkInterval</code>
        * property.
        */
  -    private void threadSleep() {
  +    protected void threadSleep() {
   
           try {
               Thread.sleep(checkInterval * 1000L);
  @@ -805,7 +1097,7 @@
        * Start the background thread that will periodically check for
        * session timeouts.
        */
  -    private void threadStart() {
  +    protected void threadStart() {
   
           if (thread != null)
               return;
  
  
  
  1.1                  jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/session/DistributedManager.java
  
  Index: DistributedManager.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/session/DistributedManager.java,v 1.1 2001/05/04 20:45:47 bip Exp $
   * $Revision: 1.1 $
   * $Date: 2001/05/04 20:45:47 $
   *
   * ====================================================================
   *
   * 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.catalina.session;
  
  import java.io.InputStream;
  import java.io.OutputStream;
  import java.io.BufferedInputStream;
  import java.io.BufferedOutputStream;
  import java.io.ByteArrayInputStream;
  import java.io.ByteArrayOutputStream;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.ObjectInputStream;
  import java.io.ObjectOutputStream;
  import java.io.ObjectStreamClass;
  import org.apache.catalina.Cluster;
  import org.apache.catalina.Container;
  import org.apache.catalina.LifecycleException;
  import org.apache.catalina.Loader;
  import org.apache.catalina.Session;
  import org.apache.catalina.cluster.MulticastSender;
  import org.apache.catalina.cluster.MulticastReceiver;
  import org.apache.catalina.cluster.ReplicationWrapper;
  import org.apache.catalina.util.CustomObjectInputStream;
  
  /**
   * This manager is responsible for in memory replication of
   * Sessions across a defined Cluster. It could also utilize a
   * Store to make Sessions persistence.
   *
   * @author Bip Thelin
   * @version $Revision: 1.1 $
   */
  
  public final class DistributedManager extends PersistentManagerBase {
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * The descriptive information about this implementation.
       */
      private static final String info = "DistributedManager/1.0";
  
      /**
       * The descriptive name of this Manager implementation (for logging).
       */
      protected static String name = "DistributedManager";
  
      /**
       * Our MulticastSender, used when replicating sessions
       */
      private MulticastSender multicastSender = null;
  
      /**
       * Our MulticastReceiver
       */
      private MulticastReceiver multicastReceiver = null;
  
  
      // ------------------------------------------------------------- Properties
  
  
      /**
       * Return descriptive information about this Manager implementation and
       * the corresponding version number, in the format
       * <code>&lt;description&gt;/&lt;version&gt;</code>.
       */
      public String getInfo() {
          return (this.info);
      }
      
      /**
       * Return the descriptive short name of this Manager implementation.
       */
      public String getName() {
          return (this.name);
      }
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * Create a Session and replicate it in our Cluster
       *
       * @return The newly created Session
       */
      public Session createSession() {
          Session session = super.createSession();
          ObjectOutputStream oos = null;
          ByteArrayOutputStream bos = null;
          ByteArrayInputStream bis = null;
  
          try {
              bos = new ByteArrayOutputStream();
              oos = new ObjectOutputStream(new BufferedOutputStream(bos));
              
              ((StandardSession)session).writeObjectData(oos);
              oos.close();
              
              byte[] obs = bos.toByteArray();
              multicastSender.send(obs);
  
              if(debug > 0)
                  log("Replicating Session: "+session.getId());
          } catch (IOException e) {
              log("An error occured when replicating Session: "+session.getId());
          }
          
          return (session);
      }
  
      /**
       * Start this manager
       *
       * @exception LifecycleException if an error occurs
       */
      public void start() throws LifecycleException {
          Container container = getContainer();
          Cluster cluster = null;
  
          if(container != null)
              cluster = container.getCluster();
  
          if(cluster != null) {
              this.multicastSender = cluster.getMulticastSender(name);
              this.multicastReceiver = cluster.getMulticastReceiver(name);
          }
  
          super.start();
      }
  
      /**
       * Called from our background thread to process new received Sessions
       *
       */
      public void processMulticastReceiver() {
          Object[] objs = multicastReceiver.getObjects();
          StandardSession _session = null;
          ByteArrayInputStream bis = null;
          Loader loader = null;
          ClassLoader classLoader = null;
          ObjectInputStream ois = null;
          byte[] buf = new byte[5000];
          ReplicationWrapper repObj = null;
  
          for(int i=0; i < objs.length;i++) {
              try {
                  bis = new ByteArrayInputStream(buf);
                  repObj = (ReplicationWrapper)objs[i];
                  buf = repObj.getDataStream();
                  bis = new ByteArrayInputStream(buf, 0, buf.length);
                  
                  if (container != null)
                      loader = container.getLoader();
                  
                  if (loader != null)
                      classLoader = loader.getClassLoader();
                  
                  if (classLoader != null)
                      ois = new CustomObjectInputStream(bis,
                                                        classLoader);
                  else
                      ois = new ObjectInputStream(bis);
                  
                  _session = (StandardSession) createSession();
                  _session.readObjectData(ois);
                  _session.setManager(this);
  
                  if (debug > 0)
                      log("Loading replicated session: "+_session.getId());
              } catch (IOException e) {
                  log("Error occured when trying to read replicated session: "+
                      e.toString());
              } catch (ClassNotFoundException e) {
                  log("Error occured when trying to read replicated session: "+
                      e.toString());
              } finally {
                  if (ois != null) {
                      try {
                          ois.close();
                          bis = null;
                      } catch (IOException e) {
                          ;
                      }
                  }
              }
          }
      }
  
      /**
       * The background thread that checks for session timeouts and shutdown.
       */
      public void run() {
          // Loop until the termination semaphore is set
          while (!threadDone) {
              threadSleep();
              processMulticastReceiver();
              processExpires();
              processPersistenceChecks();
          }
      }
  }
  
  
  
  1.21      +147 -140  jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/startup/Catalina.java
  
  Index: Catalina.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/startup/Catalina.java,v
  retrieving revision 1.20
  retrieving revision 1.21
  diff -u -r1.20 -r1.21
  --- Catalina.java	2001/04/18 18:59:22	1.20
  +++ Catalina.java	2001/05/04 20:45:55	1.21
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/startup/Catalina.java,v 1.20 2001/04/18 18:59:22 craigmcc Exp $
  - * $Revision: 1.20 $
  - * $Date: 2001/04/18 18:59:22 $
  + * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/startup/Catalina.java,v 1.21 2001/05/04 20:45:55 bip Exp $
  + * $Revision: 1.21 $
  + * $Date: 2001/05/04 20:45:55 $
    *
    * ====================================================================
    *
  @@ -97,7 +97,7 @@
    * </u>
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.20 $ $Date: 2001/04/18 18:59:22 $
  + * @version $Revision: 1.21 $ $Date: 2001/05/04 20:45:55 $
    */
   
   public class Catalina {
  @@ -268,34 +268,34 @@
        * Create and configure the XmlMapper we will be using for startup.
        */
       protected XmlMapper createStartMapper() {
  -
  -	// Initialize the mapper
  -	XmlMapper mapper = new XmlMapper();
  -	if (debug)
  -	    mapper.setDebug(999);
  -	mapper.setValidating(false);
  -
  -	// Configure the actions we will be using
  -
  -	mapper.addRule("Server", mapper.objectCreate
  -		     ("org.apache.catalina.core.StandardServer", "className"));
  -	mapper.addRule("Server", mapper.setProperties());
  +        
  +        // Initialize the mapper
  +        XmlMapper mapper = new XmlMapper();
  +        if (debug)
  +            mapper.setDebug(999);
  +        mapper.setValidating(false);
  +        
  +        // Configure the actions we will be using
  +        
  +        mapper.addRule("Server", mapper.objectCreate
  +                       ("org.apache.catalina.core.StandardServer", "className"));
  +        mapper.addRule("Server", mapper.setProperties());
           mapper.addRule("Server", mapper.addChild
  -		       ("setServer", "org.apache.catalina.Server"));
  -
  +                       ("setServer", "org.apache.catalina.Server"));
  +        
           mapper.addRule("Server/Service", mapper.objectCreate
  -                    ("org.apache.catalina.core.StandardService", "className"));
  +                       ("org.apache.catalina.core.StandardService", "className"));
           mapper.addRule("Server/Service", mapper.setProperties());
           mapper.addRule("Server/Service", mapper.addChild
                          ("addService", "org.apache.catalina.Service"));
  -
  +        
           mapper.addRule("Server/Service/Connector", mapper.objectCreate
  -		       ("org.apache.catalina.connector.http.HttpConnector",
  -			"className"));
  -	mapper.addRule("Server/Service/Connector", mapper.setProperties());
  -	mapper.addRule("Server/Service/Connector", mapper.addChild
  -		       ("addConnector", "org.apache.catalina.Connector"));
  -
  +                       ("org.apache.catalina.connector.http.HttpConnector",
  +                        "className"));
  +        mapper.addRule("Server/Service/Connector", mapper.setProperties());
  +        mapper.addRule("Server/Service/Connector", mapper.addChild
  +                       ("addConnector", "org.apache.catalina.Connector"));
  +        
           mapper.addRule("Server/Service/Connector/Factory", mapper.objectCreate
                          ("org.apache.catalina.net.DefaultServerSocketFactory",
                           "className"));
  @@ -304,132 +304,139 @@
           mapper.addRule("Server/Service/Connector/Factory", mapper.addChild
                          ("setFactory",
                           "org.apache.catalina.net.ServerSocketFactory"));
  -
  -	mapper.addRule("Server/Service/Connector/Listener", mapper.objectCreate
  -		       (null, "className"));
  -	mapper.addRule("Server/Service/Connector/Listener",
  -                       mapper.setProperties());
  -	mapper.addRule("Server/Service/Connector/Listener", mapper.addChild
  -		       ("addLifecycleListener",
  -			"org.apache.catalina.LifecycleListener"));
  -
  -	mapper.addRule("Server/Service/Engine", mapper.objectCreate
  -		       ("org.apache.catalina.core.StandardEngine",
  -			"className"));
  -	mapper.addRule("Server/Service/Engine", mapper.setProperties());
  -	mapper.addRule("Server/Service/Engine",
  -		       new LifecycleListenerAction
  -			   ("org.apache.catalina.startup.EngineConfig",
  -			    "configClass"));
  +        
  +        mapper.addRule("Server/Service/Connector/Listener", mapper.objectCreate
  +                       (null, "className"));
  +        mapper.addRule("Server/Service/Connector/Listener",
  +                       mapper.setProperties());
  +        mapper.addRule("Server/Service/Connector/Listener", mapper.addChild
  +                       ("addLifecycleListener",
  +                        "org.apache.catalina.LifecycleListener"));
  +        
  +        mapper.addRule("Server/Service/Engine", mapper.objectCreate
  +                       ("org.apache.catalina.core.StandardEngine",
  +                        "className"));
  +        mapper.addRule("Server/Service/Engine", mapper.setProperties());
  +        mapper.addRule("Server/Service/Engine",
  +                       new LifecycleListenerAction
  +                           ("org.apache.catalina.startup.EngineConfig",
  +                            "configClass"));
           mapper.addRule("Server/Service/Engine",
                          new SetParentClassLoaderAction(parentClassLoader));
  -	mapper.addRule("Server/Service/Engine", mapper.addChild
  -		       ("setContainer", "org.apache.catalina.Container"));
  -
  +        mapper.addRule("Server/Service/Engine", mapper.addChild
  +                       ("setContainer", "org.apache.catalina.Container"));
  +        
           createStartMapperContext("Server/Service/Engine/Context", mapper);
  -	createStartMapperDefaultContext(
  -			"Server/Service/Engine/DefaultContext",
  -                        mapper);
  -
  -	mapper.addRule("Server/Service/Engine/Host", mapper.objectCreate
  -		       ("org.apache.catalina.core.StandardHost",
  -			"className"));
  -	mapper.addRule("Server/Service/Engine/Host", mapper.setProperties());
  +        createStartMapperDefaultContext(
  +                                        "Server/Service/Engine/DefaultContext",
  +                                        mapper);
  +        
  +        mapper.addRule("Server/Service/Engine/Host", mapper.objectCreate
  +                       ("org.apache.catalina.core.StandardHost",
  +                        "className"));
  +        mapper.addRule("Server/Service/Engine/Host", mapper.setProperties());
           mapper.addRule("Server/Service/Engine/Host",
                          new CopyParentClassLoaderAction());
  -	mapper.addRule("Server/Service/Engine/Host",
  -		       new LifecycleListenerAction
  -			   ("org.apache.catalina.startup.HostConfig",
  -			    "configClass"));
  -	mapper.addRule("Server/Service/Engine/Host", mapper.addChild
  -		       ("addChild", "org.apache.catalina.Container"));
  -
  +        mapper.addRule("Server/Service/Engine/Host",
  +                       new LifecycleListenerAction
  +                           ("org.apache.catalina.startup.HostConfig",
  +                            "configClass"));
  +        mapper.addRule("Server/Service/Engine/Host", mapper.addChild
  +                       ("addChild", "org.apache.catalina.Container"));
  +
  +        mapper.addRule("Server/Service/Engine/Host/Cluster",
  +                       mapper.objectCreate(null, "className"));
  +        mapper.addRule("Server/Service/Engine/Host/Cluster",
  +                       mapper.setProperties());
  +        mapper.addRule("Server/Service/Engine/Host/Cluster",
  +                       mapper.addChild("setCluster", "org.apache.catalina.Cluster"));
  +        
           createStartMapperContext("Server/Service/Engine/Host/Context", mapper);
           createStartMapperDefaultContext(
  -			"Server/Service/Engine/Host/DefaultContext",
  -			mapper);
  -
  -	mapper.addRule("Server/Service/Engine/Host/Context/Manager/Store",
  -			mapper.objectCreate(null, "className"));
  -	mapper.addRule("Server/Service/Engine/Host/Context/Manager/Store",
  -			mapper.setProperties());
  -	mapper.addRule("Server/Service/Engine/Host/Context/Manager/Store",
  -			mapper.addChild("setStore", "org.apache.catalina.Store"));
  -
  -	mapper.addRule("Server/Service/Engine/Host/Listener",
  +                                        "Server/Service/Engine/Host/DefaultContext",
  +                                        mapper);
  +        
  +        mapper.addRule("Server/Service/Engine/Host/Context/Manager/Store",
  +                       mapper.objectCreate(null, "className"));
  +        mapper.addRule("Server/Service/Engine/Host/Context/Manager/Store",
  +                       mapper.setProperties());
  +        mapper.addRule("Server/Service/Engine/Host/Context/Manager/Store",
  +                       mapper.addChild("setStore", "org.apache.catalina.Store"));
  +        
  +        mapper.addRule("Server/Service/Engine/Host/Listener",
                          mapper.objectCreate
  -		       (null, "className"));
  -	mapper.addRule("Server/Service/Engine/Host/Listener",
  +                       (null, "className"));
  +        mapper.addRule("Server/Service/Engine/Host/Listener",
                          mapper.setProperties());
  -	mapper.addRule("Server/Service/Engine/Host/Listener", mapper.addChild
  -		       ("addLifecycleListener",
  -			"org.apache.catalina.LifecycleListener"));
  -
  -	mapper.addRule("Server/Service/Engine/Host/Logger", mapper.objectCreate
  -		       (null, "className"));
  -	mapper.addRule("Server/Service/Engine/Host/Logger",
  +        mapper.addRule("Server/Service/Engine/Host/Listener", mapper.addChild
  +                       ("addLifecycleListener",
  +                        "org.apache.catalina.LifecycleListener"));
  +        
  +        mapper.addRule("Server/Service/Engine/Host/Logger", mapper.objectCreate
  +                       (null, "className"));
  +        mapper.addRule("Server/Service/Engine/Host/Logger",
                          mapper.setProperties());
  -	mapper.addRule("Server/Service/Engine/Host/Logger", mapper.addChild
  -		       ("setLogger", "org.apache.catalina.Logger"));
  -
  -	mapper.addRule("Server/Service/Engine/Host/Realm", mapper.objectCreate
  -		       (null, "className"));
  -	mapper.addRule("Server/Service/Engine/Host/Realm",
  +        mapper.addRule("Server/Service/Engine/Host/Logger", mapper.addChild
  +                       ("setLogger", "org.apache.catalina.Logger"));
  +        
  +        mapper.addRule("Server/Service/Engine/Host/Realm", mapper.objectCreate
  +                       (null, "className"));
  +        mapper.addRule("Server/Service/Engine/Host/Realm",
                          mapper.setProperties());
  -	mapper.addRule("Server/Service/Engine/Host/Realm", mapper.addChild
  -		       ("setRealm", "org.apache.catalina.Realm"));
  -
  -	mapper.addRule("Server/Service/Engine/Host/Resources",
  +        mapper.addRule("Server/Service/Engine/Host/Realm", mapper.addChild
  +                       ("setRealm", "org.apache.catalina.Realm"));
  +        
  +        mapper.addRule("Server/Service/Engine/Host/Resources",
                          mapper.objectCreate
  -		       ("org.apache.naming.resources.FileDirContext",
  -			"className"));
  -	mapper.addRule("Server/Service/Engine/Host/Resources",
  -                       mapper.setProperties());
  -	mapper.addRule("Server/Service/Engine/Host/Resources", mapper.addChild
  -		       ("setResources", "javax.naming.directory.DirContext"));
  -
  -	mapper.addRule("Server/Service/Engine/Host/Valve", mapper.objectCreate
  -		       (null, "className"));
  -	mapper.addRule("Server/Service/Engine/Host/Valve",
  -                       mapper.setProperties());
  -	mapper.addRule("Server/Service/Engine/Host/Valve", mapper.addChild
  -		       ("addValve", "org.apache.catalina.Valve"));
  -
  -	mapper.addRule("Server/Service/Engine/Listener", mapper.objectCreate
  -		       (null, "className"));
  -	mapper.addRule("Server/Service/Engine/Listener",
  -                       mapper.setProperties());
  -	mapper.addRule("Server/Service/Engine/Listener", mapper.addChild
  -		       ("addLifecycleListener",
  -			"org.apache.catalina.LifecycleListener"));
  -
  -	mapper.addRule("Server/Service/Engine/Logger", mapper.objectCreate
  -		       (null, "className"));
  -	mapper.addRule("Server/Service/Engine/Logger", mapper.setProperties());
  -	mapper.addRule("Server/Service/Engine/Logger", mapper.addChild
  -		       ("setLogger", "org.apache.catalina.Logger"));
  -
  -	mapper.addRule("Server/Service/Engine/Realm", mapper.objectCreate
  -		       (null, "className"));
  -	mapper.addRule("Server/Service/Engine/Realm", mapper.setProperties());
  -	mapper.addRule("Server/Service/Engine/Realm", mapper.addChild
  -		       ("setRealm", "org.apache.catalina.Realm"));
  -
  -	mapper.addRule("Server/Service/Engine/Resources", mapper.objectCreate
  -		       ("org.apache.naming.resources.FileDirContext",
  -			"className"));
  -	mapper.addRule("Server/Service/Engine/Resources",
  -                       mapper.setProperties());
  -	mapper.addRule("Server/Service/Engine/Resources", mapper.addChild
  -		       ("setResources", "javax.naming.directory.DirContext"));
  -
  -	mapper.addRule("Server/Service/Engine/Valve", mapper.objectCreate
  -		       (null, "className"));
  -	mapper.addRule("Server/Service/Engine/Valve", mapper.setProperties());
  -	mapper.addRule("Server/Service/Engine/Valve", mapper.addChild
  -		       ("addValve", "org.apache.catalina.Valve"));
  -
  -	return (mapper);
  +                       ("org.apache.naming.resources.FileDirContext",
  +                        "className"));
  +        mapper.addRule("Server/Service/Engine/Host/Resources",
  +                       mapper.setProperties());
  +        mapper.addRule("Server/Service/Engine/Host/Resources", mapper.addChild
  +                       ("setResources", "javax.naming.directory.DirContext"));
  +        
  +        mapper.addRule("Server/Service/Engine/Host/Valve", mapper.objectCreate
  +                       (null, "className"));
  +        mapper.addRule("Server/Service/Engine/Host/Valve",
  +                       mapper.setProperties());
  +        mapper.addRule("Server/Service/Engine/Host/Valve", mapper.addChild
  +                       ("addValve", "org.apache.catalina.Valve"));
  +        
  +        mapper.addRule("Server/Service/Engine/Listener", mapper.objectCreate
  +                       (null, "className"));
  +        mapper.addRule("Server/Service/Engine/Listener",
  +                       mapper.setProperties());
  +        mapper.addRule("Server/Service/Engine/Listener", mapper.addChild
  +                       ("addLifecycleListener",
  +                        "org.apache.catalina.LifecycleListener"));
  +        
  +        mapper.addRule("Server/Service/Engine/Logger", mapper.objectCreate
  +                       (null, "className"));
  +        mapper.addRule("Server/Service/Engine/Logger", mapper.setProperties());
  +        mapper.addRule("Server/Service/Engine/Logger", mapper.addChild
  +                       ("setLogger", "org.apache.catalina.Logger"));
  +        
  +        mapper.addRule("Server/Service/Engine/Realm", mapper.objectCreate
  +                       (null, "className"));
  +        mapper.addRule("Server/Service/Engine/Realm", mapper.setProperties());
  +        mapper.addRule("Server/Service/Engine/Realm", mapper.addChild
  +                       ("setRealm", "org.apache.catalina.Realm"));
  +        
  +        mapper.addRule("Server/Service/Engine/Resources", mapper.objectCreate
  +                       ("org.apache.naming.resources.FileDirContext",
  +                        "className"));
  +        mapper.addRule("Server/Service/Engine/Resources",
  +                       mapper.setProperties());
  +        mapper.addRule("Server/Service/Engine/Resources", mapper.addChild
  +                       ("setResources", "javax.naming.directory.DirContext"));
  +        
  +        mapper.addRule("Server/Service/Engine/Valve", mapper.objectCreate
  +                       (null, "className"));
  +        mapper.addRule("Server/Service/Engine/Valve", mapper.setProperties());
  +        mapper.addRule("Server/Service/Engine/Valve", mapper.addChild
  +                       ("addValve", "org.apache.catalina.Valve"));
  +        
  +        return (mapper);
   
       }