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

24,257

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.

Share:
24,257
ziggy
Author by

ziggy

Updated on January 07, 2020

Comments

  • ziggy
    ziggy over 4 years

    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

  • Victor
    Victor over 13 years
    Hi krtrek,just for my curiosity, how did you conclude that ziggy is getting instance of JMX server for client JVM, not the Tomcat one. He did indicate Tomcat was running on port 9004
  • krtek
    krtek over 13 years
    ManagementFactory.getPlatformMBeanServer() returns JMX server for current JVM instance, not the remote one.
  • ziggy
    ziggy over 13 years
    I rerun the program again while Tomcat is not running and i get the following error "Connection refused to host: localhost;". I get this same error if i change the port number to one other than 9004. By the way the tomcat instance is local not remote)
  • krtek
    krtek over 13 years
    Yes - because you do open a connection to Tomcat JVM and then forget it and ask for JMX server of local JVM. You have to use that connection further. That was my point.