The "One Laptop Per Child" project has a great device ready to ship, but there's no Java on there. Let's think about working together to put Java on OLPC!
Scenario 1:
Imagine we have a 3rd party JAR in our application plug-in's
lib
directory, and necessary CLASSPATH added so that it's classes may be used in our code.Most of these code libraries allow dynamic loading of classes. In order to get that through with Eclipse,most of us are aware of the trick:
Thread currentThread = Thread.currentThread();
ClassLoader oldLoader = currentThread.getContextClassLoader();
Scenario 2:
It is a good practice to have 3rd party library JARs wrapped up in a different plugin, and to make other application plug-ins dependent on that, so that, each of these application plug-ins do not need to have those library files individually added to their classpaths,and duplicate them.
Having said this, let's think of putting the XML parser library,
Digester
jars from Apache, in a plugin
org.xyz.lib
. I am not going into the details of how to make 3rd party jars wrapped up in a separate plugin. There are lots of articles on that in this forum, as well as other forums.
We have our application plug-in, say
org.xyz.abc
, and we make it dependent on
org.xyz.lib
Now, let's say we start using the
Digester
functions. Everything compiles well, but when we try to run the application, we get a run-time error,
java.lang.ClassNotFoundException
Putting our old trick in action :
Digester digester = new Digester();
...
...
also doesnot seem to help at all, and we get the same error.
Investigating closely, we see that the current scenario is different from the first one. The class loader of the
Digester
class, is definitely not the same as the class loader of the currently executing application plug-in's class, because
Digester
is sitting on a different plug-in,and classloaders in eclipse are different for different plug-ins.
Fortunately Digester has 2 public methods:
setUseContextClassLoader(boolean use)
and
setClassLoader(java.lang.ClassLoader classLoader)
Either one would make things work:
1. If we wish to use
setUseContextClassLoader(boolean use)
, then code should look something like this:
Digester digester = new Digester();
...
...
2. Using
setClassLoader(java.lang.ClassLoader classLoader)
, the code would be much smaller, because Digester does the remaining job
Digester digester = new Digester();
...
...
Depending on your 3rd party libraries,you need to decide which to use. Now unfortunately, if the 3rd party libraries do not provide similar methods as shown above, and always internally uses a statement like
this.getClass().getClassLoader()
to obtain the current classloader, then I think we are in trouble and cannot package it in a separate plug-in. Rather we then need to package with individual plugins as was shown for
Scenario 1
.
I think packaging them into their own plugins is the way to go. This forces these 3rd party jars to be packaged correctly for re-use in the Eclipse platform. If an API is exposed in Eclipse it should fit the OSGI bundle model. Going ahead and wrapping it correctly with an Eclipse layer is probably your safest bet if Apache won't wrap it already.
Thanks for pointing that out. Indeed, in this case, we can use Buddy classloading in eclipse to resolve these classloader issues, by simply adding:
Eclipse-BuddyPolicy: registered
in the MANIFEST.MF of the 3rd party library plug-in
and in the application plugins's MANIFEST.MF, we add:
Eclipse-RegisterBuddy: org.xyz.lib
where org.xyz.lib is the library JAR plugin.
Hi,
I tried the scenario two and created a plugin for 3rd part jars, now i have my application plugin dependent on the 3rd party jar, but when i try to access the classes of the third party jar..i still get the class not found exception..
am i missing on something??
As mentioned, if your current 3rd party class, is not having a way to manipulate your current Class-Loader, then these will not work. In that case, Buddy-classloading should do the job. Please look at my previous thread.
Incase you still have a problem, you can send me your proto plugin code with your 3rd party JAR, at account4sanjay AT yahoo dot com, I shall be more than happy to help you.
Resolving ClassLoader issues across plug-ins
At 3:16 AM on Jan 18, 2006, Sanjay Chaudhuri
wrote:
Imagine we have a 3rd party JAR in our application plug-in's
libdirectory, and necessary CLASSPATH added so that it's classes may be used in our code.Most of these code libraries allow dynamic loading of classes. In order to get that through with Eclipse,most of us are aware of the trick:Thread currentThread = Thread.currentThread();
ClassLoader oldLoader = currentThread.getContextClassLoader();
try
{
currentThread.setContextClassLoader( XyzTest.class.getClassLoader());
//Call the library code
}
...
...
finally
{
currentThread.setContextClassLoader( oldLoader);
}
Scenario 2:
It is a good practice to have 3rd party library JARs wrapped up in a different plugin, and to make other application plug-ins dependent on that, so that, each of these application plug-ins do not need to have those library files individually added to their classpaths,and duplicate them.
Having said this, let's think of putting the XML parser library, Digester jars from Apache, in a plugin
org.xyz.lib. I am not going into the details of how to make 3rd party jars wrapped up in a separate plugin. There are lots of articles on that in this forum, as well as other forums.We have our application plug-in, say
org.xyz.abc, and we make it dependent onorg.xyz.libNow, let's say we start using the Digester functions. Everything compiles well, but when we try to run the application, we get a run-time error,
java.lang.ClassNotFoundExceptionPutting our old trick in action :
Digester digester = new Digester();
...
...
Thread currentThread = Thread.currentThread();
ClassLoader oldLoader = currentThread.getContextClassLoader();
try
{
currentThread.setContextClassLoader( XyzTest.class.getClassLoader());
digester.parse(...);
}
...
...
finally
{
currentThread.setContextClassLoader(oldLoader);
}
also doesnot seem to help at all, and we get the same error.
Investigating closely, we see that the current scenario is different from the first one. The class loader of the Digester class, is definitely not the same as the class loader of the currently executing application plug-in's class, because Digester is sitting on a different plug-in,and classloaders in eclipse are different for different plug-ins.
Fortunately Digester has 2 public methods:
setUseContextClassLoader(boolean use)andsetClassLoader(java.lang.ClassLoader classLoader)Either one would make things work:
1. If we wish to use
setUseContextClassLoader(boolean use), then code should look something like this:Digester digester = new Digester();
...
...
Thread currentThread = Thread.currentThread();
ClassLoader oldLoader = currentThread.getContextClassLoader();
try
{
currentThread.setContextClassLoader( XyzTest.class.getClassLoader());
digester.setUseContextClassLoader(true);
digester.parse(...);
}
...
...
finally
{
currentThread.setContextClassLoader(oldLoader);
}
2. Using
setClassLoader(java.lang.ClassLoader classLoader), the code would be much smaller, because Digester does the remaining jobDigester digester = new Digester();
...
...
try
{
digester.setClassLoader( XyzTest.class.getClassLoader());
digester.parse(...);
}
...
...
Depending on your 3rd party libraries,you need to decide which to use. Now unfortunately, if the 3rd party libraries do not provide similar methods as shown above, and always internally uses a statement like
this.getClass().getClassLoader()to obtain the current classloader, then I think we are in trouble and cannot package it in a separate plug-in. Rather we then need to package with individual plugins as was shown for Scenario 1 .6 replies so far (
Post your own)
Re: Resolving ClassLoader issues across plug-ins
I think packaging them into their own plugins is the way to go. This forces these 3rd party jars to be packaged correctly for re-use in the Eclipse platform. If an API is exposed in Eclipse it should fit the OSGI bundle model. Going ahead and wrapping it correctly with an Eclipse layer is probably your safest bet if Apache won't wrap it already.Re: Resolving ClassLoader issues across plug-ins
this is perfect scenario for buddy classloadingRe: Resolving ClassLoader issues across plug-ins
Thanks for pointing that out. Indeed, in this case, we can use Buddy classloading in eclipse to resolve these classloader issues, by simply adding:Eclipse-BuddyPolicy: registeredin the MANIFEST.MF of the 3rd party library plug-in
and in the application plugins's MANIFEST.MF, we add:
Eclipse-RegisterBuddy: org.xyz.libwhere org.xyz.lib is the library JAR plugin.
Re: Resolving ClassLoader issues across plug-ins
Hi,I tried the scenario two and created a plugin for 3rd part jars, now i have my application plugin dependent on the 3rd party jar, but when i try to access the classes of the third party jar..i still get the class not found exception..
am i missing on something??
Re: Resolving ClassLoader issues across plug-ins
As mentioned, if your current 3rd party class, is not having a way to manipulate your current Class-Loader, then these will not work. In that case, Buddy-classloading should do the job. Please look at my previous thread.Incase you still have a problem, you can send me your proto plugin code with your 3rd party JAR, at account4sanjay AT yahoo dot com, I shall be more than happy to help you.
Thanks
Sanjay
Re: Resolving ClassLoader issues across plug-ins
My eclipse debugger is extremely slow. When I hit a break point it takes a very long time to display the variables, and to step over/into code.I tried to update my eclipse.ini file to different properties, currently it's at:
-vmargs
-Xms1024m
-Xmx1024m
-Xmn256m
--launcher.XXMaxPermSize
512M
--launcher.XXMaxPermSize
128M
The problem doesn't go away. Outside of debug mode, eclipse works fairly fast. Does anyone have any idea of how to fix this problem?
Thank you very much in advance for your help