Tuesday, February 14, 2012

Class Loader Hierarchy Of An Application On Weblogic Server

Some Background Knowledge About the Java Class Loaders

When the JVM is started, three class loaders are used:

  1. Bootstrap class loader
  2. Extensions class loader
  3. System class loader

The bootstrap class loader loads the core Java libraries located in the <JAVA_HOME>/jre/lib directory. This class loader, which is part of the core JVM, is written in native code.

The extensions class loader loads the code in the extensions directories (<JAVA_HOME>/jre/lib/ext, or any other directory specified by the java.ext.dirs system property). It is implemented by the sun.misc.Launcher$ExtClassLoader class.

The system class loader loads code found on java.class.path, which maps to the CLASSPATH environment variable. This is implemented by the sun.misc.Launcher$AppClassLoader class.

The Weblogic Server and Application Configuration

This is weblogic 10.3.2. The application is deployed to the myAppwls10loc domain. There is a startup class for the domain. The domain lib directory has a jar jt400.jar.
In the command startWeblogic.cmd, two additional jars are put onto the classpath:
set CLASSPATH=C:\workshop\myclient.jar; %MAVEN_HOME%\oracle\jars\aqapi-9.0.2.jar ;%CLASSPATH%
The application is an ear. It has two modules: a war and an ejb jar. The ear has the following layout:
APP-INF
  classes
  lib
    x.jar
META-INF
myejb.jar
mywar.war

In summary, the results are the following.
  1. The classes in myclient.jar ( used by the startup class ) are loaded with the following hierarchy:
    |
    sun.misc.Launcher$ExtClassLoader@19134f4
    |
    sun.misc.Launcher$AppClassLoader@47858e
    

  2. The classes in APP-INF/lib/x.jar and the classes in myejb.jar are loaded with the following hirearchy (NOTE: their context class loaders are different though):
    |
    sun.misc.Launcher$ExtClassLoader@19134f4
     |
    sun.misc.Launcher$AppClassLoader@47858e
     |
    java.net.URLClassLoader@164dbd5
     |
    weblogic.utils.classloaders.GenericClassLoader@1db6942
     |
    weblogic.utils.classloaders.FilteringClassLoader@11f9cee
     |
    weblogic.utils.classloaders.GenericClassLoader@f8d6a6
    

  3. Add the code to print the class loader hierarchy in the jsp file in mywar.war. The output is the following:
    |
    sun.misc.Launcher$ExtClassLoader@19134f4
     |
    sun.misc.Launcher$AppClassLoader@47858e
     |
    java.net.URLClassLoader@164dbd5
     |
    weblogic.utils.classloaders.GenericClassLoader@1db6942
     |
    weblogic.utils.classloaders.FilteringClassLoader@11f9cee
     |
    weblogic.utils.classloaders.GenericClassLoader@f8d6a6
     |
    weblogic.utils.classloaders.ChangeAwareClassLoader@17b51e8
     |
    weblogic.servlet.jsp.TagFileClassLoader@18d70a6
     |
    weblogic.servlet.jsp.JspClassLoader@a3af1c
    
    You can see that this is a child class loader of the class loader that loads the classes in myejb.jar and x.jar.

Below are more details. In the following log file, the class SampleBo is in a jar that resides in the directory APP-INF/lib directory. And the class XyzMessageHandlerImpl is in myejb.jar.

The following functions are used to print out the classloader tree:

private void printClassloaders(Class clazz) {
  ClassLoader classLoader = clazz.getClassLoader();
  System.out.println("==============================");
  System.out.println("Class name:" + clazz.getName());
  printCLtree(classLoader, "");
  System.out
    .println("Thread.currentThread().getClass().getClassLoader():");
  ClassLoader cl = Thread.currentThread().getClass().getClassLoader();
  printCLtree(cl, "");
  System.out.println("==============================");
 }

 private void printCLtree(ClassLoader cl, String indent) {
  if (cl == null) {
   return;
  }
  System.out.println(indent + "ClassLoader=" + cl);
  ClassLoader pcl = cl.getParent();
  if (pcl == null) {
   System.out.println(indent + "  ClassLoader=" + pcl);
  } else {
   printCLtree(pcl, indent + "  ");
  }
 }

 public static void printClassLoaderHierarchy(Class c) {
  ClassLoader cl = c.getClassLoader();
  System.out.println("___________________START_______________________");
  System.out.println("\nClass loader tree");
  printClassLoaderTree(cl);
  System.out.println("\nContext loader tree");
  ClassLoader l = Thread.currentThread().getContextClassLoader();
  printClassLoaderTree(l);
  System.out.println("____________________END_______________________");
 }

 public static void printClassLoaderTree(ClassLoader l) {
  ClassLoader p = l.getParent();
  if (p != null)
   printClassLoaderTree(p);
  String u = "";
  if (l instanceof URLClassLoader)
   u = getURLs(((URLClassLoader) l).getURLs());
  System.out.println((new StringBuilder("\t|\n")).append(l).append(" ")
    .append(u).toString());
 }

 public static String getURLs(URL urls[]) {
  if (urls == null)
   return "{}";
  StringBuffer b = new StringBuffer("{");
  for (int i = 0; i < urls.length; i++)
   b.append(urls[i]).append(":");

  b.append("}");
  return b.toString();
 }



The following is the log file:

.
.
JAVA Memory arguments: -Xms256m -Xmx512m -XX:CompileThreshold=8000 -XX:PermSize=48m  -XX:MaxPermSize=128m
.
WLS Start Mode=Development
.
CLASSPATH=C:\workshop\myclient.jar; C:/workspace/maven \oracle\jars\aqapi-9.0.2.jar ;C:\bea1032\patch_wls1032\profiles\default\sys_manifest_classpath\weblogic_patch.jar;C:\bea1032\patch_oepe1032\profiles\default\sys_manifest_classpath\weblogic_patch.jar;C:\bea1032\JDK160~1.5-3\lib\tools.jar;C:\bea1032\utils\config\10.3\config-launch.jar;C:\bea1032\WLSERV~1.3\server\lib\weblogic_sp.jar;C:\bea1032\WLSERV~1.3\server\lib\weblogic.jar;C:\bea1032\modules\features\weblogic.server.modules_10.3.2.0.jar;C:\bea1032\WLSERV~1.3\server\lib\webservices.jar;C:\bea1032\modules\ORGAPA~1.0/lib/ant-all.jar;C:\bea1032\modules\NETSFA~1.0_1/lib/ant-contrib.jar;C:\bea1032\WLSERV~1.3\common\eval\pointbase\lib\pbclient57.jar;C:\bea1032\WLSERV~1.3\server\lib\xqrl.jar
.
PATH=C:\bea1032\patch_wls1032\profiles\default\native;C:\bea1032\patch_oepe1032\profiles\default\native;C:\bea1032\WLSERV~1.3\server\native\win\32;C:\bea1032\WLSERV~1.3\server\bin;C:\bea1032\modules\ORGAPA~1.0\bin;C:\bea1032\JDK160~1.5-3\jre\bin;C:\bea1032\JDK160~1.5-3\bin;C:\bea1032\jrockit_160_14_R27.6.5-32\jre\bin;C:\Program Files\CA\SC\CAWIN\;C:\PROGRA~1\CA\SC\ETPKI\lib;C:\Program Files\Java\jdk1.6.0_14\bin;C:\Program Files\JavaFX\javafx-sdk1.3\bin;C:\Program Files\JavaFX\javafx-sdk1.3\emulator\bin;C:\Program Files\JavaFX\javafx-sdk1.2\bin;C:\Program Files\JavaFX\javafx-sdk1.2\emulator\bin;C:\Perl\site\bin;C:\Perl\bin;C:\ant\apache-ant-1.7.1\bin;C:\notes\;C:\notes\data\;C:\oracle\ora90\bin;C:\Program Files\Oracle\jre\1.1.8\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\Program Files\Common Files\Autodesk Shared\;C:\Program Files\Intel\DMIX;C:\Program Files\Common Files\Roxio Shared\DLLShared\;C:\apache-maven-2.2.1\bin;C:\JavaKit\j3d\bin;C:\Program Files\Borland\CaliberRM SDK 2008\lib;;C:\Program Files\SEAGULL\BlueZone\;C:\PROGRA~1\CA\SC\CAM\bin;C:\Program Files\CA\DSM\bin;C:\Program Files\CA\SC\Csam\SockAdapter\\bin;C:\Program Files\Enterprise Vault\EVClient\;C:\WINDOWS\system32\WindowsPowerShell\v1.0;C:\Program Files\Subversion\bin;C:\Program Files\SSH Communications Security\SSH Secure Shell;C:\bea1032\WLSERV~1.3\server\native\win\32\oci920_8
.
***************************************************
*  To start WebLogic Server, use a username and   *
*  password assigned to an admin-level user.  For *
*  server administration, use the WebLogic Server *
*  console at http:\\hostname:port\console        *
***************************************************
starting weblogic with Java version:
java version "1.6.0_14"
Java(TM) SE Runtime Environment (build 1.6.0_14-b08)
Java HotSpot(TM) Client VM (build 14.0-b16, mixed mode)
Starting WLS with line:
C:\bea1032\JDK160~1.5-3\bin\java -client   -Xms256m -Xmx512m -XX:CompileThreshold=8000 -XX:PermSize=48m  -XX:MaxPermSize=128m -Dweblogic.Name=myAppAdminServer -Djava.security.policy=C:\bea1032\WLSERV~1.3\server\lib\weblogic.policy  -Xverify:none  -da -Dplatform.home=C:\bea1032\WLSERV~1.3 -Dwls.home=C:\bea1032\WLSERV~1.3\server -Dweblogic.home=C:\bea1032\WLSERV~1.3\server   -Dweblogic.management.discover=true  -Dwlw.iterativeDev= -Dwlw.testConsole= -Dwlw.logErrorsToConsole= -Dweblogic.ext.dirs=C:\bea1032\patch_wls1032\profiles\default\sysext_manifest_classpath;C:\bea1032\patch_oepe1032\profiles\default\sysext_manifest_classpath  weblogic.Server
<Feb 14, 2012 10:01:54 AM EST> <Notice> <WebLogicServer> <BEA-000395> <Following extensions directory contents added to the end of the classpath:
C:\bea1032\user_projects\domains\myAppwls10loc\lib\jt400.jar> 
<Feb 14, 2012 10:01:54 AM EST> <Info> <WebLogicServer> <BEA-000377> <Starting WebLogic Server with Java HotSpot(TM) Client VM Version 14.0-b16 from Sun Microsystems Inc.> 
<Feb 14, 2012 10:01:55 AM EST> <Info> <Management> <BEA-141107> <Version: WebLogic Server 10.3.2.0  Tue Oct 20 12:16:15 PDT 2009 1267925 > 
<Feb 14, 2012 10:01:58 AM EST> <Notice> <WebLogicServer> <BEA-000365> <Server state changed to STARTING> 
<Feb 14, 2012 10:01:58 AM EST> <Info> <WorkManager> <BEA-002900> <Initializing self-tuning thread pool> 
<Feb 14, 2012 10:01:59 AM EST> <Notice> <LoggingService> <BEA-320400> <The log file C:\bea1032\user_projects\domains\myAppwls10loc\servers\myAppAdminServer\logs\myAppAdminServer.log will be rotated. Reopen the log file if tailing has stopped. This can happen on some platforms like Windows.> 
<Feb 14, 2012 10:01:59 AM EST> <Notice> <LoggingService> <BEA-320401> <The log file has been rotated to C:\bea1032\user_projects\domains\myAppwls10loc\servers\myAppAdminServer\logs\myAppAdminServer.log00138. Log messages will continue to be logged in C:\bea1032\user_projects\domains\myAppwls10loc\servers\myAppAdminServer\logs\myAppAdminServer.log.> 
<Feb 14, 2012 10:01:59 AM EST> <Notice> <Log Management> <BEA-170019> <The server log file C:\bea1032\user_projects\domains\myAppwls10loc\servers\myAppAdminServer\logs\myAppAdminServer.log is opened. All server side log events will be written to this file.> 
<Feb 14, 2012 10:02:07 AM EST> <Notice> <Security> <BEA-090082> <Security initializing using security realm myrealm.> 
<Feb 14, 2012 10:02:11 AM EST> <Notice> <LoggingService> <BEA-320400> <The log file C:\bea1032\user_projects\domains\myAppwls10loc\servers\myAppAdminServer\logs\access.log will be rotated. Reopen the log file if tailing has stopped. This can happen on some platforms like Windows.> 
<Feb 14, 2012 10:02:11 AM EST> <Notice> <LoggingService> <BEA-320401> <The log file has been rotated to C:\bea1032\user_projects\domains\myAppwls10loc\servers\myAppAdminServer\logs\access.log00080. Log messages will continue to be logged in C:\bea1032\user_projects\domains\myAppwls10loc\servers\myAppAdminServer\logs\access.log.> 
TimerStartUp static block

Class loader tree
 |
sun.misc.Launcher$ExtClassLoader@19134f4 {
file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/dnsns.jar:
file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/localedata.jar:
file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunjce_provider.jar:
file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunmscapi.jar:
file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunpkcs11.jar:}
 |
sun.misc.Launcher$AppClassLoader@47858e {
file:/C:/workshop/myclient.jar:
file:/C:/bea1032/user_projects/domains/myAppwls10loc/%20C:/workspace/maven%20/oracle/jars/aqapi-9.0.2.jar%20:
file:/C:/bea1032/patch_wls1032/profiles/default/sys_manifest_classpath/weblogic_patch.jar:
file:/C:/bea1032/patch_oepe1032/profiles/default/sys_manifest_classpath/weblogic_patch.jar:
file:/C:/bea1032/jdk160_14_R27.6.5-32/lib/tools.jar:
file:/C:/bea1032/utils/config/10.3/config-launch.jar:
file:/C:/bea1032/wlserver_10.3/server/lib/weblogic_sp.jar:
file:/C:/bea1032/wlserver_10.3/server/lib/weblogic.jar:
file:/C:/bea1032/modules/features/weblogic.server.modules_10.3.2.0.jar:
file:/C:/bea1032/wlserver_10.3/server/lib/webservices.jar:
file:/C:/bea1032/modules/org.apache.ant_1.7.0/lib/ant-all.jar:
file:/C:/bea1032/modules/net.sf.antcontrib_1.0.0.0_1-0b2/lib/ant-contrib.jar:
file:/C:/bea1032/wlserver_10.3/common/eval/pointbase/lib/pbclient57.jar:
file:/C:/bea1032/wlserver_10.3/server/lib/xqrl.jar:}

Context loader tree
 |
sun.misc.Launcher$ExtClassLoader@19134f4 {
file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/dnsns.jar:
file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/localedata.jar:
file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunjce_provider.jar:
file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunmscapi.jar:
file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunpkcs11.jar:}
 |
sun.misc.Launcher$AppClassLoader@47858e {
file:/C:/workshop/myclient.jar:
file:/C:/bea1032/user_projects/domains/myAppwls10loc/%20C:/workspace/maven%20/oracle/jars/aqapi-9.0.2.jar%20:
file:/C:/bea1032/patch_wls1032/profiles/default/sys_manifest_classpath/weblogic_patch.jar:
file:/C:/bea1032/patch_oepe1032/profiles/default/sys_manifest_classpath/weblogic_patch.jar:
file:/C:/bea1032/jdk160_14_R27.6.5-32/lib/tools.jar:
file:/C:/bea1032/utils/config/10.3/config-launch.jar:
file:/C:/bea1032/wlserver_10.3/server/lib/weblogic_sp.jar:
file:/C:/bea1032/wlserver_10.3/server/lib/weblogic.jar:
file:/C:/bea1032/modules/features/weblogic.server.modules_10.3.2.0.jar:
file:/C:/bea1032/wlserver_10.3/server/lib/webservices.jar:
file:/C:/bea1032/modules/org.apache.ant_1.7.0/lib/ant-all.jar:
file:/C:/bea1032/modules/net.sf.antcontrib_1.0.0.0_1-0b2/lib/ant-contrib.jar:
file:/C:/bea1032/wlserver_10.3/common/eval/pointbase/lib/pbclient57.jar:
file:/C:/bea1032/wlserver_10.3/server/lib/xqrl.jar:}
 |
java.net.URLClassLoader@164dbd5 {
file:/C:/bea1032/user_projects/domains/myAppwls10loc/lib/jt400.jar:}

Tue Feb 14 10:02:11 EST 2012; INFO: binding to jnditree [t3://localhost:7001]
Tue Feb 14 10:02:11 EST 2012; INFO: binding fakequeue [App1Queue] as [javax.naming.InitialContext@1fd9726]
Tue Feb 14 10:02:11 EST 2012; INFO: timeout set [100] to [javax.naming.InitialContext@1fd9726]
Tue Feb 14 10:02:11 EST 2012; INFO: create queueconnection [timeout=100] as [com.myapp.messaging.aq.qfc.FakeQueueConnectionFactory@e0c07c]
Tue Feb 14 10:02:11 EST 2012INFO:  start connection[null] closed[false]
Tue Feb 14 10:02:11 EST 2012; INFO: binding fakefactory [App1ConnectionFactory] as [com.myapp.messaging.aq.qfc.FakeQueueConnectionFactory@e0c07c]
Tue Feb 14 10:02:11 EST 2012; INFO: creating fakeconnct [] as [com.myapp.messaging.aq.qfc.FakeQueueConnection@18a8bfasession=nullclosed=falsesession_list=0]
Tue Feb 14 10:02:11 EST 2012; INFO: TimerStartup [finished]
<Feb 14, 2012 10:02:16 AM EST> <Notice> <WebLogicServer> <BEA-000365> <Server state changed to STANDBY> 
<Feb 14, 2012 10:02:16 AM EST> <Notice> <WebLogicServer> <BEA-000365> <Server state changed to STARTING> 
==============================
Class name:com.myapp.business.sample.SampleBo
ClassLoader=weblogic.utils.classloaders.GenericClassLoader@f8d6a6 finder: weblogic.utils.classloaders.CodeGenClassFinder@8f53c8 annotation: myApp@
  ClassLoader=weblogic.utils.classloaders.FilteringClassLoader@11f9cee finder: weblogic.utils.classloaders.CodeGenClassFinder@77e77a annotation: 
    ClassLoader=weblogic.utils.classloaders.GenericClassLoader@1db6942 finder: weblogic.utils.classloaders.CodeGenClassFinder@1fe2c10 annotation: 
      ClassLoader=java.net.URLClassLoader@164dbd5
        ClassLoader=sun.misc.Launcher$AppClassLoader@47858e
          ClassLoader=sun.misc.Launcher$ExtClassLoader@19134f4
            ClassLoader=null
Thread.currentThread().getClass().getClassLoader():
ClassLoader=sun.misc.Launcher$AppClassLoader@47858e
  ClassLoader=sun.misc.Launcher$ExtClassLoader@19134f4
    ClassLoader=null
==============================
___________________START_______________________

Class loader tree
 |
sun.misc.Launcher$ExtClassLoader@19134f4 {file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/dnsns.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/localedata.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunjce_provider.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunmscapi.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunpkcs11.jar:}
 |
sun.misc.Launcher$AppClassLoader@47858e {file:/C:/workshop/myclient.jar:file:/C:/bea1032/user_projects/domains/myAppwls10loc/%20C:/workspace/maven%20/oracle/jars/aqapi-9.0.2.jar%20:file:/C:/bea1032/patch_wls1032/profiles/default/sys_manifest_classpath/weblogic_patch.jar:file:/C:/bea1032/patch_oepe1032/profiles/default/sys_manifest_classpath/weblogic_patch.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/lib/tools.jar:file:/C:/bea1032/utils/config/10.3/config-launch.jar:file:/C:/bea1032/wlserver_10.3/server/lib/weblogic_sp.jar:file:/C:/bea1032/wlserver_10.3/server/lib/weblogic.jar:file:/C:/bea1032/modules/features/weblogic.server.modules_10.3.2.0.jar:file:/C:/bea1032/wlserver_10.3/server/lib/webservices.jar:file:/C:/bea1032/modules/org.apache.ant_1.7.0/lib/ant-all.jar:file:/C:/bea1032/modules/net.sf.antcontrib_1.0.0.0_1-0b2/lib/ant-contrib.jar:file:/C:/bea1032/wlserver_10.3/common/eval/pointbase/lib/pbclient57.jar:file:/C:/bea1032/wlserver_10.3/server/lib/xqrl.jar:}
 |
java.net.URLClassLoader@164dbd5 {file:/C:/bea1032/user_projects/domains/myAppwls10loc/lib/jt400.jar:}
 |
weblogic.utils.classloaders.GenericClassLoader@1db6942 finder: weblogic.utils.classloaders.CodeGenClassFinder@1fe2c10 annotation:  
 |
weblogic.utils.classloaders.FilteringClassLoader@11f9cee finder: weblogic.utils.classloaders.CodeGenClassFinder@77e77a annotation:  
 |
weblogic.utils.classloaders.GenericClassLoader@f8d6a6 finder: weblogic.utils.classloaders.CodeGenClassFinder@8f53c8 annotation: myApp@ 

Context loader tree
 |
sun.misc.Launcher$ExtClassLoader@19134f4 {file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/dnsns.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/localedata.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunjce_provider.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunmscapi.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunpkcs11.jar:}
 |
sun.misc.Launcher$AppClassLoader@47858e {file:/C:/workshop/myclient.jar:file:/C:/bea1032/user_projects/domains/myAppwls10loc/%20C:/workspace/maven%20/oracle/jars/aqapi-9.0.2.jar%20:file:/C:/bea1032/patch_wls1032/profiles/default/sys_manifest_classpath/weblogic_patch.jar:file:/C:/bea1032/patch_oepe1032/profiles/default/sys_manifest_classpath/weblogic_patch.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/lib/tools.jar:file:/C:/bea1032/utils/config/10.3/config-launch.jar:file:/C:/bea1032/wlserver_10.3/server/lib/weblogic_sp.jar:file:/C:/bea1032/wlserver_10.3/server/lib/weblogic.jar:file:/C:/bea1032/modules/features/weblogic.server.modules_10.3.2.0.jar:file:/C:/bea1032/wlserver_10.3/server/lib/webservices.jar:file:/C:/bea1032/modules/org.apache.ant_1.7.0/lib/ant-all.jar:file:/C:/bea1032/modules/net.sf.antcontrib_1.0.0.0_1-0b2/lib/ant-contrib.jar:file:/C:/bea1032/wlserver_10.3/common/eval/pointbase/lib/pbclient57.jar:file:/C:/bea1032/wlserver_10.3/server/lib/xqrl.jar:}
 |
java.net.URLClassLoader@164dbd5 {file:/C:/bea1032/user_projects/domains/myAppwls10loc/lib/jt400.jar:}
 |
weblogic.utils.classloaders.GenericClassLoader@1db6942 finder: weblogic.utils.classloaders.CodeGenClassFinder@1fe2c10 annotation:  
 |
weblogic.utils.classloaders.FilteringClassLoader@11f9cee finder: weblogic.utils.classloaders.CodeGenClassFinder@77e77a annotation:  
 |
weblogic.utils.classloaders.GenericClassLoader@f8d6a6 finder: weblogic.utils.classloaders.CodeGenClassFinder@8f53c8 annotation: myApp@ 
 |
weblogic.utils.classloaders.ChangeAwareClassLoader@17b51e8 finder: weblogic.utils.classloaders.CodeGenClassFinder@1ad65f7 annotation: myApp@myApp 
____________________END_______________________
==============================
Class name:com.myapp.business.sample.SampleBo
ClassLoader=weblogic.utils.classloaders.GenericClassLoader@f8d6a6 finder: weblogic.utils.classloaders.CodeGenClassFinder@8f53c8 annotation: myApp@
  ClassLoader=weblogic.utils.classloaders.FilteringClassLoader@11f9cee finder: weblogic.utils.classloaders.CodeGenClassFinder@77e77a annotation: 
    ClassLoader=weblogic.utils.classloaders.GenericClassLoader@1db6942 finder: weblogic.utils.classloaders.CodeGenClassFinder@1fe2c10 annotation: 
      ClassLoader=java.net.URLClassLoader@164dbd5
        ClassLoader=sun.misc.Launcher$AppClassLoader@47858e
          ClassLoader=sun.misc.Launcher$ExtClassLoader@19134f4
            ClassLoader=null
Thread.currentThread().getClass().getClassLoader():
ClassLoader=sun.misc.Launcher$AppClassLoader@47858e
  ClassLoader=sun.misc.Launcher$ExtClassLoader@19134f4
    ClassLoader=null
==============================
___________________START_______________________

Class loader tree
 |
sun.misc.Launcher$ExtClassLoader@19134f4 {file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/dnsns.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/localedata.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunjce_provider.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunmscapi.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunpkcs11.jar:}
 |
sun.misc.Launcher$AppClassLoader@47858e {file:/C:/workshop/myclient.jar:file:/C:/bea1032/user_projects/domains/myAppwls10loc/%20C:/workspace/maven%20/oracle/jars/aqapi-9.0.2.jar%20:file:/C:/bea1032/patch_wls1032/profiles/default/sys_manifest_classpath/weblogic_patch.jar:file:/C:/bea1032/patch_oepe1032/profiles/default/sys_manifest_classpath/weblogic_patch.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/lib/tools.jar:file:/C:/bea1032/utils/config/10.3/config-launch.jar:file:/C:/bea1032/wlserver_10.3/server/lib/weblogic_sp.jar:file:/C:/bea1032/wlserver_10.3/server/lib/weblogic.jar:file:/C:/bea1032/modules/features/weblogic.server.modules_10.3.2.0.jar:file:/C:/bea1032/wlserver_10.3/server/lib/webservices.jar:file:/C:/bea1032/modules/org.apache.ant_1.7.0/lib/ant-all.jar:file:/C:/bea1032/modules/net.sf.antcontrib_1.0.0.0_1-0b2/lib/ant-contrib.jar:file:/C:/bea1032/wlserver_10.3/common/eval/pointbase/lib/pbclient57.jar:file:/C:/bea1032/wlserver_10.3/server/lib/xqrl.jar:}
 |
java.net.URLClassLoader@164dbd5 {file:/C:/bea1032/user_projects/domains/myAppwls10loc/lib/jt400.jar:}
 |
weblogic.utils.classloaders.GenericClassLoader@1db6942 finder: weblogic.utils.classloaders.CodeGenClassFinder@1fe2c10 annotation:  
 |
weblogic.utils.classloaders.FilteringClassLoader@11f9cee finder: weblogic.utils.classloaders.CodeGenClassFinder@77e77a annotation:  
 |
weblogic.utils.classloaders.GenericClassLoader@f8d6a6 finder: weblogic.utils.classloaders.CodeGenClassFinder@8f53c8 annotation: myApp@ 

Context loader tree
 |
sun.misc.Launcher$ExtClassLoader@19134f4 {file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/dnsns.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/localedata.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunjce_provider.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunmscapi.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunpkcs11.jar:}
 |
sun.misc.Launcher$AppClassLoader@47858e {file:/C:/workshop/myclient.jar:file:/C:/bea1032/user_projects/domains/myAppwls10loc/%20C:/workspace/maven%20/oracle/jars/aqapi-9.0.2.jar%20:file:/C:/bea1032/patch_wls1032/profiles/default/sys_manifest_classpath/weblogic_patch.jar:file:/C:/bea1032/patch_oepe1032/profiles/default/sys_manifest_classpath/weblogic_patch.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/lib/tools.jar:file:/C:/bea1032/utils/config/10.3/config-launch.jar:file:/C:/bea1032/wlserver_10.3/server/lib/weblogic_sp.jar:file:/C:/bea1032/wlserver_10.3/server/lib/weblogic.jar:file:/C:/bea1032/modules/features/weblogic.server.modules_10.3.2.0.jar:file:/C:/bea1032/wlserver_10.3/server/lib/webservices.jar:file:/C:/bea1032/modules/org.apache.ant_1.7.0/lib/ant-all.jar:file:/C:/bea1032/modules/net.sf.antcontrib_1.0.0.0_1-0b2/lib/ant-contrib.jar:file:/C:/bea1032/wlserver_10.3/common/eval/pointbase/lib/pbclient57.jar:file:/C:/bea1032/wlserver_10.3/server/lib/xqrl.jar:}
 |
java.net.URLClassLoader@164dbd5 {file:/C:/bea1032/user_projects/domains/myAppwls10loc/lib/jt400.jar:}
 |
weblogic.utils.classloaders.GenericClassLoader@1db6942 finder: weblogic.utils.classloaders.CodeGenClassFinder@1fe2c10 annotation:  
 |
weblogic.utils.classloaders.FilteringClassLoader@11f9cee finder: weblogic.utils.classloaders.CodeGenClassFinder@77e77a annotation:  
 |
weblogic.utils.classloaders.GenericClassLoader@f8d6a6 finder: weblogic.utils.classloaders.CodeGenClassFinder@8f53c8 annotation: myApp@ 
 |
weblogic.utils.classloaders.ChangeAwareClassLoader@17b51e8 finder: weblogic.utils.classloaders.CodeGenClassFinder@1ad65f7 annotation: myApp@myApp 
____________________END_______________________
<Feb 14, 2012 10:02:54 AM EST> <Notice> <LoggingService> <BEA-320400> <The log file C:\bea1032\user_projects\domains\myAppwls10loc\servers\myAppAdminServer\logs\myAppwls10loc.log will be rotated. Reopen the log file if tailing has stopped. This can happen on some platforms like Windows.> 
<Feb 14, 2012 10:02:54 AM EST> <Notice> <LoggingService> <BEA-320401> <The log file has been rotated to C:\bea1032\user_projects\domains\myAppwls10loc\servers\myAppAdminServer\logs\myAppwls10loc.log00095. Log messages will continue to be logged in C:\bea1032\user_projects\domains\myAppwls10loc\servers\myAppAdminServer\logs\myAppwls10loc.log.> 
<Feb 14, 2012 10:02:54 AM EST> <Notice> <Log Management> <BEA-170027> <The Server has established connection with the Domain level Diagnostic Service successfully.> 
<Feb 14, 2012 10:02:54 AM EST> <Notice> <WebLogicServer> <BEA-000365> <Server state changed to ADMIN> 
<Feb 14, 2012 10:02:54 AM EST> <Notice> <WebLogicServer> <BEA-000365> <Server state changed to RESUMING> 
<Feb 14, 2012 10:02:54 AM EST> <Notice> <Server> <BEA-002613> <Channel "Default" is now listening on 10.77.121.138:7001 for protocols iiop, t3, ldap, snmp, http.> 
<Feb 14, 2012 10:02:54 AM EST> <Notice> <Server> <BEA-002613> <Channel "Default[1]" is now listening on 127.0.0.1:7001 for protocols iiop, t3, ldap, snmp, http.> 
<Feb 14, 2012 10:02:54 AM EST> <Notice> <WebLogicServer> <BEA-000331> <Started WebLogic Admin Server "myAppAdminServer" for domain "myAppwls10loc" running in Development Mode> 
Tue Feb 14 10:02:56 EST 2012; INFO: create queueconnection [timeout=100] as [com.myapp.messaging.aq.qfc.FakeQueueConnectionFactory@1620d83]
==============================
Class name:com.myapp.messaging.aq.qfc.FakeQueueConnection
ClassLoader=sun.misc.Launcher$AppClassLoader@47858e
  ClassLoader=sun.misc.Launcher$ExtClassLoader@19134f4
    ClassLoader=null
Thread.currentThread().getClass().getClassLoader():
ClassLoader=sun.misc.Launcher$AppClassLoader@47858e
  ClassLoader=sun.misc.Launcher$ExtClassLoader@19134f4
    ClassLoader=null
==============================
___________________START_______________________

Class loader tree
 |
sun.misc.Launcher$ExtClassLoader@19134f4 {file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/dnsns.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/localedata.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunjce_provider.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunmscapi.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunpkcs11.jar:}
 |
sun.misc.Launcher$AppClassLoader@47858e {file:/C:/workshop/myclient.jar:file:/C:/bea1032/user_projects/domains/myAppwls10loc/%20C:/workspace/maven%20/oracle/jars/aqapi-9.0.2.jar%20:file:/C:/bea1032/patch_wls1032/profiles/default/sys_manifest_classpath/weblogic_patch.jar:file:/C:/bea1032/patch_oepe1032/profiles/default/sys_manifest_classpath/weblogic_patch.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/lib/tools.jar:file:/C:/bea1032/utils/config/10.3/config-launch.jar:file:/C:/bea1032/wlserver_10.3/server/lib/weblogic_sp.jar:file:/C:/bea1032/wlserver_10.3/server/lib/weblogic.jar:file:/C:/bea1032/modules/features/weblogic.server.modules_10.3.2.0.jar:file:/C:/bea1032/wlserver_10.3/server/lib/webservices.jar:file:/C:/bea1032/modules/org.apache.ant_1.7.0/lib/ant-all.jar:file:/C:/bea1032/modules/net.sf.antcontrib_1.0.0.0_1-0b2/lib/ant-contrib.jar:file:/C:/bea1032/wlserver_10.3/common/eval/pointbase/lib/pbclient57.jar:file:/C:/bea1032/wlserver_10.3/server/lib/xqrl.jar:}

Context loader tree
 |
sun.misc.Launcher$ExtClassLoader@19134f4 {file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/dnsns.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/localedata.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunjce_provider.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunmscapi.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunpkcs11.jar:}
 |
sun.misc.Launcher$AppClassLoader@47858e {file:/C:/workshop/myclient.jar:file:/C:/bea1032/user_projects/domains/myAppwls10loc/%20C:/workspace/maven%20/oracle/jars/aqapi-9.0.2.jar%20:file:/C:/bea1032/patch_wls1032/profiles/default/sys_manifest_classpath/weblogic_patch.jar:file:/C:/bea1032/patch_oepe1032/profiles/default/sys_manifest_classpath/weblogic_patch.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/lib/tools.jar:file:/C:/bea1032/utils/config/10.3/config-launch.jar:file:/C:/bea1032/wlserver_10.3/server/lib/weblogic_sp.jar:file:/C:/bea1032/wlserver_10.3/server/lib/weblogic.jar:file:/C:/bea1032/modules/features/weblogic.server.modules_10.3.2.0.jar:file:/C:/bea1032/wlserver_10.3/server/lib/webservices.jar:file:/C:/bea1032/modules/org.apache.ant_1.7.0/lib/ant-all.jar:file:/C:/bea1032/modules/net.sf.antcontrib_1.0.0.0_1-0b2/lib/ant-contrib.jar:file:/C:/bea1032/wlserver_10.3/common/eval/pointbase/lib/pbclient57.jar:file:/C:/bea1032/wlserver_10.3/server/lib/xqrl.jar:}
 |
java.net.URLClassLoader@164dbd5 {file:/C:/bea1032/user_projects/domains/myAppwls10loc/lib/jt400.jar:}
 |
weblogic.utils.classloaders.GenericClassLoader@1db6942 finder: weblogic.utils.classloaders.CodeGenClassFinder@1fe2c10 annotation:  
 |
weblogic.utils.classloaders.FilteringClassLoader@11f9cee finder: weblogic.utils.classloaders.CodeGenClassFinder@77e77a annotation:  
 |
weblogic.utils.classloaders.GenericClassLoader@f8d6a6 finder: weblogic.utils.classloaders.CodeGenClassFinder@8f53c8 annotation: myApp@ 
 |
weblogic.utils.classloaders.GenericClassLoader@fcfd10 finder: weblogic.utils.classloaders.CodeGenClassFinder@1d1bb4d annotation: myApp@ 
____________________END_______________________
Tue Feb 14 10:02:56 EST 2012; INFO:  construct queueSession
Tue Feb 14 10:02:56 EST 2012; INFO:  scheduling delayed start[5000ms], timeout[100ms] session[com.myapp.messaging.aq.qfc.FakeQueueSession@17b3b61queue=nullmessageListener=nullstopped=false]
Tue Feb 14 10:02:56 EST 2012; INFO:  session#1, queueSession created[com.myapp.messaging.aq.qfc.FakeQueueConnection@97cd75session=com.myapp.messaging.aq.qfc.FakeQueueSession@17b3b61queue=nullmessageListener=nullstopped=falseclosed=falsesession_list=1]
Tue Feb 14 10:02:56 EST 2012; INFO:  setMessageListener(weblogic.ejb.container.internal.MDListener@1598d5f)
Tue Feb 14 10:02:56 EST 2012INFO:  start connection[null] closed[false]
<Feb 14, 2012 10:02:57 AM EST> <Notice> <WebLogicServer> <BEA-000365> <Server state changed to RUNNING> 
<Feb 14, 2012 10:02:57 AM EST> <Notice> <WebLogicServer> <BEA-000360> <Server started in RUNNING mode> 
<Feb 14, 2012 10:03:01 AM EST> <Warning> <JMX> <BEA-149517> <An attempt was made to unregister an mbean that was already unregistered: weblogic.servlet.internal.ServletRuntimeMBeanImpl@bb303> 
------------------------
classLoader=weblogic.servlet.jsp.JspClassLoader@a3af1c finder: weblogic.utils.classloaders.CodeGenClassFinder@1ed70df annotation: 
  classLoader=weblogic.servlet.jsp.TagFileClassLoader@18d70a6 finder: weblogic.utils.classloaders.CodeGenClassFinder@deaa44 annotation: 
    classLoader=weblogic.utils.classloaders.ChangeAwareClassLoader@17b51e8 finder: weblogic.utils.classloaders.CodeGenClassFinder@1ad65f7 annotation: myApp@myApp
      classLoader=weblogic.utils.classloaders.GenericClassLoader@f8d6a6 finder: weblogic.utils.classloaders.CodeGenClassFinder@8f53c8 annotation: myApp@
        classLoader=weblogic.utils.classloaders.FilteringClassLoader@11f9cee finder: weblogic.utils.classloaders.CodeGenClassFinder@77e77a annotation: 
          classLoader=weblogic.utils.classloaders.GenericClassLoader@1db6942 finder: weblogic.utils.classloaders.CodeGenClassFinder@1fe2c10 annotation: 
            classLoader=java.net.URLClassLoader@164dbd5
              classLoader=sun.misc.Launcher$AppClassLoader@47858e
                classLoader=sun.misc.Launcher$ExtClassLoader@19134f4
                  classLoader=null
classLoader=null now
------------------------
___________________START_______________________

Class loader tree
 |
sun.misc.Launcher$ExtClassLoader@19134f4 {file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/dnsns.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/localedata.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunjce_provider.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunmscapi.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunpkcs11.jar:}
 |
sun.misc.Launcher$AppClassLoader@47858e {file:/C:/workshop/myclient.jar:file:/C:/bea1032/user_projects/domains/myAppwls10loc/%20C:/workspace/maven%20/oracle/jars/aqapi-9.0.2.jar%20:file:/C:/bea1032/patch_wls1032/profiles/default/sys_manifest_classpath/weblogic_patch.jar:file:/C:/bea1032/patch_oepe1032/profiles/default/sys_manifest_classpath/weblogic_patch.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/lib/tools.jar:file:/C:/bea1032/utils/config/10.3/config-launch.jar:file:/C:/bea1032/wlserver_10.3/server/lib/weblogic_sp.jar:file:/C:/bea1032/wlserver_10.3/server/lib/weblogic.jar:file:/C:/bea1032/modules/features/weblogic.server.modules_10.3.2.0.jar:file:/C:/bea1032/wlserver_10.3/server/lib/webservices.jar:file:/C:/bea1032/modules/org.apache.ant_1.7.0/lib/ant-all.jar:file:/C:/bea1032/modules/net.sf.antcontrib_1.0.0.0_1-0b2/lib/ant-contrib.jar:file:/C:/bea1032/wlserver_10.3/common/eval/pointbase/lib/pbclient57.jar:file:/C:/bea1032/wlserver_10.3/server/lib/xqrl.jar:}
 |
java.net.URLClassLoader@164dbd5 {file:/C:/bea1032/user_projects/domains/myAppwls10loc/lib/jt400.jar:}
 |
weblogic.utils.classloaders.GenericClassLoader@1db6942 finder: weblogic.utils.classloaders.CodeGenClassFinder@1fe2c10 annotation:  
 |
weblogic.utils.classloaders.FilteringClassLoader@11f9cee finder: weblogic.utils.classloaders.CodeGenClassFinder@77e77a annotation:  
 |
weblogic.utils.classloaders.GenericClassLoader@f8d6a6 finder: weblogic.utils.classloaders.CodeGenClassFinder@8f53c8 annotation: myApp@ 
 |
weblogic.utils.classloaders.ChangeAwareClassLoader@17b51e8 finder: weblogic.utils.classloaders.CodeGenClassFinder@1ad65f7 annotation: myApp@myApp 
 |
weblogic.servlet.jsp.TagFileClassLoader@18d70a6 finder: weblogic.utils.classloaders.CodeGenClassFinder@deaa44 annotation:  
 |
weblogic.servlet.jsp.JspClassLoader@a3af1c finder: weblogic.utils.classloaders.CodeGenClassFinder@1ed70df annotation:  

Context loader tree
 |
sun.misc.Launcher$ExtClassLoader@19134f4 {file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/dnsns.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/localedata.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunjce_provider.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunmscapi.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunpkcs11.jar:}
 |
sun.misc.Launcher$AppClassLoader@47858e {file:/C:/workshop/myclient.jar:file:/C:/bea1032/user_projects/domains/myAppwls10loc/%20C:/workspace/maven%20/oracle/jars/aqapi-9.0.2.jar%20:file:/C:/bea1032/patch_wls1032/profiles/default/sys_manifest_classpath/weblogic_patch.jar:file:/C:/bea1032/patch_oepe1032/profiles/default/sys_manifest_classpath/weblogic_patch.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/lib/tools.jar:file:/C:/bea1032/utils/config/10.3/config-launch.jar:file:/C:/bea1032/wlserver_10.3/server/lib/weblogic_sp.jar:file:/C:/bea1032/wlserver_10.3/server/lib/weblogic.jar:file:/C:/bea1032/modules/features/weblogic.server.modules_10.3.2.0.jar:file:/C:/bea1032/wlserver_10.3/server/lib/webservices.jar:file:/C:/bea1032/modules/org.apache.ant_1.7.0/lib/ant-all.jar:file:/C:/bea1032/modules/net.sf.antcontrib_1.0.0.0_1-0b2/lib/ant-contrib.jar:file:/C:/bea1032/wlserver_10.3/common/eval/pointbase/lib/pbclient57.jar:file:/C:/bea1032/wlserver_10.3/server/lib/xqrl.jar:}
 |
java.net.URLClassLoader@164dbd5 {file:/C:/bea1032/user_projects/domains/myAppwls10loc/lib/jt400.jar:}
 |
weblogic.utils.classloaders.GenericClassLoader@1db6942 finder: weblogic.utils.classloaders.CodeGenClassFinder@1fe2c10 annotation:  
 |
weblogic.utils.classloaders.FilteringClassLoader@11f9cee finder: weblogic.utils.classloaders.CodeGenClassFinder@77e77a annotation:  
 |
weblogic.utils.classloaders.GenericClassLoader@f8d6a6 finder: weblogic.utils.classloaders.CodeGenClassFinder@8f53c8 annotation: myApp@ 
 |
weblogic.utils.classloaders.ChangeAwareClassLoader@17b51e8 finder: weblogic.utils.classloaders.CodeGenClassFinder@1ad65f7 annotation: myApp@myApp 
____________________END_______________________



Class loaders for the class in APP-INF/lib and myejb.jar

In another test, I found the class loader that loads the class in the EJB module is the same as the one that loads the classes in the jars in the APP-INF/lib directory. In this test, there is no jar in the lib directory of the domain:C:/bea1032/user_projects/domains/myAppwls10loc/lib
The following is the log for the class in APP-INF/lib:
==============================
Class name:com.myapp.business.sample.SampleBo
ClassLoader=weblogic.utils.classloaders.GenericClassLoader@48268a finder: weblogic.utils.classloaders.CodeGenClassFinder@10e0edb annotation: myApp@
  ClassLoader=weblogic.utils.classloaders.FilteringClassLoader@38bbd7 finder: weblogic.utils.classloaders.CodeGenClassFinder@b44131 annotation: 
    ClassLoader=weblogic.utils.classloaders.GenericClassLoader@5b78cf finder: weblogic.utils.classloaders.CodeGenClassFinder@241f4e annotation: 
      ClassLoader=sun.misc.Launcher$AppClassLoader@47858e
        ClassLoader=sun.misc.Launcher$ExtClassLoader@19134f4
          ClassLoader=null
Thread.currentThread().getClass().getClassLoader():
ClassLoader=sun.misc.Launcher$AppClassLoader@47858e
  ClassLoader=sun.misc.Launcher$ExtClassLoader@19134f4
    ClassLoader=null
==============================
___________________START_______________________

Class loader tree
 |
sun.misc.Launcher$ExtClassLoader@19134f4 {file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/dnsns.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/localedata.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunjce_provider.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunmscapi.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunpkcs11.jar:}
 |
sun.misc.Launcher$AppClassLoader@47858e {file:/C:/workshop/myclient.jar:file:/C:/bea1032/user_projects/domains/myAppwls10loc/%20C:/workspace/maven%20/oracle/jars/aqapi-9.0.2.jar%20:file:/C:/bea1032/patch_wls1032/profiles/default/sys_manifest_classpath/weblogic_patch.jar:file:/C:/bea1032/patch_oepe1032/profiles/default/sys_manifest_classpath/weblogic_patch.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/lib/tools.jar:file:/C:/bea1032/utils/config/10.3/config-launch.jar:file:/C:/bea1032/wlserver_10.3/server/lib/weblogic_sp.jar:file:/C:/bea1032/wlserver_10.3/server/lib/weblogic.jar:file:/C:/bea1032/modules/features/weblogic.server.modules_10.3.2.0.jar:file:/C:/bea1032/wlserver_10.3/server/lib/webservices.jar:file:/C:/bea1032/modules/org.apache.ant_1.7.0/lib/ant-all.jar:file:/C:/bea1032/modules/net.sf.antcontrib_1.0.0.0_1-0b2/lib/ant-contrib.jar:file:/C:/bea1032/wlserver_10.3/common/eval/pointbase/lib/pbclient57.jar:file:/C:/bea1032/wlserver_10.3/server/lib/xqrl.jar:}
 |
weblogic.utils.classloaders.GenericClassLoader@5b78cf finder: weblogic.utils.classloaders.CodeGenClassFinder@241f4e annotation:  
 |
weblogic.utils.classloaders.FilteringClassLoader@38bbd7 finder: weblogic.utils.classloaders.CodeGenClassFinder@b44131 annotation:  
 |
weblogic.utils.classloaders.GenericClassLoader@48268a finder: weblogic.utils.classloaders.CodeGenClassFinder@10e0edb annotation: myApp@ 

Context loader tree
 |
sun.misc.Launcher$ExtClassLoader@19134f4 {file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/dnsns.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/localedata.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunjce_provider.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunmscapi.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunpkcs11.jar:}
 |
sun.misc.Launcher$AppClassLoader@47858e {file:/C:/workshop/myclient.jar:file:/C:/bea1032/user_projects/domains/myAppwls10loc/%20C:/workspace/maven%20/oracle/jars/aqapi-9.0.2.jar%20:file:/C:/bea1032/patch_wls1032/profiles/default/sys_manifest_classpath/weblogic_patch.jar:file:/C:/bea1032/patch_oepe1032/profiles/default/sys_manifest_classpath/weblogic_patch.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/lib/tools.jar:file:/C:/bea1032/utils/config/10.3/config-launch.jar:file:/C:/bea1032/wlserver_10.3/server/lib/weblogic_sp.jar:file:/C:/bea1032/wlserver_10.3/server/lib/weblogic.jar:file:/C:/bea1032/modules/features/weblogic.server.modules_10.3.2.0.jar:file:/C:/bea1032/wlserver_10.3/server/lib/webservices.jar:file:/C:/bea1032/modules/org.apache.ant_1.7.0/lib/ant-all.jar:file:/C:/bea1032/modules/net.sf.antcontrib_1.0.0.0_1-0b2/lib/ant-contrib.jar:file:/C:/bea1032/wlserver_10.3/common/eval/pointbase/lib/pbclient57.jar:file:/C:/bea1032/wlserver_10.3/server/lib/xqrl.jar:}
 |
weblogic.utils.classloaders.GenericClassLoader@5b78cf finder: weblogic.utils.classloaders.CodeGenClassFinder@241f4e annotation:  
 |
weblogic.utils.classloaders.FilteringClassLoader@38bbd7 finder: weblogic.utils.classloaders.CodeGenClassFinder@b44131 annotation:  
 |
weblogic.utils.classloaders.GenericClassLoader@48268a finder: weblogic.utils.classloaders.CodeGenClassFinder@10e0edb annotation: myApp@ 
 |
weblogic.utils.classloaders.ChangeAwareClassLoader@faaa93 finder: weblogic.utils.classloaders.CodeGenClassFinder@5532da annotation: myApp@myApp 
____________________END_______________________

And the following is the log for the class in myejb.jar:
==============================
Class name:com.myapp.messaging.xyz.XyzMessageHandlerImpl
ClassLoader=weblogic.utils.classloaders.GenericClassLoader@48268a finder: weblogic.utils.classloaders.CodeGenClassFinder@10e0edb annotation: myApp@
  ClassLoader=weblogic.utils.classloaders.FilteringClassLoader@38bbd7 finder: weblogic.utils.classloaders.CodeGenClassFinder@b44131 annotation: 
    ClassLoader=weblogic.utils.classloaders.GenericClassLoader@5b78cf finder: weblogic.utils.classloaders.CodeGenClassFinder@241f4e annotation: 
      ClassLoader=sun.misc.Launcher$AppClassLoader@47858e
        ClassLoader=sun.misc.Launcher$ExtClassLoader@19134f4
          ClassLoader=null
Thread.currentThread().getClass().getClassLoader():
==============================
___________________START_______________________

Class loader tree
 |
sun.misc.Launcher$ExtClassLoader@19134f4 {file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/dnsns.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/localedata.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunjce_provider.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunmscapi.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunpkcs11.jar:}
 |
sun.misc.Launcher$AppClassLoader@47858e {file:/C:/workshop/myclient.jar:file:/C:/bea1032/user_projects/domains/myAppwls10loc/%20C:/workspace/maven%20/oracle/jars/aqapi-9.0.2.jar%20:file:/C:/bea1032/patch_wls1032/profiles/default/sys_manifest_classpath/weblogic_patch.jar:file:/C:/bea1032/patch_oepe1032/profiles/default/sys_manifest_classpath/weblogic_patch.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/lib/tools.jar:file:/C:/bea1032/utils/config/10.3/config-launch.jar:file:/C:/bea1032/wlserver_10.3/server/lib/weblogic_sp.jar:file:/C:/bea1032/wlserver_10.3/server/lib/weblogic.jar:file:/C:/bea1032/modules/features/weblogic.server.modules_10.3.2.0.jar:file:/C:/bea1032/wlserver_10.3/server/lib/webservices.jar:file:/C:/bea1032/modules/org.apache.ant_1.7.0/lib/ant-all.jar:file:/C:/bea1032/modules/net.sf.antcontrib_1.0.0.0_1-0b2/lib/ant-contrib.jar:file:/C:/bea1032/wlserver_10.3/common/eval/pointbase/lib/pbclient57.jar:file:/C:/bea1032/wlserver_10.3/server/lib/xqrl.jar:}
 |
weblogic.utils.classloaders.GenericClassLoader@5b78cf finder: weblogic.utils.classloaders.CodeGenClassFinder@241f4e annotation:  
 |
weblogic.utils.classloaders.FilteringClassLoader@38bbd7 finder: weblogic.utils.classloaders.CodeGenClassFinder@b44131 annotation:  
 |
weblogic.utils.classloaders.GenericClassLoader@48268a finder: weblogic.utils.classloaders.CodeGenClassFinder@10e0edb annotation: myApp@ 

Context loader tree
 |
sun.misc.Launcher$ExtClassLoader@19134f4 {file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/dnsns.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/localedata.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunjce_provider.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunmscapi.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/jre/lib/ext/sunpkcs11.jar:}
 |
sun.misc.Launcher$AppClassLoader@47858e {file:/C:/workshop/myclient.jar:file:/C:/bea1032/user_projects/domains/myAppwls10loc/%20C:/workspace/maven%20/oracle/jars/aqapi-9.0.2.jar%20:file:/C:/bea1032/patch_wls1032/profiles/default/sys_manifest_classpath/weblogic_patch.jar:file:/C:/bea1032/patch_oepe1032/profiles/default/sys_manifest_classpath/weblogic_patch.jar:file:/C:/bea1032/jdk160_14_R27.6.5-32/lib/tools.jar:file:/C:/bea1032/utils/config/10.3/config-launch.jar:file:/C:/bea1032/wlserver_10.3/server/lib/weblogic_sp.jar:file:/C:/bea1032/wlserver_10.3/server/lib/weblogic.jar:file:/C:/bea1032/modules/features/weblogic.server.modules_10.3.2.0.jar:file:/C:/bea1032/wlserver_10.3/server/lib/webservices.jar:file:/C:/bea1032/modules/org.apache.ant_1.7.0/lib/ant-all.jar:file:/C:/bea1032/modules/net.sf.antcontrib_1.0.0.0_1-0b2/lib/ant-contrib.jar:file:/C:/bea1032/wlserver_10.3/common/eval/pointbase/lib/pbclient57.jar:file:/C:/bea1032/wlserver_10.3/server/lib/xqrl.jar:}
 |
weblogic.utils.classloaders.GenericClassLoader@5b78cf finder: weblogic.utils.classloaders.CodeGenClassFinder@241f4e annotation:  
 |
weblogic.utils.classloaders.FilteringClassLoader@38bbd7 finder: weblogic.utils.classloaders.CodeGenClassFinder@b44131 annotation:  
 |
weblogic.utils.classloaders.GenericClassLoader@48268a finder: weblogic.utils.classloaders.CodeGenClassFinder@10e0edb annotation: myApp@ 
____________________END_______________________

Friday, January 20, 2012

Analysis of A Piece of Linux Bash Script That Uses Regular Expression

I often forgot the syntax of regular expression and had trouble understanding it. The following is some code that is simple but contains quite some techinical stuff. It will be helpful to understand how it works. So I did a little bit digging to find out the answer.

pathmunge () {
        if ! echo $PATH | /bin/egrep -q "(^|:)$1($|:)" ; then  
              PATH=$1:$PATH 
        fi
}

pathmunge /sbin


Basically the function pathmunge() is used to add some string to the $PATH variable if the string is not already in the $PATH. In the code above, the line "pathmunge /sbin" is an actual call of the function.

There are several technical tips here for understanding the code.
The most compact syntax of the "if" command is
if TEST-COMMAND; then CONSEQUENT-COMMANDS; fi
  1. For the "if" statement, if the test command has the return status 0, then the "then" part is executed. Note this is different from some other programming languages where 0 means false.
  2. It is common to see the "if" statement like this "if [ ... ]". But here the test command is different. The test command might be any UNIX command that returns an exit status, and that "if" again returns an exit status of zero. In our case, the test command is
    ! echo $PATH | /bin/egrep -q "(^|:)$1($|:)" 
    
    This command first does the echo. Then does the egrep. And then apply the "!" operator. So if egrep is successful ( i.e, the string is found ), then "!" changes this to non-zero, and the "then" part will not be executed.
  3. The regular expression is "(^|:)$1($|:)". In this expression is the character "$" in "$1" a character for matching or is "$1" a symbol for the first parameter passed to the function pathmunge()? Answer: $1 is the first parameter. This is called "shell expansion".
  4. In the regular expression, the "^" character means to match the beginning. The second "$" means to match the end. The parentheses "()" is for a group. The character "|" is like an OR operator. So for the call in the code, the pattern will match the following. Here I use * to denote 0 or more characters:
    • /sbin
    • /sbin:*
    • *:/sbin
    • *:/sbin:*
  5. In the "then" part, you can have more than one command. For example, you can use
    if ! echo $PATH | /bin/egrep -q "(^|:)$1($|:)" ; then
                    echo "\$1 is " $1             
                    PATH=$1:$PATH            
            fi
    

Tuesday, January 3, 2012

Install Plugins for Different Programming Languages in Eclipse

Eclipse is usually used for java development. But it can also be used for other programming lanugages. To install the plugin for using other programming languages, use the following procedure.
  1. Go to the menu item Help --> Install New Software...
  2. In the "Work with:" input box, select the following:
    Galileo - http://download.eclipse.org/releases/galileo
    Note that this is for the Galileo version of eclipse. For other versions of eclipse, use the corresponding link.
  3. You'll see a list of softwares. One of them is "Programming Languages". From there, you can select the language you want ( for example, C/C++, PHP, etc) and install it.

Tuesday, December 6, 2011

Special Characters in Google Search

Unfortunately you usually can not search phrases with special characters. The following is the quote from the Google support link:
http://www.google.com/support/websearch/bin/answer.py?answer=134479

Generally, punctuation is ignored, including @#$%^&*()=+[]\ and other special characters.
By the way, that article has this useful tip:
Search is always case insensitive. A search for [ new york times ] is the same as a search for [ New York Times ].

Monday, October 17, 2011

How Are the Per Web Application Singleton Objects Created in the JSF Framework

In the JSF framework, there are several key classes that are the singletons for the application. They are created using the following way:
FactoryFinder --> Factory --> Singleton Object.
To guarantee that the object is a singleton, the FactoryFinder and the Factory do the following:
  1. The Factories are also singletons. So you can just use plain code to get a field object of it as a singleton too.
  2. The FactoryFinder defines all its fields and methods to be static. And it puts the code to retrieve the factoies in a synchronized block. So when you get a factory object from FactoryFinder, it will be a singleton.
  3. Now since the web app uses the static method of FactoryFinder to get the factory object, will different web applications deployed on the same server share the same factory object? The answer is "No" and it is very important. The FactoryFinder uses classloader of the specific web application to achieve this result.

Note 1: If the purpose is to just create a singleton, then there is no need to use Factory. I think the main purpose to use Factory here is to give a mechanism so the different implementations of the singleton classes can be used. Factory uses some algorithm to find and load the implementation classes.

Note 2: The factories are loaded at the startup time of the server. This is before the web application is used by any user.

In FactoryFinder, there are four factories that can be created. They are: ApplicationFactory, FacesContextFactory, LifecycleFactory, and RenderKitFactory.

Take the Application singleton as the example.

From javadoc, javax.faces.application.Application represents a per-web-application singleton object. It is created by the following:
Application application = ApplicationFactory.getApplication();

The implementation ApplicationFactoryImpl is simply the following:
private Application application;

   public Application getApplication(){
      if (application == null )
      {
         application = new ApplicationImpl();
       }
       return applicaiton;
   }
You can see that this code does not deal with thread safety. And it is not static. So this code itself does not guarantee that the returned applicaiton object will be a singleton.

The javax.faces.application.ApplicationFactory is also a per-web-application singleton. It is created by the following in FactoryFinder:
private static HashMap applicationMaps = new HashMap();
  
   public static Object getFactory(String factoryName) throws FacesException{
    validateFactoryName(factoryName);
    synchronized (applicationMaps) {
            Map appMap = getApplicationMap();
   
              Object 
      factory = null,
      factoryOrList = appMap.get(factoryName);
                if (factoryOrList != null && (!(factoryOrList instanceof List))) {
     
                    return (factoryOrList);
                }
        
                factory = getImplementationInstance(classLoader, factoryName,
          (List) factoryOrList);
         
                if (null == factory) {
                    ResourceBundle rb = LOGGER.getResourceBundle();
                    String message = rb.getString("severe.no_factory");
                    message = MessageFormat.format(message, factoryName);
                    throw new IllegalStateException(message);
                }
    
                appMap.put(factoryName, factory);
                return (factory);
        }
   
   }

So in this method, the synchronized code is used. it is guaranteed that the singleton will be returned.
Let us look at the code in more detail to see why the returned factory object is per-web application.
The line Map appMap = getApplicationMap(); creates a local Map variable appMap. The method called is the following:
private static HashMap applicationMaps = new HashMap();

private static Map getApplicationMap() {
        // Identify the web application class loader
        ClassLoader classLoader = getClassLoader();
 Map result = null;
 
 // Return any previously instantiated factory instance (of the
 // specified name) for this web application
 result = (HashMap) applicationMaps.get(classLoader);
 if (result == null) {
     result = new HashMap();
     applicationMaps.put(classLoader, result);
 }
 return result;
    }
So it is a map from the classLoader to another map. This classLoader object is different for different web applications deployed on the same server. The method is the following:
private static ClassLoader getClassLoader() throws FacesException {

        // J2EE 1.3 (and later) containers are required to make the
        // web application class loader visible through the context
        // class loader of the current thread.
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        if (cl == null) {
            throw new FacesException("getContextClassLoader");
        }
        return (cl);

    }
You can see that it uses the current thread to get the ClassLoader object. The static instance variable applicationMaps of the class FactoryFinder contains the following information:
classLoader --> {factoryName --> factoryObject}
So in a more strict sense, the factoryObject singleton is not a singleton across the JVM. It is a singleton inside each web applicaiton.

Thursday, October 13, 2011

Main Classes Called by the Phase Objects in JSF Lifecycle

UIViewRoot and ViewHandler

The JSF lifecycle has 6 phases. They are RestoreViewPhase, ApplyRequestValuesPhase,ProcessValidationsPhase, UpdateModelValuesPhase, InvokeApplicationPhase, and RenderResponsePhase. The corresponding classes are all in the package com.sun.faces.lifecycle.

The RestoreViewPhase gets the UIViewRoot from the facesContext or the viewhandler. Either way, it will eventually set the viewRoot in the facesContext.

The ApplyRequestValuesPhase basically uses the ViewRoot to do decoding:
public void execute(FacesContext facesContext) throws FacesException{
         ......
         UIComponent component = facesContext.getViewRoot();
         ......
         component.processDecodes(facesContext);
         .......
      }
 
The ProcessValidationsPhase basically uses the ViewRoot to invoke the validators:
public void execute(FacesContext facesContext) throws FacesException{
          ......
          UIComponent component = facesContext.getViewRoot();
          ......
          component.processValidators(facesContext); 
          .......
       }
 
The UpdateModelValuesPhase uses the ViewRoot to process updates:
public void execute(FacesContext facesContext) throws FacesException{
          ......
          UIComponent component = facesContext.getViewRoot();
          ......
          component.processUpdates(facesContext);
          .......
       }
The InvokeApplicationPhase uses the ViewRoot to process application:
public void execute(FacesContext facesContext) throws FacesException{
          ......
          UIComponent component = facesContext.getViewRoot();
          ......
          component.processApplication(facesContext); 
          .......
       }
The RenderResponsePhase uses the viewHandler and the ViewRoot to render the view:
public void execute(FacesContext facesContext) throws FacesException{
          ......
          facesContext.getApplication().getViewHandler().renderView(facesContext, facesContext.getViewRoot());
          .......
       }
From the above, we can see that the ViewRoot object plays an important role. All the phases between the RestoreViewPhase and the RenderViewPhase just delegate the work to the ViewRoot.

Some Notes on UIViewRoot

The UIViewRoot class calls the broadcast(event) method of the UIComponent class in many places. The name of this method is misleading. If you look at the code, it actually does not just broadcast the event. It actually also invokes the event listeners to perform actions.
The following is the method in the UIComponentBase class:
public void broadcast(FacesEvent event)
        throws AbortProcessingException {
        if (event == null) {
            throw new NullPointerException();
        }
        if (listeners == null) {
            return;
        }
        Iterator iter = listeners.iterator();
        while (iter.hasNext()) {
            FacesListener listener = iter.next();
            if (event.isAppropriateListener(listener)) {
                event.processListener(listener);
            }
        }
    }
There are two concrete event classes that implement the processListener(...) method. One is ActionEvent, and the other is ValueChangeEvent. The ActionEvent class has the following:
public void processListener(FacesListener listener) {
        ((ActionListener) listener).processAction(this);
    }
The ValueChangeEvent class has the following:
public void processListener(FacesListener listener) {
        ((ValueChangeListener) listener).processValueChange(this);
    }
So here the event actually lets the listeners to act on the event itself. It does not just sit at the listeners.
The following are more details. The com.sun.faces.application.ActionListenerImpl has the code below:
public void processAction(ActionEvent event) {
        if (logger.isLoggable(Level.FINE)) {
            logger.fine("processAction(" + event.getComponent().getId() + ")");
        }
        UIComponent source = event.getComponent();
        ActionSource actionSource = (ActionSource) source;
        FacesContext context = FacesContext.getCurrentInstance();

        Application application = context.getApplication();

        Object invokeResult = null;
        String outcome = null;
        MethodBinding binding = null;

 binding = actionSource.getAction();
 if (binding != null) {
     try {
  if (null != (invokeResult = binding.invoke(context, null))) {
                    outcome = invokeResult.toString();
                }
                // else, default to null, as assigned above.
     } catch (MethodNotFoundException e) {
                if (logger.isLoggable(Level.SEVERE)) {
                    logger.log(Level.SEVERE, e.getMessage(), e);
                }
  throw new FacesException
                    (binding.getExpressionString() + ": " + e.getMessage(), e);
     }
     catch (EvaluationException e) {
                if (logger.isLoggable(Level.SEVERE)) {
                    logger.log(Level.SEVERE, e.getMessage(), e);
                }
  throw new FacesException
                    (binding.getExpressionString() + ": " + e.getMessage(), e);
     }
 }

        // Retrieve the NavigationHandler instance..

        NavigationHandler navHandler = application.getNavigationHandler();

        // Invoke nav handling..

        navHandler.handleNavigation(context,
                                    (null != binding) ?
                                    binding.getExpressionString() : null,
                                    outcome);

        // Trigger a switch to Render Response if needed
        context.renderResponse();
    }
The javax.faces.event.MethodExpressionValueChangeListener class has the code below:
public void processValueChange(ValueChangeEvent valueChangeEvent) throws AbortProcessingException {
                         
        if (valueChangeEvent == null) {
            throw new NullPointerException();
        }
        try {
            FacesContext context = FacesContext.getCurrentInstance();
            ELContext elContext = context.getELContext();
            methodExpression.invoke(elContext, new Object[] {valueChangeEvent});
        } catch (ELException ee) {
            throw new AbortProcessingException(ee.getMessage(), ee.getCause());
        }
    }
The javax.faces.event.MethodExpressionActionListener class has the code below:
public void processAction(ActionEvent actionEvent) throws AbortProcessingException {

        if (actionEvent == null) {
            throw new NullPointerException();
        }
        try {
            FacesContext context = FacesContext.getCurrentInstance();
            ELContext elContext = context.getELContext();
            methodExpression.invoke(elContext, new Object[] {actionEvent});
        } catch (ELException ee) {
            if (LOGGER.isLoggable(Level.SEVERE)) {
                LOGGER.log(Level.SEVERE,
                           "severe.event.exception_invoking_processaction",
                           new Object[]{
                                 ee.getCause().getClass().getName(),
                                 methodExpression.getExpressionString(),
                                 actionEvent.getComponent().getId()
                           });
                StringWriter writer = new StringWriter(1024);
                ee.getCause().printStackTrace(new PrintWriter(writer));
                LOGGER.severe(writer.toString());
            }
            throw new AbortProcessingException(ee.getMessage(), ee.getCause());
        }
    }

A Closer Look at How the InvokeApplicationPhase works

The code of the execute(...) method of the InvokeApplicationPhase is very simple. Essentially it just calls root.processApplication(facesContext) where root is the UIViewRoot. And the essential code in the processApplication(...) method of UIViewRoot is the following:
broadcastEvents(context,PhaseId.INVOKE_APPLICATION);
So let's see how it works in reality. The example used here is a simple jsp file with a form:
<html>
       ...
       <f:view>
          ...
          <h:form>
             ...
             <h:commandButton action="#{quiz.answerAction}" />
             ...
          </h:form>
         ...
       </f:view>
     </html>
Here is what happened during the lifecycle of JSF. We can see when and where the event object is created.
  1. In the ApplyRequestValuePhase, JSF iterates through all the UIComponents in the UIForm and calls the processDecodes method of each component.
  2. The CommandButton component gets the Render and lets the Render do the decode.
  3. The ButtonRender creates an ActionEvent and queues the event to the UIViewRoot. The event has the Invoke_Application phase ID and so will be used in the Invoke_Applicaiton pahse. Interestingly at this point, the events[] field of the UIViewRoot class is still null. So it is created and the ActionEvent is put in. Actually this makes sense because the events[] field in UIViewRoot class is a transient field. So it is not saved in the session and can not be restored in the Restore_View phase.
  4. In the Invoke_Applicaiton phase, the UIViewRoot will pick up this event and let it work.

Monday, October 10, 2011

How Does the JSF Restore_View Phase Restore the View?

The Restore_View phase is one of the key points in the JSF lifecycle. How does JSF restore the view? From where?

When does the Restore_View actually restore the view?

When a user navigates through various pages of an application on the brower, he or she may visit the same jsp file multiple times. A jsp file is a view in JSF. Will this view be saved by the JSF framework and then be restored in every subsequent visit? In general the answer is no. We will use jsf-1.2 in this analysis.

The java file in JSF to do the RESTORE_VIEW phase is com.sun.faces.lifecycle.RestoreViewPhase.java. Two of its methods are the following
/**
     * PRECONDITION: the necessary factories have been installed in the
     * ServletContext attr set. 
     * POSTCONDITION: The facesContext has been initialized with a tree.
     */

    public void execute(FacesContext facesContext) throws FacesException {
        if (logger.isLoggable(Level.FINE)) {
            logger.fine("Entering RestoreViewPhase");
        }
        
        ......
        
        Util.getViewHandler(facesContext).initView(facesContext);        

        // If an app had explicitely set the tree in the context, use that;
        //
        UIViewRoot viewRoot = facesContext.getViewRoot();
        Locale locale = null;
        if (viewRoot != null) {
            if (logger.isLoggable(Level.FINE)) {
                logger.fine("Found a pre created view in FacesContext");
            }
            locale = facesContext.getExternalContext().getRequestLocale();
            facesContext.getViewRoot().setLocale(locale);
            doPerComponentActions(facesContext, viewRoot);
            return;
        }

        ......
        
 if (isPostback(facesContext)) {
     // try to restore the view
            ViewHandler viewHandler = Util.getViewHandler(facesContext);
     if (null == (viewRoot = viewHandler.restoreView(facesContext, viewId))) {
                JSFVersionTracker tracker = 
                        ApplicationAssociate.getInstance(facesContext.getExternalContext()).getJSFVersionTracker();

  // The tracker will be null if the user turned off the 
  // version tracking feature.  
                if (null != tracker) {
      // Get the versions of the current ViewHandler and
      // StateManager.  If they are older than the current
      // version of the implementation, fall back to the
      // JSF 1.1 behavior.
                    Version toTest = tracker.
                            getVersionForTrackedClassName(viewHandler.getClass().getName());
                    Version currentVersion = tracker.getCurrentVersion();
      boolean viewHandlerIsOld = false,
   stateManagerIsOld = false;
      
      viewHandlerIsOld = (toTest.compareTo(currentVersion) < 0);
      toTest = tracker.
   getVersionForTrackedClassName(facesContext.getApplication().getStateManager().getClass().getName());
      stateManagerIsOld = (toTest.compareTo(currentVersion) < 0);

                    if (viewHandlerIsOld || stateManagerIsOld) {
                        viewRoot = viewHandler.createView(facesContext, viewId);
                        if (null != viewRoot) {
                            facesContext.renderResponse();
                        }
                    }
                }
                
                if (null == viewRoot) {
                    Object[] params = {viewId};
                    throw new ViewExpiredException(MessageUtils.getExceptionMessageString(
                            MessageUtils.RESTORE_VIEW_ERROR_MESSAGE_ID, params), viewId);
                }
     }
            if (logger.isLoggable(Level.FINE)) {
                logger.fine("Postback: Restored view for " + viewId);
            }
 }
 else {
            if (logger.isLoggable(Level.FINE)) {
                logger.fine("New request: creating a view for " + viewId);
            }
            // if that fails, create one
            viewRoot = (Util.getViewHandler(facesContext)).
                createView(facesContext, viewId);
            facesContext.renderResponse();
        } 
        assert (null != viewRoot);

        facesContext.setViewRoot(viewRoot);
        doPerComponentActions(facesContext, viewRoot);

        if (logger.isLoggable(Level.FINE)) {
            logger.fine("Exiting RestoreViewPhase");
        }
    }

    /**
     *
     * @return true if the request method is POST or PUT, or the method
     * is GET but there are query parameters, or the request is not an
     * instance of HttpServletRequest.
     */

    private boolean isPostback(FacesContext context) {
        // Get the renderKitId by calling viewHandler.calculateRenderKitId().
        String renderkitId = 
                context.getApplication().getViewHandler().
                calculateRenderKitId(context);
        ResponseStateManager rsm = RenderKitUtils.getResponseStateManager(context,
                renderkitId);
        return rsm.isPostback(context);
    }
A typical case is the following:

Step 1. The user visits a page the first time. And that page has a form.

Step 2. The user enters the data into the form and then submits the page.

In Step 1, JSF will execute two phases Restore_View and Render_Response. It creates the view in the Restoer_View phase. But here it is just an empty ViewRoot and it is put into the facescontext. In the Render_Response phase, JSF will creates the actual UI components and build the view. It will also save the view into the session using the class com.sun.faces.application.StateManagerImpl in this phase. In Step 2, by default, the page is submitted to the same page. JSF will go through all the phases in the lifecycle. Now looking at the method execute(...) of RestoreViewPhase, we can see an if-else clause. The condition is whether or not this mehtod

isPostback(facesContext)
will return true or false. The javadoc of this method states clearly that it will return true if the request method is POST or PUT, or the method is GET but there are query parameters, or the request is not an instance of HttpServletRequest. In our case, it is a form and method is POST, so the condition is true. Hence the view will be restored using the one saved in the session in Step 1. In a different case, suppose it is still the page that the user visited before. But this time it is a redirect as a result of the processing on the server side. Under this situation, the method isPostback(...) will return false. So even though the page has been visited before, a brand new view will be created just like in Step 1 described above. A typical case is that in the Invoke_Application phase of the lifecycle,JSF determines that everything is successful and invokes a redirect call to some page. Now no matter whether or not that page has been visited before, it will be considered to be a new request. And immmediately following the Invoke_Application phase, the actual call to the Render_Response phase will be skipped. Instead, a new JSF lifecycle will start. And since it is regarded a new request, only two phases Restore_View and Render_Response will be executed for the page that is redirected to.

So under the redirect situation, a view will be re-created just as when the page is visited the first time. But this is not the whole story. To make this more precise, there is some difference here from the first time the page is visited. In the appache tomcat implementation, when the page is visited the first time, the Render_Reponse phase also does the following:

  1. Calls the jsp compiler ( org.apache.jasper.compiler.Compiler ). This compiler will removeGeneratedFiles, generateJava, and generateClass for the jsp page. Note that the three phrases in bold are from the actual log file.
  2. Creates the managed beans used in the JSP page. If the scope of the bean is session, the bean will be stored in the session.
In the subsequest visists to the same page, these compiler actions won't happen. And the session-scoped beans do not need to be created again if it is in the same session.

A closer look at how the view is stored and retrieved

Simply put, a view is stored in the session. When a page is visited the first time, two phases Restore_View and Render_Response will be called. In the Render_Response phase, the method is the following:
public void execute(FacesContext facesContext) throws FacesException
{
   ......
   facesContext.getApplication().getViewHandler().renderView(facesContext, facesContext.getViewRoot());
   ......
}
The ViewHandler will eventually call the following:
stateManager.saveView(context);
where stateManager is an instance of com.sun.faces.applicaiton.StateManagerImpl. This method will in turn invokes the following:
/**
     * Return an opaque Object containing sufficient
     * information for this same instance to restore the state of the
     * current {@link UIViewRoot} on a subsequent request.  The returned
     * object must implement java.io.Serializable. If there
     * is no state information to be saved, return null
     * instead.
     *
     * Components may opt out of being included in the serialized view
     * by setting their transient property to true.
     * This must cause the component itself, as well as all of that component's
     * children and facets, to be omitted from the saved  tree structure
     * and component state information.
     *
     * 

This method must also enforce the rule that, for components with * non-null ids, all components that are descendants of the * same nearest {@link NamingContainer} must have unique identifiers. * * For backwards compatability with existing * StateManager implementations, the default * implementation of this method calls {@link #saveSerializedView} * and creates and returns a two element Object array * with element zero containing the structure property * and element one containing the state property of the * SerializedView. * * @since 1.2 * * @param context {@link FacesContext} for the current request * * @throws IllegalStateException if more than one component or * facet within the same {@link NamingContainer} in this view has * the same non-null component id */ public Object saveView(FacesContext context) { SerializedView view = saveSerializedView(context); Object stateArray[] = { view.getStructure(), view.getState() }; return stateArray; }

And the method saveSerializedView(...) does all the dirty work. Basically it will create two objects treeStructure and componentState from the facesContext in the following code:
public SerializedView saveSerializedView(FacesContext context)
          throws IllegalStateException {
  SerializedView result = null;
  Object treeStructure = null;
  Object componentState = null;
  ......
  result = new SerializedView(treeStructure =
              getTreeStructureToSave(context),
                                    componentState =
                                          getComponentStateToSave(context));

  ......
Object stateArray[] = {treeStructure, componentState};
......
actualMap.put(idInActualMap, stateArray);
......
}
In the above code, the Map object actualMap is in another Map logicalMap. And the logicalMap is created in sessionMap which is an object in the session.

Now in another lifecycle when the view needs to be restored, the Restore_View phase will call viewHander.restoreView(facesContext, viewId) in its execute(...) method. And the restoreView(...) method of the ViewHandlerImpl is the following:

public UIViewRoot restoreView(FacesContext context, String viewId,
                                  String renderKitId) {
   ......
   viewRoot = Util.getStateManager(context).restore(context,viewId,renderKitId);
   ......
}
So it basically uses the StateManage again to retrieve the view saved there before.