IntroductionThis describes a simple example of ClassMan descriptor. Let us assume that Phoenix has been integrated with ClassMan and that the snippet defining classloader is included in Phoenixes deployment format (the .sar file). Let us also assume that we want to host a servlet container (like Catalina, Jo! or Jetty) in Phoenix. The servlet specification requires that the servlets are capable of "seeing" the servlet API but recomends strongly that no servlet should be able to access any container specific classes. To satisfy this requirement we decided to place the Servlet API classes in a parent ClassLoader to the Containers ClassLoader and each Web Applications ClassLoader. ie Servlet API CL | +------+------+ | | Servlet WebApp Container CL CL This way, both the Container and the WebApp ClassLoaders will load the Servlet API from the same ClassLoader. Unfortunately, in our case Phoenix already assembles the Servlet Container CL by default and does not give us the opportunity to construct the Servlet API CL as a parent ClassLoader. Luckily we can overide this using the ClassMan toolkit using the following configuration file. <classloaders default="container" version="1.0"> <!-- needed to run under earlier JVMs that do not include JNDI --> <classloader name="jndi-api" parent="*system*"> <entry location="sar:SAR-INF/ext/jndi.jar"/> </classloader> <!-- The actual Servlet API classLoader. Note that this does not specify a physical location but instead defines an extension. This allows the container to search for the library that best satisfies this extension. Usually all the extensions are stored in a central directory and Phoenix will search through the jars in central to find the servlet jar. This allows several applications to share the same jar. --> <classloader name="servlet-api" parent="*system*"> <extension> <name>javax.servlet</name> <specification-version>2.3</specification-version> <vendor-id>org.apache.jakarta</vendor-id> <vendor-version>1.2.3.4</vendor-version> </extension> </classloader> <!-- This is a special ClassLoader that merges two other ClassLoaders together. When you try to load a class from this ClassLoader, the ClassLoader will first try to load the class from servlet-api ClassLoader and then try to load the class from the jndi-api ClassLoader. This works fine if the ClassLoaders define disjoint sets of classes. ie No class should be loadable from both the servlet-api ClassLoader and the jndi-api ClassLoader (with the exception of Classes Loaded from System ClassLoader). --> <join name="common"> <classloader-ref name="servlet-api"/> <classloader-ref name="jndi-api"/> </join> <!-- This classloader is needed to join the Phoenix API and the Servlet API into one ClassLoader. This is needed because the container is built using Phoenix APIs but needs to share the Servlet APIs with the WebApps. --> <join name="container-base"> <classloader-ref name="common"/> <classloader-ref name="*phoenix.api*"/> </join> <!-- This classloader is the one used to actually load the Servlet Container. We know this as it is specified as the default ClassLoader in <classloaders/> element. --> <classloader name="container" parent="container-base"> <entry location="sar:SAR-INF/classes/"/> <fileset dir="sar:SAR-INF/lib/"> <include name="*.jar"/> </fileset> </classloader> </classloaders> The first thing you notice about this is that the ClassLoader hierarchy is much more complicated. In fact the diagram now looks like; "servlet-api" "jndi-api" CL CL | | +------+------+ | "*phoenix.api*" "common" CL | | +----+ +------+------+ | | | "container- WebApp base" CL CL (This is constructed | by Container but "container" shown for completeness) CL In reality we could have merged "servlet-api" and "jndi-api" into "common" but we separated them for illustration purposes. One thing you should notice is that Phoenix exposes two predefined ClassLoaders;
The above demonstrates one of the most complex examples that you are likely to come across. This arose because there was multiple "containers" hosted in same ClassLoader hierarchy. The Servlet API specification requires that implementation classes not be visible to API clients. The Phoenix API specification requires the same thing. |