Firstly, I cheated. Actually this post should be named “JMX and application-specific resources”. But, since I found this architectural property of JMX while attempting to use the JPA within JMX managed bean, the title is what it is.
Secondly, this post is neither on what JMX is nor what JPA is. If you are unfamiliar with those – read basics someplace else. Be advised though that while there is plethora of excellent material on JPA (just google for it and you’ll find everything you could’ve dreamed about), there is next to nothing on JMX good enough for ME to understand it! Well yeah, there are number of docs and articles from Sun and independent authors available out there. Me, I am dissatisfied with all of them. For instance, how the heck I work with composite or tabular data types of the open beans or, in fact, how do I work with application specific resources, huh?
So, as I said, there was this use case I was working on – “Show me in a JMX managed bean some application configuration data out of persistence”. My application is a web-app running on the tomcat. I initialized MBean in her (bean’s) constructor and registered it with the default MBeanServer of the JVM with something like this:
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
Within MBean I was using a DAO which loaded for me some config data over the JPA with Hibernate. To my great pleasure – the MBean worked at the first try until… I changed something. I did some minor optimization and my MBean broke down. For whole two days I and my colleague (wink Christian) were sweating hard to fix the bug.
The symptom was that the JPA couldn’t instantiate EntityManager anymore with the exception of something like “There are no providers for the persistence unit MyPersistenceUnit”.
After two day trial and error, endless reading and attempting to understand scarce JMX docs the issue turned out to be initialization of that DAO I mentioned earlier. Inside the DAO I was creating an entity manager like this:
emf = Persistence.createEntityManagerFactory("MyPersistenceUnit");
em = emf.createEntityManager();
In a web-app (EJB app to be precise) the JPA (or in fact Hibernate) expects a persistence.xml to be located in /META-INF/persistence.xml of the web-app. The persistence.xml is loaded then by Hibernate as a resource using context class loader of the current thread.
This is where things get ugly when using JMX. How I understand it, registering MBean with the platform MBean server causes the MBean methods be called from the system class loader of the JVM when the MBean methods are invoked by the call-backs(?) from the MBeanServer. Yes, the system class loader of the JVM (as in Java Virtual Machine). Not the class loader of the web-app, not even class loader of the tomcat, but the class loader of the JVM itself. Why? Because MBeanServer runs directly in JVM. This in turn means that if attempts are made to load resources located on the class path of the web-app in the MBean methods called back by the MBeanServer, they will fail since the class loader of the MBeanServer (the system class loader of the JVM) knows nothing about web-app or, in fact, any class path that lies below that of the JVM.
Yeah, I can’t call it a solution since it’s not. But the workaround that worked for me was to initialize the DAO and store it (the DAO) as a class attribute of the MBean implementation before I hand the control over to MBeanServer. This way, the methods of MBean can work with the initialized instance of the DAO. This workaround sucks for number of reasons but I can’t seem to find a better one.
The final point is – any resource loading done in the methods of MBean invoked by call-backs from MBeanServer will fail since those invocations are done within thread of the JVM itself.