Adobe Experience Manager Blog

AEM concepts, snippets and implementation

Tag Archives: Configuration Factory

DS annotations – Configuration Factory

2

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.

package blog.techrevel.service.impl;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Modified;
import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.Designate;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;
import org.slf4j.Logger;import org.slf4j.LoggerFactory;

import blog.techrevel.service.ConfigurationFactory;

@Component(service = ConfigurationFactory.class)
@Designate(ocd = ConfigurationFactoryImpl.Config.class, factory=true)
public class ConfigurationFactoryImpl implements ConfigurationFactory
{
    private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurationFactoryImpl.class);

    @ObjectClassDefinition(name = "Techrevel configuration factory")
    public @interface Config {
        @AttributeDefinition(name = "Content Consumer URL", defaultValue = "http://localhost:8081")
        String getContentConsumerUrl();
    }

    private String contentConsumerUrl;

    @Activate
    @Modified
    protected void activate(final Config config) {
        contentConsumerUrl = config.getContentConsumerUrl();
        LOGGER.info("Read the content Consumer Url : " + contentConsumerUrl);
    }

    @Override 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:

  • name=“The name of this reference.”
  • cardinality=”The cardinality of the service reference. This must be one of value from the enumeration ReferenceCardinality
    • AT_LEAST_ONE: The reference is mandatory and multiple.
    • MANDATORY: The reference is mandatory and unary.
    • MULTIPLE: The reference is optional and multiple.
    • OPTIONAL: The reference is optional and unary.
  • 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
  • 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 bindset or add, that is replaced withunbindunset 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.
package blog.techrevel.service.impl;
import java.util.ArrayList;
import java.util.List;

import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.slf4j.Logger;import org.slf4j.LoggerFactory;

import blog.techrevel.service.ConfigurationFactory;
import blog.techrevel.service.ConfigurationFactoryConsumer;
@Component(immediate = true, service = ConfigurationFactoryConsumer.class)
public class ConfigurationFactoryConsumerImpl implements ConfigurationFactoryConsumer {
    private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurationFactoryConsumerImpl.class);
    private List configurationList;
/**
    * Executed on Configuration Add event
    * @param config New configuration for factory
    */
    @Reference(name = "configurationFactory", cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)
    protected synchronized void bindConfigurationFactory(final ConfigurationFactory config) {
        LOGGER.info("bindConfigurationFactory: " + config.getContentConsumerUrl());
        if (configurationList == null) {
            configurationList = new ArrayList(); }
            configurationList.add(config);
        }
    /**
    * Executed on Configuration Remove event
    * @param config New configuration for factory
    */
    protected synchronized void unbindConfigurationFactory(final ConfigurationFactory config) {
        LOGGER.info("unbindConfigurationFactory: " + config.getContentConsumerUrl());
        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 !

Advertisements

Apache Felix – Configuration factory

0

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.