org.gridkit.lab.util.jmx.mxstruct.MXStruct Maven / Gradle / Ivy
package org.gridkit.lab.util.jmx.mxstruct;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import javax.management.openmbean.CompositeData;
public abstract class MXStruct implements Cloneable {
public static ObjectName name(String name) {
try {
return new ObjectName(name);
} catch (MalformedObjectNameException e) {
throw new RuntimeException(e);
}
}
private Map meta;
private String[] attrNames;
private Map data;
private long timestamp = System.nanoTime();
protected MXStruct() {
meta = collectMeta();
attrNames = new String[meta.size()];
int n = 0;
for(AttrInfo ai: meta.values()) {
attrNames[n++] = ai.attrName;
}
}
private Map collectMeta() {
Map meta = new LinkedHashMap();
for(Method m : getClass().getMethods()) {
if (m.isAnnotationPresent(AttrName.class)) {
AttrName an = m.getAnnotation(AttrName.class);
AsObject ot = m.getAnnotation(AsObject.class);
AsCollection ct = m.getAnnotation(AsCollection.class);
AsMap mt = m.getAnnotation(AsMap.class);
int ac = (ot == null ? 0 : 1)
+(ct == null ? 0 : 1)
+(mt == null ? 0 : 1);
if (ac > 1) {
throw new IllegalArgumentException("You can specify only one \"As\" annotation for method");
}
AttrInfo ai = new AttrInfo();
ai.methodName = m.getName();
ai.attrName = an.value();
if (ot != null) {
Class> t = ot.value();
ai.converter = createConverter(t);
}
else if (ct != null) {
Class> t = ct.value();
ai.converter = new CollectionConverter(createConverter(t));
}
else if (mt != null) {
String key = mt.key();
String val = mt.val();
Class> t =mt.type();
ai.converter = new MapConverter(key, val, createConverter(t));
}
else if (MXStruct.class.isAssignableFrom(m.getReturnType())) {
Class> t = m.getReturnType();
ai.converter = createConverter(t);
}
meta.put(ai.methodName, ai);
}
}
return meta;
}
private Converter createConverter(Class> t) {
if (MXStruct.class.isAssignableFrom(t)) {
return new StructConverter(t);
}
else if (t == Void.class) {
return null;
}
else {
throw new IllegalArgumentException("Class " + t.getName() + " is not an " + MXStruct.class.getSimpleName());
}
}
/**
* @return value of {@link System#nanoTime()} at the moment of creation of MXStruct
*/
public long getMXStructTimestamp() {
return timestamp;
}
@SuppressWarnings("unchecked")
public V read(MBeanServerConnection conn, ObjectName name) throws ReflectionException, IOException {
MXStruct that;
that = (MXStruct) clone();
that.meta = meta;
that.attrNames = attrNames;
that.data = new LinkedHashMap();
try {
AttributeList al = conn.getAttributes(name, attrNames);
that.timestamp = System.nanoTime();
for (Attribute attr: al.asList()) {
that.data.put(attr.getName(), attr.getValue());
}
return (V) that;
}
catch(InstanceNotFoundException e) {
return null;
}
}
@SuppressWarnings("unchecked")
public V read(CompositeData cdata) {
MXStruct that;
that = (MXStruct) clone();
that.timestamp = System.nanoTime();
that.meta = meta;
that.attrNames = attrNames;
that.data = new LinkedHashMap();
for(String attr : attrNames) {
that.data.put(attr, cdata.get(attr));
}
return (V)that;
}
protected V getMXAttr() {
return getMXAttrInternal();
}
protected int getInt() {
return (Integer)getMXAttrInternal();
}
protected long getLong() {
return (Long)getMXAttrInternal();
}
protected boolean getBoolean() {
return (Boolean)getMXAttrInternal();
}
protected float getFloat() {
return (Float)getMXAttrInternal();
}
protected double getDouble() {
return (Double)getMXAttrInternal();
}
@SuppressWarnings("unchecked")
private V getMXAttrInternal() {
StackTraceElement[] trace = Thread.currentThread().getStackTrace();
String methodName = trace[3].getMethodName();
AttrInfo info = meta.get(methodName);
if (info == null) {
throw new IllegalArgumentException("Method " + methodName + " is not annotated with MBean meta data");
}
Object val = data.get(info.attrName);
if (val != null && info.converter != null) {
return (V) info.converter.convert(val);
}
else {
return (V) val;
}
}
@Override
protected Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
throw new Error("It is cloneable");
}
}
private class AttrInfo {
private String methodName;
private String attrName;
private Converter converter;
}
private interface Converter {
public Object convert(Object val);
}
private static class StructConverter implements Converter {
private MXStruct proto;
public StructConverter(Class> type) {
try {
this.proto = (MXStruct) type.newInstance();
} catch (InstantiationException e) {
throw new IllegalArgumentException("Cannot instantiate", e);
} catch (IllegalAccessException e) {
throw new IllegalArgumentException("Cannot instantiate", e);
}
}
@Override
public Object convert(Object val) {
return val == null ? null : proto.read((CompositeData) val);
}
}
private static class CollectionConverter implements Converter {
private Converter elementConverter;
public CollectionConverter(Converter elementConverter) {
this.elementConverter = elementConverter;
}
@Override
public Object convert(Object val) {
if (val == null) {
return null;
}
else {
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy