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.
Related
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.
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 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).
I'm struggling to wrap my head around developing OSGI bundles to publish to Karaf. I'm using Netbeans 7.4 and the Create Maven OSGI bundle when creating a new project. I think what I'm wrestling with is dealing with dependencies between different projects and working with them in Netbeans and then publishing to Karaf.
What I'm trying to do is set up a REST web service; I found this tutorial to be a good starting point in getting something basic up and running. So I started setting up a parent project with sub projects (all of these are from the Maven OSGI Bundle template). But after I started deploying bundles to my Karaf instance I started wrestling with the "missing requirement" errors within Karaf. I'd start trying to list each dependency in <Export-Package> or <Embed-Dependency> but it seems like I just keep going farther down and always getting new "missing requirement" messages listing yet another dependency. I then started trying the maven copy-dependencies plugin to export whatever dependencies are used in my project and copying whatever comes out into the Karaf deploy folder, too. That worked for the most part but I'm wrestling with what I think are downstream dependencies of a 3rd party jar, but that's probably a separate question anyway.
So, what I'd like to know is how should I be developing a coherent "application" with this setup? I understand I should separate everything into standalone bundles; i.e., I'll have my REST interface as one, the implementation as another, business logic as another. As a maven project, if I have a dependency for datetime handling or string utilities, maven will handle resolving all of those. But these dependencies won't automatically be included in my OSGI bundle, is that the case? What is the workflow to make sure that everything my project depends on is available to the bundles in Karaf? What about my projects that have other projects as dependencies, i.e., an interface implementation? I would include that project as a dependency so it will compile, but how do I make sure that that dependency is met after it is published?
The mismatch between dependencies at compile time and at deployment time is indeed a problem when working with OSGi.
What you need to know is how these relate to each other. At compile time you have the maven dependencies. When you build your project the maven bundle plugin creates the necessary Import-Package and Export-Package statements for you. Most of the time this simply works and you should avoid tuning too much there by hand.
So after the build the Manifest specifies what the resulting bundle needs but this does not automatically make sure the dependencies are met. So when you deploy the bundle to karaf you get the errors about missing dependencies. This is normal.
Now you need to install other bundles that fulfil these dependencies. Often you can simply install the jars of your maven dependencies (if they are bundles). This does not always work though. So basically you install the bundles and check if the requirements are met now.
The nice thing with karaf is that many bigger dependencies like cxf are already available as features. So it is a good idea to first try to get the dependencies by installing available features before you try to install them bundle by bundle.
So this helps you in getting your dependencies right. Then for "production" use the best solution is to create your own feature file where you refer to the bundles you found.
While installing bundles using the deploy dir seems nice at first it is not a good solution. Better install the bundles directly from maven using the mvn: url syntax karaf provides.
Regarding embedding dependencies. Sometimes it is a good solution but often it only makes things worse as it can lead to package use conflicts which are hard to solve. So better do not embed anything if it is possible.
I'm new in OSGI development and am struggling to understand how best to handle dependent JARs.
i.e. if I'm creating a bundle the likelihood is that I will need to use a few 3rd party JARs. When I create my bundle JAR to deploy to OSGI, obviously these 3rd party JARs are not included and thus the bundle will not run.
I understand that one option is to turn these JARs into bundles and deploy them to the OSGI container. When I bundled and try deploy third party jar it throws error for their own dependent jars and these dependencies are endless and not possible to fulfill.
What is the best solution to this?
-- Anurag
Finally I resolve third party jar issue actually I forger to add following tag in my POM.xml file
<_exportcontents>*
My issue is resolve, thanks to all of you for your support and giving me valuable clues.
If you are a beginner with osgi then I would not recommend to bundle bigger libs yourself. Often more than defining some import and export headers is required and it can become very difficult. Fortunately a lot of libs are available as bundles.
If the original lobs is not yet a bundle then you can search in maven central for a bundled version from servicemix bundles.
Using apache karaf is also often a big help. There are karaf features with predefined deps for a lot of libs like activemq, cxf, camel, openjpa, ...
In the worst case you can embed the lib and all deps in your own jar. This tends to cause class loading issues though if you try to share some classes between bundles.
What lib is the problem in your case?
A lot of libraries you mention (log4j, quartz, dom4j) have already been converted to OSGi bundles by Springsource. You can find them in the Springsource Enterprise Bundle Repository. All Hibernate libraries > 4.2 are also osgified.
You have three choices:
Find the library in some pre-made bundles (Springsource Repository, Eclipse Orbit Repository, etc.)
Include the libraries into your bundle as an external library (Make a directory lib, copy your jar files there, and reference them from the Bundle-Classpath element in MANIFEST.MF)
Convert the library into an OSGi bundle (e.g. with the bnd wrapconverter, example here)