0

I have a Java app (that should deploy as an executable JAR) that takes a JSON file as input, something like this:

"appConfig": {
    "fizzClass": "com.me.myorg.FizzImpl"
    // Lots of other configs
}

The config allows a user to specify what fizzClass to use (for something, doesn't really matter what) at runtime. The thing is, I want this app to accept plugins; that is, I can (dynamically, at runtime) add JARs to the app, where perhaps other Fizz implementations may be packaged, and then the user can specify these newly-available impls in their config files. For instance, perhaps my app only has public class FizzImpl implements Fizz in it. Now let's say someone develops a plugin, foo-plugin.jar that contains public class FooFizz implements Fizz. Now, after deployed as a plugin to my app, an end user could pass the app the following config:

"appConfig": {
    "fizzClass": "com.some.other.foo.FooFizz"
    // Lots of other configs
}

...without getting ClassNotFoundExceptions, etc. Because now FooFizz is on the app's runtime classpath.

OSGi feels like the perfect solution for this. I'm trying to understand Apache Felix's architecture. My understanding is that I deploy my app as a JAR but include the Felix JAR as a dependency to it, which gives me access to a plugin architecture. I then have to require that plugin developers package their JARs as OSGi bundles. So first, if anything about those statements is mis-led or incorrect, please begin by correcting my understanding of how a Java JAR taps into the Felix OSGi runtime!

Assuming I'm more or less correct in my understanding, my question is: in order to develop plugins for my app, do I just follow the normal instructions for packaging bundles, or is there a special "trick" to tapping into Felix's plugin architecture?

IAmYourFaja
  • 55,468
  • 181
  • 466
  • 756

1 Answers1

2

A good way to implement a plugin architecture in OSGi is to use OSGi services. You package the Fizz interface and everything else that forms your API into one bundle. Then you use a second bundle for the FizzImpl and use an activator or e.g. blueprint to publish the impl instance as an OSGi service. The last part is your main application which needs to bind the service and call the service using the interface. So this would be your default setup.

Then someone can create another bundle with an alternative implementation and also publish it as a service. To distinguish the two services you can specify properties when publishing the service.

Then in your main application you can use a configurable filter to bind the service which matches the filter. So you can switch the impl by changing the filter.

I used this approach in cxf xkms to implement an ldap based backend for xkms that can be switched for something else. This is the blueprint file for the ldap impl: https://github.com/apache/cxf/blob/master/services/xkms/xkms-x509-repo-ldap/src/main/resources/OSGI-INF/blueprint/blueprint.xml

and this is the blueprint xml for the main application: https://github.com/apache/cxf/blob/master/services/xkms/xkms-osgi/src/main/resources/OSGI-INF/blueprint/blueprint.xml

and as a last part this is the java code to bind a service using a configurate filter: https://github.com/apache/cxf/blob/master/services/xkms/xkms-service/src/main/java/org/apache/cxf/xkms/service/CertificateRepoProxyFactory.java

Christian Schneider
  • 19,420
  • 2
  • 39
  • 64
  • Thanks @Christian Schneider (+1)! A few quick followup questions: what are the constraints on my app in your above example? Can it be any old executable JAR or Tomcat WAR? Or does it have to be deployed to an OSGi container like Karaf? **And, most importantly**, if that's the case, is there a way to embed OSGi *inside* a JAR/WAR so I can use OSGi for this plugin/modular functionality, but otherwise have no dependencies on OSGi? Thanks again! – IAmYourFaja Jun 27 '14 at 14:01
  • 1
    Your application as well as all extensions have to be OSGi bundles. So if this is not yet the case it can become difficult especially for third party dependencies. You can embed the OSGi framework inside your application but I have not yet tried this myself. – Christian Schneider Jun 27 '14 at 15:26
  • Thanks again @Christian Schneider (+1) - one last followup here: You say that my app and any extensions must all be OSGi bundles, but then you mention that I can embed the OSGi framework inside my app. Does this mean that I can have a non-OSGi app running an embedded OSGi framework (and thus, binding to OSGi bundles/plugins)? Or would my app *still* need to be OSGi? Thanks again! – IAmYourFaja Jun 27 '14 at 17:05
  • You can create the main application as standard java application and let it start an embedded framework. It can then access services of the OSGi framework. In this case only the extensions would need to be bundles. See this for details http://stackoverflow.com/questions/24411334/how-do-you-call-an-osgi-application-from-a-non-osgi-application-and-vice-versa/24416516#24416516 – Christian Schneider Jun 27 '14 at 20:19