J2EE Clustering with JBoss
Pages: 1, 2, 3
Maybe a picture will help. Here is a screenshot of the client MBean attributes:

Figure 5. HANotification Client Attributes
The first attribute points to the name of the cluster notification
broadcaster to which we will subscribe. The next attribute of interest is
ReceivedNotifications. When a message is sent to any deployed
instance of the broadcaster MBean on any of the partition nodes, it will be
received and listed in the Value column for this attribute. In the
screenshot above, there are two received notifications, iivanov2
and mau. Even though it is not obvious from the picture, one of
these messages was received from a remote host.
Now, a screenshot of the MBean operation of interest:

Figure 6. HANotification client operation
The name is not very friendly, but it is distinct and will do for this
example. When this operation is invoked with a text message as its argument,
the value will appear in the ReceivedNotification attribute on
each of the client MBeans deployed in the same partition.
Let's look at the code of the client MBean to see that it is actually straightforward. I made an attempt to annotate the code and keep it simple, so that there is no need for additional analysis.
public class HANotificationBroadcasterClientExample
extends ServiceMBeanSupport
implements HANotificationBroadcasterClientExampleMBean, NotificationListener
{
/**
*
* On service start, subscribes to notification sent by this broadcaster or
* its remote peers.
*
*/
protected void startService() throws Exception
{
super.startService();
addHANotificationListener(this);
}
/**
*
* On service stop, unsubscribes to notification sent by this broadcaster or
* its remote peers.
*
*/
protected void stopService() throws Exception
{
removeHANotificationListener(this);
super.stopService();
}
/**
* Broadcasts a notification to the cluster partition.
*
* This example does not ensure that a notification sequence number
* is unique throughout the partition.
*
*/
public void sendTextMessageViaHANBExample(String message)
throws InstanceNotFoundException, MBeanException, ReflectionException
{
long now = System.currentTimeMillis();
Notification notification =
new Notification(
"hanotification.example.counter",
super.getServiceName(),
now,
now,
message);
server.invoke(
broadcasterName_,
"sendNotification",
new Object[] { notification },
new String[] { Notification.class.getName() }
);
}
/**
* Lists the notifications received on the cluster partition
*/
public Collection getReceivedNotifications()
{
return messages_;
}
/**
* @return the name of the broadcaster MBean
*/
public String getHANotificationBroadcasterName()
{
return broadcasterName_ == null ? null : broadcasterName_.toString();
}
/**
*
* Sets the name of the broadcaster MBean.
*
* @param
*/
public void setHANotificationBroadcasterName(String newBroadcasterName)
throws InvalidParameterException
{
if (newBroadcasterName == null)
{
throw new InvalidParameterException("Broadcaster MBean must be specified");
}
try
{
broadcasterName_ = new ObjectName(newBroadcasterName);
}
catch (MalformedObjectNameException mone)
{
log.error("Broadcaster MBean Object Name is malformed", mone);
throw new InvalidParameterException("Broadcaster MBean is not correctly formatted");
}
}
protected void addHANotificationListener(NotificationListener listener)
throws InstanceNotFoundException
{
server.addNotificationListener(broadcasterName_, listener,
/* no need for filter */ null,
/* no handback object */ null);
}
protected void removeHANotificationListener(NotificationListener listener)
throws InstanceNotFoundException, ListenerNotFoundException
{
server.removeNotificationListener(broadcasterName_, listener);
}
public void handleNotification(
Notification notification,
java.lang.Object handback)
{
messages_.add(notification.getMessage());
}
// Attributes ----------------------------------------------
Collection messages_ = new LinkedList();
/**
* The broadcaster MBean that this class listens to and delegates HA notifications to
*/
ObjectName broadcasterName_ = null;
}
The key points of the code are highlighted. Notice how subscription to the cluster broadcaster is accomplished via the MBean server API.
It is also important to note that the subscription is local. Both the
client and the MBean server reside in the same VM. The
sendNotification() invocation is also local to the VM. The cluster
broadcaster hides the implementation details of working together with its
remote peers to deliver notifications throughout all nodes.
If you aren't too concerned with dependencies on JBoss-specific classes, you can directly extend the cluster broadcaster class, in which case all method calls will be direct instead of proxied through the MBean Server. Here is the code for an extended broadcaster:
public class HANotificationBroadcasterExample
extends HAServiceMBeanSupport
implements HANotificationBroadcasterExampleMBean
{
/**
*
* On service start, subscribes to notification sent by this broadcaster or
* its remote peers.
*
*/
protected void startService() throws Exception
{
super.startService();
addNotificationListener(listener_, /* no need for filter */ null, /* no handback object */ null);
}
/**
*
* On service stop, unsubscribes to notification sent by this broadcaster or
* its remote peers.
*
*/
protected void stopService() throws Exception
{
removeNotificationListener(listener_);
super.stopService();
}
/**
* Broadcasts a notification to the cluster partition.
*
* This example does not ensure that a notification sequence number
* is unique throughout the partition.
*
*/
public void sendTextMessage(String message)
{
long now = System.currentTimeMillis();
Notification notification =
new Notification("hanotification.example.counter", super.getServiceName(), now, now, message);
sendNotification(notification);
}
/**
* Lists the notifications received on the cluster partition
*/
public Collection getReceivedNotifications()
{
return messages_;
}
Collection messages_ = new LinkedList();
NotificationListener listener_ = new NotificationListener()
{
public void handleNotification(Notification notification,
java.lang.Object handback)
{
messages_.add( notification.getMessage() );
}
};
}
This class behaves similarly to the previous one. If you examine its MBean
View in the JMX console, you will notice that it has the same
ReceivedNotifications attribute. The messaging operation is called
sendTextMessage().
Conclusion
This text shows more examples where clustering is both powerful and complex. Fortunately, JBoss eliminates much of the complexity, allowing developers to enjoy the benefits of high availability. Writing singleton services in a distributed environment with JBoss is almost as easy as writing single VM singletons. If you previously invested in the JBoss Scheduler for a standalone server environment, you can keep your code and make it automatically valid in a clustered environment. Finally, lightweight notifications are no longer the prerogative of standalone applications. JBoss cluster notifications are yet another step towards practical horizontal scalability.
Ivelin Ivanov is a frequent contributor to the open source community and has recently participated in projects that include Apache Cocoon, JBoss, GNU XQuery and Jakarta Commons.
Return to ONJava.com.