JCL
Jar Class Loader, a configurable and dynamic custom classloader designed to create, manage and manipulate isolated Java classloaders in IoC frameworks and web applications.
Install / Use
/learn @kamranzafar/JCLREADME
!https://travis-ci.org/kamranzafar/JCL.png?branch=master!:https://travis-ci.org/kamranzafar/JCL
h1. Overview
JCL is a configurable, dynamic and extensible custom classloader that loads java classes directly from Jar files and other sources. The motivation was to create isolated classloaders, which can be easily integrated with IoC frameworks like Spring and with web applications.
The entire library, including it's code-base and documentation is available under the terms and conditions of "Apache License 2.0":http://www.apache.org/licenses/LICENSE-2.0.
h1. Installation
To use JCL, download and build the JCL project and put jcl(-core-2.x).jar and dependencies in the application's classpath. See the build section below and also check out the downloads section for more details on the available builds and source.
JCL is also available in Maven Central Repository, which makes it very easy to use in maven projects as a dependency.
h1. Building JCL
JCL is a multi-module maven project that has five modules as shown below:
<pre> <code> JCL |---> core |---> spring |---> web |---> test-jcl |---> test-web </code> </pre>The test-* modules create resources to run the unit tests and a sample web application. The core module builds an artifact with all the main JCL class files. The spring module generates an artifact for spring integration.
To build JCL, check-out the source code of JCL2 from "github":https://github.com/kamranzafar/JCL and run the following command:
<pre> <code> mvn clean install </code> </pre>This command will create jcl-core and jcl-spring artifacts, and will also create a sample war file to test JCL web integration. It will also copy the dependencies of each artifact in the dependecies folder.
h1. Requirements
JCL requires JDK 1.5 or later; and will pull in all its dependencies using maven.
h1. Usage
Below is a little tutorial on JCL v2 with examples. Please also see the overview section for installation.
h2. What's new in v2
Version 2.x now deprecates version 1.x so we recommend users to switch to version 2, which was a complete refactoring of version 1 and has a better design with a lot more features. Following is a list of some updates and changes in v2.x:
- Total refactoring of version 1
- Maven is being used for project management instead of ANT
- Added more robust spring and web support
- Added OSGi boot loading
- JCL 2 is more customizable and configurable
- etc. etc.
h2. Using JCL
JCL is a light weight API and has only a few but useful classes. Here is a simple example on how to programmatically use JCL. JarClassLoader has an arguments-constructor and add methods that take jar-file/class-folder paths, URLs and InputStreams.
<pre> <code> JarClassLoader jcl = new JarClassLoader(); //Loading classes from different sources jcl.add("myjar.jar"); jcl.add(new URL("http://myserver.com/myjar.jar")); jcl.add(new FileInputStream("myotherjar.jar")); jcl.add("myclassfolder/"); //Recursively load all jar files in the folder/sub-folder(s) jcl.add("myjarlib/"); JclObjectFactory factory = JclObjectFactory.getInstance(); //Create object of loaded class Object obj = factory.create(jcl, "mypack.MyClass"); </code> </pre>Now we can use reflection to invoke methods of this object. It is also possible to create object proxies and call methods the normal way, this is done by using cast(able) methods available in JclUtils class explained later.
h2. Creating a JCL Context
In order to access the created JarClassLoader instance from any where in the application a JclContext must be created. The DefaultContextLoader provides a way to create this context for a single programmatically created JarClassLoader instance.
<pre> <code> JarClassLoader jcl = new JarClassLoader(); jcl.add("myjarlib/"); DefaultContextLoader context=new DefaultContextLoader(jcl); context.loadContext(); </code> </pre>Now "jcl" can be accessed from anywhere in the application as follows.
<pre> <code> JarClassLoader jcl=JclContext.get(); // returns the Default JCL instance </code> </pre>It is also possible to create an XML configuration file for JCL and use XmlContextLoader to create the context.
h2. Using JCL in Web Applications
One of the motivations behind JCL was to be able to create multiple isolated classloaders in a single web application hosted on application servers like JBoss, Tomcat etc. This is achieved with JclContextLoaderListener.
The JCL configuration is put in a XML file and then the JclContextLoaderListener is used to load the context. Below is an example of JCL XML configuration. Note: as of v2.6 jcl-web dependency is required for the following.
<pre> <code> <?xml version="1.0" encoding="UTF-8"?> <jcl-context> <jcl name="jcl1"> <loaders> <loader name="jcl.parent"> <order>3</order> <enabled>true</enabled> </loader> <loader name="jcl.local"> <order>1</order> <enabled>true</enabled> </loader> <loader name="jcl.current"> <enabled>false</enabled> </loader> <loader name="jcl.thread"> <enabled>true</enabled> </loader> <loader name="jcl.system"> <enabled>true</enabled> </loader> <loader name="jcl.bootosgi"> <enabled>true</enabled> <strict>true</strict> <bootDelegation>mypack.system.*</bootDelegation> </loader> <loader name="custom" class="mypack.MyLoader"> <order>2</order> <enabled>true</enabled> </loader> </loaders> <sources> <source>webapp:WEB-INF/mylib/myjar.jar</source> <source>webapp:myotherjar.jar</source> </sources> </jcl> <jcl name="jcl2"> <sources> <source>webapp:WEB-INF/myjarlib/</source> </sources> </jcl> </jcl-context> </code> </pre>In this example two classloaders are created in a single context. The source paths starting with webapp: are treated as paths to internal web application jar files and folders. After this configuration, the context can be loaded in the web application by adding the JclContextLoaderListener in the application's web.xml file.
<pre> <code> <context-param> <param-name>jcl-context</param-name> <param-value> classpath:jcl.xml </param-value> </context-param> <listener> <listener-class>org.xeustechnologies.jcl.web.JclContextLoaderListener</listener-class> </listener> </code> </pre>The JCL instances can then be accessed by name from anywhere in the web application as shown below.
<pre> <code> JarClassLoader jcl1=JclContext.get("jcl1"); JarClassLoader jcl2=JclContext.get("jcl2"); </code> </pre>h3. Sample web application
The JCL project also includes a sample web application that demonstrates JCL web-app integration. The jcltest.war file is created in the test-web module at jcl-project/test-web/target when the project is built. The content of the war file is also under the same module and is located in jcl-project/test-web/src/main folder. The exploded war folder contains all the files that clearly shows the usage of JCL in web applications.
After deploying the sample web application, go to http://server-name:8080/jcltest; this will print "Hello World" on the screen with classloader details. This message is returned from a JCL-loaded object, see jcl-project/test-web/src/main/jcltest.war/index.jsp for more details.
h2. Using JCL with Spring Framework
JCL can be used with spring framework. JCL v2 provides Spring XML extension to load beans via JCL. The JCL bean is created using the new jcl:jcl element and spring beans can reference the jcl bean by using the jcl:jcl-ref element as shown in the example below. These elements are defined in the jcl-schema.xsd. This also works well in a web application using the Spring ContextLoaderListener. In addition to this JCL v2 also supports the older way of Spring integration, please see the spring-test.xml file provided with the source.
<pre> <code> <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jcl="http://www.xeustechnologies.org/schema/jcl" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.xeustechnologies.org/schema/jcl http://www.xeustechnologies.org/schema/jcl/jcl.xsd"> <jcl:jcl id="jcl1"> <constructor-arg> <list> <value>target/test-jcl.jar</value> </list> </constructor-arg> </jcl:jcl> <jcl:jcl id="jcl2"> <constructor-arg> <list> <value>target/test-jcl.jar</value> </list> </constructor-arg> </jcl:jcl> <bean id="test1" class="org.xeustechnologies.jcl.test.Test"> <jcl:jcl-ref ref="jcl1" /> <constructor-arg ref="name"/> <property name="lastName"> <value>Zafar</value> </property> </bean> <bean id="name" class="java.lang.String"> <jcl:jcl-ref ref="jcl2" /> <constructor-arg> <value>Kamran</value> </constructor-arg> </bean> </beans> </code> </pre>h2. Casting objects of types loaded in JCL
Java does not allow casting objects of types loaded in a different classloader; such casting attempt results in a ClassCastException. But sometimes it is necessary to cast objects to obtain interface references loaded in the current classloader. E.g. suppose that an API implementation is loaded using JCL and the API itself is loaded in the current classloader, now it is easy to use the interface reference to invoke methods than usin
