-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Austin,

On 3/26/15 7:33 PM, Austin Jones wrote:
> I believe I figured this part out in the debugger.  When the 
> WebappClassLoader attempts to load the class, the .class file (and
> the entire exploded directory) is not on the disk.  First, let me
> quote a few frames of the ClassNotFoundError stack trace (once
> again, 8.0.20).
> 
> java.lang.NoClassDefFoundError: com/avadyne/ThisClassNotFound ... 
> at 
> org.apache.catalina.core.StandardContext.reload(StandardContext.java:3739)
>
> 
at org.apache.catalina.startup.HostConfig.reload(HostConfig.java:1304)
> at 
> org.apache.catalina.startup.HostConfig.checkResources(HostConfig.java:1236)
>
> 
...
> 
> HostConfig.checkResources:1231 deletes the exploded directory 
> HostConfig.checkResources:1236 calls into StandardContext.reload 
> StandardContext.reload:3739 eventually invokes the
> ServletContextListeners

That sounds like an oops to me.

> Once the contextDestroyed listeners are executed, the .class file
> doesn't exist (HostConfig.checkResources deleted it).

It's odd that the class needs to be loaded on shutdown, but I think
it's a valid use case that should definitely work.

> I have walked (in the debugger) all the way from
> HostConfig.checkResources to the
> SevletContextListener/WebappClassLoader.loadClass call, and there 
> doesn't seem to be any other code that causes trouble.
> 
> It is definitely unsafe for HostConfig.checkResources to delete
> the unpacked directory before the context is stopped.  However, 
> WebappClassLoader is correct to throw a ClassNotFoundError, since
> the class really doesn't exist on disk.

Okay, so it sounds like this is really just an incorrect
order-of-operations problem.

>> Now, Tomcat 8 uses a more complicated resource-loading framework 
>> than previous Tomcats, and it's possible that the
>> resource-loading framework is being taken down earlier than your
>> code is running, which would make certain classes /libraries
>> inaccessible. I haven't read enough code to know if that's the
>> case or not. IMO it shouldn't be the case, and probably isn't
>> because the smarter Tomcat devs tend to think about things like
>> that before coding them ;)
>> 
>> IIRC, during ServletContextListener.contextDestroyed, the 
>> WebappClassLoader should be fully-functional. That is, it
>> shouldn't have complained about anything.
> 
> I wouldn't blame anyone for not noticing this bug.  And, I dream of
> a fully functional ClassLoader :D
> 
> The bug requires very specific conditions. Deploy a WAR through the
> Tomcat manager, and configure it to explode the war, and create a
> listener that references a class on shutdown that was never
> referenced prior...

Please file a bug in Bugzilla for this. If you're feeling
enterprising, go ahead and attach a WAR (including source) that can
reproduce the issue.

> Unfortunately, the impact (uncaught java.lang.Error leaving
> uncleaned resources/threads) is pretty severe.  It is also
> unavoidable if you need to execute lots of code in the shutdown
> handler, or you need to wait for Threads to stop.  I need to do
> both...

I suppose your code could try { ... } catch (NoClassDefFoundError) but
if course that's a stupid hack that should not be necessary. But,
it'll get the job done until a patch is available for Tomcat.

>> In my first example, the ClassNotFoundError is thrown when
>>> enabled=false. When enabled=true, the error doesn't occur.
>> When you say enabled=true, you mean that's what's showing in the 
>> Manager's web interface?
> 
> Don't worry too much about the enabled flag, it doesn't have
> anything to do with the actual issue.  I was trying to explain why
> a class wouldn't be loaded during contextInitialized (in this case
> - when initialization is conditional).
> 
>> The "new" WebappClassLoader shouldn't even be involved, yet,
>> since the shutdown is evidently not completing successfully, so
>> the reload never actually gets to the "load" part.
> 
> Well, yes and no.  The WebappClassLoader which throws the 
> ClassNotFoundError is definitely the one on the 'stop' side of the
> reload. I can tell from the cached classes.

Right, that's exactly what I would have expected.

> The ClassNotFoundError gets caught and logged by 
> StandardContext.listenerStop(), which catches Throwable.  Tomcat
> completes the reload without any issue.
> 
>> When you do the reload(), are you shutting-down a
>> properly-running web application, or one that failed to load
>> properly in the first place?
> 
> Yes, the app is up and running just fine.  All servlets/listeners
> are mounted, and no errors were reported during startup.
> 
>> I actually have reworked my app's top-level initialization layer
>> to
>>> preload classes on startup.  I am considering preloading all 
>>> classes in WEB-INF/classes at server startup.  Unfortunately,
>>> my init layer needs to call into code deeper in the
>>> application, which may call into bundled JARs (WEB-INF/lib).
>>> Including JARs, that would be a lot of code to preload.
> 
> 
> 
>> It also shouldn't be necessary. I think something else weird
>> might be going on.
> 
> It's a temporary workaround, but it works OK.  I get occasional
> NPEs from the ClassLoader when it needs to load from JARs in
> WEB-INF/lib, but I can live with that until the Tomcat code is
> fixed.  Actually, Guava's ClassPath API made preloading
> surprisingly easy.

Log the bug; I'm sure it's relatively easy to fix.

Thanks for your investigation, and your explanation. This is a part of
Tomcat's code with which I have little familiarity, so explaining
everything helps me get my brain around it and will also help whoever
will end up fixing this (not likely me, due to said lack of familiarity).

- -chris
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1
Comment: GPGTools - http://gpgtools.org

iQIcBAEBCAAGBQJVFVncAAoJEBzwKT+lPKRYfEYP/isWOdc8vnCwzbVLVvvEX3Ps
RnpLBOkyHyuyXPfcsYK3/Z99Sjkr2CKG5qURBut2YtequkAFvKD2GkA5mPkXvb6t
4RTu/TPIuRiOb9Z3O2g3sEYjz1lILlpXpW9rcPi3emb5c0QKUVJDtS1mZZBxkDzO
7A9FUW7Mue0thWwaHRVUqiKooVBX44s0VcAzh68LG2dhL7R6MiB9HrIka1sDKi/V
d25gKXSqLh6E2GBlQ9NygqY/D9hjkP/mTz9LbuPid5WHD28bvBX+JId8pVVLwiOp
iX2uVP6pcUXAQiHhdGGZjxM2u9FB6vDF1Mu2f8C38fLVsQ7sFsdA3SrIS2bJR62b
HOFCLqG6qbKvhzAGRBOBhjDzX0pxw2sJvxUTaL9AS2PStYetso6WKz8e24bCdjWz
WPlFzIYY7wqymx4anabyjkEG9OhXCCMiIdP6bGnj9+5BQGL5Uqi0s1rhiLzreEbB
8CdgBVjSYhunP7N3nqA5ntYVvkg1oZGQXiKbxnLwrnoV8JCVbo6mr4P8zZV8VvVr
rni7LviSlHtMrURitCN39A2s5Xg/rnZg2uQSfTCbPKUmxugEB1u15TxefLwbd3+I
kHrWOf5XOtRmKAGCiKvWJYLZbqgZhah//lXzcdo0jv5WiWt32JjvqL3ciEHuunJo
7FoKJQYPiE/dAT6PLX0c
=ZWGK
-----END PGP SIGNATURE-----

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org

Reply via email to