dev@glassfish.java.net

Re: ClassNotFoundException for webapps loading classes by System CL specified via "-javaagent:" jvm-option (e.g. AspectJ LTW app)

From: Max Poon <maxpoon_at_dev.java.net>
Date: Thu, 15 Mar 2007 16:34:42 +0800

Hi Sivakumar

Thanks for your input! I've got it "working" by :

   1. specifying in domain.xml the <java-config> <jvm-option>
      "-Dorg.aspectj.tracing.factory=org.aspectj.weaver.tools.CommonsTraceFactory"
      - to tell aspectjweaver.jar (loaded in GF's System Class Loader)
      to use commons logging instead of GF's default log manager
      com.sun.enterprise.server.logging.ServerLogManager which is loaded
      in GF's Shared Chain Class Loader and hence not accessible from
      GF's System ClassLoader (hence the previously observed
      ClassNotFoundException).
   2. adding locations of commons-logging-1.1.jar and log4j-1.2.14.jar
      to GF's system classpath
      - so that Commons Logging can see Log4j before looking for and
      then using JDK1.4 Logging (which then tries to load
      com.sun.enterprise.server.logging.ServerLogManager and throws the
      ClassNotFoundException, as per testing)

To summarise, as aspectjweaver.jar has to be specified via "-javaagent:"
jvm option and loaded via System Class Loader, make the classes in
aspectjweaver.jar access alternative logging accessible from the System
Class Loader, instead of GF's default log manager
com.sun.enterprise.server.logging.ServerLogManager.

This approach may be applicable to other AspectJ applications (with
classes required to be accessed directly by AspectJ's Load-Time Weaver)
running on GlassFish, given that those classes are/can be packaged in
known jar files to be included in GF's System Classpath.

Not sure whether this is the best approach. Any better
idea/solution/comment much welcome.

Actually, I have been trying to have GlassBox Inspector running on
GlassFish (v1 & v2), and would like to thank you as well as Ron Bodkin
of GlassBox (cc'ed) for all the input and help.

Thanks
Max


Sivakumar Thyagarajan wrote:
> Hi Max
>
> Responses inline. Thanks.
>
> --Siva.
>
> Max Poon wrote:
>> Hi Sivakumar
>>
>> Thanks! Some comments on your suggestions :
>>
>> 1) Putting required logger classes/jar in web app - This seems not
>> helping as the problem is on accessing classes loaded by the children
>> class loaders (CL) from the System CL (via "-javaagent:" jvm option),
>> not from the Web CL or App CL. Kindly advise if I understand correctly.
>
> Probably I should have been a bit more clearer. I was suggesting
> bundling the LogManager classes along with aspectjweaver.jar you
> specify in the -javaagent option. That way the logManager would also
> be loaded as part of the system classloader and AspectJ runtime would
> be able to load the LogManager.
>
>>
>> 2) I just notice : it seems that Application Class Loader (CL) is
>> involved in the exception causing execution stack:
>>
>> Could not load Logmanager
>> "com.sun.enterprise.server.logging.ServerLogManager"
>> java.lang.ClassNotFoundException:
>> com.sun.enterprise.server.logging.ServerLogManager
>> ...
>> at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
>> at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:276)
>> at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
>> ...
>> at org.aspectj.weaver.loadtime.Agent.<clinit>(Agent.java:33)*
>>
>> Questions:
>>
>> (a) as the "-javaagent:<aspectjweaver.jar>" jvm option requires
>> loading by System CL, why is AppCL involved?
>
> The name is probably a misnomer [or probably confusing in a J2EE
> appserver context]. It is not ApplicationClassLoader [as in J2EE
> application classloader] but sun.misc.Launcher$AppClassLoader. This is
> the Sun JVM's representation of what is referred to as the System
> classloader.
>
>>
>> (b) if AppCL is used, then GlassFish should be able to load
>> com.sun.enterprise.server.logging.ServerLogManager (in
>> appserv-rt.jar) via delegating up to the Shared Chain CL per
>> GlassFish default behavior. Then, why was the above exception thrown?
>>
>
> Hope the explanation above helps. It is system classloader and so the
> ServerLogManager is not visible to that classloader as it loaded below
> in the hierarchy.
>
>
>> Thanks again!
>> Max
>>
>>
>> Sivakumar Thyagarajan wrote:
>>> Hi Max
>>>
>>> > _Questions
>>> ..
>>> >
>>> > 1. how can we have the classes specified via *-javaagent:* able to
>>> > load those classes (e.g. in Shared Chain CL) available lower
>>> down
>>> > in the CL hierarchy (coz' it may not be feasible to put
>>> everything
>>> > in System CL) ?
>>>
>>> As you have mentioned already in your analysis, this is because
>>> aspectjweaver loaded by the system classloader cannot see classes
>>> loaded lower in the hierarchy such as the Logging Manager and AFAIK
>>> there is no easy fix for this.
>>>
>>> No easy fix because the static block at java.util.logging.LogManager
>>> tries to load using both the SystemClassLoader and the Thread
>>> context classloader (which at the time of initialization of the
>>> PreMain class is not set to a classloader that can load the
>>> specified loggingmanager) and both would not be able to load the
>>> loggingmanager.
>>>
>>> Unfortunately, while we did the earlier classloader changes in
>>> GlassFish v1, we tried to move our logging manager
>>> [com.sun.enterprise.server.logging.ServerLogManager] higher up in
>>> the hierarchy [to be placed with appserv-launch.jar] but it had
>>> dependencies on a whole lot of other appserv-rt.jar classes and
>>> hence couldn't get this out.
>>>
>>> Possible Workarounds:
>>> - I don't have the soruces for Aj/JDK14Trace. Is there a way to
>>> disable AspectJWeaver logging? ie an option to not have this done at
>>> all
>>>> at java.util.logging.Logger.getLogger(Logger.java:274)
>>>> at org.aspectj.weaver.tools.Jdk14Trace.<init>(Jdk14Trace.java:25)
>>>> at
>>>> org.aspectj.weaver.tools.Jdk14TraceFactory.getTrace(Jdk14TraceFactory.java:17)
>>>>
>>>> at org.aspectj.weaver.loadtime.Aj.<clinit>(Aj.java:32)
>>> If yes, we could use that as a temproary workaround
>>>
>>> - AspectJ weaving using WeavingURLClassLoader.
>>>
>>> - use a custom server log Manager. I know this is not supported but
>>> if the custom log manager is bundled with the aspectjweaver class or
>>> specified in the system classpath this would help aspectjweaver to
>>> continue to load.
>>>
>>> If none of these help, someone from the admin team could let us know
>>> if it would be possible to separate out our LoggingManager, so that
>>> this could be moved higher up in the classloader hierarchy.
>>>
>>> > 2. can we override *java.util.logging.manager* within
>>> > context/execution of our web apps (vs that set during glassfish
>>> > initialisation) so it points to something available with the
>>> web
>>> > apps (e.g. apache commons logging, log4J, etc) ?
>>>
>>> For log4j style configuration for a web app, does this help?
>>> https://glassfish.dev.java.net/servlets/ReadMsg?list=users&msgNo=590
>>>
>>> > Adding to domain.xml the jvm-option :
>>> >
>>> > * -Dcom.sun.aas.useNewClassLoader=false
>>> >
>>> > to try to disable the new Shared Chain Class Loader does not seem
>>> to help.
>>>
>>> This was more of a internal temporary flag we introduced during
>>> GlassFish v1 days. This may be broken. I shall check this. If this
>>> is fixed, this would be a workaround as well :)
>>>
>>> Thanks
>>> --Siva.