April 27, 2020
Estimated Post Reading Time ~

Configuration Services for Multiple Sites through configurationFactory

Sometimes, we have to define configuration services that will differ only with configuration values. For e.g, we will have different sites that will use the same configuration service but with different configuration values specific to sites.

In this scenario, we have to create a site-specific configuration service for all the sites (multiple services) but OSGI provides the concept of ServiceFactories, the service factory can be used to create configuration services with the same set of properties and different values.

As an example let’s assume, we have two different sites that will use the same configuration service but require site-specific configuration values. The configurationFactory can be used to create a configuration service for different sites.

configurationFactory to create site-specific configurations and to retrieve the site-specific configuration properties.

import java.util.Dictionary;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.ConfigurationPolicy;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.service.cm.Configuration;
import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component(configurationFactory = true, policy = ConfigurationPolicy.REQUIRE, immediate = true, label = "Config Factory Service", description = "Global configuration Factory Service", metatype = true)
@Properties({ @Property(name = Constants.SERVICE_DESCRIPTION, value = "Common Configuration Factory Service") })
@Service(value = ConfigFactoryServiceImpl.class)
public class ConfigFactoryServiceImpl{

 private static final Logger LOG = LoggerFactory.getLogger(ConfigFactoryServiceImpl.class);

 private static ResourceResolverFactory resourceResolverFactory;
 private static BundleContext bundleContext;

 @Reference
 private ResourceResolverFactory resourceResolverFactoryInit;

 private static final String SERVICE_PID = "service.pid";

 private static final String DEFAULT_CONFIG = "DEFAULT";

 private static Map<String, String> svcPIDMap = new HashMap<String, String>();

 @Property(label = "Site Root Path", value = "DEFAULT", description = "Root path for site (e.g. - /content/sample).")
 public static final String SITE_ROOT_PATH = "siteRootPath";

 @Property(label = "Property1", value = "Property1: ", description = "Property1.")
 public static final String PROPERTY1 = "PROPERTY1";

 @Property(label = "Property2", value = "Property2: ", description = "Property2.")
 public static final String PROPERTY2 = "PROPERTY2";

 @Property(label = "Property3", value = "Property3: ", description = "Property3.")
 public static final String PROPERTY3 = "PROPERTY3";

 protected String getSiteRootPath() {
 return SITE_ROOT_PATH;
 }

 protected void activate(ComponentContext context) {
 try {
 bundleContext = context.getBundleContext();
 resourceResolverFactory = resourceResolverFactoryInit;
 // Get the current config
 Dictionary<?, ?> props = context.getProperties();
 // Save the service.pid to static map
 String servicePID = (String) props.get(SERVICE_PID);
 setServicePID(props, servicePID);
 } catch (Exception e) {

 }
 }

 private void setServicePID(Dictionary<?, ?> props, String servicePID) {
 String siteRootPath = (String) props.get(getSiteRootPath());
 if(!siteRootPath.equals("DEFAULT") && !siteRootPath.startsWith("/"))
 {
 siteRootPath="/"+siteRootPath;
 }
 if (!StringUtils.isEmpty(siteRootPath)) {
 svcPIDMap.put(siteRootPath, servicePID);

 }
 }

 public static String getConfig(HttpServletRequest request, String key) {
 return getConfig(request, null, key);
 }

 public static String getConfig(HttpServletRequest request, String uri,String key) {
 String property = null;
 Object configObj = null;
 try {
 configObj = getConfigObj(request, uri, key);
 } catch (Exception e) {

 }
 if (null != configObj) {
 property = configObj.toString();
 }
 return property;
 }

 public static Object getConfigObj(HttpServletRequest request,String pagePath, String key) {
 Configuration conf;
 String resourcePath = null;
 try {
 if (!("DEFAULT").equals(pagePath)) {
 resourcePath = getResourcePath(request, pagePath);
 conf = locateConfiguration(resourcePath);
 } else {
 conf = locateConfiguration(DEFAULT_CONFIG);
 }

 if (null != conf && null != conf.getProperties()) {
 Object obj = conf.getProperties().get(key);
 return obj;
 } else {
 throw new Exception("Could not find matching configuration");
 }
 } catch (Exception e) {

 }
 return null;
 }

 private static Configuration locateConfiguration(String resourcePath) {
 Configuration locatedConfig = null;
 try {
 String siteRootPath = getSiteRootPath(resourcePath);
 String svcPID = svcPIDMap.get(siteRootPath);
 ConfigurationAdmin bundleConfigAdmin = (ConfigurationAdmin) bundleContext.
 getService(bundleContext.getServiceReference(ConfigurationAdmin.class.getName()));
 locatedConfig = bundleConfigAdmin.getConfiguration(svcPID);
 } catch (Exception e) {

 }
 return locatedConfig;
 }

 protected static String getResourcePath(HttpServletRequest request,String pagePath) {
 String resourcePath = null;
 String uri = request.getRequestURI();
 ResourceResolver resourceResolver = null;
 try {
 resourceResolver = resourceResolverFactory.getResourceResolver(null);
 Resource resolvedResource;
 if (null == pagePath) {
 resolvedResource = resourceResolver.resolve(request, uri);
 } else {
 resolvedResource = resourceResolver.resolve(request, pagePath);
 }
 resourcePath = resolvedResource.getPath();
 } catch (Exception e) {

 } finally {
 if (null != resourceResolver) {
 resourceResolver.close();
 }
 }

 return resourcePath;
 }

 protected static String getSiteRootPath(String resourcePath) {
 if (StringUtils.isEmpty(resourcePath)) {
 return null;
 }

 if (resourcePath.equalsIgnoreCase(DEFAULT_CONFIG)) {
 return resourcePath;
 }

 String siteRootPath = null;
 String[] path = resourcePath.split("/");
 if (path.length > 2) {
 siteRootPath = "/" + path[1] + "/" + path[2];
 LOG.error("siteRootPath= "+siteRootPath);
 }

 return siteRootPath;
 }
}

After deploying the factory service, create the configuration for different sites e.g. /content/Sample1 and /content/Sample2) and also one for DEFAULT configuration by specifying the value for siteRootPath









Retrieving the properties:
String property1 = ConfigFactoryServiceImpl.getConfig(request, ConfigFactoryServiceImpl.PROPERTY1);

If we are using this in the Sample1 site, the property1 specific to the Sample1 site will be return.



If we are using this in the Sample2 site, the property1 specific to the Sample2 site will be returned.



Retrieving the properties by specifying the path:

For e.g to retrieve the properties from DEFAULT configuration

String property1 = ConfigFactoryServiceImpl.getConfig(request,”DEFAULT”, ConfigFactoryServiceImpl.PROPERTY1);



Retrieve site-specific properties.

String property1 = ConfigFactoryServiceImpl.getConfig(request,”/content/Sample1”, ConfigFactoryServiceImpl.PROPERTY1);


By aem4beginner

No comments:

Post a Comment

If you have any doubts or questions, please let us know.