OSGI Import-Package: version vs bundle-version - what's the difference?

Eric B. picture Eric B. · Apr 5, 2016 · Viewed 9.2k times · Source

I'm having trouble getting an OSGi bundle loaded into a third party framework. It keeps rejecting my bundle because I am specifying Import-Package versions that do not exist, even though I know they are loading the bundles with the versions I want/need. To get around the problem, I have temporarily disabled my version requirements, but it is a little ugly.

Import-Package: com.ghc.ghTester.expressions,org.apache.ws.security;vers
 ion=0,org.apache.ws.security.components.crypto;version=0,org.apache.ws.
 security.message;version=0,org.apache.ws.security.message.token;version
 =0,org.apache.ws.security.processor;version=0

When I look at the Manifest for my dependency, I see:

Bundle-Version: 1.5.11
Bundle-ClassPath: wss4j-1.5.11.jar
Bundle-Vendor: Apache
Export-Package: org.apache.ws.axis.security,
 org.apache.ws.axis.security.handler,
 org.apache.ws.security,
 org.apache.ws.security.action,
 org.apache.ws.security.components.crypto,
 org.apache.ws.security.conversation,
 org.apache.ws.security.conversation.dkalgo,
 org.apache.ws.security.handler,
 org.apache.ws.security.message,
 org.apache.ws.security.message.token,
 org.apache.ws.security.processor,
 org.apache.ws.security.saml,
 org.apache.ws.security.transform,
 org.apache.ws.security.util

After complaining to the Framework team, they have told me that I need to use bundle-version and not version in my Import-Package statement, such as:

Import-Pacakge: org.apache.ws.security;bundle-version=[1.5.0,2)

I've read through the OSGi Specs (page 50), but cannot seem to understand the nuance between these two values:

The developer can specify arbitrary matching attributes. See Attribute Matching on page 58. The following arbitrary matching attributes are predefined:

• version - A version-range to select the exporter's package version. The syntax must follow Version Ranges on page 36. For more information on version selection, see Semantic Versioning on page 54. If this attribute is not specified, it is assumed to be [0.0.0, ∞).

• specification-version - This attribute is an alias of the version attribute only to ease migration from earlier versions. If the version attribute is present, the values must be equal.

• bundle-symbolic-name - The bundle symbolic name of the exporting bundle. In the case of a fragment bundle, this will be the host bundle's symbolic name.

• bundle-version - A version-range to select the bundle version of the exporting bundle. The default value is [0.0.0, ∞). See Semantic Versioning on page 54. In the case of a fragment bundle, the version is from the host bundle.

Can someone please clarify the difference between the version and the bundle-version? From the way I read the docs, the bundle-version (ie: the manifest's Bundle-Version) would extend to all packages in the bundle. So wouldn't the package version (ie: version) be the same as the bundle-version (ie: bundle-version) on the Import-Package statement? Why is there an ability to specify the two differently?

Answer

Neil Bartlett picture Neil Bartlett · Apr 5, 2016

It's pretty simple: bundle-version binds you to the version of the bundle that is exporting the package, whereas version binds to the version of the package itself.

You almost never want to use bundle-version on imports. The version of the exporting bundle is pretty much irrelevant... in fact when you are importing a package you shouldn't even care about the identity of the bundle exporting it. It's the package you care about, not the bundle it comes from.

Who told you to use bundle-version? There might be some very special reason for this, but I doubt it. More likely the person who told you this is just mistaken.

You asked:

So wouldn't the package version (ie: version) be the same as the bundle-version (ie: bundle-version) on the Import-Package statement?

No it isn't! Bundle version has nothing to do with package version. When you change a package, you change the version of that package. The bundle is just a delivery mechanism.

UPDATE

Rereading your question, I notice that the version of the packages exported by the dependency is not specified. That means that the framework is exporting everything as version 0.0.0, since that is the "default" version when a version is not specified. The version of a package emphatically does NOT default to the version of the bundle it lives in. Unfortunately it seems that the author of this framework does not have a good understanding of OSGi.

UPDATE 2

Since the framework you are using does not provide versions, I recommend creating a no-code wrapper bundle that re-exports the packages with a proper version attached. This is quite simple to build, and it will keep all the ugliness in one place. Then any of your other bundles can simply import the packages with normal versions.

Since you haven't told me the BSN of the problematic bundle I will call it "org.foo". First create a file called manifest.txt as follows:

Bundle-ManifestVersion: 2
Bundle-SymbolicName: org.foo.wrapper
Bundle-Version: 1.5.11
Require-Bundle: org.foo; bundle-version="[1.5.11,1.5.11]"
Export-Package: org.apache.ws.axis.security;version=1.5,
 org.apache.ws.axis.security.handler;version=1.5,
 ...

(Obviously I have made some other assumptions about versions here which you can correct.)

Now build the bundle with:

jar cfm wrapper.jar manifest.txt

Now that you have this bundle, your normal bundle can import a package like this:

Import-Package: org.apache.ws.security; version="[1.5,2)"

Hopefully you are using a tool based on bnd, in which case the Import-Package header will be generated for you including the version range.