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
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?
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.
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With