April 10, 2020
Estimated Post Reading Time ~

Creating JMX MBeans in AEM

Java Management Extensions (JMX) is a Java technology that provides an architecture to manage resources dynamically at runtime. JMX is used mostly in enterprise applications to make the system configurable or to get the state of the application at any point in time. Those resources are represented by objects called MBeans (for Managed Bean).

In AEM also, sometimes we need to use this architecture to manage resources dynamically. Although AEM provides a rich set of out of the box MBeans, we also create our own MBeans as and when required.

In this post, we will be creating an MBean that will take a set of input parameters and return the status of all the bundles/services/components in the AEM instance in a JSON format.

Let us look at the steps of creating such an MBean.

Create an MBean

  • The first step is to create the layout of our MBean. By layout, I mean the input parameters that the MBean requires to function.
  • All the parameters are specified by the specified parameters. In our case, we need the server's hostname, port number and the entity which we want to examine (bundles/services/components).
  • Create an interface named SystemInfo and paste the following code in it
package org.redquark.demo.core.jmx;

import com.adobe.granite.jmx.annotation.Description;

/**
 * @author Anirudh Sharma
 * 
 * This interface exposes the input parameter for the MBean
 */
@Description("Input parameters for getting the System information")
public interface SystemInfo {

 @Description("Enter the protocol, hostname, and port of the server")
 String getBundles(String protocol, String hostName, String port);

 @Description("Enter the protocol, hostname, and port of the server")
 String getComponents(String protocol, String hostName, String port);

 @Description("Enter the protocol, hostname, and port of the server")
 String getServices(String protocol, String hostName, String port);
}
  • Here we have three methods that take host, port, and protocol and gives us the JSON response of the bundles, services, and components
  • Now let us create the implementation class of the SystemInfo interface and paste the following code in it
package org.redquark.demo.core.jmx;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;

import javax.management.DynamicMBean;
import javax.management.NotCompliantMBeanException;

import org.apache.commons.codec.binary.Base64;
import org.osgi.service.component.annotations.Component;
import org.redquark.demo.core.utils.Network;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.adobe.granite.jmx.annotation.AnnotatedStandardMBean;

/**
 * @author Anirudh Sharma
 * 
 * Implementation class for the MBean
 */
@Component(immediate = true, service = DynamicMBean.class, property = {
 "jmx.objectname = org.redquark.demo.core.jmx:type=System Info MBean"
})
public class SystemInfoImpl extends AnnotatedStandardMBean implements SystemInfo {

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

 /**
  * Parameters to read user input
  */

 public SystemInfoImpl() throws NotCompliantMBeanException {
  super(SystemInfo.class);
 }

 @Override
 public String getBundles(String protocol, String hostname, String port) {

  log.info("Logging the bundles in JSON");

  String url = protocol + "://" + hostname + ":" + port + "/system/console/bundles/.json";

  String result;

  if (protocol.equalsIgnoreCase("http")) {
   result = makeHttpCall(url);
  } else {
   result = Network.readJson(url);
  }
  return result;
 }

 @Override
 public String getComponents(String protocol, String hostname, String port) {

  log.info("Logging the components in JSON");

  String url = protocol + "://" + hostname + ":" + port + "/system/console/components/.json";

  String result;

  if (protocol.equalsIgnoreCase("http")) {
   result = makeHttpCall(url);
  } else {
   result = Network.readJson(url);
  }
  return result;
 }

 @Override
 public String getServices(String protocol, String hostname, String port) {

  log.info("Logging the services in JSON");

  String url = protocol + "://" + hostname + ":" + port + "/system/console/services/.json";

  String result;

  if (protocol.equalsIgnoreCase("http")) {
   result = makeHttpCall(url);
  } else {
   result = Network.readJson(url);
  }
  return result;
 }

 private String makeHttpCall(String requestURL) {

  URL url;
  try {
   url = new URL(requestURL);
   URLConnection uc;
   uc = url.openConnection();

   uc.setRequestProperty("X-Requested-With", "Curl");

   String userpass = "admin" + ":" + "admin";
   String basicAuth = "Basic " + new String(new Base64().encode(userpass.getBytes()));
   uc.setRequestProperty("Authorization", basicAuth);

   BufferedReader reader = new BufferedReader(new InputStreamReader(uc.getInputStream()));
   StringBuilder builder = new StringBuilder();
   String line = null;
   while ((line = reader.readLine()) != null) {
    builder.append(line);
    builder.append(System.getProperty("line.separator"));

   }
   String result = builder.toString();

   return result;

  } catch (IOException e) {
   e.printStackTrace();
  }

  return "";
 }
}
  • Here we are registering this class of service DynamicMBean which exposes a dynamic management interface. We are using property jmx.objectname which defines the name of our MBean. We are reading the passed parameters and creating an appropriate URL to get the JSON response.
  • Now deploy the code and navigate to http://<host>:<port>/system/console/jmx. There you will see all the registered MBean. Search for your MBean.
System Info MBean
  • Open the MBean, you will see three methods each for bundles, components, and services.
  • Open the getBundles() methods, and configure it. After clicking on invoke, you will see the JSON response returned.
JSON Response returned


By aem4beginner

No comments:

Post a Comment

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