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.
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 currently developing a maven osgi bundle using Netbeans 7.1. While its easy to create new maven osgi bundle project from netbeans, I've been struggling about how I would run it. Simply running it from netbeans gives me an error that tells me there is missing requirement (missing slf4j for example).
Then I tried a different way. I ran equinox in a terminal and then manually install my project jar to it. But then I must also resolve all the dependencies manually.
Is there any way to automatically download all the required dependencies from an OSGI bundle and install it to a running OSGI framework?
thanx before
AFAIK there's no automation for OSGi in Netbeans (though I may well be wrong). The support you may have seen in Eclipse is only for Eclipse plugins not vanilla OSGi.
Your best bet is to go for some integrating testing or launch via a maven goal, pax-exam or bndtools or even pax-runner will allow you to launch from IDE/maven.
However I don't know of anything that will automatically resolve all dependencies (transitive dependencies and implementations of APIs you depend on would be problematic)
Its a big pain, no question about it. What I used to do was to do a full build (and if you've configured your manifests correctly should include all necessary dependencies) which will generate the necessary jar. I then wired my Tomcat to pick up the jar from my target repository and configured it to hotswap automatically.
Its a matter of preference if you want to run your app server from within your netbeans but I preferred to execute a separate instance of tomcat outside of my IDE. It'll work either way tho.
I have a java project that compiles down to an OSGi bundle. I'm using the maven-bundle-plugin to create the bundle, and the maven-sling-plugin to push the bundle to my running OSGi server. At the moment, my project has two dependencies (Guava and Gson) that need to be manually installed in the Felix server prior to installing the bundle. The manual install for these two dependency bundles only needs to occur once (when first setting up the OSGi server), but since it's a manual process, I'd kind of like to just push it into the "mvn install" phase.
I've looked at a number of maven plugins (maven-sling-plugin, maven-ipojo-plugin, dependency plugins, etc.), but I'm afraid that I just don't have enough knowledge to know where to start, or even to search in Stackoverflow for the solution (I have a suspicion that this has already been answered).
So - is there a clean way to install/start dependent bundles with maven? Something where I can specify a jar and a runlevel, and have the installation take place prior to my bundle being installed?
The Ops4j pax construct project might help: http://team.ops4j.org/wiki/display/paxconstruct/Pax+Construct
Looks like it's possible to use maven to specify which bundles to install and then spin up a felix osgi environment as described here:
http://www.sonatype.com/books/mcookbook/reference/ch01s04.html
Currently when I am writting a bundle in that depends on a package, I have to "import" or "depend" on a whole other bundle in Maven that contains that package.
This seems like it is counter-productive to what OSGi gives me.
For example let's say I have two bundles: BundleAPI and BundleImpl.
BundleAPI provides the API interfaces:
// BundleAPI's manifest
export-package: com.service.api
BundleImpl provides the implementation:
//BundleImpl's manifest
import-package com.service.api
However, when I am coding BundleImpl in Eclipse, I am forced to "depend" in maven POM on BundleAPI itself - so that eclipse does not complain.
//BundleImpl's POM
<dependency>
<groupId>com.service</groupId>
<artifactId>com.service.api</artifactId>
[...]
</dependency>
So - on one hand, I am depending only on the package com.service.api, while on the other - I need to have the whole bundle - BundleAPI.
Is there a way to make maven or eclipse smart enough to just find the packages somewhere, instead of whole bundles?
I am very much confused as to how this works - any type of clarity here would be great. Maybe I am missing something fundamentally simple?
The key is to distinguish between build-time dependencies and runtime dependencies.
At build time you have to depend on a whole artifact, i.e. a JAR file or bundle. That's pretty much unavoidable because of the way Java compilers work. However at runtime you depend only on the packages you use in your bundle, and this is how OSGi manages runtime substitution. This is the Import-Package statement in your final bundle.
Of course as a developer you don't want to list two parallel sets of dependencies, that would be crazy. Fortunately maven-bundle-plugin is based on a tool called bnd that calculates the Import-Package statement for you based on analysing your code and discovering the actual packages used. Other tools such as bndtools (an Eclipse-based IDE for OSGi development) also use bnd in this way. Incidentally bnd is much more reliable and accurate than any human at doing this job!
So, you define only the module-level dependencies that you need at build time, and the tool generates the runtime package-level dependencies.
I would recommend against using Tycho because it forces you to use Eclipse PDE, which in turn forces you to manually manage imported packages (for the sake of full disclosure, I am the author of bndtools which competes against PDE).
You cannot develop bundles like regular Java projects with Maven and eclipse. You basically have 2 options.
Apache Felix Bundle Plugin: Basically you develop the project as a regular Java project and use Maven as you normally would. This plugin will be used to add all the OSGi specifics to the jar manifest at deployment time to OSGi enable it. The disadvantage of this aproach is that you are using a Java project in your workspace instead of a bundle, which makes running your project in the OSGi container a little extra work since Eclipse doesn't recognize it as a plugin project. Thus you have to add the jar from the Maven build as part of the target platform manually.
Tycho: This is another Maven plugin that attempts to actually bring theses two environments together and does a pretty good job of it. In this scenario, you actually create an Eclipse bundle/plugin project, which obviously makes for seamless integration in Eclipse. The pom then marks the project as being an eclipse-plugin type, which effectively makes Maven resolve the project dependencies (defined in the manifest) via the target platform instead of Maven itself.
I would take the Tycho approach as it gives a much more integrated approach with Eclipse.
Having the whole jar as a dependency shouldn't be a problem, that's how you have to do it with Maven anyway.
I'm using netbeans, project: 'maven OSGI bundle', i have bundle activator running fine in felix (and so on).
But I'm not able to add an external JAR (i.e. local) to the bundle itself. In practice let's say i have and utils.jar file I'd like to use IN the bundle (without exporting it), I can't understand why and how it is so difficult (uncommon?).
P.S. I have seen that PAX and Eclipse (i tried only one with no success) may create a bundle from a jar lib, but it still sounds so strange to me that this task is not a common practice.
background:
I did some homework and I'm guessing I'm approaching the problem in the wrong way, so I'm posting for help (hints in the right way).
I'm developing a java library (as set of interfaces and implementations) acting as middleware for various projects. The generic problem and scope is very compatible with OSGI arch.
Now the problem is basically: sharing a set of classes/interfaces (=jar library) between bundles (= services and implementations).
I like and think that the best approach is having a BASE bundle exporting such library and other bundles as extensions or dependent services as users/providers/actuators.
SOLVED. after a lot of homework and some tests i got it working by finding the mavenized version of the library and using 'Embed-Dependency' keyword (editing pom manually). still dunno how to do that with netbeans ide.