How Apache Karaf sorts bundles to install and start? - osgi

I have defined four bundles:
bundle 1 : export package x version 1
bundle 2 : import package x ver [1,2] and export package y;y uses x
bundle 3 : export package x version 2
bundle 4 : import package y and also import package x version 2
Using apache felix (distribuable binary), I found that I should manually impose to not resolve (or start) the bundle 1 and then bundle 2 before starting the bundle 3 (otherwise a uses constraint problem appears because bundle 2 will use package x version 1 and in bundle 4 will appear package x version 1 and version 2 --> uses constraint violation).
Thanks to the authors of these posts:
http://njbartlett.name/2011/02/09/uses-constraints.html
http://blog.springsource.com/2008/10/20/understanding-the-osgi-uses-directive/
I don't like to impose order to my bundles, I need to copy all my bundles in the /bundle directory and then the instance of framework install and start them.
I noticed that Apache felix sorts the bundles to be installed alphabetically (so bundle 1 will be installed and then started the first).
I tried with Apache karaf, I copied my bundles into /deploy and I found that the problem disappears, so my question is:
Does Apache Karaf, (or felix file install) apply a strategy to impose any order for starting bundles in order to avoid these kind of problems ?

You should try to use a Karaf feature for this kind of deployment. You create a feature file with one feature in it and add all the bundles to this feature. Karaf will then load all the bundles and resolve and start them in one pass. So the resolver should bee able to correctly resolve all your bundles.

Apache Karaf does automatically add a startlevel to the bundles in the deploy folder this is configurable. The default of it is 50. So all your custom bundles are installed as StartLevel 50. This also makes sure the basic bundles of karaf itself are already up and running, especially the file-installer bundle.

Felix FileInstall does not have any ordering capability.
Start order isn't really important (bundles should be able to be started in any order), but a good Management Agent should be able to install and resolve a batch of bundles as a single operation. However FileInstall installs/resolves/starts bundles whenever it happens to poll the filesystem directory. Therefore FileInstall is not really usable for production deployment.
I don't know anything about Karaf, but any management agent that simply polls a directory is likely to have the same problem.

Related

How to update a bundle from Maven artifact with running Apache Felix

Currently I have a situation, where I develop a project, then run mvn install and it get's put into my local Maven repository as a simple JAR file
Then, I have a crafted by some other guys "environment" which includes a whole lot of bundles and stuff, and is ultimately run via mvn pax:run and it takes like 5 minutes to run
I would like to be able to just run felix:update <bundle-name> but I cannot fill the gap between a Maven JAR artifact in local Maven repo, and a ready-for-provisioning bundle that I could put somewhere to just run felix:update or whatever, maybe uninstall/install
When I try to run mvn pax:create-bundle with my project, it throws a Containing project does not have packaging type 'pom' exception
Any help is highly appreciated
UPDATE: I've noticed that problems with re-installed bundle begin in it's activator, with a ClassNotFoundException (although the class mentioned is and always present in the bundle, so it must an issue with classpath, ClassLoader setup or whatever)
at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation BundleWiringImpl.java:1574 at org.apache.felix.framework.BundleWiringImpl.access$400 BundleWiringImpl.java:79 at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass BundleWiringImpl.java:2018 at java.lang.ClassLoader.loadClass ClassLoader.java:357 at some.external.adapters.package.guice.SomeModule.configure SomeModule.java:46 at com.google.inject.AbstractModule.configure AbstractModule.java:59
If you have a path to a file which is the newly built bundle, you can update it from the Gogo shell as follows:
felix:update <bundleid> file:/path/to/file
refresh
Where <bundleid> is the numeric ID of the bundle that you want to update. The refresh command is needed in case any bundles depend on or import packages from the bundle you are updating; this command will cause the Framework to attempt to re-resolve them using the new dependency.
I am happy to accept #neil-bartlett's answer, though I have to add some more context:
1) one of the biggest issues I had initially is that a JAR-file in local Maven repo IS NOT THE SAME as an OSGi bundle. In order to create bundle, I had to run mvn bundle:bundle AFTER mvn install. And the bundle got created in target/ folder.
2) afterwards, in a GoGo shell, I could indeed run felix:update <bundle-id> file:C:/Users/blablabla/bundle-SNAPSHOT-2.0.jar, and for some reasons, these days it just works. The exceptions, mentioned in updates to original post, are indeed occurring, but they do not prevent proper installation of an updated bundle.

using servlet-api 3 bundle in adobe CQ5

I'm trying to use the servlet-api version 3 in an Adobe CQ5 installation, without much success.
there is already a bundle that exports the javax.servlet package (version 2.5), so I deployed a bundle with version 3.1.0. this bundle starts ok.
The problem is starting the bundle that uses the api v3. I am getting an OSGi exception that I cannot fully understand:
POST /system/console/bundles/250 HTTP/1.1] cqse-httpservice %bundles.pluginTitle: Cannot start (org.osgi.framework.BundleException:
Constraint violation for package 'javax.servlet' when resolving module 250.9 between existing import 266.0.javax.servlet
BLAMED ON [[250.9] package; (&(package=javax.servlet)(version>=3.0.0)(!(version>=4.0.0)))]
and uses constraint 22.1.javax.servlet
BLAMED ON [[250.9] package; (package=com.day.cq.wcm.foundation.forms), [210.0] package;
(&(package=org.apache.sling.api.resource)(version>=2.0.0)), [93.0]
package; (&(package=javax.servlet)(version>=2.4.0))])
bundle 266 exports javax.servlet v=3.10 (I installed this one)
bundle 22 exports javax.servlet v=2.5 (provided by CQ5)
bundle 250 (mine) imports javax.servlet,version=[3.0,4) from 266. It also imports packages from 210 and 93.
bundle 210 imports javax.servelt v=2.5 from 22 (but the import in manifest does not have a version. maybe this is the problem?)
bundle 93 has javax.servlet; version="2.4" in the Import-package. but it resolved to javax.servlet,version=2.5.0 from (22) somehow.
The problem seems to be around the dependencies of bundle 250, but Im not sure what is the problem. AFAIK two versions of a package can coexist in an OSGi container. bundles 210 and 93 are running without issues.
This is most likely due to the fact that the used http-service only supports servlet 2.5 that's why this is the pre-installed servlet version. Since you installed a servlet 3.0 api your bundle does resolve but as it tries to export a service which is picked up by the http-service you run into this issue. The root cause is the http-service implementation that is used. I don't know if this would work but you might try to replace the http service version by using Pax-Web 2 or 3 instead. Pax-Web does support Servlet API since version 2.
After reading the article left in the comments, I noticed that dependencies of my bundle expose classes of the servlet api 2.5. This is causing the constraint and prevents my bundle. If I understand correctly the classpath from bundle 210 is expanded up to my bundle.
So, the only option will be to remove the dependency of my bundle with the other bundles, which I am afraid I cannot do. I will have to deal without the V3 api

Unable to auto-deploy bundle to Karaf

I am developing an OSGI-based application, which deploys to Karaf container. Karaf has an auto-deployment feature, whereby copying a bundle to its karaf/deploy directory should automatically deploy that bundle into the container. More often than not, however, I am getting errors similar to the one below when I copy bundles into the deploy directory:
org.osgi.framework.BundleException: Bundle symbolic name and version are not unique: legacy-services-impl:8.0.0.ALPHA-SPRINT9-SNAPSHOT
at org.apache.felix.framework.BundleImpl.createRevision(BundleImpl.java:1225)
at org.apache.felix.framework.BundleImpl.<init>(BundleImpl.java:95)
at org.apache.felix.framework.Felix.installBundle(Felix.java:2979)
at org.apache.felix.framework.BundleContextImpl.installBundle(BundleContextImpl.java:165)
at org.apache.felix.fileinstall.internal.DirectoryWatcher.installOrUpdateBundle(DirectoryWatcher.java:1030)[6:org.apache.felix.fileinstall:3.3.11.fuse-71-047]
at org.apache.felix.fileinstall.internal.DirectoryWatcher.install(DirectoryWatcher.java:944)[6:org.apache.felix.fileinstall:3.3.11.fuse-71-047]
at org.apache.felix.fileinstall.internal.DirectoryWatcher.install(DirectoryWatcher.java:857)[6:org.apache.felix.fileinstall:3.3.11.fuse-71-047]
at org.apache.felix.fileinstall.internal.DirectoryWatcher.process(DirectoryWatcher.java:483)[6:org.apache.felix.fileinstall:3.3.11.fuse-71-047]
at org.apache.felix.fileinstall.internal.DirectoryWatcher.run(DirectoryWatcher.java:291)[6:org.apache.felix.fileinstall:3.3.11.fuse-71-047]
Instead of redeploying an already deployed bundle, the container tells me that I am trying to deploy a duplicate bundle.
The Karaf indeed has that bundle deployed, but why wouldn't it redeploy the bundle? What is causing this behavior? How to avoid such errors on auto-deploy?
Thank you,
Michael
I suspect that your bundle does not stop correctly. That may be the reason why karaf thinks it is still there. Do you have some code in your activator that is executed when stopping? Perhaps you are also running some threads. You should make sure the stop method of your activator works and cleanly closes all resources and stops all threads of your bundle.

Generate a equinox environment and config by script (Ant or something) of deployed OSGI bundles

I am searching for a way to generate a run able equinox configuration of deployed OSGI bundles.
A build server deploys our OSGI bundles via maven and tycho-plugin and placed them in the m2 directory.
Now, the next step is to collect the bundles from the deployment directory and put them together in a equinox configuration and start up the container.
Collect the bundles and configure the equinox container manually is not the way I prefer so now I looking for a way to do this automatically via script.
There are solutions like ANT script?
Hoping for Help
Build a "product" (i.e. a fully self-contained OSGi runtime).
See the tycho docs in general [1] and esp. exercise 5 of the tycho tutorial [2] with solution [3]
[1] http://eclipse.org/tycho/documentation.php
[2] http://eclipsecon.org/sessions/building-eclipse-plugins-and-rcp-applications-tycho
[3] https://github.com/jsievers/tycho-demo/tree/master/exercises/Exercise_06_Solution
One thing you could do is generate an config.ini file which you can put in your configuration/ directory. The osgi.bundles entry in there allows you to specify what bundles to install and start, e.g.:
config.ini content:
osgi.bundles=org.eclipse.osgi.services#start, ../mydirectory/mybundle.jar#start
You may need to specify the configuration directory when launching equinox to ensure the config.ini is picked up, e.g.
java -jar plugins/org.eclipse.osgi_3.7.1.R37x_v20110808-1106.jar -configuration configuration
You can use https://github.com/sarod/equinox-config-builder to easily generate a config.ini from a plugins directory.

Check whether a file is an OSGi bundle (and find the bundle name) without installing it in the OSGi framework

Is it possible? Or do I have to try to install it?
I'll assume you're talking about OSGi Release 4, since in OSGi Release 3 and earlier any valid JAR file was also a valid OSGi bundle.
Simply read the JAR's manifest using the standard Java APIs in the java.util.jar package. The minimum headers required to be a valid R4 bundle are:
Bundle-ManifestVersion: 2
Bundle-SymbolicName: ...
As BJ points out, the "id" of the bundle is assigned when it is installed, but what many people take to be the "id" is actually the Bundle Symbolic Name.
You can check for the Bundle-Name, or a host of Bunde-XXX properties within the *meta-inf/manifest.m*f jar file.
The bundle id is assigned by the framework when the bundle is installed. Thus only an installed bundle has a bundle id.

Resources