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: Sat, 05 May 2007 06:02:53 +0800

Hi Sivakumar

I just revisit the enclosed issue and think that we can consider the
following :-

(1) GlassFish starts up with something like :
     
"-Dcom.sun.enterprise.server.logging.manager=com.sun.enterprise.server.logging.ServerLogManager"

    instead of
     
"-Djava.util.logging.manager=com.sun.enterprise.server.logging.ServerLogManager"


(2) GlassFish tries loading what is referenced by
"com.sun.enterprise.server.logging.manager", if successful, use it as
"java.util.logging.manager"

   try {
     cname = System.getProperty("com.sun.enterprise.server.logging.manager");
     if (cname != null) {
       Class clz = ClassLoader.getSystemClassLoader().loadClass(cname);
       manager = (LogManager) clz.newInstance();
     }
   } catch (Exception ex) {
     System.err.println("Could not load Logmanager \"" + cname + "\"");
     ex.printStackTrace();
   }
   if (manager == null) {
     manager = new LogManager();
   }

So that

(a) any application (e.g. AspectJ weaver applications) loaded in System
CL (without any visibility to GlassFish's classes) can still use JDK
Logging with its own designated LogManager

(b) GlassFish can use its own
com.sun.enterprise.server.logging.ServerLogManager

I guess this involves minimal code changes to GlassFish while solving
the enclosed problem we have.

What do you think? Which GlassFish sources are needed to be changed?

Thanks
Max


Max Poon wrote:
> 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.