Skip and go to main content

Design & Technology August 03, 2018

Binding and Unbinding OSGi Services in AEM

Adwords fundamentals

In Adobe’s Experience Manager we have the ability to create OSGi components and services using only Java classes and Src annotations. This is one of AEM’s most powerful features that Java developers can leverage in order to achieve customization. We often create our own components that consume core services that are provided by AEM. Consuming these services can be done very efficiently using references.

Just like Spring framework and Google’s Guice it is possible to use dependency injection in AEM in order to acquire a reference to one or more services. The possibilities for this that are offered to us by the OSGi standards are quite numerous, in this blog I’d like to share the basics of using service references with you.

First, to create an OSGi component, simply use the @Component annotation on your class:

@Component
public class MyComponent

Your newly created component will not be activated automatically when it is not referenced by any other component. This is called delayed activation. To prevent delayed activation you can set the value of “immediate” in the component annotation to true.

@Component(immediate=true)

Referencing another component can be done though the usage of the reference annotation:

@Reference
private MyService myService;

Interfaces for OSGi Services

When using references you’ll need to add the service annotation to your component. You’ll also need to provide a service interface. Providing a service interface is not only good practice but also necessary for the binding process to work correctly. A service that may be referenced would look like this:

@Component
@Service
public class MyServiceImpl implements MyService

In this case the component implementation class is called MyServiceImpl, it’s interface is called MyService. The @Reference annotation will cause a lookup of a service with this exact interface name.

When your OSGi service implementation uses more than one interface each of these can be used to reference the service. You may also specify exactly which interfaces are used:

@Service(value={MyService.class, OtherInteface.class}

Targeting a service implementation

Referencing services using just the reference annotation and nothing more works perfectly for cases in which a service interface has only one implementation. But if a service has multiple implementations you can select a specific implementation by using a property filter:

@Reference(target = ”(type=http)”)
private MyService myService

This will make sure that the service implementation that has the property “type” set to “http” will be referenced:

@Component @Service @Properties( @Property(name = “type”, value = “http”) ) public class MyServiceImpl implements MyService

References in a List or Map

If you have more than one implementation of a service you may want to reference all of them in a list or map. By setting and implementing the bind and unbind methods you can store multiple references of the same service:

@Reference( referenceInterface = MyService.class, policy = ReferencePolicy.DYNAMIC, cardinality = ReferenceCardinality.MANDATORY_MULTIPLE, bind = “bindMyService”, unbind = “unbindMyService”) private Map<String, MyService> myServiceMap = new HashMap<String, MyService& protected void bindMyService(MyService myService, Map properties) { if (properties.containsKey(“type”)) { String type = properties.get(“type”).toString(); myServiceMap.put(type, myService); } } protected void unbindMyService(MyService myService) { myServiceMap.values().remove(myService); }

 

Notice that in the reference annotation the attribute “referenceInterface” has been set to the interface class. This is needed because we are now using the Map interface rather than the MyService interface for our class attribute.

Notice that in the bind method the first argument is a service implementation and the second argument is a map containing the properties of this implementation. This map will contain the property “type” and the value that has been assigned to it.

This setup will allow us to programmatically select one of the referenced services:

public void performAction(String type) { myServiceMap(type).action(); }

Questions? We are here to help!