Monday, January 7, 2013

Lets Play with JMX-1



Lets just say you have written one program which prints your name every 0.5 sec for 10^6 times. You started your program and then you realized "Enough of my name, now I want to see my friend's name" What will you do?? Set your name variable and restart your program?? What if next time you realized  I want 50000 times your name and then 50000 times your dog's name, or lets just say I don't want you to kill the program and change the name you are printing on the fly??


Welcome to JMX(Java Management Extension).

What is JMX??

In real simple words, JMX is a technology which allows you to dynamically manage and monitor  JAVA resources. Using it you can also manage your JVM.  A nice tutorial.

How JMX works??


JMX has three layers :
a.) Instrumentation Level :
     At instrumentation level you create an interface which defines the requirements to implement a
    manageable resource, in other words you expose all the methods through which you will manage
    your resource. In JMX this interface has a special name MBean(there are different types of mbeans
    but details about them, later). After creating the MBeans you need to register it to MBeanServer.

b.) Agent Level :
      Similarly Agent level defines requirements for implementing agents. Agents control and expose
      the managed resources which registered with agent.

c.) Connectors and Protocol Adapters:
     This layer gives you connectors and different protocol adapters which allows you to connect to
     the agents and manage your resources.


Let's take an example, now!!

Lets take the scenario given at the start(though its a really bad use case of JMX but for starters we
can use it).  To solve the above problem we will write one class which has two fields loop and name where I want to manage both fields and I will have one method which prints the name for given loop time. So first lets write the Mbean(Interface).


public interface TestExampleMBean {
    public int getLoops();
    public void setLoops(int n);
    public void setMessage(String a);
    public String getMessage();
}


Now lets implement it and create a resource


public class TestExample implements TestExampleMBean, Runnable{
    private int loops;
    private String message
    public int getLoops() {
        return loops;
    }
    public void setLoops(int loops) {
        this.loops = loops;
    }
    public String getMessage() {
        return message;
    }
    public void setMessage(String message) {
        this.message = message;
    }
    public void run() {
        for (int i=0;i<loops;i++){
        System.out.println(message);
    try {
       Thread.sleep(1000);
     } catch(Exception e){
         System.out.println("Exception caught");
     }
     }
}
}

Now the main class :


import java.lang.management.*;
import javax.management.*;
public class Main {
    public static void main(String[] args) throws Exception {
        System.out.println("Starting Main");
        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
        ObjectName name = new ObjectName("com.open.example:type=TestExample");
       TestExample te = new TestExample();
       mbs.registerMBean(te, name);
       te.setLoops(1000);
       te.setMessage("Shwet Shashank");
       Thread t = new Thread(te);
        te.run();
        Thread.sleep(Long.MAX_VALUE);
   }

}

As you see first we created an interface, then we implemented it to create a resource and then we 
registered with our MBeanServer. Important lines in Main class are :

MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); // create one mbean server


ObjectName name = new ObjectName("com.open.example:type=TestExample");

Each object must be registered with a name, ObjectName has some outlined rules to create one,
the basic format is "domain:[<key, value>]" where domain is the package name and key value is a list of string pair.

Now run the above program and in a separate console start jConsole. Click on new connection,
under local process tab you will see your program running, connect to it, click on tab Mbeans. You will see something like this :





Open the tab com.open.example(I have all my classes in this package), click on message, you will see something like this:




Now give a new name:


Click refresh and check the console where your program was printing your name, its printing the new name now. DONE!!!