I'm trying to make a simple application that loads and runs some classes during runtime. For example, let's say I have this config:
module1.classpath=module1.jar,somelibs1.jar
module1.class=com.blabla.Module1
module2.classpath=module2.jar,somelibs2.jar
module2.class=com.blabla.Module2
Then I need to load libraries specified in module1.classpath and run the module1.class with that libraries loaded. Afterwards I need to load module2.classpath and run module2.class with those libraries.
How do I handle the case when somelibs1.jar and somelibs2.jar have the same classes inside? Basically I'd like to run module1.jar using exclusively somelibs1.jar and module2.jar using exclusively somelibs2.jar. How do I implement that?
I'm guessing I need to create a separate classloader for each of my classes and push the jars in that classloaders. However I'd appreciate some example or at least a confirmation that it is a right way to do that.
This seems to be a pretty good use case for OSGI. I would recommend using OSGI for this as everything you nees is provided by OSGI out-of-box.
But if for some reason you can't use OSGI, then what you need to do is to have a classloader for each module. Load the moduleX.class by a ClassLoaderX, and moduleX.classpath should be added in to ClassLoaderX's path. You can use a set of simple URLClassLoader for this.
Thanks for question. Very interesting.
It seems to you can't use several versions of the same class in one instance of JVM. I've never had this task and I don't know how to implement this.
But let's play. I don't know what is exotic application do you develop. May be you can run many JVMs and each JVM will have exclusive CLASSPATH.
Write application which can run (for example using Runtime.exec()) another JVM and make a conversation to it via some channel (may be network).
Related
When distributing a Java application to others, it can be deployed as a JAR file for easy execution.
But is there a way to change a Java class / part of the code after deployment without having to rebundle the whole application again?
If you have an app with say 10 classes where 9 are finalized but one needs to be adjusted according to the individual case. What would be the easiest way to change just one class in an app?
Probably you want to use java web start. If your user starts application via java web start it is automatically being updated if updates are available.
EDIT
It does not provide class-based granularity, but I believe this is not the real issue. It however provides the jar-based granularity, i.e. the newer version of jar is being downloaded only if it was changed.
No, there's not.
You should repackage OR design the one that should be adjusted to be configurable at runtime. If you can modify it using a configuration database and factory that would be the only way to do it without repackaging.
In theory you could create another jar for the customized classes and put it into the classpath before the old jar, and the JVM will load the customized classes. But this is simply looking for trouble...
Better to build two jars, one with the non changing classes and another with the customized classes and rebuild the later when you need it.
I have a whole bunch of framework modules that work fine on OSGi, all the services and components are finding one another and running just fine.
There is however one framework that does some dynamic stuff regarding classes. Basically at some point you give it a class name and it performs Class.forName() and then reflection magic happens.
This works great when running in a standard jvm and using SPI to wire together the frameworks but it fails in OSGi because of course that random class "test.MyTest" that you are trying to approach via the framework is not visible to said framework.
It will throw a "java.lang.ClassNotFoundException: test.MyTest not found by framework"
So my question: how can I solve this lack of visibility for the framework that needs to see all? Import-Package: *?
UPDATE
Assuming OSGi hasn't changed much since 2010 on this front, the article http://njbartlett.name/2010/08/30/osgi-readiness-loading-classes.html is very interesting. I have currently added support for both actively registering classes and a domain factory to be injected via OSGi.
Apart from that the default resolving uses context classloader anyway so if all else fails that will be used to try and load the class.
UPDATE
I have added support for the suggested DynamicImport-Package as well which is easier for small projects.
You can use DynamicImport-Package:*. This will allow the bundle to see all classes. The problem is that you have no real control over what exactly is exposed. So this is normally a last resort and not the recommended way.
You should first try to use Thread.currentThread().setContextClassLoader() and set it to the classloader of the class you provide to the framework. Sometimes the frameworks also consult this classloader.
The even better way is to find a method in the framework that allows to provide the user classloader.
If you have control over the code then avoid Class.forName(). Instead let the user either give you a class object instead of a class name or let the user give you the combination of a class name and the classloader to use. Both ways work perfectly in and outside OSGi.
I have an ant script that I use to build my J2EE application and create jar files. The problem is the following: Two jar files are necessary for the application to run.
commons-math-2.0.jar
commons-math-1.0.jar
However, I want to only use the 2.0 for a particular package inside the application with the rest of the application using 1.0. How can I build the application to only use the 2.0 version for example with a package name such as com.naurus.eventhandler.risk? Again, I'm using an Ant script, but if there's an easier way to do this sort of thing I'm willing to experiment. Thanks!
If the two jars contain different classes/packages there should be no problem to have all of them in the application classpath. It is then a matter of discipline not to use the classes from the one jar in the other package.
However I guess these two jars contain mostly the same classes/methods? There are many ways of using different versions of the same classes:
Using different ClassLoader instances. I would not qualify it as "easy", far from it means opening the door to a bunch of nasty bugs. (can be helped using a tool like OSGi)
Splitting the application in two processes, these process being launched in the same Ant target and using any mean (CORBA, RMI, REST, etc.) to communicate.
I would not advise using any of these methods though. It would probably be simpler to make all your packages use the same version. Is there any specific difficulty in doing so?
That will be problematic since both JAR files will end up in the same classpath when you deploy your J2EE application. You could achieve what you are trying to attempt with OSGI bundles, which allow each package to have separate dependencies. However, that is a relatively large refactoring of your application.
IMO, it would be best to either:
a) Duplicate the features you need from 2.0 (if the number is small and the license allows it, e.g., package individual classes).
or
b) Spend the time to upgrade the entire application to 2.0
You could use the manisfest in your jar to define the classpath.
http://docs.oracle.com/javase/tutorial/deployment/jar/manifestindex.html
Although honestly it seems a bit convoluted, but it is your requirement.
I would like to add some kind of plugin-oriented functionality to a web application I am working on. Main reason behind this is to be able to build different kind of distribution bundles (with different sets of jar files in them) for each customer.
The only thing is I don't want to change configuration files of the application to tell it where it can find its plugins. I would like the application to discover its plugins.
I guess I need something really plain and straight forward.
One possible solution I see it to try to find in classpath classes in jars (which will perform necessary setup actions) implementing some predefined interface.
Is there a way to do this? Thank you in advance.
See the Javadoc for java.util.ServiceLoader.
I want to create a Java program that can be extended with plugins. How can I do that and where should I look for?
I have a set of interfaces that the plugin must implement, and it should be in a jar. The program should watch for new jars in a relative (to the program) folder and registered them somehow.
Although I do like Eclipse RCP, I think it's too much for my simple needs.
Same thing goes for Spring, but since I was going to look at it anyway, I might as well try it.
But still, I'd prefer to find a way to create my own plugin "framework" as simple as possible.
I've done this for software I've written in the past, it's very handy. I did it by first creating an Interface that all my 'plugin' classes needed to implement. I then used the Java ClassLoader to load those classes and create instances of them.
One way you can go about it is this:
File dir = new File("put path to classes you want to load here");
URL loadPath = dir.toURI().toURL();
URL[] classUrl = new URL[]{loadPath};
ClassLoader cl = new URLClassLoader(classUrl);
Class loadedClass = cl.loadClass("classname"); // must be in package.class name format
That has loaded the class, now you need to create an instance of it, assuming the interface name is MyModule:
MyModule modInstance = (MyModule)loadedClass.newInstance();
Look into OSGi.
On one hand, OSGi provides all sorts of infrastructure for managing, starting, and doing lots of other things with modular software components. On the other hand, it could be too heavy-weight for your needs.
Incidentally, Eclipse uses OSGi to manage its plugins.
I recommend that you take a close look at the Java Service Provider (SPI) API. It provides a simple system for finding all of the classes in all Jars on the classpath that expose themselves as implementing a particular service. I've used it in the past with plugin systems with great success.
Although I'll second the accepted solution, if a basic plugin support is needed (which is the case most of the time), there is also the Java Plugin Framework (JPF) which, though lacking proper documentation, is a very neat plugin framework implementation.
It's easily deployable and - when you get through the classloading idiosynchrasies - very easy to develop with. A comment to the above is to be aware that plugin loadpaths below the plugin directory must be named after the full classpath in addition to having its class files deployed in a normal package path named path. E.g.
plugins
`-com.my.package.plugins
`-com
`-my
`-package
`-plugins
|- Class1.class
`- Class2.class
At the home-grown classloader approach:
While its definitely a good way to learn about classloaders there is something called "classloader hell", mostly known by people who wrestled with it when it comes to use in bigger projects. Conflicting classes are easy to introduce and hard to solve.
And there is a good reason why eclipse made the move to OSGi years ago.
So, if its more then a pet project, take a serious look into OSGi. Its worth looking at.
You'll learn about classloaders PLUS an emerging technolgy standard.
Have you considered building on top of Eclipse's Rich Client Platform, and then exposing the Eclipse extension framework?
Also, depending on your needs, the Spring Framework might help with that and other things you might want to do: http://www.springframework.org/