It’s pretty common while developing an OSGi bundle that your imports and exports won’t quite match what you need or what exists in the server you’re deploying to. This can show up as NoClassDefFoundError
, ClassNotFoundException
or as log output in a stacktrace from bundle resolution. Hall, Pauls, McCullough and Savage did a great job of covering NCDFE and CNFE in “OSGi In Action” (chapter 8), let’s take a look at figuring out what the bundle resolution stacktrace is telling us. (I make nothing from the sales of “OSGi In Action” and suggest it to anyone interested in OSGi.)
Just like learning to read the stacktrace from an exception in Java is key to debugging, so is true about the dependency resolution messages from an OSGi container. Below is the output from Apache Felix when it encountered a missing dependency required by a bundle:
ERROR: Bundle org.sakaiproject.nakamura.webconsole.solr [124]: Error starting slinginstall:org.sakaiproject.nakamura.webconsole.solr-1.2-SNAPSHOT.jar (org.osgi.framework.BundleException: Unresolved constraint in bundle org.sakaiproject.nakamura.webconsole.solr [124]: Unable to resolve 124.0: missing requirement [124.0] package; (package=org.apache.solr.client.solrj) [caused by: Unable to resolve 84.0: missing requirement [84.0] package; (package=org.sakaiproject.nakamura.api.lite) [caused by: Unable to resolve 86.0: missing requirement [86.0] package; (&(package=com.google.common.collect)(version>=9.0.0)(!(version>=10.0.0)))]]) org.osgi.framework.BundleException: Unresolved constraint in bundle org.sakaiproject.nakamura.webconsole.solr [124]: Unable to resolve 124.0: missing requirement [124.0] package; (package=org.apache.solr.client.solrj) [caused by: Unable to resolve 84.0: missing requirement [84.0] package; (package=org.sakaiproject.nakamura.api.lite) [caused by: Unable to resolve 86.0: missing requirement [86.0] package; (&(package=com.google.common.collect)(version>=9.0.0)(!(version>=10.0.0)))]] at org.apache.felix.framework.Felix.resolveBundle(Felix.java:3443) at org.apache.felix.framework.Felix.startBundle(Felix.java:1727) at org.apache.felix.framework.Felix.setActiveStartLevel(Felix.java:1156) at org.apache.felix.framework.StartLevelImpl.run(StartLevelImpl.java:264) at java.lang.Thread.run(Thread.java:619)
What you have here is a stacktrace with a lengthy message. The important part of the stacktrace for us is the message.
ERROR: Bundle org.sakaiproject.nakamura.webconsole.solr [124]: Error starting slinginstall:org.sakaiproject.nakamura.webconsole.solr-1.2-SNAPSHOT.jar (org.osgi.framework.BundleException: Unresolved constraint in bundle org.sakaiproject.nakamura.webconsole.solr [124]: Unable to resolve 124.0: missing requirement [124.0] package; (package=org.apache.solr.client.solrj) [caused by: Unable to resolve 84.0: missing requirement [84.0] package; (package=org.sakaiproject.nakamura.api.lite) [caused by: Unable to resolve 86.0: missing requirement [86.0] package; (&(package=com.google.common.collect)(version>=9.0.0)(!(version>=10.0.0)))]])
This message is pretty simple but the structure is common for nastier messages (i.e. deeper resolution paths before failure). Let’s pull it apart to see what’s happening in there.
ERROR: Bundle org.sakaiproject.nakamura.webconsole.solr [124]: Error starting slinginstall:org.sakaiproject.nakamura.webconsole.solr-1.2-SNAPSHOT.jar
This very first part tells us that an error occurred while trying to load the org.sakaiproject.nakamura.webconsole.solr
bundle. Nice start, but not quite the crux of the matter. Let’s keep reading.
org.osgi.framework.BundleException: Unresolved constraint in bundle org.sakaiproject.nakamura.webconsole.solr [124]: Unable to resolve 124.0: missing requirement [124.0] package; (package=org.apache.solr.client.solrj) [caused by: Unable to resolve 84.0: missing requirement [84.0] package; (package=org.sakaiproject.nakamura.api.lite) [caused by: Unable to resolve 86.0: missing requirement [86.0] package; (&(package=com.google.common.collect)(version>=9.0.0)(!(version>=10.0.0)))]])
Phew, that’s a lot of text! This is the heart of what we need though, so let’s break it down to make more sense of it.
( org.osgi.framework.BundleException: Unresolved constraint in bundle org.sakaiproject.nakamura.webconsole.solr [124]: Unable to resolve 124.0: missing requirement [124.0] package; (package=org.apache.solr.client.solrj) [ caused by: Unable to resolve 84.0: missing requirement [84.0] package; (package=org.sakaiproject.nakamura.api.lite) [ caused by: Unable to resolve 86.0: missing requirement [86.0] package; (&(package=com.google.common.collect)(version>=9.0.0)(!(version>=10.0.0))) ] ] )
What are those [number]
s in the message?
The numbers in the message tell us the bundle ID on the server.
Unresolved Package Name | Bundle ID Where Resolution Failed |
---|---|
org.apache.solr.client.solrj | 124 |
org.sakaiproject.nakamura.api.lite | 84 |
com.google.common.collect | 86 |
Once you pull apart the message it becomes more obvious that it has structure and meaning! The structure of the message tells us that bundle 124 depends on a package from bundle 84 which depends on a package from bundle 86 which is unable to resolve com.google.common.collect;version=[9.0.0, 10.0.0)
. The innermost/very last message tells us the root of the problem; the dependency resolver was unable to find com.google.common.collect
at version=[9.0.0, 10.0.0)
. Now we have somewhere to start digging.
How To Fix This
I suggest one of the following steps:
- Add a bundle that exports the missing package with a version that matches the required version
- Change the version to match an exported package already on the server
In this particular environment, com.google.common.collect;version=10.0.0
is what our server has deployed. The descriptor above specifically blocks any version not in the 9.x.x range. We generate the OSGi manifest by using the Maven Bundle Plugin which uses the BND tool to generate the manifest. In BND version > 2.1.0, the macro for versions was changed. Our solution has ranged from rolling back to bnd version=2.1.0 OR define the macro differently. The results are the same; the version segment in the manifest header becomes com.google.common.collect;version>=9.0.0
which finds our bundle of com.google.common.collect;version=10.0.0
.
Notes about environment
The above message and stacktrace originated from a Sakai OAE environment which is built on Apache Sling and thusly Apache Felix. We use an artifact ID that is the root package of the bundle (org.sakaiproject.nakamura.webconsole.solr). This has the side effect that our bundle names look like package names in the message but gives a very clear naming convention.
Nice blog.
It is also worthwhile to point out that the “root” cause reported in the above error message, might not be what is ultimately causing the issue. The OSGi resolver algorithm will potentially evaluate lots of different candidate permutations to find a dependency resolution solution. In some scenarios, the number of permutations can be quite large, but the resolver only throws one exception and cannot easily report on every issue it encountered. Thus, it often just picks an error to report; I believe in the case of the Felix resolver, it reports the last error encountered.
In some scenarios, it is not the last error that captures the root cause. This can happen when there are multiple providers of a given package. In that case, it may be reporting an error resolving a provider different than the one you were expecting. For the Felix resolver, you can get more information if you set the framework log level to 4 (i.e., DEBUG). Then the resolver will log a similar message for each failed permutation.
Nice blog post. Regarding the version range issue… this is an unfortunate consequence of the broken version numbering scheme used by Google.
Version 10 is backwards compatible with version 9, and with all previous versions. So they should really be version 1.10 and 1.9. In that case you would import a range of [1.9,2.0) which would accept both 1.10 and 1.9 and any future version that remains backwards compatible.
[…] previously took a look at Felix’s unresolved constraint message. I started testing with Felix 4.0.2 today and realized the output for an unresolved constraint has […]
hi, i am getting similar problem and unable to solve it, hope you could help me
my menifist file
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: task-node-bundle
Bundle-SymbolicName: task-node-bundle
Bundle-Version: 1.0.0.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Export-Package: com.ccl.aws.swf.nodes
Bundle-Vendor: Waqas Sadiq
Bundle-ContactAddress: .
DynamicImport-Package: *
Import-Package: com.ccl.aws.swf.nodes; version=”1.0.0″,
com.ccl.aws.swf.nodes.util; version=”1.0.0″,
com.amazonaws.services.ec2; version=”1.3.14″,
com.amazonaws.services.s3; version=”1.3.14″,
com.amazonaws.services.sns; version=”1.3.14″,
com.amazonaws.services.sqs; version=”1.3.14″,
com.amazonaws.auth; version=”1.3.14″
and the exception i am getting on deploying on virgo server is
[2012-08-31 05:13:21.281] fs-watcher Hot deployer processing ‘CREATED’ event for file ‘task-node-bundle.jar’.
[2012-08-31 05:13:21.453] fs-watcher Installing bundle ‘task-node-bundle’ version ‘1.0.0.qualifier’.
[2012-08-31 05:13:24.187] fs-watcher Dump ‘serviceability\dump\2012-08-31-05-13-546’ generated
[2012-08-31 05:13:24.203] fs-watcher Installation of bundle ‘task-node-bundle’ version ‘1.0.0.qualifier’ failed. org.eclipse.virgo.kernel.osgi.framework.UnableToSatisfyBundleDependenciesException: Unable to satisfy dependencies of bundle ‘task-node-bundle’ at version ‘1.0.0.qualifier’: Cannot resolve: task-node-bundle
Resolver report:
An Import-Package could not be resolved. Resolver error data . Caused by missing constraint in bundle
constraint:
at org.eclipse.virgo.kernel.install.pipeline.stage.resolve.internal.QuasiResolveStage.process(QuasiResolveStage.java:46)
at org.eclipse.virgo.kernel.install.pipeline.internal.StandardPipeline.doProcessGraph(StandardPipeline.java:62)
at org.eclipse.virgo.kernel.install.pipeline.internal.CompensatingPipeline.doProcessGraph(CompensatingPipeline.java:73)
at org.eclipse.virgo.kernel.install.pipeline.stage.AbstractPipelineStage.process(AbstractPipelineStage.java:41)
at org.eclipse.virgo.kernel.install.pipeline.internal.StandardPipeline.doProcessGraph(StandardPipeline.java:62)
at org.eclipse.virgo.kernel.install.pipeline.stage.AbstractPipelineStage.process(AbstractPipelineStage.java:41)
at org.eclipse.virgo.kernel.deployer.core.internal.PipelinedApplicationDeployer.driveInstallPipeline(PipelinedApplicationDeployer.java:360)
at org.eclipse.virgo.kernel.deployer.core.internal.PipelinedApplicationDeployer.doInstall(PipelinedApplicationDeployer.java:184)
at org.eclipse.virgo.kernel.deployer.core.internal.PipelinedApplicationDeployer.install(PipelinedApplicationDeployer.java:139)
at org.eclipse.virgo.kernel.deployer.core.internal.PipelinedApplicationDeployer.deploy(PipelinedApplicationDeployer.java:252)
at org.eclipse.virgo.kernel.deployer.hot.HotDeploymentFileSystemListener.deploy(HotDeployerFileSystemListener.java:163)
at org.eclipse.virgo.kernel.deployer.hot.HotDeploymentFileSystemListener.onChange(HotDeployerFileSystemListener.java:67)
at org.eclipse.virgo.util.io.FileSystemChecker.notifyListeners(FileSystemChecker.java:245)
at org.eclipse.virgo.util.io.FileSystemChecker.check(FileSystemChecker.java:166)
at org.eclipse.virgo.kernel.deployer.hot.WatchTask.run(WatchTask.java:48)
at java.lang.Thread.run(Thread.java:662)
[2012-08-31 05:13:24.265] fs-watcher Install failed for bundle ‘task-node-bundle’ version ‘1.0.0.qualifier’.