Singleton MBean for Clustering
monocongo Jul 23, 2004 1:31 PMI am currently trying the approach to Singleton MBeans for clustering suggested in the JBoss Clustering article by Ivelin Ivanov at http://www.onjava.com/pub/a/onjava/2003/08/20/jboss_clustering.html, however there is not enough information in the article -- and I am still working on this approach. I have modified a singleton class to be a singleton MBean as described but as yet I am having trouble with the JBoss not being able to start the service, with complaints of a nested throwable and an method not being available in the singleton class:
12:38:51,141 ERROR [URLDeploymentScanner] Incomplete Deployment listing: Incompletely deployed packages: org.jboss.deployment.DeploymentInfo@7d7cded7 { url=file:/C:/jboss-3.2.5/server/all/farm/cluster-examples-service.xml } deployer: org.jboss.deployment.SARDeployer@10a2d64 status: Deployment FAILED reason: create operation failed for package file:/C:/jboss-3.2.5/server/all/farm/cluster-examples-service.xml; - nested throwable: (org.jboss.deployment.DeploymentException: com.harborsideplus.grover.mbean.AllUserMessagesSingleton.<init>(); - nested throwable: (java.lang.NoSuchMethodException: com.harborsideplus.grover.mbean.AllUserMessagesSingleton.<init>())) state: FAILED watch: file:/C:/jboss-3.2.5/server/all/farm/cluster-examples-service.xml
I have modified the singleton to be a MBean as described in the article, the MBean and interfaces are listed below:
// ---------- All UserMessagesSingletonMBean interface ---------------- package com.harborsideplus.grover.mbean; import com.harborsideplus.grover.util.UserMessages; /** * @author James Adams * */ public interface AllUserMessagesSingletonMBean { //================================================================================ // managed MBean operations, which control the lifecycle of the singleton service //================================================================================ public void startSingleton (); public void stopSingleton (); //================================================================================ // exposed methods //================================================================================ /** * * @return */ public boolean isMasterNode (); /** * Get the user's messages beginning at the specified index. * * @param userId * @param index * @return */ public UserMessages getUserMessages (String userId, int index); /** * Add a message for the specified user. If the specified user doesn't already * have a UserMessages list then one will be initialized before adding the message. * * @param userId * @param message */ public void addMessage (String userId, String message); /** * Get the number of messages for the specified user. * @param userId * @return */ public int getNumberOfUserMessages (String userId); } //----------- AllUserMessagesSingleton class --------------------- package com.harborsideplus.grover.mbean; import java.util.ArrayList; import java.util.Enumeration; import java.util.Hashtable; import com.harborsideplus.grover.util.UserMessages; /** * @author James Adams * */ public class AllUserMessagesSingleton implements AllUserMessagesSingletonMBean { // reference to the singleton private static AllUserMessagesSingleton m_reference; // hashtable of UserMessages private Hashtable m_userMessagesTable; // flag showing whether or not running on master node private boolean m_isMasterNode; //================================================================================ // managed MBean operations, which control the lifecycle of the singleton service //================================================================================ /** * */ public void startSingleton () { m_isMasterNode = true; } /** * */ public void stopSingleton () { m_isMasterNode = false; } //============================================================= // Singleton-related methods //============================================================= /** * Constructor method which is private to insure that the class can't be instantiated. * A reference to an object of the class must be obtained via the getIOIMessagesBean() method. * */ private AllUserMessagesSingleton () { // initialize the ArrayList m_userMessagesTable = new Hashtable(); } /** * Method used to obtain a reference to the object. * * @return reference to the singleton object */ public static synchronized AllUserMessagesSingleton getReference () { // if the reference hasn't already been created then instantiate an object if (m_reference == null) { // call the constructor m_reference = new AllUserMessagesSingleton(); } // return our reference return m_reference; } /** * Method provided in order to prevent cloning of the object. The method always throws an * exception to indicate that cloning is not supported by this class. * * @return never returns anything * @throws CloneNotSupportedException to inicate that cloning is not supported by this class */ public Object clone () throws CloneNotSupportedException { // do not allow cloning - throw an exception throw new CloneNotSupportedException(); } //====================================================================== // Public methods //====================================================================== /** * */ public boolean isMasterNode () { return m_isMasterNode; } /** * Get the UserMessages for the specified user. * * @param userId * @return */ /* public UserMessages getUserMessages (String userId) { // handle null keys if (userId == null) { return null; } // return the corresponding UserMessages, or null if it doesn't exist return (UserMessages) m_userMessagesTable.get(userId); } */ /** * Get the UserMessages for the specified user, from the specified index to the end. * * @param userId * @param index * @return */ public UserMessages getUserMessages (String userId, int index) { // handle bad parameters if ((userId == null) || (index < 0)) { return null; } // get the UserMessages for the specified user UserMessages userMessages = (UserMessages) m_userMessagesTable.get(userId); if (userMessages != null) { // if the index is past the range then return null if (index > userMessages.getLastIndex()) { return null; } // if the index is zero then we want the entire thing -- no need to get a subset else if (index == 0) { return userMessages; } // return a subset of the original messages else { // index is within range - copy the messages from the index // to the end into a new UserMessages object and return it // create the new UserMessages we'll return UserMessages newUserMessages = new UserMessages(userId); // loop over the original messages, copying them into the new messages object for (int i = index; i <= userMessages.getLastIndex(); i++) { newUserMessages.addMessage(userMessages.getMessage(i)); } // return the messages return newUserMessages; } } else { // no messages were found for the specified user return null; } } /** * Add a message for the specified user. If the specified user doesn't already * have a UserMessages list then one will be initialized before adding the message. * * @param userId * @param message */ public void addMessage (String userId, String message) { // either add to an existing list or create one first before adding to it if (m_userMessagesTable.containsKey(userId)) { // get the existing UserMessages for this user UserMessages userMessages = (UserMessages) m_userMessagesTable.get(userId); // add the message to the list userMessages.addMessage(message); } else { // create a UserMessages for this user UserMessages userMessages = new UserMessages(userId); // add the message to the list userMessages.addMessage(message); // add the user messages list to the hash m_userMessagesTable.put(userId, userMessages); } } /** * Get the number of messages for the specified user. * @param userId * @return */ public int getNumberOfUserMessages (String userId) { if (m_userMessagesTable.containsKey(userId)) { return ((UserMessages) m_userMessagesTable.get(userId)).size(); } else { return 0; } } }
The MBean classes are being included with my application's EJB Jar file which is part of the EAR file which is deployed in the JBOSS_HOME/server/all/deploy directory.
I have modified JBOSS_HOME/server/all/farm/cluster-examples-service.xml by adding the following entry:
<!-- ===================================================== --> <!-- This MBean is an example of a cluster Singleton --> <!-- ===================================================== --> <mbean code="com.harborsideplus.grover.mbean.AllUserMessagesSingleton" name="grover.mbean:service=AllUserMessagesSingleton"> </mbean> <!-- ===================================================== --> <!-- | This is a singleton controller which works similarly to the --> <!-- | SchedulerProvider (when a MBean target is used) --> <!-- ===================================================== --> <mbean code="org.jboss.ha.singleton.HASingletonController" name="jboss:service=HASingletonController"> <depends>jboss:service=DefaultPartition</depends> <depends>grover.mbean:service=AllUserMessagesSingleton</depends> <attribute name="TargetName">grover.mbean:service=AllUserMessagesSingleton</attribute> <attribute name="TargetStartMethod">startSingleton</attribute> <attribute name="TargetStopMethod">stopSingleton</attribute> </mbean>
Any suggestions as to what I am doing wrong ? Thanks in advance for any ideas, feedback, etc.
-James