Monday, September 10, 2012

Declarative Services with Karaf Part 1: Getting Started

OSGi Declarative Services (DS) is a lightweight and easy to use API that I found makes a very suitable dependency injection (DI) framework for OSGi containers. It has been available as part of the OSGi Specification since 4.0 making it, in my opinion, a very well baked and stable framework. The DS API that provides this capability is called the Service Component Runtime or SCR.

Now DS, like other DI frameworks, uses XML for the wiring at run-time.  DS also has annotations available like the other DI frameworks with one big difference; DS Annotations generate the XML at build-time where the other frameworks interpret them at run-time. This capability is provided by using either the BND or Felix Annotations with their respective Maven plugins. Both offerings are solid and stable implementations but have some significant differences:

Felix SCR Annotations
  • Inheritance Support for abstract components
  • Generated bind/unbind methods (less code by you, more code by manipulation)
BND/OSGi DS Annotations
  • Boilerplate for the new OSGi DS Annotations in the 4.3 Release
  • Fully supported by the Maven Bundle Plugin
  • No other library dependencies (Felix requires the annotation lib be installed)

I personally prefer the BND/OSGi annotations. They are lighter weight with regards to development and deployment. I can use my current Maven Bundle Plugin configuration and not have to introduce a new plugin and configuration. I also don't have to install the Felix Annotations into my container. Finally, with Felix SCR Annotations my source no longer matches the generated binary when you allow it to generate the service bindings.

Editorial Opinion: My concerns above are mostly trivial with the exception of the generated code. Even if you use the Felix annotations I would avoid using this capability. The SCR dynamically assigns concrete references to your component (not Proxies, another big plus of DS over other DI frameworks) making it necessary to account for thread safety on these references. Having the binding methods in the codebase allows the use of ReadWriteLocks that can be used across operations which is far superior to making synchronized methods or large synchronization blocks. More on that as we get to Part 3.

The one thing I would love to have though is inheritance. That is still a big negative but it is being discussed over at the OSGi group.

You can find more details about both sets of SCR Annotations in the following locations:

Installing Karaf SCR

To get started first install Karaf 2.2.9. It can be found here:
Now install the Karaf SCR Feature. This will allow you to manipulate the installed examples at runtime.

Navigate to where you installed Karaf 2.2.9 and open the etc/org.ops4j.pax.url.mvn.cfg file. This is where the configuration for Maven repository lookups are kept. Navigate to the bottom of the file and add the following repository:
  • http://sully6768.github.com/repos/releases/
The property file should now look like the following:
org.ops4j.pax.url.mvn.repositories= \
    http://repo1.maven.org/maven2, \
    http://repository.apache.org/content/groups/snapshots-group@snapshots@noreleases, \
    http://svn.apache.org/repos/asf/servicemix/m2-repo, \
    http://repository.springsource.com/maven/bundles/release, \
    http://repository.springsource.com/maven/bundles/external, \
    http://oss.sonatype.org/content/repositories/releases/, \
    http://sully6768.github.com/repos/releases/
Now start Karaf:
./bin/karaf debug
karaf@root>

Once it is up and running we can add the SCR Feature:
features:addurl mvn:org.apache.karaf.scr/org.apache.karaf.scr.feature/2.2.9/xml/features  
features:install scr
After installing the SCR feature you can verify everything installed correctly by typing scr: in the shell and then hitting the TAB key. This will display the new commands that were installed:
karaf@root> scr:
scr:activate      scr:deactivate    scr:details       scr:list
Finally, lets install the first SCR example and verify the commands are working as expected:
karaf@root> install -s mvn:org.apache.karaf.scr/org.apache.karaf.scr.examples.service/2.2.9
Bundle ID: 55
Now if we execute the scr:list command we should see two componets listed: The GreeterServiceComponent and he GreeterServiceImpl:

karaf@root> scr:list
   ID   State             Component Name
[6   ] [ACTIVE          ] GreeterServiceComponent
[5   ] [ACTIVE          ] org.apache.karaf.scr.examples.service.impl.GreeterServiceImpl

You are up and running and ready to start working with SCR Components in Karaf.

Using the Karaf Commands

Now lets go back and explore how to use the Karaf SCR Commands that were installed in Part 1. With the commands and the first example installed lets step through the commands.

scr:list [-s | --show-all]
-s and --show-all: Present all components (including hidden) when hitting the tab key

The scr:list command will list the current components installed in Karaf.
karaf@root> scr:list 
   ID   State             Component Name
[5   ] [ACTIVE          ] GreeterComponent
[6   ] [ACTIVE          ] org.apache.karaf.scr.examples.service.impl.GreeterServiceImpl
karaf@root>

Note: The most recent version of the Karaf SCR Components now supports hidden components in the CLI. A component with a property of "hidden.component=true" will not be displayed or available for completion without specifying the -s or --show-all option.

If we pass the -s or --show-all options to the scr:list command it will display all of the components in the container including those that provide the command and management functionality for Karaf SCR.
karaf@root> scr:list -s
   ID   State             Component Name
[5   ] [ACTIVE          ] GreeterComponent
[1   ] [ACTIVE          ] ActivateCommand
[2   ] [ACTIVE          ] ListCommand
[6   ] [ACTIVE          ] org.apache.karaf.scr.examples.service.impl.GreeterServiceImpl
[4   ] [ACTIVE          ] ScrServiceMBean
[3   ] [ACTIVE          ] DetailsCommand
[0   ] [ACTIVE          ] DeactivateCommand
karaf@root>

scr:details [-s | --show-all]
-s and --show-all: Present all components (including hidden) when hitting the tab key

The scr:details command will list the current configuration and state of a given component. Taking a look at the GreeterComponent we see it is currently active and that it has a satisfied reference to to the GreeterService:
karaf@root> scr:details GreeterComponent 
Component Details
  Name                : GreeterComponent
  State               : ACTIVE
  Properties          : ACTIVE
    component.name=GreeterComponent
    component.id=5
References
  Reference           : greeterService
    State             : satisfied
    Multiple          : single
    Optional          : mandatory
    Policy            : static
    Service Reference : Bound Service ID 195 (org.apache.karaf.scr.examples.service.impl.GreeterServiceImpl)
karaf@root>

scr:deactivate [-s | --show-all]
-s and --show-all: Present all components (including hidden) when hitting the tab key

The scr:deactivate command changes a component to disabled. Any component with a dependency on the deactivated component will become unsatisfied and deactivate as well.
karaf@root> scr:deactivate GreeterComponent 
karaf@root> scr:list 
   ID   State             Component Name
[-1  ] [DISABLED        ] GreeterComponent
[6   ] [REGISTERED      ] org.apache.karaf.scr.examples.service.impl.GreeterServiceImpl
karaf@root>

scr:activate [-s | --show-all]
-s and --show-all: Present all components (including hidden) when hitting the tab key

The scr:activate command changes a component to enabled. Any component with a dependency on the activated component will become satisfied and activate as well.
karaf@root> scr:activate GreeterComponent 
karaf@root> scr:list 
   ID   State             Component Name
[7   ] [ACTIVE          ] GreeterComponent
[6   ] [ACTIVE          ] org.apache.karaf.scr.examples.service.impl.GreeterServiceImpl
karaf@root>

In our next article we will start to look at the code behind the components: The Basics.

Next:
Part 2: The Basics

References:
OSGi 4.2 Specifications: http://www.osgi.org/Specifications/HomePage
OSGi 4.2 Javadoc: http://www.osgi.org/javadoc/r4v42/
Apache Felix Maven SCR - http://felix.apache.org/site/apache-felix-maven-scr-plugin.html
BND Annotation - http://www.aqute.biz/Bnd/Components

6 comments:

  1. First of all, great work and really good insights on the whole topic, thank you!

    I've actually manually installed that feature you mentioned in the way you provided over your github repo, unfortunately the link is not the right one I think, should be this one: https://github.com/sully6768/sully6768-mvn-repo

    And then I've rebuilt my project with the instructions you gave, all without a hassle. No warnings no errors. But when I install my component into karaf using the install command, your service is able to notice it and give infos about it, but it's not able to activate it. The command is just not starting the component. It stays in RESOLVED but never gets into the ACTIVE state. I'm also unable to see anything in the logs to understand what the problem would be...

    Do you have any ideas on why?

    Thanks in advance,
    Kjellski

    ReplyDelete
    Replies
    1. Hi Klellski,

      Thanks for feedback. It is really appreciated.

      First, the link I gave should be correct but in reality either should work. There is a Maven repository under my github web site that one gets with a github account. The repository you listed is just that, a repository. That repository is then pushed to the website. The content should be available though through http://sully6768.github.com/repos/releases/ though it won't be browsable.

      WRT the component resolution, can you execute the scr:details command for both the GreeterComponent and org.apache.karaf.scr.examples.service.impl.GreeterServiceImpl and reply with the output?

      I just ran the example with a clean build and a clean Karaf ("./bin/karaf clean") and everything cam up as expected. So any insight you could provide would be helpful.

      Let me know,
      Scott ES

      Delete
  2. This comment has been removed by the author.

    ReplyDelete
  3. Thank you. Your post is very helpful for beginners.

    ReplyDelete
  4. Hi, good posts! Just started with part 1 and have a question: what about Felix DM?
    I'm working with JBoss Fuse 6 (with Karaf), and in that sense, is it wise to use Felix DM or are there better alternatives (now) ?

    ReplyDelete
  5. Hi... i am seeing that some of the bundles are in Unsatisfied state, please let me know how do i debug that

    ReplyDelete