Showing posts with label JMX. Show all posts
Showing posts with label JMX. Show all posts

Thursday, July 30, 2020

JMX in AEM

We can invoke/consume a custom service in AEM in many ways. One way of calling it is via JMX MBean. With the JMX we can invoke any piece of code on demand by just a click on the invoke button. Also, we can pass as many parameters as required to be used inside our code. In this blog, we will create a custom JMX to call a service that simply prints a confirmation in the log.

I have already created a TestService interface and TestServiceImpl class which have only one method and it just prints a confirmation in the logger. Our JMX class will call the method in the service class and eventually the confirmation will be printed on the invoke of JMX. To Begin let's create a TestJMX interface:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
package org.autopace.core.jmx;

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

@Description("Test JMX for Autopace")
public interface TestJMX {

 @Description("Trigger Test Service")
 String triggerTestService(@Name("anyParameter") @Description("This is any parameter which we need as Input.") String anyParameter);

 @Description("Test Flag")
 String getFlag();

}

In the above code, we have used @Description annotation on top of interface TestJMX and for both the methods in the interface. This is used to give a better understanding to the authors of what each method does and what JMX does as a whole. Further, if there are any parameters which are required for any method then we can pass then with the help of @Name annotation and better description can be added with @Description annotation as done in the line:

String triggerTestService(
@Name("anyParameter") @Description("This is any parameter which we need as Input.") String any parameter);

This is how it looks to the authors who are trying to invoke the JMX:



Next, we need to create the implementation class for our JMX, let's have a look at the below code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package org.autopace.core.jmx;

import javax.management.NotCompliantMBeanException;

import org.autopace.core.services.TestService;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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


@Component(property = {"jmx.objectname=org.autopace.core.jmx:type=AutoPaceTestJMX", "pattern=/.*" })
public class TestJMXImpl extends AnnotatedStandardMBean implements TestJMX {

 public TestJMXImpl() throws NotCompliantMBeanException {
  super(TestJMX.class);
 }

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

 @Reference
 private TestService testService;

 boolean flag;

 @Override
 public String triggerTestService(String anyParameter) {

  if (flag) {
   LOG.info("Service is already Running");
   return "Service already Running";
  }

  try {
   LOG.info("Triggering Test Service via JMX");
   testService.printInLog(anyParameter);
   return "Test Service Successfully Triggered via JMX.";
  } catch (Exception e) {
   LOG.error("Some Exception occured while triggereing Test Service via JMX", e);
  } finally {
   flag = false;
  }

  return "Something went wrong while triggering Test Service via JMX.";
 }

 @Override
 public String getFlag() {
  if (flag) {
   return "Service is already running.";
  }
  return "Service is not running, we can invoke the triggerTestService Method";
 }

}

To register the JMX, I have used @Component annotation with two properties in which jmx.objectname=org.autopace.core.jmx: AutoPaceTestJMX is the name that will come in the JMX console.

Also, we have extended AnnotatedStandardMBean and created a public constructor that throws NotCompliantMBeanException.

Next, I used the @Reference annotation to use the TestService methods. Now we have implemented both the methods which we have created in TestJMX. The first method is used to trigger the TestService triggerTestService(String anyParameter) method and the second one is just a flag which tells us if the JMX service is currently invoked or not.

To clarify, let's say if we invoked a JMX and the service takes half an hour to complete. Now, we do not have any option to restrict the invoke button in between and authors can click on invoke multiple times. To prevent this scenario, we have created a flag that is set to true as soon as the jmx is invoked and it only returns to false once the service is complete. Hence, if anyone clicks on the invoke again while service is running, the flag will be true and the service method will not be called, and in our case "Service already Running" will be printed.

The getter for the flag is our second method. This is helpful when an author lands to jmx console. Based on this flag, authors can check if the service is currently active or not. Also, if we add a getter method, the variable comes under Attributes and we do not need to invoke any method to check the value. Simply landing on the JMX console will print the getter value.

If a method is added to JMX, then it comes under operations and we can invoke the methods and can pass any parameters as per requirement.

Once we have the TestJMX and TestJMXImpl ready, we need to deploy the build and follow the below steps to invoke the JMX:

Step 1: Login to <Host>:<Port>/system/console/jmx.

Step 2: Search for the JMX Name used while registering JMX. In our case, it is AutoPaceTestJMX.




Step 3: Click on the AutoPaceTestJMX, it will show you the attributes and operations available. Check the flag value to see if any method is invoked or not. If nothing is active, click on any method to invoke it.



Step 4: Now, we have an option to pass any parameter while invoking the method. Pass any parameter and click on invoke. Once the service, will be completed, it will return us "Test Service Successfully Triggered via JMX." as coded in our TestJMXImpl.



In our case, the Method in TestService simply prints an info log with the parameter passed. If you have a similar service, you can verify your execution in logs.

In this way, we can write a JMX which can help in execution of any piece of code on demand. One use case would be to write a JMX to trigger a service which is usually triggered via Scheduler. JMX will help in giving authors the flexibility and they do not need to change the cron expression everytime.

Contact Form

Name

Email *

Message *

Latest Post

Memory Management in JAVA

One of the most important features of Java is its memory management. Since Java uses automatic memory management, it becomes superior to tho...

Popular Posts