Accessing built-in MBeans in Tomcat programmatically
Asked Answered
L

2

4

Basically I'm trying to modify the code from this tutorial here: http://docs.oracle.com/javase/tutorial/jmx/remote/custom.html so that I can access the MBeans from tomcat that are described here: http://wiki.apache.org/tomcat/FAQ/Monitoring

there is no problem accessing the JMX Bean java.lang:type=Memory from code since it's interface is defined in java.lang. Here's the code example of that:

    ObjectName mbeanName = new ObjectName("java.lang:type=Memory");
    MemoryMXBean mxbeanProxy2 = JMX.newMXBeanProxy(mbsc, mbeanName, MemoryMXBean.class, true);
    MemoryUsage memUsage = mxbeanProxy2.getHeapMemoryUsage();
    echo("\nMemory Utilization: " + (memUsage.getUsed()/(double)memUsage.getMax()) * 100 +  "%");

Here the mbsc is an instance of MBeanServerConnection. The problem is that when I'm trying to access the built-in MBeans in tomcat in a similar way I run into the problem that I can't find any interface defined for any of the tomcat MBeans. I can monitor the MBeans from JConsole but for this I need to be able to do this from code. I found it somewhere that this could also done with something like this:

ObjectName mbeanName2 = new ObjectName("Catalina:type=ThreadPool,name=\"http-apr-8080\"");
Object value = mbsc.getAttribute(mbeanName, "name");

But this gives me this exception: Exception in thread "main" javax.management.AttributeNotFoundException: No such attribute: name at com.sun.jmx.mbeanserver......

I feel like I'm missing something fairly basic. But the information on this specifically seem to be very limited and google did not help much.

Lascivious answered 3/7, 2013 at 20:35 Comment(0)
B
2

I think there's a typo in your second snippet of code. You created a new ObjectName for the Catalina ThreadPool called mbeanName2, but when you try to retrieve the attribute "name", you're still using mbeanName.

So it should be:

ObjectName mbeanName2 = new ObjectName("Catalina:type=ThreadPool,name=\"http-apr-8080\"");
Object value = mbsc.getAttribute(mbeanName2, "name");

Other than that, you code should work fine.

Bedlam answered 3/7, 2013 at 20:52 Comment(1)
so just fixing this typo it should work? I'll accept your answer once I can verify this...Lascivious
I
2

Today I had the same issue what Oz0234 described above (using TomEE 1.7.0 on Windows) but I did not understand for a while why the ProxyBean solution does not work at all with any Catalina objects.

It works with the MBeanServerConnection.getAttribute(objectName, attribute) method but it does not work using the proxy bean methods. I have checked and tested many.

Finally I have found why this happens. The answer is that the attribute names in Catalina domain start with lower case letter while the attribute names in other domains (java.lang, java.nio, openejb, ...) start with upper case letter as described here: http://docs.oracle.com/javase/7/docs/api/javax/management/JMX.html

I have extracted the most relevant part:

MyMXBean proxy = JMX.newMXBeanProxy(mbs, name, MyMXBean.class);

Suppose, for example, MyMXBean looks like this:

public interface MyMXBean {
  public String getSimpleAttribute();
  public void setSimpleAttribute(String value);
  public MemoryUsage getMappedAttribute();
  public void setMappedAttribute(MemoryUsage memoryUsage);
  public MemoryUsage someOperation(String param1, MemoryUsage param2);
}

Then proxy.getSimpleAttribute() will result in a call to
mbs.getAttribute(name, "SimpleAttribute").

You can see the above example that the attribute's name starts with upper case letter "S"impleAttribute as the proxy bean getter name getSimpleAttribute. Unfortunately this is exactly the opposite what the bean's getter/setter naming convention describes.

Also I have checked other Tomcat Domain Objects' (Catalina,Users) attributes available on the JMX connection and I have compared some other attributes as well. If an attribute name starts with upper case letter, the bean proxy works. If it starts with lower case letter, only the getAttribute method works, like this:

JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:9999/jmxrmi");
try(JMXConnector jmxc = JMXConnectorFactory.connect(url)) {
  MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
  ObjectName mbeanName = new ObjectName("Catalina:type=Manager,context=/,host=localhost");
  Object value = mbsc.getAttribute(mbeanName, "activeSessions");
}

So you need to pay attention which method you choose.

Intercalary answered 8/11, 2015 at 23:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.