Find activate-immediately services that lack an activate method

Immediate service activation in OSGi can be tricky but there are some basic rules to consider. Another point to think about is when a service doesn’t contain an activate method. The code base I work in uses Felix’s SCR annotations which makes this search pretty concise. I also assume that the code is in git. If your code isn’t, you should be able to replace git with find <dir> -type f -exec <grep-fu here>.

Find activate-immediately services

Using a little git and grep-fu, we can find our services that activate immediately.

git grep -l 'immediate[[:space:]]\?=[[:space:]]\?true'

The command below makes a few assumptions:

  1. We use SCR annotations that allow immediate = (true|false)
  2. We use immediate = true almost never except in the @Component annotation.

Find services that have an activate method

For our next trick, we’ll find the set of files that have an activate method as noted by the use of an @Activate annotation.

git grep -l '@Activate'

Find the intersection of activate-immediately services that lack an activate method

Now to the fun. With the information we’ve grepped above, we need the things that are in set 1 but not in set 2. There’s a great little tool in linux called comm that can help us with the set operations. It needs sorted data to work correctly, so we’ll dress up our previous commands and send them in.

comm -23 <(git grep -l 'immediate[[:space:]]\?=[[:space:]]\?true' | sort) <(git grep -l '@Activate' | sort)

The -23 argument tells comm that we want to suppress unique items from the second set (activate method list) and to suppress items that exist in both sets (immediate + activate). This leaves us with services that don’t have an activate method. If you want to see services that are immediate and have an activate method, change the argument to -12.

Understanding the ‘unresolved constraint’, ‘missing requirement’ message from Apache Felix Pt. 2

We previously took a look at Felix’s unresolved constraint message. I started testing with Felix 4.0.2 today and realized the output for an unresolved constraint has changed a bit.

ERROR: Bundle org.sakaiproject.nakamura.world [76] Error starting file:bundles/org.sakaiproject.nakamura.world_1.4.0.SNAPSHOT.jar (org.osgi.framework.BundleException: Unresolved constraint in bundle org.sakaiproject.nakamura.world [76]: Unable to resolve 76.0: missing requirement [76.0] osgi.wiring.package; (&(osgi.wiring.package=javax.servlet)(version>=3.0.0)))
11.07.2012 17:01:43.297 *ERROR* [FelixDispatchQueue] org.sakaiproject.nakamura.world FrameworkEvent ERROR (org.osgi.framework.BundleException: Unresolved constraint in bundle org.sakaiproject.nakamura.world [76]: Unable to resolve 76.0: missing requirement [76.0] osgi.wiring.package; (&(osgi.wiring.package=javax.servlet)(version>=3.0.0))) org.osgi.framework.BundleException: Unresolved constraint in bundle org.sakaiproject.nakamura.world [76]: Unable to resolve 76.0: missing requirement [76.0] osgi.wiring.package; (&(osgi.wiring.package=javax.servlet)(version>=3.0.0))
 at org.apache.felix.framework.Felix.resolveBundleRevision(Felix.java:3826)
 at org.apache.felix.framework.Felix.startBundle(Felix.java:1868)
 at org.apache.felix.framework.Felix.setActiveStartLevel(Felix.java:1191)
 at org.apache.felix.framework.FrameworkStartLevelImpl.run(FrameworkStartLevelImpl.java:295)
 at java.lang.Thread.run(Thread.java:679)

We have the same unresolved constraint..missing requirement as before but the part we’re interested in has changed a bit. Let’s break apart that first message.

(org.osgi.framework.BundleException: Unresolved constraint in bundle org.sakaiproject.nakamura.world [76]: Unable to resolve 76.0: missing requirement [76.0] osgi.wiring.package; (&(osgi.wiring.package=javax.servlet)(version>=3.0.0)))

Given what we know from last time, the interesting bits above are:

Unresolved constraint in bundle org.sakaiproject.nakamura.world [76]

This tells you what bundle had an issue trying to resolve a constraint. The next part is a bit less obvious but can be broken up.

osgi.wiring.package; (&(osgi.wiring.package=javax.servlet)(version>=3.0.0)))

osgi.wiring.package looks pretty foreign, hu? Disregard that and you see javax.servlet and version>=3.0.0. Tada! That’s the good stuff. So, figure out where that bundle is that exports javax.servlet>=3.0.0 and you’re on your way. (Hint: maybe, javax.servlet:javax.servlet-api:3.0.0 or org.ops4j.pax.web:pax-web-jetty-bundle:2.0.1 is what you’re looking for.)

Getting started with Pax Runner

After fighting through a Maven assembly for a small project, I just couldn’t take that headache again. I’ve used Apache Sling’s Maven Launchpad Plugin to put together a standalone OSGi server but Launchpad doesn’t allow you to pick which OSGi container you deploy to or what version of Felix gets used. I’ve started working with Pax Runner because a) it looks pretty nifty, b) those Pax folks are doing great stuff for the OSGi deployers out there.

Pax Runner has a few sweet features I’m really digging right now.

Different OSGi platforms and versions

I generally develop on Apache Felix, but if I should be able to run in any other OSGi container, right? Well, to test that theory I can ask Pax Runner to load up my profile using a different platform (--platform; defaults to ‘felix‘) and the version of that platform (--version).

If I want to test my setup with Equinox I just run:

pax-run --platform=equinox awesome-profile.composite

Knopflerfish you say?

pax-run --platform=knopflerfish awesome-profile.composite

What about an older version of Felix? Easy!

pax-run --platform=felix --version=3.0.8 awesome-profile.composite

Deploy multiple profiles and build composite profiles

I plan to run my project with a single profile, but if you find the need to include other profiles it’s just another command line switch:

pax-run --profiles=config,log awesome-profile.composite

“But I want a specific version of a profile.” And you should! So use this:

pax-run --profiles=config/1.0.0,log/1.2.0 awesome-profile.composite

Profiles? What’s this crazy talk you speak?!

So, the root of all this chatter is Pax Runner Profiles. I can barely speak to the topic, but will attempt to anyway. (Don’t trust me; read the documentation)

A short glimpse into my profile file shows that I just include bundles that I know to live in a Maven repository:

scan-bundle:mvn:commons-io/commons-io/1.4@1
scan-bundle:mvn:commons-fileupload/commons-fileupload/1.2.2@1
scan-bundle:mvn:commons-collections/commons-collections/3.2.1@1
scan-bundle:mvn:commons-lang/commons-lang/2.6@1
scan-bundle:mvn:commons-pool/commons-pool/1.5.6@1
scan-bundle:mvn:commons-codec/commons-codec/1.5@1

A quick explanation of these lines is simply:
scan-bundle:mvn:<groupId>/<artifactId>/<version>@<startLevel>

For those looking for more OSGi goodness, Pax Web has really stepped up with the 2.0.0 release. You can configure your Jetty server by deploying a bundle fragment with the appropriate jetty.xml file. Awesome!