Create a configurable OSGI Service

OSGI is a key technology on Adobe AEM’s stack. AEM uses Apache Felix as its OSGI container.

In this post we will show how to create a Configurable OSGI Service on Apache Felix. A configurable service allows to manage its properties through Apache Felix Web Console.

In this example we will use Adobe AEM 6.0, Eclipse as IDE with the AEM Developer Tools for Eclipse, it provides a wizard to create a maven project using the aem archetype. You can find a good tutorial on How to create a new project using the wizard in the plugin’s page.

When we create a new project using the wizard it creates a multimodule maven project. In this example we will use only the core module, it is the module that we will use to develop our bundle.

To create our services we will use the Apache Felix SCR Annotations.

In this example we going to create an OSGI service that retrieves data from an external service. The endpoint for this service will be configured through the Web Console.

Let’s start.

Declaring the Service

To create an OSGI service we need to have an interface, you can see it below:

package com.xicojunior.xicojuniorexample.core; public interface XicoService { public String getData(); }

Once you have the interface, we need to create our service, for that we are going to use two annotations:

@Service

and

@Component

The class will be like this:

@Component(immediate=true, label="Xico Service", description="This is a Service")
@Service(value=XicoService.class)
public class XicoServiceImpl implements XicoService {

    @Override
    public String getData() {
        // TODO Auto-generated method stub
        return null;
    }
}

To deploy it we would need to use only the core module, but as it deploys it through the repository, we need to have the path created on the repository. So for the first deploy we will deploy both the apps, ui and content modules. For that we wil use the following goals and profile on the parent module:

mvn clean install -PautoInstallPackage

For the next deploys we will use only the core module, and the autoInstallBundle profile.

After the deploy, we can check if the bundle and the service on the Felix Web Console, that can be accesed using this url http://localhost:4502/system/console/services. We can see a screenshot below:

Console

Now we need to declare the properties of the service, we can do this using the annotation:

@Property

We will declare a constant with the property key, and a default value, and a field that will store the property value:

@Property(value="http://companyservices/myservice?wsdl")
static final String SERVICE_ENDPOINT_URL = "service.endpoint.url";

private String serviceEndpointUrl;

When we deploy the bundle again, we will see that now it displays the property name and value we just declared.

Let’s add the an acivate method that will be triggered when the service is activated, inside this method we will retrieve the property value. For this do we annotate a method with:

@Activate

An example can be seen below:

@Activate
public void activate(final Map<String, Object> props) {
    System.out.println("Calling Activate Method");
    this.serviceEndpointUrl = (String)props.get(SERVICE_ENDPOINT_URL);
    System.out.println("ServiceEndpointUrl:" + this.serviceEndpointUrl);
}

Now in order to make this service configurable, we just need to set the component annotation to metatype=true, when we add that and deploy the bundle again, we can see the service in the Configuration page http://localhost:4502/system/console/configMgr.

We can see the annotation below:

@Component(immediate=true, label="Xico Service", description="This is a Service", metatype=true)

After deploying, we can see the service in the configuration link, and we have a console that we can set property value, as we can see below:

Console

To test that let’s create a Sling servlet to call the service we created, we changed the method getData to just return the serviceEndpointUrl field.

The Servlet can be seen below:

package com.xicojunior.xicojuniorexample.core.servlets;

import java.io.IOException;

import javax.servlet.ServletException;

import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.sling.SlingServlet;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;

import com.xicojunior.xicojuniorexample.core.XicoService;

@SuppressWarnings("serial")
@SlingServlet(paths="/services/xicojunior/testservice", methods="GET")
public class TestServiceServlet extends SlingAllMethodsServlet{

    @Reference
    XicoService xicoService;

    @Override
    protected void doGet(SlingHttpServletRequest request,
            SlingHttpServletResponse response) throws ServletException,
            IOException {
        response.getWriter().write(xicoService.getData());
    }

}

To test the servlet we can just use this url: http://localhost:4502/services/xicojunior/testservice.

You can find the complete code for this example in the github repository.

I hope you enjoyed it. See you on the next post;

comments powered by Disqus