Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Looking for basic example of using Apache Felix in dynamic loading of Jar file and instancing a class at runtime in Java

I tried implementing my own class loader based on some examples. However, I think it is not working as expected ( unable to reload Jar file etc. I see few references of recommending using OSGI or Apache Felix for handling Jar file loading. Is there any examples of loading Jar, instancing a class from the Jar?

More details on what I am trying to accomplish..I have a Java command line application that essentially continuously runs. I want it to be able to reference JAR files dynamically at runtime and at run-time instance a class in these jars. These jars may contain 1 or more supporting classes. These Jars are essentially customized work units that get executed by certain event conditions from the main application that is continuously running. .. Since this is a multi-client, I wanted to have the jars be a pluginable type work units.

My current direction has been providing the 'client' an interface to code to and then having them package their classes in a jar file. The application will then execute the configured ( database ) jar path and run class from the Jar. This works with loading of a jar and class however, I want to be able to essentially hot deploy these jars.

In summary I would like to have a JAR file that contains classes to support a function. A defined class that will be referenced at run-time from the Jar ( from the main looping application ). The ability to change out JAR files while the main application is running.

If I am to use a third party library, it is preferred that I use Apache Felix.

thanks

I think I figured it out using Apache Felix 4. Is this the best way to load jars/classes ? Or is there a better more efficient way. My research so far did not point to one solution. thanks.

    FrameworkFactory ff = new FrameworkFactory ();
     Map<String,Object> config = new HashMap<String,Object>();
      config.put("org.osgi.framework.storage", "c:\\temp\\myclientBundles");
       config.put(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA,
   "packages needed,more packages needed");
  config.put(Constants.FRAMEWORK_STORAGE_CLEAN, "true");

  Framework fwk = ff.newFramework(config);
  fwk.start();


  BundleContext bc = fwk.getBundleContext();

  Bundle bundle =   bc.installBundle("file:C:\\my_client.jar");


      bundle.start();
      bundle.update();
      Class clazz = bundle.loadClass("client.work.process");
      Job pc = (Job) clazz.newInstance();
      pc.startWork(someConfigObject);
      bundle.stop();
      fwk.stop();
like image 844
user1533269 Avatar asked Oct 08 '22 05:10

user1533269


2 Answers

If Now, simple said, I refuse to believe your problem is loading a class ... :-) I think you have quite another problem that you think can be solved to load a class?

In the majority of cases where people naively start loading classes the problem is extensibility. They have a system and want to selectively extend it with new functionality, I am making the assumption that you have a similar problem since you want to update the provider jar?

If so, download bndtools and look at OSGi services, they usually fit the bill very well

Ok, after your update. If I understand you well, you would be very well served with Apache Felix and Apache Felix File Install. File Install watches a directory and installs any bundle in that directory in the framework. Removing that jar from the directory, uninstalls the bundle. (I wrote the archetype of File Install over 12 years ago!)

For you main JAR, make it look like:

@Component(immediate=true)
public void Main {  
    @Reference
    void setClient( Client client) { ... } // called whenever a client gets started
}

For each client JAR:

@Component
public void ClientImpl implements Client {
  ... whatever
}

This is virtually all you have to write when you use bndtools. Just create a component project, add a Bundle Descriptor for the main code and any number of descriptors for the client code examples, then Run As -> OSGi Run. You can then download Apache Felix File Install, add this to the run tab, and create some other projecs, drop the jars (continuously made in the generated folder) into the file install folder ... voila. Does not get much simpler than this :-)

like image 186
Peter Kriens Avatar answered Oct 12 '22 09:10

Peter Kriens


If I understand you right, you are asking for an example how to dynamically load a jar in OSGi, is that right?

In OSGi the modules that are dynamically loaded are called bundles. So basically the most usual approach to solve your problem will be to turn your jars in OSGi bundles. An OSGi bundle is a normal Java jar with some enhancements - it has a manifest file (a txt file) where dependencies on other java packages are declared; and an Activator class which is called when the bundle is started and stopped. This Activator is the central piece of the bundle, it knows how to instantiate the other parts of the bundle.

Now, if your dynamic jar is simply a library jar and you only want to provide its java packages in the system, you can even go without an activator, by only adding a simple manifest file. There are even tools that can do the conversion automatically for you - check BND.

Then, when you have your bundle ready, you can install it dynamically on any OSGi framework, by using the install command. Reloading is done by calling the update command etc. The lifecycle is very well defined and I would definitely recommend using this instead of reinventing the wheel ;)

For some examples and demos see here.

Hope this helps.

like image 31
pooh Avatar answered Oct 12 '22 09:10

pooh