提交 822ed038 编写于 作者: J Jennifer Hickey

SPR-5256

上级 8f359ece
......@@ -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);
......
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 "";
}
\ No newline at end of file
......@@ -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;
}
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;
}
}
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() {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册