Skip to content

Commit

Permalink
add cacheDurationMillis attribute to Flatten and Nested annotations
Browse files Browse the repository at this point in the history
  • Loading branch information
arhimondr committed Aug 30, 2015
1 parent 963a28c commit 8206093
Show file tree
Hide file tree
Showing 5 changed files with 152 additions and 24 deletions.
29 changes: 20 additions & 9 deletions src/main/java/org/weakref/jmx/AnnotationUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ public static String getDescription(Annotation... annotations)
*
* @param clazz the class to analyze
* @return a map that associates a concrete method to the actual method tagged as managed
* (which may belong to a different class in clazz's hierarchy)
* (which may belong to a different class in clazz's hierarchy)
*/
public static Map<Method, Method> findManagedMethods(Class<?> clazz)
{
Expand Down Expand Up @@ -259,7 +259,7 @@ public static Method findManagedMethod(Class<?> clazz, String methodName, Class<
try {
Method method = clazz.getDeclaredMethod(methodName, paramTypes);
if (isManagedMethod(method)) return method;
}
}
catch (NoSuchMethodException e) {
// ignore
}
Expand Down Expand Up @@ -293,30 +293,41 @@ public static boolean isManagedMethod(Method method)

public static boolean isFlatten(Method method)
{
return method != null && isAnnotationPresent(Flatten.class, new HashSet<Class<? extends Annotation>>(), method.getAnnotations());
return findAnnotation(Flatten.class, method) != null;
}

public static boolean isNested(Method method)
{
return method != null && isAnnotationPresent(Nested.class, new HashSet<Class<? extends Annotation>>(), method.getAnnotations());
return findAnnotation(Nested.class, method) != null;
}

public static <T extends Annotation> T findAnnotation(Class<T> annotationClass, Method method)
{
if (method != null) {
return findAnnotation(annotationClass, new HashSet<Class<? extends Annotation>>(), method.getAnnotations());
}
return null;
}

private static boolean isAnnotationPresent(Class<? extends Annotation> annotationClass, Set<Class<? extends Annotation>> processedTypes, Annotation... annotations)
private static <T extends Annotation> T findAnnotation(Class<T> annotationClass, Set<Class<? extends Annotation>> processedTypes, Annotation... annotations)
{
// are any of the annotations the specified annotation
for (Annotation annotation : annotations) {
if (annotationClass.isInstance(annotation)) {
return true;
return annotationClass.cast(annotation);
}
}

// are any of the annotations annotated with the specified annotation
for (Annotation annotation : annotations) {
if (processedTypes.add(annotation.annotationType()) && isAnnotationPresent(annotationClass, processedTypes, annotation.annotationType().getAnnotations())) {
return true;
if (processedTypes.add(annotation.annotationType())) {
T foundAnnotation = findAnnotation(annotationClass, processedTypes, annotation.annotationType().getAnnotations());
if (foundAnnotation != null) {
return foundAnnotation;
}
}
}

return false;
return null;
}
}
3 changes: 2 additions & 1 deletion src/main/java/org/weakref/jmx/Flatten.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@
import java.lang.annotation.ElementType;

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@ManagedAnnotation
public @interface Flatten
{
long cacheDurationMillis() default -1;
}
57 changes: 44 additions & 13 deletions src/main/java/org/weakref/jmx/MBeanAttributeBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,18 @@
import static org.weakref.jmx.ReflectionUtils.isValidSetter;

import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableList;

import javax.management.Descriptor;
import javax.management.ImmutableDescriptor;
import javax.management.MBeanAttributeInfo;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

Expand All @@ -45,14 +48,18 @@ public class MBeanAttributeBuilder

public MBeanAttributeBuilder withTargetSupplier(Supplier targetSupplier)
{
if (targetSupplier == null) throw new NullPointerException("targetSupplier is null");
if (targetSupplier == null) {
throw new NullPointerException("targetSupplier is null");
}
this.targetSupplier = targetSupplier;
return this;
}

public MBeanAttributeBuilder named(String name)
{
if (name == null) throw new NullPointerException("name is null");
if (name == null) {
throw new NullPointerException("name is null");
}
this.name = name;
return this;
}
Expand Down Expand Up @@ -135,13 +142,14 @@ public Collection<? extends MBeanFeature> build()
throw new IllegalArgumentException("Flattened JmxAttribute must have a concrete getter");
}

Class targetType = getNestedTargetType(concreteGetter);
if(targetType == null){
Class nestedObjectType = getNestedObjectType(concreteGetter);
if (nestedObjectType == null) {
return ImmutableList.of();
}
Supplier nestedObjectSupplier = createNestedObjectSupplier(targetType, concreteGetter);
long cacheDurationMillis = getNestedObjectCacheDuration(annotatedGetter);
Supplier nestedObjectSupplier = createNestedObjectSupplier(nestedObjectType, concreteGetter, cacheDurationMillis);

MBean mbean = MBeanBuilder.from(targetType, nestedObjectSupplier).build();
MBean mbean = MBeanBuilder.from(nestedObjectType, nestedObjectSupplier).build();
ArrayList<MBeanFeature> features = new ArrayList<MBeanFeature>();
features.addAll(mbean.getAttributes());
features.addAll(mbean.getOperations());
Expand All @@ -153,13 +161,14 @@ else if (nested || AnnotationUtils.isNested(annotatedGetter)) {
throw new IllegalArgumentException("Nested JmxAttribute must have a concrete getter");
}

Class targetType = getNestedTargetType(concreteGetter);
if(targetType == null){
Class nestedObjectType = getNestedObjectType(concreteGetter);
if (nestedObjectType == null) {
return ImmutableList.of();
}
Supplier nestedObjectSupplier = createNestedObjectSupplier(targetType, concreteGetter);
long cacheDurationMillis = getNestedObjectCacheDuration(annotatedGetter);
Supplier nestedObjectSupplier = createNestedObjectSupplier(nestedObjectType, concreteGetter, cacheDurationMillis);

MBean mbean = MBeanBuilder.from(targetType, nestedObjectSupplier).build();
MBean mbean = MBeanBuilder.from(nestedObjectType, nestedObjectSupplier).build();
ArrayList<MBeanFeature> features = new ArrayList<MBeanFeature>();
for (MBeanAttribute attribute : mbean.getAttributes()) {
features.add(new NestedMBeanAttribute(attributeName, attribute));
Expand Down Expand Up @@ -236,7 +245,7 @@ private static String getAttributeName(Method... methods)
return null;
}

private Class getNestedTargetType(Method concreteGetter)
private Class getNestedObjectType(Method concreteGetter)
{
try {
Object value = concreteGetter.invoke(targetSupplier.get());
Expand All @@ -248,8 +257,24 @@ private Class getNestedTargetType(Method concreteGetter)
}
}

private Supplier createNestedObjectSupplier(final Class requiredType, final Method concreteGetter){
return new Supplier() {
private long getNestedObjectCacheDuration(Method annotatedGetter)
{
long cacheDurationMillis = -1;
Nested nestedAnnotation = AnnotationUtils.findAnnotation(Nested.class, annotatedGetter);
if (nestedAnnotation != null) {
cacheDurationMillis = nestedAnnotation.cacheDurationMillis();
}
Flatten flattenAnnotation = AnnotationUtils.findAnnotation(Flatten.class, annotatedGetter);
if (flattenAnnotation != null) {
cacheDurationMillis = flattenAnnotation.cacheDurationMillis();
}
return cacheDurationMillis;
}

private Supplier createNestedObjectSupplier(final Class requiredType, final Method concreteGetter, long cacheDurationMills)
{
Supplier supplier = new Supplier()
{
public Object get()
{
try {
Expand All @@ -261,5 +286,11 @@ public Object get()
}
}
};
if (cacheDurationMills >= 0) {
supplier = Suppliers.memoizeWithExpiration(supplier, cacheDurationMills, TimeUnit.MILLISECONDS);
} else {
supplier = Suppliers.memoize(supplier);
}
return supplier;
}
}
3 changes: 2 additions & 1 deletion src/main/java/org/weakref/jmx/Nested.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@
import java.lang.annotation.ElementType;

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@ManagedAnnotation
public @interface Nested
{
long cacheDurationMillis() default -1;
}
84 changes: 84 additions & 0 deletions src/test/java/org/weakref/jmx/TestExpiration.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package org.weakref.jmx;

import com.google.common.collect.Iterables;
import org.testng.annotations.Test;

import javax.management.Attribute;

import java.util.Collection;

import static org.testng.Assert.assertEquals;

public class TestExpiration
{
private static final long CACHE_DURATION_MILLIS = 100;
private static final String DEFAULT_VALUE = "DEFAULT_VALUE";
private static final String UPDATED_VALUE = "UPDATED_VALUE";

public static class SingleValueObject
{
private String value = DEFAULT_VALUE;

@Managed
public String getValue()
{
return value;
}

@Managed
public void setValue(String value)
{
this.value = value;
}
}

public static class NestedWithExpiration
{
@Nested(cacheDurationMillis = CACHE_DURATION_MILLIS)
public SingleValueObject getSingleValueObject()
{
return new SingleValueObject();
}
}

public static class FlattenWithExpiration
{
@Flatten(cacheDurationMillis = CACHE_DURATION_MILLIS)
public SingleValueObject getSingleValueObject()
{
return new SingleValueObject();
}
}

@Test
public void testFlatterExpiration()
throws Exception
{
testExpiration(new FlattenWithExpiration());
}

@Test
public void testNestedExpiration()
throws Exception
{
testExpiration(new NestedWithExpiration());
}

private void testExpiration(Object object)
throws Exception
{

MBean mBean = MBeanBuilder.from(object).build();
Collection<MBeanAttribute> attributes = mBean.getAttributes();
String attributeName = Iterables.getOnlyElement(attributes).getName();

assertEquals(mBean.getAttribute(attributeName), DEFAULT_VALUE);

mBean.setAttribute(new Attribute(attributeName, UPDATED_VALUE));
assertEquals(mBean.getAttribute(attributeName), UPDATED_VALUE);

Thread.sleep(CACHE_DURATION_MILLIS + 1);

assertEquals(mBean.getAttribute(attributeName), DEFAULT_VALUE);
}
}

0 comments on commit 8206093

Please sign in to comment.