[jboss-cvs] JBossAS SVN: r76670 - in trunk: cluster/src/main/org/jboss/ha/singleton and 4 other directories.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Tue Aug 5 12:17:02 EDT 2008


Author: pferraro
Date: 2008-08-05 12:17:01 -0400 (Tue, 05 Aug 2008)
New Revision: 76670

Added:
   trunk/cluster/src/main/org/jboss/ha/jmx/AbstractHAServiceMBeanSupport.java
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ha/rpc/ClusteredMCMPHandlerRpcHandler.java
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ha/rpc/ModClusterServiceRpcHandler.java
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ha/rpc/ResetRequestSourceRpcHandler.java
Removed:
   trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonElectionPolicy.java
   trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonElectionPolicyBase.java
   trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonElectionPolicyMBean.java
   trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonElector.java
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ha/ModClusterServiceHASingletonElectionPolicy.java
Modified:
   trunk/cluster/src/main/org/jboss/ha/jmx/HAServiceMBean.java
   trunk/cluster/src/main/org/jboss/ha/jmx/HAServiceMBeanSupport.java
   trunk/cluster/src/main/org/jboss/ha/singleton/HASingleton.java
   trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonController.java
   trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonControllerMBean.java
   trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonElectionPolicySimple.java
   trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonElectionPolicySimpleMBean.java
   trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonMBean.java
   trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonSupport.java
   trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonSupportMBean.java
   trunk/cluster/src/main/org/jboss/ha/singleton/PreferredMasterElectionPolicy.java
   trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/test/HAServiceMBeanSupportUnitTestCase.java
   trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/test/HASingletonSupportUnitTestCase.java
   trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/test/PreferredMasterElectionPolicyUnitTestCase.java
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ModClusterService.java
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ModClusterServiceMBean.java
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ha/ClusteredMCMPHandlerImpl.java
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ha/HASingletonAwareResetRequestSource.java
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ha/ModClusterServiceDRMEntry.java
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ha/rpc/PeerMCMPDiscoveryStatus.java
Log:
Refactored HASingletonSupport into pojo + mbean wrapper.
Simplified responsibility of HASingletonElectionPolicy.

Added: trunk/cluster/src/main/org/jboss/ha/jmx/AbstractHAServiceMBeanSupport.java
===================================================================
--- trunk/cluster/src/main/org/jboss/ha/jmx/AbstractHAServiceMBeanSupport.java	                        (rev 0)
+++ trunk/cluster/src/main/org/jboss/ha/jmx/AbstractHAServiceMBeanSupport.java	2008-08-05 16:17:01 UTC (rev 76670)
@@ -0,0 +1,401 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.ha.jmx;
+
+import java.io.Serializable;
+import java.util.List;
+
+import javax.management.AttributeChangeNotification;
+import javax.management.Notification;
+import javax.management.ObjectName;
+
+import org.jboss.beans.metadata.api.annotations.Inject;
+import org.jboss.beans.metadata.api.model.FromContext;
+import org.jboss.ha.framework.interfaces.DistributedState;
+import org.jboss.ha.framework.interfaces.HAPartition;
+import org.jboss.ha.framework.interfaces.HAService;
+import org.jboss.ha.framework.server.ClusterPartitionMBean;
+import org.jboss.ha.framework.server.EventFacility;
+import org.jboss.ha.framework.server.EventFactory;
+import org.jboss.system.ServiceMBeanSupport;
+
+/**
+ * Abstract implementation of HAServiceMBean for use by subclasses, e.g. {@link org.jboss.ha.singleton.HASingletonSupport}.
+ * 
+ * @param S the class of the HAService delegate
+ * @author Paul Ferraro
+ */
+ at SuppressWarnings("deprecation")
+public abstract class AbstractHAServiceMBeanSupport<S extends HAService<Notification>>
+   extends ServiceMBeanSupport
+   implements HAServiceMBean, HAService<Notification>, EventFactory<Notification>, EventFacility<Notification>
+{
+   private final S service = this.createHAService();
+
+   private volatile boolean sendLocalLifecycleNotifications = true;
+   private volatile boolean sendRemoteLifecycleNotifications = true;
+
+   /**
+    * Defines the object used to delegate service methods.
+    * @return an {@link HAService} delegate
+    */
+   protected abstract S createHAService();
+
+   /**
+    * @return the object created by {@link #createHAService()}.
+    */
+   protected final S getHAService()
+   {
+      return this.service;
+   }
+   
+   // Public --------------------------------------------------------
+   
+   public HAPartition getHAPartition()
+   {
+      return this.service.getHAPartition();
+   }
+   
+   public void setHAPartition(HAPartition partition)
+   {
+      this.service.setHAPartition(partition);
+   }
+
+   public void setClusterPartition(ClusterPartitionMBean clusterPartition)
+   {
+      if ((this.getState() != STARTED) && (this.getState() != STARTING))
+      {
+         this.service.setHAPartition(clusterPartition.getHAPartition());
+      }
+   }
+
+   public String getPartitionName()
+   {
+      return this.service.getHAPartition().getPartitionName();
+   }
+   
+   public boolean isRegisterThreadContextClassLoader()
+   {
+      return this.service.isRegisterThreadContextClassLoader();
+   }
+   
+   public void setRegisterThreadContextClassLoader(boolean register)
+   {
+      this.service.setRegisterThreadContextClassLoader(register);
+   }
+
+   // Protected ------------------------------
+
+   /**
+    * 
+    * 
+    * Convenience method for sharing state across a cluster partition.
+    * Delegates to the DistributedStateService
+    * 
+    * @param key key for the distributed object
+    * @param value the distributed object
+    * 
+    */
+   public void setDistributedState(String key, Serializable value) throws Exception
+   {
+      DistributedState ds = this.getHAPartition().getDistributedStateService();
+      ds.set(this.getServiceHAName(), key, value);
+   }
+
+   /**
+    * 
+    * Convenience method for sharing state across a cluster partition.
+    * Delegates to the DistributedStateService
+    * 
+    * @param key key for the distributed object
+    * @return Serializable the distributed object
+    * 
+    */
+   public Serializable getDistributedState(String key)
+   {
+      DistributedState ds = this.getHAPartition().getDistributedStateService();
+      return ds.get(this.getServiceHAName(), key);
+   }
+
+   /**
+    * @see org.jboss.system.ServiceMBeanSupport#createService()
+    */
+   @Override
+   protected void createService() throws Exception
+   {
+      this.service.create();
+   }
+   
+   /**
+    * <p>
+    * Implementors of this method should not
+    * code the singleton logic here.
+    * The MBean lifecycle create/start/stop are separate from
+    * the singleton logic.
+    * Singleton logic should originate in becomeMaster().
+    * </p>
+    * 
+    * <p>
+    * <b>Attention</b>: Always call this method when you overwrite it in a subclass
+    *                   because it elects the master singleton node.
+    * </p>
+    * 
+    */
+   @Override
+   protected void startService() throws Exception
+   {
+      this.log.debug("start HAServiceMBeanSupport");
+      
+      if (this.getHAPartition() == null)
+      {
+         throw new IllegalStateException("HAPartition property must be set before starting HAServiceMBeanSupport");
+      }
+
+      this.setupPartition();
+
+      this.service.start();
+   }
+   
+   /**
+    * <p>
+    * <b>Attention</b>: Always call this method when you overwrite it in a subclass
+    * </p>
+    * 
+    */
+   @Override
+   protected void stopService() throws Exception
+   {
+      this.log.debug("stop HAServiceMBeanSupport");
+
+      this.service.stop();
+   }
+
+   /**
+    * @see org.jboss.system.ServiceMBeanSupport#destroyService()
+    */
+   @Override
+   protected void destroyService() throws Exception
+   {
+      this.service.destroy();
+   }
+
+   protected void setupPartition() throws Exception
+   {
+      // method no longer used by base implementation
+   }
+
+   @SuppressWarnings("unchecked")
+   public List callMethodOnPartition(String methodName, Object[] args, Class[] types) throws Exception
+   {
+      return this.getHAPartition().callMethodOnCluster(this.getServiceHAName(), methodName, args, types, true);
+   }
+
+   @SuppressWarnings("unchecked")
+   protected void callAsyncMethodOnPartition(String methodName, Object[] args, Class[] types) throws Exception
+   {
+      this.getHAPartition().callAsynchMethodOnCluster(this.getServiceHAName(), methodName, args, types, true);
+   }
+   
+   /**
+    * Gets whether JMX Notifications should be sent to local (same JVM) listeners
+    * if the notification is for an attribute change to attribute "State".
+    * <p>
+    * Default is <code>true</code>.
+    * </p>
+    * @see #sendNotification(Notification)
+    */
+   public boolean getSendLocalLifecycleNotifications()
+   {
+      return this.sendLocalLifecycleNotifications;
+   }
+
+   /**
+    * Sets whether JMX Notifications should be sent to local (same JVM) listeners
+    * if the notification is for an attribute change to attribute "State".
+    * <p>
+    * Default is <code>true</code>.
+    * </p>
+    * @see #sendNotification(Notification)
+    */
+   public void setSendLocalLifecycleNotifications(boolean sendLocalLifecycleNotifications)
+   {
+      this.sendLocalLifecycleNotifications = sendLocalLifecycleNotifications;
+   }
+
+   /**
+    * Gets whether JMX Notifications should be sent to remote listeners
+    * if the notification is for an attribute change to attribute "State".
+    * <p>
+    * Default is <code>true</code>.
+    * </p>
+    * <p>
+    * See http://jira.jboss.com/jira/browse/JBAS-3194 for an example of a
+    * use case where this property should be set to false.
+    * </p>
+    * 
+    * @see #sendNotification(Notification)
+    */
+   public boolean getSendRemoteLifecycleNotifications()
+   {
+      return this.sendRemoteLifecycleNotifications;
+   }
+
+   /**
+    * Sets whether JMX Notifications should be sent to remote listeners
+    * if the notification is for an attribute change to attribute "State".
+    * <p>
+    * Default is <code>true</code>.
+    * </p>
+    * <p>
+    * See http://jira.jboss.com/jira/browse/JBAS-3194 for an example of a
+    * use case where this property should be set to false.
+    * </p>
+    * 
+    * @see #sendNotification(Notification)
+    */
+   public void setSendRemoteLifecycleNotifications(boolean sendRemoteLifecycleNotifications)
+   {
+      this.sendRemoteLifecycleNotifications = sendRemoteLifecycleNotifications;
+   }
+
+   /** 
+    * Broadcast the notification to the remote listener nodes (if any) and then 
+    * invoke super.sendNotification() to notify local listeners.
+    * 
+    * @param notification sent out to local listeners and other nodes. It should be serializable.
+    * It is recommended that the source of the notification is an ObjectName of an MBean that 
+    * is is available on all nodes where the broadcaster MBean is registered. 
+    *   
+    * @see #getSendLocalLifecycleNotifications()
+    * @see #getSendRemoteLifecycleNotifications()
+    * @see javax.management.NotificationBroadcasterSupport#sendNotification(Notification)
+    * @see org.jboss.mx.util.JBossNotificationBroadcasterSupport#sendNotification(javax.management.Notification)
+    */
+   public void sendNotification(Notification notification)
+   {
+      boolean stateChange = (notification instanceof AttributeChangeNotification) ? "State".equals(((AttributeChangeNotification) notification).getAttributeName()) : false;
+      
+      if (!stateChange || this.sendRemoteLifecycleNotifications)
+      {
+         try
+         {
+            this.sendNotificationRemote(notification);
+         }
+         catch (Throwable e)
+         {
+            // even if broadcast failed, local notification should still be sent
+            this.log.warn("handleNotification( " + notification + " ) failed ", e);
+         }
+      }
+      
+      if (!stateChange || this.sendLocalLifecycleNotifications)
+      {
+         this.sendNotificationToLocalListeners(notification);
+      }
+   }
+
+   /**
+    * 
+    * Broadcast a notifcation remotely to the partition participants
+    * 
+    * @param notification
+    */
+   protected void sendNotificationRemote(Notification notification) throws Exception
+   {
+      // Overriding the source MBean with its ObjectName
+      // to ensure that it can be safely transferred over the wire
+      notification.setSource(this.getServiceName());
+      
+      this.handleEvent(notification);
+   }
+
+   protected void sendNotificationToLocalListeners(Notification notification)
+   {
+      this.notifyListeners(notification);
+   }
+
+   /**
+    * @see org.jboss.ha.framework.server.EventFacility#notifyListeners(java.util.EventObject)
+    */
+   public void notifyListeners(Notification notification)
+   {
+      super.sendNotification(notification);
+   }
+
+   /**
+    * @see org.jboss.ha.framework.interfaces.EventListener#handleEvent(java.util.EventObject)
+    */
+   public void handleEvent(Notification notification) throws Exception
+   {
+      this.service.handleEvent(notification);
+   }
+
+   /**
+    * @see org.jboss.ha.framework.server.EventFactory#createEvent(java.lang.Object, java.lang.String)
+    */
+   public Notification createEvent(Object source, String type)
+   {
+      return new Notification(type, this, this.getNextNotificationSequenceNumber());
+   }
+
+   /**
+    * 
+    * Override this method only if you need to provide a custom partition wide unique service name.
+    * The default implementation will usually work, provided that
+    * the getServiceName() method returns a unique canonical MBean name.
+    * 
+    * @return partition wide unique service name
+    */
+   public String getServiceHAName()
+   {
+      String name = this.service.getServiceHAName();
+      
+      if (name == null)
+      {
+         ObjectName on = this.getServiceName();
+         
+         if (on != null)
+         {
+            name = on.getCanonicalName();
+            
+            this.service.setServiceHAName(name);
+         }
+         else
+         {
+            // This shouldn't occur as the service name is now injected by the microcontainer.
+            //  If injection fails, the service name should then be used.
+            throw new IllegalStateException("Cannot determine ServiceHAName for " + 
+                    getClass().getName() + "; " +
+                    "either set it explicitly or register this object in JMX " +
+                    "before calling create");
+         }
+      }
+      
+      return name;
+   }
+   
+   @Inject(fromContext = FromContext.NAME)
+   public void setServiceHAName(String haName)
+   {
+      this.service.setServiceHAName(haName);
+   }
+}

Modified: trunk/cluster/src/main/org/jboss/ha/jmx/HAServiceMBean.java
===================================================================
--- trunk/cluster/src/main/org/jboss/ha/jmx/HAServiceMBean.java	2008-08-05 16:13:35 UTC (rev 76669)
+++ trunk/cluster/src/main/org/jboss/ha/jmx/HAServiceMBean.java	2008-08-05 16:17:01 UTC (rev 76670)
@@ -42,9 +42,8 @@
  */
 
 public interface HAServiceMBean 
-  extends org.jboss.system.ServiceMBean, NotificationBroadcaster
+   extends org.jboss.system.ServiceMBean, NotificationBroadcaster
 {
-
    /** 
     * Gets the name of the partition used by this service.  This is a 
     * convenience method as the partition name is an attribute of HAPartition.
@@ -52,13 +51,6 @@
     * @return the name of the partition
     */
    String getPartitionName();
- 
-   /**
-    * Get the underlying partition used by this service.
-    * 
-    * @return the partition
-    */
-   HAPartition getHAPartition();
    
    /**
     * Sets the underlying partition used by this service.
@@ -66,7 +58,7 @@
     * @param clusterPartition the partition
     */
    void setHAPartition(HAPartition clusterPartition);
-  
+ 
    /**
     * Sets the underlying partition used by this service.
     * 
@@ -75,77 +67,56 @@
     * @deprecated use {@link #setHAPartition(HAPartition)}
     */
    void setClusterPartition(ClusterPartitionMBean clusterPartition);
-   
+
    /**
-    * Test whether the thread context classloader should be used in RPC calls.
     * 
-    * @return whether the thread context classloader should be used in RPC calls.
+    * Convenience method for broadcasting a call to all members of a partition.
+    * 
+    * @param methodName
+    * @param args array of Java Object representing the set of parameters to be
+    * given to the remote method
+    * @param types The types of the parameters
+    * @return a list of responses from remote nodes
+    * @throws Exception
     */
-   public boolean isRegisterThreadContextClassLoader();
-   
+   @SuppressWarnings("unchecked")
+   List callMethodOnPartition(String methodName, Object[] args, Class[] types) throws Exception;
+
    /**
-    * Sets a flag specifying whether the calling thread's context classloader
-    * should be used when making RPC calls.  This flag must be set before the
-    * RPC handler is registered in startService().  The default value is false.
-    * This would typically be used in conjunction with a scoped classloader.
     * 
-    * @param register whether to use the thread context classloader when
-    * registering the service's RPC handler. 
+    * Convenience method for sharing state across a cluster partition.
+    * Delegates to the DistributedStateService
     * 
+    * @param key key for the distributed object
+    * @return Serializable the distributed object 
+    * 
     */
-   public void setRegisterThreadContextClassLoader(boolean register);
+   Serializable getDistributedState(String key);
 
-  /**
-   * 
-   * Convenience method for broadcasting a call to all members of a partition.
-   * 
-   * @param methodName
-   * @param args array of Java Object representing the set of parameters to be
-   * given to the remote method
-   * @param types The types of the parameters
-   * @return a list of responses from remote nodes
-   * @throws Exception
-   */
-  public List callMethodOnPartition(String methodName, Object[] args, Class[] types)
-    throws Exception;
-
-  /**
-   * 
-   * Convenience method for sharing state across a cluster partition.
-   * Delegates to the DistributedStateService
-   * 
-   * @param key key for the distributed object
-   * @return Serializable the distributed object 
-   * 
-   */
-  public Serializable getDistributedState(String key);
-
-  /**
-   * 
-   * 
-   * Convenience method for sharing state across a cluster partition.
-   * Delegates to the DistributedStateService
-   * 
-   * @param key key for the distributed object
-   * @param value the distributed object
-   * 
-   */
-  public void setDistributedState(String key, Serializable value)
-    throws Exception;
-  
-  /**
-   * 
-   * Broadcast the notification to the remote listener nodes (if any) and then 
-   * invoke super.sendNotification() to notify local listeners.
-   * 
-   * @param notification sent out to local listeners and other nodes. It should be serializable.
-   * It is recommended that the source of the notification is an ObjectName of an MBean that 
-   * is is available on all nodes where the broadcaster MBean is registered. 
-   *   
-   * 
-   * @see javax.management.NotificationBroadcasterSupport#sendNotification(Notification)
-   * 
-   */
-  public void sendNotification(Notification notification);
-  
+   /**
+    * 
+    * 
+    * Convenience method for sharing state across a cluster partition.
+    * Delegates to the DistributedStateService
+    * 
+    * @param key key for the distributed object
+    * @param value the distributed object
+    * 
+    */
+   void setDistributedState(String key, Serializable value) throws Exception;
+   
+   /**
+    * 
+    * Broadcast the notification to the remote listener nodes (if any) and then 
+    * invoke super.sendNotification() to notify local listeners.
+    * 
+    * @param notification sent out to local listeners and other nodes. It should be serializable.
+    * It is recommended that the source of the notification is an ObjectName of an MBean that 
+    * is is available on all nodes where the broadcaster MBean is registered. 
+    *   
+    * 
+    * @see javax.management.NotificationBroadcasterSupport#sendNotification(Notification)
+    * 
+    */
+   void sendNotification(Notification notification);
 }

Modified: trunk/cluster/src/main/org/jboss/ha/jmx/HAServiceMBeanSupport.java
===================================================================
--- trunk/cluster/src/main/org/jboss/ha/jmx/HAServiceMBeanSupport.java	2008-08-05 16:13:35 UTC (rev 76669)
+++ trunk/cluster/src/main/org/jboss/ha/jmx/HAServiceMBeanSupport.java	2008-08-05 16:17:01 UTC (rev 76670)
@@ -21,23 +21,12 @@
   */
 package org.jboss.ha.jmx;
 
-import java.io.Serializable;
-import java.util.List;
-
-import javax.management.AttributeChangeNotification;
 import javax.management.Notification;
-import javax.management.ObjectName;
 
-import org.jboss.beans.metadata.api.annotations.Inject;
-import org.jboss.beans.metadata.api.model.FromContext;
-import org.jboss.ha.framework.interfaces.DistributedReplicantManager;
-import org.jboss.ha.framework.interfaces.DistributedState;
-import org.jboss.ha.framework.interfaces.HAPartition;
-import org.jboss.ha.framework.server.ClusterPartitionMBean;
-import org.jboss.system.ServiceMBeanSupport;
+import org.jboss.ha.framework.interfaces.HAService;
+import org.jboss.ha.framework.server.HAServiceImpl;
 
 /**
- *  
  * Management Bean for an HA-Service.
  * Provides a convenient common base for cluster symmetric MBeans.
  * 
@@ -49,454 +38,23 @@
  * will notify all listeners in the same cluster partition.
  * TODO: The performance can be further optimized by avoiding broadcast messages
  * when remote listener nodes are not interested (e.g. have no local subscribers)
- * or by iterating locally over filters or remote listeners. 
- *  
- * @author  Ivelin Ivanov <ivelin at apache.org> *
+ * or by iterating locally over filters or remote listeners.
+ * 
+ * @author  Ivelin Ivanov <ivelin at apache.org>
+ * @author Paul Ferraro
  * @version $Revision$
  *
  */
 public class HAServiceMBeanSupport
-   extends ServiceMBeanSupport
-   implements HAServiceMBean
+   extends AbstractHAServiceMBeanSupport<HAService<Notification>>
 {
-   // Constants -----------------------------------------------------
- 
-   // Attributes ----------------------------------------------------
-   private HAPartition clusterPartition;
-   private boolean registerClassloader = false;
-
-   private DistributedReplicantManager.ReplicantListener drmListener = null;
-
-   /** 
-    * DRM participation TOKEN 
-    */
-   private String REPLICANT_TOKEN = "";
-
-   private boolean sendLocalLifecycleNotifications = true;
-   private boolean sendRemoteLifecycleNotifications = true;
-   
-   private String serviceHAName;
-   
-   // Public --------------------------------------------------------
-
-   public HAServiceMBeanSupport()
-   {
-      // for JMX
-   }
-
-   public HAPartition getHAPartition()
-   {
-      return clusterPartition;
-   }
-   
-   public void setHAPartition(HAPartition clusterPartition)
-   {
-      this.clusterPartition = clusterPartition;
-   }
-
-   public void setClusterPartition(ClusterPartitionMBean clusterPartition)
-   {
-      if ((getState() != STARTED) && (getState() != STARTING))
-      {         
-         this.clusterPartition = clusterPartition.getHAPartition();
-      }
-   }
-
-   public String getPartitionName()
-   {
-      return clusterPartition.getPartitionName();
-   }
-   
-   public boolean isRegisterThreadContextClassLoader()
-   {
-      return registerClassloader;
-   }
-   
-   public void setRegisterThreadContextClassLoader(boolean register)
-   {
-      registerClassloader = register;
-   }
-
-   // Protected ------------------------------
-
    /**
-    * 
-    * 
-    * Convenience method for sharing state across a cluster partition.
-    * Delegates to the DistributedStateService
-    * 
-    * @param key key for the distributed object
-    * @param value the distributed object
-    * 
+    * @see org.jboss.ha.jmx.AbstractHAServiceMBeanSupport#createHAService()
     */
-   public void setDistributedState(String key, Serializable value)
-      throws Exception
+   @Override
+   protected HAService<Notification> createHAService()
    {
-      DistributedState ds = clusterPartition.getDistributedStateService();
-      ds.set(getServiceHAName(), key, value);
+      return new HAServiceImpl<Notification>(this, this);
    }
-
-   /**
-    * 
-    * Convenience method for sharing state across a cluster partition.
-    * Delegates to the DistributedStateService
-    * 
-    * @param key key for the distributed object
-    * @return Serializable the distributed object 
-    * 
-    */
-   public Serializable getDistributedState(String key)
-   {
-      DistributedState ds = clusterPartition.getDistributedStateService();
-      return ds.get(getServiceHAName(), key);
-   }
-
-   /**
-    * <p>
-    * Implementors of this method should not
-    * code the singleton logic here. 
-    * The MBean lifecycle create/start/stop are separate from
-    * the singleton logic.
-    * Singleton logic should originate in becomeMaster().
-    * </p>
-    * 
-    * <p>
-    * <b>Attention</b>: Always call this method when you overwrite it in a subclass
-    *                   because it elects the master singleton node.
-    * </p>
-    * 
-    */
-   protected void startService() throws Exception
-   {
-      log.debug("start HAServiceMBeanSupport");
-      
-      if (clusterPartition == null)
-      {
-         throw new IllegalStateException("HAPartition property must be set before starting HAServiceMBeanSupport");
-      }
-
-      setupPartition();
-
-      registerRPCHandler();
-
-      registerDRMListener();
-
-   }
-
-   /**
-    * <p>
-    * <b>Attention</b>: Always call this method when you overwrite it in a subclass
-    * </p>
-    * 
-    */
-   protected void stopService() throws Exception
-   {
-      log.debug("stop HAServiceMBeanSupport");
-
-      unregisterDRMListener();
-
-      unregisterRPCHandler();
-   }
-
-   protected void setupPartition() throws Exception
-   {
-      // method no longer used by base implementation
-   }
-   
-   /**
-    * Returns the object upon which incoming RPC invocations will be made.
-    * 
-    * @return the default implementation returns <code>this</code>
-    */
-   protected Object getRPCHandler()
-   {
-      return this;
-   }
-
-   protected void registerRPCHandler()
-   {
-      if (isRegisterThreadContextClassLoader())
-         clusterPartition.registerRPCHandler(getServiceHAName(), getRPCHandler(), Thread.currentThread().getContextClassLoader());
-      else
-         clusterPartition.registerRPCHandler(getServiceHAName(), getRPCHandler());         
-   }
-
-   protected void unregisterRPCHandler()
-   {
-      clusterPartition.unregisterRPCHandler(getServiceHAName(), this);
-   }
-   
-   protected Serializable getReplicant()
-   {
-      return REPLICANT_TOKEN;
-   }
-
-   protected void registerDRMListener() throws Exception
-   {
-      DistributedReplicantManager drm = clusterPartition.getDistributedReplicantManager();
-
-      // register to listen to topology changes, which might cause the election of a new master
-      drmListener = new DistributedReplicantManager.ReplicantListener()
-      {
-         Object mutex = new Object();
-         
-         public void replicantsChanged(
-            String key,
-            List newReplicants,
-            int newReplicantsViewId, 
-            boolean merge)
-         {
-            if (key.equals(getServiceHAName()))
-            {
-               // This synchronized block was added when the internal behavior of
-               // DistributedReplicantManagerImpl was changed so that concurrent
-               // replicantsChanged notifications are possible. Synchronization
-               // ensures that this change won't break non-thread-safe 
-               // subclasses of HAServiceMBeanSupport.
-               synchronized(mutex)
-               {
-                  // change in the topology callback
-                  HAServiceMBeanSupport.this.partitionTopologyChanged(newReplicants, newReplicantsViewId, merge);
-               }
-            }
-         }
-      };
-      drm.registerListener(getServiceHAName(), drmListener);
-
-      // this ensures that the DRM knows that this node has the MBean deployed 
-      drm.add(getServiceHAName(), getReplicant());
-   }
-
-   protected void unregisterDRMListener() throws Exception
-   {
-      DistributedReplicantManager drm = clusterPartition.getDistributedReplicantManager();
-
-      // remove replicant node  
-      drm.remove(getServiceHAName());
-
-      // unregister 
-      drm.unregisterListener(getServiceHAName(), drmListener);
-   }
-
-   public void partitionTopologyChanged(List newReplicants, int newReplicantsViewId, boolean merge)
-   {
-      if (log.isDebugEnabled())
-      {
-         log.debug("partitionTopologyChanged(). cluster view id: " + newReplicantsViewId);
-      }
-   }
-
-   protected boolean isDRMMasterReplica()
-   {
-      DistributedReplicantManager drm = clusterPartition.getDistributedReplicantManager();
-
-      return drm.isMasterReplica(getServiceHAName());
-   }
-
-    public List callMethodOnPartition(String methodName, Object[] args, Class[] types)
-      throws Exception
-   {
-       return clusterPartition.callMethodOnCluster(
-         getServiceHAName(),
-         methodName,
-         args, types,
-         true);
-   }
-
-   /**
-    * Gets whether JMX Notifications should be sent to local (same JVM) listeners
-    * if the notification is for an attribute change to attribute "State".
-    * <p>
-    * Default is <code>true</code>.
-    * </p>
-    * @see #sendNotification(Notification)
-    */
-   public boolean getSendLocalLifecycleNotifications()
-   {
-      return sendLocalLifecycleNotifications;
-   }
-
-   /**
-    * Sets whether JMX Notifications should be sent to local (same JVM) listeners
-    * if the notification is for an attribute change to attribute "State".
-    * <p>
-    * Default is <code>true</code>.
-    * </p>
-    * @see #sendNotification(Notification)
-    */
-   public void setSendLocalLifecycleNotifications(boolean sendLocalLifecycleNotifications)
-   {
-      this.sendLocalLifecycleNotifications = sendLocalLifecycleNotifications;
-   }
-
-   /**
-    * Gets whether JMX Notifications should be sent to remote listeners
-    * if the notification is for an attribute change to attribute "State".
-    * <p>
-    * Default is <code>true</code>.
-    * </p>
-    * <p>
-    * See http://jira.jboss.com/jira/browse/JBAS-3194 for an example of a
-    * use case where this property should be set to false.
-    * </p>
-    * 
-    * @see #sendNotification(Notification)
-    */
-   public boolean getSendRemoteLifecycleNotifications()
-   {
-      return sendRemoteLifecycleNotifications;
-   }
-
-   /**
-    * Sets whether JMX Notifications should be sent to remote listeners
-    * if the notification is for an attribute change to attribute "State".
-    * <p>
-    * Default is <code>true</code>.
-    * </p>
-    * <p>
-    * See http://jira.jboss.com/jira/browse/JBAS-3194 for an example of a
-    * use case where this property should be set to false.
-    * </p>
-    * 
-    * @see #sendNotification(Notification)
-    */
-   public void setSendRemoteLifecycleNotifications(boolean sendRemoteLifecycleNotifications)
-   {
-      this.sendRemoteLifecycleNotifications = sendRemoteLifecycleNotifications;
-   }
-
-   /** 
-    * Broadcast the notification to the remote listener nodes (if any) and then 
-    * invoke super.sendNotification() to notify local listeners.
-    * 
-    * @param notification sent out to local listeners and other nodes. It should be serializable.
-    * It is recommended that the source of the notification is an ObjectName of an MBean that 
-    * is is available on all nodes where the broadcaster MBean is registered. 
-    *   
-    * @see #getSendLocalLifecycleNotifications()
-    * @see #getSendRemoteLifecycleNotifications()
-    * @see javax.management.NotificationBroadcasterSupport#sendNotification(Notification)
-    */
-   public void sendNotification(Notification notification)
-   {
-      boolean stateChange = isStateChangeNotification(notification);
-      
-      if (!stateChange || sendRemoteLifecycleNotifications)
-      {
-         try
-         {
-            // Overriding the source MBean with its ObjectName
-            // to ensure that it can be safely transferred over the wire
-            notification.setSource(this.getServiceName());
-            sendNotificationRemote(notification);
-         }
-   
-         catch (Throwable th)
-         {
-            boolean debug = log.isDebugEnabled();
-            if (debug)
-               log.debug("sendNotificationRemote( " + notification + " ) failed ", th);
-            // even if broadcast failed, local notification should still be sent
-   
-         }
-      }
-      
-      if (!stateChange || sendLocalLifecycleNotifications)
-      {
-         sendNotificationToLocalListeners(notification);
-      }
-   }
-   
-   private boolean isStateChangeNotification(Notification notification)
-   {
-      boolean stateChange = false;
-      if (notification instanceof AttributeChangeNotification)
-      {
-         stateChange = "State".equals(((AttributeChangeNotification) notification).getAttributeName());
-      }
-      return stateChange;
-   }
-
-   protected void sendNotificationToLocalListeners(Notification notification)
-   {
-      super.sendNotification(notification);
-   }
-
-   protected void callAsyncMethodOnPartition(String methodName, Object[] args, Class[] types)
-      throws Exception
-   {
-      clusterPartition.callAsynchMethodOnCluster(
-            getServiceHAName(),
-            methodName,
-            args, types,
-            true);
-   }
-
-
-   /**
-    * 
-    * Broadcast a notifcation remotely to the partition participants
-    * 
-    * @param notification
-    */
-   protected void sendNotificationRemote(Notification notification)
-      throws Exception
-   {
-      callAsyncMethodOnPartition("_receiveRemoteNotification",
-                                 new Object[]{notification}, new Class[]{Notification.class});
-   }
-
-   /**
-    * 
-    * Invoked by remote broadcasters. 
-    * Delegates to the super class
-    * 
-    */
-   public void _receiveRemoteNotification(Notification notification)
-   {
-      super.sendNotification(notification);
-   }
-
-
-   /**
-    * 
-    * Override this method only if you need to provide a custom partition wide unique service name. 
-    * The default implementation will usually work, provided that 
-    * the getServiceName() method returns a unique canonical MBean name.
-    * 
-    * @return partition wide unique service name
-    */
-   public String getServiceHAName()
-   {         
-      if (serviceHAName == null)
-      {
-         ObjectName on = getServiceName();
-         if (on != null)
-         {
-            serviceHAName = on.getCanonicalName();
-         }
-         else
-         {
-            // This shouldn't occur as the service name is now injected by the microcontainer.
-            //  If injection fails, the service name should then be used.
-            throw new IllegalStateException("Cannot determine ServiceHAName for " + 
-                    getClass().getName() + "; " +
-                    "either set it explicitly or register this object in JMX " +
-                    "before calling create");
-         }
-      }
-      return serviceHAName;
-   }
-   
-   @Inject(fromContext = FromContext.NAME)
-   public void setServiceHAName(String haName)
-   {
-      this.serviceHAName = haName;
-   }
-
-   // Private -------------------------------------------------------
-
-   // Inner classes -------------------------------------------------
-
 }
 

Modified: trunk/cluster/src/main/org/jboss/ha/singleton/HASingleton.java
===================================================================
--- trunk/cluster/src/main/org/jboss/ha/singleton/HASingleton.java	2008-08-05 16:13:35 UTC (rev 76669)
+++ trunk/cluster/src/main/org/jboss/ha/singleton/HASingleton.java	2008-08-05 16:17:01 UTC (rev 76670)
@@ -21,24 +21,17 @@
  */
 package org.jboss.ha.singleton;
 
+import org.jboss.ha.framework.interfaces.HASingletonLifecycle;
+
 /**
  * Basic interface for clustered singleton services 
  * 
+ * Replaced by {@link HASingletonLifecycle}.
+ * 
  * @author  Ivelin Ivanov <ivelin at apache.org>
  * @version $Revision$
  */
-public interface HASingleton
+ at Deprecated
+public interface HASingleton extends HASingletonLifecycle
 {
-   /**
-    * Invoked when this mbean is elected to run the singleton service,
-    * or in other words when this node is elected for master.
-    */
-   void startSingleton();
-
-   /**
-    * Invoked when this mbean is elected to no longer run the singleton service,
-    * or in other words when this node is elected for slave.
-    */
-   void stopSingleton();
-
 }

Modified: trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonController.java
===================================================================
--- trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonController.java	2008-08-05 16:13:35 UTC (rev 76669)
+++ trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonController.java	2008-08-05 16:17:01 UTC (rev 76670)
@@ -61,23 +61,13 @@
 
    private static final Object[] NO_ARGS = new Object[0];
    private static final String[] NO_TYPE_NAMES = new String[0];
-   private static final Class[] NO_TYPES = new Class[0];
-
-   // Constructors --------------------------------------------------
+   private static final Class<?>[] NO_TYPES = new Class[0];
    
-   /**
-    * Default CTOR
-    */
-   public HASingletonController()
-   {
-      // empty
-   }
-   
    // Attributes ----------------------------------------------------
-   
+
    public Object getTarget()
    {
-      return mSingleton;
+      return this.mSingleton;
    }
    
    public void setTarget(Object target)
@@ -87,7 +77,7 @@
    
    public ObjectName getTargetName()
    {
-      return mSingletonMBean;
+      return this.mSingletonMBean;
    }
 
    public void setTargetName(ObjectName targetObjectName)
@@ -97,47 +87,51 @@
 
    public String getTargetStartMethod()
    {
-      return mSingletonStartMethod;
+      return this.mSingletonStartMethod;
    }
 
    public void setTargetStartMethod(String targetStartMethod)
       throws InvalidParameterException
    {
       if (targetStartMethod != null)
-         mSingletonStartMethod = targetStartMethod;
+      {
+         this.mSingletonStartMethod = targetStartMethod;
+      }
    }
 
 
    public String getTargetStopMethod()
    {
-      return mSingletonStopMethod;
+      return this.mSingletonStopMethod;
    }
 
    public void setTargetStopMethod(String targetStopMethod)
       throws InvalidParameterException
    {
       if (targetStopMethod != null)
-         mSingletonStopMethod = targetStopMethod;
+      {
+         this.mSingletonStopMethod = targetStopMethod;
+      }
    }
 
    public String getTargetStartMethodArgument()
    {
-      return mSingletonStartMethodArgument ;
+      return this.mSingletonStartMethodArgument ;
    }
 
    public void setTargetStartMethodArgument(String targetStartMethodArgument)
    {
-      mSingletonStartMethodArgument = targetStartMethodArgument;
+      this.mSingletonStartMethodArgument = targetStartMethodArgument;
    }
 
    public String getTargetStopMethodArgument()
    {
-      return mSingletonStopMethodArgument ;
+      return this.mSingletonStopMethodArgument ;
    }
 
    public void setTargetStopMethodArgument(String targetStopMethodArgument)
    {
-      mSingletonStopMethodArgument =  targetStopMethodArgument;
+      this.mSingletonStopMethodArgument =  targetStopMethodArgument;
    }
   
    // HASingleton implementation ------------------------------------
@@ -147,36 +141,29 @@
     * 
     * @see org.jboss.ha.singleton.HASingletonSupport#startSingleton()
     */
+   @Override
    public void startSingleton()
    {
       super.startSingleton();
 
       try
       {
-         if (mSingleton != null)
+         if (this.mSingleton != null)
          {
-            invokeSingletonMethod(
-                  mSingleton,
-                  mSingletonStartMethod,
-                  mSingletonStartMethodArgument 
-                  );
+            this.invokeSingletonMethod( this.mSingleton, this.mSingletonStartMethod, this.mSingletonStartMethodArgument);
          }
-         else if (mSingletonMBean != null)
+         else if (this.mSingletonMBean != null)
          {
-            invokeSingletonMBeanMethod(
-               mSingletonMBean,
-               mSingletonStartMethod,
-               mSingletonStartMethodArgument 
-               );
+            this.invokeSingletonMBeanMethod( this.mSingletonMBean, this.mSingletonStartMethod, this.mSingletonStartMethodArgument);
          }
          else
          {
-            log.warn("No singleton configured; cannot start");
+            this.log.warn("No singleton configured; cannot start");
          }
       }
       catch (Exception e)
       {
-         log.error("Controlled Singleton failed to become master", e);
+         this.log.error("Controlled Singleton failed to become master", e);
       }
    }
 
@@ -185,36 +172,29 @@
     * 
     * @see org.jboss.ha.singleton.HASingletonSupport#stopSingleton()
     */
+   @Override
    public void stopSingleton()
    {
       super.stopSingleton();
 
       try
       {
-         if (mSingleton != null)
+         if (this.mSingleton != null)
          {
-            invokeSingletonMethod(
-                  mSingleton,
-                  mSingletonStopMethod,
-                  mSingletonStopMethodArgument 
-                  );
+            this.invokeSingletonMethod( this.mSingleton, this.mSingletonStopMethod, this.mSingletonStopMethodArgument);
          }
-         else if (mSingletonMBean != null)
-         {            
-            invokeSingletonMBeanMethod(
-               mSingletonMBean,
-               mSingletonStopMethod,
-               mSingletonStopMethodArgument
-               );
+         else if (this.mSingletonMBean != null)
+         {
+            this.invokeSingletonMBeanMethod( this.mSingletonMBean, this.mSingletonStopMethod, this.mSingletonStopMethodArgument);
          }
          else
          {
-            log.warn("No singleton configured; cannot start");
+            this.log.warn("No singleton configured; cannot start");
          }
       }
       catch (Exception e)
       {
-         log.error("Controlled Singleton failed to resign from master position", e);
+         this.log.error("Controlled Singleton failed to resign from master position", e);
       }
    }
 
@@ -227,35 +207,31 @@
       if (target != null && operationName != null)
       {
          Object[] params;
-         Class[]  types;
+         Class<?>[] types;
          
-         if (param != null) 
+         if (param != null)
          {
             params = new Object[] { param };
             types = new Class[] { param.getClass() };
             
-            log.debug("Calling operation: " + operationName +
-                  "(" + param + "), on target: '" + target + "'");            
+            this.log.debug("Calling operation: " + operationName + "(" + param + "), on target: '" + target + "'");
          }
          else
          {
             params = NO_ARGS;
             types = NO_TYPES;
             
-            log.debug("Calling operation: " + operationName + 
-                  "(), on target: '" + target + "'");               
+            this.log.debug("Calling operation: " + operationName + "(), on target: '" + target + "'");
          }
          
          Method method = getTargetMethod(target, operationName, types);
          
          return method.invoke(target, params);
       }
-      else
-      {
-         log.debug("No configured target mbean or operation to call");
-         
-         return null;
-      }
+
+      this.log.debug("No configured target mbean or operation to call");
+      
+      return null;
    }
    
    protected Object invokeSingletonMBeanMethod(ObjectName target,
@@ -267,37 +243,35 @@
          Object[] params;
          String[] signature;
          
-         if (param != null) 
+         if (param != null)
          {
             params = new Object[] { param };
             signature = new String[] { param.getClass().getName() };
             
-            log.debug("Calling operation: " + operationName +
-                  "(" + param + "), on target: '" + target + "'");            
+            this.log.debug("Calling operation: " + operationName +
+                  "(" + param + "), on target: '" + target + "'");
          }
          else
          {
             params = NO_ARGS;
             signature = NO_TYPE_NAMES;
             
-            log.debug("Calling operation: " + operationName + 
-                  "(), on target: '" + target + "'");               
+            this.log.debug("Calling operation: " + operationName +
+                  "(), on target: '" + target + "'");
          }
 
-         return server.invoke(target, operationName, params, signature);
+         return this.server.invoke(target, operationName, params, signature);
       }
-      else
-      {
-         log.debug("No configured target mbean or operation to call");
-         
-         return null;
-      }
+
+      this.log.debug("No configured target mbean or operation to call");
+      
+      return null;
    }
    
-   public static Method getTargetMethod(Object target, String methodName, Class[] types)
+   public static Method getTargetMethod(Object target, String methodName, Class<?>[] types)
          throws NoSuchMethodException
    {
-      Class clazz = target.getClass();
+      Class<?> clazz = target.getClass();
       NoSuchMethodException nsme = null;
       while (clazz != null)
       {

Modified: trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonControllerMBean.java
===================================================================
--- trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonControllerMBean.java	2008-08-05 16:13:35 UTC (rev 76669)
+++ trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonControllerMBean.java	2008-08-05 16:17:01 UTC (rev 76670)
@@ -26,7 +26,7 @@
 /** 
  * The management interface for the singleton controller service.
  * 
- * @see org.jboss.ha.singleton.HASingletonMBean
+ * @see org.jboss.ha.framework.interfaces.HASingletonMBean
  * 
  * @author <a href="mailto:ivelin at apache.org">Ivelin Ivanov</a>
  * @author <a href="mailto:scott.stark at jboss.org">Scott Stark</a>
@@ -34,7 +34,7 @@
  * @author <a href="mailto:dimitris at jboss.org">Dimitris Andreadis</a>
  * @version $Revision$
  */
-public interface HASingletonControllerMBean  extends HASingletonSupportMBean
+public interface HASingletonControllerMBean extends HASingletonSupportMBean
 {
    /** 
     * Sets the controlled target singleton

Deleted: trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonElectionPolicy.java
===================================================================
--- trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonElectionPolicy.java	2008-08-05 16:13:35 UTC (rev 76669)
+++ trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonElectionPolicy.java	2008-08-05 16:17:01 UTC (rev 76670)
@@ -1,52 +0,0 @@
-package org.jboss.ha.singleton;
-
-import org.jboss.ha.framework.interfaces.ClusterNode;
-import org.jboss.ha.framework.interfaces.HAPartition;
-
-/**
- * HASingletonElectionPolicy.
- * 
- * @author <a href="mailto:Alex.Fu at novell.com">Alex Fu</a>
- * @author Brian Stansberry
- * @author <a href="mailto:galder.zamarreno at jboss.com">Galder Zamarreno</a>
- */
-public interface HASingletonElectionPolicy
-{
-   /**
-    * Called by the HASingleton, during the create service phase, to set the 
-    * name with which the singleton is registered with the HAPartition.
-    * 
-    * @param serviceName the singleton service name.
-    */
-   void setSingletonName(String serviceName);
-
-   /**
-    * Get the singleton name for this election policy. 
-    * 
-    * @return the singleton service name.
-    */
-   String getSingletonName(); 
-
-   /**
-    * Called by the HASingleton, during the create service phase to sets the 
-    * HAPartition; from this the election policy can gain access to the 
-    * DistributedReplicantManager for tracking the  deployment topology for 
-    * the singleton service and to the HAPartition for making group RPC calls.
-    */
-   void setHAPartition(HAPartition partition);
-
-   /**
-    * Get the HA partition where the singleton is deployed, which can be used, 
-    * amongst other things, to find out which nodes is the singleton available 
-    * in.
-    * 
-    * @return the HA partition.
-    */
-   HAPartition getHAPartition();
-   
-   /**
-    * Return the elected master node.
-    * @return the master node or null if there're no possible master nodes.
-    */
-   ClusterNode elect();
-}
\ No newline at end of file

Deleted: trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonElectionPolicyBase.java
===================================================================
--- trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonElectionPolicyBase.java	2008-08-05 16:13:35 UTC (rev 76669)
+++ trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonElectionPolicyBase.java	2008-08-05 16:17:01 UTC (rev 76670)
@@ -1,129 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- * Copyright 2005, JBoss Inc., and individual contributors as indicated
- * by the @authors tag. See the copyright.txt in the distribution for a
- * full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.jboss.ha.singleton;
-
-import java.util.List;
-
-import org.jboss.ha.framework.interfaces.ClusterNode;
-import org.jboss.ha.framework.interfaces.HAPartition;
-import org.jboss.system.ServiceMBeanSupport;
-
-/**
- * A base class for policy service that decides which node in the cluster should be 
- * the master node to run certain HASingleton service.
- * 
- * @author <a href="mailto:afu at novell.com">Alex Fu</a>
- * @author <a href="mailto:galder.zamarreno at jboss.com">Galder Zamarreno</a> 
- * @version $Revision$
- */
-public abstract class HASingletonElectionPolicyBase 
-   extends ServiceMBeanSupport
-   implements HASingletonElectionPolicyMBean
-{
-   private String mSingletonName;
-   private HAPartition mPartition;
-   private String mPreferredMaster;
-   
-   /**
-    * @see HASingletonElectionPolicy#setSingletonName
-    */
-   public void setSingletonName(String singletonName)
-   {
-      this.mSingletonName = singletonName;
-      log.debug("set singleton name to " + this.mSingletonName);
-   }   
-   
-   /**
-    * @see HASingletonElectionPolicy#getSingletonName
-    */
-   public String getSingletonName()
-   {
-      return this.mSingletonName;
-   }
-   
-   /**
-    * @see HASingletonElectionPolicy#setPreferredMaster(ClusterNode)
-    */
-   public void setPreferredMaster(String node)
-   {
-      this.mPreferredMaster = node;
-   }
-   
-   /**
-    * @see HASingletonElectionPolicy#getPreferredMaster()
-    */
-   public String getPreferredMaster()
-   {
-      return this.mPreferredMaster;
-   }
-   
-   /**
-    * @see HASingletonElectionPolicy#setHAPartition(HAPartition)
-    */
-   public void setHAPartition(HAPartition partition)
-   {
-      this.mPartition = partition;
-   }
-
-   /**
-    * @see HASingletonElectionPolicy#getHAPartition()
-    */
-   public HAPartition getHAPartition()
-   {
-      return this.mPartition;
-   }
-      
-   /**
-    * @see HASingletonElectionPolicy#elect()
-    */
-   public ClusterNode elect() 
-   {
-      List<ClusterNode> candidates = getCandidates();
-      if (candidates == null)
-      {
-         log.debug("list of cluster node candidates where to run the singleton is null");
-         return null;
-      }
-             
-      return elect(candidates);    
-   }
-   
-   /**
-    * Get the list of candidate {@link ClusterNode} instances where the 
-    * singleton could be deployed.
-    * 
-    * @return List of {@link ClusterNode} instances.
-    */
-   protected List<ClusterNode> getCandidates() 
-   {
-      return getHAPartition().getDistributedReplicantManager().lookupReplicantsNodes(getSingletonName());
-   }
-   
-   /**
-    * Given a List of candidate {@link ClusterNode} instances, return the 
-    * elected node where the singleton should run.
-    * 
-    * @param candidates List of {@link ClusterNode}.
-    * @return {@link ClusterNode} instance.
-    */
-   protected abstract ClusterNode elect(List<ClusterNode> candidates);
-}

Deleted: trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonElectionPolicyMBean.java
===================================================================
--- trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonElectionPolicyMBean.java	2008-08-05 16:13:35 UTC (rev 76669)
+++ trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonElectionPolicyMBean.java	2008-08-05 16:17:01 UTC (rev 76670)
@@ -1,36 +0,0 @@
-/*
-  * JBoss, Home of Professional Open Source
-  * Copyright 2005, JBoss Inc., and individual contributors as indicated
-  * by the @authors tag. See the copyright.txt in the distribution for a
-  * full listing of individual contributors.
-  *
-  * This is free software; you can redistribute it and/or modify it
-  * under the terms of the GNU Lesser General Public License as
-  * published by the Free Software Foundation; either version 2.1 of
-  * the License, or (at your option) any later version.
-  *
-  * This software is distributed in the hope that it will be useful,
-  * but WITHOUT ANY WARRANTY; without even the implied warranty of
-  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  * Lesser General Public License for more details.
-  *
-  * You should have received a copy of the GNU Lesser General Public
-  * License along with this software; if not, write to the Free
-  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
-  * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
-  */
-package org.jboss.ha.singleton;
-
-
-
-/** 
- *   Management Bean for HASinigleton Election Policy.
-
- *   @author <a href="mailto:Alex.Fu at novell.com">Alex Fu</a>.
- *   @version $Revision$
- *
- */
-public interface HASingletonElectionPolicyMBean 
-   extends org.jboss.system.ServiceMBean, HASingletonElectionPolicy
-{ 
-}

Modified: trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonElectionPolicySimple.java
===================================================================
--- trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonElectionPolicySimple.java	2008-08-05 16:13:35 UTC (rev 76669)
+++ trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonElectionPolicySimple.java	2008-08-05 16:17:01 UTC (rev 76670)
@@ -25,6 +25,7 @@
 import java.util.List;
 
 import org.jboss.ha.framework.interfaces.ClusterNode;
+import org.jboss.ha.framework.interfaces.HASingletonElectionPolicy;
 
 /**
  * A simple concrete policy service that decides which node in the cluster should be 
@@ -47,22 +48,19 @@
  * <attribute name="Position">2</attribute>
  * 
  * If no election policy is defined, the oldest node in the cluster runs the 
- * singleton. This behavior can be achieved with this policy when "position" 
+ * singleton. This behaivour can be achieved with this policy when "position" 
  * is set to 0. 
  * 
  * @author <a href="mailto:Alex.Fu at novell.com">Alex Fu</a>
  * @author <a href="mailto:galder.zamarreno at jboss.com">Galder Zamarreno</a>
  * @version $Revision$
  */
-public class HASingletonElectionPolicySimple 
-   extends HASingletonElectionPolicyBase 
-   implements HASingletonElectionPolicySimpleMBean, HASingletonElector
+public class HASingletonElectionPolicySimple
+   implements HASingletonElectionPolicy, HASingletonElectionPolicySimpleMBean
 {
    // Attributes
    private int mPosition = 0; // Default
    
-   // -------------------------------------------------------------  Properties
-   
    /**
     * @see HASingletonElectionPolicySimpleMBean#setPosition(int)
     */
@@ -79,8 +77,6 @@
       return this.mPosition;
    }
 
-   // -----------------------------------------------------  HASingletonElector
-
    public ClusterNode elect(List<ClusterNode> candidates) 
    {
       int size = candidates.size();
@@ -88,5 +84,4 @@
       
       return candidates.get(remainder);
    }
-   
 }

Modified: trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonElectionPolicySimpleMBean.java
===================================================================
--- trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonElectionPolicySimpleMBean.java	2008-08-05 16:13:35 UTC (rev 76669)
+++ trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonElectionPolicySimpleMBean.java	2008-08-05 16:17:01 UTC (rev 76670)
@@ -29,7 +29,6 @@
  *
  */
 public interface HASingletonElectionPolicySimpleMBean 
-   extends HASingletonElectionPolicyMBean 
 {
    /**
     * Attribute: position. 

Deleted: trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonElector.java
===================================================================
--- trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonElector.java	2008-08-05 16:13:35 UTC (rev 76669)
+++ trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonElector.java	2008-08-05 16:17:01 UTC (rev 76670)
@@ -1,44 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2008, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-
-package org.jboss.ha.singleton;
-
-import java.util.List;
-
-import org.jboss.ha.framework.interfaces.ClusterNode;
-
-/**
- * Serves as an elector in an HASingleton master election by choosing a master
- * node from a list of candidates.
- * <p>
- * Differs from {@link HASingletonElectionPolicy} in that an election policy
- * is also responsible for identifying the list of candidates. An election
- * policy implementation could potentially prepare the list of candidates and
- * then delegate the actual election to an injected 
- * <code>HASingletonElector</code>. 
- * </p>
- * @author Brian Stansberry
- */
-public interface HASingletonElector
-{
-   ClusterNode elect(List<ClusterNode> candidates);
-}

Modified: trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonMBean.java
===================================================================
--- trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonMBean.java	2008-08-05 16:13:35 UTC (rev 76669)
+++ trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonMBean.java	2008-08-05 16:17:01 UTC (rev 76670)
@@ -33,11 +33,14 @@
  * Concrete mbeans would usually do activities like regular clean up of database tables
  * or saving statistics about cluster usage.         
  * 
+ * Replaced by {@link org.jboss.ha.framework.interfaces.HASingletonMBean}
+ * 
  * @author <a href="mailto:ivelin at apache.org">Ivelin Ivanov</a>
  * @author <a href="mailto:dimitris at jboss.org">Dimitris Andreadis</a>
  * @version $Revision$
  */
-public interface HASingletonMBean extends HAServiceMBean
+ at Deprecated
+public interface HASingletonMBean extends HAServiceMBean, org.jboss.ha.framework.interfaces.HASingletonMBean
 {
    // Constants -----------------------------------------------------
    
@@ -46,10 +49,4 @@
    String HASINGLETON_STARTED_NOTIFICATION  = "org.jboss.ha.singleton.started";   
    String HASINGLETON_STOPPING_NOTIFICATION = "org.jboss.ha.singleton.stopping";
    String HASINGLETON_STOPPED_NOTIFICATION  = "org.jboss.ha.singleton.stopped";
-   
-   // Attributes ----------------------------------------------------
-   
-	/** True if this cluster node has the active mbean singleton, false otherwise */
-	boolean isMasterNode();
-
 }

Modified: trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonSupport.java
===================================================================
--- trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonSupport.java	2008-08-05 16:13:35 UTC (rev 76669)
+++ trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonSupport.java	2008-08-05 16:17:01 UTC (rev 76670)
@@ -21,16 +21,17 @@
  */
 package org.jboss.ha.singleton;
 
-import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
-
 import javax.management.Notification;
 
-import org.jboss.ha.framework.interfaces.ClusterNode;
-import org.jboss.ha.jmx.HAServiceMBeanSupport;
+import org.jboss.ha.framework.interfaces.HASingleton;
+import org.jboss.ha.framework.interfaces.HASingletonElectionPolicy;
+import org.jboss.ha.framework.interfaces.HASingletonLifecycle;
+import org.jboss.ha.framework.server.HASingletonImpl;
+import org.jboss.ha.jmx.AbstractHAServiceMBeanSupport;
 
+
 /**
- * Base class for HA-Singleton services.
+ * Base class for HA-Singleton legacy mbean services.
  *
  * @author <a href="mailto:ivelin at apache.org">Ivelin Ivanov</a>
  * @author <a href="mailto:scott.stark at jboss.org">Scott Stark</a>
@@ -39,88 +40,53 @@
  * @author <a href="mailto:pferraro at redhat.com">Paul Ferraro</a>
  * @version $Revision$
  */
-public class HASingletonSupport extends HAServiceMBeanSupport
-   implements HASingletonMBean, HASingleton
+public class HASingletonSupport
+   extends AbstractHAServiceMBeanSupport<HASingleton<Notification>>
+   implements HASingleton<Notification>
 {
-   // Private Data --------------------------------------------------
-   
-   private final AtomicBoolean master = new AtomicBoolean(false);
-   
-   private volatile HASingletonElectionPolicy mElectionPolicyMB = null;
-   private volatile boolean restartOnMerge = true;
-
-   // Constructors --------------------------------------------------
-   
    /**
-    * Default CTOR
+    * @see org.jboss.ha.framework.interfaces.HASingletonMBean#isMasterNode()
     */
-   public HASingletonSupport()
+   public boolean isMasterNode()
    {
-      // empty
+      return this.getHAService().isMasterNode();
    }
-
-   // Attributes ----------------------------------------------------
    
    /**
-    * @jmx:managed-attribute
-    * 
-    * @return true if this cluster node has the active mbean singleton, false otherwise
+    * @see org.jboss.ha.framework.interfaces.HASingleton#setElectionPolicy(org.jboss.ha.framework.interfaces.HASingletonElectionPolicy)
     */
-   public boolean isMasterNode()
+   public void setElectionPolicy(HASingletonElectionPolicy electionPolicy)
    {
-      return this.master.get();
+      this.getHAService().setElectionPolicy(electionPolicy);
    }
-
-   /**
-    * @see HASingletonSupportMBean#setElectionPolicy(HASingletonElectionPolicyMBean)
-    */
-   public void setElectionPolicy(HASingletonElectionPolicy mb)
-   {
-      this.mElectionPolicyMB = mb;
-   }
    
    /**
-    * @see HASingletonSupportMBean#getElectionPolicy()
+    * @see org.jboss.ha.framework.interfaces.HASingleton#getElectionPolicy()
     */
    public HASingletonElectionPolicy getElectionPolicy()
    {
-      return this.mElectionPolicyMB;
+      return this.getHAService().getElectionPolicy();
    }
-
+   
    /**
-    * Gets whether this singleton will stop and restart itself if it is the
-    * master and a cluster merge occurs.
-    * <p/>
-    * A restart allows the service to reset any state that may
-    * have gotten out-of-sync with the rest of the cluster while
-    * the just-merged split was in effect.
-    * 
-    * @return <code>true</code> if a restart will occur, <code>false</code>
-    *         otherwise
+    * @see org.jboss.ha.framework.interfaces.HASingleton#getRestartOnMerge()
     */
    public boolean getRestartOnMerge()
    {
-      return this.restartOnMerge;
+      return this.getHAService().getRestartOnMerge();
    }
-
+   
    /**
-    * Sets whether this singleton will stop and restart itself if it is the
-    * master and a cluster merge occurs?
-    * <p/>
-    * A restart allows the service to reset any state that may
-    * have gotten out-of-sync with the rest of the cluster while
-    * the just-merged split was in effect.
-    * 
-    * @param restartOnMerge <code>true</code> if a restart should occur,
-    *                       <code>false</code> otherwise
+    * @see org.jboss.ha.framework.interfaces.HASingleton#setRestartOnMerge(boolean)
     */
    public void setRestartOnMerge(boolean restartOnMerge)
    {
-      this.restartOnMerge = restartOnMerge;
+      this.getHAService().setRestartOnMerge(restartOnMerge);
    }
-
+   
+   
    // Public --------------------------------------------------------
-
+   
    /**
     * Extending classes should override this method and implement the custom
     * singleton logic. Only one node in the cluster is the active master.
@@ -133,172 +99,32 @@
     * the cluster environment information that will be needed by the next node
     * elected for master should the current master node fail.
     *
-    * @see HASingleton
+    * @see HASingletonLifecycle
     */
    public void startSingleton()
    {
-      this.log.debug("startSingleton() : elected for master singleton node");
-
-      // Extending classes will implement the singleton logic here
+      this.getHAService().startSingleton();
    }
-
+   
    /**
     * Extending classes should override this method and implement the custom
     * singleton logic. Only one node in the cluster is the active master.
     * If the current node is master and another node is elected for master, this
     * method is invoked.
     * 
-    * @see HASingleton
+    * @see HASingletonLifecycle
     */
    public void stopSingleton()
    {
-      this.log.debug("stopSingleton() : another node in the partition (if any) is elected for master");
-      
-      // Extending classes will implement the singleton logic here
+      this.getHAService().stop();
    }
-
-
+   
    /**
-    * When topology changes, a new master is elected based on the result
-    * of the isDRMMasterReplica() call.
-    * 
-    * @see HAServiceMBeanSupport#partitionTopologyChanged(List, int)
-    * @see org.jboss.ha.framework.interfaces.DistributedReplicantManager#isMasterReplica(String)
+    * @see org.jboss.ha.jmx.AbstractHAServiceMBeanSupport#createHAService()
     */
    @Override
-   public void partitionTopologyChanged(List newReplicants, int newViewID, boolean merge)
+   protected HASingleton<Notification> createHAService()
    {
-      boolean isElectedNewMaster;
-      if (this.mElectionPolicyMB != null)
-      {
-         ClusterNode electedNode = this.mElectionPolicyMB.elect();
-         isElectedNewMaster = electedNode != null ? electedNode.equals(this.getHAPartition().getClusterNode()) : false;
-      }
-      else
-      {
-         isElectedNewMaster = this.isDRMMasterReplica();
-      }
-      
-      this.log.debug("partitionTopologyChanged, isElectedNewMaster=" + isElectedNewMaster
-            + ", isMasterNode=" + this.master + ", viewID=" + newViewID);
-
-      boolean isMaster = this.master.get();
-      
-      // if this node is already the master, don't bother electing it again
-      if (isElectedNewMaster && isMaster)
-      {
-         // JBAS-4229
-         if (this.restartOnMerge && merge)
-         {
-            this.restartMaster();
-         }
-      }
-      // just becoming master
-      else if (isElectedNewMaster && !isMaster)
-      {
-         this.makeThisNodeMaster();
-      }
-      // transition from master to slave
-      else if (isMaster)
-      {
-         this._stopOldMaster();
-      }
+      return new HASingletonImpl<Notification>(this, this, this);
    }
-
-   /**
-    * This method will be invoked twice by the local node
-    * when it stops as well as by the remote
-    */
-   public void _stopOldMaster()
-   {
-      this.log.debug("_stopOldMaster, isMasterNode=" + this.master);
-      
-      try
-      {
-         // since this is a cluster call, all nodes will hear it
-         // so if the node is not the master, then ignore
-         if (this.master.compareAndSet(true, false))
-         {
-            // notify stopping
-            this.sendLocalNotification(HASINGLETON_STOPPING_NOTIFICATION);
-            
-            // stop the singleton
-            this.stopSingleton();
-            
-            // notify stopped
-            this.sendLocalNotification(HASINGLETON_STOPPED_NOTIFICATION);
-         }
-      }
-      catch (Exception ex)
-      {
-         this.log.error(
-            "_stopOldMaster failed. Will still try to start new master. " +
-            "You need to examine the reason why the old master wouldn't stop and resolve it. " +
-            "It is bad that the old singleton may still be running while we are starting a new one, " +
-            "so you need to resolve this ASAP.", ex);
-      }
-   }
-
-   // Protected -----------------------------------------------------
-   
-   protected void makeThisNodeMaster()
-   {
-      try
-      {
-         // stop the old master (if there is one) before starting the new one
-
-         // ovidiu 09/02/04 - temporary solution for Case 1843, use an asynchronous
-         // distributed call.
-         //callMethodOnPartition("_stopOldMaster", new Object[0], new Class[0]);
-         this.callAsyncMethodOnPartition("_stopOldMaster", new Object[0], new Class[0]);
-
-         this.startNewMaster();
-      }
-      catch (Exception ex)
-      {
-         this.log.error("_stopOldMaster failed. New master singleton will not start.", ex);
-      }
-   }
-   
-   protected void startNewMaster()
-   {
-      this.log.debug("startNewMaster, isMasterNode=" + this.master);
-      
-      this.master.set(true);
-      
-      // notify starting
-      this.sendLocalNotification(HASINGLETON_STARTING_NOTIFICATION);
-
-      // start new master
-      this.startSingleton();
-      
-      // notify started
-      this.sendLocalNotification(HASINGLETON_STARTED_NOTIFICATION);
-   }
-   
-   protected void restartMaster()
-   {
-      this._stopOldMaster();
-      this.startNewMaster();
-   }
-   
-   @Override
-   protected void createService() throws Exception
-   {
-      super.createService();
-      
-      if (this.mElectionPolicyMB != null)
-      {
-         this.mElectionPolicyMB.setHAPartition(this.getHAPartition());
-         this.mElectionPolicyMB.setSingletonName(this.getServiceHAName());
-      }
-   }
-   
-   // Private -------------------------------------------------------
-   
-   private void sendLocalNotification(String type)
-   {
-      Notification n = new Notification(type, this, this.getNextNotificationSequenceNumber());
-      super.sendNotificationToLocalListeners(n);
-   }
 }

Modified: trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonSupportMBean.java
===================================================================
--- trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonSupportMBean.java	2008-08-05 16:13:35 UTC (rev 76669)
+++ trunk/cluster/src/main/org/jboss/ha/singleton/HASingletonSupportMBean.java	2008-08-05 16:17:01 UTC (rev 76670)
@@ -21,6 +21,8 @@
  */
 package org.jboss.ha.singleton;
 
+import javax.management.Notification;
+
 /** 
  * The management interface for the singleton support service.
  * 
@@ -28,50 +30,8 @@
  * @author <a href="mailto:galder.zamarreno at jboss.com">Galder Zamarreno</a>
  * @version $Revision$
  */
-public interface HASingletonSupportMBean extends HASingletonMBean 
+ at SuppressWarnings("deprecation")
+public interface HASingletonSupportMBean
+   extends org.jboss.ha.framework.interfaces.HASingletonMBean, org.jboss.ha.framework.interfaces.HASingleton<Notification>, HASingletonMBean, HASingleton
 {
-   /** 
-    * Sets the policy used to determine which cluster node will
-    * become the master when the service topology changes. Injection of common 
-    * attributes into the election policy should be done during createService() 
-    * method call.
-    * 
-    * @param policy the policy. Can be <code>null</code>. 
-    */
-   void setElectionPolicy(HASingletonElectionPolicy policy);
-   
-   /** 
-    * Gets the policy used to determine which cluster node will
-    * become the master when the service topology changes.
-    * 
-    * @return the policy. Can be <code>null</code>. 
-    */
-   HASingletonElectionPolicy getElectionPolicy();
-
-   /**
-    * Gets whether this singleton will stop and restart itself if it is the
-    * master and a cluster merge occurs.
-    * <p/>
-    * A restart allows the service to reset any state that may
-    * have gotten out-of-sync with the rest of the cluster while
-    * the just-merged split was in effect.
-    * 
-    * @return <code>true</code> if a restart will occur, <code>false</code>
-    *         otherwise
-    */
-   boolean getRestartOnMerge();
-
-   /**
-    * Sets whether this singleton will stop and restart itself if it is the
-    * master and a cluster merge occurs.
-    * <p/>
-    * A restart allows the service to reset any state that may
-    * have gotten out-of-sync with the rest of the cluster while
-    * the just-merged split was in effect.
-    * 
-    * @param restartOnMerge <code>true</code> if a restart should occur, 
-    *                       <code>false</code> otherwise. Default is
-    *                       <code>true</code>.
-    */
-   void setRestartOnMerge(boolean restartOnMerge);
 }

Modified: trunk/cluster/src/main/org/jboss/ha/singleton/PreferredMasterElectionPolicy.java
===================================================================
--- trunk/cluster/src/main/org/jboss/ha/singleton/PreferredMasterElectionPolicy.java	2008-08-05 16:13:35 UTC (rev 76669)
+++ trunk/cluster/src/main/org/jboss/ha/singleton/PreferredMasterElectionPolicy.java	2008-08-05 16:17:01 UTC (rev 76670)
@@ -28,6 +28,7 @@
 import java.util.List;
 
 import org.jboss.ha.framework.interfaces.ClusterNode;
+import org.jboss.logging.Logger;
 
 /**
  * Election policy that chooses the node where the singleton should run based on 
@@ -37,10 +38,14 @@
  * invalid, it delegates to the standard policy.  
  * 
  * @author <a href="mailto:galder.zamarreno at jboss.com">Galder Zamarreno</a>
+ * @author Paul Ferraro
  */
-public class PreferredMasterElectionPolicy extends HASingletonElectionPolicySimple 
+public class PreferredMasterElectionPolicy
+   extends HASingletonElectionPolicySimple 
    implements PreferredMasterElectionPolicyMBean
 {
+   protected Logger log = Logger.getLogger(this.getClass());
+   
    private String preferredMaster;
    
    // -------------------------------------------------------------  Properties
@@ -50,7 +55,7 @@
     */
    public void setPreferredMaster(String node)
    {
-      preferredMaster = node;
+      this.preferredMaster = node;
    }
    
    /**
@@ -58,7 +63,7 @@
     */
    public String getPreferredMaster()
    {
-      return preferredMaster;
+      return this.preferredMaster;
    }
 
    // -----------------------------------------------------  HASingletonElector
@@ -67,14 +72,14 @@
    public ClusterNode elect(List<ClusterNode> candidates)
    {
       // If preferred master is defined and contained in cluster, return it
-      if (preferredMaster != null) 
+      if (this.preferredMaster != null) 
       {
-         log.debug("Checking if " + preferredMaster + " is in candidate list " + candidates);
+         this.log.debug("Checking if " + this.preferredMaster + " is in candidate list " + candidates);
          
          // First just match on names
          for (ClusterNode node : candidates)
          {
-            if (node.getName().equals(preferredMaster))
+            if (node.getName().equals(this.preferredMaster))
             {
                return node;
             }
@@ -85,7 +90,7 @@
          
          // Create a URI out of the preferred master and try retrieving host 
          // and port.
-         URI uri = createUri(preferredMaster);
+         URI uri = createUri(this.preferredMaster);
          // See if we can parse out an InetAddress and port from preferredMaster.
          InetAddress addr = parseInetAddress(uri);
                  
@@ -93,7 +98,7 @@
          {
             int port = uri.getPort();
             String rewritten = addr.getHostAddress() + ":" + port;
-            if (preferredMaster.equals(rewritten))
+            if (this.preferredMaster.equals(rewritten))
             {
                rewritten = addr.getHostName() + ":" + port;
             }
@@ -123,11 +128,11 @@
    {
       try
       {
-         return new URI("cluster://" + preferredMaster);
+         return new URI("cluster://" + this.preferredMaster);
       }
       catch (URISyntaxException use)
       {
-         log.debug("Cannot extract URI from " + preferredMaster, use);
+         this.log.debug("Cannot extract URI from " + this.preferredMaster, use);
       }
       
       return null;
@@ -154,12 +159,12 @@
             try
             {
                InetAddress addr = InetAddress.getByName(host);
-               log.debug("Parsed " + preferredMaster + " into " + addr + " and " + port);
+               this.log.debug("Parsed " + this.preferredMaster + " into " + addr + " and " + port);
                return addr;
             }
             catch (UnknownHostException uhe)
             {
-               log.debug("Cannot extract InetAddress from " + preferredMaster, uhe);
+               this.log.debug("Cannot extract InetAddress from " + this.preferredMaster, uhe);
             }
          }             
       }

Modified: trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/test/HAServiceMBeanSupportUnitTestCase.java
===================================================================
--- trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/test/HAServiceMBeanSupportUnitTestCase.java	2008-08-05 16:13:35 UTC (rev 76669)
+++ trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/test/HAServiceMBeanSupportUnitTestCase.java	2008-08-05 16:17:01 UTC (rev 76670)
@@ -1,25 +1,24 @@
 /*
-  * JBoss, Home of Professional Open Source
-  * Copyright 2005, JBoss Inc., and individual contributors as indicated
-  * by the @authors tag. See the copyright.txt in the distribution for a
-  * full listing of individual contributors.
-  *
-  * This is free software; you can redistribute it and/or modify it
-  * under the terms of the GNU Lesser General Public License as
-  * published by the Free Software Foundation; either version 2.1 of
-  * the License, or (at your option) any later version.
-  *
-  * This software is distributed in the hope that it will be useful,
-  * but WITHOUT ANY WARRANTY; without even the implied warranty of
-  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  * Lesser General Public License for more details.
-  *
-  * You should have received a copy of the GNU Lesser General Public
-  * License along with this software; if not, write to the Free
-  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
-  * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
-  */
-
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
 package org.jboss.test.cluster.defaultcfg.test;
 
 import java.util.EmptyStackException;
@@ -33,128 +32,111 @@
 
 /**
  * 
- * @author  Ivelin Ivanov <ivelin at apache.org>
+ * @author   Ivelin Ivanov <ivelin at apache.org>
  *
  */
 public class HAServiceMBeanSupportUnitTestCase extends TestCase
 {
+   private HAServiceMBeanSupportTester haServiceMBeanSupportTester = null;
 
-  private HAServiceMBeanSupportTester haServiceMBeanSupportTester_ = null;
+   public HAServiceMBeanSupportUnitTestCase(String name)
+   {
+      super(name);
+   }
+    
+   @Override
+   public void setUp()
+   {
+      this.haServiceMBeanSupportTester = new HAServiceMBeanSupportTester();
+   }
 
-  public HAServiceMBeanSupportUnitTestCase(String name)
-  {
-    super(name);
-  }
    
-  public void setUp()
-  {
-    haServiceMBeanSupportTester_ = new HAServiceMBeanSupportTester();
-  }
+   @Override
+   public void tearDown()
+   {
+      this.haServiceMBeanSupportTester = null;
+   }
 
-  
-  public void tearDown() 
-  {
-    haServiceMBeanSupportTester_ = null;
-  }
 
+   /**
+    * 
+    * messages should be sent out to both remote and local listeners.
+    *
+    */
+   public void testSendNotificationBroadcastsToClusterAndLocally()
+   {
+      Notification notification = new Notification("test.notification", "some:name=tester", 1);
+      this.haServiceMBeanSupportTester.sendNotification(notification);
 
-  /**
-   * 
-   * messages should be sent out to both remote and local listeners.
-   *
-   */
-  public void testSendNotificationBroadcastsToClusterAndLocally()
-  {
-    Notification notification = new Notification("test.notification", "some:name=tester", 1);
-    haServiceMBeanSupportTester_.sendNotification( notification );
+      assertSame("sendNotificationToLocalListeners() was not handed the original notification", this.haServiceMBeanSupportTester.invocationStack.pop(), notification);
 
-    assertEquals("sendNotificationToLocalListeners() was not handed the original notification", 
-      haServiceMBeanSupportTester_.__invokationStack__.pop(), notification );
+      assertEquals("method not invoked as expected", this.haServiceMBeanSupportTester.invocationStack.pop(), "sendNotificationToLocalListeners");
 
-    assertEquals("method not invoked as expected",
-      haServiceMBeanSupportTester_.__invokationStack__.pop(), "sendNotificationToLocalListeners");      
+      assertSame("sendNotificationRemote() was not handed the original notification", this.haServiceMBeanSupportTester.invocationStack.pop(), notification);
+      
+      assertEquals("method not invoked as expected", this.haServiceMBeanSupportTester.invocationStack.pop(), "sendNotificationRemote");
+   }
 
-    assertEquals("sendNotificationRemote() was not handed the original notification", 
-      haServiceMBeanSupportTester_.__invokationStack__.pop(), notification );
-    
-    assertEquals("method not invoked as expected",
-      haServiceMBeanSupportTester_.__invokationStack__.pop(), "sendNotificationRemote");      
-  }
+   /**
+    * 
+    * Even if the message cannot be sent out to the cluster,
+    * it should still be delivered to local listeners.
+    *
+    */
+   public void testSendNotificationAfterClusterFailureContinueWithLocal()
+   {
+      this.haServiceMBeanSupportTester.shouldSendNotificationRemoteFail = true;
 
-  /**
-   * 
-   * Even if the message cannot be sent out to the cluster,
-   * it should still be delivered to local listeners.
-   *
-   */
-  public void testSendNotificationAfterClusterFailureContinueWithLocal()
-  {
-    haServiceMBeanSupportTester_.__shouldSendNotificationRemoteFail__ = true;
+      Notification notification = new Notification("test.notification", "some:name=tester", 1);
+      this.haServiceMBeanSupportTester.sendNotification( notification );
+      
+      assertEquals("sendNotificationToLocalListeners() was not handed the original notification", this.haServiceMBeanSupportTester.invocationStack.pop(), notification );
 
-    Notification notification = new Notification("test.notification", "some:name=tester", 1);
-    haServiceMBeanSupportTester_.sendNotification( notification );
-    
-    assertEquals("sendNotificationToLocalListeners() was not handed the original notification", 
-    haServiceMBeanSupportTester_.__invokationStack__.pop(), notification );
+      assertEquals("method not invoked as expected", this.haServiceMBeanSupportTester.invocationStack.pop(), "sendNotificationToLocalListeners");
+   }
+   
+   public void testSendLifecycleNotifications()
+   {
+      Notification notification = new AttributeChangeNotification(this.haServiceMBeanSupportTester, 1, System.currentTimeMillis(), "test", "State", "java.lang.Integer", new Integer(0), new Integer(1));
+       
+      this.haServiceMBeanSupportTester.setSendRemoteLifecycleNotifications(false);
+       
+      this.haServiceMBeanSupportTester.sendNotification( notification );
+       
+      assertEquals("sendNotificationToLocalListeners() was handed the original notification", this.haServiceMBeanSupportTester.invocationStack.pop(), notification );
 
-    assertEquals("method not invoked as expected",
-      haServiceMBeanSupportTester_.__invokationStack__.pop(), "sendNotificationToLocalListeners");      
-  }
-  
-  public void testSendLifecycleNotifications()
-  {
-     Notification notification = new AttributeChangeNotification(
-           haServiceMBeanSupportTester_,
-           1, System.currentTimeMillis(), "test",
-           "State", "java.lang.Integer",
-           new Integer(0), new Integer(1)
-           );
-     
-     haServiceMBeanSupportTester_.setSendRemoteLifecycleNotifications(false);
-     
-     haServiceMBeanSupportTester_.sendNotification( notification );
-     
-     assertEquals("sendNotificationToLocalListeners() was handed the original notification", 
-                 haServiceMBeanSupportTester_.__invokationStack__.pop(), notification );
+      assertEquals("method invoked as expected", this.haServiceMBeanSupportTester.invocationStack.pop(), "sendNotificationToLocalListeners");
 
-     assertEquals("method invoked as expected",
-       haServiceMBeanSupportTester_.__invokationStack__.pop(), "sendNotificationToLocalListeners");      
+      try
+      {
+         this.haServiceMBeanSupportTester.invocationStack.pop();
+         fail("sendNotificationRemote() was not handed the original notification");
+      }
+      catch (EmptyStackException good) {}
+       
+      this.haServiceMBeanSupportTester.setSendRemoteLifecycleNotifications(true);
+      this.haServiceMBeanSupportTester.setSendLocalLifecycleNotifications(false);
+       
+      this.haServiceMBeanSupportTester.sendNotification( notification );
 
-     try
-     {
-        haServiceMBeanSupportTester_.__invokationStack__.pop();
-        fail("sendNotificationRemote() was not handed the original notification");
-     }
-     catch (EmptyStackException good) {}
-     
-     haServiceMBeanSupportTester_.setSendRemoteLifecycleNotifications(true);
-     haServiceMBeanSupportTester_.setSendLocalLifecycleNotifications(false);
-     
-     haServiceMBeanSupportTester_.sendNotification( notification );     
-
-     assertEquals("sendNotificationRemote() was handed the original notification", 
-       haServiceMBeanSupportTester_.__invokationStack__.pop(), notification );
-     
-     assertEquals("method invoked as expected",
-       haServiceMBeanSupportTester_.__invokationStack__.pop(), "sendNotificationRemote");
-     
-     try
-     {
-        haServiceMBeanSupportTester_.__invokationStack__.pop();
-        fail("sendNotificationToLocalListeners() was not handed the original notification");
-     }
-     catch (EmptyStackException good) {}
-  }
-  
-  public void testServiceHAName() throws Exception
-  {
-     assertEquals("Default name correct", HAServiceMBeanSupportTester.SERVICE_NAME, 
-                   haServiceMBeanSupportTester_.getServiceHAName());
-     
-     haServiceMBeanSupportTester_.setServiceHAName("Test");
-     
-     assertEquals("Specified name correct", "Test", 
-           haServiceMBeanSupportTester_.getServiceHAName());
-  }
-
+      assertEquals("sendNotificationRemote() was handed the original notification", this.haServiceMBeanSupportTester.invocationStack.pop(), notification );
+       
+      assertEquals("method invoked as expected", this.haServiceMBeanSupportTester.invocationStack.pop(), "sendNotificationRemote");
+       
+      try
+      {
+         this.haServiceMBeanSupportTester.invocationStack.pop();
+         fail("sendNotificationToLocalListeners() was not handed the original notification");
+      }
+      catch (EmptyStackException good) {}
+   }
+   
+   public void testServiceHAName() throws Exception
+   {
+      assertEquals("Default name correct", HAServiceMBeanSupportTester.SERVICE_NAME, this.haServiceMBeanSupportTester.getServiceHAName());
+       
+      this.haServiceMBeanSupportTester.setServiceHAName("Test");
+       
+      assertEquals("Specified name correct", "Test", this.haServiceMBeanSupportTester.getServiceHAName());
+   }
 }

Modified: trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/test/HASingletonSupportUnitTestCase.java
===================================================================
--- trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/test/HASingletonSupportUnitTestCase.java	2008-08-05 16:13:35 UTC (rev 76669)
+++ trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/test/HASingletonSupportUnitTestCase.java	2008-08-05 16:17:01 UTC (rev 76670)
@@ -1,24 +1,24 @@
 /*
-  * JBoss, Home of Professional Open Source
-  * Copyright 2008, Red Hat Middleware LLC, and individual contributors
-  * as indicated by the @author tags. See the copyright.txt file in the
-  * distribution for a full listing of individual contributors.
-  *
-  * This is free software; you can redistribute it and/or modify it
-  * under the terms of the GNU Lesser General Public License as
-  * published by the Free Software Foundation; either version 2.1 of
-  * the License, or (at your option) any later version.
-  *
-  * This software is distributed in the hope that it will be useful,
-  * but WITHOUT ANY WARRANTY; without even the implied warranty of
-  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  * Lesser General Public License for more details.
-  *
-  * You should have received a copy of the GNU Lesser General Public
-  * License along with this software; if not, write to the Free
-  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
-  * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
-  */
+ * JBoss, Home of Professional Open Source
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
 package org.jboss.test.cluster.defaultcfg.test;
  
 import java.util.ArrayList;
@@ -30,229 +30,214 @@
 /**
  * Tests of the HASingletonSupport class.
  *
- * @author  Ivelin Ivanov <ivelin at jboss.org>
- * @author  Brian Stansberry
+ * @author   Ivelin Ivanov <ivelin at jboss.org>
+ * @author   Brian Stansberry
  *
  */
 public class HASingletonSupportUnitTestCase extends TestCase
 {
 
-  private HASingletonSupportTester singletonSupportTester = null;
+   private HASingletonSupportTester singletonSupportTester = null;
 
-  public HASingletonSupportUnitTestCase(String testCaseName)
-  {
-    super(testCaseName);
-  }
+   public HASingletonSupportUnitTestCase(String testCaseName)
+   {
+      super(testCaseName);
+   }
 
 
-  public void setUp()
-  {
-    singletonSupportTester = new HASingletonSupportTester();
-    singletonSupportTester.setRestartOnMerge(true);
-  }
-  
-  public void tearDown() 
-  {
-    singletonSupportTester = null;
-  }
-  
-  public void testStartService() throws Exception
-  {    
-    singletonSupportTester.start();
+   @Override
+   public void setUp()
+   {
+      this.singletonSupportTester = new HASingletonSupportTester();
+      this.singletonSupportTester.setRestartOnMerge(true);
+   }
+   
+   @Override
+   public void tearDown()
+   {
+      this.singletonSupportTester = null;
+   }
+   
+   public void testStartService() throws Exception
+   {
+      this.singletonSupportTester.start();
 
-    // test that the correct start sequence was followed correctly  
-    assertEquals("method not invoked as expected",
-      singletonSupportTester.__invokationStack__.pop(), "registerDRMListener");  
-    assertEquals("method not invoked as expected",
-      singletonSupportTester.__invokationStack__.pop(), "registerRPCHandler");  
-    assertEquals("method not invoked as expected",
-      singletonSupportTester.__invokationStack__.pop(), "setupPartition"); 
-  }
+      // test that the correct start sequence was followed correctly
+      assertEquals("method not invoked as expected", this.singletonSupportTester.invocationStack.pop(), "registerDRMListener");
+      assertEquals("method not invoked as expected", this.singletonSupportTester.invocationStack.pop(), "registerRPCHandler");
+      assertEquals("method not invoked as expected", this.singletonSupportTester.invocationStack.pop(), "setupPartition");
+   }
 
-  public void testStopService() throws Exception
-  {
-    singletonSupportTester.start();
-    singletonSupportTester.stop();
+   public void testStopService() throws Exception
+   {
+      this.singletonSupportTester.start();
+      this.singletonSupportTester.stop();
 
-    assertEquals("method not invoked as expected",
-      singletonSupportTester.__invokationStack__.pop(), "unregisterRPCHandler");  
-    assertEquals("method not invoked as expected",
-      singletonSupportTester.__invokationStack__.pop(), "unregisterDRMListener"); 
-  }
-  
-  public void testBecomeMasterNode() throws Exception
-  {
-     becomeMasterNodeTest(false);
-  }
-  
-  private void becomeMasterNodeTest(boolean merge) throws Exception
-  {
-    singletonSupportTester.start();
-    
-    // register DRM Listener is expected to call back
-    singletonSupportTester.__isDRMMasterReplica__ = true;
-    singletonSupportTester.partitionTopologyChanged( new ArrayList(2), 1, merge);
+      assertEquals("method not invoked as expected", this.singletonSupportTester.invocationStack.pop(), "unregisterRPCHandler");
+      assertEquals("method not invoked as expected", this.singletonSupportTester.invocationStack.pop(), "unregisterDRMListener");
+   }
+   
+   public void testBecomeMasterNode() throws Exception
+   {
+       this.becomeMasterNodeTest(false);
+   }
+   
+   private void becomeMasterNodeTest(boolean merge) throws Exception
+   {
+      this.singletonSupportTester.start();
+      
+      // register DRM Listener is expected to call back
+      this.singletonSupportTester.isDRMMasterReplica = true;
+      this.singletonSupportTester.getDelegate().partitionTopologyChanged(new ArrayList<Integer>(2), 1, merge);
 
-    // test whether it was elected    
-    assertTrue("expected to become master", singletonSupportTester.isMasterNode());
-    
-    // test whether the election sequence was followed correctly
-    assertEquals("method not invoked as expected",
-      singletonSupportTester.__invokationStack__.pop(), "startSingleton");  
-    //assertEquals("method not invoked as expected",
-    //  singletonSupportTester.__invokationStack__.pop(), "callMethodOnCluster:_stopOldMaster");  
-    assertEquals("method not invoked as expected",
-      singletonSupportTester.__invokationStack__.pop(), "makeThisNodeMaster");      
-  }
-  
-  public void testBecomeSlaveNodeWithAnotherMaster() throws Exception
-  {
-     becomeSlaveNodeWithAnotherMasterTest(false);
-  }
-  
-  private void becomeSlaveNodeWithAnotherMasterTest(boolean merge) throws Exception
-  {
-    singletonSupportTester.start();
-    
-    boolean savedIsMasterNode = singletonSupportTester.isMasterNode();
-    
-    // register DRM Listener is expected to call back
-    singletonSupportTester.__isDRMMasterReplica__ = false;
-    singletonSupportTester.partitionTopologyChanged(new ArrayList(2), 1, merge);
-    
-    // this call back should not change the master/slave status
-    assertEquals("expected to be still in old master/slave state", singletonSupportTester.isMasterNode(), savedIsMasterNode );
-    
-    // the new master is expected to call back
-    singletonSupportTester._stopOldMaster();
-    
-    if (savedIsMasterNode)
-    {
-      assertEquals("this node was the old master, but method not invoked as expected",
-        singletonSupportTester.__invokationStack__.pop(), "stopSingleton");  
-    }
+      // test whether it was elected
+      assertTrue("expected to become master", this.singletonSupportTester.isMasterNode());
       
-    // now it should be slave
-    assertTrue("expected to be slave", !singletonSupportTester.isMasterNode());
-            
-  }
+      // test whether the election sequence was followed correctly
+      assertEquals("method not invoked as expected", this.singletonSupportTester.invocationStack.pop(), "startSingleton");
+      //assertEquals("method not invoked as expected", singletonSupportTester.invocationStack.pop(), "callMethodOnCluster:_stopOldMaster");
+      assertEquals("method not invoked as expected", this.singletonSupportTester.invocationStack.pop(), "makeThisNodeMaster");
+   }
+   
+   public void testBecomeSlaveNodeWithAnotherMaster() throws Exception
+   {
+      this.becomeSlaveNodeWithAnotherMasterTest(false);
+   }
+   
+   private void becomeSlaveNodeWithAnotherMasterTest(boolean merge) throws Exception
+   {
+      this.singletonSupportTester.start();
+      
+      boolean savedIsMasterNode = this.singletonSupportTester.isMasterNode();
+      
+      // register DRM Listener is expected to call back
+      this.singletonSupportTester.isDRMMasterReplica = false;
+      this.singletonSupportTester.getDelegate().partitionTopologyChanged(new ArrayList<Integer>(2), 1, merge);
+      
+      // this call back should not change the master/slave status
+      assertEquals("expected to be still in old master/slave state", this.singletonSupportTester.isMasterNode(), savedIsMasterNode );
+      
+      // the new master is expected to call back
+      this.singletonSupportTester.getDelegate().stopIfMaster();
+      
+      if (savedIsMasterNode)
+      {
+         assertEquals("this node was the old master, but method not invoked as expected", this.singletonSupportTester.invocationStack.pop(), "stopSingleton");
+      }
+         
+      // now it should be slave
+      assertTrue("expected to be slave", !this.singletonSupportTester.isMasterNode());
+                  
+   }
 
-  public void testStopOnlyNode() throws Exception
-  {
-    singletonSupportTester.start();
-    
-    // register DRM Listener is expected to call back
-    singletonSupportTester.__isDRMMasterReplica__ = true;
-    singletonSupportTester.partitionTopologyChanged( new ArrayList(2), 1, false);
+   public void testStopOnlyNode() throws Exception
+   {
+      this.singletonSupportTester.start();
+      
+      // register DRM Listener is expected to call back
+      this.singletonSupportTester.isDRMMasterReplica = true;
+      this.singletonSupportTester.getDelegate().partitionTopologyChanged(new ArrayList<Integer>(2), 1, false);
 
-    // test whether it was elected for master    
-    assertTrue("expected to become master", singletonSupportTester.isMasterNode());
-    
-    singletonSupportTester.stop();
-    
-    // register DRM Listener is expected to call back
-    singletonSupportTester.__isDRMMasterReplica__ = false;
-    // since the only node (this one) in the partition is now removed, the replicants list should be empty 
-    singletonSupportTester.partitionTopologyChanged(new ArrayList(0), 1, false);
-    
-    assertTrue("expected to have made a call to _stopOldMaster(), thus become slave", !singletonSupportTester.isMasterNode() );
-    
-    assertEquals("method not invoked as expected",
-      singletonSupportTester.__invokationStack__.pop(), "stopSingleton");  
+      // test whether it was elected for master
+      assertTrue("expected to become master", this.singletonSupportTester.isMasterNode());
       
-  }
-  
-  public void testStartServiceWithRestartOff() throws Exception
-  {
-     singletonSupportTester.setRestartOnMerge(false);
-     testStartService();
-  }
+      this.singletonSupportTester.stop();
+      
+      // register DRM Listener is expected to call back
+      this.singletonSupportTester.isDRMMasterReplica = false;
+      // since the only node (this one) in the partition is now removed, the replicants list should be empty
+      this.singletonSupportTester.getDelegate().partitionTopologyChanged(new ArrayList<Integer>(0), 1, false);
+      
+      assertTrue("expected to have made a call to _stopOldMaster(), thus become slave", !this.singletonSupportTester.isMasterNode() );
+      
+      assertEquals("method not invoked as expected", this.singletonSupportTester.invocationStack.pop(), "stopSingleton");
+         
+   }
+   
+   public void testStartServiceWithRestartOff() throws Exception
+   {
+      this.singletonSupportTester.setRestartOnMerge(false);
+      this.testStartService();
+   }
 
-  public void testStopServiceWithRestartOff() throws Exception
-  {
-     singletonSupportTester.setRestartOnMerge(false);
-     testStopService();
-  }
-  
-  public void testBecomeMasterNodeWithRestartOff() throws Exception
-  {
-    singletonSupportTester.setRestartOnMerge(false);
-    becomeMasterNodeTest(false);     
-  }
-  
-  public void testBecomeSlaveNodeWithAnotherMasterWithRestartOff() throws Exception
-  {
-     singletonSupportTester.setRestartOnMerge(false);
-     becomeSlaveNodeWithAnotherMasterTest(false);
-  }
-  
-  public void testBecomeMasterNodeDuringMerge() throws Exception
-  {  
-     becomeMasterNodeTest(true);
-  }
-  
-  public void testMasterRestartDuringMerge() throws Exception
-  {
-     // Just run the BecomeMaster test to get ourself set up as master
-     becomeMasterNodeTest(false);
-     
-     // Drain off any un-popped events
-     singletonSupportTester.__invokationStack__.clear();
-     
-     singletonSupportTester.partitionTopologyChanged( new ArrayList(3), 2, true);
+   public void testStopServiceWithRestartOff() throws Exception
+   {
+      this.singletonSupportTester.setRestartOnMerge(false);
+      this.testStopService();
+   }
+   
+   public void testBecomeMasterNodeWithRestartOff() throws Exception
+   {
+      this.singletonSupportTester.setRestartOnMerge(false);
+      this.becomeMasterNodeTest(false);
+   }
+   
+   public void testBecomeSlaveNodeWithAnotherMasterWithRestartOff() throws Exception
+   {
+      this.singletonSupportTester.setRestartOnMerge(false);
+      this.becomeSlaveNodeWithAnotherMasterTest(false);
+   }
+   
+   public void testBecomeMasterNodeDuringMerge() throws Exception
+   {
+      this.becomeMasterNodeTest(true);
+   }
+   
+   public void testMasterRestartDuringMerge() throws Exception
+   {
+      // Just run the BecomeMaster test to get ourself set up as master
+      this.becomeMasterNodeTest(false);
+      
+      // Drain off any un-popped events
+      this.singletonSupportTester.invocationStack.clear();
+      
+      this.singletonSupportTester.getDelegate().partitionTopologyChanged(new ArrayList<Integer>(3), 2, true);
+      
+      // test whether it's still master
+      assertTrue("expected to remain master", this.singletonSupportTester.isMasterNode());
+      
+      // test whether the election sequence was followed correctly
+      assertEquals("method not invoked as expected", "startSingleton", this.singletonSupportTester.invocationStack.pop());
+      assertEquals("method not invoked as expected", "stopSingleton", this.singletonSupportTester.invocationStack.pop());
+      assertEquals("method not invoked as expected", "restartMaster", this.singletonSupportTester.invocationStack.pop());
+   }
+   
+   public void testBecomeSlaveNodeWithAnotherMasterDuringMerge() throws Exception
+   {
+      // Just run the BecomeMaster test to get ourself set up as master
+      this.becomeMasterNodeTest(false);
+      
+      // Drain off any un-popped events
+      this.singletonSupportTester.invocationStack.clear();
+      
+      this.singletonSupportTester.isDRMMasterReplica = false;
+      
+      this.singletonSupportTester.getDelegate().partitionTopologyChanged(new ArrayList<Integer>(3), 2, true);
+      
+      // now it should be slave
+      assertFalse("expected to be slave", this.singletonSupportTester.isMasterNode());
+      
+      assertEquals("this node was the old master, but method not invoked as expected", this.singletonSupportTester.invocationStack.pop(), "stopSingleton");
+   }
 
-     // test whether it's still master    
-     assertTrue("expected to remain master", singletonSupportTester.isMasterNode());
-     
-     // test whether the election sequence was followed correctly  
-     assertEquals("method not invoked as expected",
-           "startSingleton", singletonSupportTester.__invokationStack__.pop());  
-     assertEquals("method not invoked as expected",
-           "stopSingleton", singletonSupportTester.__invokationStack__.pop());
-     assertEquals("method not invoked as expected",
-           "restartMaster", singletonSupportTester.__invokationStack__.pop());
-  }
-  
-  public void testBecomeSlaveNodeWithAnotherMasterDuringMerge() throws Exception
-  {
-     // Just run the BecomeMaster test to get ourself set up as master
-     becomeMasterNodeTest(false);
-     
-     // Drain off any un-popped events
-     singletonSupportTester.__invokationStack__.clear();
-     
-     singletonSupportTester.__isDRMMasterReplica__ = false;
-     
-     singletonSupportTester.partitionTopologyChanged( new ArrayList(3), 2, true);
-     
-     // now it should be slave
-     assertFalse("expected to be slave", singletonSupportTester.isMasterNode());
-     
-     assertEquals("this node was the old master, but method not invoked as expected",
-         singletonSupportTester.__invokationStack__.pop(), "stopSingleton");     
-  }
-
-  
-  public void testMasterRestartDuringMergeWithRestartOff() throws Exception
-  {
-     singletonSupportTester.setRestartOnMerge(false);
-     
-     // Just run the BecomeMaster test to get ourself set up as master
-     testBecomeMasterNode();
-     
-     // Drain off any un-popped events
-     singletonSupportTester.__invokationStack__.clear();
-     
-     singletonSupportTester.partitionTopologyChanged( new ArrayList(3), 2, true);
-
-     // test whether it's still master    
-     assertTrue("expected to remain master", singletonSupportTester.isMasterNode());
-     
-     // test whether the election sequence was followed correctly   
-     assertEquals("method not invoked as expected",
-           "isDRMMasterReplica", singletonSupportTester.__invokationStack__.pop());  
-     assertEquals("method not invoked as expected",
-                  0, singletonSupportTester.__invokationStack__.size()); 
-  }
-  
+   
+   public void testMasterRestartDuringMergeWithRestartOff() throws Exception
+   {
+      this.singletonSupportTester.setRestartOnMerge(false);
+      
+      // Just run the BecomeMaster test to get ourself set up as master
+      this.testBecomeMasterNode();
+      
+      // Drain off any un-popped events
+      this.singletonSupportTester.invocationStack.clear();
+      
+      this.singletonSupportTester.getDelegate().partitionTopologyChanged(new ArrayList<Integer>(3), 2, true);
+      
+       // test whether it's still master
+      assertTrue("expected to remain master", this.singletonSupportTester.isMasterNode());
+      
+      // test whether the election sequence was followed correctly
+      assertEquals("method not invoked as expected", "isDRMMasterReplica", this.singletonSupportTester.invocationStack.pop());
+      assertEquals("method not invoked as expected", 0, this.singletonSupportTester.invocationStack.size());
+   }
 }

Modified: trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/test/PreferredMasterElectionPolicyUnitTestCase.java
===================================================================
--- trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/test/PreferredMasterElectionPolicyUnitTestCase.java	2008-08-05 16:13:35 UTC (rev 76669)
+++ trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/test/PreferredMasterElectionPolicyUnitTestCase.java	2008-08-05 16:17:01 UTC (rev 76670)
@@ -24,14 +24,13 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import junit.framework.TestCase;
+
 import org.jboss.ha.framework.interfaces.ClusterNode;
 import org.jboss.ha.framework.server.ClusterNodeImpl;
 import org.jboss.ha.singleton.PreferredMasterElectionPolicy;
-import org.jboss.ha.singleton.PreferredMasterElectionPolicyMBean;
 import org.jgroups.stack.IpAddress;
 
-import junit.framework.TestCase;
-
 /**
  * Unit tests for the preferred master election policy. The tested policy has 
  * been configured with position 0 which means that the first member of the 
@@ -46,7 +45,7 @@
 {
    private final List<ClusterNode> candidates = new ArrayList<ClusterNode>(2);
    
-   private PreferredMasterElectionPolicyMBean policy;
+   private PreferredMasterElectionPolicy policy;
    
    @Override
    protected void setUp() throws Exception
@@ -59,14 +58,7 @@
       candidates.add(cn1);
       candidates.add(cn2);
       
-      policy = new PreferredMasterElectionPolicy()
-      {
-         @Override
-         protected List<ClusterNode> getCandidates()
-         {
-            return candidates;
-         }
-      };
+      policy = new PreferredMasterElectionPolicy();
       
       policy.setPosition(0);
    }
@@ -74,13 +66,13 @@
    public void testIpPort() throws Exception
    {
       policy.setPreferredMaster("127.0.0.1:1199");
-      assertEquals(candidates.get(1), policy.elect());
+      assertEquals(candidates.get(1), policy.elect(this.candidates));
    }
 
    public void testHostPort() throws Exception
    {
       policy.setPreferredMaster("localhost:1199");
-      assertEquals(candidates.get(1), policy.elect());
+      assertEquals(candidates.get(1), policy.elect(this.candidates));
    }
    
    public void testOnlyPort() throws Exception
@@ -88,7 +80,7 @@
       policy.setPreferredMaster(":1199");
       /* invalid preferred master definiton, so 1st candidate in the list 
        * should be chosen */
-      assertEquals(candidates.get(0), policy.elect());
+      assertEquals(candidates.get(0), policy.elect(this.candidates));
    }
    
    public void testNonNumericPort() throws Exception
@@ -96,7 +88,7 @@
       policy.setPreferredMaster("localhost:abcd");
       /* invalid preferred master definiton, so 1st candidate in the list 
        * should be chosen */
-      assertEquals(candidates.get(0), policy.elect());
+      assertEquals(candidates.get(0), policy.elect(this.candidates));
    }
 
    public void testUnknownHost() throws Exception
@@ -104,7 +96,7 @@
       policy.setPreferredMaster("onceuponatimeinalandfarfarawaylivedamancalledgalder:1199");
       /* invalid preferred master definiton, so 1st candidate in the list 
        * should be chosen */
-      assertEquals(candidates.get(0), policy.elect());
+      assertEquals(candidates.get(0), policy.elect(this.candidates));
    }
    
    public void testEmpty() throws Exception
@@ -112,7 +104,7 @@
       policy.setPreferredMaster("");
       /* invalid preferred master definiton, so 1st candidate in the list 
        * should be chosen */
-      assertEquals(candidates.get(0), policy.elect());
+      assertEquals(candidates.get(0), policy.elect(this.candidates));
    }
    
    public void testGarbage() throws Exception
@@ -120,6 +112,6 @@
       policy.setPreferredMaster("%^$%&%^&$%$£");
       /* invalid preferred master definiton, so 1st candidate in the list 
        * should be chosen */
-      assertEquals(candidates.get(0), policy.elect());
+      assertEquals(candidates.get(0), policy.elect(this.candidates));
    }
 }

Modified: trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ModClusterService.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ModClusterService.java	2008-08-05 16:13:35 UTC (rev 76669)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ModClusterService.java	2008-08-05 16:17:01 UTC (rev 76670)
@@ -22,17 +22,15 @@
 
 package org.jboss.web.tomcat.service.modcluster;
 
-import java.io.IOException;
 import java.io.Serializable;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-import javax.management.Notification;
-
 import org.apache.catalina.Context;
 import org.apache.catalina.Engine;
 import org.apache.catalina.Server;
@@ -42,24 +40,29 @@
 import org.jboss.ha.framework.interfaces.ClusterNode;
 import org.jboss.ha.framework.interfaces.DistributedReplicantManager;
 import org.jboss.ha.framework.interfaces.HAPartition;
+import org.jboss.ha.framework.interfaces.HASingletonElectionPolicy;
+import org.jboss.ha.framework.server.HAServiceEvent;
+import org.jboss.ha.framework.server.HAServiceEventFactory;
+import org.jboss.ha.framework.server.HAServiceImpl;
+import org.jboss.ha.framework.server.HAServiceRpcHandler;
+import org.jboss.ha.framework.server.HASingletonImpl;
 import org.jboss.ha.singleton.HASingletonElectionPolicySimple;
-import org.jboss.ha.singleton.HASingletonElector;
-import org.jboss.ha.singleton.HASingletonSupport;
 import org.jboss.web.tomcat.service.modcluster.config.BalancerConfiguration;
 import org.jboss.web.tomcat.service.modcluster.config.ModClusterConfig;
 import org.jboss.web.tomcat.service.modcluster.config.NodeConfiguration;
-import org.jboss.web.tomcat.service.modcluster.ha.ModClusterServiceDRMEntry;
-import org.jboss.web.tomcat.service.modcluster.ha.ModClusterServiceHASingletonElectionPolicy;
 import org.jboss.web.tomcat.service.modcluster.ha.ClusteredMCMPHandler;
 import org.jboss.web.tomcat.service.modcluster.ha.ClusteredMCMPHandlerImpl;
 import org.jboss.web.tomcat.service.modcluster.ha.HASingletonAwareResetRequestSource;
+import org.jboss.web.tomcat.service.modcluster.ha.ModClusterServiceDRMEntry;
 import org.jboss.web.tomcat.service.modcluster.ha.rpc.BooleanGroupRpcResponse;
-import org.jboss.web.tomcat.service.modcluster.ha.rpc.ModClusterServiceStateGroupRpcResponse;
+import org.jboss.web.tomcat.service.modcluster.ha.rpc.ClusteredMCMPHandlerRpcHandler;
 import org.jboss.web.tomcat.service.modcluster.ha.rpc.GroupRpcResponse;
-import org.jboss.web.tomcat.service.modcluster.ha.rpc.InetAddressGroupRpcResponse;
 import org.jboss.web.tomcat.service.modcluster.ha.rpc.MCMPServerDiscoveryEvent;
+import org.jboss.web.tomcat.service.modcluster.ha.rpc.ModClusterServiceRpcHandler;
+import org.jboss.web.tomcat.service.modcluster.ha.rpc.ModClusterServiceStateGroupRpcResponse;
 import org.jboss.web.tomcat.service.modcluster.ha.rpc.PeerMCMPDiscoveryStatus;
 import org.jboss.web.tomcat.service.modcluster.ha.rpc.ResetRequestGroupRpcResponse;
+import org.jboss.web.tomcat.service.modcluster.ha.rpc.ResetRequestSourceRpcHandler;
 import org.jboss.web.tomcat.service.modcluster.ha.rpc.StringGroupRpcResponse;
 import org.jboss.web.tomcat.service.modcluster.ha.rpc.ThrowableGroupRpcResponse;
 import org.jboss.web.tomcat.service.modcluster.load.LoadBalanceFactorProvider;
@@ -77,31 +80,32 @@
  * @author Brian Stansberry
  * @version $Revision$
  */
-public class ModClusterService extends HASingletonSupport 
-   implements JBossWebEventHandler, ModClusterServiceMBean
+public class ModClusterService extends HASingletonImpl<HAServiceEvent>
+   implements JBossWebEventHandler, ModClusterServiceMBean, ModClusterServiceRpcHandler<List<?>, MCMPServerState>
 {
+   private static final Class<?>[] STOP_OLD_MASTER_TYPES = new Class[] { String.class };
+   
    // -----------------------------------------------------------------  Fields
    
+   final MCMPHandler localHandler;
+   final ClusteredMCMPHandler clusteredHandler;
+   final HASingletonAwareResetRequestSource resetRequestSource;
+   final Map<ClusterNode, MCMPServerDiscoveryEvent> proxyChangeDigest =
+      new HashMap<ClusterNode, MCMPServerDiscoveryEvent>();
+   
    /**
     * The string manager for this package.
     */
-   private final StringManager sm = StringManager.getManager(Constants.Package);
+   final StringManager sm = StringManager.getManager(Constants.Package);
    
-   private final HASingletonAwareResetRequestSource resetRequestSource;
-   private final MCMPHandler localHandler;
-   private final ClusteredMCMPHandler clusteredHandler;
    private final LoadBalanceFactorProvider loadManager;
    private final RpcHandler rpcHandler;
    private final JBossWebEventHandler eventHandlerDelegate;
-   private final ModClusterServiceHASingletonElectionPolicy electionPolicy;
    private final String domain;
-   private final Map<ClusterNode, MCMPServerDiscoveryEvent> proxyChangeDigest = 
-      new HashMap<ClusterNode, MCMPServerDiscoveryEvent>();
    
-   
+   volatile int latestLoad;
    private volatile int statusCount = 0;
    private volatile int processStatusFrequency = 1;
-   private volatile int latestLoad;
    private ModClusterServiceDRMEntry drmEntry;
    
    
@@ -131,29 +135,29 @@
    public ModClusterService(HAPartition partition,
                              ModClusterConfig config,
                              LoadBalanceFactorProvider loadFactorProvider,
-                             HASingletonElector singletonElector)
-   {      
-      assert partition != null          : sm.getString("modcluster.error.iae.null", "partition");        
-      assert loadFactorProvider != null : sm.getString("modcluster.error.iae.null", "loadFactorProvider");         
-      assert config != null             : sm.getString("modcluster.error.iae.null", "config is null");
+                             HASingletonElectionPolicy electionPolicy)
+   {
+      super(new HAServiceEventFactory());
       
-      setHAPartition(partition);
+      assert partition != null          : this.sm.getString("modcluster.error.iae.null", "partition");
+      assert loadFactorProvider != null : this.sm.getString("modcluster.error.iae.null", "loadFactorProvider");
+      assert config != null             : this.sm.getString("modcluster.error.iae.null", "config is null");
       
+      this.setHAPartition(partition);
+      
       this.resetRequestSource = new HASingletonAwareResetRequestSource(config, config, partition, ClusteredMCMPHandler.HA_SERVICE_NAME);
       this.localHandler = new DefaultMCMPHandler(config, this.resetRequestSource);
 //      this.localHandler.init();
       this.clusteredHandler = new ClusteredMCMPHandlerImpl(this.localHandler, partition, ClusteredMCMPHandler.HA_SERVICE_NAME);
       this.loadManager = loadFactorProvider;
-      this.eventHandlerDelegate = new DefaultJBossWebEventHandler(config, config, clusteredHandler, loadFactorProvider);
-      this.domain = config.getDomain();      
-      if (singletonElector == null)
-         singletonElector = new HASingletonElectionPolicySimple();
-      this.electionPolicy = new ModClusterServiceHASingletonElectionPolicy(singletonElector);
-      setElectionPolicy(this.electionPolicy);
+      this.eventHandlerDelegate = new DefaultJBossWebEventHandler(config, config, this.clusteredHandler, loadFactorProvider);
+      this.domain = config.getDomain();
       
-      this.drmEntry = new ModClusterServiceDRMEntry(partition.getClusterNode(), null);
+      this.setElectionPolicy((electionPolicy != null) ? electionPolicy : new HASingletonElectionPolicySimple());
       
-      this.rpcHandler = new RpcHandler();           
+      this.drmEntry = new ModClusterServiceDRMEntry(partition.getClusterNode(), this.domain, null);
+      
+      this.rpcHandler = new RpcHandler();
    }
    
    /**
@@ -177,31 +181,30 @@
          HASingletonAwareResetRequestSource resetRequestSource,
          ClusteredMCMPHandler clusteredHandler,
          LoadBalanceFactorProvider loadManager,
-         HASingletonElector singletonElector)
+         HASingletonElectionPolicy electionPolicy)
    {
-      assert partition != null          : sm.getString("modcluster.error.iae.null", "partition");
-      assert localHandler != null       : sm.getString("modcluster.error.iae.null", "localHandler");         
-      assert loadManager != null        : sm.getString("modcluster.error.iae.null", "loadManager");   
-      assert resetRequestSource != null : sm.getString("modcluster.error.iae.null", "resetRequestSource");       
-      assert nodeConfig != null         : sm.getString("modcluster.error.iae.null", "nodeConfig"); 
-      assert balancerConfig != null     : sm.getString("modcluster.error.iae.null", "balancerConfig");
-      assert clusteredHandler != null   : sm.getString("modcluster.error.iae.null", "clusteredHandler");
+      super(new HAServiceEventFactory());
       
-      setHAPartition(partition);
+      assert partition != null          : this.sm.getString("modcluster.error.iae.null", "partition");
+      assert localHandler != null       : this.sm.getString("modcluster.error.iae.null", "localHandler");
+      assert loadManager != null        : this.sm.getString("modcluster.error.iae.null", "loadManager");
+      assert resetRequestSource != null : this.sm.getString("modcluster.error.iae.null", "resetRequestSource");
+      assert nodeConfig != null         : this.sm.getString("modcluster.error.iae.null", "nodeConfig");
+      assert balancerConfig != null     : this.sm.getString("modcluster.error.iae.null", "balancerConfig");
+      assert clusteredHandler != null   : this.sm.getString("modcluster.error.iae.null", "clusteredHandler");
       
+      this.setHAPartition(partition);
+      
       this.localHandler = localHandler;
       this.resetRequestSource = resetRequestSource;
       this.clusteredHandler = clusteredHandler;
       this.loadManager = loadManager;
       this.eventHandlerDelegate = new DefaultJBossWebEventHandler(nodeConfig, balancerConfig, clusteredHandler, loadManager);
-      this.domain = nodeConfig.getDomain();  
+      this.domain = nodeConfig.getDomain();
       
-      if (singletonElector == null)
-         singletonElector = new HASingletonElectionPolicySimple();
-      this.electionPolicy = new ModClusterServiceHASingletonElectionPolicy(singletonElector);
-      setElectionPolicy(this.electionPolicy);
+      this.setElectionPolicy((electionPolicy != null) ? electionPolicy : new HASingletonElectionPolicySimple());
       
-      this.drmEntry = new ModClusterServiceDRMEntry(partition.getClusterNode(), null);
+      this.drmEntry = new ModClusterServiceDRMEntry(partition.getClusterNode(), this.domain, null);
       
       this.rpcHandler = new RpcHandler();
    }
@@ -235,7 +238,7 @@
    public void reset()
    {
       this.clusteredHandler.reset();
-   }  
+   }
    
    
    // ---------------------------------------------------- JBossWebEventHandler
@@ -250,7 +253,7 @@
    public void shutdown()
    {
       // Use the standard logic
-      this.eventHandlerDelegate.shutdown();      
+      this.eventHandlerDelegate.shutdown();
    }
    
    
@@ -260,76 +263,76 @@
       this.resetRequestSource.setJbossWebServer(server);
       
       // Use the standard logic
-      this.eventHandlerDelegate.startServer(server); 
+      this.eventHandlerDelegate.startServer(server);
    }
 
    public void stopServer(Server server)
    {
       // Use the standard logic
-      this.eventHandlerDelegate.stopServer(server); 
+      this.eventHandlerDelegate.stopServer(server);
    }
 
    public void config(Engine engine)
-   {          
+   {
       // If needed, create automagical JVM route (address + port + engineName)
       try {
          Utils.establishJvmRouteAndConnectorAddress(engine, this.clusteredHandler);
       } catch (Exception e) {
          this.clusteredHandler.markProxiesInError();
-         log.info(sm.getString("modcluster.error.addressJvmRoute"), e);
+         this.log.info(this.sm.getString("modcluster.error.addressJvmRoute"), e);
          return;
       }
       
       this.drmEntry.addJvmRoute(engine.getJvmRoute());
-      updateLocalDRM(drmEntry);
+      this.updateLocalDRM(this.drmEntry);
       
       // Use the standard logic
       this.eventHandlerDelegate.config(engine);
    }
    
    public void removeAll(Engine engine)
-   {       
+   {
       // Use the standard logic
       this.eventHandlerDelegate.removeAll(engine);
       
       this.drmEntry.removeJvmRoute(engine.getJvmRoute());
-      updateLocalDRM(drmEntry);      
+      this.updateLocalDRM(this.drmEntry);
    }
    
    public void addContext(Context context)
    {
       // Use the standard logic
-      this.eventHandlerDelegate.addContext(context);       
+      this.eventHandlerDelegate.addContext(context);
    }
    
    public void startContext(Context context)
    {
       // Use the standard logic
-      this.eventHandlerDelegate.startContext(context);       
+      this.eventHandlerDelegate.startContext(context);
    }
    
    public void stopContext(Context context)
    {
       // Use the standard logic
-      this.eventHandlerDelegate.stopContext(context);        
+      this.eventHandlerDelegate.stopContext(context);
    }
    
    public void removeContext(Context context)
    {
       // Use the standard logic
-      this.eventHandlerDelegate.removeContext(context);        
+      this.eventHandlerDelegate.removeContext(context);
    }
    
    public void status(Engine engine)
    {
-      this.latestLoad = loadManager.getLoadBalanceFactor();
+      this.latestLoad = this.loadManager.getLoadBalanceFactor();
       
       if (this.isMasterNode())
       {
-         statusCount = (statusCount + 1) % processStatusFrequency;
-         if (statusCount == 0) 
+         this.statusCount = (this.statusCount + 1) % this.processStatusFrequency;
+         if (this.statusCount == 0)
          {
-            updateClusterStatus();
+            this.updateClusterStatus();
          }
       }
    }
@@ -356,12 +359,6 @@
    // -------------------------------------------------------  Public Overrides
 
    @Override
-   public void _stopOldMaster()
-   {
-      this.stopOldMaster(this.getDomain());
-   }
-
-   @Override
    public void startSingleton()
    {
       super.startSingleton();
@@ -370,7 +367,7 @@
       this.resetRequestSource.setMasterNode(true);
       
       // Ensure we do a full status on the next event
-      this.statusCount = processStatusFrequency - 1;
+      this.statusCount = this.processStatusFrequency - 1;
    }
 
    @Override
@@ -378,16 +375,16 @@
    {
       super.stopSingleton();
       
-      this.clusteredHandler.setMasterNode(false); 
+      this.clusteredHandler.setMasterNode(false);
       this.resetRequestSource.setMasterNode(false);
-   }   
+   }
 
    @Override
    @Inject(fromContext = FromContext.NAME)
    public void setServiceHAName(String haName)
    {
       super.setServiceHAName(haName);
-      this.clusteredHandler.setHAServiceName(getServiceHAName());
+      this.clusteredHandler.setHAServiceName(this.getServiceHAName());
    }
    
 
@@ -396,83 +393,105 @@
    /**
     * {@inheritDoc}
     * 
-    * We override the superclass to pass our domain as a param to the 
-    * "_stopOldMaster" call.
+    * @return an inner class that allows us to avoid exposing RPC methods as
+    *         public methods of this class
     */
    @Override
-   protected void makeThisNodeMaster()
+   protected HAServiceRpcHandler<HAServiceEvent> getRpcHandler()
    {
-      try
-      {
-         // stop the old master (if there is one) before starting the new one
-
-         // ovidiu 09/02/04 - temporary solution for Case 1843, use an asynchronous
-         // distributed call.
-         this.callAsyncMethodOnPartition("stopOldMaster", new Object[]{ getDomain() }, new Class[]{ String.class });
-
-         this.startNewMaster();
-      }
-      catch (Exception ex)
-      {
-         this.log.error(sm.getString("modcluster.error.stopOldMaster"), ex);
-      }
+      return this.rpcHandler;
    }
 
    /**
     * {@inheritDoc}
     * 
-    * @return an inner class that allows us to avoid exposing RPC methods as
-    *         public methods of this class
+    * @return a {@link ModClusterServiceDRMEntry}
     */
    @Override
-   protected Object getRPCHandler()
+   protected Serializable getReplicant()
    {
-      return rpcHandler;
-   }   
+      return this.drmEntry;
+   }
 
    /**
     * {@inheritDoc}
-    * 
-    * @return a {@link ModClusterServiceDRMEntry}
+    * @return a list of cluster nodes from which to elect a new master
     */
    @Override
-   protected Serializable getReplicant()
+   @SuppressWarnings("unchecked")
+   protected List<ClusterNode> getElectionCandidates()
    {
-      return drmEntry;
+      List<ModClusterServiceDRMEntry> candidates = this.getHAPartition().getDistributedReplicantManager().lookupReplicants(this.getServiceHAName());
+      
+      return this.narrowCandidateList(candidates);
    }
    
-   // ----------------------------------------------------------------- Private
-
-   private void stopOldMaster(String domain)
+   /**
+    * Processes the candidate list, discarding those who don't match our domain nor the best
+    * candidate when it comes to the ability to communicate with proxies.
+    * 
+    * @param candidates the universe of possible candidates.
+    * @return a list of candidates with an equivalent ability to communicate
+    *         with proxies, or <code>null</code> if <code>candidates</code>
+    *         is <code>null</code>.
+    */
+   List<ClusterNode> narrowCandidateList(Collection<ModClusterServiceDRMEntry> candidates)
    {
-      if (safeEquals(domain, this.getDomain()))
+      if (candidates == null)
       {
-         super._stopOldMaster();
+         return null;
       }
-      else
+      
+      List<ClusterNode> narrowed = new ArrayList<ClusterNode>(candidates.size());
+      ModClusterServiceDRMEntry champion = null;
+      
+      for (ModClusterServiceDRMEntry candidate : candidates)
       {
-         log.debug(sm.getString("modcluster.singleton.ignorestop", domain, this.getDomain()));
+         if (!this.domainEquals(candidate.getDomain()))
+         {
+            continue;
+         }
+         
+         if (champion == null)
+         {
+            champion = candidate;
+            narrowed.add(candidate.getPeer());
+         }
+         else
+         {
+            int compFactor = candidate.compareTo(champion);
+            if (compFactor < 0)
+            {
+               // New champ
+               narrowed.clear();
+               champion = candidate;
+               narrowed.add(candidate.getPeer());
+            }
+            else if (compFactor == 0)
+            {
+               // As good as our champ
+               narrowed.add(candidate.getPeer());
+            }
+            // else candidate didn't make the cut; continue
+         }
       }
+      
+      return narrowed;
    }
    
-   private boolean safeEquals(Object a, Object b)
-   {      
-      return (a == b || (a != null && a.equals(b)));
-   }
-   
    @SuppressWarnings("unchecked")
    private void updateClusterStatus()
    {
       this.localHandler.status();
       Set<MCMPServerState> masterList = null;
       Map<ClusterNode, MCMPServerDiscoveryEvent> latestEvents = null;
-      synchronized (proxyChangeDigest)
+      synchronized (this.proxyChangeDigest)
       {
          masterList = this.localHandler.getProxyStates();
-         latestEvents = new HashMap<ClusterNode, MCMPServerDiscoveryEvent>(proxyChangeDigest);
+         latestEvents = new HashMap<ClusterNode, MCMPServerDiscoveryEvent>(this.proxyChangeDigest);
       }
-      HAPartition partition = getHAPartition();      
-      List<ModClusterServiceDRMEntry> replicants = partition.getDistributedReplicantManager().lookupReplicants(getServiceHAName());
+      HAPartition partition = this.getHAPartition();
+      List<ModClusterServiceDRMEntry> replicants = partition.getDistributedReplicantManager().lookupReplicants(this.getServiceHAName());
       Map<ClusterNode, ModClusterServiceDRMEntry> nonresponsive = new HashMap<ClusterNode, ModClusterServiceDRMEntry>();
       for (ModClusterServiceDRMEntry replicant : replicants)
       {
@@ -481,15 +500,7 @@
       nonresponsive.remove(partition.getClusterNode());
       
       // FIXME -- what about our own dropped discovery events if we just became master?
-      List responses = null;
-      try
-      {
-         responses = partition.callMethodOnCluster(getServiceHAName(), "getClusterCoordinatorState", new Object[]{ masterList }, new Class[]{ Set.class }, true);
-      }
-      catch (Exception e)
-      {
-         throw Utils.convertToUnchecked(e);
-      }
+      List responses = this.getClusterCoordinatorState(masterList);
       
       // Gather up all the reset requests in one list
       // FIXME -- what about our own dropped requests if we just became master?
@@ -514,7 +525,9 @@
             for (MCMPServerDiscoveryEvent toCheck : mcssgrr.getUnacknowledgedEvents())
             {
                if (latestEvent != null && latestEvent.getEventIndex() <= toCheck.getEventIndex())
+               {
                   continue; // already processed it
+               }
             
                AddressPort ap = toCheck.getMCMPServer();
                if (toCheck.isAddition())
@@ -530,11 +543,13 @@
             
             if (!resync) // don't bother if we are going to start over
             {
-               statuses.put(cn, new PeerMCMPDiscoveryStatus(cn, mcssgrr.getStates(), latestEvent));
+               statuses.put(cn, new PeerMCMPDiscoveryStatus(cn, this.domain, mcssgrr.getStates(), latestEvent));
                
                List<MCMPRequest> toAdd = mcssgrr.getResetRequests();
                if (toAdd != null)
+               {
                   resetRequests.addAll(toAdd);
+               }
                
                ModClusterServiceDRMEntry removed = nonresponsive.remove(cn);
                if (removed != null)
@@ -552,34 +567,34 @@
             ThrowableGroupRpcResponse tgrr = (ThrowableGroupRpcResponse) response;
             ClusterNode cn = tgrr.getSender();
             
-            log.warn(sm.getString("modcluster.error.rpc.known", "getClusterCoordinatorState", cn), tgrr.getValue());
+            this.log.warn(this.sm.getString("modcluster.error.rpc.known", "getClusterCoordinatorState", cn), tgrr.getValue());
             
-            // Don't remove from nonresponsive list and we'll pass back an error 
+            // Don't remove from nonresponsive list and we'll pass back an error
             // status (null server list) to this peer
          }
          else if (response instanceof Throwable)
          {
-            log.warn(sm.getString("modcluster.error.rpc.unknown", "getClusterCoordinatorState"), (Throwable) response);
+            this.log.warn(this.sm.getString("modcluster.error.rpc.unknown", "getClusterCoordinatorState"), (Throwable) response);
          }
          else
          {
-            log.error(sm.getString("modcluster.error.rpc.unexpected", response, "getClusterCoordinatorState"));
+            this.log.error(this.sm.getString("modcluster.error.rpc.unexpected", response, "getClusterCoordinatorState"));
          }
       }
       
       if (resync)
       {
          // We picked up previously unknown discovery events; start over
-         updateClusterStatus();
+         this.updateClusterStatus();
          return;
       }
       
-      // Add error-state objects for non-responsive peers      
+      // Add error-state objects for non-responsive peers
       Integer lbf = new Integer(0);
       for (Map.Entry<ClusterNode, ModClusterServiceDRMEntry> entry : nonresponsive.entrySet())
       {
          ClusterNode cn = entry.getKey();
-         statuses.put(entry.getKey(), new PeerMCMPDiscoveryStatus(cn, null, latestEvents.get(cn)));
+         statuses.put(entry.getKey(), new PeerMCMPDiscoveryStatus(cn, this.domain, null, latestEvents.get(cn)));
          
          for (String jvmRoute : entry.getValue().getJvmRoutes())
          {
@@ -601,60 +616,79 @@
       this.localHandler.sendRequests(statusRequests);
       
       // Advise the members the process is done and that they should update DRM
-      notifyClusterStatusComplete(masterList, statuses);      
+      this.notifyClusterStatusComplete(masterList, statuses);
    }
 
-   private void notifyClusterStatusComplete(Set<MCMPServerState> masterList, 
+   private void notifyClusterStatusComplete(Set<MCMPServerState> masterList,
                            Map<ClusterNode, PeerMCMPDiscoveryStatus> statuses)
    {
-      HAPartition partition = getHAPartition();
+      HAPartition partition = this.getHAPartition();
       
       // Determine who should update DRM first -- us or the rest of the nodes
       Set<ModClusterServiceDRMEntry> allStatuses = new HashSet<ModClusterServiceDRMEntry>(statuses.values());
-      ModClusterServiceDRMEntry ourCurrentStatus = (ModClusterServiceDRMEntry) partition.getDistributedReplicantManager().lookupLocalReplicant(getServiceHAName());
+      ModClusterServiceDRMEntry ourCurrentStatus = (ModClusterServiceDRMEntry) partition.getDistributedReplicantManager().lookupLocalReplicant(this.getServiceHAName());
       allStatuses.add(ourCurrentStatus);
       
-      boolean othersFirst = this.electionPolicy.narrowCandidateList(allStatuses).contains(partition.getClusterNode());
-      ModClusterServiceDRMEntry ourNewStatus = new ModClusterServiceDRMEntry(partition.getClusterNode(), masterList);
+      boolean othersFirst = this.narrowCandidateList(allStatuses).contains(partition.getClusterNode());
+      ModClusterServiceDRMEntry ourNewStatus = new ModClusterServiceDRMEntry(partition.getClusterNode(), this.domain, masterList);
       boolean updated = (ourNewStatus.equals(ourCurrentStatus) == false);
       
       if (othersFirst)
       {
-         remoteNotifyClusterStatusComplete(statuses);
+         this.clusterStatusComplete(statuses);
          
          if (updated)
          {
-            updateLocalDRM(ourNewStatus);
-         }         
+            this.updateLocalDRM(ourNewStatus);
+         }
       }
       else
       {
          if (updated)
          {
-            updateLocalDRM(ourNewStatus);
+            this.updateLocalDRM(ourNewStatus);
          }
          
-         remoteNotifyClusterStatusComplete(statuses);
+         this.clusterStatusComplete(statuses);
       }
    }
 
-   private void remoteNotifyClusterStatusComplete(Map<ClusterNode, PeerMCMPDiscoveryStatus> statuses)
+   /**
+    * @see org.jboss.web.tomcat.service.modcluster.ha.rpc.ModClusterServiceRpcHandler#clusterStatusComplete(java.util.Map)
+    */
+   public void clusterStatusComplete(Map<ClusterNode, PeerMCMPDiscoveryStatus> statuses)
    {
       try
       {
-         getHAPartition().callMethodOnCluster(getServiceHAName(), "clusterStatusComplete", new Object[]{ statuses }, new Class[]{ Map.class }, true);
+         this.callMethodOnPartition("clusterStatusComplete", new Object[] { statuses }, new Class[] { Map.class });
       }
       catch (Exception e)
       {
-         log.error(sm.getString("modcluster.error.status.complete"), e);
+         this.log.error(this.sm.getString("modcluster.error.status.complete"), e);
       }
    }
 
+   /**
+    * @see org.jboss.web.tomcat.service.modcluster.ha.rpc.ModClusterServiceRpcHandler#getClusterCoordinatorState(java.util.Set)
+    */
+   public List<?> getClusterCoordinatorState(Set<MCMPServerState> masterList)
+   {
+      try
+      {
+         return this.callMethodOnPartition("getClusterCoordinatorState", new Object[] { masterList }, new Class[] { Set.class });
+      }
+      catch (Exception e)
+      {
+         throw Utils.convertToUnchecked(e);
+      }
+   }
+
+
    private void updateLocalDRM(ModClusterServiceDRMEntry ourNewStatus) throws Error
    {
       try
       {
-         getHAPartition().getDistributedReplicantManager().add(getServiceHAName(), ourNewStatus);
+         this.getHAPartition().getDistributedReplicantManager().add(this.getServiceHAName(), ourNewStatus);
       }
       catch (Exception e)
       {
@@ -662,47 +696,77 @@
       }
    }
    
+   /**
+    * Redirect to {@link #stopOldMaster(String)}
+    * @see org.jboss.ha.framework.server.HASingletonImpl#stopOldMaster()
+    */
+   @Override
+   public void stopOldMaster()
+   {
+      this.stopOldMaster(this.domain);
+   }
 
+   /**
+    * @see org.jboss.web.tomcat.service.modcluster.ha.rpc.ModClusterServiceRpcHandler#stopOldMaster(java.lang.String)
+    */
+   public void stopOldMaster(String domain)
+   {
+      try
+      {
+         this.callAsyncMethodOnPartition("stopOldMaster", new Object[] { domain }, STOP_OLD_MASTER_TYPES);
+      }
+      catch (Exception e)
+      {
+         throw Utils.convertToUnchecked(e);
+      }
+   }
+
+   boolean domainEquals(String domain)
+   {
+      return ((this.domain != null) && (domain != null)) ? this.domain.equals(domain) : (this.domain == domain);
+   }
+
    // ---------------------------------------------------------- Inner classes
    
    /**
     * This is the object that gets invoked on via reflection by HAPartition.
     */
-   public class RpcHandler
+   protected class RpcHandler extends HAServiceImpl<HAServiceEvent>.RpcHandler implements ModClusterServiceRpcHandler<GroupRpcResponse, MCMPServer>, ClusteredMCMPHandlerRpcHandler, ResetRequestSourceRpcHandler<GroupRpcResponse>
    {
       private final ModClusterService coord = ModClusterService.this;
-      private final GroupRpcResponse SUCCESS = 
-         new GroupRpcResponse(this.coord.getHAPartition().getClusterNode());
+      private final GroupRpcResponse SUCCESS = new GroupRpcResponse(this.coord.getHAPartition().getClusterNode());
       
-      
+      /**
+       * @see org.jboss.web.tomcat.service.modcluster.ha.rpc.ModClusterServiceRpcHandler#stopOldMaster(java.lang.String)
+       */
       public void stopOldMaster(String domain)
       {
-         this.coord.stopOldMaster(domain);
+         // Ignore rpc calls from other domains
+         if (this.coord.domainEquals(domain))
+         {
+            this.coord.stopIfMaster();
+         }
       }
-      
-      public void _receiveRemoteNotification(Notification notification)
+/*
+      public GroupRpcResponse getLocalAddress() throws IOException
       {
-         this.coord._receiveRemoteNotification(notification);
-      }
-
-      public InetAddressGroupRpcResponse getLocalAddress() throws IOException
-      {
-         if (this.coord.isMasterNode())      
+         if (this.coord.isMasterNode())
          {
-            return new InetAddressGroupRpcResponse(this.coord.getHAPartition().getClusterNode(), 
+            return new InetAddressGroupRpcResponse(this.coord.getHAPartition().getClusterNode(),
                                                    this.coord.localHandler.getLocalAddress());
          }
-         else
-         {         
-            return null;
-         }
+         
+         return null;
       }
-      
+*/
+      /**
+       * @see org.jboss.web.tomcat.service.modcluster.ha.rpc.ClusteredMCMPHandlerRpcHandler#mcmpServerDiscoveryEvent(org.jboss.web.tomcat.service.modcluster.ha.rpc.MCMPServerDiscoveryEvent)
+       */
       public GroupRpcResponse mcmpServerDiscoveryEvent(MCMPServerDiscoveryEvent event)
       {
-         if (this.coord.isMasterNode())      
+         if (this.coord.isMasterNode())
          {
-            synchronized (proxyChangeDigest)
+            synchronized (ModClusterService.this.proxyChangeDigest)
             {
                AddressPort ap = event.getMCMPServer();
                if (event.isAddition())
@@ -713,19 +777,20 @@
                {
                   this.coord.localHandler.removeProxy(ap.address, ap.port);
                }
-               proxyChangeDigest.put(event.getSender(), event);
-               return new GroupRpcResponse(getHAPartition().getClusterNode());
-            }            
+               ModClusterService.this.proxyChangeDigest.put(event.getSender(), event);
+               return new GroupRpcResponse(ModClusterService.this.getHAPartition().getClusterNode());
+            }
          }
-         else
-         {         
-            return null;
-         }           
+
+         return null;
       }
       
-      public ModClusterServiceStateGroupRpcResponse getClusterCoordinatorState(Set<MCMPServer> masterList)
+      /**
+       * @see org.jboss.web.tomcat.service.modcluster.ha.rpc.ModClusterServiceRpcHandler#getClusterCoordinatorState(java.util.Set)
+       */
+      public GroupRpcResponse getClusterCoordinatorState(Set<MCMPServer> masterList)
       {
-         if (this.coord.isMasterNode() == false)      
+         if (this.coord.isMasterNode() == false)
          {
             Set<MCMPServerState> ourStates = this.coord.clusteredHandler.updateServersFromMasterNode(masterList);
             
@@ -736,8 +801,8 @@
                resetRequests = this.coord.resetRequestSource.getLocalResetRequests();
             }
             
-            ModClusterServiceStateGroupRpcResponse response = 
-               new ModClusterServiceStateGroupRpcResponse(getHAPartition().getClusterNode(), 
+            GroupRpcResponse response =
+               new ModClusterServiceStateGroupRpcResponse(ModClusterService.this.getHAPartition().getClusterNode(),
                                                            this.coord.latestLoad,
                                                            ourStates,
                                                            this.coord.clusteredHandler.getPendingDiscoveryEvents(),
@@ -750,14 +815,14 @@
             
             return response;
          }
-         else
-         {         
-            // TODO is this the correct response here?
-            return null;
-         }   
-         
+
+         // TODO is this the correct response here?
+         return null;
       }
       
+      /**
+       * @see org.jboss.web.tomcat.service.modcluster.ha.rpc.ModClusterServiceRpcHandler#clusterStatusComplete(java.util.Map)
+       */
       public void clusterStatusComplete(Map<ClusterNode, PeerMCMPDiscoveryStatus> statuses)
       {
          HAPartition partition = this.coord.getHAPartition();
@@ -773,101 +838,110 @@
             
             DistributedReplicantManager drm = partition.getDistributedReplicantManager();
             String haName = this.coord.getServiceHAName();
-            ModClusterServiceDRMEntry oldStatus = 
+            ModClusterServiceDRMEntry oldStatus =
                (ModClusterServiceDRMEntry) drm.lookupLocalReplicant(haName);
             if (newStatus.equals(oldStatus) == false)
             {
                try
                {
-                  drm.add(haName, new ModClusterServiceDRMEntry(cn, newStatus.getMCMPServerStates()));
+                  drm.add(haName, new ModClusterServiceDRMEntry(cn, this.coord.getDomain(), newStatus.getMCMPServerStates()));
                }
                catch (Exception e)
                {
-                  this.coord.log.error(sm.getString("modcluster.error.drm"), e);
+                  this.coord.log.error(ModClusterService.this.sm.getString("modcluster.error.drm"), e);
                }
             }
          }
       }
 
-      public StringGroupRpcResponse getProxyConfiguration()
+      /**
+       * @see org.jboss.web.tomcat.service.modcluster.ha.rpc.ClusteredMCMPHandlerRpcHandler#getProxyConfiguration()
+       */
+      public GroupRpcResponse getProxyConfiguration()
       {
-         if (this.coord.isMasterNode())      
+         if (this.coord.isMasterNode())
          {
-            return new StringGroupRpcResponse(getHAPartition().getClusterNode(), this.coord.localHandler.getProxyConfiguration());
+            return new StringGroupRpcResponse(ModClusterService.this.getHAPartition().getClusterNode(), this.coord.localHandler.getProxyConfiguration());
          }
-         else
-         {         
-            return null;
-         }
+
+         return null;
       }
 
-      public BooleanGroupRpcResponse isProxyHealthOK()
+      /**
+       * @see org.jboss.web.tomcat.service.modcluster.ha.rpc.ClusteredMCMPHandlerRpcHandler#isProxyHealthOK()
+       */
+      public GroupRpcResponse isProxyHealthOK()
       {
-         if (this.coord.isMasterNode())      
+         if (this.coord.isMasterNode())
          {
-            return new BooleanGroupRpcResponse(getHAPartition().getClusterNode(), this.coord.localHandler.isProxyHealthOK());
+            return new BooleanGroupRpcResponse(ModClusterService.this.getHAPartition().getClusterNode(), this.coord.localHandler.isProxyHealthOK());
          }
-         else
-         {         
-            return null;
-         }
+
+         return null;
       }
 
+      /**
+       * @see org.jboss.web.tomcat.service.modcluster.ha.rpc.ClusteredMCMPHandlerRpcHandler#markProxiesInError()
+       */
       public GroupRpcResponse markProxiesInError()
       {
-         if (this.coord.isMasterNode())      
+         if (this.coord.isMasterNode())
          {
             this.coord.localHandler.markProxiesInError();
-            return SUCCESS;
+            return this.SUCCESS;
          }
-         else
-         {         
-            return null;
-         }
+
+         return null;
       }
 
+      /**
+       * @see org.jboss.web.tomcat.service.modcluster.ha.rpc.ClusteredMCMPHandlerRpcHandler#reset()
+       */
       public GroupRpcResponse reset()
       {
-         if (this.coord.isMasterNode())      
+         if (this.coord.isMasterNode())
          {
             this.coord.localHandler.reset();
-            return SUCCESS;
+            return this.SUCCESS;
          }
-         else
-         {         
-            return null;
-         }
+
+         return null;
       }
 
+      /**
+       * @see org.jboss.web.tomcat.service.modcluster.ha.rpc.ClusteredMCMPHandlerRpcHandler#sendRequest(org.jboss.web.tomcat.service.modcluster.mcmp.MCMPRequest)
+       */
       public GroupRpcResponse sendRequest(MCMPRequest request)
       {
-         if (this.coord.isMasterNode())      
+         if (this.coord.isMasterNode())
          {
             this.coord.localHandler.sendRequest(request);
-            return SUCCESS;
+            return this.SUCCESS;
          }
-         else
-         {         
-            return null;
-         }
+
+         return null;
       }
 
+      /**
+       * @see org.jboss.web.tomcat.service.modcluster.ha.rpc.ClusteredMCMPHandlerRpcHandler#sendRequests(java.util.List)
+       */
       public GroupRpcResponse sendRequests(List<MCMPRequest> requests)
       {
-         if (this.coord.isMasterNode())      
+         if (this.coord.isMasterNode())
          {
             this.coord.localHandler.sendRequests(requests);
-            return SUCCESS;
+            return this.SUCCESS;
          }
-         else
-         {         
-            return null;
-         }
+
+         return null;
       }
       
-      public ResetRequestGroupRpcResponse getResetRequests()
+      /**
+       * @see org.jboss.web.tomcat.service.modcluster.ha.rpc.ResetRequestSourceRpcHandler#getResetRequests()
+       */
+      public GroupRpcResponse getResetRequests()
       {
-         return new ResetRequestGroupRpcResponse(getHAPartition().getClusterNode(), 
+         return new ResetRequestGroupRpcResponse(ModClusterService.this.getHAPartition().getClusterNode(),
                                                  this.coord.resetRequestSource.getLocalResetRequests());
       }
    }

Modified: trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ModClusterServiceMBean.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ModClusterServiceMBean.java	2008-08-05 16:13:35 UTC (rev 76669)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ModClusterServiceMBean.java	2008-08-05 16:17:01 UTC (rev 76670)
@@ -22,7 +22,6 @@
 
 package org.jboss.web.tomcat.service.modcluster;
 
-import org.jboss.ha.jmx.HAServiceMBean;
 import org.jboss.web.tomcat.service.modcluster.mcmp.MCMPRequestType;
 import org.jboss.web.tomcat.service.modcluster.mcmp.MCMPServerState;
 
@@ -31,7 +30,7 @@
  * 
  * @author Brian Stansberry
  */
-public interface ModClusterServiceMBean extends HAServiceMBean
+public interface ModClusterServiceMBean
 {   
    /**
     * Add a proxy to the list of those with which this handler communicates.
@@ -79,5 +78,6 @@
     * @return the configuration information from all the accessible proxies.
     */
    String getProxyConfiguration();
-
+   
+   String getDomain();
 }

Modified: trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ha/ClusteredMCMPHandlerImpl.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ha/ClusteredMCMPHandlerImpl.java	2008-08-05 16:13:35 UTC (rev 76669)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ha/ClusteredMCMPHandlerImpl.java	2008-08-05 16:17:01 UTC (rev 76670)
@@ -37,9 +37,9 @@
 import org.jboss.logging.Logger;
 import org.jboss.web.tomcat.service.modcluster.Constants;
 import org.jboss.web.tomcat.service.modcluster.Utils;
-import org.jboss.web.tomcat.service.modcluster.advertise.AdvertiseListener;
 import org.jboss.web.tomcat.service.modcluster.config.MCMPHandlerConfiguration;
 import org.jboss.web.tomcat.service.modcluster.ha.rpc.BooleanGroupRpcResponse;
+import org.jboss.web.tomcat.service.modcluster.ha.rpc.ClusteredMCMPHandlerRpcHandler;
 import org.jboss.web.tomcat.service.modcluster.ha.rpc.GroupRpcResponse;
 import org.jboss.web.tomcat.service.modcluster.ha.rpc.GroupRpcResponseFilter;
 import org.jboss.web.tomcat.service.modcluster.ha.rpc.MCMPServerDiscoveryEvent;
@@ -54,19 +54,20 @@
 
 public class ClusteredMCMPHandlerImpl implements ClusteredMCMPHandler
 {
-   private static final Object[] NULL_ARGS = new Object[0];
-   private static final Class[] NULL_TYPES = new Class[0];
-   private static final Class[] MCMPREQ_TYPES = new Class[] { MCMPRequest.class };
-   private static final Class[] MCMPREQS_TYPES = new Class[] { List.class };
-   private static final Class[] DISC_EVENT_TYPES = new Class[] { MCMPServerDiscoveryEvent.class };
+   static final Object[] NULL_ARGS = new Object[0];
+   static final Class<?>[] NULL_TYPES = new Class[0];
+   static final Class<?>[] MCMPREQ_TYPES = new Class[] { MCMPRequest.class };
+   static final Class<?>[] MCMPREQS_TYPES = new Class[] { List.class };
+   static final Class<?>[] DISC_EVENT_TYPES = new Class[] { MCMPServerDiscoveryEvent.class };
    
-   private static final Logger log = Logger.getLogger(ClusteredMCMPHandlerImpl.class);
+   static final Logger log = Logger.getLogger(ClusteredMCMPHandlerImpl.class);
    
+   final HAPartition partition;
    private final MCMPHandler localHandler;
-   private final HAPartition partition;
-   private String haServiceName;
-   private AdvertiseListener advertiseListener;
+   private final ClusteredMCMPHandlerRpcHandler rpcStub = new RpcStub();
+//   private AdvertiseListener advertiseListener;
    
+   private volatile String haServiceName;
    private volatile boolean masterNode = false;
    
    @GuardedBy("errorState")
@@ -80,8 +81,7 @@
    /**
     * The string manager for this package.
     */
-   private final StringManager sm =
-       StringManager.getManager(Constants.Package);
+   final StringManager sm = StringManager.getManager(Constants.Package);
    
    public ClusteredMCMPHandlerImpl(MCMPHandler localHandler, HAPartition partition, String haServiceName)
    {
@@ -102,16 +102,25 @@
       this.masterNode = masterNode;
    }
 
+   /**
+    * @see org.jboss.web.tomcat.service.modcluster.ha.ClusteredMCMPHandler#getHAServiceName()
+    */
    public String getHAServiceName()
    {
       return this.haServiceName;
    }
 
-   public void setHAServiceName(String haServiceName)
+   /**
+    * @see org.jboss.web.tomcat.service.modcluster.ha.ClusteredMCMPHandler#setHAServiceName(java.lang.String)
+    */
+   public void setHAServiceName(String serviceName)
    {
-      this.haServiceName = haServiceName;
+      this.haServiceName = serviceName;
    }
-   
+
+   /**
+    * @see org.jboss.web.tomcat.service.modcluster.ha.ClusteredMCMPHandler#getPartitionName()
+    */
    public String getPartitionName()
    {
       return this.partition.getPartitionName();
@@ -119,14 +128,14 @@
 
    public synchronized List<MCMPServerDiscoveryEvent> getPendingDiscoveryEvents()
    {
-      return new ArrayList<MCMPServerDiscoveryEvent>(pendingDiscoveryEvents);
+      return new ArrayList<MCMPServerDiscoveryEvent>(this.pendingDiscoveryEvents);
    }
    
    public synchronized void discoveryEventsReceived(MCMPServerDiscoveryEvent lastReceived)
    {
       if (lastReceived != null)
       {
-         for (Iterator<MCMPServerDiscoveryEvent> it = pendingDiscoveryEvents.iterator(); it.hasNext();)
+         for (Iterator<MCMPServerDiscoveryEvent> it = this.pendingDiscoveryEvents.iterator(); it.hasNext();)
          {
             MCMPServerDiscoveryEvent event = it.next();
             if (event.getEventIndex() <= lastReceived.getEventIndex())
@@ -144,16 +153,16 @@
    public synchronized Set<MCMPServerState> updateServersFromMasterNode(Set<MCMPServer> masterList)
    {
       for (MCMPServer server : masterList)
-      {         
-         this.localHandler.addProxy(server.getAddress(), server.getPort(), server.isEstablished());         
+      {
+         this.localHandler.addProxy(server.getAddress(), server.getPort(), server.isEstablished());
       }
       
       for (MCMPServer server : this.localHandler.getProxyStates())
       {
          if (!masterList.contains(server))
          {
-            this.localHandler.removeProxy(server.getAddress(), server.getPort()); 
-         }            
+            this.localHandler.removeProxy(server.getAddress(), server.getPort());
+         }
       }
       
       this.localHandler.status();
@@ -163,33 +172,33 @@
    
    public boolean getNeedsResetTransmission()
    {
-      synchronized (errorState)
-      {         
-         return errorState.size() > 0 && (errorState.get(errorState.size() -1).booleanValue() == false);
+      synchronized (this.errorState)
+      {
+         return this.errorState.size() > 0 && (this.errorState.get(this.errorState.size() - 1).booleanValue() == false);
       }
    }
    
    public void recordResetTransmission()
    {
-      synchronized (errorState)
+      synchronized (this.errorState)
       {
-         if (errorState.size() > 0)
+         if (this.errorState.size() > 0)
          {
-            errorState.set(0, Boolean.TRUE);
+            this.errorState.set(0, Boolean.TRUE);
          }
       }
    }
    
    public void recordResetSuccess()
    {
-      synchronized (errorState)
+      synchronized (this.errorState)
       {
-         if (errorState.size() > 0 || errorState.get(errorState.size() -1).booleanValue())
+         if (this.errorState.size() > 0 || this.errorState.get(this.errorState.size() - 1).booleanValue())
          {
-            errorState.remove(0);            
+            this.errorState.remove(0);
          }
       }
-   }   
+   }
    
    // ------------------------------------------------------------  MCMPHandler
 
@@ -199,9 +208,9 @@
    }
 
    public void addProxy(String address)
-   {      
+   {
       AddressPort ap = MCMPUtils.parseAddressPort(address);
-      addProxy(ap.address, ap.port);
+      this.addProxy(ap.address, ap.port);
    }
 
    public void addProxy(String host, int port)
@@ -213,31 +222,31 @@
          throw new IllegalArgumentException(e);
       }
       
-      addProxy(address, port);  
+      this.addProxy(address, port);
    }
 
    public synchronized void addProxy(InetAddress address, int port)
    {
-      if (isMasterNode())
+      if (this.isMasterNode())
       {
          this.localHandler.addProxy(address, port);
       }
       else
       {
-         sendDiscoveryEventToPartition(address, port, true);
-      }      
+         this.sendDiscoveryEventToPartition(address, port, true);
+      }
    }
 
    public void addProxy(InetAddress address, int port, boolean established)
    {
-      this.localHandler.addProxy(address, port, established);               
+      this.localHandler.addProxy(address, port, established);
    }
    
    
    /**
     * Remove proxy.
     */
-   public synchronized void removeProxy(String host, int port) 
+   public synchronized void removeProxy(String host, int port)
    {
       InetAddress address = null;
       try {
@@ -245,22 +254,22 @@
       } catch (Exception e) {
          throw new IllegalArgumentException(e);
       }
-      removeProxy(address, port);
-   }   
+      this.removeProxy(address, port);
+   }
    
    /**
     * Remove proxy.
     */
-   public synchronized void removeProxy(InetAddress address, int port) 
+   public synchronized void removeProxy(InetAddress address, int port)
    {
-      if (isMasterNode())
+      if (this.isMasterNode())
       {
          this.localHandler.removeProxy(address, port);
       }
       else
       {
-         sendDiscoveryEventToPartition(address, port, false);
-      }  
+         this.sendDiscoveryEventToPartition(address, port, false);
+      }
    }
 
    public Set<MCMPServerState> getProxyStates()
@@ -270,160 +279,125 @@
 
    public InetAddress getLocalAddress() throws IOException
    {
-      return localHandler.getLocalAddress();
+      return this.localHandler.getLocalAddress();
    }
 
    public String getProxyConfiguration()
    {
-      if (isMasterNode())
+      if (this.isMasterNode())
       {
          return this.localHandler.getProxyConfiguration();
       }
-      else
-      {
-         GroupRpcResponse result = invokeNoArgGroupRpc("getProxyConfiguration");
-         if (result instanceof StringGroupRpcResponse)
-         {
-            return ((StringGroupRpcResponse) result).getValue();
-         }
-         else
-         {
-            throw ((ThrowableGroupRpcResponse) result).getValueAsRuntimeException();
-         }
-      }
+
+      GroupRpcResponse response = this.rpcStub.getProxyConfiguration();
+      
+      this.validateResponse(response, false);
+      
+      return ((StringGroupRpcResponse) response).getValue();
    }
 
    public void init(List<AddressPort> initialProxies)
-   {      
-      if (isMasterNode())
+   {
+      if (this.isMasterNode())
       {
          this.localHandler.init(initialProxies);
       }
       else
       {
          this.localHandler.init(new ArrayList<AddressPort>());
+         
          if (initialProxies != null)
          {
             for (AddressPort proxy : initialProxies)
-            {               
-               sendDiscoveryEventToPartition(proxy.address, proxy.port, true);
+            {
+               this.sendDiscoveryEventToPartition(proxy.address, proxy.port, true);
             }
          }
-      }      
+      }
    }
 
    public boolean isProxyHealthOK()
    {
-      if (isMasterNode())
+      if (this.isMasterNode())
       {
          return this.localHandler.isProxyHealthOK();
       }
-      else
-      {
-         GroupRpcResponse result = invokeNoArgGroupRpc("isProxyHealthOK");
-         if (result instanceof BooleanGroupRpcResponse)
-         {
-            return ((BooleanGroupRpcResponse) result).getValue();
-         }
-         else
-         {
-            throw ((ThrowableGroupRpcResponse) result).getValueAsRuntimeException();
-         }
-      }
+
+      GroupRpcResponse response = this.rpcStub.isProxyHealthOK();
+      
+      this.validateResponse(response, false);
+      
+      return ((BooleanGroupRpcResponse) response).getValue();
    }
 
    public void markProxiesInError()
    {
-      recordRequestFailure();
+      this.recordRequestFailure();
       
-      if (isMasterNode())
+      if (this.isMasterNode())
       {
          this.localHandler.markProxiesInError();
       }
       else
       {
-         GroupRpcResponse result = invokeNoArgGroupRpc("markProxiesInError");
-         if (result instanceof ThrowableGroupRpcResponse)
-         {
-            throw ((ThrowableGroupRpcResponse) result).getValueAsRuntimeException();
-         }
+         GroupRpcResponse response = this.rpcStub.markProxiesInError();
+         
+         this.validateResponse(response, false);
       }
    }
 
    public void reset()
    {
-      if (isMasterNode())
+      if (this.isMasterNode())
       {
          this.localHandler.reset();
       }
       else
       {
-         GroupRpcResponse result = invokeNoArgGroupRpc("reset");
-         if (result instanceof ThrowableGroupRpcResponse)
-         {
-            throw ((ThrowableGroupRpcResponse) result).getValueAsRuntimeException();
-         }
+         GroupRpcResponse response = this.rpcStub.reset();
+         
+         this.validateResponse(response, false);
       }
    }
 
-   @SuppressWarnings("unchecked")
    public void sendRequest(MCMPRequest request)
    {
-      if (isMasterNode())
+      if (this.isMasterNode())
       {
          this.localHandler.sendRequest(request);
       }
       else
       {
-         GroupRpcResponse response = null;
-         try
-         {
-            List<Object> rsps = this.partition.callMethodOnCluster(this.haServiceName, "sendRequest", new Object[] { request }, MCMPREQ_TYPES, false, new GroupRpcResponseFilter());
-            response = extractGroupRpcResponse(rsps, "sendRequest");
-         }
-         catch (Exception e)
-         {
-            recordRequestFailure();
-            throw Utils.convertToUnchecked(e);
-         }
+         GroupRpcResponse response = this.rpcStub.sendRequest(request);
          
-         if (response instanceof ThrowableGroupRpcResponse)
-         {
-            recordRequestFailure();
-            throw ((ThrowableGroupRpcResponse) response).getValueAsRuntimeException();
-         }
+         this.validateResponse(response, true);
       }
    }
 
-   @SuppressWarnings("unchecked")
    public void sendRequests(List<MCMPRequest> requests)
    {
-      if (isMasterNode())
+      if (this.isMasterNode())
       {
          this.localHandler.sendRequests(requests);
       }
       else
       {
-         GroupRpcResponse response = null;
-         try
-         {
-            List<Object> rsps = this.partition.callMethodOnCluster(this.haServiceName, "sendRequests", new Object[] { requests }, MCMPREQS_TYPES, false, new GroupRpcResponseFilter());
-            response = extractGroupRpcResponse(rsps, "sendRequests");
-         }
-         catch (Exception e)
-         {
-            recordRequestFailure();
-            throw Utils.convertToUnchecked(e);
-         }
+         GroupRpcResponse response = this.rpcStub.sendRequests(requests);
          
-         if (response instanceof ThrowableGroupRpcResponse)
-         {
-            recordRequestFailure();
-            throw ((ThrowableGroupRpcResponse) response).getValueAsRuntimeException();
-         }
+         this.validateResponse(response, true);
       }
    }
 
+   private void validateResponse(GroupRpcResponse response, boolean recordFailure)
+   {
+      if (response instanceof ThrowableGroupRpcResponse)
+      {
+         if (recordFailure) this.recordRequestFailure();
+         
+         throw ((ThrowableGroupRpcResponse) response).getValueAsRuntimeException();
+      }
+   }
+   
    public void shutdown()
    {
       this.localHandler.shutdown();
@@ -431,95 +405,157 @@
 
    public void status()
    {
-      log.warn(sm.getString("modcluster.error.status.unsupported"));      
+      log.warn(this.sm.getString("modcluster.error.status.unsupported"));
    }
    
    // ----------------------------------------------------------------  Private
    
-   @SuppressWarnings("unchecked")
-   private GroupRpcResponse invokeNoArgGroupRpc(String methodName)
+   private synchronized void sendDiscoveryEventToPartition(InetAddress address, int port, boolean addition)
    {
-      try
+      AddressPort ap = new AddressPort(address, port);
+      MCMPServerDiscoveryEvent event = new MCMPServerDiscoveryEvent(this.partition.getClusterNode(), ap, addition, this.discoveryEventIndex.incrementAndGet());
+      this.pendingDiscoveryEvents.add(event);
+      
+      GroupRpcResponse response = this.rpcStub.mcmpServerDiscoveryEvent(event);
+      
+      if (response instanceof ThrowableGroupRpcResponse)
       {
-         List<Object> rsps = this.partition.callMethodOnCluster(this.haServiceName, methodName, NULL_ARGS, NULL_TYPES, false, new GroupRpcResponseFilter());
-         return extractGroupRpcResponse(rsps, methodName);
+         // Just log it; we'll retry later
+         String msg = addition ? "modcluster.error.discovery.add"
+                               : "modcluster.error.discovery.remove";
+         log.error(this.sm.getString(msg, address.toString(), new Integer(port)), ((ThrowableGroupRpcResponse) response).getValue());
       }
-      catch (Exception e)
+   }
+   
+   void recordRequestFailure()
+   {
+      synchronized (this.errorState)
       {
-         throw Utils.convertToUnchecked(e);
+         if (this.errorState.size() == 0 || this.errorState.get(this.errorState.size() -1).booleanValue())
+         {
+            this.errorState.add(Boolean.FALSE);
+         }
       }
    }
    
-   private GroupRpcResponse extractGroupRpcResponse(List<Object> responses, String methodName)
+   class RpcStub implements ClusteredMCMPHandlerRpcHandler
    {
-      Throwable thrown = null;
-      for (Object obj : responses)
+      /**
+       * @see org.jboss.web.tomcat.service.modcluster.ha.rpc.ClusteredMCMPHandlerRpcHandler#getProxyConfiguration()
+       */
+      public GroupRpcResponse getProxyConfiguration()
       {
-         if (obj instanceof GroupRpcResponse)
+         return this.invokeRpc("getProxyConfiguration");
+      }
+
+      /**
+       * @see org.jboss.web.tomcat.service.modcluster.ha.rpc.ClusteredMCMPHandlerRpcHandler#isProxyHealthOK()
+       */
+      public GroupRpcResponse isProxyHealthOK()
+      {
+         return this.invokeRpc("isProxyHealthOk");
+      }
+
+      /**
+       * @see org.jboss.web.tomcat.service.modcluster.ha.rpc.ClusteredMCMPHandlerRpcHandler#markProxiesInError()
+       */
+      public GroupRpcResponse markProxiesInError()
+      {
+         return this.invokeRpc("markProxiesInError");
+      }
+
+      /**
+       * @see org.jboss.web.tomcat.service.modcluster.ha.rpc.ClusteredMCMPHandlerRpcHandler#mcmpServerDiscoveryEvent(org.jboss.web.tomcat.service.modcluster.ha.rpc.MCMPServerDiscoveryEvent)
+       */
+      public GroupRpcResponse mcmpServerDiscoveryEvent(MCMPServerDiscoveryEvent event)
+      {
+         try
          {
-            return (GroupRpcResponse) obj;
+            return this.invokeRpc("mcmpServerDiscoveryEvent", new Object[] { event }, DISC_EVENT_TYPES);
          }
-         else if (obj instanceof Throwable)
+         catch (Exception e)
          {
-            if (thrown == null) 
-            {
-               thrown = (Throwable) obj;
-            }
+            return new ThrowableGroupRpcResponse(null, e);
          }
-         else 
-         {
-            log.warn(sm.getString("modcluster.error.rpc.unexpected", obj, methodName));
-         }
       }
-      
-      if (thrown != null)
-         throw Utils.convertToUnchecked(thrown);
-         
-      throw new IllegalStateException(sm.getString("modcluster.error.rpc.noresp", methodName));
-   } 
-   
-   @SuppressWarnings("unchecked")
-   private synchronized void sendDiscoveryEventToPartition(InetAddress address, int port, boolean addition)
-   {
-      AddressPort ap = new AddressPort(address, port);
-      MCMPServerDiscoveryEvent event = new MCMPServerDiscoveryEvent(this.partition.getClusterNode(), ap, addition, discoveryEventIndex.incrementAndGet());
-      pendingDiscoveryEvents.add(event);      
-      
-      GroupRpcResponse response = null;
-      Throwable throwable = null;;
-      try
-      {         
-         List<Object> rsps = this.partition.callMethodOnCluster(this.haServiceName, "mcmpServerDiscoveryEvent", new Object[] { event }, DISC_EVENT_TYPES, false, new GroupRpcResponseFilter());
-         response = extractGroupRpcResponse(rsps, "mcmpServerDiscoveryEvent");
+
+      /**
+       * @see org.jboss.web.tomcat.service.modcluster.ha.rpc.ClusteredMCMPHandlerRpcHandler#reset()
+       */
+      public GroupRpcResponse reset()
+      {
+         return this.invokeRpc("reset");
       }
-      catch (Exception e)
+
+      /**
+       * @see org.jboss.web.tomcat.service.modcluster.ha.rpc.ClusteredMCMPHandlerRpcHandler#sendRequest(org.jboss.web.tomcat.service.modcluster.mcmp.MCMPRequest)
+       */
+      public GroupRpcResponse sendRequest(MCMPRequest request)
       {
-         throwable = e;
+         return this.invokeRpc("sendRequest", new Object[] { request }, MCMPREQ_TYPES, true);
       }
+
+      /**
+       * @see org.jboss.web.tomcat.service.modcluster.ha.rpc.ClusteredMCMPHandlerRpcHandler#sendRequests(java.util.List)
+       */
+      public GroupRpcResponse sendRequests(List<MCMPRequest> requests)
+      {
+         return this.invokeRpc("sendRequests", new Object[] { requests }, MCMPREQS_TYPES, true);
+      }
       
-      if (response instanceof ThrowableGroupRpcResponse)
+      private GroupRpcResponse invokeRpc(String methodName)
       {
-         throwable = ((ThrowableGroupRpcResponse) response).getValue();
+         return this.invokeRpc(methodName, NULL_ARGS, NULL_TYPES, false);
       }
       
-      if (throwable != null)
+      private GroupRpcResponse invokeRpc(String methodName, Object[] args, Class<?>[] types, boolean recordFailure)
       {
-         // Just log it; we'll retry later
-         String msg = addition ? "modcluster.error.discovery.add" 
-                               : "modcluster.error.discovery.remove";
-         log.error(sm.getString(msg, address.toString(), port), throwable);
+         try
+         {
+            return this.invokeRpc(methodName, args, types);
+         }
+         catch (Exception e)
+         {
+            if (recordFailure)
+            {
+               ClusteredMCMPHandlerImpl.this.recordRequestFailure();
+            }
+            
+            throw Utils.convertToUnchecked(e);
+         }
+      }
+      
+      private GroupRpcResponse invokeRpc(String methodName, Object[] args, Class<?>[] types) throws Exception
+      {
+         List<?> responses = ClusteredMCMPHandlerImpl.this.partition.callMethodOnCluster(ClusteredMCMPHandlerImpl.this.getHAServiceName(), methodName, args, types, false, new GroupRpcResponseFilter());
          
-      }      
-   }
-   
-   private void recordRequestFailure()
-   {
-      synchronized (errorState)
-      {
-         if (errorState.size() == 0 || errorState.get(errorState.size() -1).booleanValue())
+         Throwable thrown = null;
+         
+         for (Object obj : responses)
          {
-            errorState.add(Boolean.FALSE);
+            if (obj instanceof GroupRpcResponse)
+            {
+               return (GroupRpcResponse) obj;
+            }
+            else if (obj instanceof Throwable)
+            {
+               if (thrown == null)
+               {
+                  thrown = (Throwable) obj;
+               }
+            }
+            else
+            {
+               log.warn(ClusteredMCMPHandlerImpl.this.sm.getString("modcluster.error.rpc.unexpected", obj, methodName));
+            }
          }
+         
+         if (thrown != null)
+         {
+            throw Utils.convertToUnchecked(thrown);
+         }
+            
+         throw new IllegalStateException(ClusteredMCMPHandlerImpl.this.sm.getString("modcluster.error.rpc.noresp", methodName));
       }
    }
 }
\ No newline at end of file

Modified: trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ha/HASingletonAwareResetRequestSource.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ha/HASingletonAwareResetRequestSource.java	2008-08-05 16:13:35 UTC (rev 76669)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ha/HASingletonAwareResetRequestSource.java	2008-08-05 16:17:01 UTC (rev 76670)
@@ -35,20 +35,25 @@
 import org.jboss.web.tomcat.service.modcluster.config.BalancerConfiguration;
 import org.jboss.web.tomcat.service.modcluster.config.NodeConfiguration;
 import org.jboss.web.tomcat.service.modcluster.ha.rpc.ResetRequestGroupRpcResponse;
+import org.jboss.web.tomcat.service.modcluster.ha.rpc.ResetRequestSourceRpcHandler;
 import org.jboss.web.tomcat.service.modcluster.ha.rpc.ThrowableGroupRpcResponse;
 import org.jboss.web.tomcat.service.modcluster.mcmp.MCMPRequest;
 import org.jboss.web.tomcat.service.modcluster.mcmp.MCMPUtils;
 import org.jboss.web.tomcat.service.modcluster.mcmp.ResetRequestSource;
 
 /**
- * {@link ResetRequestSource} that provides different reset requests 
- * depending on whether or not it believes it is running on the singleton 
+ * {@link ResetRequestSource} that provides different reset requests
+ * depending on whether or not it believes it is running on the singleton
  * master.
  * 
  * @author Brian Stansberry
  */
 public class HASingletonAwareResetRequestSource implements ResetRequestSource
 {
+   static final String METHOD_NAME = "getResetRequests";
+   static final Object[] ARGS = new Object[0];
+   static final Class<?>[] TYPES = new Class[0];
+   
    private static final Logger log = Logger.getLogger(HASingletonAwareResetRequestSource.class);
    
    /**
@@ -58,8 +63,7 @@
    
    private final NodeConfiguration nodeConfig;
    private final BalancerConfiguration balancerConfig;
-   private final HAPartition partition;
-   private final String haServiceName;
+   private final ResetRequestSourceRpcHandler<List<?>> rpcStub;
    private volatile boolean master;
    private volatile Server jbossWebServer;
    
@@ -67,23 +71,19 @@
    {
       this.nodeConfig = nodeConfig;
       this.balancerConfig = balancerConfig;
-      this.partition = partition;
-      this.haServiceName = haServiceName;
+      this.rpcStub = new RpcStub(partition, haServiceName);
    }
    
-   @SuppressWarnings("unchecked")
-   public List<MCMPRequest> getResetRequests()   
+   public List<MCMPRequest> getResetRequests()
    {
       if (this.master)
       {
-         List<MCMPRequest> resets = getLocalResetRequests();
-         addRemoteRequests(resets);
+         List<MCMPRequest> resets = this.getLocalResetRequests();
+         this.addRemoteRequests(resets);
          return resets;
       }
-      else
-      {
-         return Collections.EMPTY_LIST;
-      }
+
+      return Collections.emptyList();
    }
 
    public List<MCMPRequest> getLocalResetRequests()
@@ -113,16 +113,7 @@
    
    private void addRemoteRequests(List<MCMPRequest> resets)
    {
-      List responses = null;
-      try
-      {
-         responses = this.partition.callMethodOnCluster(this.haServiceName, "getResetRequests", new Object[]{}, new Class[]{}, true);
-      }
-      catch (Exception e)
-      {
-         //FIXME what to do?
-         throw Utils.convertToUnchecked(e);
-      }
+      List<?> responses = this.rpcStub.getResetRequests();
       
       for (Object response : responses)
       {
@@ -134,19 +125,45 @@
          {
             ThrowableGroupRpcResponse tgrr = (ThrowableGroupRpcResponse) response;
             //FIXME what to do?
-            log.warn(sm.getString("modcluster.error.rpc.known", "getResetRequests", tgrr.getSender()), tgrr.getValue());
+            log.warn(this.sm.getString("modcluster.error.rpc.known", METHOD_NAME, tgrr.getSender()), tgrr.getValue());
          }
          else if (response instanceof Throwable)
          {
-            log.warn(sm.getString("modcluster.error.rpc.unknown", "getResetRequests"), (Throwable) response);
+            log.warn(this.sm.getString("modcluster.error.rpc.unknown", METHOD_NAME), (Throwable) response);
          }
          else
          {
-            log.error(sm.getString("modcluster.error.rpc.unexpected", response, "getResetRequests"));
+            log.error(this.sm.getString("modcluster.error.rpc.unexpected", response, METHOD_NAME));
          }
          
       }
+   }
+
+   private class RpcStub implements ResetRequestSourceRpcHandler<List<?>>
+   {
+      private final HAPartition partition;
+      private final String haServiceName;
       
+      public RpcStub(HAPartition partition, String haServiceName)
+      {
+         this.partition = partition;
+         this.haServiceName = haServiceName;
+      }
+      
+      /**
+       * @see org.jboss.web.tomcat.service.modcluster.ha.rpc.ResetRequestSourceRpcHandler#getResetRequests()
+       */
+      public List<?> getResetRequests()
+      {
+         try
+         {
+            return this.partition.callMethodOnCluster(this.haServiceName, METHOD_NAME, ARGS, TYPES, true);
+         }
+         catch (Exception e)
+         {
+            //FIXME what to do?
+            throw Utils.convertToUnchecked(e);
+         }
+      }
    }
-
 }

Modified: trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ha/ModClusterServiceDRMEntry.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ha/ModClusterServiceDRMEntry.java	2008-08-05 16:13:35 UTC (rev 76669)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ha/ModClusterServiceDRMEntry.java	2008-08-05 16:17:01 UTC (rev 76670)
@@ -41,6 +41,7 @@
    private static final long serialVersionUID = 8275232749243297786L;
    
    private final ClusterNode peer;
+   private final String domain;
    private final Set<MCMPServerState> mcmpServerStates;
    private final Integer healthyEstablishedCount;
    private final Integer establishedCount;
@@ -48,11 +49,12 @@
    private final Integer knownCount;
    private final Set<String> jvmRoutes = new HashSet<String>();
 
-   public ModClusterServiceDRMEntry(ClusterNode peer, Set<MCMPServerState> mcmpServerStates)
+   public ModClusterServiceDRMEntry(ClusterNode peer, String domain, Set<MCMPServerState> mcmpServerStates)
    {
       assert peer != null : "peer is null";
       
       this.peer = peer;
+      this.domain = domain;
       this.mcmpServerStates = mcmpServerStates;
       
       int healthyEstablished = 0;
@@ -92,6 +94,11 @@
       return this.peer;
    }
 
+   public String getDomain()
+   {
+      return this.domain;
+   }
+   
    public Set<MCMPServerState> getMCMPServerStates()
    {
       return this.mcmpServerStates;
@@ -99,26 +106,26 @@
    
    public Set<String> getJvmRoutes()
    {
-      synchronized (jvmRoutes)
+      synchronized (this.jvmRoutes)
       {
-         return new HashSet<String>(jvmRoutes);
+         return new HashSet<String>(this.jvmRoutes);
       }
    }
    
    public void addJvmRoute(String jvmRoute)
    {
-      synchronized (jvmRoutes)
+      synchronized (this.jvmRoutes)
       {
-         jvmRoutes.add(jvmRoute);
-      }      
+         this.jvmRoutes.add(jvmRoute);
+      }
    }
    
    public void removeJvmRoute(String jvmRoute)
    {
-      synchronized (jvmRoutes)
+      synchronized (this.jvmRoutes)
       {
-         jvmRoutes.remove(jvmRoute);
-      }      
+         this.jvmRoutes.remove(jvmRoute);
+      }
    }
 
    public int compareTo(ModClusterServiceDRMEntry other)
@@ -144,14 +151,17 @@
    public boolean equals(Object obj)
    {
       if (this == obj)
+      {
          return true;
+      }
       
       if (obj instanceof ModClusterServiceDRMEntry)
       {
          ModClusterServiceDRMEntry other = (ModClusterServiceDRMEntry) obj;
-         return (this.peer.equals(other.peer) 
-                   && safeEquals(this.mcmpServerStates, other.mcmpServerStates)
-                   && safeEquals(this.jvmRoutes, other.jvmRoutes));
+         return (this.peer.equals(other.peer)
+                   && this.safeEquals(this.domain, other.domain)
+                   && this.safeEquals(this.mcmpServerStates, other.mcmpServerStates)
+                   && this.safeEquals(this.jvmRoutes, other.jvmRoutes));
       }
       return false;
    }
@@ -160,6 +170,7 @@
    public int hashCode()
    {
       int result = 17;
+      result += 23 * (this.domain == null ? 0 : this.domain.hashCode());
       result += 23 * this.peer.hashCode();
       result += 23 * (this.mcmpServerStates == null ? 0 : this.mcmpServerStates.hashCode());
       result += 23 * (this.jvmRoutes == null ? 0 : this.jvmRoutes.hashCode());
@@ -169,8 +180,8 @@
    @Override
    public String toString()
    {
-      return new StringBuilder(getClass().getName())
-                     .append("{peer=").append(peer).append("}").toString();
+      return new StringBuilder(this.getClass().getName())
+                     .append("{peer=").append(this.peer).append(",domain=").append(this.domain).append("}").toString();
    }
 
    private boolean safeEquals(Object a, Object b)

Deleted: trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ha/ModClusterServiceHASingletonElectionPolicy.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ha/ModClusterServiceHASingletonElectionPolicy.java	2008-08-05 16:13:35 UTC (rev 76669)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ha/ModClusterServiceHASingletonElectionPolicy.java	2008-08-05 16:17:01 UTC (rev 76670)
@@ -1,116 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2008, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-
-package org.jboss.web.tomcat.service.modcluster.ha;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-import org.jboss.ha.framework.interfaces.ClusterNode;
-import org.jboss.ha.singleton.HASingletonElectionPolicy;
-import org.jboss.ha.singleton.HASingletonElectionPolicyBase;
-import org.jboss.ha.singleton.HASingletonElector;
-
-/**
- * {@link HASingletonElectionPolicy} that factors the ability to communicate
- * with proxy servers in its election decision.
- * 
- * @author Brian Stansberry
- */
-public class ModClusterServiceHASingletonElectionPolicy extends HASingletonElectionPolicyBase
-{
-   private final HASingletonElector delegate;
-   
-   
-   public ModClusterServiceHASingletonElectionPolicy(HASingletonElector delegate)
-   {
-      this.delegate = delegate;
-   }
-   
-   @Override
-   protected ClusterNode elect(List<ClusterNode> candidates)
-   {
-      if (candidates == null)
-         return null;
-      
-      if (candidates.size() == 1)
-         return candidates.get(0);
-      
-      return delegate.elect(candidates);
-   }
-   
-   @Override
-   @SuppressWarnings("unchecked")
-   protected List<ClusterNode> getCandidates()
-   {
-      List<ModClusterServiceDRMEntry> candidates = getHAPartition().getDistributedReplicantManager().lookupReplicants(getSingletonName());
-      return narrowCandidateList(candidates);
-   }
-   
-   /**
-    * Processes the candidate list, discarding those who don't match the best
-    * candidate when it comes to the ability to communicate with proxies.
-    * 
-    * @param candidates the universe of possible candidates.
-    * @return a list of candidates with an equivalent ability to communicate 
-    *         with proxies, or <code>null</code> if <code>candidates</code>
-    *         is <code>null</code>.
-    */
-   public List<ClusterNode> narrowCandidateList(Collection<ModClusterServiceDRMEntry> candidates)
-   {
-      if (candidates == null)
-            return null;
-      
-      List<ClusterNode> narrowed = new ArrayList<ClusterNode>();
-      ModClusterServiceDRMEntry champion = null;
-      
-      for (ModClusterServiceDRMEntry candidate : candidates)
-      {
-         if (champion == null)
-         {
-            champion = candidate;
-            narrowed.add(candidate.getPeer());
-         }
-         else
-         {
-            int compFactor = candidate.compareTo(champion);
-            if (compFactor < 0)
-            {
-               // New champ
-               narrowed.clear();
-               champion = candidate;
-               narrowed.add(candidate.getPeer());
-            }
-            else if (compFactor == 0)
-            {
-               // As good as our champ
-               narrowed.add(candidate.getPeer());
-            }            
-            // else candidate didn't make the cut; continue
-         }
-      }
-      
-      return narrowed;
-   }
-
-}

Added: trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ha/rpc/ClusteredMCMPHandlerRpcHandler.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ha/rpc/ClusteredMCMPHandlerRpcHandler.java	                        (rev 0)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ha/rpc/ClusteredMCMPHandlerRpcHandler.java	2008-08-05 16:17:01 UTC (rev 76670)
@@ -0,0 +1,47 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.web.tomcat.service.modcluster.ha.rpc;
+
+import java.util.List;
+
+import org.jboss.web.tomcat.service.modcluster.mcmp.MCMPRequest;
+
+/**
+ * @author Paul Ferraro
+ *
+ */
+public interface ClusteredMCMPHandlerRpcHandler
+{
+   GroupRpcResponse sendRequest(MCMPRequest request);
+   
+   GroupRpcResponse sendRequests(List<MCMPRequest> requests);
+   
+   GroupRpcResponse mcmpServerDiscoveryEvent(MCMPServerDiscoveryEvent event);
+   
+   GroupRpcResponse getProxyConfiguration();
+
+   GroupRpcResponse isProxyHealthOK();
+
+   GroupRpcResponse markProxiesInError();
+
+   GroupRpcResponse reset();
+}

Added: trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ha/rpc/ModClusterServiceRpcHandler.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ha/rpc/ModClusterServiceRpcHandler.java	                        (rev 0)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ha/rpc/ModClusterServiceRpcHandler.java	2008-08-05 16:17:01 UTC (rev 76670)
@@ -0,0 +1,43 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.web.tomcat.service.modcluster.ha.rpc;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.jboss.ha.framework.interfaces.ClusterNode;
+import org.jboss.ha.framework.server.HAServiceEvent;
+import org.jboss.ha.framework.server.HAServiceRpcHandler;
+import org.jboss.web.tomcat.service.modcluster.mcmp.MCMPServer;
+
+/**
+ * @author Paul Ferraro
+ *
+ */
+public interface ModClusterServiceRpcHandler<T, S extends MCMPServer> extends HAServiceRpcHandler<HAServiceEvent>
+{
+   void stopOldMaster(String domain);
+   
+   void clusterStatusComplete(Map<ClusterNode, PeerMCMPDiscoveryStatus> statuses);
+   
+   T getClusterCoordinatorState(Set<S> masterList);
+}

Modified: trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ha/rpc/PeerMCMPDiscoveryStatus.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ha/rpc/PeerMCMPDiscoveryStatus.java	2008-08-05 16:13:35 UTC (rev 76669)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ha/rpc/PeerMCMPDiscoveryStatus.java	2008-08-05 16:17:01 UTC (rev 76670)
@@ -51,10 +51,10 @@
     *                         not be obtained for the peer.
     * @param latestDiscoveryEvent most recent discovery event received from the peer
     */
-   public PeerMCMPDiscoveryStatus(ClusterNode peer, Set<MCMPServerState> mcmpServerStates, 
+   public PeerMCMPDiscoveryStatus(ClusterNode peer, String domain, Set<MCMPServerState> mcmpServerStates, 
                              MCMPServerDiscoveryEvent latestDiscoveryEvent)
    {
-      super(peer, mcmpServerStates);
+      super(peer, domain, mcmpServerStates);
       this.latestDiscoveryEvent = latestDiscoveryEvent;
    }
 

Added: trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ha/rpc/ResetRequestSourceRpcHandler.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ha/rpc/ResetRequestSourceRpcHandler.java	                        (rev 0)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/modcluster/ha/rpc/ResetRequestSourceRpcHandler.java	2008-08-05 16:17:01 UTC (rev 76670)
@@ -0,0 +1,32 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.web.tomcat.service.modcluster.ha.rpc;
+
+
+/**
+ * @author Paul Ferraro
+ *
+ */
+public interface ResetRequestSourceRpcHandler<T>
+{
+   T getResetRequests();
+}




More information about the jboss-cvs-commits mailing list