Hola a Todos,David:
Thanks for take a look in this area, is hard to test and has little to
nothing review and is plenty of big traps ( as the last found ) ..
One of the most hard things that TC33 does is to hide the complexity of
JDK11 and 12 compatibility without to much hassle for the poor devs that
deal with CL.., all that great work was made by Costin .. ( Perplexity
was the word :)))
I only did a some startup work ( Main class ) and test it.., and the big
trick of it was to make Jasper work consistently when used as a servlet
( that is in webapp CL ) or when used as interceptor ( container CL ) ..
and the trick now is to simply walk down the CL chain adding every
Classpath found in the CL to the classpath of the java compiler used to
compile JSPs.... think on it taking into account that this works well
and trasparently ( mostly ) using JDK11 ( that has a non delegating CL
scheme ) and JDK12 ( that uses the beloved and quick URLClassloader and
a delegating scheme ).. this was the really hard part !!!
( More Comments intermixed )
>
> Hi folks,
>
> I've been having a peek at the Tomcat main CVS branch in
> respect of its classloading behaviour. Apologies if I have
> missed any discussion - I have only just subscribed, and I
> did not find much in the tomcat-dev archives a couple of days ago.
>
> It appears to me that ClassLoading is not quite right in a
> couple of respects ( ie. not working 'as advertised' ), and
> if you're willing, I'd like to have a go at a couple of
> patches for it.
>
> Here's the list of things that I consider to be broken, based
> on the understandings that:
>
>
> A) the hierarchy should go:
>
> SystemCL
> | <-- LAYER 1
> lib/common CL
> / \ <-- LAYER 2
> lib/container lib/apps CL
> | <-- LAYER 3
> WEB-INF/lib << same CL, but with URLs
> WEB-INF/classes from both dirs, in this
> order...
>
>
> B) a classloader which failed to find a class
> will delegate to it's parent a'la JDK 2 style,
> with the delegation behaviour in:
> JDK 1.2+ java.net.URLClassLoader
> JDK 1.1 org.apache.tomcat.util.compat.SimpleClassLoader
>
>
>
Everything is right in your interpretation, but some historical insights
will be helpful, everything was done thinking on a quick restoration of
the old behaviour ( pre CL division ) .., more on that later
> List of broken behaviours:
>
>
> 1) LAYER 1 and LAYER 2 are broken ( do not delegate to parent )
>
>
> org.apache.tomcat.modules.config.ProfileLoader [ -r ]
>
>
> line 320: commonLoader is set to be its own parent, if there
> was previously a commonLoader, or the System
> CL if not.
>
>
> line 331: ( same, with appLoader )
>
>
> line 343: ( same, with containerLoader )
>
>
> this is also a potential memory leak after a while,
> if initClassLoaders() is called more than once.
>
>
Costin has explained ProfileLoader and TC33 out the box dont use it..
>
>
> 2) LAYER 3 bypasses straight to the System CL:
>
> there is a piece of code in
>
> org.apache.tomcat.modules.config.LoaderInterceptor11 [
>
> ( line 197 - 207 )
>
>
> if( useAL && !context.isTrusted() ) {
> if( debug > 0 ) log( "Using webapp loader " +
> context.isTrusted());
> parent=cm.getParentLoader();
> } else if( useNoParent ) {
> if( debug > 0 ) log( "Using no parent loader ");
> parent=null;
> } else {
> if( debug > 0 ) log( "Using container loader ");
> parent=this.getClass().getClassLoader();
> }
>
>
> I am not really sure why this piece of code is as it is.
>
> note:
>
> - useAL is set by setUseApplicationLoader( boolean ).
> I could find no callers of this method in the source,
> but the method is still public.
>
> - same story for useNoParent, which is set by
> setUseNoParent( boolean )
>
> - since useAL is initialised in the constructor
> to false, it would appear that if(1) is never called.
>
> - since useNoParent also defaults to false, it
> would appear that if(2) is never called
>
> - so it must always default to if(3), and this line
> does NOT gurarantee delegation to the
> container loader! ( expected
>
> Context.getContextManager().getContainerLoader()
>
> instead )
>
>
>
IF(3) can be considered the old escape path to the pre CL division
behaviour.., so a user can easily reverse the CL operation to the OLD
Behaviour.., call it Flexibility Syndrome :)
All that methods are called as a reaction to user configs called by
introspection by the XML Mapper ( aka Digester in commons ), all this
configs are on server.xml..
>
> 3) Inconsistent directory-scanning behaviours
>
> org.apache.tomcat.modules.config.ProfileLoader [ -r ]
>
> makes use of IntrospectionUtils, but
>
> orb.apache.tomcat.core.LoaderInterceptor11 [ -r ]
>
> does not ...
>
>
> as a result of this, there are different behaviours
> in classloading with respect to the recursion of
> directories.
>
>
Gotcha , you are right we can use IntrospectionUtils on
LoaderInterceptor..
>
>
> Here's a list of questions I need answered to make some improvements:
>
> 0) Are there good historical reasons why the above
> behaviours are as they are?
>
>
Well , my intention was only to clone TC4.0 behaviour without the
reversed CL delegation present on TC4.0..( a really hard thing ), so ask
the historical reasons to Craig, he knows more than me..:)
> 1) is it OK to not use the IntrospectionUtils when
> constructing classpaths? I find its API a little awkward. (
> Would factor out classpath-ish utilities into their own
> Class, deprecate existing classpath-ish methods on
> IntrospectionUtils ).
>
A patch is welcomed ..if you have an itch you can scratch it as you
want..
> 1b) assuming yes, what package should that class be placed into?
>
>
ughh . hard question..Costin has many good responses about package
naming..:)
>
> 2) is it OK to introduce the following new behaviour that
> allows the user to specify order in directories where
> classloading occurs?
>
> IF there is a file called 'classpath.properties' ( call
> it what you like ), in the root directory of a classpath
> location, or in any of its descended directories,
>
> AND that file contains a line
> 'org.apache.tomcat.classpath.order=<comma_separated_list_of_files>'
>
> THAT for each item in <comma_separated_list_of_files>
> which is actually an immediate child of the directory
> according to the filesystem, it is placed into the classpath
> in that particular order. Unorded entries would be appended
> to to the end of the list for that directory.
>
> [ I already have an implementation of this if anyone
> wants to see it first. Also, I am prepared to writup the
> user-documentation before actually doing it. ]
>
>
Only a curiosity about that , Why you need it ?, depending on classpath
ordering can be evil..as Costin has pointed out..
>
> 3) where is the appropriate place to put user-documentation
> about classloading behaviour?
>
:) , perhaps the src/docs directory ?.., all the help in documenting TC
3.3 is welcomed.., please do so and send it to tomcat-dev.. we will put
it where aproppiate.. :)
>
> 4) is there a test ( eg. JUnit test? ) or test-suite ( eg.
> WatchDog? ) or test web-app, that verifies contracts about
> classloading behaviour with respect to the Servlet 2.2 specification?
>
>
TC3.3 is tested by a combination of Watchdog and TC3.3 own testing
webapp.., and everything can be done trought a browser.., but to test
classloading behaviour can be hard.. try to look at the tester include
on HEAD branch.. to see how can you use it to test CL behavior .. i'm
courious about how this can be done ..
Saludos ,
Ignacio J. Ortega