Developing custom MBeans to manage J2EE Applications (Part IV)

Part III was intended to be the final blog entry in this serie of blogs, that demonstrate how to add management capability to our own application using JMX MBeans. However I received several requests regarding notification supports and how it could be added to the sample code we developed so far. This last entry will demonstrate just that. Below is a quick reminder of what we have done so far with associated links:

In Part I we saw:

  • How to implement a custom MBean to manage configuration associated with an application.
  • How to package the resulting code and configuration as part of the application's ear file.
  • How to register MBeans upon application startup, and unregistered them upon application stop (or undeployment).
  • How to use generic JMX clients such as JConsole to browse and edit our application's MBean.

In Part II we saw:

  • How to add localized descriptions to our MBean, MBean attributes, MBean operations and MBean operation parameters.
  • How to specify meaningful name to our MBean operation parameters.
  • We also touched on future enhancements that will simplify how we can implement localized MBeans.

In Part III we saw:

  • How to localize our MBean based on the calling client's locale as opposed to the server's locale.
  • How to take advantage of the default resource mapping provided by WebLogic Server to localize MBean descriptions.
  • How to write a simple client that access our MBean using a locale other than the server's locale.
  • How to set the locale associated with JConsole.

In this new blog entry we will demonstrate:

  • How to emit an AttributeChangeNotification each time a new property is added or changed through our MBean.
  • How to properly localize our notifications.
  • How to observe notification using JConsole.
  • How to write a client that subscribes to the notification emitted by our MBean.

The complete code sample and associated build files for part IV are available as a zip file. The code has been tested against WebLogic Server 10.3.3.0 and JDK6. To build and deploy our sample application, please follow the instruction provided in Part I, as they also apply to part IV's code and associated zip file.

Adding notification support to our MBean

The first thing we need to do is modify our MBean implementation to extend the StandardEmitterMBean class in place of StandardMBean:

public class PropertyConfig 
    extends StandardMBean 
    implements PropertyConfigMXBean, MBeanRegistration { ... }
becomes:
public class PropertyConfig 
    extends StandardEmitterMBean 
    implements PropertyConfigMXBean, MBeanRegistration { ... }
Next we need to create the MBeanNotificationInfo that describes the notification emitted by our MBean, and add it to our MBean's MBeanInfo.
    private static final MBeanNotificationInfo info =
        new MBeanNotificationInfo(
           new String[]
               {javax.management.AttributeChangeNotification.ATTRIBUTE_CHANGE },
           AttributeChangeNotification.class.getName(),
           null
         );
 
    public PropertyConfig(String relativePath) throws Exception {
        super(PropertyConfigMXBean.class , 
              true, 
              new NotificationBroadcasterSupport(info));
 
        props_ = new Properties();
        relativePath_ = relativePath;
    }
The above code creates the MBeanNotificationInfo that describes the AttributeChangeNotification our MBean emits. The null parameter corresponds to the notification's description. The reason we pass in a null value for the description is that we want the value to be properly localized similarly to what we did in Part III for the MBean, MBean operations, and MBean attributes descriptions. We want WebLogic Server to extract the description from our MBean resource bundles based on the client's locale. To do so we will use a new mapping rules that we didn't touched on in Part III, and that is used for notification descriptions. Below is a list of all the mapping rules including the one related to notifications.

WebLogic 10.3.3.0 similarly to JDK 7 can automatically localize MBean descriptions as long as those are specified according to the following conventions:

Descriptions resource bundle keys are named according to:

  • MBean description: <MBeanInterfaceClass>.mbean
  • MBean attribute description: <MBeanInterfaceClass>.attribute.<AttributeName>
  • MBean operation description: <MBeanInterfaceClass>.operation.<OperationName>
  • MBean operation parameter description: <MBeanInterfaceClass>.operation.<OperationName>.<ParameterName>
  • MBean constructor description: <MBeanInterfaceClass>.constructor.<ConstructorName>
  • MBean constructor parameter description: <MBeanInterfaceClass>.constructor.<ConstructorName>.<ParameterName>
  • MBean notification description: <MBeanInterfaceClass>.notification.<NotificationName>
So we added the following entry to our resource bundles:
public class MBeanDescriptions extends ListResourceBundle {
     protected Object[][] getContents() {
         return new Object[][] {
             ....              
     {"PropertyConfigMXBean.notification.javax.management.AttributeChangeNotification", 
       "Notification sent each time a new property is added or its value is changed"},
             ....
        };
     }
 }
and
public class MBeanDescriptions_fr extends ListResourceBundle {
     protected Object[][] getContents() {
         return new Object[][] {
             ....         
     {"PropertyConfigMXBean.notification.javax.management.AttributeChangeNotification", 
        "Notification envoye quand une nouvelle propriete est ajoute, ou ca valeur est modifie."},
             ....
        };
     }
 }
The value for <NotificationName> correspond to the MBeanNotificationInfo.getName() method return value, which is also the value of the second parameter we passed to the MBeanNotificationInfo constructor: AttributeChangeNotification.class.getName()

Next we construct an instance of NotificationBroadcasterSupport passing our MBean's MBeanNotificationInfo as parameter. We then pass the NotificationBroadcasterSupport to the StandardEmitterMBean constructor as demonstrated in the code below:

    public PropertyConfig(String relativePath) throws Exception {
        super(PropertyConfigMXBean.class , 
              true, 
              new NotificationBroadcasterSupport(info));
 
        props_ = new Properties();
        relativePath_ = relativePath;
    }
The NotificationBroadcasterSupport handles the notification logic for the StandardEmitterMBean, and can be replaced by ones own implementation if needed.

When accessing our MBean using JConsole started with the following command line:

jconsole -J-Djava.class.path=$JAVA_HOME/lib/jconsole.jar:$JAVA_HOME/lib/tools.jar: $WL_HOME/server/lib/wljmxclient.jar -J-Djmx.remote.protocol.provider.pkgs=weblogic.management.remote -debug

We now see that our MBean includes proper notification meta-data and that descriptions are localized according to the WebLogic's server Locale. English in this case:

app_mbean_part4_jconsole1.JPG

Note: Consult Part I for information on how to use JConsole to browse/edit our MBean.

Now we are ready to add the code that will send a notification each time our MBean is used to add a new property or change the value of an existing one.

    public String setProperty(String key,String value) throws IOException {
 
        String oldValue = null;
 
        if (value == null) {
            oldValue = String.class.cast(props_.remove(key));
        } else {
            oldValue = String.class.cast(props_.setProperty(key, value));      
        }
 
        save();
 
        ResourceBundle bundle = 
            ResourceBundle.getBundle("blog.wls.jmx.appmbean.MBeanDescriptions");
        String notificationMessage = 
            bundle.getString("AttributeChangeNotification.message");
 
        AttributeChangeNotification acn = 
           new AttributeChangeNotification(this, notifCnt_++, 
               System.currentTimeMillis(),
               notificationMessage, 
               "Property", 
               String.class.getName(), 
               oldValue, 
               value);
 
        sendNotification(acn);
 
        return oldValue;
    }

We create an AttributeChangeNotification instance an pass the following parameters to its constructor:

  • The source of the notification, which is our MBean
  • The notification sequence number for the given source Object. We use a static variable to maintain this value, and increment it each time a new notification is sent.
  • The time at which the notification is being sent
  • The message associated with the notification. In the above sample code, we use our resource bundle to retrieve the localized message. We use the server's default locale to localize this message. We could have also used the client's locale that can be retrieved as follow:
       import weblogic.management.mbeanservers.JMXContextUtil;
       ......
       Locale callersLocale = JMXContextUtil.getLocale();    
    
    Either locale is not really satisfactory, as notifications are stored in a single global queue shared by all clients when the WebLogic or Sun's connector is used. So if different clients use different locales and register to receive notifications emitted by our MBean, there is no simple way to localize those notifications for the different clients if we want the localization to be carried out on the server side. For notification such as AttributeChangeNotification it is almost better not to include a message.
  • The name of the property that was added or whose value was changed.
  • The type of the property that was added or whose value was changed.
  • The property's old value
  • The property's new value
Finally we call the sendNotification method provided by the StandardEmitterMBean class. Note: That call is ultimately delegated to the NotificationBroadcasterSupport instance we created in our MBean constructor.

With that final code change, our MBean is now capable of emitting proper notifications each time a new property is added or an existing one is changed.

Using JConsole to observe our MBean's notifications

We can use JConsole to observe the notifications emitted by our MBean. We start JConsole using the following command line:

jconsole -J-Djava.class.path=$JAVA_HOME/lib/jconsole.jar:$JAVA_HOME/lib/tools.jar: $WL_HOME/server/lib/wljmxclient.jar -J-Djmx.remote.protocol.provider.pkgs=weblogic.management.remote -debug

We can then subscribe to receive the notifications emitted by our MBean by navigating to our MBean's Notifications sub tree and clicking the <Subscribe> button:

app_mbean_part4_jconsole2.JPG

Next lets go add a new property:

app_mbean_part4_jconsole3.JPG

We can now observe that we received a new notification:

app_mbean_part4_jconsole4.JPG

JConsole is designed to handle generic Notification but doesn't display the extra information provided by the AttributeChangeNotification. So from JConsole we do not have access to the name of the modified property, or the new and old values associated with that property. In the next section we modify the client code we first developed in Part III to register a listener that will display the full content of the AttributeChangeNotification emitted by our MBean on the client's console.

Writing a JMX client to observe our MBean's notifications

Below is the client's code developed in Part III and updated to register a NotificationListener with our MBean. We developed our own NotificationListener in class NotificationListenerWriter. That class is included as part of the zip file with the rest of the code.

package blog.wls.jmx.appmbean.client;
 
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.MBeanInfo;
 
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXServiceURL;
import javax.management.remote.JMXConnectorFactory;
     
import java.util.Hashtable;
import java.util.Set;
import java.util.Locale;
 
public class JMXClient {
 
    public static void main(String[] args) throws Exception {
 
        JMXConnector jmxCon = null;
 
        try {
      
            JMXServiceURL serviceUrl = 
                new JMXServiceURL(
    "service:jmx:iiop://127.0.0.1:7001/jndi/weblogic.management.mbeanservers.runtime"); 
 
            System.out.println("Connecting to: " + serviceUrl);
 
            // properties associated with the connection
            Hashtable env = new Hashtable();
 
            // Specifies WLS JMX protocol provider package
            env.put(
               JMXConnectorFactory.PROTOCOL_PROVIDER_PACKAGES, 
               "weblogic.management.remote");
 
            String[] credentials = new String[2];
            credentials[0] = "weblogic";
            credentials[1] = "weblogic";
            env.put(JMXConnector.CREDENTIALS, credentials);
 
            env.put("weblogic.management.remote.locale", Locale.FRENCH);
 
            // We get an instance of the JMXConnector interface
            jmxCon = JMXConnectorFactory.newJMXConnector(serviceUrl, env);
 
            // We connect to the WebLogic instance defined  in the JMXServiceURL
            jmxCon.connect();
 
            MBeanServerConnection con = jmxCon.getMBeanServerConnection();
 
            ObjectName mbeanName = new ObjectName(
                "blog.wls.jmx.appmbean:name=myAppProperties,type=PropertyConfig"); 
 
            System.out.println("\n\nMBEAN: " + mbeanName);
 
            MBeanInfo minfo = con.getMBeanInfo(mbeanName);
 
            System.out.println("MBean Description: "+minfo.getDescription());
            System.out.println("\n");
 
            con.addNotificationListener(
                mbeanName,
                new NotificationListenerWriter(System.out),
                null,
                null);
 
            for ( int i = 0; i < 5; i++ ) {
 
                con.invoke(
                    mbeanName, 
                    "setProperty", 
                    new Object[] {"P"+i, "V"+i}, 
                    new String[] {String.class.getName(), String.class.getName()} );
            } 
 
            con.invoke(
                mbeanName, 
                "setProperty", 
                new Object[] {"P1", "NEW VALUE"}, 
                new String[] {String.class.getName(), String.class.getName()} );
 
            // wait 10 sec before exiting so that
            // notifications get delivered
            Thread.sleep(10000);
        
 
        }
        finally {
            // release the connection
            if (jmxCon != null)
                jmxCon.close();
        }
    }
}

The above client code is part of the zip file associated with this blog, and can be run using the provided client.sh script. The resulting output is shown below:

$ . ./client.sh Connecting to: service:jmx:iiop://127.0.0.1:7001/jndi/weblogic.management.mbeanservers.runtime

MBEAN: blog.wls.jmx.appmbean:name=myAppProperties,type=PropertyConfig
MBean Description: Manage proprietes sauvegarde dans un fichier disque.

source: blog.wls.jmx.appmbean:type=PropertyConfig,name=myAppProperties type: jmx.attribute.change message: A property value was changed attribute name: Property attribute type: java.lang.String old value: null new value: V0
source: blog.wls.jmx.appmbean:type=PropertyConfig,name=myAppProperties type: jmx.attribute.change message: A property value was changed attribute name: Property attribute type: java.lang.String old value: null new value: V1
source: blog.wls.jmx.appmbean:type=PropertyConfig,name=myAppProperties type: jmx.attribute.change message: A property value was changed attribute name: Property attribute type: java.lang.String old value: null new value: V2
source: blog.wls.jmx.appmbean:type=PropertyConfig,name=myAppProperties type: jmx.attribute.change message: A property value was changed attribute name: Property attribute type: java.lang.String old value: null new value: V3
source: blog.wls.jmx.appmbean:type=PropertyConfig,name=myAppProperties type: jmx.attribute.change message: A property value was changed attribute name: Property attribute type: java.lang.String old value: null new value: V4
source: blog.wls.jmx.appmbean:type=PropertyConfig,name=myAppProperties type: jmx.attribute.change message: A property value was changed attribute name: Property attribute type: java.lang.String old value: V1 new value: NEW VALUE
$

Conclusion

In this blog entry we demonstrated how to add notification support to our application MBean. We also leveraged WebLogic's localization functionality to provide proper localization to our notifications similarly to what we did for the rest of the MBean in Part III. I hope that the provided code and scripts will be of help when developing your own application MBeans. I am sure we will add more functionality in a not so distant future.

Comments:

Or do you go on a treasure hunt in your home! Hide the bag somewhere, it would be unlikely to find it, then leave notes around the house or apartment that his lead from track to track. In this way we know something special is waiting for them will, but they do not know what to expect from it and they will see!

Posted by Replica Louis Vuitton Handbags on March 16, 2011 at 04:16 AM PDT #

What a wonderful blog you have. I love how you write and make everything simple and easy to understand. Thank You!

Posted by Augusta Devera on April 03, 2011 at 07:32 AM PDT #

Post a Comment:
  • HTML Syntax: NOT allowed
About

The official blog for Oracle WebLogic Server fans and followers!

Stay Connected

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
5
6
7
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today