/*
* Copyright 2006-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.batch.admin.jmx;
import javax.management.ObjectName;
import javax.management.monitor.GaugeMonitor;
import javax.management.monitor.MonitorMBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
/**
* Monitors executions of a given step and sends JMX notifications if it takes
* too long. The monitor is a {@link MonitorMBean} so it can be automatically
* exposed to an existing MBeanServer using Spring JMX. JMX clients subscribe to
* notifications and receive them whenever the thresholds are crossed.
*
* @author Dave Syer
*
*/
public class StepExecutionServiceLevelMonitor implements FactoryBean<GaugeMonitor>, InitializingBean {
private String defaultDomain = BatchMBeanExporter.DEFAULT_DOMAIN;
private String stepName;
private String jobName;
private int upperThreshold = 0;
private int lowerThreshold = 0;
private boolean autoStart = true;
private String observedAttribute = "LatestDuration";
/**
* The name of the attribute to monitor on the step. Defaults to
* <code>LatestDuration</code>. This can be changed at runtime, but note
* that if the type of the observed metric changes (e.g. from double to
* integer) then the thresholds will also have to be changed so their type
* matches.
*
* @param observedAttribute the observed attribute to set
*/
public void setObservedAttribute(String observedAttribute) {
this.observedAttribute = observedAttribute;
}
/**
* Should the monitor start immediately or wait to be started manually?
*
* @param autoStart the auto start flag to set
*/
public void setAutoStart(boolean autoStart) {
this.autoStart = autoStart;
}
/**
* The domain name to use in constructing object names for the monitored
* step. Default to <code>org.springframework.batch</code> (same as
* {@link BatchMBeanExporter}).
*
* @param defaultDomain the default domain to set
*/
public void setDefaultDomain(String defaultDomain) {
this.defaultDomain = defaultDomain;
}
/**
* @param stepName the stepName to set
*/
public void setStepName(String stepName) {
this.stepName = stepName;
}
/**
* @param jobName the jobName to set
*/
public void setJobName(String jobName) {
this.jobName = jobName;
}
/**
* Upper threshold for observed attribute. Mandatory with no default.
*
* @param upperThreshold the upper threshold to set
*/
public void setUpperThreshold(int upperThreshold) {
this.upperThreshold = upperThreshold;
}
/**
* Optional lower threshold. Defaults to 80% of the upper threshold.
*
* @param lowerThreshold the lower threshold to set
*/
public void setLowerThreshold(int lowerThreshold) {
this.lowerThreshold = lowerThreshold;
}
public GaugeMonitor getObject() throws Exception {
GaugeMonitor monitor = new GaugeMonitor();
monitor.setNotifyHigh(true);
monitor.addObservedObject(new ObjectName(String.format("%s:type=JobExecution,name=%s,step=%s", defaultDomain,
jobName, stepName)));
monitor.setObservedAttribute(observedAttribute);
if (observedAttribute.endsWith("Duration")) {
monitor.setThresholds(new Double(upperThreshold), new Double(lowerThreshold));
}
else {
monitor.setThresholds(new Integer(upperThreshold), new Integer(lowerThreshold));
}
if (autoStart) {
monitor.start();
}
return monitor;
}
public Class<?> getObjectType() {
return GaugeMonitor.class;
}
public boolean isSingleton() {
return true;
}
public void afterPropertiesSet() throws Exception {
Assert.state(jobName != null, "A Job name must be provided");
Assert.state(stepName != null, "A Step name must be provided");
Assert.state(upperThreshold > 0, "A threshold must be provided");
Assert.state(lowerThreshold < upperThreshold, "A threshold must be provided");
if (lowerThreshold == 0) {
lowerThreshold = upperThreshold * 8 / 10;
}
}
}