Using JMX to Manage Web Applications

The Java Management Extensions (JMX) standard is gaining adoption within the J2EE community for the management of applications, as well as application servers and other infrastructure software. JMX makes it possible to manage and monitor applications using a choice of management systems and consoles, including SNMP consoles.

Introduction

The Java Management Extensions (JMX) standard is gaining adoption within the J2EE community for the management of applications, as well as application servers and other infrastructure software. JMX makes it possible to manage and monitor applications using a choice of management systems and consoles, including SNMP consoles. It also simplifies the task of making applications manageable, i.e. management instrumentation, and enables improved management of deployed applications in the enterprise.

Despite this growing adoption however, application developers often do not realize the benefits of application management and JMX. In many development projects, application management is an afterthought, which results in deployed applications being largely unmanaged. This may result in operational difficulties and missed opportunities to derive additional business value from management. In the past there was good reason for this, as management instrumentation was too much effort for application developers. However, now management with JMX is considerably simpler and can provide a lot of management value with little effort.

This article takes a closer look at how JMX could be used for the management of web applications. Using a simple example application with a set of JSP pages, it illustrates how JMX can be used to manage application-specific data and provide good visibility into how the application is operating in production. We look beyond basic monitoring, for which automated JMX-based tools are now available. While there is clearly value in monitoring application availability and performance, our examples focus on business-specific management of the web application. This kind of business-specific management can often result in adding tangible business value for production applications.


Managing Business Applications with JMX

The primary driver for application management is business productivity and efficiency goals. Enterprises deploying J2EE applications are often using these applications to drive their business processes. Since the goal of these J2EE applications is often to enable efficient business operations, managing these applications provides visibility into how the applications are impacting operations and shows ways to improve productivity and efficiency.

The first step in managing applications is monitoring availability and performance. In order to minimize downtime, and avoid disruption to business operations, there is a clear need to monitor and measure the availability of applications. In addition, the performance of the application as measured by key business methods or user transactions needs to be tracked. This helps ensure the application performs to the service levels needed, and enables pro-active and rapid response if the application is under-performing.

Beyond monitoring availability and performance, managing business-specific aspects of the application can be helpful in maximizing productivity. For example, a banking application may require the ability to monitor cash withdrawals to ensure sufficient cash at a required ATM or branch office. Another example is the need to monitor inventory levels for an on-line store. While some of these management needs may be anticipated and designed into the application, many of these needs arise from production use of the application. It's hard to change the application software at that point. This is where business-specific application management can be very useful.

JMX is an emerging standard for application management in the Java and J2EE world. The JMX architecture, like most management standards, is based on a manager and agent model. The JMX agent typically resides with the application server and provides management instrumentation, i.e. application data and control. The management console collects and presents management information from one or more agents on the network.

JMX provides a common management instrumentation model that makes the management data available via a choice of protocols, including SNMP, HTTP, SOAP, etc. JMX is also an easy to use Java API, widely available in application servers and other infrastructure software. A number of tools are now available to manage J2EE application performance and availability using JMX. It's now possible to gain many of the benefits of application management with minimal effort.

To illustrate some of the benefits of application-specific management, we'll use the JMX API to manage a simple JSP web application. Web applications are often used to give users online access to information, as well as allow them to perform business transactions online. We'll look at monitoring these user transactions to see how JMX management can provide useful visibility into how the application is doing in production.


JSP Application Example

Let's look at an example application that models a simple user task, i.e. a user transaction. Many of the J2EE applications being deployed in enterprises use Servlets or JSP pages to serve browser-based clients. These web applications may include financial applications like banking, insurance, or brokerage applications, as well as a number of other intranet applications like HR, call-center, and CRM applications.

Our example represents an application that allows users to transfer money between accounts using a set of JSP pages. To complete the transaction, the user navigates through four pages, a start page, a select transaction details page, a confirm transaction page, and a transaction complete page. We'll look at these JSP pages in more detail in a little bit.

Let's first consider what would be useful to manage with such an application. In many web applications, the user navigates a series of pages to accomplish a task or transaction. Depending on the application, it may be useful to know whether users are having difficulty completing these tasks. For example, if a number of users start a transaction but fail to complete it, it may indicate some work needs to be done on making navigation easier. We will use the session tracking capabilities available with JSP to track the data we need on how our users are doing.

In addition to tracking user success in completing their transactions, for this specific application it may be useful to track aspects of the money transfer. For example, we may wish to send a management notification when the transfer amount exceeds a threshold. Let's look at how one can implement these management functions using JMX.


JMX Management Instrumentation

In order to manage our JSP application, we'll track user transactions and determine how many completed, and how many were abandoned at each stage. This should tell us whether users are having trouble with completing their work. These stats on user navigation will be stored as JMX management instrumentation.

JMX management instrumentation is a set of Java components called MBeans. The MBean components are Java classes that fit design patterns based on the type of MBean. The defined MBean types are Standard, Dynamic, Open and Model MBeans. JMX agent MBeans are all registered with a common MBeanServer interface, which remote management consoles access to get management information from the agent.

We'll create a standard MBean for the management instrumentation of our JSP application. Standard MBeans provide a defined static interface that follows a naming convention. The interface class file is named by adding "MBean" to the name of the standard MBean class.

We'll call our standard MBean MyJspStats. The MBean interface will then need to be named MyJspStatsMBean. The following is the code listing for the MBean interface.

/**
 * The JMX MBean interface
 **/
public interface MyJspStatsMBean {

    /** Get number of abandoned user Tx at start stage**/
    public int getStarts();
    /** Get number of abandoned user Tx at select stage **/
    public int getSelects();
    /** Get number of abandoned user Tx at confirm stage **/
    public int getConfirms();
    /** Get number of completed user Tx **/
    public int getCompletions();
}

Our management data as defined by the MBean interface has one integer variable for each stage, indicating how many user transactions ended at that stage. This represents the data available to management systems.


MBean Implementation

The MBean (MyJspStats.java) will implement the MBean interface. Since our MBean will also be a Java Bean, we can use it as a Java Bean component in our JSP pages, and take advantage of the JSP tags.

We start with a set of imports. This example uses the BEA Weblogic server and it's JMX implementation, which requires us to authenticate and access the JMX MBeanServer using Weblogic APIs. Besides server access, the JMX code uses standard JMX APIs.

In our MBean implementation, we have variables for the management data we want to expose, as well as access methods per our MBean interface. We register our MBean with the MBean server in the constructor, after getting access to it using the Weblogic JNDI service. We use hash tables to keep track of sessions in progress at each stage, using the HttpSession instance passed from each JSP page via the updateTx() method. The HttpSession instance for a session gets invalidated when a session times out, or is otherwise closed. We create a checkTimeouts() method to check for invalidated sessions in each hash table, i.e. the sessions abandoned at each stage.

package sample;

import java.util.Hashtable;
import java.util.Enumeration;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.servlet.http.HttpSession;
import javax.management.ObjectName;
import weblogic.jndi.Environment;
import weblogic.management.MBeanHome;
import javax.management.MBeanServer;

/**
 * This JMX MBean tracks user progress for a JSP application
 * transaction spanning multiple pages.  It records how many
 * transactions were abandoned at each stage, and makes the
 * information available to management systems via JMX.
 **/
public class MyJspStats implements MyJspStatsMBean {

    MBeanServer server = null; // MBeanServer

    int starts = 0;  // Number abandoned at start page
    int selects = 0;  // Number abandoned at selection
    int confirms = 0;  // Number abandoned before confirmation
    int completions = 0;  // Number of completed user Tx

    Hashtable inStart = new Hashtable(); // Track user Tx started
    Hashtable inSelect = new Hashtable(); // Track user Tx in select
    Hashtable inConfirm = new Hashtable(); // Track user Tx in confirm

    /** A no-argument constructor is necessary for Beans in JSPs **/
    public MyJspStats() {
 try {
     Environment env = new Environment();
     env.setProviderUrl("t3://localhost:7001");
     env.setSecurityPrincipal("weblogic"); // username
     env.setSecurityCredentials("weblogic"); // password
     Context myCtx = env.getInitialContext();
     MBeanHome mbeanHome =
  (MBeanHome)myCtx.lookup("weblogic.management.home.localhome");
     server = mbeanHome.getMBeanServer();

     ObjectName objName =
  new ObjectName(mbeanHome.getDomainName()+
          ":Name=MyJspStats,Type=MyJspStats");

// Register MBean so MBean can be accessed by remote managers
     server.registerMBean(this, objName);

 } catch (Exception ex) {
     System.err.println("Cannot get MBeanServer: "+ex);
 }
    }

    /** Get number of abandoned user Tx at start stage**/
    public int getStarts() {
 starts += removeTimeouts(inStart);  // Check abandoned sessions
 return starts;
    }

    /** Get number of abandoned user Tx at select stage **/
    public int getSelects() {
 selects += removeTimeouts(inSelect); // Check abandoned sessions
 return selects;
    }

    /** Get number of abandoned user Tx at confirm stage **/
    public int getConfirms() {
 confirms += removeTimeouts(inConfirm); // Check abandoned sessions
 return confirms;
    }

    /** Get number of completed user Tx **/
    public int getCompletions() { return completions; }

    /** Update statistics based on supplied user Tx data **/
    public void updateTx(HttpSession session, String stage) {
 // First remove from existing in-progress tables
 inStart.remove(session);
 inSelect.remove(session);
 inConfirm.remove(session);

 if (stage.equals("START")) inStart.put(session, stage);
 else if (stage.equals("SELECT")) inSelect.put(session, stage);
 else if (stage.equals("CONFIRM")) inConfirm.put(session, stage);
 else if (stage.equals("COMPLETE")) completions++;
    }

    /** Remove timeouts **/
    int removeTimeouts(Hashtable table) {
 int removed = 0;
 for (Enumeration en=table.keys();en.hasMoreElements();) {
     HttpSession s = (HttpSession) en.nextElement();
     try {
  s.isNew();
     } catch (IllegalStateException ex) {
  table.remove(s);
  removed++;
     }
 }
 return removed;
    }
}

This MBean can now be used on our JSP pages to track user transactions across the JSP pages, which will use the MBean like a Java Bean.


JSP Pages

The first JSP page will include the jsp:usebean tag, which allows us to share a single instance of MyJspStats across the entire web application using the scope attribute. We call the updateTx() method in our MBean, to record that a new transaction has started. We need to pass the HttpSession instance to know which session is being tracked.


<jsp:useBean id="mbean" class="sample.MyJspStats" scope="application"/>

<%
mbean.updateTx(request.getSession(true), "START");
%>

<p><b>Start a Transaction</b><p>
<p><a HREF="page2.jsp">Transfer Money Between Accounts</a>
<p><a HREF="abortpage.jsp">Abort Transaction</a>

We include an abort transaction page (here the motivation is for easy testing - you may have a logout page instead) to allow users to explicitly terminate a transaction, instead of waiting for it to timeout.

The second JSP page asks for details of the money transfer request in a form. Here again we use the jsp:usebean tag to re-use the MBean and record a state change.

<jsp:useBean id="mbean"
    class="sample.MyJspStats" scope="application"/>

<%
mbean.updateTx(request.getSession(true), "SELECT");
%>

<p><b>Select Transaction Details</b><p>

<form NAME="Select Details" ACTION="page3.jsp"  METHOD=POST>
<table border="3"><tbody><tr>
<td>Transfer From: </td>
<td><select name="fromacct">
<option value="savings">Savings
<option value="checking">Checking
</select></td></tr>
<tr><td>Transfer To: </td><td><select name="toacct">
<option value="savings">Savings
<option value="checking">Checking
</select></td></tr>
<tr><td>Amount: $</td>
<td><input maxlength="70" name="amount" size="30"></td></tr>
</tbody></table>

<input name="SUBMIT" type="submit" value="Submit Transaction"></form>

<p><p><a HREF="abortpage.jsp">Abort Transaction</a>

The third page picks up the user data and asks for confirmation. The data needs to be stored in a session object for executing the transaction in the next stage, which we leave out in our example. The HttpSession instance can be used for doing this.


<jsp:useBean id="mbean"
    class="sample.MyJspStats" scope="application"/>

<%
mbean.updateTx(request.getSession(true), "CONFIRM");

out.print("<p><b>Confirm Transaction</b><p>");
out.print("Transfer from "+request.getParameter("fromacct"));
out.print(" to "+request.getParameter("toacct"));
out.print("<br>Amount: $"+request.getParameter("amount"));

// Store the session transaction information for completion
. . .
%>

<p><a HREF="page4.jsp">Complete Transaction</a>
<p><a HREF="abortpage.jsp">Abort Transaction</a>

The last page executes the transaction and updates the MBean.

<jsp:useBean id="mbean"
    class="sample.MyJspStats" scope="application"/>

<body>
<%
// Execute the requested transaction
. . .
mbean.updateTx(request.getSession(true), "COMPLETE");
out.print("<p><b>Transaction Complete</b>");
%>

To make it easy to test the application monitoring, we include an abort page to quickly close sessions. The following JSP code is needed on that page.


request.getSession().invalidate();

These pages can be tested on a BEA Weblogic server installation along with the MBean classes (sample.MyJspStats and sample.MyJspStatsMBean). In the next section, we'll look at how the management information we created can be accessed from a management console.


Management Consoles

In many large enterprises, IT operations use existing enterprise management consoles to manage their IT infrastructure. Many of these consoles support SNMP management, which makes it useful to have SNMP access to management data we created. Most of the existing enterprise management consoles can use SNMP to collect and present management information on our JSP application.

JMX is designed to expose management information via SNMP, HTTP, and a variety of other remote access protocols. Tools are available to take the MBeans you create, and make the data available via SNMP for management consoles. AdventNet ManageEngine is one such tool, which loads your MBeans and generates the SNMP support you need for existing managers to access the management data. There are also JMX-capable management consoles available.

Let's put together a JSP page to display the management information. The server with this page can be either local or remote. We'll use the MBeanServer to show how a remote management console would access the data. This will not work until the MBean is registered with the MBean server, i.e. at least one application JSP page is used.


<%@ page import="
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.management.ObjectName;
import weblogic.jndi.Environment;
import weblogic.management.MBeanHome;
import javax.management.MBeanServer;
" %>

<h2>User Transaction Statistics</h2>

<table border="3"><tbody><tr>
<td><b>User Transaction Stage</b></td>
<td><b>Number of Transactions</b></td> </tr>
<%
  Environment env = new Environment();
  env.setProviderUrl("t3://localhost:7001");
  env.setSecurityPrincipal("weblogic"); // username
  env.setSecurityCredentials("weblogic"); // password
  Context myCtx = new InitialContext();
  MBeanHome mbeanHome = (MBeanHome)myCtx.lookup("weblogic.management.home.localhome");
  MBeanServer server = mbeanHome.getMBeanServer();

  ObjectName objName = new ObjectName(mbeanHome.getDomainName()+":Name=MyJspStats,Type=MyJspStats");

  out.print("<tr><td>Completions</td><td>"
    +server.getAttribute(objName, "Completions")+"</td></tr>");
  out.print("<tr><td>Abandonded at Confirm</td><td>"
    +server.getAttribute(objName, "Confirms")+"</td></tr>");
  out.print("<tr><td>Abandonded at Select</td><td>"
    +server.getAttribute(objName, "Selects")+"</td></tr>");
  out.print("<tr><td>Abandonded at Start</td><td>"
    +server.getAttribute(objName, "Starts")+"</td></tr>");
%>
</tbody></table>

The resulting page provides a view of the MBean data, and looks like this (works only after one or more of the JSP application pages are used, i.e. MBean in instantiated).


Pro-active JMX Notifications

JMX also supports asynchronous notifications to allow agents to notify administrators of significant events that need attention. This facility could be used to send notifications on application data and transactions that need attention. For example, we could setup notifications when money transfers exceed a preset limit. These kinds of notifications enable application management to be used for important business-specific rules that trigger attention or intervention as needed.

For our example, it is straightforward to add notification support. We would need to do the following to add notifications on money transfer amounts to our application:

  1. Add notification support in our MBean by changing MyJspStats to extend javax.management.NotificationBroadcasterSupport

  2. Add code in the JSP page to invoke the sendNotification() method in the MBean. For example, we could add the following in a try/catch block in the confirmation page to send a notification when the transfer amount exceeds 10,000:

    if (Integer.parseInt(request.getAttribute("amount")) > 10000)
      mbean.sendNotification(
        new javax.management.Notification("sample.MyJSPStats", mbean,
          System.currentTimeMillis(),
          "Large Transfer Amount: "+request.getAttribute("amount"));
    

The JMX notifications generated can be viewed in many different management consoles. Typically management consoles would register for the kinds of events of interest to them. Adding SNMP support for notifications so existing consoles can view the notifications as SNMP traps is easily supported with JMX tools.


Summary

Monitoring and managing applications has been made considerably simpler with the JMX API and tools built around JMX. This standard approach to building management provides a powerful way to expose management information about your application useful to operations. JMX makes it easy to integrate with existing management consoles using SNMP.


The simple examples used in this article illustrate the kind of information that would be useful in managing applications in production. With an understanding of how your applications are deployed and used, the JMX API and tools can be used to better manage these applications for greater business benefits.

About the Author

Tony G. Thomas is CTO of AdventNet, the first independent vendor of JMX technology. AdventNet provides management software products, which includes ManageEngine, a JMX management tool. Thomas is a member of the Java Community Process Expert Group driving JMX standards. Prior to founding AdventNet, he was at AT&T Bell Laboratories where his responsibilities included building and managing OSS software solutions. He obtained his PhD in Engineering from the Johns Hopkins University. He can be reached at [email protected].

Dig Deeper on Software development best practices and processes