Apache Felix – Configuration factory


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

If you looking for Configuration factories via new OSGi Annotations, then please visit link

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 ‘configurationFactory=true’ attribute to the Component annotation.

import java.util.Dictionary;

import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;

import org.apache.sling.commons.osgi.PropertiesUtil;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component(label = "Techrevel configuration factory", metatype = true, configurationFactory = true)
@Service(ConfigurationFactory.class)
public class ConfigurationFactory {
    private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurationFactory.class);

    @Property(label = "Content Consumer URL", value = "http://localhost:8081")
    private static final String CONTENT_CONSUMER_URL = "content.consumer.url";
    private String contentConsumerUrl;

    @Activate
    public void activate(ComponentContext componentContext) {
        Dictionary properties = componentContext.getProperties();
        contentConsumerUrl = PropertiesUtil.toString(properties.get(CONTENT_CONSUMER_URL), "");
        LOGGER.info("Read the content Consumer Url : " + contentConsumerUrl);
    }

    public String getContentConsumerUrl() {
        return contentConsumerUrl;
    }
}

Step 2: Consume factory’s configurations

This is the service which would act based on values configured via factory.

Step 2.1: To aggregate configurations values in a collection use @Reference annotation with following attributes:

  • referenceInterface=”name of the service interface/class”
  • cardinality=”The cardinality of the service reference. This must be one of value from the enumeration ReferenceCardinality
    • OPTIONAL_UNARY: (“0..1”) Optional, unary reference: No service required to be available for the reference to be satisfied. Only a single service is available through this reference.
    • MANDATORY_UNARY: (“1..1”) Mandatory, unary reference: At least one service must be available for the reference to be satisfied. Only a single service is available through this reference.
    • OPTIONAL_MULTIPLE: (“0..n”) Optional, multiple reference: No service required to be available for the reference to be satisfied. All matching services are available through this reference.
    • MANDATORY_MULTIPLE: (“1..n”) Mandatory, multiple reference: At least one service must be available for the reference to be satisfied. All matching services are available through this reference.
  • policy=”ReferencePolicy.DYNAMIC Or ReferencePolicy.STATIC”
    • 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
  • bind=”name of the method to be called when the service is to be bound to the component”
    • The default value is the name created by appending the reference name to the string bind.
  • unbind=”name of the method to be called when the service is to be unbound from the component”
    • The default value is the name created by appending the reference name to the string unbind.
import java.util.ArrayList;
import java.util.List;

import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.ReferencePolicy;
import org.apache.felix.scr.annotations.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component(immediate = true)
@Service(ConfigurationFactoryConsumer.class)
public class ConfigurationFactoryConsumer {
    private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurationFactoryConsumer.class);

    @Reference(referenceInterface = ConfigurationFactory.class, cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE, policy = ReferencePolicy.DYNAMIC)
    private List configurationList;

    //Aggregating new configutaion values in the collection
    protected synchronized void bindConfigurationFactory(final ConfigurationFactory config) {
        if (configurationList == null) {
            configurationList = new ArrayList();
        }
        configurationList.add(config);
    }

    //Removing deleted configuration values from the collection
    protected synchronized void unbindConfigurationFactory(final ConfigurationFactory config) {
        configurationList.remove(config);
    }
}

Step 2.2: Consume the configuration collection

The configurationList collection created in Step 2.1 can be accessed through various functions of ConfigurationFactoryConsumer class.

Access the collection and execute the business logic as needed. Happy Coding !

To access a specific configuration only, please refer to link.

Leave a comment