Merge
This commit is contained in:
commit
e23242de59
@ -369,6 +369,7 @@ TOOLS = \
|
||||
com/sun/jarsigner \
|
||||
com/sun/mirror \
|
||||
com/sun/source \
|
||||
com/sun/tools/classfile \
|
||||
com/sun/tools/doclets \
|
||||
com/sun/tools/example/debug/expr \
|
||||
com/sun/tools/example/debug/tty \
|
||||
@ -378,6 +379,7 @@ TOOLS = \
|
||||
com/sun/tools/javadoc \
|
||||
com/sun/tools/apt \
|
||||
com/sun/tools/javah \
|
||||
com/sun/tools/javap \
|
||||
com/sun/tools/corba \
|
||||
com/sun/tools/internal/xjc \
|
||||
com/sun/tools/internal/ws \
|
||||
@ -568,6 +570,8 @@ $(NOT_RT_JAR_LIST): FRC
|
||||
$(ECHO) "sun/tools/java/" >> $@
|
||||
$(ECHO) "sun/tools/javac/" >> $@
|
||||
$(ECHO) "sun/tools/javap/" >> $@
|
||||
$(ECHO) "com/sun/tools/classfile/" >> $@
|
||||
$(ECHO) "com/sun/tools/javap/" >> $@
|
||||
$(ECHO) "sun/tools/jconsole/" >> $@
|
||||
$(ECHO) "sun/tools/jps/" >> $@
|
||||
$(ECHO) "sun/tools/jstat/" >> $@
|
||||
|
@ -31,13 +31,15 @@ IMPORT_RT_PACKAGES += \
|
||||
javax/tools
|
||||
|
||||
IMPORT_TOOLS_PACKAGES += \
|
||||
com/sun/javadoc \
|
||||
com/sun/mirror \
|
||||
com/sun/source \
|
||||
com/sun/tools/apt \
|
||||
com/sun/tools/javac \
|
||||
com/sun/tools/javah \
|
||||
com/sun/tools/javadoc \
|
||||
com/sun/tools/classfile \
|
||||
com/sun/tools/doclets \
|
||||
com/sun/javadoc \
|
||||
com/sun/tools/javac \
|
||||
com/sun/tools/javadoc \
|
||||
com/sun/tools/javah \
|
||||
com/sun/tools/javap \
|
||||
sun/tools/javap
|
||||
|
||||
|
@ -31,13 +31,15 @@ import java.lang.reflect.Type;
|
||||
|
||||
import javax.management.Descriptor;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.openmbean.MXBeanMapping;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
import javax.management.openmbean.OpenDataException;
|
||||
import javax.management.openmbean.OpenType;
|
||||
|
||||
final class ConvertingMethod {
|
||||
static ConvertingMethod from(Method m) {
|
||||
static ConvertingMethod from(Method m, MXBeanMappingFactory mappingFactory) {
|
||||
try {
|
||||
return new ConvertingMethod(m);
|
||||
return new ConvertingMethod(m, mappingFactory);
|
||||
} catch (OpenDataException ode) {
|
||||
final String msg = "Method " + m.getDeclaringClass().getName() +
|
||||
"." + m.getName() + " has parameter or return type that " +
|
||||
@ -67,13 +69,13 @@ final class ConvertingMethod {
|
||||
}
|
||||
|
||||
OpenType getOpenReturnType() {
|
||||
return returnConverter.getOpenType();
|
||||
return returnMapping.getOpenType();
|
||||
}
|
||||
|
||||
OpenType[] getOpenParameterTypes() {
|
||||
final OpenType[] types = new OpenType[paramConverters.length];
|
||||
for (int i = 0; i < paramConverters.length; i++)
|
||||
types[i] = paramConverters[i].getOpenType();
|
||||
final OpenType[] types = new OpenType[paramMappings.length];
|
||||
for (int i = 0; i < paramMappings.length; i++)
|
||||
types[i] = paramMappings[i].getOpenType();
|
||||
return types;
|
||||
}
|
||||
|
||||
@ -85,9 +87,9 @@ final class ConvertingMethod {
|
||||
* value will be converted to an Open Type, so if it is convertible
|
||||
* at all there is no further check needed.
|
||||
*/
|
||||
void checkCallFromOpen() throws IllegalArgumentException {
|
||||
void checkCallFromOpen() {
|
||||
try {
|
||||
for (OpenConverter paramConverter : paramConverters)
|
||||
for (MXBeanMapping paramConverter : paramMappings)
|
||||
paramConverter.checkReconstructible();
|
||||
} catch (InvalidObjectException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
@ -102,32 +104,32 @@ final class ConvertingMethod {
|
||||
* open types, so if it is convertible at all there is no further
|
||||
* check needed.
|
||||
*/
|
||||
void checkCallToOpen() throws IllegalArgumentException {
|
||||
void checkCallToOpen() {
|
||||
try {
|
||||
returnConverter.checkReconstructible();
|
||||
returnMapping.checkReconstructible();
|
||||
} catch (InvalidObjectException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
String[] getOpenSignature() {
|
||||
if (paramConverters.length == 0)
|
||||
if (paramMappings.length == 0)
|
||||
return noStrings;
|
||||
|
||||
String[] sig = new String[paramConverters.length];
|
||||
for (int i = 0; i < paramConverters.length; i++)
|
||||
sig[i] = paramConverters[i].getOpenClass().getName();
|
||||
String[] sig = new String[paramMappings.length];
|
||||
for (int i = 0; i < paramMappings.length; i++)
|
||||
sig[i] = paramMappings[i].getOpenClass().getName();
|
||||
return sig;
|
||||
}
|
||||
|
||||
final Object toOpenReturnValue(MXBeanLookup lookup, Object ret)
|
||||
throws OpenDataException {
|
||||
return returnConverter.toOpenValue(lookup, ret);
|
||||
return returnMapping.toOpenValue(ret);
|
||||
}
|
||||
|
||||
final Object fromOpenReturnValue(MXBeanLookup lookup, Object ret)
|
||||
throws InvalidObjectException {
|
||||
return returnConverter.fromOpenValue(lookup, ret);
|
||||
return returnMapping.fromOpenValue(ret);
|
||||
}
|
||||
|
||||
final Object[] toOpenParameters(MXBeanLookup lookup, Object[] params)
|
||||
@ -136,17 +138,17 @@ final class ConvertingMethod {
|
||||
return params;
|
||||
final Object[] oparams = new Object[params.length];
|
||||
for (int i = 0; i < params.length; i++)
|
||||
oparams[i] = paramConverters[i].toOpenValue(lookup, params[i]);
|
||||
oparams[i] = paramMappings[i].toOpenValue(params[i]);
|
||||
return oparams;
|
||||
}
|
||||
|
||||
final Object[] fromOpenParameters(MXBeanLookup lookup, Object[] params)
|
||||
final Object[] fromOpenParameters(Object[] params)
|
||||
throws InvalidObjectException {
|
||||
if (paramConversionIsIdentity || params == null)
|
||||
return params;
|
||||
final Object[] jparams = new Object[params.length];
|
||||
for (int i = 0; i < params.length; i++)
|
||||
jparams[i] = paramConverters[i].fromOpenValue(lookup, params[i]);
|
||||
jparams[i] = paramMappings[i].fromOpenValue(params[i]);
|
||||
return jparams;
|
||||
}
|
||||
|
||||
@ -154,23 +156,35 @@ final class ConvertingMethod {
|
||||
Object param,
|
||||
int paramNo)
|
||||
throws OpenDataException {
|
||||
return paramConverters[paramNo].toOpenValue(lookup, param);
|
||||
return paramMappings[paramNo].toOpenValue(param);
|
||||
}
|
||||
|
||||
final Object fromOpenParameter(MXBeanLookup lookup,
|
||||
Object param,
|
||||
int paramNo)
|
||||
throws InvalidObjectException {
|
||||
return paramConverters[paramNo].fromOpenValue(lookup, param);
|
||||
return paramMappings[paramNo].fromOpenValue(param);
|
||||
}
|
||||
|
||||
Object invokeWithOpenReturn(MXBeanLookup lookup,
|
||||
Object obj, Object[] params)
|
||||
throws MBeanException, IllegalAccessException,
|
||||
InvocationTargetException {
|
||||
MXBeanLookup old = MXBeanLookup.getLookup();
|
||||
try {
|
||||
MXBeanLookup.setLookup(lookup);
|
||||
return invokeWithOpenReturn(obj, params);
|
||||
} finally {
|
||||
MXBeanLookup.setLookup(old);
|
||||
}
|
||||
}
|
||||
|
||||
private Object invokeWithOpenReturn(Object obj, Object[] params)
|
||||
throws MBeanException, IllegalAccessException,
|
||||
InvocationTargetException {
|
||||
final Object[] javaParams;
|
||||
try {
|
||||
javaParams = fromOpenParameters(lookup, params);
|
||||
javaParams = fromOpenParameters(params);
|
||||
} catch (InvalidObjectException e) {
|
||||
// probably can't happen
|
||||
final String msg = methodName() + ": cannot convert parameters " +
|
||||
@ -179,7 +193,7 @@ final class ConvertingMethod {
|
||||
}
|
||||
final Object javaReturn = method.invoke(obj, javaParams);
|
||||
try {
|
||||
return returnConverter.toOpenValue(lookup, javaReturn);
|
||||
return returnMapping.toOpenValue(javaReturn);
|
||||
} catch (OpenDataException e) {
|
||||
// probably can't happen
|
||||
final String msg = methodName() + ": cannot convert return " +
|
||||
@ -192,15 +206,17 @@ final class ConvertingMethod {
|
||||
return method.getDeclaringClass() + "." + method.getName();
|
||||
}
|
||||
|
||||
private ConvertingMethod(Method m) throws OpenDataException {
|
||||
private ConvertingMethod(Method m, MXBeanMappingFactory mappingFactory)
|
||||
throws OpenDataException {
|
||||
this.method = m;
|
||||
returnConverter = OpenConverter.toConverter(m.getGenericReturnType());
|
||||
returnMapping =
|
||||
mappingFactory.mappingForType(m.getGenericReturnType(), mappingFactory);
|
||||
Type[] params = m.getGenericParameterTypes();
|
||||
paramConverters = new OpenConverter[params.length];
|
||||
paramMappings = new MXBeanMapping[params.length];
|
||||
boolean identity = true;
|
||||
for (int i = 0; i < params.length; i++) {
|
||||
paramConverters[i] = OpenConverter.toConverter(params[i]);
|
||||
identity &= paramConverters[i].isIdentity();
|
||||
paramMappings[i] = mappingFactory.mappingForType(params[i], mappingFactory);
|
||||
identity &= DefaultMXBeanMappingFactory.isIdentity(paramMappings[i]);
|
||||
}
|
||||
paramConversionIsIdentity = identity;
|
||||
}
|
||||
@ -208,7 +224,7 @@ final class ConvertingMethod {
|
||||
private static final String[] noStrings = new String[0];
|
||||
|
||||
private final Method method;
|
||||
private final OpenConverter returnConverter;
|
||||
private final OpenConverter[] paramConverters;
|
||||
private final MXBeanMapping returnMapping;
|
||||
private final MXBeanMapping[] paramMappings;
|
||||
private final boolean paramConversionIsIdentity;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -42,7 +42,6 @@ import javax.management.ImmutableDescriptor;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
|
||||
import com.sun.jmx.mbeanserver.Util;
|
||||
import com.sun.jmx.remote.util.EnvHelp;
|
||||
import java.beans.BeanInfo;
|
||||
import java.beans.PropertyDescriptor;
|
||||
@ -50,6 +49,7 @@ import java.lang.reflect.Array;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import javax.management.AttributeNotFoundException;
|
||||
import javax.management.openmbean.CompositeData;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
|
||||
/**
|
||||
* This class contains the methods for performing all the tests needed to verify
|
||||
@ -165,30 +165,34 @@ public class Introspector {
|
||||
throw new NotCompliantMBeanException(msg);
|
||||
}
|
||||
|
||||
public static DynamicMBean makeDynamicMBean(Object mbean)
|
||||
throws NotCompliantMBeanException {
|
||||
public static <T> DynamicMBean makeDynamicMBean(T mbean)
|
||||
throws NotCompliantMBeanException {
|
||||
if (mbean == null)
|
||||
throw new NotCompliantMBeanException("Null MBean object");
|
||||
if (mbean instanceof DynamicMBean)
|
||||
return (DynamicMBean) mbean;
|
||||
final Class mbeanClass = mbean.getClass();
|
||||
Class<?> c = null;
|
||||
Class<? super T> c = null;
|
||||
try {
|
||||
c = getStandardMBeanInterface(mbeanClass);
|
||||
c = Util.cast(getStandardMBeanInterface(mbeanClass));
|
||||
} catch (NotCompliantMBeanException e) {
|
||||
// Ignore exception - we need to check whether
|
||||
// mbean is an MXBean first.
|
||||
}
|
||||
if (c != null)
|
||||
return new StandardMBeanSupport(mbean, Util.<Class<Object>>cast(c));
|
||||
return new StandardMBeanSupport(mbean, c);
|
||||
|
||||
try {
|
||||
c = getMXBeanInterface(mbeanClass);
|
||||
c = Util.cast(getMXBeanInterface(mbeanClass));
|
||||
} catch (NotCompliantMBeanException e) {
|
||||
// Ignore exception - we cannot decide whether mbean was supposed
|
||||
// to be an MBean or an MXBean. We will call checkCompliance()
|
||||
// to generate the appropriate exception.
|
||||
}
|
||||
if (c != null)
|
||||
return new MXBeanSupport(mbean, Util.<Class<Object>>cast(c));
|
||||
if (c != null) {
|
||||
MXBeanMappingFactory factory = MXBeanMappingFactory.forInterface(c);
|
||||
return new MXBeanSupport(mbean, c, factory);
|
||||
}
|
||||
checkCompliance(mbeanClass);
|
||||
throw new NotCompliantMBeanException("Not compliant"); // not reached
|
||||
}
|
||||
@ -217,9 +221,10 @@ public class Introspector {
|
||||
return testCompliance(baseClass, null);
|
||||
}
|
||||
|
||||
public static void testComplianceMXBeanInterface(Class interfaceClass)
|
||||
public static void testComplianceMXBeanInterface(Class interfaceClass,
|
||||
MXBeanMappingFactory factory)
|
||||
throws NotCompliantMBeanException {
|
||||
MXBeanIntrospector.getInstance().getAnalyzer(interfaceClass);
|
||||
MXBeanIntrospector.getInstance(factory).getAnalyzer(interfaceClass);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -325,6 +330,15 @@ public class Introspector {
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> Class<? super T> getStandardOrMXBeanInterface(
|
||||
Class<T> baseClass, boolean mxbean)
|
||||
throws NotCompliantMBeanException {
|
||||
if (mxbean)
|
||||
return getMXBeanInterface(baseClass);
|
||||
else
|
||||
return getStandardMBeanInterface(baseClass);
|
||||
}
|
||||
|
||||
/*
|
||||
* ------------------------------------------
|
||||
* PRIVATE METHODS
|
||||
|
@ -29,13 +29,10 @@ import static com.sun.jmx.mbeanserver.Util.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
|
||||
/**
|
||||
@ -54,15 +51,15 @@ import javax.management.NotCompliantMBeanException;
|
||||
*/
|
||||
class MBeanAnalyzer<M> {
|
||||
|
||||
static interface MBeanVisitor<M> {
|
||||
static interface MBeanVisitor<M, X extends Exception> {
|
||||
public void visitAttribute(String attributeName,
|
||||
M getter,
|
||||
M setter);
|
||||
M setter) throws X;
|
||||
public void visitOperation(String operationName,
|
||||
M operation);
|
||||
M operation) throws X;
|
||||
}
|
||||
|
||||
void visit(MBeanVisitor<M> visitor) {
|
||||
<X extends Exception> void visit(MBeanVisitor<M, X> visitor) throws X {
|
||||
// visit attributes
|
||||
for (Map.Entry<String, AttrMethods<M>> entry : attrMap.entrySet()) {
|
||||
String name = entry.getKey();
|
||||
@ -98,21 +95,21 @@ class MBeanAnalyzer<M> {
|
||||
// cached PerInterface object for an MBean interface means that
|
||||
// an analyzer will not be recreated for a second MBean using the
|
||||
// same interface.
|
||||
static <M> MBeanAnalyzer<M> analyzer(Class<?> mbeanInterface,
|
||||
static <M> MBeanAnalyzer<M> analyzer(Class<?> mbeanType,
|
||||
MBeanIntrospector<M> introspector)
|
||||
throws NotCompliantMBeanException {
|
||||
return new MBeanAnalyzer<M>(mbeanInterface, introspector);
|
||||
return new MBeanAnalyzer<M>(mbeanType, introspector);
|
||||
}
|
||||
|
||||
private MBeanAnalyzer(Class<?> mbeanInterface,
|
||||
private MBeanAnalyzer(Class<?> mbeanType,
|
||||
MBeanIntrospector<M> introspector)
|
||||
throws NotCompliantMBeanException {
|
||||
introspector.checkCompliance(mbeanInterface);
|
||||
introspector.checkCompliance(mbeanType);
|
||||
|
||||
try {
|
||||
initMaps(mbeanInterface, introspector);
|
||||
initMaps(mbeanType, introspector);
|
||||
} catch (Exception x) {
|
||||
throw Introspector.throwException(mbeanInterface,x);
|
||||
throw Introspector.throwException(mbeanType,x);
|
||||
}
|
||||
}
|
||||
|
||||
@ -126,7 +123,8 @@ class MBeanAnalyzer<M> {
|
||||
/* Run through the methods to detect inconsistencies and to enable
|
||||
us to give getter and setter together to visitAttribute. */
|
||||
for (Method m : methods) {
|
||||
String name = m.getName();
|
||||
final String name = m.getName();
|
||||
final int nParams = m.getParameterTypes().length;
|
||||
|
||||
final M cm = introspector.mFrom(m);
|
||||
|
||||
@ -137,7 +135,7 @@ class MBeanAnalyzer<M> {
|
||||
&& m.getReturnType() == boolean.class)
|
||||
attrName = name.substring(2);
|
||||
|
||||
if (attrName.length() != 0 && m.getParameterTypes().length == 0
|
||||
if (attrName.length() != 0 && nParams == 0
|
||||
&& m.getReturnType() != void.class) {
|
||||
// It's a getter
|
||||
// Check we don't have both isX and getX
|
||||
@ -154,7 +152,7 @@ class MBeanAnalyzer<M> {
|
||||
am.getter = cm;
|
||||
attrMap.put(attrName, am);
|
||||
} else if (name.startsWith("set") && name.length() > 3
|
||||
&& m.getParameterTypes().length == 1 &&
|
||||
&& nParams == 1 &&
|
||||
m.getReturnType() == void.class) {
|
||||
// It's a setter
|
||||
attrName = name.substring(3);
|
||||
@ -228,7 +226,11 @@ class MBeanAnalyzer<M> {
|
||||
but only the overriding one is of interest. We return the methods
|
||||
in the same order they arrived in. This isn't required by the spec
|
||||
but existing code may depend on it and users may be used to seeing
|
||||
operations or attributes appear in a particular order. */
|
||||
operations or attributes appear in a particular order.
|
||||
|
||||
Because of the way this method works, if the same Method appears
|
||||
more than once in the given List then it will be completely deleted!
|
||||
So don't do that. */
|
||||
static List<Method>
|
||||
eliminateCovariantMethods(List<Method> startMethods) {
|
||||
// We are assuming that you never have very many methods with the
|
||||
@ -243,7 +245,7 @@ class MBeanAnalyzer<M> {
|
||||
final Method m0 = sorted[i-1];
|
||||
final Method m1 = sorted[i];
|
||||
|
||||
// Methods that don't have the same name can't override each others
|
||||
// Methods that don't have the same name can't override each other
|
||||
if (!m0.getName().equals(m1.getName())) continue;
|
||||
|
||||
// Methods that have the same name and same signature override
|
||||
@ -251,7 +253,8 @@ class MBeanAnalyzer<M> {
|
||||
// due to the way we have sorted them in MethodOrder.
|
||||
if (Arrays.equals(m0.getParameterTypes(),
|
||||
m1.getParameterTypes())) {
|
||||
overridden.add(m0);
|
||||
if (!overridden.add(m0))
|
||||
throw new RuntimeException("Internal error: duplicate Method");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,7 @@ import java.util.WeakHashMap;
|
||||
|
||||
import javax.management.Descriptor;
|
||||
import javax.management.ImmutableDescriptor;
|
||||
import javax.management.IntrospectionException;
|
||||
import javax.management.InvalidAttributeValueException;
|
||||
import javax.management.MBeanAttributeInfo;
|
||||
import javax.management.MBeanConstructorInfo;
|
||||
@ -53,8 +54,9 @@ import javax.management.ReflectionException;
|
||||
|
||||
/**
|
||||
* An introspector for MBeans of a certain type. There is one instance
|
||||
* of this class for Standard MBeans and one for MXBeans, characterized
|
||||
* by the two concrete subclasses of this abstract class.
|
||||
* of this class for Standard MBeans, and one for every MXBeanMappingFactory;
|
||||
* these two cases correspond to the two concrete subclasses of this abstract
|
||||
* class.
|
||||
*
|
||||
* @param <M> the representation of methods for this kind of MBean:
|
||||
* Method for Standard MBeans, ConvertingMethod for MXBeans.
|
||||
@ -119,7 +121,7 @@ abstract class MBeanIntrospector<M> {
|
||||
* MXBean interface is not valid if one of its parameters cannot be
|
||||
* mapped to an Open Type.
|
||||
*/
|
||||
abstract void checkMethod(M m) throws IllegalArgumentException;
|
||||
abstract void checkMethod(M m);
|
||||
|
||||
/**
|
||||
* Invoke the method with the given target and arguments.
|
||||
@ -149,7 +151,8 @@ abstract class MBeanIntrospector<M> {
|
||||
* may be null.
|
||||
*/
|
||||
abstract MBeanAttributeInfo getMBeanAttributeInfo(String attributeName,
|
||||
M getter, M setter);
|
||||
M getter, M setter) throws IntrospectionException;
|
||||
|
||||
/**
|
||||
* Construct an MBeanOperationInfo for the given operation based on
|
||||
* the M it was derived from.
|
||||
@ -170,6 +173,16 @@ abstract class MBeanIntrospector<M> {
|
||||
*/
|
||||
abstract Descriptor getMBeanDescriptor(Class<?> resourceClass);
|
||||
|
||||
/**
|
||||
* Get any additional Descriptor entries for this introspector instance.
|
||||
* If there is a non-default MXBeanMappingFactory, it will appear in
|
||||
* this Descriptor.
|
||||
* @return Additional Descriptor entries, or an empty Descriptor if none.
|
||||
*/
|
||||
Descriptor getSpecificMBeanDescriptor() {
|
||||
return ImmutableDescriptor.EMPTY_DESCRIPTOR;
|
||||
}
|
||||
|
||||
void checkCompliance(Class<?> mbeanType) throws NotCompliantMBeanException {
|
||||
if (!mbeanType.isInterface()) {
|
||||
throw new NotCompliantMBeanException("Not an interface: " +
|
||||
@ -216,7 +229,7 @@ abstract class MBeanIntrospector<M> {
|
||||
* the MBeanInfo's Descriptor.
|
||||
*/
|
||||
private MBeanInfo makeInterfaceMBeanInfo(Class<?> mbeanInterface,
|
||||
MBeanAnalyzer<M> analyzer) {
|
||||
MBeanAnalyzer<M> analyzer) throws IntrospectionException {
|
||||
final MBeanInfoMaker maker = new MBeanInfoMaker();
|
||||
analyzer.visit(maker);
|
||||
final String description =
|
||||
@ -317,11 +330,12 @@ abstract class MBeanIntrospector<M> {
|
||||
}
|
||||
|
||||
/** A visitor that constructs the per-interface MBeanInfo. */
|
||||
private class MBeanInfoMaker implements MBeanAnalyzer.MBeanVisitor<M> {
|
||||
private class MBeanInfoMaker
|
||||
implements MBeanAnalyzer.MBeanVisitor<M, IntrospectionException> {
|
||||
|
||||
public void visitAttribute(String attributeName,
|
||||
M getter,
|
||||
M setter) {
|
||||
M setter) throws IntrospectionException {
|
||||
MBeanAttributeInfo mbai =
|
||||
getMBeanAttributeInfo(attributeName, getter, setter);
|
||||
|
||||
@ -346,13 +360,14 @@ abstract class MBeanIntrospector<M> {
|
||||
ops.toArray(new MBeanOperationInfo[0]);
|
||||
final String interfaceClassName =
|
||||
"interfaceClassName=" + mbeanInterface.getName();
|
||||
final Descriptor interfDescriptor =
|
||||
final Descriptor classNameDescriptor =
|
||||
new ImmutableDescriptor(interfaceClassName);
|
||||
final Descriptor mbeanDescriptor = getBasicMBeanDescriptor();
|
||||
final Descriptor annotatedDescriptor =
|
||||
Introspector.descriptorForElement(mbeanInterface);
|
||||
final Descriptor descriptor =
|
||||
DescriptorCache.getInstance().union(interfDescriptor,
|
||||
DescriptorCache.getInstance().union(
|
||||
classNameDescriptor,
|
||||
mbeanDescriptor,
|
||||
annotatedDescriptor);
|
||||
|
||||
@ -388,20 +403,24 @@ abstract class MBeanIntrospector<M> {
|
||||
* Return the MBeanInfo for the given resource, based on the given
|
||||
* per-interface data.
|
||||
*/
|
||||
final MBeanInfo getMBeanInfo(Object resource, PerInterface<M> perInterface) {
|
||||
final MBeanInfo getMBeanInfo(Object resource, PerInterface<M> perInterface)
|
||||
throws NotCompliantMBeanException {
|
||||
MBeanInfo mbi =
|
||||
getClassMBeanInfo(resource.getClass(), perInterface);
|
||||
MBeanNotificationInfo[] notifs = findNotifications(resource);
|
||||
if (notifs == null || notifs.length == 0)
|
||||
Descriptor d = getSpecificMBeanDescriptor();
|
||||
boolean anyNotifs = (notifs != null && notifs.length > 0);
|
||||
if (!anyNotifs && ImmutableDescriptor.EMPTY_DESCRIPTOR.equals(d))
|
||||
return mbi;
|
||||
else {
|
||||
d = ImmutableDescriptor.union(d, mbi.getDescriptor());
|
||||
return new MBeanInfo(mbi.getClassName(),
|
||||
mbi.getDescription(),
|
||||
mbi.getAttributes(),
|
||||
mbi.getConstructors(),
|
||||
mbi.getOperations(),
|
||||
notifs,
|
||||
mbi.getDescriptor());
|
||||
d);
|
||||
}
|
||||
}
|
||||
|
||||
@ -446,7 +465,7 @@ abstract class MBeanIntrospector<M> {
|
||||
return null;
|
||||
MBeanNotificationInfo[] mbn =
|
||||
((NotificationBroadcaster) moi).getNotificationInfo();
|
||||
if (mbn == null)
|
||||
if (mbn == null || mbn.length == 0)
|
||||
return null;
|
||||
MBeanNotificationInfo[] result =
|
||||
new MBeanNotificationInfo[mbn.length];
|
||||
|
@ -38,6 +38,7 @@ import javax.management.MBeanServer;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.ReflectionException;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
|
||||
/**
|
||||
* Base class for MBeans. There is one instance of this class for
|
||||
@ -121,24 +122,26 @@ import javax.management.ReflectionException;
|
||||
public abstract class MBeanSupport<M>
|
||||
implements DynamicMBean2, MBeanRegistration {
|
||||
|
||||
<T> MBeanSupport(T resource, Class<T> mbeanInterface)
|
||||
<T> MBeanSupport(T resource, Class<T> mbeanInterfaceType,
|
||||
MXBeanMappingFactory mappingFactory)
|
||||
throws NotCompliantMBeanException {
|
||||
if (mbeanInterface == null)
|
||||
if (mbeanInterfaceType == null)
|
||||
throw new NotCompliantMBeanException("Null MBean interface");
|
||||
if (!mbeanInterface.isInstance(resource)) {
|
||||
if (!mbeanInterfaceType.isInstance(resource)) {
|
||||
final String msg =
|
||||
"Resource class " + resource.getClass().getName() +
|
||||
" is not an instance of " + mbeanInterface.getName();
|
||||
" is not an instance of " + mbeanInterfaceType.getName();
|
||||
throw new NotCompliantMBeanException(msg);
|
||||
}
|
||||
this.resource = resource;
|
||||
MBeanIntrospector<M> introspector = getMBeanIntrospector();
|
||||
this.perInterface = introspector.getPerInterface(mbeanInterface);
|
||||
MBeanIntrospector<M> introspector = getMBeanIntrospector(mappingFactory);
|
||||
this.perInterface = introspector.getPerInterface(mbeanInterfaceType);
|
||||
this.mbeanInfo = introspector.getMBeanInfo(resource, perInterface);
|
||||
}
|
||||
|
||||
/** Return the appropriate introspector for this type of MBean. */
|
||||
abstract MBeanIntrospector<M> getMBeanIntrospector();
|
||||
abstract MBeanIntrospector<M>
|
||||
getMBeanIntrospector(MXBeanMappingFactory mappingFactory);
|
||||
|
||||
/**
|
||||
* Return a cookie for this MBean. This cookie will be passed to
|
||||
@ -162,9 +165,8 @@ public abstract class MBeanSupport<M>
|
||||
public final ObjectName preRegister(MBeanServer server, ObjectName name)
|
||||
throws Exception {
|
||||
if (resource instanceof MBeanRegistration)
|
||||
return ((MBeanRegistration) resource).preRegister(server, name);
|
||||
else
|
||||
return name;
|
||||
name = ((MBeanRegistration) resource).preRegister(server, name);
|
||||
return name;
|
||||
}
|
||||
|
||||
public final void preRegister2(MBeanServer server, ObjectName name)
|
||||
|
@ -25,18 +25,26 @@
|
||||
|
||||
package com.sun.jmx.mbeanserver;
|
||||
|
||||
import com.sun.jmx.mbeanserver.MBeanIntrospector.MBeanInfoMap;
|
||||
import com.sun.jmx.mbeanserver.MBeanIntrospector.PerInterfaceMap;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.GenericArrayType;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import javax.management.Descriptor;
|
||||
import javax.management.ImmutableDescriptor;
|
||||
import javax.management.IntrospectionException;
|
||||
import javax.management.JMX;
|
||||
import javax.management.MBeanAttributeInfo;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.MBeanOperationInfo;
|
||||
import javax.management.MBeanParameterInfo;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
import javax.management.openmbean.OpenMBeanAttributeInfoSupport;
|
||||
import javax.management.openmbean.OpenMBeanOperationInfoSupport;
|
||||
import javax.management.openmbean.OpenMBeanParameterInfo;
|
||||
@ -49,10 +57,36 @@ import javax.management.openmbean.OpenType;
|
||||
* @since 1.6
|
||||
*/
|
||||
class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {
|
||||
private static final MXBeanIntrospector instance = new MXBeanIntrospector();
|
||||
/* We keep one MXBeanIntrospector per MXBeanMappingFactory, since the results
|
||||
* of the introspection depend on the factory. The MXBeanIntrospector
|
||||
* has a reference back to the factory, so we wrap it in a WeakReference.
|
||||
* It will be strongly referenced by any MXBeanSupport instances using it;
|
||||
* if there are none then it is OK to gc it.
|
||||
*/
|
||||
private static final
|
||||
Map<MXBeanMappingFactory, WeakReference<MXBeanIntrospector>> map =
|
||||
new WeakHashMap<MXBeanMappingFactory, WeakReference<MXBeanIntrospector>>();
|
||||
|
||||
static MXBeanIntrospector getInstance() {
|
||||
return instance;
|
||||
static MXBeanIntrospector getInstance(MXBeanMappingFactory factory) {
|
||||
if (factory == null)
|
||||
factory = MXBeanMappingFactory.DEFAULT;
|
||||
synchronized (map) {
|
||||
MXBeanIntrospector intro;
|
||||
WeakReference<MXBeanIntrospector> wr = map.get(factory);
|
||||
if (wr != null) {
|
||||
intro = wr.get();
|
||||
if (intro != null)
|
||||
return intro;
|
||||
}
|
||||
intro = new MXBeanIntrospector(factory);
|
||||
wr = new WeakReference<MXBeanIntrospector>(intro);
|
||||
map.put(factory, wr);
|
||||
return intro;
|
||||
}
|
||||
}
|
||||
|
||||
private MXBeanIntrospector(MXBeanMappingFactory factory) {
|
||||
this.mappingFactory = factory;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -78,7 +112,7 @@ class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {
|
||||
|
||||
@Override
|
||||
ConvertingMethod mFrom(Method m) {
|
||||
return ConvertingMethod.from(m);
|
||||
return ConvertingMethod.from(m, mappingFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -139,7 +173,8 @@ class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {
|
||||
|
||||
@Override
|
||||
MBeanAttributeInfo getMBeanAttributeInfo(String attributeName,
|
||||
ConvertingMethod getter, ConvertingMethod setter) {
|
||||
ConvertingMethod getter, ConvertingMethod setter)
|
||||
throws IntrospectionException {
|
||||
|
||||
final boolean isReadable = (getter != null);
|
||||
final boolean isWritable = (setter != null);
|
||||
@ -222,14 +257,14 @@ class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {
|
||||
Introspector.descriptorForAnnotations(annots[i]));
|
||||
final MBeanParameterInfo pi;
|
||||
if (canUseOpenInfo(originalType)) {
|
||||
pi = new OpenMBeanParameterInfoSupport("p" + i,
|
||||
pi = new OpenMBeanParameterInfoSupport(paramName,
|
||||
paramDescription,
|
||||
openType,
|
||||
descriptor);
|
||||
} else {
|
||||
openParameterTypes = false;
|
||||
pi = new MBeanParameterInfo(
|
||||
"p" + i,
|
||||
paramName,
|
||||
originalTypeString(originalType),
|
||||
paramDescription,
|
||||
descriptor);
|
||||
@ -291,6 +326,17 @@ class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {
|
||||
return ImmutableDescriptor.EMPTY_DESCRIPTOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
Descriptor getSpecificMBeanDescriptor() {
|
||||
if (mappingFactory == MXBeanMappingFactory.DEFAULT)
|
||||
return ImmutableDescriptor.EMPTY_DESCRIPTOR;
|
||||
else {
|
||||
return new ImmutableDescriptor(
|
||||
JMX.MXBEAN_MAPPING_FACTORY_CLASS_FIELD + "=" +
|
||||
mappingFactory.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
private static Descriptor typeDescriptor(OpenType openType,
|
||||
Type originalType) {
|
||||
return new ImmutableDescriptor(
|
||||
@ -331,8 +377,10 @@ class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {
|
||||
return type.toString();
|
||||
}
|
||||
|
||||
private static final PerInterfaceMap<ConvertingMethod>
|
||||
private final PerInterfaceMap<ConvertingMethod>
|
||||
perInterfaceMap = new PerInterfaceMap<ConvertingMethod>();
|
||||
|
||||
private static final MBeanInfoMap mbeanInfoMap = new MBeanInfoMap();
|
||||
private final MBeanInfoMap mbeanInfoMap = new MBeanInfoMap();
|
||||
|
||||
private final MXBeanMappingFactory mappingFactory;
|
||||
}
|
||||
|
@ -25,15 +25,21 @@
|
||||
|
||||
package com.sun.jmx.mbeanserver;
|
||||
|
||||
import com.sun.jmx.remote.util.EnvHelp;
|
||||
import java.io.InvalidObjectException;
|
||||
import static com.sun.jmx.mbeanserver.Util.*;
|
||||
import java.util.Map;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.security.AccessController;
|
||||
import javax.management.InstanceAlreadyExistsException;
|
||||
import javax.management.JMX;
|
||||
import javax.management.MBeanServerConnection;
|
||||
import javax.management.MBeanServerInvocationHandler;
|
||||
import javax.management.MalformedObjectNameException;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.openmbean.OpenDataException;
|
||||
|
||||
/**
|
||||
* @since 1.6
|
||||
@ -80,71 +86,199 @@ import javax.management.ObjectName;
|
||||
*
|
||||
* From the above, it is clear that the logic for getX on an MXBean is
|
||||
* the same as for setX on a proxy, and vice versa.
|
||||
*
|
||||
* The above describes the logic for "plain" MXBeanLookup, represented
|
||||
* by MXBeanLookup.Plain. When namespaces enter the picture, we see
|
||||
* MXBeanLookup.Prefix. Here, the idea is that the name of the ModuleMXBean
|
||||
* might be a//m:m=m. In this case, we don't accept a reference to
|
||||
* an MXBean object, since that would require different namespaces to know
|
||||
* each others' objects. We only accept proxies. Suppose you have a proxy
|
||||
* for a//m:m=m, call it moduleProxy, and you call
|
||||
* moduleProxy.setProduct(productProxy). Then if productProxy is for
|
||||
* a//p:p=p we should convert this to just p:p=p. If productProxy is for
|
||||
* a//b//p:p=p we should convert it to b//p:p=p. Conversely, if getProduct
|
||||
* returns an ObjectName like b//p:p=p then we should convert it into a proxy
|
||||
* for a//b//p:p=p.
|
||||
*/
|
||||
public class MXBeanLookup {
|
||||
public abstract class MXBeanLookup {
|
||||
private MXBeanLookup(MBeanServerConnection mbsc) {
|
||||
this.mbsc = mbsc;
|
||||
}
|
||||
|
||||
static MXBeanLookup lookupFor(MBeanServerConnection mbsc) {
|
||||
synchronized (mbscToLookup) {
|
||||
WeakReference<MXBeanLookup> weakLookup = mbscToLookup.get(mbsc);
|
||||
MXBeanLookup lookup = (weakLookup == null) ? null : weakLookup.get();
|
||||
if (lookup == null) {
|
||||
lookup = new MXBeanLookup(mbsc);
|
||||
mbscToLookup.put(mbsc, new WeakReference<MXBeanLookup>(lookup));
|
||||
static MXBeanLookup lookupFor(MBeanServerConnection mbsc, String prefix) {
|
||||
if (prefix == null)
|
||||
return Plain.lookupFor(mbsc);
|
||||
else
|
||||
return new Prefix(mbsc, prefix);
|
||||
}
|
||||
|
||||
abstract <T> T objectNameToMXBean(ObjectName name, Class<T> type)
|
||||
throws InvalidObjectException;
|
||||
|
||||
abstract ObjectName mxbeanToObjectName(Object mxbean)
|
||||
throws OpenDataException;
|
||||
|
||||
static class Plain extends MXBeanLookup {
|
||||
Plain(MBeanServerConnection mbsc) {
|
||||
super(mbsc);
|
||||
}
|
||||
|
||||
static Plain lookupFor(MBeanServerConnection mbsc) {
|
||||
synchronized (mbscToLookup) {
|
||||
WeakReference<Plain> weakLookup = mbscToLookup.get(mbsc);
|
||||
Plain lookup = (weakLookup == null) ? null : weakLookup.get();
|
||||
if (lookup == null) {
|
||||
lookup = new Plain(mbsc);
|
||||
mbscToLookup.put(mbsc, new WeakReference<Plain>(lookup));
|
||||
}
|
||||
return lookup;
|
||||
}
|
||||
return lookup;
|
||||
}
|
||||
|
||||
@Override
|
||||
synchronized <T> T objectNameToMXBean(ObjectName name, Class<T> type) {
|
||||
WeakReference<Object> wr = objectNameToProxy.get(name);
|
||||
if (wr != null) {
|
||||
Object proxy = wr.get();
|
||||
if (type.isInstance(proxy))
|
||||
return type.cast(proxy);
|
||||
}
|
||||
T proxy = JMX.newMXBeanProxy(mbsc, name, type);
|
||||
objectNameToProxy.put(name, new WeakReference<Object>(proxy));
|
||||
return proxy;
|
||||
}
|
||||
|
||||
@Override
|
||||
synchronized ObjectName mxbeanToObjectName(Object mxbean)
|
||||
throws OpenDataException {
|
||||
String wrong;
|
||||
if (mxbean instanceof Proxy) {
|
||||
InvocationHandler ih = Proxy.getInvocationHandler(mxbean);
|
||||
if (ih instanceof MBeanServerInvocationHandler) {
|
||||
MBeanServerInvocationHandler mbsih =
|
||||
(MBeanServerInvocationHandler) ih;
|
||||
if (mbsih.getMBeanServerConnection().equals(mbsc))
|
||||
return mbsih.getObjectName();
|
||||
else
|
||||
wrong = "proxy for a different MBeanServer";
|
||||
} else
|
||||
wrong = "not a JMX proxy";
|
||||
} else {
|
||||
ObjectName name = mxbeanToObjectName.get(mxbean);
|
||||
if (name != null)
|
||||
return name;
|
||||
wrong = "not an MXBean registered in this MBeanServer";
|
||||
}
|
||||
String s = (mxbean == null) ?
|
||||
"null" : "object of type " + mxbean.getClass().getName();
|
||||
throw new OpenDataException(
|
||||
"Could not convert " + s + " to an ObjectName: " + wrong);
|
||||
// Message will be strange if mxbean is null but it is not
|
||||
// supposed to be.
|
||||
}
|
||||
|
||||
synchronized void addReference(ObjectName name, Object mxbean)
|
||||
throws InstanceAlreadyExistsException {
|
||||
ObjectName existing = mxbeanToObjectName.get(mxbean);
|
||||
if (existing != null) {
|
||||
String multiname = AccessController.doPrivileged(
|
||||
new GetPropertyAction("jmx.mxbean.multiname"));
|
||||
if (!"true".equalsIgnoreCase(multiname)) {
|
||||
throw new InstanceAlreadyExistsException(
|
||||
"MXBean already registered with name " + existing);
|
||||
}
|
||||
}
|
||||
mxbeanToObjectName.put(mxbean, name);
|
||||
}
|
||||
|
||||
synchronized boolean removeReference(ObjectName name, Object mxbean) {
|
||||
if (name.equals(mxbeanToObjectName.get(mxbean))) {
|
||||
mxbeanToObjectName.remove(mxbean);
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
/* removeReference can be called when the above condition fails,
|
||||
* notably if you try to register the same MXBean twice.
|
||||
*/
|
||||
}
|
||||
|
||||
private final WeakIdentityHashMap<Object, ObjectName>
|
||||
mxbeanToObjectName = WeakIdentityHashMap.make();
|
||||
private final Map<ObjectName, WeakReference<Object>>
|
||||
objectNameToProxy = newMap();
|
||||
private static WeakIdentityHashMap<MBeanServerConnection,
|
||||
WeakReference<Plain>>
|
||||
mbscToLookup = WeakIdentityHashMap.make();
|
||||
}
|
||||
|
||||
private static class Prefix extends MXBeanLookup {
|
||||
private final String prefix;
|
||||
|
||||
Prefix(MBeanServerConnection mbsc, String prefix) {
|
||||
super(mbsc);
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
@Override
|
||||
<T> T objectNameToMXBean(ObjectName name, Class<T> type)
|
||||
throws InvalidObjectException {
|
||||
String domain = prefix + name.getDomain();
|
||||
try {
|
||||
name = switchDomain(domain, name);
|
||||
} catch (MalformedObjectNameException e) {
|
||||
throw EnvHelp.initCause(
|
||||
new InvalidObjectException(e.getMessage()), e);
|
||||
}
|
||||
return JMX.newMXBeanProxy(mbsc, name, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
ObjectName mxbeanToObjectName(Object mxbean)
|
||||
throws OpenDataException {
|
||||
ObjectName name = proxyToObjectName(mxbean);
|
||||
String domain = name.getDomain();
|
||||
if (!domain.startsWith(prefix)) {
|
||||
throw new OpenDataException(
|
||||
"Proxy's name does not start with " + prefix + ": " + name);
|
||||
}
|
||||
try {
|
||||
name = switchDomain(domain.substring(prefix.length()), name);
|
||||
} catch (MalformedObjectNameException e) {
|
||||
throw EnvHelp.initCause(new OpenDataException(e.getMessage()), e);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
synchronized <T> T objectNameToMXBean(ObjectName name, Class<T> type) {
|
||||
WeakReference<Object> wr = objectNameToProxy.get(name);
|
||||
if (wr != null) {
|
||||
Object proxy = wr.get();
|
||||
if (type.isInstance(proxy))
|
||||
return type.cast(proxy);
|
||||
ObjectName proxyToObjectName(Object proxy) {
|
||||
InvocationHandler ih = Proxy.getInvocationHandler(proxy);
|
||||
if (ih instanceof MBeanServerInvocationHandler) {
|
||||
MBeanServerInvocationHandler mbsih =
|
||||
(MBeanServerInvocationHandler) ih;
|
||||
if (mbsih.getMBeanServerConnection().equals(mbsc))
|
||||
return mbsih.getObjectName();
|
||||
}
|
||||
T proxy = JMX.newMXBeanProxy(mbsc, name, type);
|
||||
objectNameToProxy.put(name, new WeakReference<Object>(proxy));
|
||||
return proxy;
|
||||
return null;
|
||||
}
|
||||
|
||||
synchronized ObjectName mxbeanToObjectName(Object mxbean) {
|
||||
if (mxbean instanceof Proxy) {
|
||||
InvocationHandler ih = Proxy.getInvocationHandler(mxbean);
|
||||
if (ih instanceof MBeanServerInvocationHandler) {
|
||||
MBeanServerInvocationHandler mbsih =
|
||||
(MBeanServerInvocationHandler) ih;
|
||||
if (mbsih.getMBeanServerConnection().equals(mbsc))
|
||||
return mbsih.getObjectName();
|
||||
}
|
||||
return null;
|
||||
} else
|
||||
return mxbeanToObjectName.get(mxbean);
|
||||
static MXBeanLookup getLookup() {
|
||||
return currentLookup.get();
|
||||
}
|
||||
|
||||
synchronized void addReference(ObjectName name, Object mxbean) {
|
||||
mxbeanToObjectName.put(mxbean, name);
|
||||
static void setLookup(MXBeanLookup lookup) {
|
||||
currentLookup.set(lookup);
|
||||
}
|
||||
|
||||
synchronized boolean removeReference(ObjectName name, Object mxbean) {
|
||||
if (name.equals(mxbeanToObjectName.get(mxbean))) {
|
||||
mxbeanToObjectName.remove(mxbean);
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
/* removeReference can be called when the above condition fails,
|
||||
* notably if you try to register the same MXBean twice.
|
||||
*/
|
||||
// Method temporarily added until we have ObjectName.switchDomain in the
|
||||
// public API. Note that this method DOES NOT PRESERVE the order of
|
||||
// keys in the ObjectName so it must not be used in the final release.
|
||||
static ObjectName switchDomain(String domain, ObjectName name)
|
||||
throws MalformedObjectNameException {
|
||||
return new ObjectName(domain, name.getKeyPropertyList());
|
||||
}
|
||||
|
||||
private final MBeanServerConnection mbsc;
|
||||
private final WeakIdentityHashMap<Object, ObjectName>
|
||||
mxbeanToObjectName = WeakIdentityHashMap.make();
|
||||
private final Map<ObjectName, WeakReference<Object>>
|
||||
objectNameToProxy = newMap();
|
||||
private static WeakIdentityHashMap<MBeanServerConnection,
|
||||
WeakReference<MXBeanLookup>>
|
||||
mbscToLookup = WeakIdentityHashMap.make();
|
||||
private static final ThreadLocal<MXBeanLookup> currentLookup =
|
||||
new ThreadLocal<MXBeanLookup>();
|
||||
|
||||
final MBeanServerConnection mbsc;
|
||||
}
|
||||
|
@ -27,14 +27,15 @@ package com.sun.jmx.mbeanserver;
|
||||
|
||||
import static com.sun.jmx.mbeanserver.Util.*;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.management.Attribute;
|
||||
import javax.management.MBeanServerConnection;
|
||||
import javax.management.MalformedObjectNameException;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
|
||||
/**
|
||||
<p>Helper class for an {@link InvocationHandler} that forwards methods from an
|
||||
@ -46,8 +47,7 @@ import javax.management.ObjectName;
|
||||
@since 1.6
|
||||
*/
|
||||
public class MXBeanProxy {
|
||||
public MXBeanProxy(Class<?> mxbeanInterface)
|
||||
throws IllegalArgumentException {
|
||||
public MXBeanProxy(Class<?> mxbeanInterface, MXBeanMappingFactory factory) {
|
||||
|
||||
if (mxbeanInterface == null)
|
||||
throw new IllegalArgumentException("Null parameter");
|
||||
@ -55,14 +55,15 @@ public class MXBeanProxy {
|
||||
final MBeanAnalyzer<ConvertingMethod> analyzer;
|
||||
try {
|
||||
analyzer =
|
||||
MXBeanIntrospector.getInstance().getAnalyzer(mxbeanInterface);
|
||||
MXBeanIntrospector.getInstance(factory).getAnalyzer(mxbeanInterface);
|
||||
} catch (NotCompliantMBeanException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
analyzer.visit(new Visitor());
|
||||
}
|
||||
|
||||
private class Visitor implements MBeanAnalyzer.MBeanVisitor<ConvertingMethod> {
|
||||
private class Visitor
|
||||
implements MBeanAnalyzer.MBeanVisitor<ConvertingMethod, RuntimeException> {
|
||||
public void visitAttribute(String attributeName,
|
||||
ConvertingMethod getter,
|
||||
ConvertingMethod setter) {
|
||||
@ -160,10 +161,29 @@ public class MXBeanProxy {
|
||||
|
||||
Handler handler = handlerMap.get(method);
|
||||
ConvertingMethod cm = handler.getConvertingMethod();
|
||||
MXBeanLookup lookup = MXBeanLookup.lookupFor(mbsc);
|
||||
Object[] openArgs = cm.toOpenParameters(lookup, args);
|
||||
Object result = handler.invoke(mbsc, name, openArgs);
|
||||
return cm.fromOpenReturnValue(lookup, result);
|
||||
String prefix = extractPrefix(name);
|
||||
MXBeanLookup lookup = MXBeanLookup.lookupFor(mbsc, prefix);
|
||||
MXBeanLookup oldLookup = MXBeanLookup.getLookup();
|
||||
try {
|
||||
MXBeanLookup.setLookup(lookup);
|
||||
Object[] openArgs = cm.toOpenParameters(lookup, args);
|
||||
Object result = handler.invoke(mbsc, name, openArgs);
|
||||
return cm.fromOpenReturnValue(lookup, result);
|
||||
} finally {
|
||||
MXBeanLookup.setLookup(oldLookup);
|
||||
}
|
||||
}
|
||||
|
||||
private static String extractPrefix(ObjectName name)
|
||||
throws MalformedObjectNameException {
|
||||
String domain = name.getDomain();
|
||||
int slashslash = domain.lastIndexOf("//");
|
||||
if (slashslash > 0 && domain.charAt(slashslash - 1) == '/')
|
||||
slashslash--;
|
||||
if (slashslash >= 0)
|
||||
return domain.substring(0, slashslash + 2);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
private final Map<Method, Handler> handlerMap = newMap();
|
||||
|
@ -35,6 +35,8 @@ import javax.management.JMX;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
import javax.management.openmbean.MXBeanMappingFactoryClass;
|
||||
|
||||
/**
|
||||
* Base class for MXBeans.
|
||||
@ -61,14 +63,16 @@ public class MXBeanSupport extends MBeanSupport<ConvertingMethod> {
|
||||
if it does not implement the class {@code mxbeanInterface} or if
|
||||
that class is not a valid MXBean interface.
|
||||
*/
|
||||
public <T> MXBeanSupport(T resource, Class<T> mxbeanInterface)
|
||||
public <T> MXBeanSupport(T resource, Class<T> mxbeanInterface,
|
||||
MXBeanMappingFactory mappingFactory)
|
||||
throws NotCompliantMBeanException {
|
||||
super(resource, mxbeanInterface);
|
||||
super(resource, mxbeanInterface, mappingFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
MBeanIntrospector<ConvertingMethod> getMBeanIntrospector() {
|
||||
return MXBeanIntrospector.getInstance();
|
||||
MBeanIntrospector<ConvertingMethod>
|
||||
getMBeanIntrospector(MXBeanMappingFactory mappingFactory) {
|
||||
return MXBeanIntrospector.getInstance(mappingFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -76,8 +80,7 @@ public class MXBeanSupport extends MBeanSupport<ConvertingMethod> {
|
||||
return mxbeanLookup;
|
||||
}
|
||||
|
||||
static Class<?> findMXBeanInterface(Class<?> resourceClass)
|
||||
throws IllegalArgumentException {
|
||||
static <T> Class<? super T> findMXBeanInterface(Class<T> resourceClass) {
|
||||
if (resourceClass == null)
|
||||
throw new IllegalArgumentException("Null resource class");
|
||||
final Set<Class<?>> intfs = transitiveInterfaces(resourceClass);
|
||||
@ -104,7 +107,7 @@ public class MXBeanSupport extends MBeanSupport<ConvertingMethod> {
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
if (candidates.iterator().hasNext()) {
|
||||
return candidates.iterator().next();
|
||||
return Util.cast(candidates.iterator().next());
|
||||
} else {
|
||||
final String msg =
|
||||
"Class " + resourceClass.getName() +
|
||||
@ -116,7 +119,7 @@ public class MXBeanSupport extends MBeanSupport<ConvertingMethod> {
|
||||
/* Return all interfaces inherited by this class, directly or
|
||||
* indirectly through the parent class and interfaces.
|
||||
*/
|
||||
private static Set<Class<?>> transitiveInterfaces(Class c) {
|
||||
private static Set<Class<?>> transitiveInterfaces(Class<?> c) {
|
||||
Set<Class<?>> set = newSet();
|
||||
transitiveInterfaces(c, set);
|
||||
return set;
|
||||
@ -127,7 +130,7 @@ public class MXBeanSupport extends MBeanSupport<ConvertingMethod> {
|
||||
if (c.isInterface())
|
||||
intfs.add(c);
|
||||
transitiveInterfaces(c.getSuperclass(), intfs);
|
||||
for (Class sup : c.getInterfaces())
|
||||
for (Class<?> sup : c.getInterfaces())
|
||||
transitiveInterfaces(sup, intfs);
|
||||
}
|
||||
|
||||
@ -157,12 +160,7 @@ public class MXBeanSupport extends MBeanSupport<ConvertingMethod> {
|
||||
// eventually we could have some logic to supply a default name
|
||||
|
||||
synchronized (lock) {
|
||||
if (this.objectName != null) {
|
||||
final String msg =
|
||||
"MXBean already registered with name " + this.objectName;
|
||||
throw new InstanceAlreadyExistsException(msg);
|
||||
}
|
||||
this.mxbeanLookup = MXBeanLookup.lookupFor(server);
|
||||
this.mxbeanLookup = MXBeanLookup.Plain.lookupFor(server);
|
||||
this.mxbeanLookup.addReference(name, getResource());
|
||||
this.objectName = name;
|
||||
}
|
||||
@ -171,12 +169,20 @@ public class MXBeanSupport extends MBeanSupport<ConvertingMethod> {
|
||||
@Override
|
||||
public void unregister() {
|
||||
synchronized (lock) {
|
||||
if (mxbeanLookup.removeReference(objectName, getResource()))
|
||||
objectName = null;
|
||||
if (mxbeanLookup != null) {
|
||||
if (mxbeanLookup.removeReference(objectName, getResource()))
|
||||
objectName = null;
|
||||
}
|
||||
// XXX: need to revisit the whole register/unregister logic in
|
||||
// the face of wrapping. The mxbeanLookup!=null test is a hack.
|
||||
// If you wrap an MXBean in a MyWrapperMBean and register it,
|
||||
// the lookup table should contain the wrapped object. But that
|
||||
// implies that MyWrapperMBean calls register, which today it
|
||||
// can't within the public API.
|
||||
}
|
||||
}
|
||||
private final Object lock = new Object(); // for mxbeanLookup and objectName
|
||||
|
||||
private Object lock = new Object(); // for mxbeanLookup and objectName
|
||||
private MXBeanLookup mxbeanLookup;
|
||||
private MXBeanLookup.Plain mxbeanLookup;
|
||||
private ObjectName objectName;
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.Notification;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
|
||||
/**
|
||||
* <p>A variant of {@code StandardMBeanSupport} where the only
|
||||
@ -48,7 +49,7 @@ public class NotificationMBeanSupport extends StandardMBeanSupport {
|
||||
}
|
||||
|
||||
@Override
|
||||
MBeanIntrospector<Method> getMBeanIntrospector() {
|
||||
MBeanIntrospector<Method> getMBeanIntrospector(MXBeanMappingFactory ignored) {
|
||||
return introspector;
|
||||
}
|
||||
|
||||
|
@ -231,7 +231,7 @@ final class PerInterface<M> {
|
||||
/**
|
||||
* Visitor that sets up the method maps (operations, getters, setters).
|
||||
*/
|
||||
private class InitMaps implements MBeanAnalyzer.MBeanVisitor<M> {
|
||||
private class InitMaps implements MBeanAnalyzer.MBeanVisitor<M, RuntimeException> {
|
||||
public void visitAttribute(String attributeName,
|
||||
M getter,
|
||||
M setter) {
|
||||
|
@ -25,14 +25,13 @@
|
||||
|
||||
package com.sun.jmx.mbeanserver;
|
||||
|
||||
import static com.sun.jmx.mbeanserver.Util.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
|
||||
/**
|
||||
* Base class for Standard MBeans.
|
||||
@ -61,11 +60,11 @@ public class StandardMBeanSupport extends MBeanSupport<Method> {
|
||||
*/
|
||||
public <T> StandardMBeanSupport(T resource, Class<T> mbeanInterface)
|
||||
throws NotCompliantMBeanException {
|
||||
super(resource, mbeanInterface);
|
||||
super(resource, mbeanInterface, (MXBeanMappingFactory) null);
|
||||
}
|
||||
|
||||
@Override
|
||||
MBeanIntrospector<Method> getMBeanIntrospector() {
|
||||
MBeanIntrospector<Method> getMBeanIntrospector(MXBeanMappingFactory ignored) {
|
||||
return StandardMBeanIntrospector.getInstance();
|
||||
}
|
||||
|
||||
|
@ -26,8 +26,17 @@
|
||||
package javax.management;
|
||||
|
||||
import com.sun.jmx.mbeanserver.Introspector;
|
||||
import com.sun.jmx.remote.util.ClassLogger;
|
||||
import java.beans.BeanInfo;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
|
||||
/**
|
||||
* Static methods from the JMX API. There are no instances of this class.
|
||||
@ -39,6 +48,8 @@ public class JMX {
|
||||
* this class.
|
||||
*/
|
||||
static final JMX proof = new JMX();
|
||||
private static final ClassLogger logger =
|
||||
new ClassLogger("javax.management.misc", "JMX");
|
||||
|
||||
private JMX() {}
|
||||
|
||||
@ -84,6 +95,14 @@ public class JMX {
|
||||
*/
|
||||
public static final String MXBEAN_FIELD = "mxbean";
|
||||
|
||||
/**
|
||||
* The name of the
|
||||
* <a href="Descriptor.html#mxbeanMappingFactoryClass">{@code
|
||||
* mxbeanMappingFactoryClass}</a> field.
|
||||
*/
|
||||
public static final String MXBEAN_MAPPING_FACTORY_CLASS_FIELD =
|
||||
"mxbeanMappingFactoryClass";
|
||||
|
||||
/**
|
||||
* The name of the <a href="Descriptor.html#openType">{@code
|
||||
* openType}</a> field.
|
||||
@ -96,6 +115,264 @@ public class JMX {
|
||||
*/
|
||||
public static final String ORIGINAL_TYPE_FIELD = "originalType";
|
||||
|
||||
/**
|
||||
* <p>Options to apply to an MBean proxy or to an instance of {@link
|
||||
* StandardMBean}.</p>
|
||||
*
|
||||
* <p>For example, to specify a custom {@link MXBeanMappingFactory}
|
||||
* for a {@code StandardMBean}, you might write this:</p>
|
||||
*
|
||||
* <pre>
|
||||
* MXBeanMappingFactory factory = new MyMXBeanMappingFactory();
|
||||
* JMX.MBeanOptions opts = new JMX.MBeanOptions();
|
||||
* opts.setMXBeanMappingFactory(factory);
|
||||
* StandardMBean mbean = new StandardMBean(impl, intf, opts);
|
||||
* </pre>
|
||||
*
|
||||
* @see javax.management.JMX.ProxyOptions
|
||||
*/
|
||||
public static class MBeanOptions implements Serializable, Cloneable {
|
||||
private static final long serialVersionUID = -6380842449318177843L;
|
||||
|
||||
static final MBeanOptions MXBEAN = new MBeanOptions();
|
||||
static {
|
||||
MXBEAN.setMXBeanMappingFactory(MXBeanMappingFactory.DEFAULT);
|
||||
}
|
||||
|
||||
private MXBeanMappingFactory mappingFactory;
|
||||
|
||||
/**
|
||||
* <p>Construct an {@code MBeanOptions} object where all options have
|
||||
* their default values.</p>
|
||||
*/
|
||||
public MBeanOptions() {}
|
||||
|
||||
@Override
|
||||
public MBeanOptions clone() {
|
||||
try {
|
||||
return (MBeanOptions) super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>True if this is an MXBean proxy or a StandardMBean instance
|
||||
* that is an MXBean. The default value is false.</p>
|
||||
*
|
||||
* <p>This method is equivalent to {@link #getMXBeanMappingFactory()
|
||||
* this.getMXBeanMappingFactory()}{@code != null}.</p>
|
||||
*
|
||||
* @return true if this is an MXBean proxy or a StandardMBean instance
|
||||
* that is an MXBean.
|
||||
*/
|
||||
public boolean isMXBean() {
|
||||
return (this.mappingFactory != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>The mappings between Java types and Open Types to be used in
|
||||
* an MXBean proxy or a StandardMBean instance that is an MXBean,
|
||||
* or null if this instance is not for an MXBean.
|
||||
* The default value is null.</p>
|
||||
*
|
||||
* @return the mappings to be used in this proxy or StandardMBean,
|
||||
* or null if this instance is not for an MXBean.
|
||||
*/
|
||||
public MXBeanMappingFactory getMXBeanMappingFactory() {
|
||||
return mappingFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Set the {@link #getMXBeanMappingFactory() MXBeanMappingFactory} to
|
||||
* the given value. The value should be null if this instance is not
|
||||
* for an MXBean. If this instance is for an MXBean, the value should
|
||||
* usually be either a custom mapping factory, or
|
||||
* {@link MXBeanMappingFactory#forInterface
|
||||
* MXBeanMappingFactory.forInterface}{@code (mxbeanInterface)}
|
||||
* which signifies
|
||||
* that the {@linkplain MXBeanMappingFactory#DEFAULT default} mapping
|
||||
* factory should be used unless an {@code @}{@link
|
||||
* javax.management.openmbean.MXBeanMappingFactoryClass
|
||||
* MXBeanMappingFactoryClass} annotation on {@code mxbeanInterface}
|
||||
* specifies otherwise.</p>
|
||||
*
|
||||
* <p>Examples:</p>
|
||||
* <pre>
|
||||
* MBeanOptions opts = new MBeanOptions();
|
||||
* opts.setMXBeanMappingFactory(myMappingFactory);
|
||||
* MyMXBean proxy = JMX.newMBeanProxy(
|
||||
* mbeanServerConnection, objectName, MyMXBean.class, opts);
|
||||
*
|
||||
* // ...or...
|
||||
*
|
||||
* MBeanOptions opts = new MBeanOptions();
|
||||
* MXBeanMappingFactory defaultFactoryForMyMXBean =
|
||||
* MXBeanMappingFactory.forInterface(MyMXBean.class);
|
||||
* opts.setMXBeanMappingFactory(defaultFactoryForMyMXBean);
|
||||
* MyMXBean proxy = JMX.newMBeanProxy(
|
||||
* mbeanServerConnection, objectName, MyMXBean.class, opts);
|
||||
* </pre>
|
||||
*
|
||||
* @param f the new value. If null, this instance is not for an
|
||||
* MXBean.
|
||||
*/
|
||||
public void setMXBeanMappingFactory(MXBeanMappingFactory f) {
|
||||
this.mappingFactory = f;
|
||||
}
|
||||
|
||||
/* To maximise object sharing, classes in this package can replace
|
||||
* a private MBeanOptions with no MXBeanMappingFactory with one
|
||||
* of these shared instances. But they must be EXTREMELY careful
|
||||
* never to give out the shared instances to user code, which could
|
||||
* modify them.
|
||||
*/
|
||||
private static final MBeanOptions[] CANONICALS = {
|
||||
new MBeanOptions(), MXBEAN,
|
||||
};
|
||||
// Overridden in local subclasses:
|
||||
MBeanOptions[] canonicals() {
|
||||
return CANONICALS;
|
||||
}
|
||||
|
||||
// This is only used by the logic for canonical instances.
|
||||
// Overridden in local subclasses:
|
||||
boolean same(MBeanOptions opt) {
|
||||
return (opt.mappingFactory == mappingFactory);
|
||||
}
|
||||
|
||||
final MBeanOptions canonical() {
|
||||
for (MBeanOptions opt : canonicals()) {
|
||||
if (opt.getClass() == this.getClass() && same(opt))
|
||||
return opt;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
final MBeanOptions uncanonical() {
|
||||
for (MBeanOptions opt : canonicals()) {
|
||||
if (this == opt)
|
||||
return clone();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private Map<String, Object> toMap() {
|
||||
Map<String, Object> map = new TreeMap<String, Object>();
|
||||
try {
|
||||
BeanInfo bi = java.beans.Introspector.getBeanInfo(getClass());
|
||||
PropertyDescriptor[] pds = bi.getPropertyDescriptors();
|
||||
for (PropertyDescriptor pd : pds) {
|
||||
String name = pd.getName();
|
||||
if (name.equals("class"))
|
||||
continue;
|
||||
Method get = pd.getReadMethod();
|
||||
if (get != null)
|
||||
map.put(name, get.invoke(this));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Throwable t = e;
|
||||
if (t instanceof InvocationTargetException)
|
||||
t = t.getCause();
|
||||
map.put("Exception", t);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + toMap();
|
||||
// For example "MBeanOptions{MXBean=true, <etc>}".
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Indicates whether some other object is "equal to" this one. The
|
||||
* result is true if and only if the other object is also an instance
|
||||
* of MBeanOptions or a subclass, and has the same properties with
|
||||
* the same values.</p>
|
||||
* @return {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this)
|
||||
return true;
|
||||
if (obj == null || obj.getClass() != this.getClass())
|
||||
return false;
|
||||
return toMap().equals(((MBeanOptions) obj).toMap());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return toMap().hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Options to apply to an MBean proxy.</p>
|
||||
*
|
||||
* @see #newMBeanProxy
|
||||
*/
|
||||
public static class ProxyOptions extends MBeanOptions {
|
||||
private static final long serialVersionUID = 7238804866098386559L;
|
||||
|
||||
private boolean notificationEmitter;
|
||||
|
||||
/**
|
||||
* <p>Construct a {@code ProxyOptions} object where all options have
|
||||
* their default values.</p>
|
||||
*/
|
||||
public ProxyOptions() {}
|
||||
|
||||
@Override
|
||||
public ProxyOptions clone() {
|
||||
return (ProxyOptions) super.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Defines whether the returned proxy should
|
||||
* implement {@link NotificationEmitter}. The default value is false.</p>
|
||||
*
|
||||
* @return true if this proxy will be a NotificationEmitter.
|
||||
*
|
||||
* @see JMX#newMBeanProxy(MBeanServerConnection, ObjectName, Class,
|
||||
* MBeanOptions)
|
||||
*/
|
||||
public boolean isNotificationEmitter() {
|
||||
return this.notificationEmitter;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Set the {@link #isNotificationEmitter NotificationEmitter} option to
|
||||
* the given value.</p>
|
||||
* @param emitter the new value.
|
||||
*/
|
||||
public void setNotificationEmitter(boolean emitter) {
|
||||
this.notificationEmitter = emitter;
|
||||
}
|
||||
|
||||
// Canonical objects for each of (MXBean,!MXBean) x (Emitter,!Emitter)
|
||||
private static final ProxyOptions[] CANONICALS = {
|
||||
new ProxyOptions(), new ProxyOptions(),
|
||||
new ProxyOptions(), new ProxyOptions(),
|
||||
};
|
||||
static {
|
||||
CANONICALS[1].setMXBeanMappingFactory(MXBeanMappingFactory.DEFAULT);
|
||||
CANONICALS[2].setNotificationEmitter(true);
|
||||
CANONICALS[3].setMXBeanMappingFactory(MXBeanMappingFactory.DEFAULT);
|
||||
CANONICALS[3].setNotificationEmitter(true);
|
||||
}
|
||||
@Override
|
||||
MBeanOptions[] canonicals() {
|
||||
return CANONICALS;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean same(MBeanOptions opt) {
|
||||
return (super.same(opt) && opt instanceof ProxyOptions &&
|
||||
((ProxyOptions) opt).notificationEmitter == notificationEmitter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Make a proxy for a Standard MBean in a local or remote
|
||||
* MBean Server.</p>
|
||||
@ -172,7 +449,7 @@ public class JMX {
|
||||
*
|
||||
* <p>This method behaves the same as {@link
|
||||
* #newMBeanProxy(MBeanServerConnection, ObjectName, Class)}, but
|
||||
* additionally, if {@code notificationBroadcaster} is {@code
|
||||
* additionally, if {@code notificationEmitter} is {@code
|
||||
* true}, then the MBean is assumed to be a {@link
|
||||
* NotificationBroadcaster} or {@link NotificationEmitter} and the
|
||||
* returned proxy will implement {@link NotificationEmitter} as
|
||||
@ -189,25 +466,21 @@ public class JMX {
|
||||
* {@code connection} to forward to.
|
||||
* @param interfaceClass the management interface that the MBean
|
||||
* exports, which will also be implemented by the returned proxy.
|
||||
* @param notificationBroadcaster make the returned proxy
|
||||
* @param notificationEmitter make the returned proxy
|
||||
* implement {@link NotificationEmitter} by forwarding its methods
|
||||
* via {@code connection}.
|
||||
*
|
||||
* @param <T> allows the compiler to know that if the {@code
|
||||
* interfaceClass} parameter is {@code MyMBean.class}, for
|
||||
* example, then the return type is {@code MyMBean}.
|
||||
*
|
||||
* @return the new proxy instance.
|
||||
*/
|
||||
public static <T> T newMBeanProxy(MBeanServerConnection connection,
|
||||
ObjectName objectName,
|
||||
Class<T> interfaceClass,
|
||||
boolean notificationBroadcaster) {
|
||||
return MBeanServerInvocationHandler.newProxyInstance(
|
||||
connection,
|
||||
objectName,
|
||||
interfaceClass,
|
||||
notificationBroadcaster);
|
||||
boolean notificationEmitter) {
|
||||
ProxyOptions opts = new ProxyOptions();
|
||||
opts.setNotificationEmitter(notificationEmitter);
|
||||
return newMBeanProxy(connection, objectName, interfaceClass, opts);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -314,7 +587,7 @@ public class JMX {
|
||||
*
|
||||
* <p>This method behaves the same as {@link
|
||||
* #newMXBeanProxy(MBeanServerConnection, ObjectName, Class)}, but
|
||||
* additionally, if {@code notificationBroadcaster} is {@code
|
||||
* additionally, if {@code notificationEmitter} is {@code
|
||||
* true}, then the MXBean is assumed to be a {@link
|
||||
* NotificationBroadcaster} or {@link NotificationEmitter} and the
|
||||
* returned proxy will implement {@link NotificationEmitter} as
|
||||
@ -331,31 +604,105 @@ public class JMX {
|
||||
* {@code connection} to forward to.
|
||||
* @param interfaceClass the MXBean interface,
|
||||
* which will also be implemented by the returned proxy.
|
||||
* @param notificationBroadcaster make the returned proxy
|
||||
* @param notificationEmitter make the returned proxy
|
||||
* implement {@link NotificationEmitter} by forwarding its methods
|
||||
* via {@code connection}.
|
||||
*
|
||||
* @param <T> allows the compiler to know that if the {@code
|
||||
* interfaceClass} parameter is {@code MyMXBean.class}, for
|
||||
* example, then the return type is {@code MyMXBean}.
|
||||
*
|
||||
* @return the new proxy instance.
|
||||
*/
|
||||
public static <T> T newMXBeanProxy(MBeanServerConnection connection,
|
||||
ObjectName objectName,
|
||||
Class<T> interfaceClass,
|
||||
boolean notificationBroadcaster) {
|
||||
// Check interface for MXBean compliance
|
||||
//
|
||||
boolean notificationEmitter) {
|
||||
ProxyOptions opts = new ProxyOptions();
|
||||
MXBeanMappingFactory f = MXBeanMappingFactory.forInterface(interfaceClass);
|
||||
opts.setMXBeanMappingFactory(f);
|
||||
opts.setNotificationEmitter(notificationEmitter);
|
||||
return newMBeanProxy(connection, objectName, interfaceClass, opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Make a proxy for a Standard MBean or MXBean in a local or remote MBean
|
||||
* Server that may also support the methods of {@link
|
||||
* NotificationEmitter} and (for an MXBean) that may define custom MXBean
|
||||
* type mappings.</p>
|
||||
*
|
||||
* <p>This method behaves the same as
|
||||
* {@link #newMBeanProxy(MBeanServerConnection, ObjectName, Class)} or
|
||||
* {@link #newMXBeanProxy(MBeanServerConnection, ObjectName, Class)},
|
||||
* according as {@code opts.isMXBean()} is respectively false or true; but
|
||||
* with the following changes based on {@code opts}.</p>
|
||||
*
|
||||
* <ul>
|
||||
* <li>If {@code opts.isNotificationEmitter()} is {@code
|
||||
* true}, then the MBean is assumed to be a {@link
|
||||
* NotificationBroadcaster} or {@link NotificationEmitter} and the
|
||||
* returned proxy will implement {@link NotificationEmitter} as
|
||||
* well as {@code interfaceClass}. A call to {@link
|
||||
* NotificationBroadcaster#addNotificationListener} on the proxy
|
||||
* will result in a call to {@link
|
||||
* MBeanServerConnection#addNotificationListener(ObjectName,
|
||||
* NotificationListener, NotificationFilter, Object)}, and
|
||||
* likewise for the other methods of {@link
|
||||
* NotificationBroadcaster} and {@link NotificationEmitter}.</li>
|
||||
*
|
||||
* <li>If {@code opts.getMXBeanMappingFactory()} is not null,
|
||||
* then the mappings it defines will be applied to convert between
|
||||
* arbitrary Java types and Open Types.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param connection the MBean server to forward to.
|
||||
* @param objectName the name of the MBean within
|
||||
* {@code connection} to forward to.
|
||||
* @param interfaceClass the Standard MBean or MXBean interface,
|
||||
* which will also be implemented by the returned proxy.
|
||||
* @param opts the options to apply for this proxy. Can be null,
|
||||
* in which case default options are applied.
|
||||
* @param <T> allows the compiler to know that if the {@code
|
||||
* interfaceClass} parameter is {@code MyMXBean.class}, for
|
||||
* example, then the return type is {@code MyMXBean}.
|
||||
* @return the new proxy instance.
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code interfaceClass} is not a
|
||||
* valid MXBean interface.
|
||||
*/
|
||||
public static <T> T newMBeanProxy(MBeanServerConnection connection,
|
||||
ObjectName objectName,
|
||||
Class<T> interfaceClass,
|
||||
MBeanOptions opts) {
|
||||
try {
|
||||
Introspector.testComplianceMXBeanInterface(interfaceClass);
|
||||
return newMBeanProxy2(connection, objectName, interfaceClass, opts);
|
||||
} catch (NotCompliantMBeanException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> T newMBeanProxy2(MBeanServerConnection connection,
|
||||
ObjectName objectName,
|
||||
Class<T> interfaceClass,
|
||||
MBeanOptions opts)
|
||||
throws NotCompliantMBeanException {
|
||||
|
||||
if (opts == null)
|
||||
opts = new MBeanOptions();
|
||||
|
||||
boolean notificationEmitter = opts instanceof ProxyOptions &&
|
||||
((ProxyOptions) opts).isNotificationEmitter();
|
||||
|
||||
MXBeanMappingFactory mappingFactory = opts.getMXBeanMappingFactory();
|
||||
|
||||
if (mappingFactory != null) {
|
||||
// Check interface for MXBean compliance
|
||||
Introspector.testComplianceMXBeanInterface(interfaceClass,
|
||||
mappingFactory);
|
||||
}
|
||||
|
||||
InvocationHandler handler = new MBeanServerInvocationHandler(
|
||||
connection, objectName, true);
|
||||
connection, objectName, opts);
|
||||
final Class[] interfaces;
|
||||
if (notificationBroadcaster) {
|
||||
if (notificationEmitter) {
|
||||
interfaces =
|
||||
new Class<?>[] {interfaceClass, NotificationEmitter.class};
|
||||
} else
|
||||
|
@ -33,6 +33,9 @@ import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Arrays;
|
||||
import java.util.WeakHashMap;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
|
||||
import static javax.management.JMX.MBeanOptions;
|
||||
|
||||
/**
|
||||
* <p>{@link InvocationHandler} that forwards methods in an MBean's
|
||||
@ -111,7 +114,7 @@ public class MBeanServerInvocationHandler implements InvocationHandler {
|
||||
public MBeanServerInvocationHandler(MBeanServerConnection connection,
|
||||
ObjectName objectName) {
|
||||
|
||||
this(connection, objectName, false);
|
||||
this(connection, objectName, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -138,6 +141,14 @@ public class MBeanServerInvocationHandler implements InvocationHandler {
|
||||
public MBeanServerInvocationHandler(MBeanServerConnection connection,
|
||||
ObjectName objectName,
|
||||
boolean isMXBean) {
|
||||
this(connection, objectName, isMXBean ? MBeanOptions.MXBEAN : null);
|
||||
}
|
||||
|
||||
public MBeanServerInvocationHandler(MBeanServerConnection connection,
|
||||
ObjectName objectName,
|
||||
MBeanOptions options) {
|
||||
if (options == null)
|
||||
options = new MBeanOptions();
|
||||
if (connection == null) {
|
||||
throw new IllegalArgumentException("Null connection");
|
||||
}
|
||||
@ -146,7 +157,7 @@ public class MBeanServerInvocationHandler implements InvocationHandler {
|
||||
}
|
||||
this.connection = connection;
|
||||
this.objectName = objectName;
|
||||
this.isMXBean = isMXBean;
|
||||
this.options = options.canonical();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -182,7 +193,16 @@ public class MBeanServerInvocationHandler implements InvocationHandler {
|
||||
* @since 1.6
|
||||
*/
|
||||
public boolean isMXBean() {
|
||||
return isMXBean;
|
||||
return options.isMXBean();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the {@link MBeanOptions} used for this proxy.</p>
|
||||
*
|
||||
* @return the MBeanOptions.
|
||||
*/
|
||||
public MBeanOptions getMBeanOptions() {
|
||||
return options.uncanonical();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -260,7 +280,7 @@ public class MBeanServerInvocationHandler implements InvocationHandler {
|
||||
return doLocally(proxy, method, args);
|
||||
|
||||
try {
|
||||
if (isMXBean) {
|
||||
if (isMXBean()) {
|
||||
MXBeanProxy p = findMXBeanProxy(methodClass);
|
||||
return p.invoke(connection, objectName, method, args);
|
||||
} else {
|
||||
@ -326,21 +346,34 @@ public class MBeanServerInvocationHandler implements InvocationHandler {
|
||||
*/
|
||||
}
|
||||
|
||||
private static MXBeanProxy findMXBeanProxy(Class<?> mxbeanInterface) {
|
||||
private MXBeanProxy findMXBeanProxy(Class<?> mxbeanInterface) {
|
||||
MXBeanMappingFactory mappingFactory = options.getMXBeanMappingFactory();
|
||||
synchronized (mxbeanProxies) {
|
||||
WeakReference<MXBeanProxy> proxyRef =
|
||||
mxbeanProxies.get(mxbeanInterface);
|
||||
MXBeanProxy p = (proxyRef == null) ? null : proxyRef.get();
|
||||
if (p == null) {
|
||||
p = new MXBeanProxy(mxbeanInterface);
|
||||
mxbeanProxies.put(mxbeanInterface,
|
||||
new WeakReference<MXBeanProxy>(p));
|
||||
ClassToProxy classToProxy = mxbeanProxies.get(mappingFactory);
|
||||
if (classToProxy == null) {
|
||||
classToProxy = new ClassToProxy();
|
||||
mxbeanProxies.put(mappingFactory, classToProxy);
|
||||
}
|
||||
WeakReference<MXBeanProxy> wr = classToProxy.get(mxbeanInterface);
|
||||
MXBeanProxy p;
|
||||
if (wr != null) {
|
||||
p = wr.get();
|
||||
if (p != null)
|
||||
return p;
|
||||
}
|
||||
p = new MXBeanProxy(mxbeanInterface, mappingFactory);
|
||||
classToProxy.put(mxbeanInterface, new WeakReference<MXBeanProxy>(p));
|
||||
return p;
|
||||
}
|
||||
}
|
||||
private static final WeakHashMap<Class<?>, WeakReference<MXBeanProxy>>
|
||||
mxbeanProxies = new WeakHashMap<Class<?>, WeakReference<MXBeanProxy>>();
|
||||
private static final WeakHashMap<MXBeanMappingFactory, ClassToProxy>
|
||||
mxbeanProxies = newWeakHashMap();
|
||||
private static class ClassToProxy
|
||||
extends WeakHashMap<Class<?>, WeakReference<MXBeanProxy>> {}
|
||||
|
||||
private static <K, V> WeakHashMap<K, V> newWeakHashMap() {
|
||||
return new WeakHashMap<K, V>();
|
||||
}
|
||||
|
||||
private Object invokeBroadcasterMethod(Object proxy, Method method,
|
||||
Object[] args) throws Exception {
|
||||
@ -453,7 +486,7 @@ public class MBeanServerInvocationHandler implements InvocationHandler {
|
||||
objectName.equals(handler.objectName) &&
|
||||
proxy.getClass().equals(args[0].getClass());
|
||||
} else if (methodName.equals("toString")) {
|
||||
return (isMXBean ? "MX" : "M") + "BeanProxy(" +
|
||||
return (isMXBean() ? "MX" : "M") + "BeanProxy(" +
|
||||
connection + "[" + objectName + "])";
|
||||
} else if (methodName.equals("hashCode")) {
|
||||
return objectName.hashCode()+connection.hashCode();
|
||||
@ -484,5 +517,5 @@ public class MBeanServerInvocationHandler implements InvocationHandler {
|
||||
|
||||
private final MBeanServerConnection connection;
|
||||
private final ObjectName objectName;
|
||||
private final boolean isMXBean;
|
||||
private final MBeanOptions options;
|
||||
}
|
||||
|
@ -44,6 +44,10 @@ import javax.management.openmbean.CompositeDataInvocationHandler;
|
||||
import javax.management.openmbean.CompositeDataSupport;
|
||||
import javax.management.openmbean.CompositeDataView;
|
||||
import javax.management.openmbean.CompositeType;
|
||||
import javax.management.openmbean.MXBeanMapping;
|
||||
import javax.management.openmbean.MXBeanMappingClass;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
import javax.management.openmbean.MXBeanMappingFactoryClass;
|
||||
import javax.management.openmbean.OpenDataException;
|
||||
import javax.management.openmbean.OpenMBeanInfo;
|
||||
import javax.management.openmbean.OpenType;
|
||||
@ -78,7 +82,7 @@ import javax.management.openmbean.TabularType;
|
||||
public interface MisleadingMXBean {}
|
||||
</pre>
|
||||
|
||||
<h3><a name="MXBean-spec">MXBean specification</a></h3>
|
||||
<h3 id="MXBean-spec">MXBean specification</h3>
|
||||
|
||||
<p>The MXBean concept provides a simple way to code an MBean
|
||||
that only references a predefined set of types, the ones defined
|
||||
@ -314,7 +318,7 @@ public class MemoryPool
|
||||
</table>
|
||||
|
||||
|
||||
<h2><a name="mxbean-def">Definition of an MXBean</a></h2>
|
||||
<h2 id="mxbean-def">Definition of an MXBean</h2>
|
||||
|
||||
<p>An MXBean is a kind of MBean. An MXBean object can be
|
||||
registered directly in the MBean Server, or it can be used as an
|
||||
@ -367,7 +371,7 @@ public class MemoryPool
|
||||
above rules will produce an exception.</p>
|
||||
|
||||
|
||||
<h2><a name="naming-conv">Naming conventions</a></h2>
|
||||
<h2 id="naming-conv">Naming conventions</h2>
|
||||
|
||||
<p>The same naming conventions are applied to the methods in an
|
||||
MXBean as in a Standard MBean:</p>
|
||||
@ -413,7 +417,7 @@ public class MemoryPool
|
||||
read-only or write-only respectively.</p>
|
||||
|
||||
|
||||
<h2><a name="mapping-rules">Type mapping rules</a></h2>
|
||||
<h2 id="mapping-rules">Type mapping rules</h2>
|
||||
|
||||
<p>An MXBean is a kind of Open MBean, as defined by the {@link
|
||||
javax.management.openmbean} package. This means that the types of
|
||||
@ -475,7 +479,11 @@ public class MemoryPool
|
||||
from type <em>opendata(J)</em> to type <em>J</em>, a null value is
|
||||
mapped to a null value.</p>
|
||||
|
||||
<p>The following table summarizes the type mapping rules.</p>
|
||||
<p>In addition to the default type mapping rules, you can specify
|
||||
custom type mappings, as described <a
|
||||
href="#custom">below</a>.</p>
|
||||
|
||||
<p>The following table summarizes the default type mapping rules.</p>
|
||||
|
||||
<table border="1" cellpadding="5">
|
||||
<tr>
|
||||
@ -658,7 +666,7 @@ TabularType tabularType =
|
||||
TabularData} that serializes as {@code TabularDataSupport}.</p>
|
||||
|
||||
|
||||
<h3><a name="mxbean-map">Mappings for MXBean interfaces</a></h3>
|
||||
<h3 id="mxbean-map">Mappings for MXBean interfaces</h3>
|
||||
|
||||
<p>An MXBean interface, or a type referenced within an MXBean
|
||||
interface, can reference another MXBean interface, <em>J</em>.
|
||||
@ -747,7 +755,7 @@ public interface ModuleMXBean {
|
||||
general, notably because it does not work well for MBeans that are
|
||||
{@link NotificationBroadcaster}s.</p>
|
||||
|
||||
<h3><a name="composite-map">Mappings for other types</a></h3>
|
||||
<h3 id="composite-map">Mappings for other types</h3>
|
||||
|
||||
<p>Given a Java class or interface <em>J</em> that does not match the other
|
||||
rules in the table above, the MXBean framework will attempt to map
|
||||
@ -1035,6 +1043,76 @@ public interface Node {
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>Alternatively, you can define a custom mapping for your recursive
|
||||
type; see the next section.</p>
|
||||
|
||||
<h3 id="custom">Custom MXBean type mappings</h3>
|
||||
|
||||
<p>You can augment or replace the default type mappings described
|
||||
above with custom mappings. An example appears in the
|
||||
documentation for {@link MXBeanMapping}.</p>
|
||||
|
||||
<p>If an MXBean uses custom mappings, then an MXBean proxy for
|
||||
that MXBean must use the same mappings for correct behavior.
|
||||
This requires more careful synchronization between client and
|
||||
server than is necessary with the default mappings. For example
|
||||
it typically requires the client to have the same implementation
|
||||
of any {@link MXBeanMapping} subclasses as the server. For this
|
||||
reason, custom mappings should be avoided if possible.</p>
|
||||
|
||||
<p>Every MXBean has an associated {@link MXBeanMappingFactory}.
|
||||
Call this <code><em>f</em></code>. Then every type that appears
|
||||
in that MXBean has an associated {@link MXBeanMapping}
|
||||
determined by <code><em>f</em></code>. If the type is
|
||||
<code><em>J</em></code>, say, then the mapping is {@link
|
||||
MXBeanMappingFactory#mappingForType
|
||||
<em>f</em>.mappingForType}<code>(<em>J</em>,
|
||||
<em>f</em>)</code>.</p>
|
||||
|
||||
<p>The {@code MXBeanMappingFactory} <code><em>f</em></code> for an
|
||||
MXBean is determined as follows.</p>
|
||||
|
||||
<ul>
|
||||
<li><p>If an {@link JMX.MBeanOptions} argument is supplied to
|
||||
the {@link StandardMBean} constructor that makes an MXBean,
|
||||
or to the {@link JMX#newMXBeanProxy JMX.newMXBeanProxy}
|
||||
method, and the {@code MBeanOptions} object defines a non-null
|
||||
{@code MXBeanMappingFactory}, then that is the value of
|
||||
<code><em>f</em></code>.</p></li>
|
||||
|
||||
<li><p>Otherwise, if the MXBean interface has an {@link
|
||||
MXBeanMappingFactoryClass} annotation, then that annotation
|
||||
must identify a subclass of {@code MXBeanMappingFactory}
|
||||
with a no-argument constructor. Then
|
||||
<code><em>f</em></code> is the result of calling this
|
||||
constructor. If the class does not have a no-argument
|
||||
constructor, or if calling the constructor produces an
|
||||
exception, then the MXBean is invalid and an attempt to
|
||||
register it in the MBean Server will produce a {@link
|
||||
NotCompliantMBeanException}.</p>
|
||||
|
||||
<p>This annotation is not inherited from any parent
|
||||
interfaces. If an MXBean interface has this annotation,
|
||||
then usually any MXBean subinterfaces must repeat the same
|
||||
annotation for correct behavior.</p></li>
|
||||
|
||||
<li><p>Otherwise, if the package in which the MXBean interface
|
||||
appears has an {@code MXBeanMappingFactoryClass} annotation,
|
||||
then <code><em>f</em></code> is determined as if that
|
||||
annotation appeared on the MXBean interface.</p></li>
|
||||
|
||||
<li><p>Otherwise, <code><em>f</em></code> is the default mapping
|
||||
factory, {@link MXBeanMappingFactory#DEFAULT}.</p></li>
|
||||
</ul>
|
||||
|
||||
<p>The default mapping factory recognizes the {@link
|
||||
MXBeanMappingClass} annotation on a class or interface. If
|
||||
<code><em>J</em></code> is a class or interface that has such an
|
||||
annotation, then the {@code MXBeanMapping} for
|
||||
<code><em>J</em></code> produced by the default mapping factory
|
||||
will be determined by the value of the annotation as described
|
||||
in its {@linkplain MXBeanMappingClass documentation}.</p>
|
||||
|
||||
<h3>MBeanInfo contents for an MXBean</h3>
|
||||
|
||||
<p>An MXBean is a type of Open MBean. However, for compatibility
|
||||
@ -1091,7 +1169,7 @@ public interface Node {
|
||||
{@code mxbean} whose value is the string "{@code true}".</p>
|
||||
|
||||
|
||||
<h3><a name="type-names">Type Names</a></h3>
|
||||
<h3 id="type-names">Type Names</h3>
|
||||
|
||||
<p>Sometimes the unmapped type <em>T</em> of a method parameter or
|
||||
return value in an MXBean must be represented as a string. If
|
||||
@ -1163,6 +1241,8 @@ public interface Node {
|
||||
appropriate), or <em>C</em> is true of <em>e</em>.{@link
|
||||
Throwable#getCause() getCause()}".</p>
|
||||
|
||||
@see MXBeanMapping
|
||||
|
||||
@since 1.6
|
||||
*/
|
||||
|
||||
|
@ -109,36 +109,7 @@ class MatchQueryExp extends QueryEval implements QueryExp {
|
||||
* Returns the string representing the object
|
||||
*/
|
||||
public String toString() {
|
||||
return exp + " like " + new StringValueExp(likeTranslate(pattern));
|
||||
}
|
||||
|
||||
private static String likeTranslate(String s) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int c;
|
||||
for (int i = 0; i < s.length(); i += Character.charCount(c)) {
|
||||
c = s.codePointAt(i);
|
||||
switch (c) {
|
||||
case '\\':
|
||||
i += Character.charCount(c);
|
||||
sb.append('\\');
|
||||
if (i < s.length()) {
|
||||
c = s.codePointAt(i);
|
||||
sb.appendCodePoint(c);
|
||||
}
|
||||
break;
|
||||
case '*':
|
||||
sb.append('%'); break;
|
||||
case '?':
|
||||
sb.append('_'); break;
|
||||
case '%':
|
||||
sb.append("\\%"); break;
|
||||
case '_':
|
||||
sb.append("\\_"); break;
|
||||
default:
|
||||
sb.appendCodePoint(c); break;
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
return exp + " like " + new StringValueExp(pattern);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1781,7 +1781,7 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp {
|
||||
}
|
||||
|
||||
String toQueryString() {
|
||||
return "LIKE " + Query.value(toString());
|
||||
return "like " + Query.value(toString());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -108,13 +108,13 @@ package javax.management;
|
||||
* <dd>Selects MBeans that have a {@code Status} attribute whose value
|
||||
* is one of those three strings.
|
||||
*
|
||||
* <dt>{@code Message like 'OK: %'}
|
||||
* <dt>{@code Message like 'OK: *'}
|
||||
* <dd>Selects MBeans that have a {@code Message} attribute whose value
|
||||
* is a string beginning with {@code "OK: "}. <b>Notice that the
|
||||
* wildcard characters are SQL's ones.</b> In the query language,
|
||||
* wildcard characters are not the ones that SQL uses.</b> In SQL,
|
||||
* {@code %} means "any sequence of characters" and {@code _}
|
||||
* means "any single character". In the rest of the JMX API, these
|
||||
* correspond to {@code *} and {@code %} respectively.
|
||||
* means "any single character". Here, as in the rest of the JMX API,
|
||||
* those are represented by {@code *} and {@code ?} respectively.
|
||||
*
|
||||
* <dt>{@code instanceof 'javax.management.NotificationBroadcaster'}
|
||||
* <dd>Selects MBeans that are instances of
|
||||
@ -319,11 +319,11 @@ package javax.management;
|
||||
*
|
||||
* <tr><td><i>value</i> <b>LIKE</b> <i>stringLiteral</i>
|
||||
* <td>{@link Query#match Query.match}(<i>q(value)</i>,
|
||||
* <i><a href="#translateWildcards">translateWildcards</a>(q(stringLiteral))</i>)
|
||||
* <i>q(stringLiteral)</i>)
|
||||
*
|
||||
* <tr><td><i>value</i> <b>NOT LIKE</b> <i>stringLiteral</i>
|
||||
* <td>{@link Query#not Query.not}({@link Query#match Query.match}(<i>q(value)</i>,
|
||||
* <i><a href="#translateWildcards">translateWildcards</a>(q(stringLiteral))</i>))
|
||||
* <i>q(stringLiteral)</i>))
|
||||
*
|
||||
* <tr><td><i>value1</i> <b>+</b> <i>value2</i>
|
||||
* <td>{@link Query#plus Query.plus}(<i>q(value1)</i>, <i>q(value2)</i>)
|
||||
@ -360,13 +360,6 @@ package javax.management;
|
||||
* --><i>floatingPointLiteral</i>))
|
||||
* </table>
|
||||
*
|
||||
* <p id="translateWildcards">Here, <i>translateWildcards</i> is a function
|
||||
* that translates from the SQL notation for wildcards, using {@code %} and
|
||||
* {@code _}, to the JMX API notation, using {@code *} and {@code ?}. If the
|
||||
* <b>LIKE</b> string already contains {@code *} or {@code ?}, these characters
|
||||
* have their literal meanings, and will be quoted in the call to
|
||||
* {@link Query#match Query.match}.</p>
|
||||
*
|
||||
* @since 1.5
|
||||
*/
|
||||
public class Query extends Object {
|
||||
|
@ -43,12 +43,6 @@ import java.util.Set;
|
||||
* on both the client and the server in the remote case, so using this class
|
||||
* instead is recommended where possible.</p>
|
||||
*
|
||||
* <!-- <p>Because this class was introduced in version 2.0 of the JMX API,
|
||||
* it may not be present on a remote JMX agent that is running an earlier
|
||||
* version. The method {@link JMX#addListenerWithFilter JMX.addListenerWithFilter}
|
||||
* can be used when you cannot be sure whether this class is present in the
|
||||
* agent you are connecting to.</p> -->
|
||||
*
|
||||
* <p>This class uses the {@linkplain Query Query API} to specify the
|
||||
* filtering logic. For example, to select only notifications where the
|
||||
* {@linkplain Notification#getType() type} is {@code "com.example.mytype"},
|
||||
|
@ -490,8 +490,7 @@ class QueryParser {
|
||||
}
|
||||
AttributeValueExp alhs = (AttributeValueExp) lhs;
|
||||
StringValueExp sve = stringvalue();
|
||||
String s = sve.getValue();
|
||||
q = Query.match(alhs, patternValueExp(s));
|
||||
q = Query.match(alhs, sve);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -624,40 +623,4 @@ class QueryParser {
|
||||
throw new IllegalArgumentException("Expected string: " + t);
|
||||
return Query.value(t.string);
|
||||
}
|
||||
|
||||
// Convert the SQL pattern syntax, using % and _, to the Query.match
|
||||
// syntax, using * and ?. The tricky part is recognizing \% and
|
||||
// \_ as literal values, and also not replacing them inside [].
|
||||
// But Query.match does not recognize \ inside [], which makes our
|
||||
// job a tad easier.
|
||||
private StringValueExp patternValueExp(String s) {
|
||||
int c;
|
||||
for (int i = 0; i < s.length(); i += Character.charCount(c)) {
|
||||
c = s.codePointAt(i);
|
||||
switch (c) {
|
||||
case '\\':
|
||||
i++; // i += Character.charCount(c), but we know it's 1!
|
||||
if (i >= s.length())
|
||||
throw new IllegalArgumentException("\\ at end of pattern");
|
||||
break;
|
||||
case '[':
|
||||
i = s.indexOf(']', i);
|
||||
if (i < 0)
|
||||
throw new IllegalArgumentException("[ without ]");
|
||||
break;
|
||||
case '%':
|
||||
s = s.substring(0, i) + "*" + s.substring(i + 1);
|
||||
break;
|
||||
case '_':
|
||||
s = s.substring(0, i) + "?" + s.substring(i + 1);
|
||||
break;
|
||||
case '*':
|
||||
case '?':
|
||||
s = s.substring(0, i) + '\\' + (char) c + s.substring(i + 1);
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Query.value(s);
|
||||
}
|
||||
}
|
||||
|
@ -25,22 +25,19 @@
|
||||
|
||||
package javax.management;
|
||||
|
||||
import static com.sun.jmx.defaults.JmxProperties.MISC_LOGGER;
|
||||
import com.sun.jmx.mbeanserver.DescriptorCache;
|
||||
import com.sun.jmx.mbeanserver.Introspector;
|
||||
import com.sun.jmx.mbeanserver.MBeanSupport;
|
||||
import com.sun.jmx.mbeanserver.MXBeanSupport;
|
||||
import com.sun.jmx.mbeanserver.StandardMBeanSupport;
|
||||
import com.sun.jmx.mbeanserver.Util;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.logging.Level;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
import javax.management.openmbean.OpenMBeanAttributeInfo;
|
||||
import javax.management.openmbean.OpenMBeanAttributeInfoSupport;
|
||||
import javax.management.openmbean.OpenMBeanConstructorInfo;
|
||||
@ -50,6 +47,9 @@ import javax.management.openmbean.OpenMBeanOperationInfoSupport;
|
||||
import javax.management.openmbean.OpenMBeanParameterInfo;
|
||||
import javax.management.openmbean.OpenMBeanParameterInfoSupport;
|
||||
|
||||
import static com.sun.jmx.defaults.JmxProperties.MISC_LOGGER;
|
||||
import static javax.management.JMX.MBeanOptions;
|
||||
|
||||
/**
|
||||
* <p>An MBean whose management interface is determined by reflection
|
||||
* on a Java interface.</p>
|
||||
@ -140,6 +140,11 @@ public class StandardMBean implements DynamicMBean, MBeanRegistration {
|
||||
**/
|
||||
private volatile MBeanInfo cachedMBeanInfo;
|
||||
|
||||
/**
|
||||
* The MBeanOptions for this StandardMBean.
|
||||
**/
|
||||
private MBeanOptions options;
|
||||
|
||||
/**
|
||||
* Make a DynamicMBean out of <var>implementation</var>, using the
|
||||
* specified <var>mbeanInterface</var> class.
|
||||
@ -155,12 +160,14 @@ public class StandardMBean implements DynamicMBean, MBeanRegistration {
|
||||
* implementation is allowed. If null implementation is allowed,
|
||||
* and a null implementation is passed, then the implementation
|
||||
* is assumed to be <var>this</var>.
|
||||
* @param options MBeanOptions to apply to this instance.
|
||||
* @exception IllegalArgumentException if the given
|
||||
* <var>implementation</var> is null, and null is not allowed.
|
||||
**/
|
||||
@SuppressWarnings("unchecked") // cast to T
|
||||
private <T> void construct(T implementation, Class<T> mbeanInterface,
|
||||
boolean nullImplementationAllowed,
|
||||
boolean isMXBean)
|
||||
MBeanOptions options)
|
||||
throws NotCompliantMBeanException {
|
||||
if (implementation == null) {
|
||||
// Have to use (T)this rather than mbeanInterface.cast(this)
|
||||
@ -169,20 +176,23 @@ public class StandardMBean implements DynamicMBean, MBeanRegistration {
|
||||
implementation = Util.<T>cast(this);
|
||||
else throw new IllegalArgumentException("implementation is null");
|
||||
}
|
||||
if (isMXBean) {
|
||||
if (mbeanInterface == null) {
|
||||
mbeanInterface = Util.cast(Introspector.getMXBeanInterface(
|
||||
implementation.getClass()));
|
||||
}
|
||||
this.mbean = new MXBeanSupport(implementation, mbeanInterface);
|
||||
if (options == null)
|
||||
options = new MBeanOptions();
|
||||
MXBeanMappingFactory mappingFactory = options.getMXBeanMappingFactory();
|
||||
boolean mx = (mappingFactory != null);
|
||||
if (mbeanInterface == null) {
|
||||
mbeanInterface = Util.cast(Introspector.getStandardOrMXBeanInterface(
|
||||
implementation.getClass(), mx));
|
||||
}
|
||||
if (mx) {
|
||||
this.mbean =
|
||||
new MXBeanSupport(implementation, mbeanInterface,
|
||||
mappingFactory);
|
||||
} else {
|
||||
if (mbeanInterface == null) {
|
||||
mbeanInterface = Util.cast(Introspector.getStandardMBeanInterface(
|
||||
implementation.getClass()));
|
||||
}
|
||||
this.mbean =
|
||||
new StandardMBeanSupport(implementation, mbeanInterface);
|
||||
}
|
||||
this.options = options.canonical();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -211,14 +221,14 @@ public class StandardMBean implements DynamicMBean, MBeanRegistration {
|
||||
**/
|
||||
public <T> StandardMBean(T implementation, Class<T> mbeanInterface)
|
||||
throws NotCompliantMBeanException {
|
||||
construct(implementation, mbeanInterface, false, false);
|
||||
construct(implementation, mbeanInterface, false, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Make a DynamicMBean out of <var>this</var>, using the specified
|
||||
* <var>mbeanInterface</var> class.</p>
|
||||
*
|
||||
* <p>Call {@link #StandardMBean(java.lang.Object, java.lang.Class)
|
||||
* <p>Calls {@link #StandardMBean(java.lang.Object, java.lang.Class)
|
||||
* this(this,mbeanInterface)}.
|
||||
* This constructor is reserved to subclasses.</p>
|
||||
*
|
||||
@ -231,13 +241,14 @@ public class StandardMBean implements DynamicMBean, MBeanRegistration {
|
||||
**/
|
||||
protected StandardMBean(Class<?> mbeanInterface)
|
||||
throws NotCompliantMBeanException {
|
||||
construct(null, mbeanInterface, true, false);
|
||||
construct(null, mbeanInterface, true, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Make a DynamicMBean out of the object
|
||||
* <var>implementation</var>, using the specified
|
||||
* <var>mbeanInterface</var> class. This constructor can be used
|
||||
* <var>mbeanInterface</var> class, and choosing whether the
|
||||
* resultant MBean is an MXBean. This constructor can be used
|
||||
* to make either Standard MBeans or MXBeans. Unlike the
|
||||
* constructor {@link #StandardMBean(Object, Class)}, it
|
||||
* does not throw NotCompliantMBeanException.</p>
|
||||
@ -267,7 +278,17 @@ public class StandardMBean implements DynamicMBean, MBeanRegistration {
|
||||
public <T> StandardMBean(T implementation, Class<T> mbeanInterface,
|
||||
boolean isMXBean) {
|
||||
try {
|
||||
construct(implementation, mbeanInterface, false, isMXBean);
|
||||
MBeanOptions opts = new MBeanOptions();
|
||||
if (mbeanInterface == null) {
|
||||
mbeanInterface = Util.cast(Introspector.getStandardOrMXBeanInterface(
|
||||
implementation.getClass(), isMXBean));
|
||||
}
|
||||
if (isMXBean) {
|
||||
MXBeanMappingFactory f = MXBeanMappingFactory.forInterface(
|
||||
mbeanInterface);
|
||||
opts.setMXBeanMappingFactory(f);
|
||||
}
|
||||
construct(implementation, mbeanInterface, false, opts);
|
||||
} catch (NotCompliantMBeanException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
@ -275,12 +296,13 @@ public class StandardMBean implements DynamicMBean, MBeanRegistration {
|
||||
|
||||
/**
|
||||
* <p>Make a DynamicMBean out of <var>this</var>, using the specified
|
||||
* <var>mbeanInterface</var> class. This constructor can be used
|
||||
* <var>mbeanInterface</var> class, and choosing whether the resulting
|
||||
* MBean is an MXBean. This constructor can be used
|
||||
* to make either Standard MBeans or MXBeans. Unlike the
|
||||
* constructor {@link #StandardMBean(Object, Class)}, it
|
||||
* does not throw NotCompliantMBeanException.</p>
|
||||
*
|
||||
* <p>Call {@link #StandardMBean(java.lang.Object, java.lang.Class, boolean)
|
||||
* <p>Calls {@link #StandardMBean(java.lang.Object, java.lang.Class, boolean)
|
||||
* this(this, mbeanInterface, isMXBean)}.
|
||||
* This constructor is reserved to subclasses.</p>
|
||||
*
|
||||
@ -297,7 +319,77 @@ public class StandardMBean implements DynamicMBean, MBeanRegistration {
|
||||
**/
|
||||
protected StandardMBean(Class<?> mbeanInterface, boolean isMXBean) {
|
||||
try {
|
||||
construct(null, mbeanInterface, true, isMXBean);
|
||||
MBeanOptions opts = new MBeanOptions();
|
||||
if (mbeanInterface == null) {
|
||||
mbeanInterface = Introspector.getStandardOrMXBeanInterface(
|
||||
getClass(), isMXBean);
|
||||
}
|
||||
if (isMXBean) {
|
||||
MXBeanMappingFactory f = MXBeanMappingFactory.forInterface(
|
||||
mbeanInterface);
|
||||
opts.setMXBeanMappingFactory(f);
|
||||
}
|
||||
construct(null, mbeanInterface, true, opts);
|
||||
} catch (NotCompliantMBeanException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Make a DynamicMBean out of the object
|
||||
* <var>implementation</var>, using the specified
|
||||
* <var>mbeanInterface</var> class and the specified options.</p>
|
||||
*
|
||||
* @param implementation The implementation of this MBean.
|
||||
* @param mbeanInterface The Management Interface exported by this
|
||||
* MBean's implementation. If <code>null</code>, then this
|
||||
* object will use standard JMX design pattern to determine
|
||||
* the management interface associated with the given
|
||||
* implementation.
|
||||
* @param options MBeanOptions that control the operation of the resulting
|
||||
* MBean, as documented in the {@link MBeanOptions} class.
|
||||
* @param <T> Allows the compiler to check
|
||||
* that {@code implementation} does indeed implement the class
|
||||
* described by {@code mbeanInterface}. The compiler can only
|
||||
* check this if {@code mbeanInterface} is a class literal such
|
||||
* as {@code MyMBean.class}.
|
||||
*
|
||||
* @exception IllegalArgumentException if the given
|
||||
* <var>implementation</var> is null, or if the <var>mbeanInterface</var>
|
||||
* does not follow JMX design patterns for Management Interfaces, or
|
||||
* if the given <var>implementation</var> does not implement the
|
||||
* specified interface.
|
||||
**/
|
||||
public <T> StandardMBean(T implementation,
|
||||
Class<T> mbeanInterface,
|
||||
MBeanOptions options) {
|
||||
try {
|
||||
construct(implementation, mbeanInterface, false, options);
|
||||
} catch (NotCompliantMBeanException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Make a DynamicMBean out of <var>this</var>, using the specified
|
||||
* <var>mbeanInterface</var> class and the specified options.</p>
|
||||
*
|
||||
* <p>Calls {@link #StandardMBean(Object, Class, JMX.MBeanOptions)
|
||||
* this(this,mbeanInterface,options)}.
|
||||
* This constructor is reserved to subclasses.</p>
|
||||
*
|
||||
* @param mbeanInterface The Management Interface exported by this
|
||||
* MBean.
|
||||
* @param options MBeanOptions that control the operation of the resulting
|
||||
* MBean, as documented in the {@link MBeanOptions} class.
|
||||
*
|
||||
* @exception IllegalArgumentException if the <var>mbeanInterface</var>
|
||||
* does not follow JMX design patterns for Management Interfaces, or
|
||||
* if <var>this</var> does not implement the specified interface.
|
||||
**/
|
||||
protected StandardMBean(Class<?> mbeanInterface, MBeanOptions options) {
|
||||
try {
|
||||
construct(null, mbeanInterface, true, options);
|
||||
} catch (NotCompliantMBeanException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
@ -326,13 +418,19 @@ public class StandardMBean implements DynamicMBean, MBeanRegistration {
|
||||
|
||||
if (implementation == null)
|
||||
throw new IllegalArgumentException("implementation is null");
|
||||
setImplementation2(implementation);
|
||||
}
|
||||
|
||||
if (isMXBean()) {
|
||||
private <T> void setImplementation2(T implementation)
|
||||
throws NotCompliantMBeanException {
|
||||
Class<? super T> intf = Util.cast(getMBeanInterface());
|
||||
|
||||
if (this.mbean.isMXBean()) {
|
||||
this.mbean = new MXBeanSupport(implementation,
|
||||
Util.<Class<Object>>cast(getMBeanInterface()));
|
||||
intf,
|
||||
options.getMXBeanMappingFactory());
|
||||
} else {
|
||||
this.mbean = new StandardMBeanSupport(implementation,
|
||||
Util.<Class<Object>>cast(getMBeanInterface()));
|
||||
this.mbean = new StandardMBeanSupport(implementation, intf);
|
||||
}
|
||||
}
|
||||
|
||||
@ -362,6 +460,19 @@ public class StandardMBean implements DynamicMBean, MBeanRegistration {
|
||||
return mbean.getResource().getClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the MBeanOptions that were specified or implied for this StandardMBean
|
||||
* instance. If an MBeanOptions object was supplied when this StandardMBean
|
||||
* instance was constructed, and if that object has not been modified in the
|
||||
* meantime, then the returned object will be equal to that object, although
|
||||
* it might not be the same object.
|
||||
* @return The MBeanOptions that were specified or implied for this StandardMBean
|
||||
* instance.
|
||||
*/
|
||||
public MBeanOptions getOptions() {
|
||||
return options.uncanonical();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// From the DynamicMBean interface.
|
||||
// ------------------------------------------------------------------
|
||||
@ -726,7 +837,7 @@ public class StandardMBean implements DynamicMBean, MBeanRegistration {
|
||||
* @return the MBeanNotificationInfo[] for the new MBeanInfo.
|
||||
**/
|
||||
MBeanNotificationInfo[] getNotifications(MBeanInfo info) {
|
||||
return null;
|
||||
return info.getNotifications();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1234,5 +1345,4 @@ public class StandardMBean implements DynamicMBean, MBeanRegistration {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -26,7 +26,7 @@
|
||||
package javax.management.openmbean;
|
||||
|
||||
import com.sun.jmx.mbeanserver.MXBeanLookup;
|
||||
import com.sun.jmx.mbeanserver.OpenConverter;
|
||||
import com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
@ -115,7 +115,12 @@ public class CompositeDataInvocationHandler implements InvocationHandler {
|
||||
is null.
|
||||
*/
|
||||
public CompositeDataInvocationHandler(CompositeData compositeData) {
|
||||
this(compositeData, null);
|
||||
this(compositeData, MXBeanMappingFactory.DEFAULT);
|
||||
}
|
||||
|
||||
public CompositeDataInvocationHandler(CompositeData compositeData,
|
||||
MXBeanMappingFactory mappingFactory) {
|
||||
this(compositeData, mappingFactory, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -134,11 +139,13 @@ public class CompositeDataInvocationHandler implements InvocationHandler {
|
||||
is null.
|
||||
*/
|
||||
CompositeDataInvocationHandler(CompositeData compositeData,
|
||||
MXBeanMappingFactory mappingFactory,
|
||||
MXBeanLookup lookup) {
|
||||
if (compositeData == null)
|
||||
throw new IllegalArgumentException("compositeData");
|
||||
this.compositeData = compositeData;
|
||||
this.lookup = lookup;
|
||||
this.mappingFactory = mappingFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -176,7 +183,7 @@ public class CompositeDataInvocationHandler implements InvocationHandler {
|
||||
}
|
||||
}
|
||||
|
||||
String propertyName = OpenConverter.propertyName(method);
|
||||
String propertyName = DefaultMXBeanMappingFactory.propertyName(method);
|
||||
if (propertyName == null) {
|
||||
throw new IllegalArgumentException("Method is not getter: " +
|
||||
method.getName());
|
||||
@ -185,7 +192,7 @@ public class CompositeDataInvocationHandler implements InvocationHandler {
|
||||
if (compositeData.containsKey(propertyName))
|
||||
openValue = compositeData.get(propertyName);
|
||||
else {
|
||||
String decap = OpenConverter.decapitalize(propertyName);
|
||||
String decap = DefaultMXBeanMappingFactory.decapitalize(propertyName);
|
||||
if (compositeData.containsKey(decap))
|
||||
openValue = compositeData.get(decap);
|
||||
else {
|
||||
@ -196,9 +203,10 @@ public class CompositeDataInvocationHandler implements InvocationHandler {
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
}
|
||||
OpenConverter converter =
|
||||
OpenConverter.toConverter(method.getGenericReturnType());
|
||||
return converter.fromOpenValue(lookup, openValue);
|
||||
MXBeanMapping mapping =
|
||||
mappingFactory.mappingForType(method.getGenericReturnType(),
|
||||
MXBeanMappingFactory.DEFAULT);
|
||||
return mapping.fromOpenValue(openValue);
|
||||
}
|
||||
|
||||
/* This method is called when equals(Object) is
|
||||
@ -242,4 +250,5 @@ public class CompositeDataInvocationHandler implements InvocationHandler {
|
||||
|
||||
private final CompositeData compositeData;
|
||||
private final MXBeanLookup lookup;
|
||||
private final MXBeanMappingFactory mappingFactory;
|
||||
}
|
||||
|
@ -159,8 +159,8 @@ public class CompositeType extends OpenType<CompositeData> {
|
||||
}
|
||||
|
||||
private static void checkForNullElement(Object[] arg, String argName) {
|
||||
if ( (arg == null) || (arg.length == 0) ) {
|
||||
throw new IllegalArgumentException("Argument "+ argName +"[] cannot be null or empty.");
|
||||
if (arg == null) {
|
||||
throw new IllegalArgumentException("Argument "+ argName +"[] cannot be null.");
|
||||
}
|
||||
for (int i=0; i<arg.length; i++) {
|
||||
if (arg[i] == null) {
|
||||
|
@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Sun designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Sun in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package javax.management.openmbean;
|
||||
|
||||
import java.io.InvalidObjectException;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* <p>A custom mapping between Java types and Open types for use in MXBeans.
|
||||
* To define such a mapping, subclass this class and define at least the
|
||||
* {@link #fromOpenValue fromOpenValue} and {@link #toOpenValue toOpenValue}
|
||||
* methods, and optionally the {@link #checkReconstructible} method.
|
||||
* Then either use an {@link MXBeanMappingClass} annotation on your custom
|
||||
* Java types, or include this MXBeanMapping in an
|
||||
* {@link MXBeanMappingFactory}.</p>
|
||||
*
|
||||
* <p>For example, suppose we have a class {@code MyLinkedList}, which looks
|
||||
* like this:</p>
|
||||
*
|
||||
* <pre>
|
||||
* public class MyLinkedList {
|
||||
* public MyLinkedList(String name, MyLinkedList next) {...}
|
||||
* public String getName() {...}
|
||||
* public MyLinkedList getNext() {...}
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>This is not a valid type for MXBeans, because it contains a
|
||||
* self-referential property "next" defined by the {@code getNext()}
|
||||
* method. MXBeans do not support recursive types. So we would like
|
||||
* to specify a mapping for {@code MyLinkedList} explicitly. When an
|
||||
* MXBean interface contains {@code MyLinkedList}, that will be mapped
|
||||
* into a {@code String[]}, which is a valid Open Type.</p>
|
||||
*
|
||||
* <p>To define this mapping, we first subclass {@code MXBeanMapping}:</p>
|
||||
*
|
||||
* <pre>
|
||||
* public class MyLinkedListMapping extends MXBeanMapping {
|
||||
* public MyLinkedListMapping(Type type) throws OpenDataException {
|
||||
* super(MyLinkedList.class, ArrayType.getArrayType(SimpleType.STRING));
|
||||
* if (type != MyLinkedList.class)
|
||||
* throw new OpenDataException("Mapping only valid for MyLinkedList");
|
||||
* }
|
||||
*
|
||||
* {@literal @Override}
|
||||
* public Object fromOpenValue(Object openValue) throws InvalidObjectException {
|
||||
* String[] array = (String[]) openValue;
|
||||
* MyLinkedList list = null;
|
||||
* for (int i = array.length - 1; i >= 0; i--)
|
||||
* list = new MyLinkedList(array[i], list);
|
||||
* return list;
|
||||
* }
|
||||
*
|
||||
* {@literal @Override}
|
||||
* public Object toOpenValue(Object javaValue) throws OpenDataException {
|
||||
* ArrayList<String> array = new ArrayList<String>();
|
||||
* for (MyLinkedList list = (MyLinkedList) javaValue; list != null;
|
||||
* list = list.getNext())
|
||||
* array.add(list.getName());
|
||||
* return array.toArray(new String[0]);
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>The call to the superclass constructor specifies what the
|
||||
* original Java type is ({@code MyLinkedList.class}) and what Open
|
||||
* Type it is mapped to ({@code
|
||||
* ArrayType.getArrayType(SimpleType.STRING)}). The {@code
|
||||
* fromOpenValue} method says how we go from the Open Type ({@code
|
||||
* String[]}) to the Java type ({@code MyLinkedList}), and the {@code
|
||||
* toOpenValue} method says how we go from the Java type to the Open
|
||||
* Type.</p>
|
||||
*
|
||||
* <p>With this mapping defined, we can annotate the {@code MyLinkedList}
|
||||
* class appropriately:</p>
|
||||
*
|
||||
* <pre>
|
||||
* {@literal @MXBeanMappingClass}(MyLinkedListMapping.class)
|
||||
* public class MyLinkedList {...}
|
||||
* </pre>
|
||||
*
|
||||
* <p>Now we can use {@code MyLinkedList} in an MXBean interface and it
|
||||
* will work.</p>
|
||||
*
|
||||
* <p>If we are unable to modify the {@code MyLinkedList} class,
|
||||
* we can define an {@link MXBeanMappingFactory}. See the documentation
|
||||
* of that class for further details.</p>
|
||||
*/
|
||||
public abstract class MXBeanMapping {
|
||||
private final Type javaType;
|
||||
private final OpenType<?> openType;
|
||||
private final Class<?> openClass;
|
||||
|
||||
/**
|
||||
* <p>Construct a mapping between the given Java type and the given
|
||||
* Open Type.</p>
|
||||
*
|
||||
* @param javaType the Java type (for example, {@code MyLinkedList}).
|
||||
* @param openType the Open Type (for example, {@code
|
||||
* ArrayType.getArrayType(SimpleType.STRING)})
|
||||
*
|
||||
* @throws NullPointerException if either argument is null.
|
||||
*/
|
||||
protected MXBeanMapping(Type javaType, OpenType<?> openType) {
|
||||
if (javaType == null || openType == null)
|
||||
throw new NullPointerException("Null argument");
|
||||
this.javaType = javaType;
|
||||
this.openType = openType;
|
||||
this.openClass = makeOpenClass(javaType, openType);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>The Java type that was supplied to the constructor.</p>
|
||||
* @return the Java type that was supplied to the constructor.
|
||||
*/
|
||||
public final Type getJavaType() {
|
||||
return javaType;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>The Open Type that was supplied to the constructor.</p>
|
||||
* @return the Open Type that was supplied to the constructor.
|
||||
*/
|
||||
public final OpenType<?> getOpenType() {
|
||||
return openType;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>The Java class that corresponds to instances of the
|
||||
* {@linkplain #getOpenType() Open Type} for this mapping.</p>
|
||||
* @return the Java class that corresponds to instances of the
|
||||
* Open Type for this mapping.
|
||||
* @see OpenType#getClassName
|
||||
*/
|
||||
public final Class<?> getOpenClass() {
|
||||
return openClass;
|
||||
}
|
||||
|
||||
private static Class<?> makeOpenClass(Type javaType, OpenType<?> openType) {
|
||||
if (javaType instanceof Class<?> && ((Class<?>) javaType).isPrimitive())
|
||||
return (Class<?>) javaType;
|
||||
try {
|
||||
String className = OpenType.validClassName(openType.getClassName());
|
||||
return Class.forName(className, false, null);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException(e); // should not happen
|
||||
} catch (OpenDataException e) {
|
||||
throw new IllegalArgumentException("Bad OpenType: " + openType, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Convert an instance of the Open Type into the Java type.
|
||||
* @param openValue the value to be converted.
|
||||
* @return the converted value.
|
||||
* @throws InvalidObjectException if the value cannot be converted.
|
||||
*/
|
||||
public abstract Object fromOpenValue(Object openValue)
|
||||
throws InvalidObjectException;
|
||||
|
||||
/**
|
||||
* <p>Convert an instance of the Java type into the Open Type.
|
||||
* @param javaValue the value to be converted.
|
||||
* @return the converted value.
|
||||
* @throws OpenDataException if the value cannot be converted.
|
||||
*/
|
||||
public abstract Object toOpenValue(Object javaValue)
|
||||
throws OpenDataException;
|
||||
|
||||
|
||||
/**
|
||||
* <p>Throw an appropriate InvalidObjectException if we will not
|
||||
* be able to convert back from the open data to the original Java
|
||||
* object. The {@link #fromOpenValue fromOpenValue} throws an
|
||||
* exception if a given open data value cannot be converted. This
|
||||
* method throws an exception if <em>no</em> open data values can
|
||||
* be converted. The default implementation of this method never
|
||||
* throws an exception. Subclasses can override it as
|
||||
* appropriate.</p>
|
||||
* @throws InvalidObjectException if {@code fromOpenValue} will throw
|
||||
* an exception no matter what its argument is.
|
||||
*/
|
||||
public void checkReconstructible() throws InvalidObjectException {}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Sun designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Sun in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package javax.management.openmbean;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
|
||||
/**
|
||||
* Specifies the MXBean mapping to be used for this Java type.
|
||||
* @see MXBeanMapping
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@Documented @Inherited
|
||||
public @interface MXBeanMappingClass {
|
||||
/**
|
||||
* <p>The {@link MXBeanMapping} class to be used to map the
|
||||
* annotated type. This class must have a public constructor with
|
||||
* a single argument of type {@link java.lang.reflect.Type}. The
|
||||
* constructor will be called with the annotated type as an
|
||||
* argument. See the {@code MXBeanMapping} documentation
|
||||
* for an example.</p>
|
||||
*
|
||||
* <p>If the {@code MXBeanMapping} cannot in fact handle that
|
||||
* type, the constructor should throw an {@link
|
||||
* OpenDataException}. If the constructor throws this or any other
|
||||
* exception then an MXBean in which the annotated type appears is
|
||||
* invalid, and registering it in the MBean Server will produce a
|
||||
* {@link NotCompliantMBeanException}.
|
||||
*/
|
||||
public Class<? extends MXBeanMapping> value();
|
||||
}
|
@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Sun designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Sun in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package javax.management.openmbean;
|
||||
|
||||
import com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* <p>Defines how types are mapped for a given MXBean or set of MXBeans.
|
||||
* An {@code MXBeanMappingFactory} can be specified either through the
|
||||
* {@link MXBeanMappingFactoryClass} annotation, or through the
|
||||
* {@link javax.management.JMX.MBeanOptions JMX.MBeanOptions} argument to a
|
||||
* {@link javax.management.StandardMBean StandardMBean} constructor or MXBean
|
||||
* proxy.</p>
|
||||
*
|
||||
* <p>An {@code MXBeanMappingFactory} must return an {@code MXBeanMapping}
|
||||
* for any Java type that appears in the MXBeans that the factory is being
|
||||
* used for. Usually it does that by handling any custom types, and
|
||||
* forwarding everything else to the {@linkplain #DEFAULT default mapping
|
||||
* factory}.</p>
|
||||
*
|
||||
* <p>Consider the {@code MyLinkedList} example from the {@link MXBeanMapping}
|
||||
* documentation. If we are unable to change the {@code MyLinkedList} class
|
||||
* to add an {@link MXBeanMappingClass} annotation, we could achieve the same
|
||||
* effect by defining {@code MyLinkedListMappingFactory} as follows:</p>
|
||||
*
|
||||
* <pre>
|
||||
* public class MyLinkedListMappingFactory implements MXBeanMappingFactory {
|
||||
* public MyLinkedListMappingFactory() {}
|
||||
*
|
||||
* public MXBeanMapping mappingForType(Type t, MXBeanMappingFactory f)
|
||||
* throws OpenDataException {
|
||||
* if (t == MyLinkedList.class)
|
||||
* return new MyLinkedListMapping(t);
|
||||
* else
|
||||
* return MXBeanMappingFactory.DEFAULT.mappingForType(t, f);
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>The mapping factory handles only the {@code MyLinkedList} class.
|
||||
* Every other type is forwarded to the default mapping factory.
|
||||
* This includes types such as {@code MyLinkedList[]} and
|
||||
* {@code List<MyLinkedList>}; the default mapping factory will recursively
|
||||
* invoke {@code MyLinkedListMappingFactory} to map the contained
|
||||
* {@code MyLinkedList} type.</p>
|
||||
*
|
||||
* <p>Once we have defined {@code MyLinkedListMappingFactory}, we can use
|
||||
* it in an MXBean interface like this:</p>
|
||||
*
|
||||
* <pre>
|
||||
* {@literal @MXBeanMappingFactoryClass}(MyLinkedListMappingFactory.class)
|
||||
* public interface SomethingMXBean {
|
||||
* public MyLinkedList getSomething();
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>Alternatively we can annotate the package that {@code SomethingMXBean}
|
||||
* appears in, or we can supply the factory to a {@link
|
||||
* javax.management.StandardMBean StandardMBean} constructor or MXBean
|
||||
* proxy.</p>
|
||||
*/
|
||||
public abstract class MXBeanMappingFactory {
|
||||
/**
|
||||
* <p>Construct an instance of this class.</p>
|
||||
*/
|
||||
protected MXBeanMappingFactory() {}
|
||||
|
||||
/**
|
||||
* <p>Mapping factory that applies the default rules for MXBean
|
||||
* mappings, as described in the <a
|
||||
* href="../MXBean.html#MXBean-spec">MXBean specification</a>.</p>
|
||||
*/
|
||||
public static final MXBeanMappingFactory DEFAULT =
|
||||
new DefaultMXBeanMappingFactory();
|
||||
|
||||
/**
|
||||
* <p>Determine the appropriate MXBeanMappingFactory to use for the given
|
||||
* MXBean interface, based on its annotations. If the interface has an
|
||||
* {@link MXBeanMappingFactoryClass @MXBeanMappingFactoryClass} annotation,
|
||||
* that is used to determine the MXBeanMappingFactory. Otherwise, if the
|
||||
* package containing the interface has such an annotation, that is used.
|
||||
* Otherwise the MXBeanMappingFactory is the {@linkplain #DEFAULT default}
|
||||
* one.</p>
|
||||
*
|
||||
* @param intf the MXBean interface for which to determine the
|
||||
* MXBeanMappingFactory.
|
||||
*
|
||||
* @return the MXBeanMappingFactory for the given MXBean interface.
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code intf} is null, or if an
|
||||
* exception occurs while trying constructing an MXBeanMappingFactory
|
||||
* based on an annotation. In the second case, the exception will appear
|
||||
* in the {@linkplain Throwable#getCause() cause chain} of the
|
||||
* {@code IllegalArgumentException}.
|
||||
*/
|
||||
public static MXBeanMappingFactory forInterface(Class<?> intf) {
|
||||
if (intf == null)
|
||||
throw new IllegalArgumentException("Null interface");
|
||||
MXBeanMappingFactoryClass annot =
|
||||
intf.getAnnotation(MXBeanMappingFactoryClass.class);
|
||||
if (annot == null) {
|
||||
Package p = intf.getPackage();
|
||||
if (p != null)
|
||||
annot = p.getAnnotation(MXBeanMappingFactoryClass.class);
|
||||
}
|
||||
if (annot == null)
|
||||
return MXBeanMappingFactory.DEFAULT;
|
||||
Class<? extends MXBeanMappingFactory> factoryClass = annot.value();
|
||||
try {
|
||||
return annot.value().newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException(
|
||||
"Could not instantiate MXBeanMappingFactory " +
|
||||
factoryClass.getName() +
|
||||
" from @MXBeanMappingFactoryClass", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the mapping for the given Java type. Typically, a
|
||||
* mapping factory will return mappings for types it handles, and
|
||||
* forward other types to another mapping factory, most often
|
||||
* the {@linkplain #DEFAULT default one}.</p>
|
||||
* @param t the Java type to be mapped.
|
||||
* @param f the original mapping factory that was consulted to do
|
||||
* the mapping. A mapping factory should pass this parameter intact
|
||||
* if it forwards a type to another mapping factory. In the example,
|
||||
* this is how {@code MyLinkedListMappingFactory} works for types
|
||||
* like {@code MyLinkedList[]} and {@code List<MyLinkedList>}.
|
||||
* @return the mapping for the given type.
|
||||
* @throws OpenDataException if this type cannot be mapped. This
|
||||
* exception is appropriate if the factory is supposed to handle
|
||||
* all types of this sort (for example, all linked lists), but
|
||||
* cannot handle this particular type.
|
||||
*/
|
||||
public abstract MXBeanMapping mappingForType(Type t, MXBeanMappingFactory f)
|
||||
throws OpenDataException;
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Sun designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Sun in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package javax.management.openmbean;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* <p>Specifies the MXBean mapping factory to be used for Java types
|
||||
* in an MXBean interface, or in all MXBean interfaces in a package.</p>
|
||||
*
|
||||
* <p>Applying a mapping factory to all Java types in an MXBean interface
|
||||
* looks like this:</p>
|
||||
*
|
||||
* <pre>
|
||||
* {@literal @MXBeanMappingFactoryClass}(MyLinkedListMappingFactory.class)
|
||||
* public interface SomethingMXBean {
|
||||
* public MyLinkedList getSomething();
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>Applying a mapping factory to all Java types in all MXBean interfaces
|
||||
* in a package, say {@code com.example.mxbeans}, looks like this. In the
|
||||
* package source directory, create a file called {@code package-info.java}
|
||||
* with these contents:</p>
|
||||
*
|
||||
* <pre>
|
||||
* {@literal @MXBeanMappingFactoryClass}(MyLinkedListMappingFactory.class)
|
||||
* package com.example.mxbeans;
|
||||
* </pre>
|
||||
*
|
||||
* @see MXBeanMappingFactory
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE, ElementType.PACKAGE})
|
||||
@Documented @Inherited
|
||||
public @interface MXBeanMappingFactoryClass {
|
||||
/**
|
||||
* <p>The {@link MXBeanMappingFactory} class to be used to map
|
||||
* types in the annotated interface or package. This class must
|
||||
* have a public constructor with no arguments. See the {@code
|
||||
* MXBeanMappingFactory} documentation for an example.</p>
|
||||
*/
|
||||
public Class<? extends MXBeanMappingFactory> value();
|
||||
}
|
@ -219,7 +219,7 @@ public abstract class OpenType<T> implements Serializable {
|
||||
});
|
||||
}
|
||||
|
||||
private static String validClassName(String className) throws OpenDataException {
|
||||
static String validClassName(String className) throws OpenDataException {
|
||||
className = valid("className", className);
|
||||
|
||||
// Check if className describes an array class, and determines its elements' class name.
|
||||
|
@ -37,7 +37,7 @@ import java.security.*;
|
||||
|
||||
public class CharsetMapping {
|
||||
public final static char UNMAPPABLE_DECODING = '\uFFFD';
|
||||
public final static int UNMAPPABLE_ENCODING = -1;
|
||||
public final static int UNMAPPABLE_ENCODING = 0xFFFD;
|
||||
|
||||
char[] b2cSB; //singlebyte b->c
|
||||
char[] b2cDB1; //dobulebyte b->c /db1
|
||||
@ -109,9 +109,11 @@ public class CharsetMapping {
|
||||
}
|
||||
|
||||
public int encodeSurrogate(char hi, char lo) {
|
||||
char c = (char)Character.toCodePoint(hi, lo);
|
||||
int cp = Character.toCodePoint(hi, lo);
|
||||
if (cp < 0x20000 || cp >= 0x30000)
|
||||
return UNMAPPABLE_ENCODING;
|
||||
int end = c2bSupp.length / 2;
|
||||
int i = Arrays.binarySearch(c2bSupp, 0, end, c);
|
||||
int i = Arrays.binarySearch(c2bSupp, 0, end, (char)cp);
|
||||
if (i >= 0)
|
||||
return c2bSupp[end + i];
|
||||
return UNMAPPABLE_ENCODING;
|
||||
|
@ -274,15 +274,15 @@ public class SJIS_0213 extends Charset {
|
||||
leftoverBase = c;
|
||||
} else {
|
||||
db = encodeChar(c);
|
||||
if (db > MAX_SINGLEBYTE) { // DoubleByte
|
||||
if (db <= MAX_SINGLEBYTE) { // SingleByte
|
||||
if (dl <= dp)
|
||||
return CoderResult.OVERFLOW;
|
||||
da[dp++] = (byte)db;
|
||||
} else if (db != UNMAPPABLE) { // DoubleByte
|
||||
if (dl - dp < 2)
|
||||
return CoderResult.OVERFLOW;
|
||||
da[dp++] = (byte)(db >> 8);
|
||||
da[dp++] = (byte)db;
|
||||
} else if (db != UNMAPPABLE) { // SingleByte
|
||||
if (dl <= dp)
|
||||
return CoderResult.OVERFLOW;
|
||||
da[dp++] = (byte)db;
|
||||
} else if (Character.isHighSurrogate(c)) {
|
||||
if ((sp + 1) == sl)
|
||||
return CoderResult.UNDERFLOW;
|
||||
@ -297,6 +297,8 @@ public class SJIS_0213 extends Charset {
|
||||
da[dp++] = (byte)(db >> 8);
|
||||
da[dp++] = (byte)db;
|
||||
sp++;
|
||||
} else if (Character.isLowSurrogate(c)) {
|
||||
return CoderResult.malformedForLength(1);
|
||||
} else {
|
||||
return CoderResult.unmappableForLength(1);
|
||||
}
|
||||
@ -337,15 +339,15 @@ public class SJIS_0213 extends Charset {
|
||||
leftoverBase = c;
|
||||
} else {
|
||||
db = encodeChar(c);
|
||||
if (db > MAX_SINGLEBYTE) { // DoubleByte
|
||||
if (db <= MAX_SINGLEBYTE) { // Single-byte
|
||||
if (dst.remaining() < 1)
|
||||
return CoderResult.OVERFLOW;
|
||||
dst.put((byte)db);
|
||||
} else if (db != UNMAPPABLE) { // DoubleByte
|
||||
if (dst.remaining() < 2)
|
||||
return CoderResult.OVERFLOW;
|
||||
dst.put((byte)(db >> 8));
|
||||
dst.put((byte)(db));
|
||||
} else if (db != UNMAPPABLE) { // Single-byte
|
||||
if (dst.remaining() < 1)
|
||||
return CoderResult.OVERFLOW;
|
||||
dst.put((byte)db);
|
||||
} else if (Character.isHighSurrogate(c)) {
|
||||
if (!src.hasRemaining()) // Surrogates
|
||||
return CoderResult.UNDERFLOW;
|
||||
@ -360,6 +362,8 @@ public class SJIS_0213 extends Charset {
|
||||
dst.put((byte)(db >> 8));
|
||||
dst.put((byte)(db));
|
||||
mark++;
|
||||
} else if (Character.isLowSurrogate(c)) {
|
||||
return CoderResult.malformedForLength(1);
|
||||
} else {
|
||||
return CoderResult.unmappableForLength(1);
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ Java_java_lang_System_identityHashCode(JNIEnv *env, jobject this, jobject x)
|
||||
#define VENDOR_URL_BUG "http://java.sun.com/cgi-bin/bugreport.cgi"
|
||||
#endif
|
||||
|
||||
#define JAVA_MAX_SUPPORTED_VERSION 50
|
||||
#define JAVA_MAX_SUPPORTED_VERSION 51
|
||||
#define JAVA_MAX_SUPPORTED_MINOR_VERSION 0
|
||||
|
||||
JNIEXPORT jobject JNICALL
|
||||
|
@ -50,15 +50,6 @@
|
||||
*/
|
||||
sys_mon_t _dl_lock;
|
||||
|
||||
/*
|
||||
* glibc-2.0 libdl is not MT safe. If you are building with any glibc,
|
||||
* chances are you might want to run the generated bits against glibc-2.0
|
||||
* libdl.so, so always use locking for any version of glibc.
|
||||
*/
|
||||
#ifdef __GLIBC__
|
||||
#define NEED_DL_LOCK
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Solaris green threads needs to lock around libdl.so.
|
||||
*/
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 4989690 6259855
|
||||
* @bug 4989690 6259855 6706299
|
||||
* @summary Check that version-related system property invariants hold.
|
||||
* @author Martin Buchholz
|
||||
*/
|
||||
|
590
jdk/test/javax/management/mxbean/CustomTypeTest.java
Normal file
590
jdk/test/javax/management/mxbean/CustomTypeTest.java
Normal file
@ -0,0 +1,590 @@
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
/* @test %M% %I%
|
||||
* @bug 6562936
|
||||
* @run compile customtypes/package-info.java
|
||||
* @run main CustomTypeTest
|
||||
*/
|
||||
|
||||
import java.io.InvalidObjectException;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import javax.management.JMX;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.StandardMBean;
|
||||
import javax.management.Descriptor;
|
||||
import javax.management.MBeanServerInvocationHandler;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.openmbean.ArrayType;
|
||||
import javax.management.openmbean.CompositeData;
|
||||
import javax.management.openmbean.CompositeDataSupport;
|
||||
import javax.management.openmbean.CompositeType;
|
||||
import javax.management.openmbean.MXBeanMapping;
|
||||
import javax.management.openmbean.MXBeanMappingClass;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
import javax.management.openmbean.MXBeanMappingFactoryClass;
|
||||
import javax.management.openmbean.OpenDataException;
|
||||
import javax.management.openmbean.OpenType;
|
||||
import javax.management.openmbean.SimpleType;
|
||||
import javax.management.openmbean.TabularData;
|
||||
|
||||
import static javax.management.JMX.MBeanOptions;
|
||||
|
||||
import customtypes.*;
|
||||
|
||||
public class CustomTypeTest {
|
||||
@MXBeanMappingClass(LinkedListMapping.class)
|
||||
public static class LinkedList {
|
||||
private final String name;
|
||||
private final LinkedList next;
|
||||
|
||||
public LinkedList(String name, LinkedList next) {
|
||||
this.name = name;
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public LinkedList getNext() {
|
||||
return next;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
if (next == null)
|
||||
return "(" + name + ")";
|
||||
else
|
||||
return "(" + name + " " + next + ")";
|
||||
}
|
||||
|
||||
public boolean equals(Object x) {
|
||||
if (!(x instanceof LinkedList))
|
||||
return false;
|
||||
LinkedList other = (LinkedList) x;
|
||||
return (this.name.equals(other.name) &&
|
||||
(this.next == null ? other.next == null :
|
||||
this.next.equals(other.next)));
|
||||
}
|
||||
}
|
||||
|
||||
public static class LinkedListMapping extends MXBeanMapping {
|
||||
public LinkedListMapping(Type type) throws OpenDataException {
|
||||
super(LinkedList.class, ArrayType.getArrayType(SimpleType.STRING));
|
||||
if (type != LinkedList.class) {
|
||||
throw new OpenDataException("Mapping only valid for " +
|
||||
LinkedList.class);
|
||||
}
|
||||
}
|
||||
|
||||
public Object fromOpenValue(Object openValue) throws InvalidObjectException {
|
||||
String[] array = (String[]) openValue;
|
||||
LinkedList list = null;
|
||||
for (int i = array.length - 1; i >= 0; i--)
|
||||
list = new LinkedList(array[i], list);
|
||||
return list;
|
||||
}
|
||||
|
||||
public Object toOpenValue(Object javaValue) throws OpenDataException {
|
||||
ArrayList<String> array = new ArrayList<String>();
|
||||
for (LinkedList list = (LinkedList) javaValue; list != null;
|
||||
list = list.getNext())
|
||||
array.add(list.getName());
|
||||
return array.toArray(new String[0]);
|
||||
}
|
||||
}
|
||||
|
||||
public static interface LinkedListMXBean {
|
||||
public LinkedList getLinkedList();
|
||||
}
|
||||
|
||||
public static class LinkedListImpl implements LinkedListMXBean {
|
||||
public LinkedList getLinkedList() {
|
||||
return new LinkedList("car", new LinkedList("cdr", null));
|
||||
}
|
||||
}
|
||||
|
||||
public static class ObjectMXBeanMapping extends MXBeanMapping {
|
||||
private static final CompositeType wildcardType;
|
||||
|
||||
static {
|
||||
try {
|
||||
wildcardType =
|
||||
new CompositeType(Object.class.getName(),
|
||||
"Wildcard type for Object",
|
||||
new String[0], // itemNames
|
||||
new String[0], // itemDescriptions
|
||||
new OpenType<?>[0]); // itemTypes
|
||||
} catch (OpenDataException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public ObjectMXBeanMapping() {
|
||||
super(Object.class, wildcardType);
|
||||
}
|
||||
|
||||
public Object fromOpenValue(Object openValue) throws InvalidObjectException {
|
||||
if (!(openValue instanceof CompositeData)) {
|
||||
throw new InvalidObjectException("Not a CompositeData: " +
|
||||
openValue.getClass());
|
||||
}
|
||||
CompositeData cd = (CompositeData) openValue;
|
||||
if (!cd.containsKey("value")) {
|
||||
throw new InvalidObjectException("CompositeData does not " +
|
||||
"contain a \"value\" item: " + cd);
|
||||
}
|
||||
Object x = cd.get("value");
|
||||
if (!(x instanceof CompositeData || x instanceof TabularData ||
|
||||
x instanceof Object[]))
|
||||
return x;
|
||||
|
||||
String typeName = (String) cd.get("type");
|
||||
if (typeName == null) {
|
||||
throw new InvalidObjectException("CompositeData does not " +
|
||||
"contain a \"type\" item: " + cd);
|
||||
}
|
||||
Class<?> c;
|
||||
try {
|
||||
c = Class.forName(typeName);
|
||||
} catch (ClassNotFoundException e) {
|
||||
InvalidObjectException ioe =
|
||||
new InvalidObjectException("Could not find type");
|
||||
ioe.initCause(e);
|
||||
throw ioe;
|
||||
}
|
||||
MXBeanMapping mapping;
|
||||
try {
|
||||
mapping = objectMappingFactory.mappingForType(c, objectMappingFactory);
|
||||
} catch (OpenDataException e) {
|
||||
InvalidObjectException ioe =
|
||||
new InvalidObjectException("Could not map object's " +
|
||||
"type " + c.getName());
|
||||
ioe.initCause(e);
|
||||
throw ioe;
|
||||
}
|
||||
return mapping.fromOpenValue(x);
|
||||
}
|
||||
|
||||
public Object toOpenValue(Object javaValue) throws OpenDataException {
|
||||
OpenType<?> openType;
|
||||
Object openValue;
|
||||
String typeName;
|
||||
if (javaValue == null) {
|
||||
openType = SimpleType.VOID;
|
||||
openValue = null;
|
||||
typeName = null;
|
||||
} else {
|
||||
Class<?> c = javaValue.getClass();
|
||||
if (c.equals(Object.class))
|
||||
throw new OpenDataException("Cannot map Object to an open value");
|
||||
MXBeanMapping mapping =
|
||||
objectMappingFactory.mappingForType(c, objectMappingFactory);
|
||||
openType = mapping.getOpenType();
|
||||
openValue = mapping.toOpenValue(javaValue);
|
||||
typeName = c.getName();
|
||||
}
|
||||
CompositeType ct = new CompositeType(
|
||||
(javaValue == null) ? "null" : openType.getClassName(),
|
||||
"Open Mapping for Object",
|
||||
new String[] {"type", "value"},
|
||||
new String[] {"type", "value"},
|
||||
new OpenType<?>[] {SimpleType.STRING, openType});
|
||||
return new CompositeDataSupport(
|
||||
ct,
|
||||
new String[] {"type", "value"},
|
||||
new Object[] {typeName, openValue});
|
||||
}
|
||||
}
|
||||
|
||||
public static class ObjectMappingFactory extends MXBeanMappingFactory {
|
||||
private static MXBeanMapping objectMapping =
|
||||
new ObjectMXBeanMapping();
|
||||
|
||||
@Override
|
||||
public MXBeanMapping mappingForType(Type t, MXBeanMappingFactory f)
|
||||
throws OpenDataException {
|
||||
if (t.equals(Object.class))
|
||||
return objectMapping;
|
||||
else
|
||||
return MXBeanMappingFactory.DEFAULT.mappingForType(t, f);
|
||||
}
|
||||
}
|
||||
|
||||
private static MXBeanMappingFactory objectMappingFactory =
|
||||
new ObjectMappingFactory();
|
||||
|
||||
public static interface ObjectMXBean {
|
||||
public Object getObject();
|
||||
public Object[] getObjects();
|
||||
public List<Object> getObjectList();
|
||||
public Object[][] getMoreObjects();
|
||||
}
|
||||
|
||||
public static class ObjectImpl implements ObjectMXBean {
|
||||
public Object getObject() {
|
||||
return 123;
|
||||
}
|
||||
|
||||
private static Object[] objects = {
|
||||
"foo", 3, 3.14f, 3.14, 3L, new Date(), ObjectName.WILDCARD,
|
||||
new byte[3], new char[3], new int[3][3],
|
||||
new LinkedListImpl().getLinkedList(),
|
||||
};
|
||||
|
||||
public Object[] getObjects() {
|
||||
return objects;
|
||||
}
|
||||
|
||||
public List<Object> getObjectList() {
|
||||
return Arrays.asList(getObjects());
|
||||
}
|
||||
|
||||
public Object[][] getMoreObjects() {
|
||||
return new Object[][] {{getObjects()}};
|
||||
}
|
||||
}
|
||||
|
||||
@MXBeanMappingFactoryClass(ObjectMappingFactory.class)
|
||||
public static interface AnnotatedObjectMXBean extends ObjectMXBean {}
|
||||
|
||||
public static class AnnotatedObjectImpl extends ObjectImpl
|
||||
implements AnnotatedObjectMXBean {}
|
||||
|
||||
public static class BrokenMappingFactory extends MXBeanMappingFactory {
|
||||
public MXBeanMapping mappingForType(Type t, MXBeanMappingFactory f)
|
||||
throws OpenDataException {
|
||||
throw new OpenDataException(t.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public static class ReallyBrokenMappingFactory extends BrokenMappingFactory {
|
||||
public ReallyBrokenMappingFactory() {
|
||||
throw new RuntimeException("Oops");
|
||||
}
|
||||
}
|
||||
|
||||
@MXBeanMappingFactoryClass(BrokenMappingFactory.class)
|
||||
public static interface BrokenMXBean {
|
||||
public int getX();
|
||||
}
|
||||
|
||||
public static class BrokenImpl implements BrokenMXBean {
|
||||
public int getX() {return 0;}
|
||||
}
|
||||
|
||||
@MXBeanMappingFactoryClass(ReallyBrokenMappingFactory.class)
|
||||
public static interface ReallyBrokenMXBean {
|
||||
public int getX();
|
||||
}
|
||||
|
||||
public static class ReallyBrokenImpl implements ReallyBrokenMXBean {
|
||||
public int getX() {return 0;}
|
||||
}
|
||||
|
||||
public static class BrokenMapping extends MXBeanMapping {
|
||||
public BrokenMapping(Type t) {
|
||||
super(t, SimpleType.STRING);
|
||||
throw new RuntimeException("Oops");
|
||||
}
|
||||
|
||||
public Object fromOpenValue(Object openValue) throws InvalidObjectException {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
public Object toOpenValue(Object javaValue) throws OpenDataException {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
@MXBeanMappingClass(BrokenMapping.class)
|
||||
public static class BrokenType {}
|
||||
|
||||
public static interface BrokenTypeMXBean {
|
||||
BrokenType getBroken();
|
||||
}
|
||||
|
||||
public static class BrokenTypeImpl implements BrokenTypeMXBean {
|
||||
public BrokenType getBroken() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
|
||||
|
||||
System.out.println("Test @MXBeanMappingClass");
|
||||
ObjectName linkedName = new ObjectName("d:type=LinkedList");
|
||||
LinkedListMXBean linkedListMXBean = new LinkedListImpl();
|
||||
LinkedList list1 = linkedListMXBean.getLinkedList();
|
||||
mbs.registerMBean(linkedListMXBean, linkedName);
|
||||
LinkedListMXBean linkedProxy =
|
||||
JMX.newMXBeanProxy(mbs, linkedName, LinkedListMXBean.class);
|
||||
MBeanServerInvocationHandler mbsih = (MBeanServerInvocationHandler)
|
||||
Proxy.getInvocationHandler(linkedProxy);
|
||||
if (!mbsih.isMXBean())
|
||||
fail("not MXBean proxy");
|
||||
LinkedList list2 = linkedProxy.getLinkedList();
|
||||
if (list1 == list2)
|
||||
fail("lists identical!");
|
||||
// They should have gone through the mapping and back,
|
||||
// and the mapping doesn't do anything that would allow it
|
||||
// to restore the identical object.
|
||||
if (!list1.equals(list2))
|
||||
fail("lists different: " + list1 + " vs " + list2);
|
||||
System.out.println("...success");
|
||||
|
||||
System.out.println("Test StandardMBean with MXBeanMappingFactory");
|
||||
ObjectMXBean wildcardMBean = new ObjectImpl();
|
||||
MBeanOptions options = new MBeanOptions();
|
||||
options.setMXBeanMappingFactory(objectMappingFactory);
|
||||
if (!options.isMXBean())
|
||||
fail("Setting MXBeanMappingFactory should imply MXBean");
|
||||
StandardMBean wildcardStandardMBean =
|
||||
new StandardMBean(wildcardMBean, ObjectMXBean.class, options);
|
||||
testWildcardMBean(mbs, wildcardMBean, wildcardStandardMBean,
|
||||
options, ObjectMXBean.class);
|
||||
|
||||
System.out.println("Test @MXBeanMappingFactoryClass on interface");
|
||||
ObjectMXBean annotatedWildcardMBean = new AnnotatedObjectImpl();
|
||||
testWildcardMBean(mbs, annotatedWildcardMBean, annotatedWildcardMBean,
|
||||
null, AnnotatedObjectMXBean.class);
|
||||
|
||||
System.out.println("Test @MXBeanMappingFactoryClass on package");
|
||||
CustomMXBean custom = zeroProxy(CustomMXBean.class);
|
||||
ObjectName customName = new ObjectName("d:type=Custom");
|
||||
mbs.registerMBean(custom, customName);
|
||||
Object x = mbs.getAttribute(customName, "X");
|
||||
if (!(x instanceof String))
|
||||
fail("Should be String: " + x + " (a " + x.getClass().getName() + ")");
|
||||
CustomMXBean customProxy =
|
||||
JMX.newMXBeanProxy(mbs, customName, CustomMXBean.class);
|
||||
x = customProxy.getX();
|
||||
if (!(x instanceof Integer) || (Integer) x != 0)
|
||||
fail("Wrong return from proxy: " + x + " (a " + x.getClass().getName() + ")");
|
||||
|
||||
System.out.println("Test MXBeanMappingFactory exception");
|
||||
try {
|
||||
mbs.registerMBean(new BrokenImpl(), new ObjectName("d:type=Broken"));
|
||||
fail("Register did not throw exception");
|
||||
} catch (NotCompliantMBeanException e) {
|
||||
System.out.println("...OK: threw: " + e);
|
||||
}
|
||||
|
||||
System.out.println("Test MXBeanMappingFactory constructor exception");
|
||||
try {
|
||||
mbs.registerMBean(new ReallyBrokenImpl(), new ObjectName("d:type=Broken"));
|
||||
fail("Register did not throw exception");
|
||||
} catch (IllegalArgumentException e) {
|
||||
System.out.println("...OK: threw: " + e);
|
||||
}
|
||||
|
||||
System.out.println("Test MXBeanMappingFactory exception with StandardMBean");
|
||||
MXBeanMappingFactory brokenF = new BrokenMappingFactory();
|
||||
MBeanOptions brokenO = new MBeanOptions();
|
||||
brokenO.setMXBeanMappingFactory(brokenF);
|
||||
try {
|
||||
new StandardMBean(wildcardMBean, ObjectMXBean.class, brokenO);
|
||||
fail("StandardMBean with broken factory did not throw exception");
|
||||
} catch (IllegalArgumentException e) {
|
||||
if (!(e.getCause() instanceof NotCompliantMBeanException)) {
|
||||
fail("StandardMBean with broken factory threw wrong exception: "
|
||||
+ e.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("Test MXBeanMappingClass exception");
|
||||
try {
|
||||
mbs.registerMBean(new BrokenTypeImpl(), new ObjectName("d:type=Broken"));
|
||||
fail("Broken MXBeanMappingClass did not throw exception");
|
||||
} catch (NotCompliantMBeanException e) {
|
||||
System.out.println("...OK: threw: " + e);
|
||||
}
|
||||
|
||||
if (failure == null)
|
||||
System.out.println("TEST PASSED");
|
||||
else
|
||||
throw new Exception("TEST FAILED: " + failure);
|
||||
}
|
||||
|
||||
private static void testWildcardMBean(MBeanServer mbs, ObjectMXBean impl,
|
||||
Object mbean,
|
||||
MBeanOptions proxyOptions,
|
||||
Class<? extends ObjectMXBean> intf)
|
||||
throws Exception {
|
||||
ObjectName wildcardName = new ObjectName("d:type=Object");
|
||||
mbs.registerMBean(mbean, wildcardName);
|
||||
try {
|
||||
testWildcardMBean2(mbs, impl, wildcardName, proxyOptions, intf);
|
||||
} finally {
|
||||
mbs.unregisterMBean(wildcardName);
|
||||
}
|
||||
}
|
||||
|
||||
private static void testWildcardMBean2(MBeanServer mbs, ObjectMXBean impl,
|
||||
ObjectName wildcardName,
|
||||
MBeanOptions proxyOptions,
|
||||
Class<? extends ObjectMXBean> intf)
|
||||
throws Exception {
|
||||
if (proxyOptions == null) {
|
||||
proxyOptions = new MBeanOptions();
|
||||
MXBeanMappingFactory f = MXBeanMappingFactory.forInterface(intf);
|
||||
proxyOptions.setMXBeanMappingFactory(f);
|
||||
}
|
||||
Descriptor d = mbs.getMBeanInfo(wildcardName).getDescriptor();
|
||||
String factoryName = (String)
|
||||
d.getFieldValue(JMX.MXBEAN_MAPPING_FACTORY_CLASS_FIELD);
|
||||
if (!ObjectMappingFactory.class.getName().equals(factoryName)) {
|
||||
fail("Descriptor has wrong MXBeanMappingFactory: " + factoryName +
|
||||
" should be " + ObjectMappingFactory.class.getName());
|
||||
}
|
||||
ObjectMXBean wildcardProxy =
|
||||
JMX.newMBeanProxy(mbs, wildcardName, intf, proxyOptions);
|
||||
MBeanServerInvocationHandler mbsih = (MBeanServerInvocationHandler)
|
||||
Proxy.getInvocationHandler(wildcardProxy);
|
||||
MBeanOptions opts = mbsih.getMBeanOptions();
|
||||
if (!opts.equals(proxyOptions)) {
|
||||
fail("Proxy options differ from request: " + opts + " vs " +
|
||||
proxyOptions);
|
||||
}
|
||||
Method[] wildcardMethods = ObjectMXBean.class.getMethods();
|
||||
for (Method m : wildcardMethods) {
|
||||
System.out.println("..." + m.getName());
|
||||
Object orig = m.invoke(impl);
|
||||
Object copy = m.invoke(wildcardProxy);
|
||||
if (!deepEquals(orig, copy)) {
|
||||
fail("objects differ: " + deepToString(orig) + " vs " +
|
||||
deepToString(copy));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> T zeroProxy(Class<T> intf) {
|
||||
return intf.cast(Proxy.newProxyInstance(intf.getClassLoader(),
|
||||
new Class<?>[] {intf},
|
||||
new ZeroInvocationHandler()));
|
||||
}
|
||||
|
||||
private static class ZeroInvocationHandler implements InvocationHandler {
|
||||
public Object invoke(Object proxy, Method method, Object[] args)
|
||||
throws Throwable {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean deepEquals(Object x, Object y) {
|
||||
if (x == y)
|
||||
return true;
|
||||
if (x == null || y == null)
|
||||
return false;
|
||||
|
||||
if (x instanceof Collection<?>) {
|
||||
if (!(y instanceof Collection<?>))
|
||||
return false;
|
||||
Collection<?> xcoll = (Collection<?>) x;
|
||||
Collection<?> ycoll = (Collection<?>) y;
|
||||
if (xcoll.size() != ycoll.size())
|
||||
return false;
|
||||
Iterator<?> xit = xcoll.iterator();
|
||||
Iterator<?> yit = ycoll.iterator();
|
||||
while (xit.hasNext()) {
|
||||
if (!deepEquals(xit.next(), yit.next()))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Class<?> xclass = x.getClass();
|
||||
Class<?> yclass = y.getClass();
|
||||
if (xclass.isArray()) {
|
||||
if (!yclass.isArray())
|
||||
return false;
|
||||
if (!xclass.getComponentType().equals(yclass.getComponentType()))
|
||||
return false;
|
||||
int len = Array.getLength(x);
|
||||
if (Array.getLength(y) != len)
|
||||
return false;
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (!deepEquals(Array.get(x, i), Array.get(y, i)))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// return x.equals(y);
|
||||
if (x.equals(y))
|
||||
return true;
|
||||
System.out.println("Not equal: <" + x + "> and <" + y + ">");
|
||||
return false;
|
||||
}
|
||||
|
||||
private static String deepToString(Object x) {
|
||||
if (x == null)
|
||||
return "null";
|
||||
|
||||
if (x instanceof Collection<?>) {
|
||||
Collection<?> xcoll = (Collection<?>) x;
|
||||
StringBuilder sb = new StringBuilder("[");
|
||||
for (Object e : xcoll) {
|
||||
if (sb.length() > 1)
|
||||
sb.append(", ");
|
||||
sb.append(deepToString(e));
|
||||
}
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
if (x instanceof Object[]) {
|
||||
Object[] xarr = (Object[]) x;
|
||||
return deepToString(Arrays.asList(xarr));
|
||||
}
|
||||
|
||||
if (x.getClass().isArray()) { // primitive array
|
||||
String s = Arrays.deepToString(new Object[] {x});
|
||||
return s.substring(1, s.length() - 1);
|
||||
}
|
||||
|
||||
return x.toString();
|
||||
}
|
||||
|
||||
private static void fail(String msg) {
|
||||
System.out.println("TEST FAILED: " + msg);
|
||||
if (msg.length() > 100)
|
||||
msg = msg.substring(0, 100) + "...";
|
||||
failure = msg;
|
||||
}
|
||||
|
||||
private static String failure;
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
// CustomLongMXBean.java - see CustomTypeTest
|
||||
|
||||
package customtypes;
|
||||
|
||||
import javax.management.openmbean.MXBeanMappingFactoryClass;
|
||||
|
||||
@MXBeanMappingFactoryClass(IntegerIsLongFactory.class)
|
||||
public interface CustomLongMXBean extends CustomMXBean {}
|
@ -1,12 +1,10 @@
|
||||
/*
|
||||
* Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Sun designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Sun in the LICENSE file that accompanied this code.
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
@ -23,16 +21,10 @@
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package javax.management;
|
||||
// CustomMXBean.java - see CustomTypeTest
|
||||
|
||||
/* QueryExp classes can extend this to get non-default treatment for
|
||||
* Query.toString(q). We're reluctant to change the public toString()
|
||||
* methods of the classes because people might be parsing them, even
|
||||
* though that's rather fragile. But Query.toString(q) has no such
|
||||
* constraint so it can use the new toQueryString() method defined here.
|
||||
*/
|
||||
class ToQueryString {
|
||||
String toQueryString() {
|
||||
return toString();
|
||||
}
|
||||
package customtypes;
|
||||
|
||||
public interface CustomMXBean {
|
||||
public Integer getX();
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
// IntegerIsLongFactory.java - see CustomTypeTest
|
||||
|
||||
package customtypes;
|
||||
|
||||
import java.io.InvalidObjectException;
|
||||
import java.lang.reflect.Type;
|
||||
import javax.management.openmbean.MXBeanMapping;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
import javax.management.openmbean.OpenDataException;
|
||||
import javax.management.openmbean.SimpleType;
|
||||
|
||||
public class IntegerIsLongFactory implements MXBeanMappingFactory {
|
||||
public MXBeanMapping forType(Type t, MXBeanMappingFactory f)
|
||||
throws OpenDataException {
|
||||
if (t == Integer.class)
|
||||
return IntegerIsLongMapping;
|
||||
else
|
||||
return MXBeanMappingFactory.DEFAULT.forType(t, f);
|
||||
}
|
||||
|
||||
private static final MXBeanMapping IntegerIsLongMapping =
|
||||
new IntegerIsLongMapping();
|
||||
|
||||
private static class IntegerIsLongMapping extends MXBeanMapping {
|
||||
IntegerIsLongMapping() {
|
||||
super(Integer.class, SimpleType.STRING);
|
||||
}
|
||||
|
||||
public Object fromOpenValue(Object openValue)
|
||||
throws InvalidObjectException {
|
||||
try {
|
||||
return (Long) openValue;
|
||||
} catch (Exception e) {
|
||||
InvalidObjectException ioe = new InvalidObjectException("oops");
|
||||
ioe.initCause(e);
|
||||
throw ioe;
|
||||
}
|
||||
}
|
||||
|
||||
public Object toOpenValue(Object javaValue) throws OpenDataException {
|
||||
try {
|
||||
Integer i = (Integer) javaValue;
|
||||
return new Long((int) i);
|
||||
} catch (Exception e) {
|
||||
OpenDataException ode = new OpenDataException("oops");
|
||||
ode.initCause(e);
|
||||
throw ode;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
// IntegerIsStringFactory.java - see CustomTypeTest
|
||||
|
||||
package customtypes;
|
||||
|
||||
import java.io.InvalidObjectException;
|
||||
import java.lang.reflect.Type;
|
||||
import javax.management.openmbean.MXBeanMapping;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
import javax.management.openmbean.OpenDataException;
|
||||
import javax.management.openmbean.SimpleType;
|
||||
|
||||
public class IntegerIsStringFactory extends MXBeanMappingFactory {
|
||||
@Override
|
||||
public MXBeanMapping mappingForType(Type t, MXBeanMappingFactory f)
|
||||
throws OpenDataException {
|
||||
if (t == Integer.class)
|
||||
return integerIsStringMapping;
|
||||
else
|
||||
return MXBeanMappingFactory.DEFAULT.mappingForType(t, f);
|
||||
}
|
||||
|
||||
private static final MXBeanMapping integerIsStringMapping =
|
||||
new IntegerIsStringMapping();
|
||||
|
||||
private static class IntegerIsStringMapping extends MXBeanMapping {
|
||||
IntegerIsStringMapping() {
|
||||
super(Integer.class, SimpleType.STRING);
|
||||
}
|
||||
|
||||
public Object fromOpenValue(Object openValue)
|
||||
throws InvalidObjectException {
|
||||
try {
|
||||
String s = (String) openValue;
|
||||
return Integer.parseInt(s);
|
||||
} catch (Exception e) {
|
||||
InvalidObjectException ioe = new InvalidObjectException("oops");
|
||||
ioe.initCause(e);
|
||||
throw ioe;
|
||||
}
|
||||
}
|
||||
|
||||
public Object toOpenValue(Object javaValue) throws OpenDataException {
|
||||
try {
|
||||
Integer i = (Integer) javaValue;
|
||||
return i.toString();
|
||||
} catch (Exception e) {
|
||||
OpenDataException ode = new OpenDataException("oops");
|
||||
ode.initCause(e);
|
||||
throw ode;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
// package-info.java - test package annotations for custom types
|
||||
|
||||
@javax.management.openmbean.MXBeanMappingFactoryClass(IntegerIsStringFactory.class)
|
||||
package customtypes;
|
@ -121,14 +121,14 @@ public class QueryExpStringTest {
|
||||
eq, "(12345678) = (2.5)",
|
||||
between, "(12345678) between (2.5) and (2.5)",
|
||||
match, "attr like 'simpleString'",
|
||||
initial, "attr like 'simpleString%'",
|
||||
initialStar, "attr like '\\*%'",
|
||||
initialPercent, "attr like '\\%%'",
|
||||
any, "attr like '%simpleString%'",
|
||||
anyStar, "attr like '%\\*%'",
|
||||
anyPercent, "attr like '%\\%%'",
|
||||
ffinal, "attr like '%simpleString'",
|
||||
finalMagic, "attr like '%\\?\\*\\[\\\\'",
|
||||
initial, "attr like 'simpleString*'",
|
||||
initialStar, "attr like '\\**'",
|
||||
initialPercent, "attr like '%*'",
|
||||
any, "attr like '*simpleString*'",
|
||||
anyStar, "attr like '*\\**'",
|
||||
anyPercent, "attr like '*%*'",
|
||||
ffinal, "attr like '*simpleString'",
|
||||
finalMagic, "attr like '*\\?\\*\\[\\\\'",
|
||||
in, "12345678 in (12345678, 2.5)",
|
||||
and, "((12345678) > (2.5)) and ((12345678) < (2.5))",
|
||||
or, "((12345678) > (2.5)) or ((12345678) < (2.5))",
|
||||
@ -207,7 +207,6 @@ public class QueryExpStringTest {
|
||||
exp + " like " + pat);
|
||||
}
|
||||
StringValueExp spat = (StringValueExp) pat;
|
||||
spat = Query.value(translateMatch(spat.getValue()));
|
||||
return Query.match((AttributeValueExp) exp, spat);
|
||||
}
|
||||
|
||||
@ -226,28 +225,6 @@ public class QueryExpStringTest {
|
||||
throw new Exception("Expected in or like after expression");
|
||||
}
|
||||
|
||||
private static String translateMatch(String s) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < s.length(); i++) { // logic not correct for wide chars
|
||||
char c = s.charAt(i);
|
||||
switch (c) {
|
||||
case '\\':
|
||||
sb.append(c).append(s.charAt(++i)); break;
|
||||
case '%':
|
||||
sb.append('*'); break;
|
||||
case '_':
|
||||
sb.append('?'); break;
|
||||
case '*':
|
||||
sb.append("\\*"); break;
|
||||
case '?':
|
||||
sb.append("\\?"); break;
|
||||
default:
|
||||
sb.append(c); break;
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static QueryExp parseQueryAfterParen(String[] ss)
|
||||
throws Exception {
|
||||
/* This is very ugly. We might have "(q1) and (q2)" here, or
|
||||
|
@ -347,30 +347,30 @@ public class QueryParseTest {
|
||||
|
||||
// LIKE
|
||||
|
||||
"A like 'b%m'",
|
||||
"A like 'b*m'",
|
||||
expectTrue("blim"), expectTrue("bm"),
|
||||
expectFalse(""), expectFalse("blimmo"), expectFalse("mmm"),
|
||||
|
||||
"A not like 'b%m'",
|
||||
"A not like 'b*m'",
|
||||
expectFalse("blim"), expectFalse("bm"),
|
||||
expectTrue(""), expectTrue("blimmo"), expectTrue("mmm"),
|
||||
|
||||
"A like 'b_m'",
|
||||
"A like 'b?m'",
|
||||
expectTrue("bim"), expectFalse("blim"),
|
||||
|
||||
"A like '%can''t%'",
|
||||
"A like '*can''t*'",
|
||||
expectTrue("can't"),
|
||||
expectTrue("I'm sorry Dave, I'm afraid I can't do that"),
|
||||
expectFalse("cant"), expectFalse("can''t"),
|
||||
|
||||
"A like '\\%%\\%'",
|
||||
expectTrue("%blim%"), expectTrue("%%"),
|
||||
expectFalse("blim"), expectFalse("%asdf"), expectFalse("asdf%"),
|
||||
"A like '\\**\\*'",
|
||||
expectTrue("*blim*"), expectTrue("**"),
|
||||
expectFalse("blim"), expectFalse("*asdf"), expectFalse("asdf*"),
|
||||
|
||||
"A LIKE '*%?_'",
|
||||
expectTrue("*blim?!"), expectTrue("*?_"),
|
||||
expectFalse("blim"), expectFalse("blim?"),
|
||||
expectFalse("?*"), expectFalse("??"), expectFalse(""), expectFalse("?"),
|
||||
"A LIKE '%*_?'",
|
||||
expectTrue("%blim_?"), expectTrue("%_?"), expectTrue("%blim_!"),
|
||||
expectFalse("blim"), expectFalse("blim_"),
|
||||
expectFalse("_%"), expectFalse("??"), expectFalse(""), expectFalse("?"),
|
||||
|
||||
Query.toString(
|
||||
Query.initialSubString(Query.attr("A"), Query.value("*?%_"))),
|
||||
@ -483,7 +483,7 @@ public class QueryParseTest {
|
||||
// note the little {} at the end which means this is a subclass
|
||||
// and therefore QualifiedAttributeValue should return false.
|
||||
|
||||
MBeanServerDelegate.class.getName() + "#SpecificationName LIKE '%'",
|
||||
MBeanServerDelegate.class.getName() + "#SpecificationName LIKE '*'",
|
||||
new Wrapped(new MBeanServerDelegate(), true),
|
||||
new Tester(new String[] {"SpecificationName"}, new Object[] {"JMX"}, false),
|
||||
|
||||
@ -497,7 +497,7 @@ public class QueryParseTest {
|
||||
"A.class.name = 'java.lang.String'",
|
||||
expectTrue("blim"), expectFalse(95), expectFalse((Object) null),
|
||||
|
||||
"A.canonicalName like 'JMImpl%:%'",
|
||||
"A.canonicalName like 'JMImpl*:*'",
|
||||
expectTrue(MBeanServerDelegate.DELEGATE_NAME),
|
||||
expectFalse(ObjectName.WILDCARD),
|
||||
|
||||
@ -544,12 +544,15 @@ public class QueryParseTest {
|
||||
"a in b, c", "a in 23", "a in (2, 3", "a in (2, 3x)",
|
||||
"a like \"foo\"", "a like b", "a like 23",
|
||||
"like \"foo\"", "like b", "like 23", "like 'a:b'",
|
||||
"5 like 'a'", "'a' like '%'",
|
||||
"5 like 'a'", "'a' like '*'",
|
||||
"a not= b", "a not = b", "a not b", "a not b c",
|
||||
"a = +b", "a = +'b'", "a = +true", "a = -b", "a = -'b'",
|
||||
"a#5 = b", "a#'b' = c",
|
||||
"a instanceof b", "a instanceof 17", "a instanceof",
|
||||
"a like 'oops\\'", "a like '[oops'",
|
||||
// "a like 'oops\\'", "a like '[oops'",
|
||||
// We don't check the above because Query.match doesn't. If LIKE
|
||||
// rejected bad patterns then there would be some QueryExp values
|
||||
// that could not be converted to a string and back.
|
||||
|
||||
// Check that -Long.MIN_VALUE is an illegal constant. This is one more
|
||||
// than Long.MAX_VALUE and, like the Java language, we only allow it
|
||||
|
Loading…
x
Reference in New Issue
Block a user