Wednesday, September 19, 2012

Camel Committer!

I am so very excited. I was inducted into the Apache brotherhood for the first time joining Camel as an official committer. I am just seriously geeking out about this.

To kewl.

Sunday, September 16, 2012

Declarative Services with Karaf Part 4: Component Factories

Continuing my series on Declarative Services (DS) in Karaf in this article we will take a look at Component Factories and how they behave when using the Service Component Runtime (SCR) in Karaf.

For me, DS Component Factories are most easily thought of as Managed Services in reverse. Why? Because the immediate component is now responsible for managing the life-cycle and configuration of a given service.

Note: The ComponentFactory is very useful for managing a collection of services such as a group of Mina Server threads or say Camel Producer Templates (a bit of foreshadowing).

Lets take a look at a simple example of a Component Factory. In the sources we downloaded in Part 2 of the series change to the component-factory project. Lets first take a look at the GreeterServiceComponentFactory.

Comparing the GreeterServiceFactoryComponentImpl.java with the ManagedGreeterServiceImpl.java code, aside from the class names, the only difference is the attributes that are used to define the component.

GreeterServiceComponentFactoryImpl.java
// The ConfigAdmin PID of our component
@Component(name = GreeterServiceComponentFactoryImpl.COMPONENT_NAME,
// The Factory ID of the Component Factory
factory = "greeter.factory.provider")
public class GreeterServiceComponentFactoryImpl implements
    GreeterServiceComponentFactory {

    {snip....}
}

ManagedGreeterServiceImpl.java
// The ConfigAdmin PID of our component
@Component(name = ManagedGreeterServiceImpl.COMPONENT_NAME,
// The policy that makes our configuration a required dependency
configurationPolicy = ConfigurationPolicy.require)
public class ManagedGreeterServiceImpl implements ManagedGreeterService {

    {snip....}
}

The GreeterServiceComponentFactoryImpl.java uses the factory attribute in place of configurationPolicy. The factory attribute serves two purposes. BND uses it to configure the component as a factory for service creation. It is also used as the targe service property in our component factory manager class. Lets take a look at it now.

GreeterServiceFactoryManager.java
@Component(name = GreeterServiceFactoryManager.COMPONENT_NAME)
public class GreeterServiceFactoryManager {

    public static final String COMPONENT_NAME = "GreeterServiceFactoryManager";

    public static final String COMPONENT_LABEL = "Greeter Service Factory Manager";

    private static final Logger LOG =
        LoggerFactory.getLogger(GreeterServiceFactoryManager.class);

    private ComponentFactory factory;
    private ComponentInstance instance;
    private GreeterServiceComponentFactory greeterService;
    private ReadWriteLock lock = new ReentrantReadWriteLock();

    /**
     * Called when all of the SCR Components required dependencies have been
     * satisfied.
     */
    @Activate
    public void activate() {
        LOG.info("Activating the " + COMPONENT_LABEL);
            final Properties props = new Properties();
            props.setProperty("salutation", "Hello");
            props.setProperty("name", "Scott");
            instance = factory.newInstance(props);
            greeterService = (GreeterServiceComponentFactory)instance.getInstance();
            greeterService.startGreeter();
    }

    /**
     * Called when any of the SCR Components required dependencies become
     * unsatisfied.
     */
    @Deactivate
    public void deactivate() {
        LOG.info("Deactivating the " + COMPONENT_LABEL);
        greeterService.stopGreeter();
        instance.dispose();
    }

    @Reference(target = "(component.factory=greeter.factory.provider)")
    public void setFactory(final ComponentFactory factory) {
        this.factory = factory;
    }

    public void unsetFactory(final ComponentFactory factory) {
        this.factory = null;
    }
}

Note: The actual source contains the necessary thread locks to ensure we are thread safe. Snipped here for clarity.

There are several areas worth calling attention to above. The first is the set/unset bindings. You will notice that we do not bind to an instance of the GreeterServiceComponentFactory but to the DS API provided ComponentFactory service. It is through this service that we will obtain our reference to the GreeterServiceComponentFactory.

Next look at the activate method on line 20. There is where the magic really happens. After our dependency on the ComponentFactory is satisfied the activate method is called. In there we use our ComponentFactory to create an instance of ComponentInstance. The ComponentInstance is responsible for configuration and creation of our GreeterServiceComponentFactory and this happens on line 25. From there we can now create a new instance of the GreeterServiceComponentFactory.

Finally, as we are now responsible for the creation of our components we are also responsible for its clean up. On line 38 after shutting down the Greeter Service we must clean up our reference to the ComponentInstance by calling dispose which removes the configuration associated with this instance of the Greeter Service.

Lets now take a look at how a Component Factory behaves when we deploy it to Karaf using the Karaf SCR Components.

Running the Code
Build and install the code for the compoent-factory. To install execute the following command at the Karaf CLI:
install -s mvn:org.apache.karaf.scr/org.apache.karaf.scr.examples.component.factories/2.2.9
Taking a look at the list of components that are installed you will see that there are actually 3 components and not 2. That is because when we started our manager component obtained an instance of the factory component and used it to create the actual service instance.
scr:list 
   ID   State             Component Name
[21  ] [ACTIVE          ] GreeterServiceFactoryManager
[20  ] [FACTORY         ] GreeterServiceComponentFactory
[22  ] [ACTIVE          ] GreeterServiceComponentFactory
In the log file you will find that the output is slightly different also. In the case of the managed services from Part 3 the service component was always activated first and then its dependent components were activated. Here the manager component has to be activated first since it is responsible for the creation of its dependent service.
INFO  | Karaf Shell Console Thread       | Activating the Greeter Service Factory Manager
INFO  | Karaf Shell Console Thread       | Activating the Greeter Service Component Factory
INFO  | pool-26-thread-1                 | Message 1: Hello Scott
INFO  | pool-26-thread-1                 | Message 2: Hello Scott
INFO  | pool-26-thread-1                 | Message 3: Hello Scott
INFO  | pool-26-thread-1                 | Message 4: Hello Scott
INFO  | pool-26-thread-1                 | Message 5: Hello Scott
If we deactivate the manager we should see that we now have only two components registered with the SCR since the manager is going to dispose of the service instance.
scr:deactivate GreeterServiceFactoryManager
Looking at the list we find just that now.
scr:list 
   ID   State             Component Name
[-1  ] [DISABLED        ] GreeterServiceFactoryManager
[20  ] [FACTORY         ] GreeterServiceComponentFactory
We also find that the manager deactivation preceeds the services deactivation. Again, this is expected since our manager is responsible for the management of the service instance.
INFO  | Karaf Shell Console Thread       | Deactivating the Greeter Service Factory Manager
INFO  | pool-26-thread-1                 | Thread shutting down
INFO  | Karaf Shell Console Thread       | Deactivating the Greeter Service Component Factory

Well that about wraps it up. If you to see the real power of the ComponentFactory in DS try extending the manager to become a managed immediate component that will take the passed in configurations to create many custom greeters. I think you will really start to see the possibilities then.

If you have an questions or comments please feel free to drop me a note.

And watch for my next series: Camel DS with Camel SJMS.

Thanks!

Declarative Services with Karaf Part 3: Managed Services

Continuing my series on Declarative Services in Karaf in this article we will take a look at Managed Services and how they behave when using the Service Component Runtime (SCR) in Karaf. Managed Services are OSGi services that need access to configuration data at initialization and/or run-time. These configurations are administered through the OSGi Configuration Admin service which is a core service in Karaf. Karaf provides three ways to manage configurations used by the Config Admin service: the Felix File Install framework, the Config Admin CLI Commands and the Web Console.

The Felix File Install framework is configured to monitor the $KARAF_HOME/etc directory for bundle configuration files. When files are added with a name that matches the Managed Service PID and ending with .cfg, the file is read and a new configuration is added to the Config Admin registry.

Lets take a look at the second example that was included in the code we downloaded from Part 2: managed-service.

The managed-service project it is basically the same as what we found in the service project from Part 2. We have a delayed component, the ManagedGreeterService, and an immediate component, the ManagedGreeterComponent.

The ManagedGreeterComponent is mostly the same as what was in the GreeterComponent from Part 2. The only real difference is that it calls the new interface from the activate and deactivate methods. The annotations have not changed though so lets take a look at our delayed component.

Since we are discussing a managed service it makes sense to create a service that can demonstrate how creating, changing and removing the configuration for a given managed service behaves when using DS. To explore this we have created a new interface that allows a consumer of the delayed component to stop and start its logic:

ManagedGreeterService.java
public interface ManagedGreeterService {
    void startGreeter();
    void stopGreeter();
}

The ManagedGreeterServiceImpl.java code has a number of changes that are worth pointing out. First, in lines 47-77 we have added a runnable that when started, will print to our log until the stop method is called. This runnable requires configuration before it is started though. That is going to be handled by the managed part of our delayed component.

First look at the activate method on line 17. The signature has changed by adding a Map argument (one of the three possible arguments you can pass to the any of the lifecycle methods in DS, see the spec for further details). The SCR will recognize this signature and will ask the ConfigAdmin service for a configuration that corresponds to the components name, in this case, the ManagedGreeterService.

Remember that a delayed component will activate when all of its dependencies are satisfied and that there is an active reference to it. In this case the dependency is not another service but the configuration. The SCR annotations though configure our components configuration to be optional by default though. Therefore we need to tell the SCR that a configuration is required and to do that we set the annotation attribute configurationPolicy to ConfigurationPolicy.require on line 2. This will make a configuration required for our component before it will become satisfied.

ManagedGreeterServiceImpl.java
@Component(name = ManagedGreeterServiceImpl.COMPONENT_NAME,
           configurationPolicy = ConfigurationPolicy.require)
public class ManagedGreeterServiceImpl implements ManagedGreeterService {

    public static final String COMPONENT_NAME = "ManagedGreeterService";
    public static final String COMPONENT_LABEL = "Managed Greeeter Service";

    private static final Logger LOG = LoggerFactory.getLogger(ManagedGreeterServiceImpl.class);

    private ExecutorService executor = Executors.newCachedThreadPool();
    private Worker worker = new Worker();

    /**
     * Called when all of the SCR Components required dependencies have been
     * satisfied.
     */
    @Activate
    public void activate(final Map<string> properties) {
        LOG.info("Activating the " + COMPONENT_LABEL);

        if (properties.containsKey("salutation"))
            worker.setSalutation((String)properties.get("salutation"));

        if (properties.containsKey("name"))
            worker.setName((String)properties.get("name"));
    }

    /**
     * Called when any of the SCR Components required dependencies become
     * unsatisfied.
     */
    @Deactivate
    public void deactivate() {
        LOG.info("Deactivating the " + COMPONENT_LABEL);
    }

    public void startGreeter() {
        executor.execute(worker);
    }

    public void stopGreeter() {
        if (!executor.isTerminated()) {
            executor.shutdownNow();
        }
    }

    /**
     * Thread worker that continuously prints a message.
     */
    private class Worker implements Runnable {

        private String name;
        private String salutation;

        public void run() {
            boolean running = true;
            int messageCount = 0;
            while (running) {
                try {
                    LOG.info("Message " + (++messageCount) + ": " + salutation + " " + name);
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    running = false;
                    LOG.info("Thread shutting down");
                }
            }
        }

        public void setName(String userName) {
            this.name = userName;
        }

        public void setSalutation(String salutation) {
            this.salutation = salutation;
        }
    }
}

Running the Code
Lets see how our new code behaves in Karaf using the SCR commands. First lets install it:

install -s mvn:org.apache.karaf.scr/org.apache.karaf.scr.examples.managed.service/2.2.9

To verify it was installed run scr:list from the Karaf CLI.
scr:list 
   ID   State             Component Name
[7   ] [UNSATISFIED     ] ManagedGreeterComponent
[8   ] [UNSATISFIED     ] ManagedGreeterService

Both components should be UNSATISFIED because we have not created a configuration yet for the ManagedGreeterService. Lets create one then and see what happens. From the Karaf CLI issue the following configuration commands:
config:edit ManagedGreeterService
config:propset salutation "Hello"
config:propset name "Scott"
config:update
Now when we use the scr:list command we see that our components are now SATISFIED
scr:list 
   ID   State             Component Name
[9   ] [ACTIVE          ] ManagedGreeterComponent
[8   ] [ACTIVE          ] ManagedGreeterService
And if we look into our log file we will start to see the output from our ManagedGreeterService:
INFO  | vent: pid=ManagedGreeterService) | Activating the Managed Greeeter Service
INFO  | vent: pid=ManagedGreeterService) | Activating the Managed Greeter Component
INFO  | pool-19-thread-1                 | Message 1: Hello Scott
INFO  | pool-19-thread-1                 | Message 2: Hello Scott
INFO  | opt/karaf/apache-karaf-2.2.9/etc | Installed /opt/karaf/apache-karaf-2.2.9/etc/ManagedGreeterService.cfg
INFO  | pool-19-thread-1                 | Message 3: Hello Scott
INFO  | pool-19-thread-1                 | Message 4: Hello Scott
INFO  | pool-19-thread-1                 | Message 5: Hello Scott
...
Note: Observe on line 5 that when we use the CLI to add a configuration a ManagedGreeterService.cfg file is added to the etc directory.

Lets remove the configuration now and verify that everything shuts down and is cleaned up:
config:delete ManagedGreeterService
Using the scr:list command again we see that our components have become UNSATISFIED and have deactivated. Reviewing the log file verifies this.
INFO  | vent: pid=ManagedGreeterService) | Deactivating the Managed Greeter Component
INFO  | pool-19-thread-1                 | Thread shutting down
INFO  | vent: pid=ManagedGreeterService) | Deactivating the Managed Greeeter Service
INFO  | opt/karaf/apache-karaf-2.2.9/etc | Uninstalled /opt/karaf/apache-karaf-2.2.9/etc/ManagedGreeterService.cfg
Both services are shut down and the CFG is removed.

Updating at Run-Time
Now what happens when we change the configuration without shutting the components down? To find out lets update it. Issue the following command on the Karaf CLI:
config:edit ManagedGreeterService
config:propset salutation "Bonjour"
config:propset name "Sully"
config:update
Now lets go back and update the configuration with new values:
config:edit ManagedGreeterService
config:propset salutation "Bonjour"
config:propset name "Sully"
config:update
If we take a look at the log file we see that the components behaved in a very predictable manor. They were activated upon the initial configuration and then when the configuration changed the SCR was notified of the change and then proceeded to deactivate the ManagedGreeterComponent so it could deactivate and then reactivate the ManagedGreeterService with the new configuration. When completed the SCR called the activate on the ManagedGreeterComponent and we were off and running again.
INFO  | vent: pid=ManagedGreeterService) | Activating the Managed Greeeter Service
INFO  | vent: pid=ManagedGreeterService) | Activating the Managed Greeter Component
INFO  | pool-20-thread-1                 | Message 1: Hello Scott
INFO  | pool-20-thread-1                 | Message 2: Hello Scott
INFO  | opt/karaf/apache-karaf-2.2.9/etc | Installed /opt/karaf/apache-karaf-2.2.9/etc/ManagedGreeterService.cfg
INFO  | pool-20-thread-1                 | Message 3: Hello Scott
INFO  | pool-20-thread-1                 | Message 4: Hello Scott
INFO  | pool-20-thread-1                 | Message 5: Hello Scott
INFO  | vent: pid=ManagedGreeterService) | Deactivating the Managed Greeter Component
INFO  | pool-20-thread-1                 | Thread shutting down
INFO  | vent: pid=ManagedGreeterService) | Deactivating the Managed Greeeter Service
INFO  | vent: pid=ManagedGreeterService) | Activating the Managed Greeeter Service
INFO  | vent: pid=ManagedGreeterService) | Activating the Managed Greeter Component
INFO  | pool-21-thread-1                 | Message 1: Bonjour Sully
INFO  | pool-21-thread-1                 | Message 2: Bonjour Sully
INFO  | pool-21-thread-1                 | Message 3: Bonjour Sully
INFO  | pool-21-thread-1                 | Message 4: Bonjour Sully
INFO  | pool-21-thread-1                 | Message 5: Bonjour Sully

This cascading behavior of available dependencies allows our components to start and stop in a very predictable manor.

The Modified Life-cycle
In DS we have another lifecycle method that allows us to update the configuration of a component dynamically. It is referred to the "modified" life-cycle and we use the @Modified annotation to denote the method we choose to handle the modification. In our case we use the modified(Map properties) signature so the SCR knows to pass in the updated properties from the ConfigAdmin service. Here is the new code:
@Modified
public void modified(final Map<string> properties) {
    LOG.info("Modifying the " + COMPONENT_LABEL);

    // This time we really only need to make sure if it changed it isn't
    // empty
    if (properties.containsKey("salutation") && !properties.get("salutation").equals("")) {
        worker.setSalutation((String)properties.get("salutation"));
    }

    // Same for name
    if (properties.containsKey("name") && !properties.get("name").equals("")) {
        worker.setName((String)properties.get("name"));
    }
}
Before testing it out lets clean up our old configuration by issuing the config:delete ManagedGreeterService command at the Karaf CLI. Now if you are using the supplied example code you can uncomment the modified method, rebuild it and issue the update command on the Karaf CLI for the managed services bundle. Once that is done lets go back and issue the two different configuration update commands:
config:edit ManagedGreeterService
config:propset salutation "Bonjour"
config:propset name "Sully"
config:update
And then update the configuration with new values again:
config:edit ManagedGreeterService
config:propset salutation "Bonjour"
config:propset name "Sully"
config:update
Now lets take a look at our log to see how the components behaved:
INFO  | vent: pid=ManagedGreeterService) | Activating the Managed Greeeter Service
INFO  | vent: pid=ManagedGreeterService) | Activating the Managed Greeter Component
INFO  | pool-22-thread-1                 | Message 1: Hello Scott
INFO  | pool-22-thread-1                 | Message 2: Hello Scott
INFO  | opt/karaf/apache-karaf-2.2.9/etc | Installed /opt/karaf/apache-karaf-2.2.9/etc/ManagedGreeterService.cfg
INFO  | pool-22-thread-1                 | Message 3: Hello Scott
INFO  | pool-22-thread-1                 | Message 4: Hello Scott
INFO  | pool-22-thread-1                 | Message 5: Hello Scott
...
INFO  | vent: pid=ManagedGreeterService) | Modifying the Managed Greeeter Service
INFO  | pool-22-thread-1                 | Message 11: Bonjour Sully
INFO  | pool-22-thread-1                 | Message 12: Bonjour Sully
INFO  | pool-22-thread-1                 | Message 13: Bonjour Sully
INFO  | pool-22-thread-1                 | Message 14: Bonjour Sully
INFO  | pool-22-thread-1                 | Message 15: Bonjour Sully
Now this output should cause concern. Why? Because our components were never deactivated and threads were updated when the component was modified. We are no longer thread safe!

So what happened? Before when we only had the activate & deactivate method defined the activate & deactivate life-cycles were used to manage all updates of the component. This allowed our components to de/activate cleanly. When the component is configured with the modified life-cycle the SCR will only call the modified method which never causes the ManagedGreeterService to become UNSATISFIED. Therefore any component with a dependency on the ManagedGreeterService is never notified that there has been a change in the state of the component and they continue upon their merry way oblivious to the changes.
WRT thread safety, the same actually goes for our set/unset methods as well in the ManagedGreeterComponent. These methods along with the life-cycle methods are called by separate threads in the SCR. If you remember back in Part 1 in my Editorial Opinion, I touched on the importance of creating bind/unbind methods to allow our components to lock be thread safe. If you look at the ManagedGreeterComponent source code you will see where we make sure to wrap our service in lock blocks to ensure that it maintain thread safety.

That should give you a pretty good overview of Managed Services using DS in Karaf. In Part 4 of this series, we will take a look at using components to configure components use DS Factory components.

Next Article:
Part 4: Component Factories

Previous Articles:
Part 1: Getting Started
Part 2: The Basics

References:
Karaf
Felix File Install
OSGi 4.2 Specification
BND Annotations

Monday, September 10, 2012

Declarative Services with Karaf Part 2: The Basics

Now that you have had the chance to install the SCR Commands and the Basic Service Example lets start to look at the code that was executed. The code for the basic GreeterService example is on Github. Follow the steps below to retrieve and build it.

Source Checkout and Build
git clone https://github.com/sully6768/karaf-scr-examples.git
cd karaf-scr-examples
git fetch
mvn clean install
cd service

SCR POM

First lets examine what is required to make our build work. After changing to the service project open the pom.xml in your favorite editor. It is a standard Maven OSGi build configuration using the maven-bundle-plugin with the pom.xml packaging set to bundle. To use the the SCR annotations though we need to add the BND Library. We will also add the Felix SCR Library though in reality we don't need it to build in the case of the GreeterService as it sits. It is only required when your code needs to use the lower level SCR APIs which we will use as we get further along.

Maven Dependency Configuration
<dependencies>
    <!-- 
        Contains the SCR Annotations
     -->
    <dependency>
        <groupId>biz.aQute</groupId>
        <artifactId>bndlib</artifactId>
        <version>1.50.0</version>
    </dependency>
    <!-- 
        Contains the SCR binaries.  Only required 
        if you need the low level SCR APIs 
    <dependency>
        <groupId>org.apache.felix</groupId>
        <artifactId>org.apache.felix.scr</artifactId>
        <version>1.6.0</version>
    </dependency>
    -->
    <!-- 
        Snipped.  See example for full config
    -->
</dependencies>

Looking over the Maven Bundle Plugin there is a new addition to our configurations that will help create our SCR XML configuration for our bundle. It is the <Service-Component> element. This element tells the BND library to search through our source code and when the @Component annotation is found, create a new configuration for it.

Maven Bundle Plugin Configuration
<plugin>
    <groupId>org.apache.felix</groupId>
    <artifactId>maven-bundle-plugin</artifactId>
    <configuration>
        <instructions>
            <Service-Component>*</Service-Component>
        </instructions>
    </configuration>
</plugin>

SCR Sources

Our sources for SCR are annotated POJOs. In the case of the basic GreeterService example detailed below there are two types of Components defined: an Immediate Component (a service consumer) and a Delayed Component (a service provider).

First lets look at the GreeterService. GreeterService.java is a simple interface that provides a single method of invocation.

GreeterService.java
public interface GreeterService {
    void printGreetings();
}

The implementation for the GreeterService is found in GreeterServiceImpl.java.

GreeterServiceImpl.java
@Component
public class GreeterServiceImpl implements GreeterService {
    
    private static final Logger LOG = LoggerFactory.getLogger(GreeterServiceImpl.class);

    private String name = System.getProperty("user.name", "Scott ES");

    private String salutation = "Hello";

    public void printGreetings() {
        LOG.info(salutation + " " + name);
    }
}

This service provider is a very simple implementation that will print a greeting to the log upon activation. The key to this POJO is the inclusion of the @Component annotation at the top of implementation class. As the source code is parsed by BND, the annotations are then used to create the SCR configuration XML that is then included in the makes decisions by what is available as it parses the source code.

In this case the GreeterService is considered a Delayed Component. As BND parses the source code will first consider a Java class with @Component to be a Delayed Component if the class implements an interface. The containers SCR instance will then register the Component and not activate it until the service is required by a service consumer.

If your service needs to be realized immediately you can do so by adding the immediate attribute set to true on the @Component annotation. For instance if you want to activate a component that does implement an interface but isn't considered a service you will need to add this attribute.

Back in Part 1 you may remember that the GreeterService was in an Active state after it was installed.  This was due to there being an active consumer of the service in the container, the GreeterComponent. Since the GreeterComponent was in an Active state, the containers SCR instance created an instance of the GreeterService and injected into our GreeterComponent. To understand what happend lets take a look at GreeterComponent.java.

GreeterComponent.java
@Component(name = GreeterComponent.COMPONENT_NAME)
public class GreeterComponent {

    public static final String COMPONENT_NAME = "GreeterComponent";

    public static final String COMPONENT_LABEL = "Greeter Component";
    
    private static final Logger LOG = LoggerFactory.getLogger(GreeterComponent.class);

    private GreeterService greeterService;

    /**
     * Called when all of the SCR Components required dependencies have been
     * satisfied.
     */
    @Activate
    public void activate() {
        LOG.info("Activating the " + COMPONENT_LABEL);
        greeterService.printGreetings();
    }

    /**
     * Called when any of the SCR Components required dependencies become
     * unsatisfied.
     */
    @Deactivate
    public void deactivate() {
        LOG.info("Deactivating the " + COMPONENT_LABEL);
    }

    @Reference
    public void setGreeterService(final GreeterService greeterService) {
        this.greeterService = greeterService;
    }

    public void unsetGreeterService(final GreeterService greeterService) {
        this.greeterService = null;
    }
}

The GreeterComponent.java class is our service consumer class. It is annotated with the @Component annotation just like GreeterService but considered an Immediate Component. BND will configure GreeterComponent.java as an Immediate Component because it doesn't implement an interface. Therefore once all of its required dependencies are available this component will be activated.

Again, this can be overridden if you need to by adding the immediate attribute set to false on the @Component annotation.

The GreeterComponent also introduces 3 more annotations: @Activate, @Deactivate & @Reference.

The @Reference annotation is used to configure a dependency requirement for a component, in this case the GreeterService. As such the defaults will cause the GreeterComponent to remain deactivated if the GreeterService is not available.

When the GreeterService dependency becomes satisfied, the SCR service will call the configured activation method denoted by the @Activate annotation. Conversely if the dependency becomes unsatisfied post activation the SCR service will call the components configured deactivate method denoted by the @Deactivate annotation.

Running the Example

Open up your instance of Karaf where we installed the Karaf SCR Components in Part 1 so you can manipulate the example components. Once at the Karaf CLI, execute the scr:list command:

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

Both components are current active as all dependencies are satisfied.

What happens though when the GreeterService is deactivated?

karaf@root> scr:deactivate GreeterComponent 
karaf@root> scr:list 
   ID   State             Component Name
[-1  ] [DISABLED        ] GreeterComponent
[9   ] [REGISTERED      ] org.apache.karaf.scr.examples.service.impl.GreeterServiceImpl
karaf@root>

As you can see from above the GreeterComponent becomes unsatisfied.  If you review the log file it will show that the GreeterComponents deactivate method has also been called:

INFO  | Deactivating the GreeterService Component

Now that it is deactivated lets activate the GreeterService again using scr:activate GreeterComponent. Executing scr:list displays all components are now active.

karaf@root> scr:activate GreeterComponent
karaf@root> scr:list 
   ID   State             Component Name
[7   ] [ACTIVE          ] GreeterComponent
[9   ] [ACTIVE          ] org.apache.karaf.scr.examples.service.impl.GreeterServiceImpl
karaf@root>

The log file also shows that the GreeterComponent's activate method was called once its dependencies became satisfied.

INFO  | Activating the GreeterService Component
INFO  | Hello sully6768

Lets see the difference though when we deactivate the GreeterService:

karaf@root> scr:deactivate org.apache.karaf.scr.examples.service.impl.GreeterServiceImpl
karaf@root> scr:list 
   ID   State             Component Name
[11  ] [UNSATISFIED     ] GreeterComponent
[-1  ] [DISABLED        ] org.apache.karaf.scr.examples.service.impl.GreeterServiceImpl
karaf@root>

With the GreeterService now disabled the GreeterComponent becomes unsatisfied resulting in the GreeterComponent deactivate method being called.

Modifying and Running Your Own Example

Now that we have covered the basics feel free to review other options that are a part of the BND/OSGi Annotations to the example to see how SCR behaves in Karaf. By now, if you haven't used SCR before, I am sure you are starting to see the benefits and the possiblities. In Part 3 we will start looking at the easiest ManagedServices you have ever developed for OSGi.

Next Article:
Part 3: Managed Services

Previous Articles:
Part 1: Getting Started

References:
Maven Bundle Plugin: http://felix.apache.org/site/apache-felix-maven-bundle-plugin-bnd.html
BND: http://www.aqute.biz/Bnd/Components

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

Declarative Services with Karaf

Since I use OSGi Declarative Services (DS), the associated DS Annotations and some SCR Commands for Karaf that I developed (to be included in Karaf 2.3 & 3.0) for my example projects I figured I should have a primer on their use with some example SCR code.

Part 1: Getting Started
Part 2: The Basics
Part 3: Managed Services
Part 4: Component Factories

Enjoy!

Adding a Shell Alias to Karaf

Did you know you can add a shell alias to Karaf just like you can in your favorite bash shell? Its pretty simple.  Just follow the steps below to add ll (list): 

  • Navigate to your installation of Karaf
  • Open etc/shell.init.script
  • After the license header add the following:ll = { osgi:list $args } ;
Now restart and ll will be available to you at the shell.

There are already a number of available ones installed so take a look and see what works for you.

Thursday, September 6, 2012

Open-Source and the 80/20 Rule

I have any number of articles that I have drafted and not published.  Why, because sometimes it is cathartic to rant privately and get over it.  Sometimes though it needs to be said.  This is one of those times...

As a consultant, I typically work with organizations with very high system availability and resiliency requirements or SLAs.  These organizations are in the 20th or 10th or even the 1st percentile of market.  Enterprise organizations that are striving for some level of zero down time, immediate recovery and zero data loss on high-volume systems.  These same organizations are also starting to embrace Free and Open-Source Software (FOSS) to replace their current Commercial Off-The-Shelf (COTS) product.  And after they have completed 90% of their new project using FOSS I am typically called in and asked to solve the following: How do I make this "free" stuff meet my current SLA needs.

My answer is typically "you can't".

How did we get here?

It usually starts with a developer or architect that has been given the green light to develop a new application with FOSS.  They read articles and see documented capabilities that will help them avoid writing large amounts of code to gain the same functionality.  They download the product and run through some demos and see that bam, delivers as expected.  Then they start the prototype...

The prototype is done in a vacuum, many times on a desktop.  An environment that can in no way replicate the daily stress of a production environment.  Then this person demonstrates their prototype to management, extrapolates some numbers and gets green lighted.  And the project takes off.

Then after months of development they drop their newly minted product into a test environment and it doesn't come close to failing over fast enough or recovering fast enough or performing fast enough.  They tweek and nob-turn and then they call.

"This product is awful.  Come make this work!"

I typically arrive and find that there is little I can do for them in the short term.  You know, turn a nob and all is well.  Unfortunately the issue is really a misapplication of the capability or the capability just isn't working as expected.  So while it has shaved significant amounts of time off of the development cycle the capability is now under tremendous stress and cracks began to show.  Why did it work when it was in my prototype and not in production?  Typically it is because you are using a product that has been written by the masses, for the masses or the other 80 percent of the market.

That doesn't mean it won't work.  It is just important to keep in mind that FOSS projects are almost always on the bleeding edge of their given scope.  They are in a perpetual state of motion, with that motion being forward, and as new capabilities are added it takes time before they are fully baked.  Remember, someone out there with the greatest of intents and a genuine desire to help has added that handy new widget, one that you fully expect to make a living on.  Sometimes it is a single use-case, sometimes it is a full-blown API.  If it is a new capability, hopefully someone other than yourself needed it and went through the pains of hardening it for those in the 20th percentile.  If not, it is now up to you and/or me.  And you should never assume.

So how do you avoid this scenario?

Get Educated

Don't just read some articles and run through some demos.  Download the sources and familiarize yourself with the unit tests that cover the capability you were planning on using.  There are times you will find that what is being tested is not completely in line with what is documented.  Again, FOSS is in a constant state of motion so there are going to be times when what is on paper and what is in the codebase don't align.

Get Involved

Are all your use cases covered?  If not, write some and test it out.  Make sure it works the way you were expecting.  And when you are done, offer those test cases back to the community so others don't have to go through what you just did.  Also, with all those new test cases you have just written, if you find an issue report it and follow through.  The last part of that is so important.  I see so many people jump in and say they have an issue or open up a Jira ticket and then just disappear.  There is no indication as to whether the problem was solved or not.  I know it takes time but you chose to use the free product.  So don't be surprised when you are expected to give back.

Get Help

Finally, get those with experience involved early.  Don't be afraid to ask questions on the mailing lists.  You will get answers from a great many qualified folks who love to help.  Its in their nature.  They spend their free time writing software to give a way for free.  That being the case I bet they would love to sit and talk with you about it.

There are also commercial organizations that provide services and support for all sorts of FOSS products.  They have highly technical folks who are specialized in FOSS and how to get the best out of it.  Spending a week with one of them in the early stages of your application may save you many weeks or months of issues later.

Having worked with a great number of developers on open-source projects like ActiveMQ, Camel, CXF, ServiceMix and Karaf, I have gotten to know these folks and one thing should be understood, they are very good at what they do.  But there are only so many of them out there and so many use cases to cover.  They need you to be involved to deliver that first class quality product.

Besides it is in your own best interest.  Your application may be dependent on it.