FileDocCategorySizeDatePackage
HAServiceMBeanSupport.javaAPI DocJBoss 4.2.116229Fri Jul 13 20:52:38 BST 2007org.jboss.ha.jmx

HAServiceMBeanSupport

public class HAServiceMBeanSupport extends org.jboss.system.ServiceMBeanSupport implements HAServiceMBean
Management Bean for an HA-Service. Provides a convenient common base for cluster symmetric MBeans. This class is also a user transparent extension of the standard NotificationBroadcasterSupport to a clustered environment. Listeners register with their local broadcaster. Invoking sendNotification() on any broadcaster, 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 *
version
$Revision: 57188 $

Fields Summary
private org.jboss.ha.framework.interfaces.HAPartition
partition_
private org.jboss.ha.framework.server.ClusterPartitionMBean
clusterPartition
private String
partitionName
private DistributedReplicantManager.ReplicantListener
drmListener
private String
REPLICANT_TOKEN
DRM participation TOKEN
private boolean
sendLocalLifecycleNotifications
private boolean
sendRemoteLifecycleNotifications
Constructors Summary
public HAServiceMBeanSupport()

   
   // Public --------------------------------------------------------

    
   
      // for JMX
   
Methods Summary
public void_receiveRemoteNotification(javax.management.Notification notification)
Invoked by remote broadcasters. Delegates to the super class

      super.sendNotification(notification);
   
protected voidcallAsyncMethodOnPartition(java.lang.String methodName, java.lang.Object[] args, java.lang.Class[] types)

      HAPartition partition = getPartition();
      if (partition != null)
      {
         getPartition().callAsynchMethodOnCluster(
            getServiceHAName(),
            methodName,
            args, types,
            true);
      }
   
public voidcallMethodOnPartition(java.lang.String methodName, java.lang.Object[] args)

param
methodName
param
args
throws
Exception
deprecated
Use {@link #callMethodOnPartition(String, Object[], Class[])} instead

      getPartition().callMethodOnCluster(
         getServiceHAName(),
         methodName,
         args,
         true);
   
public voidcallMethodOnPartition(java.lang.String methodName, java.lang.Object[] args, java.lang.Class[] types)

      getPartition().callMethodOnCluster(
         getServiceHAName(),
         methodName,
         args, types,
         true);
   
protected org.jboss.ha.framework.interfaces.HAPartitionfindHAPartitionWithName(java.lang.String name)

      log.debug("findHAPartitionWithName, name="+name);
      HAPartition result = null;
      QueryExp classEQ = Query.eq(Query.classattr(),
               Query.value(ClusterPartition.class.getName()));
      QueryExp matchPartitionName = Query.match(Query.attr("PartitionName"),
         Query.value(name));
      QueryExp exp = Query.and(classEQ, matchPartitionName);
      Set mbeans = this.getServer().queryMBeans(null, exp);
      if (mbeans != null && mbeans.size() > 0)
      {
         ObjectInstance inst = (ObjectInstance) (mbeans.iterator().next());
         ClusterPartitionMBean cp =
            (ClusterPartitionMBean) MBeanProxyExt.create(
               ClusterPartitionMBean.class,
               inst.getObjectName(),
               this.getServer());
         result = cp.getHAPartition();
      }

      if( result == null )
      {
         String msg = "Failed to find HAPartition with PartitionName="+name;
         throw new InstanceNotFoundException(msg);
      }
      return result;
   
public org.jboss.ha.framework.server.ClusterPartitionMBeangetClusterPartition()

      return clusterPartition;
   
public java.io.SerializablegetDistributedState(java.lang.String key)
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

      DistributedState ds = getPartition().getDistributedStateService();
      return ds.get(getServiceHAName(), key);
   
public org.jboss.ha.framework.interfaces.HAPartitiongetPartition()

      return partition_;
   
public java.lang.StringgetPartitionName()

      return partitionName;
   
public booleangetSendLocalLifecycleNotifications()
Gets whether JMX Notifications should be sent to local (same JVM) listeners if the notification is for an attribute change to attribute "State".

Default is true.

see
#sendNotification(Notification)

      return sendLocalLifecycleNotifications;
   
public booleangetSendRemoteLifecycleNotifications()
Gets whether JMX Notifications should be sent to remote listeners if the notification is for an attribute change to attribute "State".

Default is true.

See http://jira.jboss.com/jira/browse/JBAS-3194 for an example of a use case where this property should be set to false.

see
#sendNotification(Notification)

      return sendRemoteLifecycleNotifications;
   
public java.lang.StringgetServiceHAName()
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

      return getServiceName().getCanonicalName();
   
protected booleanisDRMMasterReplica()

      DistributedReplicantManager drm =
         getPartition().getDistributedReplicantManager();

      return drm.isMasterReplica(getServiceHAName());
   
private booleanisStateChangeNotification(javax.management.Notification notification)

      boolean stateChange = false;
      if (notification instanceof AttributeChangeNotification)
      {
         stateChange = "State".equals(((AttributeChangeNotification) notification).getAttributeName());
      }
      return stateChange;
   
public voidpartitionTopologyChanged(java.util.List newReplicants, int newReplicantsViewId)

      boolean debug = log.isDebugEnabled();

      if (debug)
      {
         log.debug("partitionTopologyChanged(). cluster view id: " + newReplicantsViewId);
      }
   
protected voidregisterDRMListener()

      DistributedReplicantManager drm =
         this.partition_.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)
         {
            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);
               }
            }
         }
      };
      drm.registerListener(getServiceHAName(), drmListener);

      // this ensures that the DRM knows that this node has the MBean deployed 
      drm.add(getServiceHAName(), REPLICANT_TOKEN);
   
protected voidregisterRPCHandler()

      partition_.registerRPCHandler(getServiceHAName(), this);
   
public voidsendNotification(javax.management.Notification notification)
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)

      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);
      }
   
protected voidsendNotificationRemote(javax.management.Notification notification)
Broadcast a notifcation remotely to the partition participants

param
notification

      callAsyncMethodOnPartition("_receiveRemoteNotification",
                                 new Object[]{notification}, new Class[]{Notification.class});
   
protected voidsendNotificationToLocalListeners(javax.management.Notification notification)

      super.sendNotification(notification);
   
public voidsetClusterPartition(org.jboss.ha.framework.server.ClusterPartitionMBean clusterPartition)

      if ((getState() != STARTED) && (getState() != STARTING))
      {         
         this.clusterPartition = clusterPartition;
      }
   
public voidsetDistributedState(java.lang.String key, java.io.Serializable value)
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

      DistributedState ds = getPartition().getDistributedStateService();
      ds.set(getServiceHAName(), key, value);
   
public voidsetPartitionName(java.lang.String newPartitionName)

      if ((getState() != STARTED) && (getState() != STARTING))
      {
         partitionName = newPartitionName;
      }
   
public voidsetSendLocalLifecycleNotifications(boolean sendLocalLifecycleNotifications)
Sets whether JMX Notifications should be sent to local (same JVM) listeners if the notification is for an attribute change to attribute "State".

Default is true.

see
#sendNotification(Notification)

      this.sendLocalLifecycleNotifications = sendLocalLifecycleNotifications;
   
public voidsetSendRemoteLifecycleNotifications(boolean sendRemoteLifecycleNotifications)
Sets whether JMX Notifications should be sent to remote listeners if the notification is for an attribute change to attribute "State".

Default is true.

See http://jira.jboss.com/jira/browse/JBAS-3194 for an example of a use case where this property should be set to false.

see
#sendNotification(Notification)

      this.sendRemoteLifecycleNotifications = sendRemoteLifecycleNotifications;
   
protected voidsetupPartition()

      // get handle to the cluster partition
      if (clusterPartition == null)
      {
         String pName = getPartitionName();
         partition_ = findHAPartitionWithName(pName);
      }
      else
      {
         partition_ = clusterPartition.getHAPartition();
         partitionName = partition_.getPartitionName();
      }
   
protected voidstartService()

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().

Attention: Always call this method when you overwrite it in a subclass because it elects the master singleton node.

      boolean debug = log.isDebugEnabled();
      if (debug)
         log.debug("start HAServiceMBeanSupport");

      setupPartition();

      registerRPCHandler();

      registerDRMListener();
   
protected voidstopService()

Attention: Always call this method when you overwrite it in a subclass

      boolean debug = log.isDebugEnabled();
      if (debug)
         log.debug("stop HAServiceMBeanSupport");

      unregisterDRMListener();

      unregisterRPCHandler();
   
protected voidunregisterDRMListener()

      DistributedReplicantManager drm =
         this.partition_.getDistributedReplicantManager();

      // remove replicant node  
      drm.remove(getServiceHAName());

      // unregister 
      drm.unregisterListener(getServiceHAName(), drmListener);
   
protected voidunregisterRPCHandler()

      partition_.unregisterRPCHandler(getServiceHAName(), this);