Search

Using JMX to Manage Web Applications

1 views

Why Management Matters for Modern Web Apps

Web applications are the backbone of today’s digital services. They process payments, route orders, handle customer support, and power the daily workflow of thousands of employees. The business value of a web app is therefore tied directly to its uptime, speed, and reliability. Yet many teams still treat performance monitoring as a post‑deployment chore: a log file that is checked occasionally, a simple uptime check that triggers an email, and a handful of metrics that rarely change. The result is that most applications run in a black box, with no insight into how real users are interacting with them and what issues creep in as traffic grows.

Java’s Java Management Extensions (JMX) were created to close this gap. The JMX specification gives developers a uniform way to expose internal state and control operations from within an application. When combined with existing management tools – such as SNMP agents, HTTP dashboards, or Java‑based consoles – JMX becomes a single source of truth for both operational and business‑level metrics.

Because JMX is part of the Java Platform, it fits naturally into Java EE stacks. Most application servers already ship with a JMX agent that can be used to register custom MBeans, the objects that expose data and actions. From the perspective of a developer, adding a few simple interfaces and some bookkeeping code can give the same visibility that would otherwise require a custom instrumentation layer, a dedicated monitoring agent, or even a separate database of performance counters.

JMX also encourages a proactive mindset. Instead of waiting for alerts that “the server is down”, you can set up business rules that trigger notifications when certain thresholds are exceeded. A finance application, for example, can warn when a transfer exceeds a regulatory limit, or an e‑commerce site can flag when cart abandonment rises above a target. These alerts are delivered through the same infrastructure that provides visibility, keeping operations and development in sync.

The adoption of JMX in the Java EE community has grown steadily. The standard now powers a wide range of tools – from lightweight dashboards to full‑blown enterprise platforms. For a developer who wants to provide immediate, actionable insight into a web app’s behavior, JMX is the most straightforward path. In the following sections we’ll walk through a concrete example: a multi‑page money‑transfer app built with JSP and Servlets, instrumented with a JMX MBean, and exposed to a console that shows real‑time statistics and can send notifications when needed.

Designing a JMX‑Enabled JSP Application

The core idea of the example is simple: track how users move through four stages of a transaction – start, select, confirm, and complete – and expose counts of completed and abandoned sessions via a JMX MBean. The application itself is a set of JSP pages that simulate a banking transfer. By weaving a single Java Bean into each page, we keep the instrumentation separate from the UI logic while still sharing state across the entire web application.

The MBean is a Standard MBean. In JMX, a Standard MBean follows a naming convention: the interface ends with MBean, while the implementing class has the same name without the suffix. For our case, the interface is MyJspStatsMBean and the implementation is MyJspStats. The interface exposes four read‑only properties – Starts, Selects, Confirms, and Completions – that represent the number of user sessions that were abandoned or completed at each stage.

Below is the interface definition. The methods are intentionally simple: they return integers that represent counters. The implementation will handle the bookkeeping and registration with the MBean server.

Prompt
/</p> <p> * The JMX MBean interface</p><strong>/</strong></p> <p>public interface MyJspStatsMBean {</p> <p> /<strong> Number of abandoned transactions at the start stage </strong>/</p> <p> public int getStarts();</p> <p> /<strong> Number of abandoned transactions at the select stage </strong>/</p> <p> public int getSelects();</p> <p> /<strong> Number of abandoned transactions at the confirm stage </strong>/</p> <p> public int getConfirms();</p> <p> /<strong> Number of completed transactions </strong>/</p> <p> public int getCompletions();</p> <p>}</p>

The implementation stores four counters and three hash tables that map HttpSession objects to their current stage. Each time a page is accessed, the corresponding stage is recorded via the updateTx method. When the session times out or is explicitly invalidated, the removal logic ensures the counters are updated to reflect an abandonment.

Because the MBean lives inside the application server, it needs to acquire a reference to the server’s MBeanServer before registration. In the example we use BEA WebLogic’s JNDI environment to look up the local MBean home and obtain the server. If you are running on another Java EE server (e.g., WildFly or GlassFish), the lookup code will differ, but the rest of the MBean remains identical. Once registered, the MBean becomes available to any remote console that can connect to the server via JMX protocols.

Prompt
package sample;</p> <p>import java.util.Hashtable;</p> <p>import java.util.Enumeration;</p> <p>import javax.naming.Context;</p> <p>import javax.naming.InitialContext;</p> <p>import javax.servlet.http.HttpSession;</p> <p>import javax.management.ObjectName;</p> <p>import weblogic.jndi.Environment;</p> <p>import weblogic.management.MBeanHome;</p> <p>import javax.management.MBeanServer;</p> <p>/</p> <p> * This JMX MBean tracks user progress for a JSP application</p> <p> * transaction spanning multiple pages. It records how many</p> <p> * transactions were abandoned at each stage, and makes the</p> <p> * information available to management systems via JMX.</p><strong>/</strong></p> <p>public class MyJspStats implements MyJspStatsMBean {</p> <p> MBeanServer server = null;</p> <p> int starts = 0;</p> <p> int selects = 0;</p> <p> int confirms = 0;</p> <p> int completions = 0;</p> <p> Hashtable inStart = new Hashtable();</p> <p> Hashtable inSelect = new Hashtable();</p> <p> Hashtable inConfirm = new Hashtable();</p> <p> public MyJspStats() {</p> <p> try {</p> <p> Environment env = new Environment();</p> <p> env.setProviderUrl("t3://localhost:7001");</p> <p> env.setSecurityPrincipal("weblogic");</p> <p> env.setSecurityCredentials("weblogic");</p> <p> Context myCtx = env.getInitialContext();</p> <p> MBeanHome mbeanHome = (MBeanHome)myCtx.lookup("weblogic.management.home.localhome");</p> <p> server = mbeanHome.getMBeanServer();</p> <p> ObjectName objName = new ObjectName(mbeanHome.getDomainName()+</p> <p> ":Name=MyJspStats,Type=MyJspStats");</p> <p> server.registerMBean(this, objName);</p> <p> } catch (Exception ex) {</p> <p> System.err.println("Cannot get MBeanServer: "+ex);</p> <p> }</p> <p> }</p> <p> public int getStarts() {</p> <p> starts += removeTimeouts(inStart);</p> <p> return starts;</p> <p> }</p> <p> public int getSelects() {</p> <p> selects += removeTimeouts(inSelect);</p> <p> return selects;</p> <p> }</p> <p> public int getConfirms() {</p> <p> confirms += removeTimeouts(inConfirm);</p> <p> return confirms;</p> <p> }</p> <p> public int getCompletions() {</p> <p> return completions;</p> <p> }</p> <p> public void updateTx(HttpSession session, String stage) {</p> <p> inStart.remove(session);</p> <p> inSelect.remove(session);</p> <p> inConfirm.remove(session);</p> <p> if (stage.equals("START")) inStart.put(session, stage);</p> <p> else if (stage.equals("SELECT")) inSelect.put(session, stage);</p> <p> else if (stage.equals("CONFIRM")) inConfirm.put(session, stage);</p> <p> else if (stage.equals("COMPLETE")) completions++;</p> <p> }</p> <p> int removeTimeouts(Hashtable table) {</p> <p> int removed = 0;</p> <p> for (Enumeration en=table.keys(); en.hasMoreElements();) {</p> <p> HttpSession s = (HttpSession) en.nextElement();</p> <p> try {</p> <p> s.isNew();</p> <p> } catch (IllegalStateException ex) {</p> <p> table.remove(s);</p> <p> removed++;</p> <p> }</p> <p> }</p> <p> return removed;</p> <p> }</p> <p>}</p>

With the MBean in place, each JSP page can simply reference a single bean instance and call updateTx at the appropriate step. The jsp:useBean tag creates or reuses the bean across the entire application by setting the scope to application. This approach keeps the code minimal and avoids repeated instantiation costs.

Prompt
<jsp:useBean id="mbean" class="sample.MyJspStats" scope="application"/></p> <p><% mbean.updateTx(request.getSession(true), "START"); %></p> <p><p><b>Start a Transaction</b></p></p> <p><p><a HREF="page2.jsp">Transfer Money Between Accounts</a></p></p> <p><p><a HREF="abortpage.jsp">Abort Transaction</a></p></p>

The subsequent pages follow the same pattern, changing the stage string passed to updateTx. A special abortpage.jsp is included to simulate a user intentionally cancelling the transaction; it simply calls request.getSession().invalidate(); to force a session timeout and trigger the counter increment for abandonment.

Exposing MBean Data to Management Consoles

Once the MBean is registered, any remote console that knows the ObjectName can retrieve its attributes. Many enterprises already run SNMP‑based dashboards; JMX makes it trivial to expose the same data via SNMP, HTTP, or the native JMX protocol. Tools such as AdventNet ManageEngine automatically generate the required SNMP traps from your MBeans, so that legacy consoles can display live counters.

Below is an example JSP that pulls the four counters from the MBean and renders them as an HTML table. This page could run on the same server that hosts the application, or on a separate management host that has network access to the JMX port.

Prompt
<%@ page import="</p> <p>" %></p> <p><h3>User Transaction Statistics</h3></p> <p><table border="3"></p> <p> <tr></p> <p> <td><b>Stage</b></td></p> <p> <td><b>Count</b></td></p> <p> </tr></p> <p> <%</p> <p> Environment env = new Environment();</p> <p> env.setProviderUrl("t3://localhost:7001");</p> <p> env.setSecurityPrincipal("weblogic");</p> <p> env.setSecurityCredentials("weblogic");</p> <p> Context myCtx = new InitialContext();</p> <p> MBeanHome mbeanHome = (MBeanHome)myCtx.lookup("weblogic.management.home.localhome");</p> <p> MBeanServer server = mbeanHome.getMBeanServer();</p> <p> ObjectName objName = new ObjectName(mbeanHome.getDomainName()+":Name=MyJspStats,Type=MyJspStats");</p> <p> out.print("<tr><td>Completions</td><td>"+server.getAttribute(objName,"Completions")+"</td></tr>");</p> <p> out.print("<tr><td>Abandoned at Confirm</td><td>"+server.getAttribute(objName,"Confirms")+"</td></tr>");</p> <p> out.print("<tr><td>Abandoned at Select</td><td>"+server.getAttribute(objName,"Selects")+"</td></tr>");</p> <p> out.print("<tr><td>Abandoned at Start</td><td>"+server.getAttribute(objName,"Starts")+"</td></tr>");</p> <p> %></p> <p></table></p>

If the application receives traffic, the numbers on this page will grow. By refreshing the page, administrators get a real‑time snapshot of user behavior: how many people begin a transfer, how many drop out at each stage, and how many finish successfully. These raw numbers can be fed into dashboards that correlate with business metrics, such as revenue loss from abandoned transfers.

The same data can also be pulled via JMX clients written in Java or via command‑line tools like jmxterm. A simple command that queries the counter for completions would look like:

Prompt
jmxterm -l t3://localhost:7001 -u weblogic -p weblogic -e "get com.mydomain:type=MyJspStats,Name=MyJspStats completions"</p>

Because the data lives inside the application server, there is no need to expose custom HTTP endpoints or write additional persistence code. The MBean approach keeps instrumentation tightly coupled to business logic while exposing a standard API that any tool can consume.

Adding Business‑Rule Notifications with JMX

JMX is not only about data exposure; it also supports asynchronous notifications. By extending javax.management.NotificationBroadcasterSupport, an MBean can send alerts whenever a particular event occurs. For the money‑transfer example, a common rule is to flag transfers that exceed a regulatory threshold – say, $10,000 – as potentially suspicious. Instead of periodically polling the MBean, the application can emit a notification at the moment the transfer is confirmed.

To enable notifications, modify the implementation class to inherit from NotificationBroadcasterSupport and add a method that dispatches the alert. The JSP that handles the confirmation step is updated to call this method if the amount crosses the limit. A notification carries a message, a timestamp, and an optional user data payload. The management console can register a listener to receive these events, or an SNMP trap can be generated automatically if the management tool supports it.

Prompt
public class MyJspStats extends NotificationBroadcasterSupport implements MyJspStatsMBean {</p> <p> // existing fields and methods omitted for brevity</p> <p> public void updateTx(HttpSession session, String stage, int amount) {</p> <p> // existing logic for START, SELECT, CONFIRM, COMPLETE</p> <p> if (stage.equals("CONFIRM")) {</p> <p> if (amount > 10000) {</p> <p> Notification n = new Notification(</p> <p> "sample.MyJspStats.TransferExceeded",</p> <p> this,</p> <p> getSequenceNumber(),</p> <p> System.currentTimeMillis(),</p> <p> "Transfer amount of $" + amount + " exceeds limit."</p> <p> );</p> <p> sendNotification(n);</p> <p> }</p> <p> }</p> <p> }</p> <p>}</p>

The confirmation page would pass the amount when invoking updateTx:

Prompt
<%</p> <p> int amt = Integer.parseInt(request.getParameter("amount"));</p> <p> mbean.updateTx(request.getSession(true), "CONFIRM", amt);</p> <p>%></p>

Once the notification is sent, any console that listens for sample.MyJspStats.TransferExceeded will receive it immediately. For teams using SNMP, a tool can translate the JMX notification into an SNMP trap, enabling legacy monitoring dashboards to react in real time. For teams using a modern JMX console, the notification can be displayed as a pop‑up or logged to a file.

Incorporating notifications into a production application turns passive metrics into active alerts. Administrators can focus on high‑impact events without continuously checking counters. Business teams can also tie the notification data into compliance workflows, such as triggering an audit or a compliance check when thresholds are breached.

Implementing JMX notifications is a small change: a single inheritance line, an extra method call, and a minimal code tweak in a JSP page. The payoff is immediate, with real‑time visibility into critical business events that would otherwise go unnoticed until manual review or a customer complaint.

Suggest a Correction

Found an error or have a suggestion? Let us know and we'll review it.

Share this article

Comments (0)

Please sign in to leave a comment.

No comments yet. Be the first to comment!

Related Articles