SPR-5256
This commit is contained in:
parent
8f359ece3f
commit
822ed03826
|
|
@ -26,6 +26,7 @@ import org.springframework.core.annotation.AnnotationUtils;
|
|||
import org.springframework.jmx.export.metadata.InvalidMetadataException;
|
||||
import org.springframework.jmx.export.metadata.JmxAttributeSource;
|
||||
import org.springframework.jmx.export.metadata.ManagedAttribute;
|
||||
import org.springframework.jmx.export.metadata.ManagedMetric;
|
||||
import org.springframework.jmx.export.metadata.ManagedNotification;
|
||||
import org.springframework.jmx.export.metadata.ManagedOperation;
|
||||
import org.springframework.jmx.export.metadata.ManagedOperationParameter;
|
||||
|
|
@ -41,6 +42,7 @@ import org.springframework.util.StringUtils;
|
|||
*
|
||||
* @author Rob Harrop
|
||||
* @author Juergen Hoeller
|
||||
* @author Jennifer Hickey
|
||||
* @since 1.2
|
||||
* @see org.springframework.jmx.export.annotation.ManagedResource
|
||||
* @see org.springframework.jmx.export.annotation.ManagedAttribute
|
||||
|
|
@ -75,6 +77,19 @@ public class AnnotationJmxAttributeSource implements JmxAttributeSource {
|
|||
}
|
||||
return managedAttribute;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ManagedMetric getManagedMetric(Method method)
|
||||
throws InvalidMetadataException {
|
||||
org.springframework.jmx.export.annotation.ManagedMetric ann =
|
||||
AnnotationUtils.getAnnotation(method, org.springframework.jmx.export.annotation.ManagedMetric.class);
|
||||
if (ann == null) {
|
||||
return null;
|
||||
}
|
||||
ManagedMetric managedMetric = new ManagedMetric();
|
||||
AnnotationBeanUtils.copyPropertiesToBean(ann, managedMetric);
|
||||
return managedMetric;
|
||||
}
|
||||
|
||||
public ManagedOperation getManagedOperation(Method method) throws InvalidMetadataException {
|
||||
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
package org.springframework.jmx.export.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.jmx.support.MetricType;
|
||||
|
||||
/**
|
||||
* JDK 1.5+ method-level annotation that indicates to expose a given bean
|
||||
* property as JMX attribute, with added Descriptor properties to indicate that
|
||||
* it is a metric. Only valid when used on a JavaBean getter.
|
||||
*
|
||||
*
|
||||
* @author Jennifer Hickey
|
||||
* @since 3.0
|
||||
* @see org.springframework.jmx.export.metadata.ManagedMetric
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface ManagedMetric {
|
||||
|
||||
String category() default "";
|
||||
|
||||
int currencyTimeLimit() default -1;
|
||||
|
||||
String description() default "";
|
||||
|
||||
String displayName() default "";
|
||||
|
||||
MetricType metricType() default MetricType.GAUGE;
|
||||
|
||||
int persistPeriod() default -1;
|
||||
|
||||
String persistPolicy() default "";
|
||||
|
||||
String unit() default "";
|
||||
|
||||
}
|
||||
|
|
@ -143,7 +143,26 @@ public abstract class AbstractReflectiveMBeanInfoAssembler extends AbstractMBean
|
|||
* Constant identifier for the persistName field in a JMX {@link Descriptor}.
|
||||
*/
|
||||
protected static final String FIELD_PERSIST_NAME = "persistName";
|
||||
|
||||
/**
|
||||
* Constant identifier for the displayName field in a JMX {@link Descriptor}.
|
||||
*/
|
||||
protected static final String FIELD_DISPLAY_NAME = "displayName";
|
||||
|
||||
/**
|
||||
* Constant identifier for the units field in a JMX {@link Descriptor}.
|
||||
*/
|
||||
protected static final String FIELD_UNITS = "units";
|
||||
|
||||
/**
|
||||
* Constant identifier for the metricType field in a JMX {@link Descriptor}.
|
||||
*/
|
||||
protected static final String FIELD_METRIC_TYPE = "metricType";
|
||||
|
||||
/**
|
||||
* Constant identifier for the custom metricCategory field in a JMX {@link Descriptor}.
|
||||
*/
|
||||
protected static final String FIELD_METRIC_CATEGORY = "metricCategory";
|
||||
|
||||
/**
|
||||
* Default value for the JMX field "currencyTimeLimit".
|
||||
|
|
|
|||
|
|
@ -30,10 +30,12 @@ import org.springframework.jmx.export.metadata.InvalidMetadataException;
|
|||
import org.springframework.jmx.export.metadata.JmxAttributeSource;
|
||||
import org.springframework.jmx.export.metadata.JmxMetadataUtils;
|
||||
import org.springframework.jmx.export.metadata.ManagedAttribute;
|
||||
import org.springframework.jmx.export.metadata.ManagedMetric;
|
||||
import org.springframework.jmx.export.metadata.ManagedNotification;
|
||||
import org.springframework.jmx.export.metadata.ManagedOperation;
|
||||
import org.springframework.jmx.export.metadata.ManagedOperationParameter;
|
||||
import org.springframework.jmx.export.metadata.ManagedResource;
|
||||
import org.springframework.jmx.support.MetricType;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
|
|
@ -51,6 +53,7 @@ import org.springframework.util.StringUtils;
|
|||
*
|
||||
* @author Rob Harrop
|
||||
* @author Juergen Hoeller
|
||||
* @author Jennifer Hickey
|
||||
* @since 1.2
|
||||
* @see #setAttributeSource
|
||||
* @see org.springframework.jmx.export.metadata.AttributesJmxAttributeSource
|
||||
|
|
@ -60,8 +63,8 @@ public class MetadataMBeanInfoAssembler extends AbstractReflectiveMBeanInfoAssem
|
|||
implements AutodetectCapableMBeanInfoAssembler, InitializingBean {
|
||||
|
||||
private JmxAttributeSource attributeSource;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create a new <code>MetadataMBeanInfoAssembler<code> which needs to be
|
||||
* configured through the {@link #setAttributeSource} method.
|
||||
|
|
@ -129,7 +132,7 @@ public class MetadataMBeanInfoAssembler extends AbstractReflectiveMBeanInfoAssem
|
|||
*/
|
||||
@Override
|
||||
protected boolean includeReadAttribute(Method method, String beanKey) {
|
||||
return hasManagedAttribute(method);
|
||||
return hasManagedAttribute(method) || hasManagedMetric(method);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -166,6 +169,13 @@ public class MetadataMBeanInfoAssembler extends AbstractReflectiveMBeanInfoAssem
|
|||
private boolean hasManagedAttribute(Method method) {
|
||||
return (this.attributeSource.getManagedAttribute(method) != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if the given Method has the <code>ManagedMetric</code> attribute.
|
||||
*/
|
||||
private boolean hasManagedMetric(Method method) {
|
||||
return (this.attributeSource.getManagedMetric(method) != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if the given Method has the <code>ManagedOperation</code> attribute.
|
||||
|
|
@ -207,6 +217,12 @@ public class MetadataMBeanInfoAssembler extends AbstractReflectiveMBeanInfoAssem
|
|||
else if (setter != null && StringUtils.hasText(setter.getDescription())) {
|
||||
return setter.getDescription();
|
||||
}
|
||||
|
||||
ManagedMetric metric = (readMethod != null) ? this.attributeSource.getManagedMetric(readMethod) : null;
|
||||
if(metric != null && StringUtils.hasText(metric.getDescription())) {
|
||||
return metric.getDescription();
|
||||
}
|
||||
|
||||
return propertyDescriptor.getDisplayName();
|
||||
}
|
||||
|
||||
|
|
@ -222,6 +238,10 @@ public class MetadataMBeanInfoAssembler extends AbstractReflectiveMBeanInfoAssem
|
|||
if (ma != null && StringUtils.hasText(ma.getDescription())) {
|
||||
return ma.getDescription();
|
||||
}
|
||||
ManagedMetric metric = this.attributeSource.getManagedMetric(method);
|
||||
if (metric != null && StringUtils.hasText(metric.getDescription())) {
|
||||
return metric.getDescription();
|
||||
}
|
||||
return method.getName();
|
||||
}
|
||||
else {
|
||||
|
|
@ -314,18 +334,24 @@ public class MetadataMBeanInfoAssembler extends AbstractReflectiveMBeanInfoAssem
|
|||
}
|
||||
|
||||
/**
|
||||
* Adds descriptor fields from the <code>ManagedAttribute</code> attribute
|
||||
* to the attribute descriptor. Specifically, adds the <code>currencyTimeLimit</code>,
|
||||
* <code>default</code>, <code>persistPolicy</code> and <code>persistPeriod</code>
|
||||
* descriptor fields if they are present in the metadata.
|
||||
* Adds descriptor fields from the <code>ManagedAttribute</code> attribute or the <code>ManagedMetric</code> attribute
|
||||
* to the attribute descriptor.
|
||||
*/
|
||||
@Override
|
||||
protected void populateAttributeDescriptor(Descriptor desc, Method getter, Method setter, String beanKey) {
|
||||
ManagedAttribute gma =
|
||||
if(getter != null && hasManagedMetric(getter)) {
|
||||
populateMetricDescriptor(desc, this.attributeSource.getManagedMetric(getter));
|
||||
}
|
||||
else {
|
||||
ManagedAttribute gma =
|
||||
(getter == null) ? ManagedAttribute.EMPTY : this.attributeSource.getManagedAttribute(getter);
|
||||
ManagedAttribute sma =
|
||||
ManagedAttribute sma =
|
||||
(setter == null) ? ManagedAttribute.EMPTY : this.attributeSource.getManagedAttribute(setter);
|
||||
|
||||
populateAttributeDescriptor(desc,gma,sma);
|
||||
}
|
||||
}
|
||||
|
||||
private void populateAttributeDescriptor(Descriptor desc, ManagedAttribute gma, ManagedAttribute sma) {
|
||||
applyCurrencyTimeLimit(desc, resolveIntDescriptor(gma.getCurrencyTimeLimit(), sma.getCurrencyTimeLimit()));
|
||||
|
||||
Object defaultValue = resolveObjectDescriptor(gma.getDefaultValue(), sma.getDefaultValue());
|
||||
|
|
@ -340,6 +366,32 @@ public class MetadataMBeanInfoAssembler extends AbstractReflectiveMBeanInfoAssem
|
|||
desc.setField(FIELD_PERSIST_PERIOD, Integer.toString(persistPeriod));
|
||||
}
|
||||
}
|
||||
|
||||
private void populateMetricDescriptor(Descriptor desc, ManagedMetric metric) {
|
||||
applyCurrencyTimeLimit(desc, metric.getCurrencyTimeLimit());
|
||||
|
||||
if (StringUtils.hasLength(metric.getPersistPolicy())) {
|
||||
desc.setField(FIELD_PERSIST_POLICY, metric.getPersistPolicy());
|
||||
}
|
||||
if (metric.getPersistPeriod() >= 0) {
|
||||
desc.setField(FIELD_PERSIST_PERIOD, Integer.toString(metric.getPersistPeriod()));
|
||||
}
|
||||
|
||||
if (StringUtils.hasLength(metric.getDisplayName())) {
|
||||
desc.setField(FIELD_DISPLAY_NAME, metric.getDisplayName());
|
||||
}
|
||||
|
||||
if(StringUtils.hasLength(metric.getUnit())) {
|
||||
desc.setField(FIELD_UNITS, metric.getUnit());
|
||||
}
|
||||
|
||||
if(StringUtils.hasLength(metric.getCategory())) {
|
||||
desc.setField(FIELD_METRIC_CATEGORY, metric.getCategory());
|
||||
}
|
||||
|
||||
String metricType = (metric.getMetricType() == null) ? MetricType.GAUGE.toString() : metric.getMetricType().toString();
|
||||
desc.setField(FIELD_METRIC_TYPE, metricType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds descriptor fields from the <code>ManagedAttribute</code> attribute
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import java.lang.reflect.Method;
|
|||
* read source-level metadata from a managed resource's class.
|
||||
*
|
||||
* @author Rob Harrop
|
||||
* @author Jennifer Hickey
|
||||
* @since 1.2
|
||||
* @see org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler#setAttributeSource
|
||||
* @see org.springframework.jmx.export.MBeanExporter#setAssembler
|
||||
|
|
@ -48,6 +49,16 @@ public interface JmxAttributeSource {
|
|||
* @throws InvalidMetadataException in case of invalid attributes
|
||||
*/
|
||||
ManagedAttribute getManagedAttribute(Method method) throws InvalidMetadataException;
|
||||
|
||||
/**
|
||||
* Implementations should return an instance of <code>ManagedMetric</code>
|
||||
* if the supplied <code>Method</code> has the corresponding metadata.
|
||||
* Otherwise should return <code>null</code>.
|
||||
* @param method the method to read the attribute data from
|
||||
* @return the metric, or <code>null</code> if not found
|
||||
* @throws InvalidMetadataException in case of invalid attributes
|
||||
*/
|
||||
ManagedMetric getManagedMetric(Method method) throws InvalidMetadataException;
|
||||
|
||||
/**
|
||||
* Implementations should return an instance of <code>ManagedOperation</code>
|
||||
|
|
@ -78,4 +89,7 @@ public interface JmxAttributeSource {
|
|||
* @throws InvalidMetadataException in the case of invalid metadata
|
||||
*/
|
||||
ManagedNotification[] getManagedNotifications(Class clazz) throws InvalidMetadataException;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,124 @@
|
|||
package org.springframework.jmx.export.metadata;
|
||||
|
||||
import org.springframework.jmx.support.MetricType;
|
||||
|
||||
/**
|
||||
* Metadata that indicates to expose a given bean property as a JMX attribute,
|
||||
* with additional descriptor properties that indicate that the attribute is a
|
||||
* metric. Only valid when used on a JavaBean getter.
|
||||
*
|
||||
* @author Jennifer Hickey
|
||||
* @since 3.0
|
||||
* @see org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler
|
||||
*/
|
||||
public class ManagedMetric extends AbstractJmxAttribute {
|
||||
|
||||
private String category = "";
|
||||
|
||||
private String displayName = "";
|
||||
|
||||
private MetricType metricType = MetricType.GAUGE;
|
||||
|
||||
private int persistPeriod = -1;
|
||||
|
||||
private String persistPolicy = "";
|
||||
|
||||
private String unit = "";
|
||||
|
||||
/**
|
||||
*
|
||||
*@return The category of this metric (ex. throughput, performance, utilization)
|
||||
*/
|
||||
public String getCategory() {
|
||||
return category;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return A display name for this metric
|
||||
*/
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return A description of how this metric's values change over time
|
||||
*/
|
||||
public MetricType getMetricType() {
|
||||
return metricType;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return The persist period for this metric
|
||||
*/
|
||||
public int getPersistPeriod() {
|
||||
return persistPeriod;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return The persist policy for this metric
|
||||
*/
|
||||
public String getPersistPolicy() {
|
||||
return persistPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return The expected unit of measurement values
|
||||
*/
|
||||
public String getUnit() {
|
||||
return unit;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param category The category of this metric (ex. throughput, performance, utilization)
|
||||
*/
|
||||
public void setCategory(String category) {
|
||||
this.category = category;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param displayName A display name for this metric
|
||||
*/
|
||||
public void setDisplayName(String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param metricType A description of how this metric's values change over time
|
||||
*/
|
||||
public void setMetricType(MetricType metricType) {
|
||||
this.metricType = metricType;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param persistPeriod The persist period for this metric
|
||||
*/
|
||||
public void setPersistPeriod(int persistPeriod) {
|
||||
this.persistPeriod = persistPeriod;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param persistPolicy The persist policy for this metric
|
||||
*/
|
||||
public void setPersistPolicy(String persistPolicy) {
|
||||
this.persistPolicy = persistPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param unit The expected unit of measurement values
|
||||
*/
|
||||
public void setUnit(String unit) {
|
||||
this.unit = unit;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package org.springframework.jmx.support;
|
||||
|
||||
|
||||
/**
|
||||
* Represents how the measurement values of a <code>ManagedMetric</code> will change over time
|
||||
* @author Jennifer Hickey
|
||||
* @since 3.0
|
||||
*
|
||||
*/
|
||||
public enum MetricType {
|
||||
/**
|
||||
* The measurement values may go up or down over time
|
||||
*/
|
||||
GAUGE,
|
||||
|
||||
/**
|
||||
* The measurement values will always increase
|
||||
*/
|
||||
COUNTER
|
||||
}
|
||||
|
|
@ -17,6 +17,7 @@
|
|||
package org.springframework.jmx.export.annotation;
|
||||
|
||||
import org.springframework.jmx.IJmxTestBean;
|
||||
import org.springframework.jmx.support.MetricType;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
|
|
@ -65,7 +66,7 @@ public class AnnotationTestBean implements IJmxTestBean {
|
|||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
@ManagedAttribute(description = "The Nick Name Attribute")
|
||||
public void setNickName(String nickName) {
|
||||
this.nickName = nickName;
|
||||
|
|
@ -97,5 +98,16 @@ public class AnnotationTestBean implements IJmxTestBean {
|
|||
public void dontExposeMe() {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
@ManagedMetric(description="The QueueSize metric", currencyTimeLimit = 20, persistPolicy="OnUpdate", persistPeriod=300,
|
||||
category="utilization", metricType = MetricType.COUNTER, displayName="Queue Size", unit="messages")
|
||||
public long getQueueSize() {
|
||||
return 100l;
|
||||
}
|
||||
|
||||
@ManagedMetric
|
||||
public int getCacheEntries() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,10 @@ import test.interceptor.NopInterceptor;
|
|||
* @author Chris Beams
|
||||
*/
|
||||
public abstract class AbstractMetadataAssemblerTests extends AbstractJmxAssemblerTests {
|
||||
|
||||
protected static final String QUEUE_SIZE_METRIC = "QueueSize";
|
||||
|
||||
protected static final String CACHE_ENTRIES_METRIC = "CacheEntries";
|
||||
|
||||
public void testDescription() throws Exception {
|
||||
ModelMBeanInfo info = getMBeanInfoFromAssembler();
|
||||
|
|
@ -165,15 +169,49 @@ public abstract class AbstractMetadataAssemblerTests extends AbstractJmxAssemble
|
|||
|
||||
assertTrue("Not included in autodetection", assembler.includeBean(proxy.getClass(), "some bean name"));
|
||||
}
|
||||
|
||||
public void testMetricDescription() throws Exception {
|
||||
ModelMBeanInfo inf = getMBeanInfoFromAssembler();
|
||||
ModelMBeanAttributeInfo metric = inf.getAttribute(QUEUE_SIZE_METRIC);
|
||||
ModelMBeanOperationInfo operation = inf.getOperation("getQueueSize");
|
||||
assertEquals("The description for the queue size metric is incorrect",
|
||||
"The QueueSize metric", metric.getDescription());
|
||||
assertEquals("The description for the getter operation of the queue size metric is incorrect",
|
||||
"The QueueSize metric", operation.getDescription());
|
||||
}
|
||||
|
||||
public void testMetricDescriptor() throws Exception {
|
||||
ModelMBeanInfo info = getMBeanInfoFromAssembler();
|
||||
Descriptor desc = info.getAttribute(QUEUE_SIZE_METRIC).getDescriptor();
|
||||
assertEquals("Currency Time Limit should be 20", "20", desc.getFieldValue("currencyTimeLimit"));
|
||||
assertEquals("Persist Policy should be OnUpdate", "OnUpdate", desc.getFieldValue("persistPolicy"));
|
||||
assertEquals("Persist Period should be 300", "300", desc.getFieldValue("persistPeriod"));
|
||||
assertEquals("Unit should be messages", "messages",desc.getFieldValue("units"));
|
||||
assertEquals("Display Name should be Queue Size", "Queue Size",desc.getFieldValue("displayName"));
|
||||
assertEquals("Metric Type should be COUNTER", "COUNTER",desc.getFieldValue("metricType"));
|
||||
assertEquals("Metric Category should be utilization", "utilization",desc.getFieldValue("metricCategory"));
|
||||
}
|
||||
|
||||
public void testMetricDescriptorDefaults() throws Exception {
|
||||
ModelMBeanInfo info = getMBeanInfoFromAssembler();
|
||||
Descriptor desc = info.getAttribute(CACHE_ENTRIES_METRIC).getDescriptor();
|
||||
assertNull("Currency Time Limit should not be populated", desc.getFieldValue("currencyTimeLimit"));
|
||||
assertNull("Persist Policy should not be populated", desc.getFieldValue("persistPolicy"));
|
||||
assertNull("Persist Period should not be populated", desc.getFieldValue("persistPeriod"));
|
||||
assertNull("Unit should not be populated", desc.getFieldValue("units"));
|
||||
assertEquals("Display Name should be populated by default via JMX", CACHE_ENTRIES_METRIC,desc.getFieldValue("displayName"));
|
||||
assertEquals("Metric Type should be GAUGE", "GAUGE",desc.getFieldValue("metricType"));
|
||||
assertNull("Metric Category should not be populated", desc.getFieldValue("metricCategory"));
|
||||
}
|
||||
|
||||
protected abstract String getObjectName();
|
||||
|
||||
protected int getExpectedAttributeCount() {
|
||||
return 4;
|
||||
return 6;
|
||||
}
|
||||
|
||||
protected int getExpectedOperationCount() {
|
||||
return 7;
|
||||
return 9;
|
||||
}
|
||||
|
||||
protected IJmxTestBean createJmxTestBean() {
|
||||
|
|
|
|||
Loading…
Reference in New Issue