I'm trying to get the library BioJava to work inside an OSGi context.
To get the JAR into the OSGi context, I'm using the Maven plugin p2-maven-plugin, which generates a file Manifest.MF, and the part relevant to the exception I'm facing is:
Bundle-SymbolicName: org.biojava.core
Bundle-Version: 5.3.0
Import-Package: [snip],
org.slf4j;resolution:=optional,
[snap]
Which looks okay to me. However when I access a class that uses slf4j I get the titular exception:
java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory
at org.biojava.nbio.core.sequence.template.AbstractCompoundSet.<clinit>(AbstractCompoundSet.java:40)
at org.biojava.nbio.core.sequence.io.ABITrace.getSequence(ABITrace.java:179)
Caused by: java.lang.ClassNotFoundException: org.slf4j.LoggerFactory cannot be found by org.biojava.core_5.3.0
at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:511)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:422)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:414)
Now it's easy to find this exception everywhere, because a lot of people have tried (and failed) to install slf4j. I checked sites like the documentation or the SO question ClassNotFoundException: org.slf4j.LoggerFactory and hence tried to add the following bundles:
slf4j-simple
slf4j-log4j12 (plus the log4j dependencies)
pax-logging-log4j2
However neither worked. Maybe the OSGi container is having problems, but slf4j JARs have the bundle information with the export packages out of the box, so I'm assuming these work. And the BioJava JAR has an import package, so I have no idea why it wouldn't be able to find the class.
Oh, I checked, the LoggerFactory is present in slf4j-api, so it's not that, either.
I also tried different start levels and autostart for the implementations. And I rebundled the JAR without the optional dependency, but I keep having problems because now the MD5 hash is broken.
Has anybody managed to get slf4j to work in OSGi? Or failing that, is there any way to replace that stupid dependency with some kind of Java proxy so I will not need the broken dependency anymore?
resolution:=optional means that when the bundle resolves, it will either get access to the package or not. The framework is permitted to resolve the bundle without access to the package. If the bundle needs access to the package, why make resolution of the package optional?
I have been trying to fix this issue for several days now, but i seem stuck somehow. I want to develop a OSGi bundle, and my implementation requires an external library (that has some more dependencies). The situation is as follows: My project is using gradle and i got a simple code snippet to compile, but it crashes at runtime when the bundle is launched ( i am using apache felix), giving me an exception complaining about unmet dependencies. But all libraries are present in the jar bundle, and i added them into the classpath. The missing package org.ethereum.facade is listed within Private-Packages.
I read a lot of questions with similar problems, but none of the silutions proposed seems to solve my problem.
I am posting my gradle.build files
// ETHEREUM NODE
configurations.create('embed')
repositories {
mavenLocal()
mavenCentral()
maven {
url "http://dl.bintray.com/ethereum/maven"
}
}
dependencies {
// This will compile the openMuc Framework and place the result into the build classpath:
compile project(':openmuc-core-api')
// This will place the etherum libraries into the classpath
compile ("org.ethereum:ethereumj-core:latest.release")
embed ("org.ethereum:ethereumj-core:latest.release")
}
jar {
manifest {
name = 'OpenMUC App - EthereumNode'
instruction 'Bundle-ClassPath', 'lib/ethereumj-core-1.4.2-RELEASE.jar,.'
}
into('lib') {
from configurations.embed
}
}
The resulting jar:
[MANIFEST openmuc-app-ethereumNode-0.16.0.jar]
Bnd-LastModified 1490003658351
Bundle-ClassPath lib/ethereumj-core-1.4.2-RELEASE.jar,.
Bundle-ManifestVersion 2
Bundle-Name OpenMUC App - EthereumNode
Bundle-SymbolicName org.openmuc.framework.openmuc-app-ethereumNode
Bundle-Version 0.16.0
Created-By 1.8.0_25 (Oracle Corporation)
Export-Package org.openmuc.framework.app.ethereumNode;version="0.16.0";uses:="javax.xml.bind,org.osgi.service.component"
Import-Package javax.xml.bind,org.osgi.service.component;version="[1.2,2)",org.slf4j;version="[1.7,2)",org.ethereum.facade
Manifest-Version 1.0
Private-Package genesis,org.ethereum,org.ethereum.cli,org.ethereum.config,org.ethereum.config.blockchain,org.ethereum.config.net,org.ethereum.core,org.ethereum.core.genesis,org.ethereum.crypto,org.ethereum.crypto.cryptohash,org.ethereum.crypto.jce,org.ethereum.datasource,org.ethereum.datasource.inmem,org.ethereum.datasource.leveldb,org.ethereum.datasource.mapdb,org.ethereum.db,org.ethereum.db.index,org.ethereum.facade,org.ethereum.json,org.ethereum.jsonrpc,org.ethereum.listener,org.ethereum.manager,org.ethereum.mine,org.ethereum.net,org.ethereum.net.client,org.ethereum.net.dht,org.ethereum.net.eth,org.ethereum.net.eth.handler,org.ethereum.net.eth.message,org.ethereum.net.message,org.ethereum.net.p2p,org.ethereum.net.rlpx,org.ethereum.net.rlpx.discover,org.ethereum.net.rlpx.discover.table,org.ethereum.net.server,org.ethereum.net.shh,org.ethereum.net.submit,org.ethereum.net.swarm,org.ethereum.net.swarm.bzz,org.ethereum.samples,org.ethereum.solidity,org.ethereum.solidity.compiler,org.ethereum.sync,org.ethereum.trie,org.ethereum.util,org.ethereum.util.blockchain,org.ethereum.validator,org.ethereum.vm,org.ethereum.vm.program,org.ethereum.vm.program.invoke,org.ethereum.vm.program.listener,org.ethereum.vm.trace,lib
Require-Capability osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.7))"
Service-Component OSGI-INF/org.openmuc.framework.app.ethereumNode.EthereumNode.xml
Tool Bnd-3.0.0.201509101326
[IMPEXP]
Import-Package
javax.xml.bind
org.ethereum.facade
org.osgi.service.component {version=[1.2,2)}
org.slf4j {version=[1.7,2)}
Export-Package
org.openmuc.framework.app.ethereumNode {version=0.16.0}
[USES]
org.openmuc.framework.app.ethereumNode java.lang
javax.xml.bind
org.ethereum.facade
org.osgi.service.component
org.slf4j
[USEDBY]
java.lang org.openmuc.framework.app.ethereumNode
javax.xml.bind org.openmuc.framework.app.ethereumNode
org.ethereum.facade org.openmuc.framework.app.ethereumNode
org.osgi.service.component org.openmuc.framework.app.ethereumNode
org.slf4j org.openmuc.framework.app.ethereumNode
[COMPONENTS]
OSGI-INF/org.openmuc.framework.app.ethereumNode.EthereumNode.xml
<?xml version="1.0" encoding="UTF-8"?>
<component name="org.openmuc.framework.app.ethereumNode.EthereumNode">
<implementation class="org.openmuc.framework.app.ethereumNode.EthereumNode"/>
</component>
[LIST]
META-INF
MANIFEST.MF extra='\uFFFD\uFFFD\u0000\u0000'
OSGI-INF
org.openmuc.framework.app.ethereumNode.EthereumNode.xml
lib
aopalliance-1.0.jar
commons-codec-1.10.jar
commons-collections4-4.0.jar
commons-lang3-3.4.jar
commons-logging-1.2.jar
config-1.2.1.jar
core-1.53.0.0.jar
ethereumj-core-1.4.2-RELEASE.jar
guava-16.0.1.jar
jackson-annotations-2.5.0.jar
jackson-core-2.5.1.jar
jackson-core-asl-1.9.13.jar
jackson-databind-2.5.1.jar
jackson-mapper-asl-1.9.13.jar
java-util-1.8.0.jar
javassist-3.15.0-GA.jar
json-io-2.4.1.jar
json-simple-1.1.1.jar
jsr305-3.0.0.jar
leveldb-0.7.jar
leveldb-api-0.7.jar
leveldbjni-all-1.18.3.jar
logback-classic-1.1.7.jar
logback-core-1.1.7.jar
mapdb-2.0-beta12.jar
netty-all-4.0.30.Final.jar
prov-1.53.0.0.jar
slf4j-api-1.7.20.jar
solcJ-all-0.4.8.jar
spring-aop-4.2.0.RELEASE.jar
spring-beans-4.2.0.RELEASE.jar
spring-context-4.2.0.RELEASE.jar
spring-core-4.2.0.RELEASE.jar
spring-expression-4.2.0.RELEASE.jar
spring-jdbc-4.2.0.RELEASE.jar
spring-orm-4.2.0.RELEASE.jar
spring-tx-4.2.0.RELEASE.jar
org
org/openmuc
org/openmuc/framework
org/openmuc/framework/app
org/openmuc/framework/app/ethereumNode
EthereumNode.class
The exception i encounter when the bundle is loaded:
ERROR: Bundle org.openmuc.framework.openmuc-app-ethereumNode [3] Error starting file:/Volumes/UserData/Documents/FH/MasterThesis_MatthiasPosch/java/openmuc/framework/bundle/openmuc-app-ethereumNode-0.16.0.jar (org.osgi.framework.BundleException: Unable to resolve org.openmuc.framework.openmuc-app-ethereumNode [3](R 3.0): missing requirement [org.openmuc.framework.openmuc-app-ethereumNode [3](R 3.0)] osgi.wiring.package; (osgi.wiring.package=org.ethereum.facade) Unresolved requirements: [[org.openmuc.framework.openmuc-app-ethereumNode [3](R 3.0)] osgi.wiring.package; (osgi.wiring.package=org.ethereum.facade)])
org.osgi.framework.BundleException: Unable to resolve org.openmuc.framework.openmuc-app-ethereumNode [3](R 3.0): missing requirement [org.openmuc.framework.openmuc-app-ethereumNode [3](R 3.0)] osgi.wiring.package; (osgi.wiring.package=org.ethereum.facade) Unresolved requirements: [[org.openmuc.framework.openmuc-app-ethereumNode [3](R 3.0)] osgi.wiring.package; (osgi.wiring.package=org.ethereum.facade)]
at org.apache.felix.framework.Felix.resolveBundleRevision(Felix.java:4112)
at org.apache.felix.framework.Felix.startBundle(Felix.java:2118)
at org.apache.felix.framework.Felix.setActiveStartLevel(Felix.java:1372)
at org.apache.felix.framework.FrameworkStartLevelImpl.run(FrameworkStartLevelImpl.java:308)
at java.lang.Thread.run(Thread.java:745)
So it seems all libraries are in place in the lib folder, but still the bundle does not work. I tried to play with the code, but any reference to the included libraries (eg. spring) will lead to a similar exception. Why?
My solution was to use the osgi-run plugin for gradle instead of the original osgi plugin. Declaring my dependencies as SystemLibrary systemLib ("org.ethereum:ethereumj-core:1.2.0-RELEASE") resolved the issues and i am able to use the library without exceptions and errors.
In your Manifest you import the package org.ethereum.facade. This can only work if there is also a bundle that exports this package. If the package is purely internal then you should set it as private package and not import it.
If the package might be needed from the outside then make sure you have an import and an export for it in your bundle. If you have not configured the import manually then for some reason the build seems to think you need it and it is not present locally in your bundle.
How do you create the Manifest? Do you use bnd for this? If yes then maybe the manual change in bundle classpath is not recognized by it.
I noticed a fragment I have uses a Export-Package directive for the package that is contributed to its host:
Fragment-Host: org.eclipse.jetty.osgi.boot
Export-Package: org.eclipse.jetty.osgi.boot.utils;version="1.0.1.felix"
-buildpath: osgi.core;version=4.3.0,\
org.eclipse.jetty.osgi.boot;version=7.6.1.v20120215
-sources: false
Import-Package: !org.eclipse.jetty.osgi.boot.utils.internal,\
*
This bundle contributes some extra classes into the org.eclipse.jetty.osgi.boot.utils package in the host.
Ideally I think I should strive to keep packages private where possible, but what about this case? None of the rest of my code requires org.eclipse.jetty.osgi.boot.utils.
From the OSGi core specification (6.0):
A host bundle's class path is searched before a fragment's class path.
"This bundle contributes a new org.eclipse.jetty.osgi.boot.utils with classes that override those of the host"
Fragment bundles cannot override the classes of the host bundle (if that was what you meant).
If a package is not intended to use by other bundles, it should not be exported. The host bundle can see the classes and resources of its attached fragment bundle, but only if it does not have the same class or resource.
The accepted answer of #balazs-zsoldos:
Fragment bundles cannot override the classes of the host bundle
...is correct in this specific case, but it is not true in general. A more nuanced answer would be that fragments cannot override the host bundle's classes unless the host bundle has been configured to allow it (which in your case the org.eclipse.jetty.osgi.boot bundle is not).
The way you configure the host bundle to allow it is by using the Bundle-ClassPath header. Let's assume you have a host bundle A with an attached fragment B, and A has the following manifest entry:
Bundle-ClassPath: contrib,.
Suppose the bundle classloader is asked to look for class pack.Z in bundle A. The bundle classloader will search in the following order:
A:contrib/pack/Z.class
B:contrib/pack/Z.class
A:pack/Z.class
B:pack/Z.class
So you can see that if your contrib directory in A is empty or non-existent, then the bundle classloader will try and load B:contrib/pack/Z.class before it will try and load A:pack/Z.class. But as you can see, this is only possible if A was explicitly built to allow it.
I use osgi container (virgo) [i'm not very good in that].
I added a dependency to my pom.xml
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-osgi_2.10</artifactId>
<version>2.2-M3</version>
</dependency>
I put akka-osgi_2.10-2.2-M3.jar to my lib/deploy folder to OSGI server (to myserver/repository/usr).
I added dummy actor to my code base:
import akka.actor.UntypedActor;
public class ManagerActor extends UntypedActor {
#Override
public void onReceive(Object o) throws Exception {
// ...
}
}
I build and start my application.
And as result I have the following exceptions in my log (it complains to version="0.0.0"):
.. failed. org.eclipse.virgo.kernel.osgi.framework.UnableToSatisfyBundleDependenciesException: Unable to satisfy dependencies of bundle 'com.
com.mycompnay.mything-security' at version '1.0.1.BUILD-SNAPSHOT': Cannot resolve: com.mycompany.mything-security
Resolver report:
An Import-Package could not be resolved. Resolver error data <Import-Package: akka.actor; version="0.0.0">. Caused by missing constrai
nt in bundle <com.mycompany.mything-security_1.0.1.BUILD-SNAPSHOT>
constraint: <Import-Package: akka.actor; version="0.0.0">
I go to my template.mf file, which is used to generate final MANIFEST.MF file. To specify the range of versions for AKKA lib I use. Putting there:
Import-Template:
akka.actor.*;version="[2.2.0.M3, 2.3)"
Import-Package:
akka.actor;version="[2.2.0.M3, 2.3)"
Then rebuild and start app.
But in console it complains to akka versions (complains to version="[2.2.0.M3,2.3.0)" now):
An Import-Package could not be resolved. Resolver error data <Import-Package: akka.actor; version="[2.2.0.M3,2.3.0)">. Caused by missi
ng constraint in bundle <com.mycompany.mything-security_1.0.1.BUILD-SNAPSHOT>
constraint: <Import-Package: akka.actor; version="[2.2.0.M3,2.3.0)">
Q: what's wrong?
Also I tried to add this line: to Import-Bundle:
Import-Bundle:
...
com.typesafe.akka.osgi;version="[2.2.0.M3, 2.3)"
Then I have it in the log (now it complains to com.typesafe.akka.osgi version):
.. failed. org.eclipse.virgo.kernel.deployer.core.DeploymentException: Unable to satisfy dependencies of bundle 'com.mycompany.mything-security
' at version '1.0.1.BUILD-SNAPSHOT': Import-Bundle with symbolic name 'com.typesafe.akka.osgi' in version range '[2.2.0.M3, oo)' could not be
satisfied
The reason was:
I need to put akka-actor_2.10-2.2-M3.jar (along with akka-osgi_2.10-2.2-M3.jar) to my osgi (virgo) deploy folder.
So, we should NOT do it manually but with help of maven (in order not to miss some jar that comes along with expecting one).
I try to package an OSGI bundle using the maven-bundle-plugin (which uses BND).
To run properly the bundle must import a package which is not in the classpath during development (because object references will be passed to the bundle methods as "Class" references).
I do not manage to configure the "Import-Package" declaration in the pom.xml or *.bnd file so that the packe will be included in the OSGI Import-Package part of the MANIFEST. I though
Import-Package: de.foo.bar,*
should do the job, but as de.foo.bar is not in the classpath (or better not declared as an import in the code) it will not be taken to the MANIFEST.
Has anybody an idea how to force the package to be available in the OSGi Import-Package MANIFEST declaration.
Thanks and regards
Klaus
I finally found a solution
Import-Package: de.foo.bar;resolution:=optional,*
will put "de.foo.bar" in the "Import-Package" declaration of the bundle MANIFEST.MF even if the package is not imported by the bundle code.