Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Tomcat JMX - Connecting to server but cant find the MBean i want

Tags:

java

tomcat

jmx

I am trying to write a client utility that to connect to Tomcat via JMX and look at the status of the connection datasource. I set the following VM arguments in $CATALINA_HOME/bin/setenv.bat and restarted Tomcat

set JAVA_OPTS=-Xms512M -Xmx1024M -XX:MaxPermSize=256M %JAVA_OPTS% set CATALINA_OPTS=-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9004 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false %CATALINA_OPTS%

I am not very familiar with JMX so i am just having a play with it to get the feel of it. The utility i am writing will be running outside of Tomcat. I wrote the following test to try and access datasource Mbean object in Tomcat but for some reason it is not finding it.

    public class GuiMonitor {
      public static void main(String[] args){

       try{
        JMXServiceURL url = new JMXServiceURL(
             "service:jmx:rmi:///jndi/rmi://localhost:9004/jmxrmi");
            JMXConnector jmxc = JMXConnectorFactory.connect(url, null);

            final List<MBeanServer> servers = new LinkedList<MBeanServer>();

            servers.add(ManagementFactory.getPlatformMBeanServer());
            servers.addAll(MBeanServerFactory.findMBeanServer(null));

            System.out.println("MbeanServers " + servers.size()); 

            for(final MBeanServer server : servers){
              System.out.println("Server : " + server.getClass().getName());
             }

            MBeanServer mbsc = ManagementFactory.getPlatformMBeanServer();
            System.out.println(mbsc.queryMBeans(null, null));
            ObjectName on = new ObjectName("Catalina:type=DataSource,path=/appdb,host=localhost,class=javax.sql.DataSource,name=\"jdbc/appdb\"");
            System.out.println("ObjectName : " + on.toString());
            System.out.println(mbsc.getAttribute(on, "Catalina:type=DataSource,path=/appdb,host=localhost,class=javax.sql.DataSource,name=\"jdbc/appdb\""));

       } catch (Exception e) {
                 e.printStackTrace();
             }  
          }
         }

I have a JSP page that i found on the internet which when i upload onto the webapps folder and run it, it displays all of the available MBeans in Tomcat. The object string/name i used above came from the name that was reported on both the jsp page i used and Jconsole so it does exist.

The output to the above program is shown below

     MbeanServers 2

     Server : com.sun.jmx.mbeanserver.JmxMBeanServer
     Server : com.sun.jmx.mbeanserver.JmxMBeanServer

     [com.sun.management.OperatingSystem[java.lang:type=OperatingSystem], sun.management.MemoryPoolImpl[java.lang:type=MemoryPool,name=Tenured Gen], sun.management.MemoryPoolImpl[java.lang:type=MemoryPool,name=Perm Gen], java.util.logging.Logging[java.util.logging:type=Logging], sun.management.CompilationImpl[java.lang:type=Compilation], javax.management.MBeanServerDelegate[JMImplementation:type=MBeanServerDelegate], sun.management.MemoryImpl[java.lang:type=Memory], sun.management.MemoryPoolImpl[java.lang:type=MemoryPool,name=Survivor Space], sun.management.RuntimeImpl[java.lang:type=Runtime], sun.management.GarbageCollectorImpl[java.lang:type=GarbageCollector,name=Copy], sun.management.MemoryPoolImpl[java.lang:type=MemoryPool,name=Eden Space], sun.management.GarbageCollectorImpl[java.lang:type=GarbageCollector,name=MarkSweepCompact], sun.management.ThreadImpl[java.lang:type=Threading], sun.management.MemoryPoolImpl[java.lang:type=MemoryPool,name=Perm Gen [shared-ro]], sun.management.MemoryPoolImpl[java.lang:type=MemoryPool,name=Perm Gen [shared-rw]], sun.management.HotSpotDiagnostic[com.sun.management:type=HotSpotDiagnostic], sun.management.ClassLoadingImpl[java.lang:type=ClassLoading], sun.management.MemoryManagerImpl[java.lang:type=MemoryManager,name=CodeCacheManager], sun.management.MemoryPoolImpl[java.lang:type=MemoryPool,name=Code Cache]]
     ObjectName : Catalina:type=DataSource,path=/appdb,host=localhost,class=javax.sql.DataSource,name="jdbc/appdb"

     javax.management.InstanceNotFoundException: Catalina:type=DataSource,path=/appdb,host=localhost,class=javax.sql.DataSource,name="jdbc/appdb"
      at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.getMBean(DefaultMBeanServerInterceptor.java:1094)
      at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.getAttribute(DefaultMBeanServerInterceptor.java:662)
      at com.sun.jmx.mbeanserver.JmxMBeanServer.getAttribute(JmxMBeanServer.java:638)
      at com.bt.c21.c21mon.C21GuiMonitor.main(C21GuiMonitor.java:39)

A couple of questions

  • Is the URL correct? I know the port number is correct but i am not sure of the service name. The service name "jmxrmi" i am using on the URL is just one that i saw in one of the examples i have been looking at.

I have a feeling that this is connecting to a different MBeanServer. I suspect this because if you look at the output of mbsc.queryMBeans(null, null), there is nothing tomcat specific. What service name do i use for the Tomcat instance?

  • If the URL is correct then is the service name always jmxrmi? And why does it not find the "Catalina:type=DataSource,path=/appdb,host=localhost,class=javax.sql.DataSource,name=\"jdbc/appdb\"" entry?

  • I have seen a lot of examples of how to do this and most use a different method to get teh MbeanServer. A couple of examples i have seen are

    ManagementFactory.getPlatformMBeanServer() MBeanServerFactory.findMBeanServer(null) getMBeanServerConnection()

  • As mentioned earlier, the utility i am writing is a normal java application that will be running outside of tomcat. Is there any other configuration that i have missed out? I have been looking at several examples and the majority talk about creating MBeans and there is usually references to Listeners. As i am not creating any new Mbeans but only reading the values of existing ones, do i need to configure a listener?

Edit

It seems that getPlatformMbeanServer() is not returning the correct JVM Instance. I tried the following

MBeanServerConnection conn = jmxc.getMBeanServerConnection(); 
System.out.println("Query2  : " + conn.queryMBeans(null, null)); 

And this does return some Tomcat specific values. But i am still unable to get the jdbc/appdb datasource.

krtek - I wont be able to use JMX Console as i plan to do it all manually with the intention of automating it.

Edit 2

Ok, i figured out what i was doing wrong. Initially i was trying to retrieve the values as

MBeanServerConnection conn = jmxc.getMBeanServerConnection(); 
ObjectName on = new ObjectName("Catalina:type=DataSource,path=/appdb,host=localhost,class=javax.sql.DataSource,name=\"jdbc/appdb\"");
mbsc.getAttribute(on, "Catalina:type=DataSource,path=/appdb,host=localhost,class=javax.sql.DataSource,name=\"jdbc/appdb\""));

The above is wrong because the second parameter for mbsc.getAttribute is supposed to be the attribute in the Mbean not the String name.

This gave me the correct attribute values

MBeanServerConnection conn = jmxc.getMBeanServerConnection(); 
ObjectName on = new ObjectName("Catalina:type=DataSource,path=/appdb,host=localhost,class=javax.sql.DataSource,name=\"jdbc/appdb\"");
mbsc.getAttribute(on, "numIdle")

And i also changed the MBeanServer i was using from getPlatformMbeanServer() to getMBeanserverConnection(). I must admit i dont quite understand the difference because since Tomcat is running on the same JVM as the one returned by getPlatformMbeanServer(). Does it mean that getPlatformMbeanServer() will only return sun specific Mbeans? and getMBeanserverConnection() will include both?

Thanks

like image 764
ziggy Avatar asked Jan 05 '11 18:01

ziggy


1 Answers

That's because you are getting instance of JMX server for your client JVM, not the Tomcat one.

This is right:

JMXServiceURL url = new JMXServiceURL(
    "service:jmx:rmi:///jndi/rmi://localhost:9004/jmxrmi");
JMXConnector jmxc = JMXConnectorFactory.connect(url, null);

But you should continue with something like:

MBeanServerConnection conn = jmxc.getMBeanServerConnection(); 
Set result = conn.queryMBeans(null, 
"Catalina:type=DataSource,path=/appdb,host=localhost,class=javax.sql.DataSource");

To test your query string use some tool like JMX console.

like image 200
krtek Avatar answered Sep 25 '22 13:09

krtek