Blog / 20091020 aQute - Software Consultancy
Search
*

Components and Annotations

My favorite OSGi spec is the Declarative Services specification. It is exactly as a specification should be: small and concise. It does not try to be everything for everybody. The only thing it does is handle your service dependencies. And it does that very well, without compromises. And as a bonus, it is also well integrated with Configuration Admin.

The only potential flaw is that it uses XML for its configuration data. XML is fine for computers but it lacks about every possible feature necessary to make it user friendly. However, long time ago I added an extra syntax to bnd to create the XML on the fly directly from the manifest header. For example:

  Service-Component: aQute.example.EventHandlerImpl; 

provide:= org.osgi.service.event.EventHandler;

log=org.osgi.service.log.LogService?

This header is translated to a proper XML resource, somewhere in your bundle and the Service-Component header is rewritten to point to this resource. While creating the XML resource, bnd verifies the different classes and does sanity checks. This feature works fine and it is widely used.

However, even though the header is lot smaller than the corresponding XML (10x?), it still contains cruft. In the compiler we have the advantage of being able to use short names for fully qualified names. Isn't there a way to use the compiler? Well, annotations were added to Java 5 for exactly this reason. I therefore recently added annotations to make it event simpler.

The first part is the source code. Let's make a class that implements an EventHandler service. This is a part of the Event Admin service:

  package com.example;
  import aQute.bnd.annotation.component.*;
  import org.osgi.service.event.*;

  @Component
  public class MyHandler implements EventHandler {  
    public void handleEvent(Event event) {
      System.out.println(event);
    }
  }

So how does bnd find these annotations? Well, it would be easy to just check the whole JAR. However, this can sometimes be too wide a scope. bnd must therefore be instructed where to look. This can be done with wildcards. The most promiscuous is:

  Service-Component: *
  Private-Package: com.example.*

This header will inspect every class in the current JAR for the Component annotation. Quite simple! if you know the package root where your components are, then you can limit the scope:

  Service-Component: com.example.*

So what are the annotations? The following annotations are supported by bnd:

ComponentProvides the component information like, name, provides, etc. Can only be used on a type.
ReferenceOn a setXXX(XXX) method. Will analyze the argument and calculate the service dependency
ActivateOn the activate method.
DeactivateOn the activate method.
ModifiedOn the modified method.

I've been using this feature for some time now and it seems to work very well. Please try it out and let me know any shortcomings.

  Peter Kriens

P.S. If you do not want to put all of bnd on your classpath, you can also use the annotations jar, see the download page.

Copyright 2006 aQute SARL, All Rights Reserved