bip         01/05/04 13:48:04

  Added:       catalina/src/share/org/apache/catalina/cluster
                        ClusterMemberInfo.java MulticastReceiver.java
                        MulticastSender.java ReplicationWrapper.java
                        StandardCluster.java
  Log:
  Basic Cluster implementation
  
  Revision  Changes    Path
  1.1                  
jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/cluster/ClusterMemberInfo.java
  
  Index: ClusterMemberInfo.java
  ===================================================================
  /*
   * $Header: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/cluster/ClusterMemberInfo.java,v
 1.1 2001/05/04 20:48:00 bip Exp $
   * $Revision: 1.1 $
   * $Date: 2001/05/04 20:48:00 $
   *
   * ====================================================================
   *
   * 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 [EMAIL PROTECTED]
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */ 
  
  package org.apache.catalina.cluster;
  
  /**
   * Class that represents a member in a Cluster, keeps information
   * that can be used when implementing Classes thats utilizing a Cluster.
   *
   * @author Bip Thelin
   * @version $Revision: 1.1 $
   */
  
  public final class ClusterMemberInfo {
  
      // ------------------------------------------------------------- Properties
  
      // --------------------------------------------------------- Public Methods
  }
  
  
  
  1.1                  
jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/cluster/MulticastReceiver.java
  
  Index: MulticastReceiver.java
  ===================================================================
  /*
   * $Header: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/cluster/MulticastReceiver.java,v
 1.1 2001/05/04 20:48:01 bip Exp $
   * $Revision: 1.1 $
   * $Date: 2001/05/04 20:48:01 $
   *
   * ====================================================================
   *
   * 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 [EMAIL PROTECTED]
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */ 
  
  package org.apache.catalina.cluster;
  
  import java.net.DatagramPacket;
  import java.net.InetAddress;
  import java.net.MulticastSocket;
  import java.io.InputStream;
  import java.io.OutputStream;
  import java.io.BufferedOutputStream;
  import java.io.ByteArrayInputStream;
  import java.io.ByteArrayOutputStream;
  import java.io.IOException;
  import java.io.ObjectInputStream;
  import java.io.ObjectOutputStream;
  import java.io.ObjectStreamClass;
  import java.util.Vector;
  
  
  /**
   * This class is responsible for checking for incoming multicast
   * data and determine if the data belongs to us and if so push
   * it onto an internal stack and let it be picked up when needed.
   *
   * @author Bip Thelin
   * @version $Revision: 1.1 $
   */
  
  public class MulticastReceiver implements Runnable {
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * The unique message ID
       */
      private static String senderId = null;
  
      /**
       * The MulticastSocket to use
       */
      private MulticastSocket multicastSocket = null;
  
      /**
       * Our Thread name
       */
      private String threadName = "MulticastReceiver";
  
      /**
       * The stack that keeps incoming requests
       */
      private static Vector stack = new Vector();
  
      /**
       * Has this component been started?
       */
      private boolean started = false;
  
      /**
       * The background thread.
       */
      private Thread thread = null;
  
      /**
       * The background thread completion semaphore.
       */
      protected boolean threadDone = false;
  
      /**
       * The interval for the background thread to sleep
       */
      private int checkInterval = 5;
  
      // --------------------------------------------------------- Public Methods
  
      /**
       * Create a new MulticastReceiver.
       *
       * @param senderId The unique senderId
       * @param multicastSocket The MulticastSocket to use
       */
      MulticastReceiver(String senderId, MulticastSocket multicastSocket,
                      InetAddress multicastAddress, int multicastPort) {
          this.multicastSocket = multicastSocket;
          this.senderId = senderId;
      }
  
      /**
       * Receive the objects currently in our stack
       *
       * @return An array with objects
       */
      public Object[] getObjects() {
          Object[] objs = stack.toArray();
          stack.removeAllElements();
  
          return (objs);
      }
  
      /**
       * Start our component
       */
      public void start() {
          started = true;
  
          // Start the background reaper thread
          threadStart();
      }
  
      /**
       * Stop our component
       */
      public void stop() {
          started = false;
  
          // Stop the background reaper thread
          threadStop();
      }
  
      // --------------------------------------------------------- Private Methods
  
      /**
       * Check our multicast socket for new data and determine if the
       * data matches us(senderId) and if so push it onto the stack,
       */
      private void receive() {
          try {
              byte[] buf = new byte[5000];
              DatagramPacket recv = new DatagramPacket(buf, buf.length);
              ByteArrayInputStream ips = null;
              ObjectInputStream ois = null;
  
              multicastSocket.receive(recv);
              ips = new ByteArrayInputStream(buf, 0, buf.length);
              ois = new ObjectInputStream(ips);
              ReplicationWrapper obj = (ReplicationWrapper)ois.readObject();
  
              if(obj.getSenderId().equals(this.senderId))
                  stack.add(obj);
          } catch (IOException e) {
              System.out.println("An error occured when trying to replicate: "+
                                 e.toString());
          } catch (ClassNotFoundException e) {
              System.out.println("An error occured when trying to replicate: "+
                                 e.toString());
          }
      }
  
      // ------------------------------------------------------ Background Thread
  
      /**
       * The background thread.
       */
      public void run() {
          // Loop until the termination semaphore is set
          while (!threadDone) {
              receive();
              threadSleep();
          }
      }
  
      /**
       * Sleep for the duration specified by the <code>checkInterval</code>
       * property.
       */
      private void threadSleep() {
          try {
              Thread.sleep(checkInterval * 1000L);
          } catch (InterruptedException e) {
              ;
          }
      }
  
      /**
       * Start the background thread.
       */
      private void threadStart() {
          if (thread != null)
              return;
  
          threadDone = false;
          threadName = threadName+"["+senderId+"]";
          thread = new Thread(this, threadName);
          thread.setDaemon(true);
          thread.start();
      }
  
      /**
       * Stop the background thread.
       */
      private void threadStop() {
          if (thread == null)
              return;
  
          threadDone = true;
          thread.interrupt();
          try {
              thread.join();
          } catch (InterruptedException e) {
              ;
          }
  
          thread = null;
      }
  }
  
  
  
  1.1                  
jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/cluster/MulticastSender.java
  
  Index: MulticastSender.java
  ===================================================================
  /*
   * $Header: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/cluster/MulticastSender.java,v
 1.1 2001/05/04 20:48:01 bip Exp $
   * $Revision: 1.1 $
   * $Date: 2001/05/04 20:48:01 $
   *
   * ====================================================================
   *
   * 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 [EMAIL PROTECTED]
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */ 
  
  package org.apache.catalina.cluster;
  
  import java.net.DatagramPacket;
  import java.net.InetAddress;
  import java.net.MulticastSocket;
  import java.io.InputStream;
  import java.io.OutputStream;
  import java.io.BufferedOutputStream;
  import java.io.ByteArrayOutputStream;
  import java.io.IOException;
  import java.io.ObjectOutputStream;
  import java.io.ObjectStreamClass;
  
  
  /**
   * This class is responsible for sending outgoing multicast
   * packets to a Cluster.
   *
   * @author Bip Thelin
   * @version $Revision: 1.1 $
   */
  
  public class MulticastSender {
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * The unique message ID
       */
      private static String senderId = null;
  
      /**
       * The MulticastSocket to use
       */
      private MulticastSocket multicastSocket = null;
  
      /**
       * The multicastAdress this socket is bound to
       */
      private InetAddress multicastAddress = null;
  
      /**
       * The multicastPort this socket is bound to
       */
      private int multicastPort;
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * Create a new MulticastSender, only receivers with our
       * senderId will receive our data.
       *
       * @param senderId The senderId
       * @param multicastSocket the socket to use
       * @param multicastAddress the address to use
       * @param multicastPort the port to use
       */
      MulticastSender(String senderId, MulticastSocket multicastSocket,
                      InetAddress multicastAddress, int multicastPort) {
          this.multicastAddress = multicastAddress;
          this.multicastPort = multicastPort;
          this.multicastSocket = multicastSocket;
          this.senderId = senderId;
      }
  
      /**
       * Send multicast data
       *
       * @param b data to be sent
       */
      public synchronized void send(byte[] b) {
          ReplicationWrapper out = new ReplicationWrapper(b, senderId);
          ObjectOutputStream oos = null;
          ByteArrayOutputStream bos = null;
  
          try {        
              bos = new ByteArrayOutputStream();
              oos = new ObjectOutputStream(new BufferedOutputStream(bos));
          
              oos.writeObject(out);
              oos.flush();
          
              byte[] obs = bos.toByteArray();
              int size = obs.length;
              System.out.println("size: "+size);
              DatagramPacket p = new DatagramPacket(obs, size,
                                                    multicastAddress, multicastPort);
              multicastSocket.send(p);
          } catch (IOException e) {
              //            log("An error occured when trying to replicate.");
          }
      }
  
      /**
       * Send multicast data
       *
       * @param p data to be sent
       */
      public synchronized void send(DatagramPacket p) {
          try {
              multicastSocket.send(p);
          } catch (IOException e) {
              //            log("An error occured when trying to replicate.");
          }
      }
  }
  
  
  
  1.1                  
jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/cluster/ReplicationWrapper.java
  
  Index: ReplicationWrapper.java
  ===================================================================
  /*
   * $Header: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/cluster/ReplicationWrapper.java,v
 1.1 2001/05/04 20:48:02 bip Exp $
   * $Revision: 1.1 $
   * $Date: 2001/05/04 20:48:02 $
   *
   * ====================================================================
   *
   * 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 [EMAIL PROTECTED]
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */
  
  package org.apache.catalina.cluster;
  
  import java.io.IOException;
  import java.io.OutputStream;
  import java.io.Serializable;
  
  /**
   * A ReplicationWrapper, used when sending and receiving multicast
   * data, wrapped is the data and the senderId which is used for
   * identification.
   *
   * @author Bip Thelin
   * @version $Revision: 1.1 $, $Date: 2001/05/04 20:48:02 $
   */
  public final class ReplicationWrapper implements Serializable {
  
      /**
       * Our buffer to hold the stream
       */
      private byte[] _buf = null;
  
      /**
       * Our sender Id
       */
      private String senderId = null;
  
      /**
       * Construct a new ReplicationWrapper
       *
       */
      public ReplicationWrapper(byte[] b, String senderId) {
          this.senderId = senderId;
          _buf = b;
      }
  
      /**
       * Write our stream to the <code>OutputStream</code> provided.
       *
       * @param out the OutputStream to write this stream to
       * @exception IOException if an input/output error occurs
       */
      public final void writeTo(OutputStream out) throws IOException {
          out.write(_buf);
      }
  
      /**
       * return our internal data as a array of bytes
       *
       * @return a our data
       */
      public final byte[] getDataStream() {
          return(_buf);
      }
  
      /**
       * Set the sender id for this wrapper
       *
       * @param senderId The sender id
       */
      public final void setSenderId(String senderId) {
          this.senderId = senderId;
      }
  
      /**
       * get the sender id for this wrapper
       *
       * @return The sender Id associated with this wrapper
       */
      public final String getSenderId() {
          return(this.senderId);
      }
  }
  
  
  
  1.1                  
jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/cluster/StandardCluster.java
  
  Index: StandardCluster.java
  ===================================================================
  /*
   * $Header: 
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/cluster/StandardCluster.java,v
 1.1 2001/05/04 20:48:03 bip Exp $
   * $Revision: 1.1 $
   * $Date: 2001/05/04 20:48:03 $
   *
   * ====================================================================
   *
   * 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 [EMAIL PROTECTED]
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */ 
  
  package org.apache.catalina.cluster;
  
  import java.beans.PropertyChangeSupport;
  import java.net.InetAddress;
  import java.net.MulticastSocket;
  import java.net.UnknownHostException;
  import java.io.IOException;
  import java.util.Collection;
  import org.apache.catalina.Cluster;
  import org.apache.catalina.Container;
  import org.apache.catalina.Lifecycle;
  import org.apache.catalina.LifecycleEvent;
  import org.apache.catalina.LifecycleException;
  import org.apache.catalina.LifecycleListener;
  import org.apache.catalina.Logger;
  import org.apache.catalina.cluster.ClusterMemberInfo;
  import org.apache.catalina.cluster.MulticastSender;
  import org.apache.catalina.cluster.MulticastReceiver;
  import org.apache.catalina.util.LifecycleSupport;
  
  /**
   * A <b>Cluster</b> implementation. Responsible for setting up
   * a cluster and provides callers with a valid multicast receiver/sender.
   *
   * @author Bip Thelin
   * @version $Revision: 1.1 $
   */
  
  public final class StandardCluster
      implements Cluster, Lifecycle, Runnable {
  
      // ----------------------------------------------------- Instance Variables
  
      /**
       * Descriptive information about this component implementation.
       */
      private static final String info = "StandardCluster/1.0";
  
      /**
       * Name to register for the background thread.
       */
      private String threadName = "StandardCluster";
  
      /**
       * Name for logging purpose
       */
      private String clusterImpName = "StandardCluster";
  
      /**
       * The background thread.
       */
      private Thread thread = null;
  
      /**
       * The background thread completion semaphore.
       */
      private boolean threadDone = false;
  
      /**
       * The cluster name to join
       */
      private String clusterName = null;
  
      /**
       * The Container associated with this Cluster.
       */
      private Container container = null;
  
      /**
       * The MulticastPort to use with this cluster
       */
      private int multicastPort;
  
      /**
       * The MulticastAdress to use with this cluster
       */
      private InetAddress multicastAddress = null;
  
      /**
       * Our MulticastSocket
       */
      private MulticastSocket multicastSocket = null;
  
      /**
       * The lifecycle event support for this component.
       */
      private LifecycleSupport lifecycle = new LifecycleSupport(this);
  
      /**
       * Has this component been started?
       */
      private boolean started = false;
  
      /**
       * The property change support for this component.
       */
      private PropertyChangeSupport support = new PropertyChangeSupport(this);
  
      /**
       * The debug level for this Container
       */
      private int debug = 99;
  
      /**
       * The interval for the background thread to sleep
       */
      private int checkInterval = 60;
  
      // ------------------------------------------------------------- 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(this.info);
      }
  
      /**
       * Return a <code>String</code> containing the name of this
       * Cluster implementation, used for logging
       *
       * @return The Cluster implementation
       */
      protected String getName() {
          return(this.clusterImpName);
      }
  
      /**
       * 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() {
          return(this.clusterName);
      }
  
      /**
       * 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) {
          String oldClusterName = this.clusterName;
          this.clusterName = clusterName;
          support.firePropertyChange("clusterName",
                                     oldClusterName,
                                     this.clusterName);
      }
  
      /**
       * Set the Container associated with our Cluster
       *
       * @param container The Container to use
       */
      public void setContainer(Container container) {
          Container oldContainer = this.container;
          this.container = container;
          support.firePropertyChange("container",
                                     oldContainer,
                                     this.container);
      }
  
      /**
       * Get the Port associated with our Cluster
       *
       * @return The Port associated with our Cluster
       */
      public int getMulticastPort() {
          return(this.multicastPort);
      }
  
      /**
       * Set the Port associated with our Cluster
       *
       * @param port The Port to use
       */
      public void setMulticastPort(int multicastPort) {
          int oldMulticastPort = this.multicastPort;
          this.multicastPort = multicastPort;
          support.firePropertyChange("multicastPort",
                                     oldMulticastPort,
                                     this.multicastPort);
      }
  
      /**
       * Get the Groupaddress associated with our Cluster
       *
       * @return The Groupaddress associated with our Cluster
       */
      public InetAddress getMulticastAddress() {
          return(this.multicastAddress);
      }
  
      /**
       * Set the Groupaddress associated with our Cluster
       *
       * @param port The Groupaddress to use
       */
      public void setMulticastAddress(String multicastAddress) {
          try {
              InetAddress oldMulticastAddress = this.multicastAddress;
              this.multicastAddress = InetAddress.getByName(multicastAddress);
              support.firePropertyChange("multicastAddress",
                                         oldMulticastAddress,
                                         this.multicastAddress);
          } catch (UnknownHostException e) {
              log("Invalid multicastAddress: "+multicastAddress);
          }
      }
  
      /**
       * Get the Container associated with our Cluster
       *
       * @return The Container associated with our Cluster
       */
      public Container getContainer() {
          return(this.container);
      }
  
      // --------------------------------------------------------- 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() {
          return(null);
      }
  
      /**
       * Return cluster information about the local host
       *
       * @return Cluster information
       */
      public ClusterMemberInfo getLocalClusterInfo() {
          return(null);
      }
  
      /**
       * 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) {
          MulticastSender send = new MulticastSender(senderId,
                                                     multicastSocket,
                                                     multicastAddress,
                                                     multicastPort);
  
          return(send);
      }
  
      /**
       * 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) {
          MulticastReceiver recv = new MulticastReceiver(senderId,
                                                         multicastSocket,
                                                         multicastAddress,
                                                         multicastPort);
          recv.start();
  
          return(recv);
      }
  
      /**
       * Log a message on the Logger associated with our Container (if any).
       *
       * @param message Message to be logged
       */
      protected void log(String message) {
          Logger logger = null;
  
          if (container != null)
              logger = container.getLogger();
  
          if (logger != null) {
              logger.log(getName() + "[" + container.getName() + "]: "
                         + message);
          } else {
              String containerName = null;
              if (container != null)
                  containerName = container.getName();
  
              System.out.println(getName() + "[" + containerName
                                 + "]: " + message);
          }
      }
  
      // ------------------------------------------------------ Lifecycle Methods
  
  
      /**
       * Add a lifecycle event listener to this component.
       *
       * @param listener The listener to add
       */
      public void addLifecycleListener(LifecycleListener listener) {
          lifecycle.addLifecycleListener(listener);
      }
  
  
      /**
       * Remove a lifecycle event listener from this component.
       *
       * @param listener The listener to remove
       */
      public void removeLifecycleListener(LifecycleListener listener) {
          lifecycle.removeLifecycleListener(listener);
      }
  
      /**
       * Prepare for the beginning of active use of the public methods of this
       * component.  This method should be called after <code>configure()</code>,
       * and before any of the public methods of the component are utilized.
       *
       * @exception IllegalStateException if this component has already been
       *  started
       * @exception LifecycleException if this component detects a fatal error
       *  that prevents this component from being used
       */
      public void start() throws LifecycleException {
          if (debug > 1)
              log("Started");
  
          try {
              multicastSocket = new MulticastSocket(multicastPort);
  
              if(multicastSocket != null && multicastAddress != null) {
                  multicastSocket.joinGroup(multicastAddress);
  
                  if (debug > 1)
                      log("Joining group: "+multicastAddress);
              } else {
                  log("multicastSocket || multicastAddress can't be null");
              }
          } catch (IOException e) {
              log("An error occured when trying to join group");
          }
  
          // Validate and update our current component state
          if (started)
              ;
  
          lifecycle.fireLifecycleEvent(START_EVENT, null);
          started = true;
  
          // Start the background reaper thread
          threadStart();
      }
  
      /**
       * 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");
  
          try {
              multicastSocket.leaveGroup(multicastAddress);
              multicastSocket = null;
          } catch (IOException e) {
              ;
          }
  
          if (debug > 1)
              log("Leaving group: "+multicastAddress);
  
          // Validate and update our current component state
          if (!started)
              ;
  
          lifecycle.fireLifecycleEvent(STOP_EVENT, null);
          started = false;
  
          // Stop the background reaper thread
          threadStop();
      }
  
      // ------------------------------------------------------ Background Thread
  
      /**
       * The background thread.
       */
      public void run() {
          // Loop until the termination semaphore is set
          while (!threadDone) {
              threadSleep();
          }
      }
  
      /**
       * Sleep for the duration specified by the <code>checkInterval</code>
       * property.
       */
      private void threadSleep() {
          try {
              Thread.sleep(checkInterval * 1000L);
          } catch (InterruptedException e) {
              ;
          }
      }
  
      /**
       * Start the background thread.
       */
      private void threadStart() {
          if (thread != null)
              return;
  
          threadDone = false;
          threadName = "StandardCluster[" + getClusterName() + "]";
          thread = new Thread(this, threadName);
          thread.setDaemon(true);
          thread.start();
      }
  
      /**
       * Stop the background thread.
       */
      private void threadStop() {
          if (thread == null)
              return;
  
          threadDone = true;
          thread.interrupt();
          try {
              thread.join();
          } catch (InterruptedException e) {
              ;
          }
  
          thread = null;
      }
  }
  
  
  

Reply via email to