April 10, 2020
Estimated Post Reading Time ~

Creating your Custom OSGi configuration

We all know that AEM works on Apache Felix which is an implementation of OSGi. OSGi provides a way to manage bundles and configurations.

You can find all the Out of the box OSGi configurations at - http://<host>:<port>/system/console/configMgr. Apart from out of the box configurations, we can also create our custom configurations. In this post, we will be creating a custom out of the box configuration which reads the user input and gets the JSON response from a web service.

Code in Action

  • To make a custom OSGi configuration, we need to first create an interface whose public methods will represent the fields in the configuration. 
  • Create an interface named HttpConfiguration and paste the following code in it.

package org.redquark.demo.core.services;

import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.AttributeType;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;
import org.osgi.service.metatype.annotations.Option;

/**
 * @author Anirudh Sharma
 * 
 * This interface represents an OSGi configuration which can be found at - 
 * ./system/console/configMgr
 */
@ObjectClassDefinition(
 name = "Http Configuration",
 description = "This configuration reads the values to make an HTTP call to a JSON webservice")
public @interface HttpConfiguration {

 /**
  * This is a checkbox property which will indicate of the configuration is
  * executed or not
  * 
  * @return {@link Boolean}
  */
 @AttributeDefinition(
  name = "Enable config",
  description = "This property indicates whether the configuration values will taken into account or not",
  type = AttributeType.BOOLEAN)
 public boolean enableConfig();

 /**
  * This method returns the protocol that is being used
  * 
  * @return Protocol
  */
 @AttributeDefinition(
  name = "Protocol",
  description = "Choose Protocol",
  options = {
   @Option(label = "HTTP", value = "http"),
   @Option(label = "HTTPS", value = "https")
  })
 public String getProtocol();

 /**
  * Returns the server
  * 
  * @return {@link String}
  */
 @AttributeDefinition(
  name = "Server",
  description = "Enter the server name")
 public String getServer();

 /**
  * Returns the endpoint
  * 
  * @return {@link String}
  */
 @AttributeDefinition(
  name = "Endpoint",
  description = "Enter the endpoint")
 public String getEndpoint();
}
  • This configuration has a checkbox Enable Config, a drop-down Protocol, two text fields Server, and Endpoint.
  • Now create an interface HttpService to make the http call as below

package org.redquark.demo.core.services;

/**
 * @author Anirudh Sharma
 * 
 * This interface exposes the functionality of calling a JSON Web Service
 */
public interface HttpService {

 /**
  * This method makes the HTTP call on the given URL
  * 
  * @param url
  * @return {@link String}
  */
 public String makeHttpCall();
}
  • Create an implementation class HttpServiceImpl as below.

package org.redquark.demo.core.services.impl;

import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.metatype.annotations.Designate;
import org.redquark.demo.core.services.HttpConfiguration;
import org.redquark.demo.core.services.HttpService;
import org.redquark.demo.core.utils.Network;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author Anirudh Sharma
 * 
 * Implementation class of HttpService interface and this class reads values from the OSGi configuration as well
 */
@Component(service = HttpService.class, immediate = true)
@Designate(ocd = HttpConfiguration.class)
public class HttpServiceImpl implements HttpService {

 /**
  * Logger
  */
 private static final Logger log = LoggerFactory.getLogger(HttpServiceImpl.class);

 /**
  * Instance of the OSGi configuration class
  */
 private HttpConfiguration configuration;

 @Activate
 protected void activate(HttpConfiguration configuration) {
  this.configuration = configuration;
 }

 /**
  * Overridden method of the HttpService
  */
 @Override
 public String makeHttpCall() {

  log.info("----------< Reading the config values >----------");

  try {

   /**
    * Reading values from the configuration
    */
   boolean enable = configuration.enableConfig();
   String protocol = configuration.getProtocol();
   String server = configuration.getServer();
   String endpoint = configuration.getEndpoint();

   /**
    * Constructing the URL
    */
   String url = protocol + "://" + server + "/" + endpoint;

   /**
    * Make HTTP call only if "enable" is true
    */
   if (enable) {
    /**
     * Making the actual HTTP call
     */
    String response = Network.readJson(url);

    /**
     * Printing the response in the logs
     */
    log.info("----------< JSON response from the webservice is >----------");
    log.info(response);

    return response;

   } else {

    log.info("----------< Configuration is not enabled >----------");

    return "Configuration not enabled";
   }

  } catch (Exception e) {

   log.error(e.getMessage(), e);

   return "Error occurred" + e.getMessage();
  }
 }

}
  • This is an OSGi component in which we are reading values from the OSGi configuration. Notice that we are using @Designate annotation to link this class to the configuration.
  • Now create a simple Sling Servlet to use this component as follows.

package org.redquark.demo.core.servlets;

import javax.servlet.Servlet;

import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.servlets.HttpConstants;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.redquark.demo.core.services.HttpService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author Anirudh Sharma
 * 
 * This method makes an HTTP call and read the value from the JSON webservice via an OSGi configuration
 *
 */
@Component(service = Servlet.class, property = {
 Constants.SERVICE_DESCRIPTION + "=HTTP servlet",
 "sling.servlet.methods=" + HttpConstants.METHOD_GET,
 "sling.servlet.paths=" + "/bin/demo/httpcall"
})
public class HttpServlet extends SlingSafeMethodsServlet {

 /**
  * Generated serialVersionUid
  */
 private static final long serialVersionUID = -2014397651676211439 L;

 /**
  * Logger
  */
 private static final Logger log = LoggerFactory.getLogger(HttpServlet.class);

 @Reference
 private HttpService httpService;

 /**
  * Overridden doGet() method
  */
 @Override
 protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) {

  try {

   String jsonResponse = httpService.makeHttpCall();

   /**
    * Printing the json response on the browser
    */
   response.getWriter().println(jsonResponse);

  } catch (Exception e) {

   log.error(e.getMessage(), e);
  }
 }

}
  • Go to the ./system/console/configMgr and search for Http Configuration and open it and configure it accordingly. Then save.
OSGi Configuration
[{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}, {"userId": 1, "id": 2, "title": "quis ut nam facilis et officia qui", "completed": false}, {"userId": 1, "id": 3, "title": "fugiat veniam minus", "completed": false}, {"userId": 1, "id": 4, "title": "et porro tempora", "completed": true}, ...]



By aem4beginner

No comments:

Post a Comment

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