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
@JmxRunAsync
annotation 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 thetimeout
parameter 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
String
as 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
@Component
annotation defines the class as a managed bean with thesales_OrdersMBean
name. 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
@Authenticated
annotation, 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 thecatch
section. -
The method starts the transaction, loads the
Order
entity instance by identifier, and passes control to theOrderWorker
bean 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
MBeanExporter
instance in themap/entry
elements of thebeans
property. The key is JMX ObjectName, the value – the bean’s name specified in the@Component
annotation. 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).