diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/control/ControlBus.java b/spring-integration-jmx/src/main/java/org/springframework/integration/control/ControlBus.java
index fe549c2c16..53e88a4311 100644
--- a/spring-integration-jmx/src/main/java/org/springframework/integration/control/ControlBus.java
+++ b/spring-integration-jmx/src/main/java/org/springframework/integration/control/ControlBus.java
@@ -33,7 +33,11 @@ import org.springframework.integration.support.MessageBuilder;
import org.springframework.util.Assert;
/**
- * JMX-based Control Bus implementation. Exports all channel and endpoint beans from a given BeanFactory as MBeans.
+ * JMX-based Control Bus implementation. Routes control messages on an operation channel to the other control points
+ * (channels and handlers) via JMX. To use the control bus send a message to the operation channel with a header
+ * {@link #TARGET_BEAN_NAME} equal to the bean name of the channel or endpoint you want to target. Include also a header
+ * {@link JmxHeaders#OPERATION_NAME} to specify the operation you want to invoke and a message payload containing the
+ * arguments (if any).
*
* @author Mark Fisher
* @since 2.0
diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/ExponentialMovingAverage.java b/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/ExponentialMovingAverage.java
index bf47c86a0c..8a9de55043 100644
--- a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/ExponentialMovingAverage.java
+++ b/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/ExponentialMovingAverage.java
@@ -14,8 +14,11 @@ package org.springframework.integration.monitor;
/**
* Cumulative statistics for a series of real numbers with higher weight given to recent data but without storing any
- * history. Older values are given exponentially smaller weight, with a decay factor determined by a "window" size
- * chosen by the client.
+ * history. Clients call {@link #append(double)} every time there is a new measurement, and then can collect summary
+ * statistics from the convenience getters (e.g. {@link #getStatistics()}). Older values are given exponentially smaller
+ * weight, with a decay factor determined by a "window" size chosen by the caller. The result is a good approximation to
+ * the statistics of the series but with more weight given to recent measurements, so if the statistics change over time
+ * those trends can be approximately reflected.
*
* @author Dave Syer
*
@@ -37,12 +40,20 @@ public class ExponentialMovingAverage {
private final double decay;
/**
+ * Create a moving average accumulator with decay lapse window provided. Measurements older than this will have
+ * smaller weight than 1/e.
+ *
* @param window the exponential lapse window (number of measurements)
*/
public ExponentialMovingAverage(int window) {
this.decay = 1 - 1. / window;
}
+ /**
+ * Add a new measurement to the series.
+ *
+ * @param value the measurement to append
+ */
public void append(double value) {
if (value > max || count == 0)
max = value;
@@ -54,28 +65,46 @@ public class ExponentialMovingAverage {
count++;
}
+ /**
+ * @return the number of measurements recorded
+ */
public int getCount() {
return count;
}
+ /**
+ * @return the mean value
+ */
public double getMean() {
return weight > 0 ? sum / weight : 0.;
}
+ /**
+ * @return the approximate standard deviation
+ */
public double getStandardDeviation() {
double mean = getMean();
double var = weight > 0 ? sumSquares / weight - mean * mean : 0.;
return var > 0 ? Math.sqrt(var) : 0;
}
+ /**
+ * @return the maximum value recorded (not weighted)
+ */
public double getMax() {
return max;
}
+ /**
+ * @return the minimum value recorded (not weighted)
+ */
public double getMin() {
return min;
}
+ /**
+ * @return summary statistics (count, mean, standard deviation etc.)
+ */
public Statistics getStatistics() {
return new Statistics(count, min, max, getMean(), getStandardDeviation());
}
diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/ExponentialMovingAverageRate.java b/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/ExponentialMovingAverageRate.java
index bae74a915c..aa096c29bb 100644
--- a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/ExponentialMovingAverageRate.java
+++ b/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/ExponentialMovingAverageRate.java
@@ -13,8 +13,17 @@
package org.springframework.integration.monitor;
/**
- * Cumulative statistics for rate with higher weight given to recent data but without storing any history. Older values
- * are given exponentially smaller weight, with a decay factor determined by a duration chosen by the client.
+ * Cumulative statistics for an event rate with higher weight given to recent data but without storing any history.
+ * Clients call {@link #increment()} when a new event occurs, and then use convenience methods (e.g. {@link #getMean()})
+ * to retrieve estimates of the rate of event arrivals and the statistics of the series. Older values are given
+ * exponentially smaller weight, with a decay factor determined by a duration chosen by the client. The rate measurement
+ * weights decay in two dimensions:
+ *
+ * - in time according to the lapse period supplied:
weight = exp((t0-t)/T) where t0 is the
+ * last measurement time, t is the current time and T is the lapse period)
+ * - per measurement according to the lapse window supplied:
weight = exp(-i/L) where L is
+ * the lapse window and i is the sequence number of the measurement.
+ *
*
* @author Dave Syer
*
@@ -48,6 +57,9 @@ public class ExponentialMovingAverageRate {
this.period = period * 1000; // convert to millisecs
}
+ /**
+ * Add a new event to the series.
+ */
public void increment() {
long t = System.currentTimeMillis();
@@ -66,6 +78,9 @@ public class ExponentialMovingAverageRate {
}
+ /**
+ * @return the number of measurements recorded
+ */
public int getCount() {
return rates.getCount();
}
@@ -77,9 +92,12 @@ public class ExponentialMovingAverageRate {
return (System.currentTimeMillis() - t0) / 1000.;
}
+ /**
+ * @return the mean value
+ */
public double getMean() {
int count = rates.getCount();
- if (count==0) {
+ if (count == 0) {
return 0;
}
long t = System.currentTimeMillis();
@@ -87,18 +105,30 @@ public class ExponentialMovingAverageRate {
return count / (count / rates.getMean() + value);
}
+ /**
+ * @return the approximate standard deviation
+ */
public double getStandardDeviation() {
return rates.getStandardDeviation();
}
+ /**
+ * @return the maximum value recorded (not weighted)
+ */
public double getMax() {
return min > 0 ? 1 / min : 0;
}
+ /**
+ * @return the minimum value recorded (not weighted)
+ */
public double getMin() {
return max > 0 ? 1 / max : 0;
}
+ /**
+ * @return summary statistics (count, mean, standard deviation etc.)
+ */
public Statistics getStatistics() {
return new Statistics(getCount(), min, max, getMean(), getStandardDeviation());
}
diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/ExponentialMovingAverageRatio.java b/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/ExponentialMovingAverageRatio.java
index 2e2ca1a0e0..48297f2bb0 100644
--- a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/ExponentialMovingAverageRatio.java
+++ b/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/ExponentialMovingAverageRatio.java
@@ -13,9 +13,15 @@
package org.springframework.integration.monitor;
/**
- * Cumulative statistics for success rate (ratio) with higher weight given to recent data but without storing any
- * history. Older values are given exponentially smaller weight, with a decay factor determined by a duration chosen by
- * the client.
+ * Cumulative statistics for success ratio with higher weight given to recent data but without storing any history.
+ * Clients call {@link #success()} or {@link #failure()} when an event occurs, and the ratio of success to total events
+ * is accumulated. Older values are given exponentially smaller weight, with a decay factor determined by a duration
+ * chosen by the client. The rate measurement weights decay in two dimensions:
+ *
+ * - in time according to the lapse period supplied:
weight = exp((t0-t)/T) where t0 is the
+ * last measurement time, t is the current time and T is the lapse period)
+ * - per measurement according to the lapse window supplied:
weight = exp(-i/L) where L is
+ * the lapse window and i is the sequence number of the measurement.
*
* @author Dave Syer
*
@@ -41,10 +47,16 @@ public class ExponentialMovingAverageRatio {
this.lapse = lapsePeriod > 0 ? 0.001 / lapsePeriod : 0; // convert to millisecs
}
+ /**
+ * Add a new event with successful outcome.
+ */
public void success() {
append(1);
}
+ /**
+ * Add a new event with failed outcome.
+ */
public void failure() {
append(0);
}
@@ -60,6 +72,9 @@ public class ExponentialMovingAverageRatio {
}
+ /**
+ * @return the number of measurements recorded
+ */
public int getCount() {
return cumulative.getCount();
}
@@ -71,6 +86,9 @@ public class ExponentialMovingAverageRatio {
return (System.currentTimeMillis() - t0) / 1000.;
}
+ /**
+ * @return the mean success rate
+ */
public double getMean() {
int count = cumulative.getCount();
if (count == 0) {
@@ -81,18 +99,30 @@ public class ExponentialMovingAverageRatio {
return alpha * cumulative.getMean() + 1 - alpha;
}
+ /**
+ * @return the approximate standard deviation of the success rate measurements
+ */
public double getStandardDeviation() {
return cumulative.getStandardDeviation();
}
+ /**
+ * @return the maximum value recorded of the exponential weighted average (per measurement) success rate
+ */
public double getMax() {
return cumulative.getMax();
}
+ /**
+ * @return the minimum value recorded of the exponential weighted average (per measurement) success rate
+ */
public double getMin() {
return cumulative.getMin();
}
+ /**
+ * @return summary statistics (count, mean, standard deviation etc.)
+ */
public Statistics getStatistics() {
return new Statistics(getCount(), getMin(), getMax(), getMean(), getStandardDeviation());
}
diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/IntegrationMBeanExporter.java b/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/IntegrationMBeanExporter.java
index e0a54cb357..1d9a9681de 100644
--- a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/IntegrationMBeanExporter.java
+++ b/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/IntegrationMBeanExporter.java
@@ -56,7 +56,25 @@ import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
/**
- * MBean exporter for Spring Integration components in an existing application.
+ *
+ * MBean exporter for Spring Integration components in an existing application. Add an instance of this as a bean
+ * definition in the same context as the components you need to monitor and all message channels and message handlers
+ * will be exposed.
+ *
+ *
+ * Channels will report metrics on send and receive (counts, rates, errors) and handlers will report metrics on
+ * execution duration. Channels will be registered under their name (bean id), if explicit, or the last part of their
+ * internal name (e.g. "nullChannel") if registered by the framework. A handler that is attached to an endpoint will be
+ * registered with the endpoint name (bean id) if there is one, otherwise under the name of the input channel. Handler
+ * object names contain a bean key that reports the source of the name: "endpoint" if the name is the
+ * endpoint id; "anonymous" if it is the input channel; and "handler" as a fallback, where the object name is just the
+ * toString() of the handler.
+ *
+ *
+ * This component is itself an MBean, reporting attributes concerning the names and object names of the channels and
+ * handlers. It doesn't register itself to avoid conflicts with the standard <context:mbean-export/>
+ * from Spring (which should therefore be used any time you need to expose those features).
+ *
*
* @author Dave Syer
* @author Helena Edelson
@@ -288,13 +306,13 @@ public class IntegrationMBeanExporter extends MBeanExporter implements BeanPostP
public Map getObjectNames() {
return Collections.unmodifiableMap(objectNamesByName);
}
-
+
public Statistics getHandlerDuration(String name) {
if (handlersByName.containsKey(name)) {
return handlersByName.get(name).getDuration();
}
logger.debug("No handler found for (" + name + ")");
- return null;
+ return null;
}
public int getChannelReceiveCount(String name) {
@@ -355,8 +373,7 @@ public class IntegrationMBeanExporter extends MBeanExporter implements BeanPostP
}
}
- private Object applyChannelInterceptor(Object bean, DirectChannelMonitor interceptor,
- ClassLoader beanClassLoader) {
+ private Object applyChannelInterceptor(Object bean, DirectChannelMonitor interceptor, ClassLoader beanClassLoader) {
NameMatchMethodPointcutAdvisor channelsAdvice = new NameMatchMethodPointcutAdvisor(interceptor);
channelsAdvice.addMethodName("send");
channelsAdvice.addMethodName("receive");
diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/LifecycleMessageHandlerMonitor.java b/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/LifecycleMessageHandlerMonitor.java
index 50cfa71bd6..c630add493 100644
--- a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/LifecycleMessageHandlerMonitor.java
+++ b/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/LifecycleMessageHandlerMonitor.java
@@ -21,15 +21,19 @@ import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedResource;
/**
+ * A {@link MessageHandlerMonitor} that exposes in addition the {@link Lifecycle} interface. The lifecycle methods can
+ * be used to stop and start polling endpoints, for instance, in a live system.
+ *
* @author Dave Syer
*
* @since 2.0
- *
+ *
*/
@ManagedResource
-public class LifecycleMessageHandlerMonitor implements MessageHandlerMonitor {
+public class LifecycleMessageHandlerMonitor implements MessageHandlerMonitor, Lifecycle {
private final Lifecycle lifecycle;
+
private final MessageHandlerMonitor delegate;
public LifecycleMessageHandlerMonitor(Lifecycle lifecycle, MessageHandlerMonitor delegate) {
diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/MessageChannelMonitor.java b/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/MessageChannelMonitor.java
index 149fb87f12..bf5ceec4f5 100644
--- a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/MessageChannelMonitor.java
+++ b/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/MessageChannelMonitor.java
@@ -19,45 +19,89 @@ import org.springframework.jmx.export.annotation.ManagedMetric;
import org.springframework.jmx.support.MetricType;
/**
- * @author dsyer
- *
+ * Interface for all message channel monitors containing accessors for various useful metrics that are generic for all
+ * channel types.
+ *
+ * @author Dave Syer
+ *
+ * @since 2.0
+ *
*/
public interface MessageChannelMonitor {
+ /**
+ * @return the number of successful sends
+ */
@ManagedMetric(metricType = MetricType.COUNTER, displayName = "MessageChannel Sends")
int getSendCount();
+ /**
+ * @return the number of failed sends (either throwing an exception or rejected by the channel)
+ */
@ManagedMetric(metricType = MetricType.COUNTER, displayName = "MessageChannel Send Errors")
int getSendErrorCount();
+ /**
+ * @return the time in seconds since the last send
+ */
@ManagedMetric(metricType = MetricType.GAUGE, displayName = "Channel Time Since Last Send in Seconds")
double getTimeSinceLastSend();
+ /**
+ * @return the mean send rate (per second)
+ */
@ManagedMetric(metricType = MetricType.GAUGE, displayName = "Channel Send Rate per Second")
double getMeanSendRate();
+ /**
+ * @return the mean error rate (per second). Errors comprise all failed sends.
+ */
@ManagedMetric(metricType = MetricType.GAUGE, displayName = "Channel Error Rate per Second")
double getMeanErrorRate();
+ /**
+ * @return the mean ratio of failed to successful sends in approximately the last minute
+ */
@ManagedMetric(metricType = MetricType.GAUGE, displayName = "Mean Channel Error Ratio per Minute")
double getMeanErrorRatio();
+ /**
+ * @return the mean send duration (milliseconds)
+ */
@ManagedMetric(metricType = MetricType.GAUGE, displayName = "Channel Send Mean Duration")
double getMeanSendDuration();
+ /**
+ * @return the minimum send duration (milliseconds) since startup
+ */
@ManagedMetric(metricType = MetricType.GAUGE, displayName = "Channel Send Min Duration")
double getMinSendDuration();
+ /**
+ * @return the maximum send duration (milliseconds) since startup
+ */
@ManagedMetric(metricType = MetricType.GAUGE, displayName = "Channel Send Max Duration")
double getMaxSendDuration();
+ /**
+ * @return the standard deviation send duration (milliseconds)
+ */
@ManagedMetric(metricType = MetricType.GAUGE, displayName = "Channel Send Standard Deviation Duration")
double getStandardDeviationSendDuration();
+ /**
+ * @return summary statistics about the send duration (milliseconds)
+ */
Statistics getSendDuration();
+ /**
+ * @return summary statistics about the send rates (per second)
+ */
Statistics getSendRate();
+ /**
+ * @return summary statistics about the error rates (per second)
+ */
Statistics getErrorRate();
}
\ No newline at end of file
diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/MessageHandlerMonitor.java b/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/MessageHandlerMonitor.java
index 6c29af162f..4e06cfc904 100644
--- a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/MessageHandlerMonitor.java
+++ b/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/MessageHandlerMonitor.java
@@ -25,24 +25,42 @@ import org.springframework.jmx.support.MetricType;
*/
public interface MessageHandlerMonitor {
+ /**
+ * @return the number of successful handler calls
+ */
@ManagedMetric(metricType = MetricType.COUNTER, displayName = "Handler Execution Count", description = "rate=1h")
int getHandleCount();
+ /**
+ * @return the number of failed handler calls
+ */
@ManagedMetric(metricType = MetricType.COUNTER, displayName = "Handler Error Count", description = "rate=1h")
int getErrorCount();
+ /**
+ * @return the maximum handler duration (milliseconds)
+ */
@ManagedMetric(metricType = MetricType.GAUGE, displayName = "Handler Mean Duration")
double getMeanDuration();
+ /**
+ * @return the minimum handler duration (milliseconds)
+ */
@ManagedMetric(metricType = MetricType.GAUGE, displayName = "Handler Min Duration")
double getMinDuration();
+ /**
+ * @return the standard deviation handler duration (milliseconds)
+ */
@ManagedMetric(metricType = MetricType.GAUGE, displayName = "Handler Max Duration")
double getMaxDuration();
@ManagedMetric(metricType = MetricType.GAUGE, displayName = "Handler Standard Deviation Duration")
double getStandardDeviationDuration();
+ /**
+ * @return summary statistics about the handler duration (milliseconds)
+ */
Statistics getDuration();
String getName();
diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/ObjectNameLocator.java b/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/ObjectNameLocator.java
index 648e727f27..dd167878f6 100644
--- a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/ObjectNameLocator.java
+++ b/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/ObjectNameLocator.java
@@ -18,6 +18,8 @@ package org.springframework.integration.monitor;
import java.util.Map;
/**
+ * Locator interface for mapping bean names to JMX object names.
+ *
* @author Dave Syer
*
* @since 2.0
@@ -25,8 +27,15 @@ import java.util.Map;
*/
public interface ObjectNameLocator {
+ /**
+ * @param beanName the bean name to query
+ * @return a String representation of the corresponding JMX object name (or null if there is none)
+ */
String getObjectName(String beanName);
+ /**
+ * @return a map of all the known bean and object names
+ */
Map getObjectNames();
}
\ No newline at end of file