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. Ifstatic
the component will be deactivated and re-activated if the service comes and/or goes away
- If
- 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 stringbind
.
- The default value is the name created by appending the reference
- 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 stringunbind
.
- The default value is the name created by appending the reference
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.