5.2.5.1. Creating a JMX Bean
The following example shows how to create a JMX bean.
-
JMX bean interface:
package com.sample.sales.core; import org.springframework.jmx.export.annotation.*; @ManagedResource(description = "Performs operations on Orders") public interface OrdersMBean { @ManagedOperation(description = "Recalculates an order amount") @ManagedOperationParameters({@ManagedOperationParameter(name = "orderId", description = "")}) String calculateTotals(String orderId); }-
The interface and its methods may contain annotations to specify the description of the JMX bean and its operations. This description will be displayed in all tools that work with this JMX interface, thereby helping the system administrator.
-
Optional
@JmxRunAsyncannotation is designed to denote long operations. When such operation is launched using the built-in JMX console, the platform displays a dialog with an indefinite progress bar and the Cancel button. A user can abort the operation and continue to work with the application. The annotation can also contain thetimeoutparameter that sets a maximum execution time for the operation in milliseconds, for example:@JmxRunAsync(timeout = 30000) String calculateTotals();If the timeout is exceeded, the dialog closes with an error message.
WarningPlease note, that if an operation is cancelled or timed out on UI, it still continue to work in background, i.e. these actions do not abort the actual execution, they just return control back to the user.
-
Since the JMX tools support a limited set of data types, it is desirable to use
Stringas the type for the parameters and result of the method and perform the conversion inside the method, if necessary. Alongside withString, the following parameter types are supported:boolean,double,float,int,long,Boolean,Integer.
-
-
The JMX bean class:
package com.sample.sales.core; import com.haulmont.cuba.core.*; import com.haulmont.cuba.core.app.*; import com.sample.sales.entity.Order; import org.apache.commons.lang.exception.ExceptionUtils; import org.springframework.stereotype.Component; import javax.inject.Inject; import java.util.UUID; @Component("sales_OrdersMBean") public class Orders implements OrdersMBean { @Inject protected OrderWorker orderWorker; @Inject protected Persistence persistence; @Authenticated @Override public String calculateTotals(String orderId) { try { try (Transaction tx = persistence.createTransaction()) { Order entity = persistence.getEntityManager().find(Order.class, UUID.fromString(orderId)); orderWorker.calculateTotals(entity); tx.commit(); }; return "Done"; } catch (Throwable e) { return ExceptionUtils.getStackTrace(e); } } }The
@Componentannotation defines the class as a managed bean with thesales_OrdersMBeanname. The name is specified directly in the annotation and not in the constant, since access to the JMX bean from Java code is not required.Lets overview the implementation of the
calculateTotals()method.-
The method has the
@Authenticatedannotation, i.e., system authentication is performed on method entry in the absence of the user session. -
The method’s body is wrapped in the try/catch block, so that, if successful, the method returns "Done", and in case of error – the stack trace of the exception as string.
In this case, all exceptions are handled and therefore do not get logged automatically, because they never fall through to
MBeanInterceptor. If logging of exceptions is required, the call of the logger should be added in thecatchsection. -
The method starts the transaction, loads the
Orderentity instance by identifier, and passes control to theOrderWorkerbean for processing.
-
-
The registration of the JMX bean in
spring.xml:<bean id="sales_MBeanExporter" lazy-init="false" class="com.haulmont.cuba.core.sys.jmx.MBeanExporter"> <property name="beans"> <map> <entry key="${cuba.webContextName}.sales:type=Orders" value-ref="sales_OrdersMBean"/> </map> </property> </bean>All JMX beans of a project are declared in one
MBeanExporterinstance in themap/entryelements of thebeansproperty. The key is JMX ObjectName, the value – the bean’s name specified in the@Componentannotation. ObjectName begins with the name of the web application, because several web applications, which export the same JMX interfaces, can be deployed into one application server instance (i.e., into one JVM).