While the Apache Felix Maven SCR Plugin is a great tool (see below), for developing OSGi components using Declarative Services you should use the official annotations from the OSGi R6 specification. The development of the Apache Felix SCR Plugin is in maintenance mode.

The examples and dependencies have been verified on AEM 6.3 Instance

Maven dependency changes:

In order to use the new OSGi annotations, we need to add following dependencies to pom.xml.

For a project upgrading from Felix to DS annotations, you can remove following:

All Felix dependencies. Example:

org.apache.felix.scr.annotations

biz.aQute.bnd

Plugins

maven-scr-plugin: is required to resolve felix annotations at build time

Code changes:

You can choose to update java files at once, or one-by-one.

Incase you wish to modify all files together, then remove felix dependencies and plugins. The IDE would now recognize all the files that need modifcation.

However, if you wish to change files one-by-one, then you can keep both DS and Felix dependencies in pom.xml. A bundle with both types of annotations would still be good. Once all the code changes are done, you should remove all felix dependencies.

How to identify the changes:

You can easily identify the files, by looking for package imports of “org.apache.felix.scr.annotations.*”.

We would be using the following packages instead:

org.osgi.service.component.annotations.*

org.osgi.service.metatype.annotations.*

For more details on code changes involved, please visit the specific links:

name: The name would help you search the configuration in OSGi’s configuration manager.

Add @Designate to the Component that would consume the configurations. The ocd attribute should refer to the Configuration interface created in Step-2.

Declare properties that you would like to configure via @AttributeDefinition

Following image maps annotation attributes with the OSGi UI.

Please note that there are 2 ways to define default values:

defaultValue attribute of @AttributeDefinition: The value is displayed to the user, when he/she tries to configure the interface via Configuration manager. OSGi will NOT pick this default value, if no Configuration exists. Thus, when you install a bundle, the output would appear as:

Specifying default value in variable declarartion: The value is displayed to the user, when he/she tries to configure the interface via Configuration manager. OSGi will pick this default value, even if no Configuration exists.

Also, note that we no longer need PropertiesUtil to resolve OSGi configurations. 🙂

Notes:

Via Declarative Services, the number of annotations have been reduced. For example: @Component annotation is used for:

Component

Service

Servlet

Filter etc..

All of the above can be created by utilizing attributes of @Component details. More details are available on specific links

Multiple Service Implementation can be used to define multiple implementations of a Service, and then execute all/specific implementation depending on the use-case.

A close example would be Replication Agents. Here a specific replication implementation (Static Agent, Default Agent, Custom Transport Handler/Builders etc) is called, depending on the configuration.

Lets construct a multiple service implementation via an Example.

Scenario:

Consider an online course website. A lecturer can publish his content by submitting a course bundle comprising of html pages, videos and assessment questions.

While the bundle is processed, each content type is to be dealt with specific import-service implementation:

Page import

Video import

Assessment import

Lets get started with the implementation !!!

Create multiple service implementation

The implementation can be divided into 3 simple steps:

Create an interface which each of Service implementation would implement.

Implement concrete service implementations

A handler which would hold list of service implementation & execute relevent implementation.

Step 1: Interface which each service implementation would implement

The interface would comprise of abstract methods which:

would execute business logic for each service.

allow identification of best service to process current use-case.

Sample interface for the course import scenario:

package blog.techrevel.service;
public interface CourseImport {
//Import pages, videos and assessment
public abstract void importContent();
//Identify the service which would be able to process current file
public abstract boolean canProcess(String fileName);
}

Step 2: Implement concrete service implementations

Here we would be create multiple content import implementation to deal specifically with each content type. Example:

If dynamic the service will be made available to the component as it comes and goes.

If static the component will be deactivated and re-activated if the service comes and/or goes away

unbind=”name of the method to be called when the service is to be unbound from the component”

To declare no unbind method, the value "-" must be used.

If not specified, the name of the unbind method is derived from the name of the annotated bind method. If the annotated method name begins with bind, set or add, that is replaced withunbind, unset or remove, respectively, to derive the unbind method name. Otherwise, un is prefixed to the annotated method name to derive the unbind method name. The unbind method is only set if the component type contains a method with the derived name.

OSGi provides many modular features which enhances a developer’s implementation experience. Current blog focuses on one such feature: Configuration Factories via new OSGi Annotations

The concept is similar to logging configuration in AEM, where we define multiple configurations for different loggers, but the service implementation stays the same. Thus, multiple configuration, single implementation.

Create and access a configuration factory

It takes just two steps to create and use a Configuration factory.

Step 1: Create Configuration factory

This is achieved by adding ‘factory=true’ attribute to the Component annotation.

If dynamic the service will be made available to the component as it comes and goes.

If static the component will be deactivated and re-activated if the service comes and/or goes away

unbind=”name of the method to be called when the service is to be unbound from the component”

To declare no unbind method, the value "-" must be used.

If not specified, the name of the unbind method is derived from the name of the annotated bind method. If the annotated method name begins with bind, set or add, that is replaced withunbind, unset or remove, respectively, to derive the unbind method name. Otherwise, un is prefixed to the annotated method name to derive the unbind method name. The unbind method is only set if the component type contains a method with the derived name.