-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256 All,
I think I already know the answer to this question, but I'm going to ask anyway in case it helps others understand what's going on. I have a custom MBean for a loadable-object in my web application. This is an object that lives in the application-scope and needs to be periodically re-loaded from our relational database when we add new data to it. The bean looks like this: public static class ReloadableObjectBean implements ReloadableObjectBeanMBean { private ReloadableObject _rlo; private Date _loadTime; public ReloadableObjectBean() { _rlo = null; _loadTime = null; } public ReloadableObjectBean(ReloadableObject dxe) { _loadTime = new Date(); _rlo = dxe; } @Override public int getItemCount() { return _rlo.getItems().size(); } protected Date getLoadTimeInternal() { return _loadTime; } @Override public Date getLoadTime() { return (Date)getLoadTimeInternal().clone(); } @Override public void reload() throws ReloadableObjectException, ServiceException { ReloadableObject rlo = ReloadableObjectHelper.newReloadableObject(); _loadTime = new Date(); _rlo = rlo; } } This is an inner class defined in one of my ServletContextListeners, and it's inserted into the MBeanServer like this: ReloadableObject rlo = ReloadableObjectHelper.newReloadableObject(); try { MBeanServer mbs = getServer(); ObjectName objectName = new ObjectName("com.chadis:type=ReloadableObject"); if(mbs.isRegistered(objectName)) mbs.unregisterMBean(objectName); mbs.registerMBean(new ReloadableObjectBean(rlo), objectName) ; } catch (MBeanException mbe) { logger.warn("Cannot register MBean", mbe); } catch (InstanceAlreadyExistsException iaee) { logger.warn("Cannot register MBean", iaee); } catch (NotCompliantMBeanException ncme) { logger.warn("Cannot register MBean", ncme); } catch (MalformedObjectNameException mone) { logger.warn("Cannot register MBean", mone); } catch (InstanceNotFoundException infe) { logger.warn("Cannot de-register MBean", infe); } application.setAttribute("reloadbleObject", rlo); Everything goes well until I try to invoke the "reload" operation on this MBean from a JMX client, where I get ClassNotFoundException: 2018-03-06 10:26:07,271 [RMI TCP Connection(1)-169.254.211.40] FATAL ReloadableObjectHelper- Could not load ReloadableObject: ServiceException: Cannot obtain database connection at ReloadableObjectHelper.getConnection(ReloadableObjectHelper.java:147 ) at ReloadableObjectHelper.newDiagnosisEngine(ReloadableObjectHelper.java:55 ) at InitListener$ReloadableObjectBean.reloadEngine(InitListener.java:159 ) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.jav a:62) .... Caused by: Caused by: javax.naming.NoInitialContextException: Cannot instantiate class: org.apache.naming.java.javaURLContextFactory [Root exception is java.lang.ClassNotFoundException: org.apache.naming.java.javaURLContextFactory] at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:674) at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:31 3) at javax.naming.InitialContext.init(InitialContext.java:244) at javax.naming.InitialContext.<init>(InitialContext.java:192) at ReloadbleObjectHelper.getConnection(ReloadableObjectHelper.java:136) ... 39 more Caused by: java.lang.ClassNotFoundException: org.apache.naming.java.javaURLContextFactory at java.net.URLClassLoader.findClass(URLClassLoader.java:381) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:348) at com.sun.naming.internal.VersionHelper12.loadClass(VersionHelper12.java:7 2) at com.sun.naming.internal.VersionHelper12.loadClass(VersionHelper12.java:6 1) at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:672) ... 43 more The error I get on VisualVM (my JMX client, here) is that it can't load my ServiceException class -- one that is defined only within the web application. I suspect the problem is that the thread's context class loader (TCCL) is set to Tomcat's ClassLoader, since the request is being handled by Tomcat's internal JMX server. If I were to invoke this operation via the Manager's JMXProxyServlet, I'd probably be dealing with the Manager's WebappClassLoader, instead, but the problem would be the same: those ClassLoaders are unaware of my application's classes. I *believe* the solution is to change the TCCL in this "reload" method, but that means I'll need to capture the TCCL during the invocation of the MBean itself and hang on to it... something like this: ClassLoader originalCL = Thread.currentThread().getContextClassLoader(); ReloadableObject rlo = ReloadableObjectHelper.newReloadableObject(); try { MBeanServer mbs = getServer(); ObjectName objectName = new ObjectName("com.chadis:type=ReloadableObject"); if(mbs.isRegistered(objectName)) mbs.unregisterMBean(objectName); mbs.registerMBean(new ReloadableObjectBean(rlo, originalCL), objectName); } Then, later, in the reload() method: @Override public void reload() throws ReloadableObjectException, ServiceException { ClassLoader tccl = Thread.currentThread().getContextClassLoader(); try { Thread.currentThread().setContextClassLoader(originalCL) ; ReloadableObject rlo = ReloadableObjectHelper.newReloadableObject(); _loadTime = new Date(); _rlo = rlo; } finally { Thread.currentThread().setContextClassLoader(tccl); } } Does that sound about right? I'll probably want to future-proof it by wrapping those calls into PrivilegedActions, etc. but is this the right approach for what I'm trying to do, here? Or am I missing something? - -chris -----BEGIN PGP SIGNATURE----- Comment: GPGTools - http://gpgtools.org Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/ iQJRBAEBCAA7FiEEMmKgYcQvxMe7tcJcHPApP6U8pFgFAlqetzEdHGNocmlzQGNo cmlzdG9waGVyc2NodWx0ei5uZXQACgkQHPApP6U8pFgN8RAAwaaFjruUtxisKCrl SvCxe+8UYbVjOq889x8UdBirnt0fQI6q53W4q51l72pvJ4yi83R1XrtjjcltbQ+4 A/OXS6VKg0L9gY6heM38LRp6Yp0Jjy9jIMjNMxCdjU9hqqfT+7jWinvxelFpMfFj QXMILFHD0BRkwpc83ntyFGG/9i0cGdzaYb28GhvCff+48gk0CF7T2IO4VNN+UvYU TnWbfiPhO8ng+Cqja4QwrMv2CcBvTp4OuFU7rg/hBAZ545H2hBIPhzaVMCTzqBdO z1UOHhluBc2srvoVzXg7OlX4w4PRShu4QqvYECm/JQBKa8kWlgfLQgeKJbms6xc8 4Y+tuEZMaROPVITpncyj24gur+gD3PjZh4+JRKucdZg5Bt/ci7Rb9lpvwJSL9pmq pV05I4tXakU5JibTNFydZNEn6vHWEz9DuQeYr2EQb4JeJ81FlOAuuqF6kgBVRINQ F0RCdW5D8BXh2QLs9/ijUnnUbk83rmbah/4zKYdHGtlsiaJ1lmhZmmfAvZRek1vK 8NZ6A0/YaGw34LK2bYEctllZYSBs6G2AMQgO0KPU09jDXe4bVfjz00XR96A+1cX1 RNL/jRhcZlfizPbLtg4GDwxWzJj664p+1F236Zg8haUjQXI4WrV6UaeCf5X3SIdQ rxhOvK+OGoSOl6TWP5OaqMHrKaQ= =snnR -----END PGP SIGNATURE----- --------------------------------------------------------------------- To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org