I am new to Java OSGi programming. I am creating a new bundle called com.myManager and adding it to an existing application which has many bundles.
This bundle I am creating depends on an external jar file called jsoup-1.12.1 which is used for parsing html files. I can add this dependency via eclipse, and my bundle builds fine.
However, when I try to add my bundle to the main bndrun application, I get the below pasted error. Unfortunately i'm not able to understand what is required here.
I guess that we can't just simply add external jar files the way I did? Thanks in advance.
Resolution failed. Capabilities satisfying the following requirements could not be found:
[<<INITIAL>>]
⇒ osgi.identity: (osgi.identity=com.myManager)
⇒ [com.myManager version=0.0.0]
⇒ osgi.wiring.package: (&(osgi.wiring.package=org.jsoup))
Until now you only added jsoup to the build time dependencies of your bundle. Using jsoup in your bundle then creates a import package declaration in your bundle manifest. This is expected and not a problem.
The error you see is that at assembly time (when bnd creates the runbundles list) of your application you have no bundle in the repository that can provide this package.
Jsoup already is an OSGi bundle. Simply add it to the bundles of your application and you are done. How to add jsoup to the bundles depends on how you assemble your application. For eclipse pde you would add it to the target platform. For apache karaf you would add it to your feature.
For the new bndrun with the maven build you simply add jsoup to the pom where you build your repository. Like in this example. Having the bundle in the repository allows bndtools to select the bundle for your application if there is a requirement for it.
Related
Is there a way to use an OSGI bundle as a maven dependency without getting all the packages from it into the classpath that it doesn't even export?
Background of the question: We just added the org.apache.sling.xss bundle as a maven dependency into our project. As you can see in the pom.xml, it just exports the package org.apache.sling.xss but embeds various dependencies directly into it's jar as Private-Package. While OSGI hides this stuff from other bundles, maven does not. So we get collisions: org.apache.sling.xss embeds e.g. version 1.7.0 of commons-beanutils, which is incompatible with the newer version of commons-beanutils we have been using, so that we now get compile errors.
Is there any good solution to this - both from our perspective, as from the perspective of the maintainers of the org.apache.sling.xss bundle? Ideally, you'd get only the exported org.apache.sling.xss package into the classpath if you use that bundle. So maybe a good solution would be if org.apache.sling.xss provided a separate API jar, containing only that class? Is there a standard way to do this, or another solution? Can we somehow tell maven just to include only that package into the classpath? (I know maven has dependency exclusion, but that doesn't help here, since the problematic stuff is not a transitive dependency of sling.xss, but actually included into the org.apache.sling.xss jar.)
Unfortunately there is no good way to handle such bundles with maven.
The recommended way is to split the bundle into an API bundle that just defines the API and an implementation bundle that imports the API and imports or embeds all implementation dependencies.
This way consumers will only have a maven dependency to the API and the problem does not occur at all.
Can you open an jira issue for sling xss to provide an API bundle?
You could include in your build system a step that performs OSGi resolution, for example using the bnd-export-maven-plugin.
In this way the build as a whole will fail if you write code that depends on a non-exported package of another bundle. This is because bnd will automatically add an Import-Package for the package that you used in your bundle, but the resolve step will be unable to find a corresponding Export-Package in the other bundle.
Of course this is not ideal. You will still be able to write the code in your IDE and compile it with the maven-compiler-plugin. But you at least find out about the problem before you hit the runtime.
I'm working on this BndTools based OSGi project: https://github.com/Jafre13/ISS-Product
My project though requires a non-OSGi based library (aliasi-lingpipe - https://mvnrepository.com/artifact/de.julielab/aliasi-lingpipe/4.1.0).
And here is where the problem starts. First I tried to add the JAR directly from the Maven repository, as BndTools is supposedly compatible with Maven repositories, but it doesn't seem to work from the "Repository Browser". Even when adding the Maven Central plugin to the build.bnd file as stated in http://bnd.bndtools.org/plugins/maven.html, still yields the same result.
Giving up on having Maven working, I tried to do it the most spartan way and download the JAR myself and add it as plain JAR as specified here: http://bndtools.org/faq.html (6 How Can I Depend on a Plain JAR File at Build Time?)
This time the JAR got recognised and I could start using it in the code. But once you launch the OSGi framework everything just crumbles again as it is trying to resolve the non-OSGi class paths, resulting in a wiring error like this:
could not resolve the bundles: [slf4j.api-1.7.25
org.osgi.framework.BundleException: Unable to resolve slf4j.api [6](R
6.0): missing requirement [slf4j.api [6](R 6.0)] osgi.wiring.package; (&(osgi.wiring.package=org.slf4j.impl)(version>=1.6.0)) Unresolved
requirements: [[slf4j.api [6](R 6.0)] osgi.wiring.package;
(&(osgi.wiring.package=org.slf4j.impl)(version>=1.6.0))] ,
dk.sdu.sso.sred-0.0.0.201712041036 org.osgi.framework.BundleException:
Unable to resolve dk.sdu.sso.sred [7](R 7.0): missing requirement
[dk.sdu.sso.sred [7](R 7.0)] osgi.wiring.package;
(osgi.wiring.package=com.aliasi.classify) Unresolved requirements:
[[dk.sdu.sso.sred [7](R 7.0)] osgi.wiring.package;
(osgi.wiring.package=com.aliasi.classify)] ]
So at this point I'm completely blocked and unable to proceed. I hope somebody with some OSGi experience could help here.
Greetings and thanks.
By adding the jar at build time you are able to compile but not to run.
During the build bnd will see that you need the packages from the jar and create Import-Package statements for it. So in this state you would need to deploy a bundle that exports the packages. In fact this means you would have to create a bundle out of your jar.
The other option is to embed the jar into your own bundle. This can be done by adding the packages you need as private packages. Bnd will then automatically embed these. This approach works well if the jar is really only used internally.
I have an OSGI bundle that is working perfectly, I added, as a maven dependency, unirest a lightweight HTTP library, when deploying to serviceMix I get a missing requirement:
filter:="(osgi.wiring.package=com.mashape.unirest.http)"
Of course I am using that package in my bundle, but as far as serviceMix is concerned, that library is just classes in my classpath like my own classes
I guess I'am missing something Here
I know it is possible to embed a library, but I don't understand why any additional manipulation is needed ? how is that different from just adding that library as a maven dependency
Any answers and pointers to articles/documentation is really appreciated
There is a difference between the way dependencies are treated in maven and osgi.
Maven treats the dependencies as a single classpath/classloader where the classes from every jar can access the classes from every other jar.
This is historical from main apps, and its the way maven runs unit tests.
In the osgi run-time environment each bundle has its own classloader, and by default, only has access to the classes and jars embedded in its own bundle.
The classes in each bundle are isolated unless the package is exported from one bundle and imported to another.
The maven bundle plugin attempts to bridge the gap. Just adding a dependency to maven is not enough, one must also tell the maven bundle plugin how to package and deploy it. The options are 1) embed the dependency in your bundle, or 2) deploy the dependency as a separate bundle.
The maven bundle plugin defaults to option 2: import everything.
To understand the exports from your dependency better, I suggest looking at the manifest file in the bundle jar. (META-INF/manifest.mf)
I just looked at the unirest jar on maven central and found no packages exported in the manifest. In fact unirest has no bundle headers, so its not an osgi bundle.
The error message
missing requirement : filter:="(osgi.wiring.package=com.mashape.unirest.http)"
means your bundle is attempting to import a package, but servicemix has no bundle exporting it.
To understand this better, I suggest looking at the manifest file in your bundle jar. (META-INF/manifest.mf) I expect it will contain an import of com.mashape.unirest.http. Also look at servicemix to see if anything exports it:
From the command from try: exports | grep com.mashape.unirest.http
I expect you will find no bundle exporting it.
I suggest you configure the maven bundle plugin to embed unirest instead of importing it. like this:
<Embed-Dependency>unirest-java</Embed-Dependency>
(if you already have an Embed-Dependency configuration you will need to merge them.)
Ref. http://felix.apache.org/documentation/subprojects/apache-felix-maven-bundle-plugin-bnd.html#detailed-how-to
Another way is deploy unirest-java as a bundle by wrapping it.
That could be as simple as copying it to the deploy folder:
https://karaf.apache.org/manual/latest/#_wrap_deployer
That would have the advantage of sharing unirest-java.
Lastly, if unirest does its own class loading, then that may turn out to be incompatible with osgi.
I have a 3rd party jar, no source, that is used to connect to a proprietary database system. I believe the jar is actually an Eclipse plugin; it was taken from one of the lib folders of the Eclipse-based editor for that system.
Anyway, I'm trying to develop a bundle that exposes the functionality of this jar, using Netbeans 7.4 and Karaf 3.0.1. Just trying to install the jar into Karaf isn't working - if I drop it into the deploy folder it doesn't even appear on the list, like it doesn't recognize it as an OSGI bundle. I created a new OSGI Maven bundle in Netbeans, added the jar as a dependency, and have tried all manner of shading, including in Bundle-ClassPath, Export-Package, with no luck. At one point I thought I had it working but Karaf was complaining about needing some Eclipse requirements.
I did more digging, unzipped the jar and the manifest for the 3rd party jar has this:
Require-Bundle: org.eclipse.core.runtime
So then I started down the rabbit hole of fulfilling those dependencies. Based on the maven pages I put together this features.xml file:
<features xmlns="http://karaf.apache.org/xmlns/features/v1.0.0">
<feature name='custom_deps' version='1.0'>
<bundle>mvn:org.eclipse.equinox/log/1.0.100-v20070226</bundle>
<bundle>mvn:org.eclipse/osgi/3.5.0.v20090520</bundle>
<bundle>mvn:org.eclipse.core/contenttype/3.2.100-v20070319</bundle>
<bundle>mvn:org.eclipse.core/jobs/3.3.0-v20070423</bundle>
<bundle>mvn:org.eclipse.core.runtime.compatibility/auth/3.2.100-v20070502</bundle>
<bundle>mvn:org.eclipse.equinox/app/1.3.100-v20130327-1442</bundle>
<bundle>mvn:org.eclipse.equinox/common/3.6.200-v20130402-1505</bundle>
<bundle>mvn:org.eclipse.equinox/preferences/3.5.100-v20130422-1538</bundle>
<bundle>mvn:org.eclipse.equinox/registry/3.5.301-v20130717-1549</bundle>
<bundle>mvn:org.eclipse.core/runtime/3.3.100-v20070530</bundle>
</feature>
</features>
Now when I try to install that I get:
karaf#root()> feature:install custom_deps
Error executing command: Could not start bundle mvn:org.eclipse/osgi/3.5.0.v2009
0520 in feature(s) custom_deps-1.0: Activator start error in bundle org.eclips
e.osgi [256].
which I think might have something to do with equinox vs felix? I'm just using the default Karaf setup and creating bundles using the built-in Netbeans Maven project and am still relatively new to the OSGI world. For the most part I can get bundles up and running and have put together a basic collection for an app, but this one bundle depends on being able to use this library and I'm struggling to find a way to get it working. I'm wondering if there's a way to either resolve all the linked dependencies of the jar, or somehow strip out whatever is depending on eclipse? I'm wondering if it's just plugin-related parts that aren't necessary for the connectivity I'm looking for.
Thanks for any ideas.
Edit: adding more info about the 3rd party jar
The jar is vendor-provided, but from a now defunct vendor. I'm not sure whether I can give vendor details or not so I'll mask the specific company info here. So the jar is named "com.bigcompany.product.productbeans_4.3.1.jar". The full manifest of the jar looks like this:
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Productbeans Plug-in
Bundle-SymbolicName: com.bigcompany.product.productbeans
Bundle-Version: 4.3.1
Bundle-Activator: com.bigcompany.product.productbeans.ProductbeansPlugin
Bundle-Vendor: BIGCOMPANY
Bundle-Localization: plugin
Require-Bundle: org.eclipse.core.runtime
Eclipse-AutoStart: true
Export-Package: com.bigcompany.product.productbeans
The switch to Equinox in Karaf was relatively painless, but dropping the jar into Karaf still it still didn't appear in the list. I tried unzipping the jar, modifying the manifest to remove the Require-Bundle and Eclipse-Autostart lines, repacked it up and tried installing that - at that point it showed up but my bundles that want this library still complain about missing requirements 'com.bigcompany.product.productbeans'.
From there I'm tried redeploying my bundle that tries to import the 3rd party package, and when I try installing my features file above that complains about missing constraints - is there a required order of the bundles in the features file?
I think ultimately what I'm hoping is is there an authoritative way to just embed or include a jar (or it's contained .class files?) into a bundle that requires them, and to have it just work? I've tried Embed-Dependency, Bundle-Classpath (although I'm not sure if I have the syntax or locations correct?), using the maven shade plugin, and either I get to where my bundle says it's missing the 3rd party package, or if it doesn't give that it says it can't find the eclipse dependencies. If I have a non-OSGI project, the maven dependencies don't list or include any sort of eclipse-related dependencies. I can include snippets of my POM or something else if needed.
Basically the Require-Bundle says that it needs the equinox bundle. Karaf by standard uses Apache felix as OSGi runtime. As equinox is also a runtime you can not simply install it inside felix.
Instead you simply switch your karaf to use equinox instead of felix.
Edit etc/config.properties and set
karaf.framework=equinox
Then try to deploy your bundle again (without additional dependencies first).
How to create OSGi bundle from jar library?
In case you are using eclipse: There is a wizard for that.
It allows you to select a number of jar libraries and creates a plug-in project (i.e. OSGi bundle) including these jars.
You can find it here:
File -> New -> Other ... -> Plug-in from Existing jar Archives.
In principle you just need to add OSGi metadata to the manifest
There is a bundle creator for eclipse which gives a very practical way to add these entries which should be part of the Plugin Dev Toolkit.
Here is an article detailing the process and how to do it with the Bnd tool, maven and so forth.
I personally like the pax tools very much. It is all command line based, but very practical. To create an OSGi bundle of an existing jar you can use bnd tool.
First check out if you can find a osgi enabled version of your library from repositories
SpringSource http://www.springsource.com/repository
Fusesource http://repo.fusesource.com/
If you don't find the OSGi enabled versions. You can go ahead with using the pax tool - PaxConstruct or use the aQute's Bnd tool.
Create a new Plug-in project from existing JAR archive.
Add the jar file to be exported
Click next and name the project.
NOTE:
Make sure OSGI framework is selected in target platform.
Unzip the JAR archives into the project is deselected -> deselecting it, will export all the packages of the JAR
if Unzip the JAR archives into the project is selected then you will manually need to export required packages in the MANIFEST.MF file.
Click finish. You will find project with name transport-5.1.1 created in your workspace. Also you can verify, all the packages of the JAR are exported in MANIFEST.MF file.
The Eclipse Bundle Recipe project provides a Maven based approach for adding OSGi meta data to JARs consumed from a Maven repository.
At its core, it uses the bnd tool. This tool is like a swiss army knife. It analyzes jars and class files and properly calculate package import and exports. You should use bnd for converting proprietary jars yourself. It's available in Maven Central.
Late arrival to the party:
If you're using Gradle, you can add the jar as a normal dependency of your project if you apply the osgi-run plugin.
The osgi-run plugin will wrap the jar transparently into a bundle for you, exporting every package in it and calculating all its imports. As Gradle will know the jar's transitive dependencies, it will do the same for them as well, if necessary.
The jar(s) will be part of the OSGi runtime osgi-run creates, which you can then start up with gradle runOsgi or gradle createOsgi, then executing either the run.sh or run.bat scripts.
The actual wrapping is done by Bnd, the swiss knife of the OSGi world, of course.
If you want to configure how the wrapping happens (what should be imported/exported, usually), you can do it easily in the Gradle build file, see the documentation for details.
Example:
wrapInstructions {
// use regex to match file name of dependency
manifest( "c3p0.*" ) {
// import everything except the log4j package - should not be needed
instruction 'Import-Package', '!org.apache.log4j', '*'
instruction 'Bundle-Description', 'c3p0 is an easy-to-use library for making traditional ' +
'JDBC drivers "enterprise-ready" by augmenting them with functionality defined by ' +
'the jdbc3 spec and the optional extensions to jdbc2.'
}
}