Dynamic .JAR loading
Hi All,
I am not sure if this is possible, but my problem is briefly;
I have to use xxx4.jar library for my application and I used it perfectly, but then the third party published the newer version of the library that I used as xxx5.jar. None of the interfaces has changed but only one of the package name has changed. So I dont have to change a lot in my code(hopefully).
I want to read my config file(a parameter) and decide which jar file to use in my application depending on the parameter i read in run-time, is it possible? and How? or is there any other solution to this problem?
Thanks in advance
[635 byte] By [
oturcoa] at [2007-10-2 16:10:27]

You can implement jar-file loading using URLClassLoader and JarInputStream classes. For example:
package com.comarch.telco.test;
import java.io.*;
import java.net.*;
import java.util.jar.*;
public class MyJarLoader {
public static void main(String[] args) throws FileNotFoundException, IOException {
String jarName = "c:/temp/temp.jar"; // заменить на свой
URLClassLoader urlLoader = getURLClassLoader(new URL("file", null, jarName));
JarInputStream jis = new JarInputStream(new FileInputStream(jarName));
JarEntry entry = jis.getNextJarEntry();
int loadedCount = 0, totalCount = 0;
while (entry != null) {
String name = entry.getName();
if (name.endsWith(".class")) {
totalCount++;
name = name.substring(0, name.length() - 6);
name = name.replace('/', '.');
System.out.print("> " + name);
try {
urlLoader.loadClass(name);
System.out.println("\t- loaded");
loadedCount++;
} catch (Throwable e) {
System.out.println("\t- not loaded");
System.out.println("\t " + e.getClass().getName() + ": " + e.getMessage());
}
}
entry = jis.getNextJarEntry();
}
System.out.println("\n");
System.out.println("Summary:");
System.out.println("\tLoaded:\t" + loadedCount);
System.out.println("\tFailed:\t" + (totalCount - loadedCount));
System.out.println("\tTotal:\t" + totalCount);
}
private static URLClassLoader getURLClassLoader(URL jarURL) {
return new URLClassLoader(new URL[]{jarURL});
}
}
AciDa at 2007-7-13 16:54:29 >

> Hi All,
>
> I am not sure if this is possible, but my problem is
> briefly;
> I have to use xxx4.jar library for my application
> and I used it perfectly, but then the third party
> published the newer version of the library that I
> used as xxx5.jar. None of the interfaces has changed
> but only one of the package name has changed. So I
> dont have to change a lot in my code(hopefully).
>
> I want to read my config file(a parameter) and decide
> which jar file to use in my application depending on
> the parameter i read in run-time
Given there is an impact in your code, I don't understand why you focus on selecting the 3rd-party jar. Maybe I have misunderstood your question ?
1) Do you want to integrate the new lib in your distribution, replacing the old one?
Then simply update your code, bundle everything consistently (new code with new jar), and release an update of the bundle.
2) Is is that the 3rd-party jar is not part of your bundl, and your customers will throw in their own version of the 3rd-party jar?
Then you also need to provide both versions of your code in the distribution, and in addition to selecting the 3rd-party jar to use at runtime, you also need to select the relevant version of your code.
2-1) As far as the 3rd party jar is concernd:
as one former poster says, the safest and cheapest way is to specify the classpath accordingly (if your customer is able to elect a version of the 3rd-party, it is probably able to edit a classpath script).
2-2) As far as your code is concerned:
2-2-1 : you can package the impacted classes in
a separate jar, and provide 2 versions of the jar. Same issue/soluton as above then.
2-2-2 : Alternately, you can dedouble each impacted class (MyClientClassForv4, MyClientClassForv5, both have a common MyClient interface), and select the correct one at initialization of your program (there is likely one root class from which all dependants will follow). But that forces you into architecting an awkward inheritance hierachy for all such classes.
2-2-3: If such changes are likely to happen in the future, you can also choose to design an Adapter layer for this library.
For example if the library exports a com.3dparty.Xxx class, you can design a com.yourcompany.XxxAdapter interface or abstract class, and have com.yourcompany.Xxxv4Adapter and com.yourcompany.Xxxv5Adapter implementation classes. You can also design an Xxxv6 class in the future, or even switch the provider library for another provider, designing just another adpater class.
I used to work for a company who designed such adapters for almost all of their dependency libraries (including low-levels suchs a util.log package to abstract from log4j/jdkLogger, a util.mail package, a util.xml,...).
The drawback obviously, are:
- design-wise, you have to design the adapter interfaces in a very abstract way, especially abstracting from the library's implementation. Easy (?) for the log or mail, a bit harder for the (real-life example) TrainReservationSystem...
- maintenance-wise, if you want to update the abstract layer (add new Log levels constants, stupid example), you likely have to update all the adapter implementations accordingly.