Replacing classes/resources with an OSGi fragment - possible without including a jar in the fragment?

2.7k views Asked by At

We want to replace certain resources in a host OSGi bundle by adding an OSGi fragment.

As I understand it, the resources included in an OSGi fragment are merely added to the classpath of the host bundle. There is no guarantee that if the fragment is adding a resource that already exists in the host bundle, the resource from the fragment will be loaded: it could also still be the host version.

In order to make sure the fragment version of the resource is loaded instead of the host version, http://wiki.osgi.org/wiki/Fragment mentions it is possible to use the Bundle-ClassPath header to specify resources as "first"(preferred).

It gives patch.jar as an example:

Bundle-ClassPath: patch.jar,.

As mentioned there: "Since patch.jar is ahead of '.' it will allow classes to be preferentially loaded from the fragment instead of the host."

I could use this technique, but this means I first have to bundle my fragment resources in a separate jar and then include this jar in the fragment bundle.

Is there a way to preferentially load classes/resources from the fragment instead of the host without having to include a jar in the fragment?

3

There are 3 answers

0
BJ Hargrave On BEST ANSWER

You don't have to include a jar. You can instead use a "patch" directory and then put your classes in a patch directory in the fragment.

0
pm_ On

For those that are still struggling, these are the exact steps that worked for me:

  1. Create a fragment project with the resource/class you want to replace

  2. In the fragment's build.properties, change source.. = src/ and output.. = bin/ to source.patch/ = src/ and output.patch/ = bin/

  3. In the fragment's manifest, add patch/ to the bundle class-path

Example:

Let's say you have com.example.ui plug-in which has a com.example.ui.MessageDialog class that you want to replace.

  • Create a fragment project com.example.ui.fragment

  • Create the MessageDialog class in the com.example.ui package (not com.example.ui.fragment);

  • Edit the fragment's build.properties file like this:

    source.patch/ = src/
    output.patch/ = bin/
    
  • In the fragment's manifest add this:

    Bundle-ClassPath: patch/
    
  • In the com.example.ui manifest change the bundle class-path:

    Bundle-ClassPath: patch/,. 
    
0
Mike Van On

Ok, there are a couple of ways to accomplish what you want. As I understand it, after everything is done, you want to export packages from a library bundle except for the packages located in your patch bundle.

To accomplish this, in the Manifest.MF of your library bundle, specify the explicit packages you want to export instead of '.'. You can do this with a fragment so that you won't have to modify the original bundle. Then, do the same with your patch bundle.

Another option is to use the maven-bundle-plugin to "shade" (merge) the patch bundle and the library bundle together into a new bundle. As long as the patch bundle and he library bundle have different version numbers, this will also work. Many blogs will instruct you to use the maven-shade-plugin along with the maven-bundle-plugin for this option, but they are incorrect. You can definately perform shading with the maven-bundle-plugin.