Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/javax/management/MBeanServer/OldMBeanServerTest.java
38838 views
/*1* Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223import java.io.IOException;24import java.io.ObjectInputStream;25import java.io.Serializable;26import java.lang.annotation.Retention;27import java.lang.annotation.RetentionPolicy;28import java.lang.management.ManagementFactory;29import java.lang.ref.WeakReference;30import java.lang.reflect.AccessibleObject;31import java.lang.reflect.Constructor;32import java.lang.reflect.InvocationTargetException;33import java.lang.reflect.Method;34import java.lang.reflect.Modifier;35import java.util.ArrayList;36import java.util.Arrays;37import java.util.HashMap;38import java.util.HashSet;39import java.util.Iterator;40import java.util.List;41import java.util.Map;42import java.util.Set;43import java.util.WeakHashMap;44import java.util.concurrent.Callable;45import java.util.concurrent.ConcurrentHashMap;46import java.util.concurrent.ConcurrentMap;47import javax.management.Attribute;48import javax.management.AttributeList;49import javax.management.AttributeNotFoundException;50import javax.management.DynamicMBean;51import javax.management.InstanceAlreadyExistsException;52import javax.management.InstanceNotFoundException;53import javax.management.IntrospectionException;54import javax.management.InvalidAttributeValueException;55import javax.management.ListenerNotFoundException;56import javax.management.MBeanAttributeInfo;57import javax.management.MBeanConstructorInfo;58import javax.management.MBeanException;59import javax.management.MBeanInfo;60import javax.management.MBeanNotificationInfo;61import javax.management.MBeanOperationInfo;62import javax.management.MBeanRegistration;63import javax.management.MBeanRegistrationException;64import javax.management.MBeanServer;65import javax.management.MBeanServerBuilder;66import javax.management.MBeanServerConnection;67import javax.management.MBeanServerDelegate;68import javax.management.MBeanServerFactory;69import javax.management.MBeanServerNotification;70import javax.management.MalformedObjectNameException;71import javax.management.NotCompliantMBeanException;72import javax.management.Notification;73import javax.management.NotificationBroadcaster;74import javax.management.NotificationBroadcasterSupport;75import javax.management.NotificationEmitter;76import javax.management.NotificationFilter;77import javax.management.NotificationListener;78import javax.management.ObjectInstance;79import javax.management.ObjectName;80import javax.management.OperationsException;81import javax.management.QueryEval;82import javax.management.QueryExp;83import javax.management.ReflectionException;84import javax.management.RuntimeErrorException;85import javax.management.RuntimeMBeanException;86import javax.management.StandardMBean;87import javax.management.loading.ClassLoaderRepository;88import javax.management.remote.JMXConnector;89import javax.management.remote.JMXConnectorFactory;90import javax.management.remote.JMXConnectorServer;91import javax.management.remote.JMXConnectorServerFactory;92import javax.management.remote.JMXServiceURL;9394/*95* @test OldMBeanServerTest.java96* @bug 507226897* @summary Test that nothing assumes a post-1.2 MBeanServer98* @author Eamonn McManus99* @run main/othervm -ea OldMBeanServerTest100*/101102/*103* We defined the MBeanServerBuilder class and the associated system104* property javax.management.builder.initial in version 1.2 of the JMX105* spec. That amounts to a guarantee that someone can set the property106* to an MBeanServer that only knows about JMX 1.2 semantics, and if they107* only do JMX 1.2 operations, everything should work. This test is a108* sanity check that ensures we don't inadvertently make any API changes109* that stop that from being true. It includes a complete (if slow)110* MBeanServer implementation. That implementation doesn't replicate the111* mandated exception behaviour everywhere, though, since there's lots of112* arbitrary cruft in that. Also, the behaviour of concurrent unregisterMBean113* calls is incorrect in detail.114*/115116public class OldMBeanServerTest {117private static MBeanServerConnection mbsc;118private static String failure;119120public static void main(String[] args) throws Exception {121if (!OldMBeanServerTest.class.desiredAssertionStatus())122throw new Exception("Test must be run with -ea");123124System.setProperty("javax.management.builder.initial",125OldMBeanServerBuilder.class.getName());126assert MBeanServerFactory.newMBeanServer() instanceof OldMBeanServer;127128System.out.println("=== RUNNING TESTS WITH LOCAL MBEANSERVER ===");129runTests(new Callable<MBeanServerConnection>() {130public MBeanServerConnection call() {131return MBeanServerFactory.newMBeanServer();132}133}, null);134135System.out.println("=== RUNNING TESTS THROUGH CONNECTOR ===");136ConnectionBuilder builder = new ConnectionBuilder();137runTests(builder, builder);138139if (failure == null)140System.out.println("TEST PASSED");141else142throw new Exception("TEST FAILED: " + failure);143}144145private static class ConnectionBuilder146implements Callable<MBeanServerConnection>, Runnable {147private JMXConnector connector;148public MBeanServerConnection call() {149MBeanServer mbs = MBeanServerFactory.newMBeanServer();150try {151JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://");152JMXConnectorServer cs =153JMXConnectorServerFactory.newJMXConnectorServer(154url, null, mbs);155cs.start();156JMXServiceURL addr = cs.getAddress();157connector = JMXConnectorFactory.connect(addr);158return connector.getMBeanServerConnection();159} catch (IOException e) {160throw new RuntimeException(e);161}162}163public void run() {164if (connector != null) {165try {166connector.close();167} catch (IOException e) {168throw new RuntimeException(e);169}170}171}172}173174private static void runTests(175Callable<MBeanServerConnection> maker, Runnable breaker)176throws Exception {177for (Method m : OldMBeanServerTest.class.getDeclaredMethods()) {178if (Modifier.isStatic(m.getModifiers()) &&179m.getName().startsWith("test") &&180m.getParameterTypes().length == 0) {181ExpectException expexc = m.getAnnotation(ExpectException.class);182mbsc = maker.call();183try {184m.invoke(null);185if (expexc != null) {186failure =187m.getName() + " did not got expected exception " +188expexc.value().getName();189System.out.println(failure);190} else191System.out.println(m.getName() + " OK");192} catch (InvocationTargetException ite) {193Throwable t = ite.getCause();194String prob = null;195if (expexc != null) {196if (expexc.value().isInstance(t)) {197System.out.println(m.getName() + " OK (got expected " +198expexc.value().getName() + ")");199} else200prob = "got wrong exception";201} else202prob = "got exception";203if (prob != null) {204failure = m.getName() + ": " + prob + " " +205t.getClass().getName();206System.out.println(failure);207t.printStackTrace(System.out);208}209} finally {210if (breaker != null)211breaker.run();212}213}214}215}216217@Retention(RetentionPolicy.RUNTIME)218private static @interface ExpectException {219Class<? extends Exception> value();220}221222public static interface BoringMBean {223public String getName();224public int add(int x, int y);225}226227// This class is Serializable so we can createMBean a StandardMBean228// that contains it. Not recommended practice in general --229// should we have a StandardMBean constructor that takes a class230// name and constructor parameters?231public static class Boring implements BoringMBean, Serializable {232public String getName() {233return "Jessica";234}235236public int add(int x, int y) {237return x + y;238}239}240241public static interface BoringNotifierMBean extends BoringMBean {242public void send();243}244245public static class BoringNotifier246extends Boring implements BoringNotifierMBean, NotificationBroadcaster {247private final NotificationBroadcasterSupport nbs =248new NotificationBroadcasterSupport();249250public void addNotificationListener(251NotificationListener listener, NotificationFilter filter, Object handback)252throws IllegalArgumentException {253nbs.addNotificationListener(listener, filter, handback);254}255256public void removeNotificationListener(NotificationListener listener)257throws ListenerNotFoundException {258nbs.removeNotificationListener(listener);259}260261public MBeanNotificationInfo[] getNotificationInfo() {262return null;263}264265public void send() {266Notification n = new Notification("type.type", this, 0L);267nbs.sendNotification(n);268}269}270271private static class CountListener implements NotificationListener {272volatile int count;273public void handleNotification(Notification n, Object h) {274if (h == null)275h = 1;276count += (Integer) h;277}278void waitForCount(int expect) throws InterruptedException {279long deadline = System.currentTimeMillis() + 2000L;280while (count < expect && System.currentTimeMillis() < deadline)281Thread.sleep(1);282assert count == expect;283}284}285286private static void testBasic() throws Exception {287CountListener countListener = new CountListener();288mbsc.addNotificationListener(289MBeanServerDelegate.DELEGATE_NAME, countListener, null, null);290assert countListener.count == 0;291ObjectName name = new ObjectName("a:b=c");292if (mbsc instanceof MBeanServer)293((MBeanServer) mbsc).registerMBean(new Boring(), name);294else295mbsc.createMBean(Boring.class.getName(), name);296countListener.waitForCount(1);297assert mbsc.isRegistered(name);298assert mbsc.queryNames(null, null).contains(name);299assert mbsc.getAttribute(name, "Name").equals("Jessica");300assert mbsc.invoke(301name, "add", new Object[] {2, 3}, new String[] {"int", "int"})302.equals(5);303mbsc.unregisterMBean(name);304countListener.waitForCount(2);305assert !mbsc.isRegistered(name);306assert !mbsc.queryNames(null, null).contains(name);307308mbsc.createMBean(BoringNotifier.class.getName(), name);309countListener.waitForCount(3);310CountListener boringListener = new CountListener();311class AlwaysNotificationFilter implements NotificationFilter {312public boolean isNotificationEnabled(Notification notification) {313return true;314}315}316mbsc.addNotificationListener(317name, boringListener, new AlwaysNotificationFilter(), 5);318mbsc.invoke(name, "send", null, null);319boringListener.waitForCount(5);320}321322private static void testPrintAttrs() throws Exception {323printAttrs(mbsc, null);324}325326private static void testPlatformMBeanServer() throws Exception {327MBeanServer pmbs = ManagementFactory.getPlatformMBeanServer();328assert pmbs instanceof OldMBeanServer;329// Preceding assertion could be violated if at some stage we wrap330// the Platform MBeanServer. In that case we can still check that331// it is ultimately an OldMBeanServer for example by adding a332// counter to getAttribute and checking that it is incremented333// when we call pmbs.getAttribute.334335printAttrs(pmbs, UnsupportedOperationException.class);336ObjectName memoryMXBeanName =337new ObjectName(ManagementFactory.MEMORY_MXBEAN_NAME);338pmbs.invoke(memoryMXBeanName, "gc", null, null);339}340341private static void printAttrs(342MBeanServerConnection mbsc1, Class<? extends Exception> expectX)343throws Exception {344Set<ObjectName> names = mbsc1.queryNames(null, null);345for (ObjectName name : names) {346System.out.println(name + ":");347MBeanInfo mbi = mbsc1.getMBeanInfo(name);348MBeanAttributeInfo[] mbais = mbi.getAttributes();349for (MBeanAttributeInfo mbai : mbais) {350String attr = mbai.getName();351Object value;352try {353value = mbsc1.getAttribute(name, attr);354} catch (Exception e) {355if (expectX != null && expectX.isInstance(e))356value = "<" + e + ">";357else358throw e;359}360String s = " " + attr + " = " + value;361if (s.length() > 80)362s = s.substring(0, 77) + "...";363System.out.println(s);364}365}366}367368private static void testJavaxManagementStandardMBean() throws Exception {369ObjectName name = new ObjectName("a:b=c");370Object mbean = new StandardMBean(new Boring(), BoringMBean.class);371mbsc.createMBean(372StandardMBean.class.getName(), name,373new Object[] {new Boring(), BoringMBean.class},374new String[] {Object.class.getName(), Class.class.getName()});375assert mbsc.getAttribute(name, "Name").equals("Jessica");376assert mbsc.invoke(377name, "add", new Object[] {2, 3}, new String[] {"int", "int"})378.equals(5);379mbsc.unregisterMBean(name);380}381382private static void testConnector() throws Exception {383}384385public static class OldMBeanServerBuilder extends MBeanServerBuilder {386public MBeanServer newMBeanServer(387String defaultDomain, MBeanServer outer, MBeanServerDelegate delegate) {388return new OldMBeanServer(defaultDomain, delegate);389}390}391392public static class OldMBeanServer implements MBeanServer {393// We pretend there's a ClassLoader MBean representing the Class Loader394// Repository and intercept references to it where necessary to keep up395// the pretence. This allows us to fake the right behaviour for396// the omitted-ClassLoader versions of createMBean and instantiate397// (which are not the same as passing a null for the ClassLoader parameter398// of the versions that have one).399private static final ObjectName clrName;400static {401try {402clrName =403new ObjectName("JMImplementation:type=ClassLoaderRepository");404} catch (MalformedObjectNameException e) {405throw new RuntimeException(e);406}407}408409private final ConcurrentMap<ObjectName, DynamicMBean> mbeans =410new ConcurrentHashMap<ObjectName, DynamicMBean>();411private final ConcurrentMap<ObjectName, ListenerTable> listenerMap =412new ConcurrentHashMap<ObjectName, ListenerTable>();413private final String defaultDomain;414private final MBeanServerDelegate delegate;415private final ClassLoaderRepositoryImpl clr =416new ClassLoaderRepositoryImpl();417418OldMBeanServer(String defaultDomain, MBeanServerDelegate delegate) {419this.defaultDomain = defaultDomain;420this.delegate = delegate;421try {422registerMBean(delegate, MBeanServerDelegate.DELEGATE_NAME);423} catch (Exception e) {424throw new RuntimeException(e);425}426}427428public ObjectInstance createMBean(String className, ObjectName name)429throws ReflectionException, InstanceAlreadyExistsException,430MBeanRegistrationException, MBeanException,431NotCompliantMBeanException {432return createMBean(className, name, null, null);433}434435public ObjectInstance createMBean(436String className, ObjectName name, ObjectName loaderName)437throws ReflectionException, InstanceAlreadyExistsException,438MBeanRegistrationException, MBeanException,439NotCompliantMBeanException, InstanceNotFoundException {440return createMBean(className, name, loaderName, null, null);441}442443public ObjectInstance createMBean(444String className, ObjectName name, Object[] params, String[] signature)445throws ReflectionException, InstanceAlreadyExistsException,446MBeanRegistrationException, MBeanException,447NotCompliantMBeanException {448try {449return createMBean(className, name, clrName, params, signature);450} catch (InstanceNotFoundException ex) {451throw new RuntimeException(ex); // can't happen452}453}454455public ObjectInstance createMBean(456String className, ObjectName name, ObjectName loaderName,457Object[] params, String[] signature)458throws ReflectionException, InstanceAlreadyExistsException,459MBeanRegistrationException, MBeanException,460NotCompliantMBeanException, InstanceNotFoundException {461Object mbean = instantiate(className, loaderName, params, signature);462return registerMBean(mbean, name);463}464465private void forbidJMImpl(ObjectName name) {466if (name.getDomain().equals("JMImplementation") &&467mbeans.containsKey(MBeanServerDelegate.DELEGATE_NAME))468throw new IllegalArgumentException("JMImplementation reserved");469}470471public ObjectInstance registerMBean(Object object, ObjectName name)472throws InstanceAlreadyExistsException, MBeanRegistrationException,473NotCompliantMBeanException {474forbidJMImpl(name);475if (name.isPattern())476throw new IllegalArgumentException(name.toString());477// This is the only place we check for wildcards. Since you478// can't register a wildcard name, other operations that supply479// one will get InstanceNotFoundException when they look it up.480481DynamicMBean mbean;482if (object instanceof DynamicMBean)483mbean = (DynamicMBean) object;484else485mbean = standardToDynamic(object);486MBeanRegistration reg = mbeanRegistration(object);487try {488name = reg.preRegister(this, name);489} catch (Exception e) {490throw new MBeanRegistrationException(e);491}492DynamicMBean put = mbeans.putIfAbsent(name, mbean);493if (put != null) {494reg.postRegister(false);495throw new InstanceAlreadyExistsException(name.toString());496}497reg.postRegister(true);498499if (object instanceof ClassLoader)500clr.addLoader((ClassLoader) object);501502Notification n = new MBeanServerNotification(503MBeanServerNotification.REGISTRATION_NOTIFICATION,504MBeanServerDelegate.DELEGATE_NAME,5050,506name);507delegate.sendNotification(n);508509String className = mbean.getMBeanInfo().getClassName();510return new ObjectInstance(name, className);511}512513public void unregisterMBean(ObjectName name)514throws InstanceNotFoundException, MBeanRegistrationException {515516forbidJMImpl(name);517518DynamicMBean mbean = getMBean(name);519if (mbean == null)520throw new InstanceNotFoundException(name.toString());521522MBeanRegistration reg = mbeanRegistration(mbean);523try {524reg.preDeregister();525} catch (Exception e) {526throw new MBeanRegistrationException(e);527}528if (!mbeans.remove(name, mbean))529throw new InstanceNotFoundException(name.toString());530// This is incorrect because we've invoked preDeregister531532Object userMBean = getUserMBean(mbean);533if (userMBean instanceof ClassLoader)534clr.removeLoader((ClassLoader) userMBean);535536Notification n = new MBeanServerNotification(537MBeanServerNotification.REGISTRATION_NOTIFICATION,538MBeanServerDelegate.DELEGATE_NAME,5390,540name);541delegate.sendNotification(n);542543reg.postDeregister();544}545546public ObjectInstance getObjectInstance(ObjectName name)547throws InstanceNotFoundException {548DynamicMBean mbean = getMBean(name);549return new ObjectInstance(name, mbean.getMBeanInfo().getClassName());550}551552private static class TrueQueryExp implements QueryExp {553public boolean apply(ObjectName name) {554return true;555}556557public void setMBeanServer(MBeanServer s) {}558}559private static final QueryExp trueQuery = new TrueQueryExp();560561public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) {562Set<ObjectInstance> instances = newSet();563if (name == null)564name = ObjectName.WILDCARD;565if (query == null)566query = trueQuery;567MBeanServer oldMBS = QueryEval.getMBeanServer();568try {569query.setMBeanServer(this);570for (ObjectName n : mbeans.keySet()) {571if (name.apply(n)) {572try {573if (query.apply(n))574instances.add(getObjectInstance(n));575} catch (Exception e) {576// OK: Ignore this MBean in the result577}578}579}580} finally {581query.setMBeanServer(oldMBS);582}583return instances;584}585586public Set<ObjectName> queryNames(ObjectName name, QueryExp query) {587Set<ObjectInstance> instances = queryMBeans(name, query);588Set<ObjectName> names = newSet();589for (ObjectInstance instance : instances)590names.add(instance.getObjectName());591return names;592}593594public boolean isRegistered(ObjectName name) {595return mbeans.containsKey(name);596}597598public Integer getMBeanCount() {599return mbeans.size();600}601602public Object getAttribute(ObjectName name, String attribute)603throws MBeanException, AttributeNotFoundException,604InstanceNotFoundException, ReflectionException {605return getMBean(name).getAttribute(attribute);606}607608public AttributeList getAttributes(ObjectName name, String[] attributes)609throws InstanceNotFoundException, ReflectionException {610return getMBean(name).getAttributes(attributes);611}612613public void setAttribute(ObjectName name, Attribute attribute)614throws InstanceNotFoundException, AttributeNotFoundException,615InvalidAttributeValueException, MBeanException,616ReflectionException {617getMBean(name).setAttribute(attribute);618}619620public AttributeList setAttributes(621ObjectName name, AttributeList attributes)622throws InstanceNotFoundException, ReflectionException {623return getMBean(name).setAttributes(attributes);624}625626public Object invoke(627ObjectName name, String operationName, Object[] params,628String[] signature)629throws InstanceNotFoundException, MBeanException, ReflectionException {630return getMBean(name).invoke(operationName, params, signature);631}632633public String getDefaultDomain() {634return defaultDomain;635}636637public String[] getDomains() {638Set<String> domains = newSet();639for (ObjectName name : mbeans.keySet())640domains.add(name.getDomain());641return domains.toArray(new String[0]);642}643644// ClassCastException if MBean is not a NotificationBroadcaster645public void addNotificationListener(646ObjectName name, NotificationListener listener,647NotificationFilter filter, Object handback)648throws InstanceNotFoundException {649NotificationBroadcaster userMBean =650(NotificationBroadcaster) getUserMBean(name);651NotificationListener wrappedListener =652wrappedListener(name, userMBean, listener);653userMBean.addNotificationListener(wrappedListener, filter, handback);654}655656public void addNotificationListener(657ObjectName name, ObjectName listener,658NotificationFilter filter, Object handback)659throws InstanceNotFoundException {660NotificationListener nl =661(NotificationListener) getUserMBean(listener);662addNotificationListener(name, nl, filter, handback);663}664665public void removeNotificationListener(666ObjectName name, ObjectName listener)667throws InstanceNotFoundException, ListenerNotFoundException {668NotificationListener nl =669(NotificationListener) getUserMBean(listener);670removeNotificationListener(name, nl);671}672673public void removeNotificationListener(674ObjectName name, ObjectName listener,675NotificationFilter filter, Object handback)676throws InstanceNotFoundException, ListenerNotFoundException {677NotificationListener nl =678(NotificationListener) getUserMBean(listener);679removeNotificationListener(name, nl, filter, handback);680}681682public void removeNotificationListener(683ObjectName name, NotificationListener listener)684throws InstanceNotFoundException, ListenerNotFoundException {685NotificationBroadcaster userMBean =686(NotificationBroadcaster) getUserMBean(name);687NotificationListener wrappedListener =688wrappedListener(name, userMBean, listener);689userMBean.removeNotificationListener(wrappedListener);690}691692public void removeNotificationListener(693ObjectName name, NotificationListener listener,694NotificationFilter filter, Object handback)695throws InstanceNotFoundException, ListenerNotFoundException {696NotificationEmitter userMBean =697(NotificationEmitter) getMBean(name);698NotificationListener wrappedListener =699wrappedListener(name, userMBean, listener);700userMBean.removeNotificationListener(wrappedListener, filter, handback);701}702703public MBeanInfo getMBeanInfo(ObjectName name)704throws InstanceNotFoundException, IntrospectionException,705ReflectionException {706return getMBean(name).getMBeanInfo();707}708709public boolean isInstanceOf(ObjectName name, String className)710throws InstanceNotFoundException {711DynamicMBean mbean = getMBean(name);712String mbeanClassName = mbean.getMBeanInfo().getClassName();713if (className.equals(mbeanClassName))714return true;715ClassLoader loader = getUserMBean(mbean).getClass().getClassLoader();716try {717Class<?> mbeanClass = Class.forName(mbeanClassName, false, loader);718Class<?> isInstClass = Class.forName(className, false, loader);719return isInstClass.isAssignableFrom(mbeanClass);720} catch (ClassNotFoundException e) {721return false;722}723}724725public Object instantiate(String className)726throws ReflectionException, MBeanException {727return instantiate(className, null, null);728}729730public Object instantiate(String className, ObjectName loaderName)731throws ReflectionException, MBeanException, InstanceNotFoundException {732return instantiate(className, loaderName, null, null);733}734735public Object instantiate(736String className, Object[] params, String[] signature)737throws ReflectionException, MBeanException {738try {739return instantiate(className, clrName, params, signature);740} catch (InstanceNotFoundException e) {741throw new RuntimeException(e); // can't happen742}743}744745public Object instantiate(746String className, ObjectName loaderName,747Object[] params, String[] signature)748throws ReflectionException, MBeanException, InstanceNotFoundException {749750if (params == null)751params = new Object[0];752if (signature == null)753signature = new String[0];754755ClassLoader loader;756if (loaderName == null)757loader = this.getClass().getClassLoader();758else if (loaderName.equals(clrName))759loader = clr;760else761loader = (ClassLoader) getMBean(loaderName);762763Class<?> c;764try {765c = Class.forName(className, false, loader);766} catch (ClassNotFoundException e) {767throw new ReflectionException(e);768}769770Constructor[] constrs = c.getConstructors();771Constructor found = null;772findconstr:773for (Constructor constr : constrs) {774Class<?>[] cTypes = constr.getParameterTypes();775if (cTypes.length == signature.length) {776for (int i = 0; i < cTypes.length; i++) {777if (!cTypes[i].getName().equals(signature[i]))778continue findconstr;779}780found = constr;781break findconstr;782}783}784if (found == null) {785Exception x = new NoSuchMethodException(786className + Arrays.toString(signature));787throw new ReflectionException(x);788}789return invokeSomething(found, null, params);790}791792@Deprecated793public ObjectInputStream deserialize(ObjectName name, byte[] data)794throws InstanceNotFoundException, OperationsException {795throw new UnsupportedOperationException();796}797798@Deprecated799public ObjectInputStream deserialize(String className, byte[] data)800throws OperationsException, ReflectionException {801throw new UnsupportedOperationException();802}803804@Deprecated805public ObjectInputStream deserialize(806String className, ObjectName loaderName, byte[] data)807throws InstanceNotFoundException, OperationsException, ReflectionException {808throw new UnsupportedOperationException();809}810811public ClassLoader getClassLoaderFor(ObjectName mbeanName)812throws InstanceNotFoundException {813DynamicMBean mbean = getMBean(mbeanName);814Object userMBean = getUserMBean(mbean);815return userMBean.getClass().getClassLoader();816}817818public ClassLoader getClassLoader(ObjectName loaderName)819throws InstanceNotFoundException {820return (ClassLoader) getMBean(loaderName);821}822823public ClassLoaderRepository getClassLoaderRepository() {824return new ClassLoaderRepository() {825public Class<?> loadClass(String className)826throws ClassNotFoundException {827return clr.loadClass(className);828}829830public Class<?> loadClassWithout(831ClassLoader exclude, String className)832throws ClassNotFoundException {833return clr.loadClassWithout(exclude, className);834}835836public Class<?> loadClassBefore(837ClassLoader stop, String className)838throws ClassNotFoundException {839return clr.loadClassBefore(stop, className);840}841};842}843844private static class ClassLoaderRepositoryImpl845extends ClassLoader implements ClassLoaderRepository {846private List<ClassLoader> loaders = newList();847{848loaders.add(this.getClass().getClassLoader());849// We also behave as if the system class loader were in850// the repository, since we do nothing to stop delegation851// to the parent, which is the system class loader, and852// that delegation happens before our findClass is called.853}854855void addLoader(ClassLoader loader) {856loaders.add(loader);857}858859void removeLoader(ClassLoader loader) {860if (!loaders.remove(loader))861throw new RuntimeException("Loader was not in CLR!");862}863864public Class<?> loadClassWithout(865ClassLoader exclude, String className)866throws ClassNotFoundException {867return loadClassWithoutBefore(exclude, null, className);868}869870public Class<?> loadClassBefore(ClassLoader stop, String className)871throws ClassNotFoundException {872return loadClassWithoutBefore(null, stop, className);873}874875private Class<?> loadClassWithoutBefore(876ClassLoader exclude, ClassLoader stop, String className)877throws ClassNotFoundException {878for (ClassLoader loader : loaders) {879if (loader == exclude)880continue;881if (loader == stop)882break;883try {884return Class.forName(className, false, loader);885} catch (ClassNotFoundException e) {886// OK: try others887}888}889throw new ClassNotFoundException(className);890}891892@Override893protected Class<?> findClass(String className)894throws ClassNotFoundException {895return loadClassWithout(null, className);896}897}898899/* There is zero or one ListenerTable per MBean.900* The ListenerTable stuff is complicated. We want to rewrite the901* source of notifications so that if the source of a notification902* from the MBean X is a reference to X itself, it gets replaced903* by X's ObjectName. To do this, we wrap the user's listener in904* a RewriteListener. But if the same listener is added a second905* time (perhaps with a different filter or handback) we must906* reuse the same RewriteListener so that the two-argument907* removeNotificationListener(ObjectName,NotificationListener) will908* correctly remove both listeners. This means we must remember the909* mapping from listener to WrappedListener. But if the MBean910* discards its listeners (as a result of removeNL or spontaneously)911* then we don't want to keep a reference to the WrappedListener.912* So we have tons of WeakReferences. The key in the ListenerTable913* is an IdentityListener, which wraps the user's listener to ensure914* that identity and not equality is used during the lookup, even if915* the user's listener has an equals method. The value in the916* ListenerTable is a WeakReference wrapping a RewriteListener wrapping917* the same IdentityListener. Since the RewriteListener is what is918* added to the user's MBean, the WeakReference won't disappear as long919* as the MBean still has this listener. And since it references the920* IdentityListener, that won't disappear either. But once the921* RewriteListener is no longer referenced by the user's MBean,922* there's nothing to stop its WeakReference from being cleared,923* and then corresponding IdentityListener that is now only weakly924* referenced from the key in the table.925*/926private static class ListenerTable927extends WeakHashMap<NotificationListener,928WeakReference<NotificationListener>> {929}930931private static class IdentityListener implements NotificationListener {932private final NotificationListener userListener;933934IdentityListener(NotificationListener userListener) {935this.userListener = userListener;936}937938public void handleNotification(939Notification notification, Object handback) {940userListener.handleNotification(notification, handback);941}942943@Override944public boolean equals(Object o) {945return (this == o);946}947948@Override949public int hashCode() {950return System.identityHashCode(this);951}952}953954private static class RewriteListener implements NotificationListener {955private final ObjectName name;956private final Object userMBean;957private final NotificationListener userListener;958959RewriteListener(960ObjectName name, Object userMBean,961NotificationListener userListener) {962this.name = name;963this.userMBean = userMBean;964this.userListener = userListener;965}966967public void handleNotification(968Notification notification, Object handback) {969if (notification.getSource() == userMBean)970notification.setSource(name);971userListener.handleNotification(notification, handback);972}973}974975private NotificationListener wrappedListener(976ObjectName name, Object userMBean, NotificationListener userListener)977throws InstanceNotFoundException {978ListenerTable table = new ListenerTable();979ListenerTable oldTable = listenerMap.putIfAbsent(name, table);980if (oldTable != null)981table = oldTable;982NotificationListener identityListener =983new IdentityListener(userListener);984synchronized (table) {985NotificationListener rewriteListener = null;986WeakReference<NotificationListener> wr =987table.get(identityListener);988if (wr != null)989rewriteListener = wr.get();990if (rewriteListener == null) {991rewriteListener = new RewriteListener(992name, userMBean, identityListener);993wr = new WeakReference<NotificationListener>(rewriteListener);994table.put(identityListener, wr);995}996return rewriteListener;997}998}9991000private DynamicMBean getMBean(ObjectName name)1001throws InstanceNotFoundException {1002DynamicMBean mbean = mbeans.get(name);1003if (mbean == null)1004throw new InstanceNotFoundException(name.toString());1005return mbean;1006}10071008private static interface WrapDynamicMBean extends DynamicMBean {1009public Object getWrappedMBean();1010}10111012private static class StandardWrapper1013implements WrapDynamicMBean, MBeanRegistration {1014private final Map<String, AttrMethods> attrMap = newMap();1015private final Map<String, List<Method>> opMap = newMap();1016private static class AttrMethods {1017Method getter, setter;1018}10191020private final Object std;10211022StandardWrapper(Object std) throws NotCompliantMBeanException {1023this.std = std;1024Class<?> intf = mbeanInterface(std.getClass());1025try {1026initMaps(intf);1027} catch (NotCompliantMBeanException e) {1028throw e;1029} catch (Exception e) {1030NotCompliantMBeanException x =1031new NotCompliantMBeanException(e.getMessage());1032x.initCause(e);1033throw x;1034}1035}10361037private static Class<?> mbeanInterface(Class<?> c)1038throws NotCompliantMBeanException {1039do {1040Class<?>[] intfs = c.getInterfaces();1041String intfName = c.getName() + "MBean";1042for (Class<?> intf : intfs) {1043if (intf.getName().equals(intfName))1044return intf;1045}1046c = c.getSuperclass();1047} while (c != null);1048throw new NotCompliantMBeanException(1049"Does not match Standard or Dynamic MBean patterns: " +1050c.getName());1051}10521053private void initMaps(Class<?> intf) throws NotCompliantMBeanException {1054Method[] methods = intf.getMethods();10551056for (Method m : methods) {1057final String name = m.getName();1058final int nParams = m.getParameterTypes().length;10591060String attrName = "";1061if (name.startsWith("get"))1062attrName = name.substring(3);1063else if (name.startsWith("is")1064&& m.getReturnType() == boolean.class)1065attrName = name.substring(2);10661067if (attrName.length() != 0 && m.getParameterTypes().length == 01068&& m.getReturnType() != void.class) {1069// It's a getter1070// Check we don't have both isX and getX1071AttrMethods am = attrMap.get(attrName);1072if (am == null)1073am = new AttrMethods();1074else {1075if (am.getter != null) {1076final String msg = "Attribute " + attrName +1077" has more than one getter";1078throw new NotCompliantMBeanException(msg);1079}1080}1081am.getter = m;1082attrMap.put(attrName, am);1083} else if (name.startsWith("set") && name.length() > 31084&& m.getParameterTypes().length == 1 &&1085m.getReturnType() == void.class) {1086// It's a setter1087attrName = name.substring(3);1088AttrMethods am = attrMap.get(attrName);1089if (am == null)1090am = new AttrMethods();1091else if (am.setter != null) {1092final String msg = "Attribute " + attrName +1093" has more than one setter";1094throw new NotCompliantMBeanException(msg);1095}1096am.setter = m;1097attrMap.put(attrName, am);1098} else {1099// It's an operation1100List<Method> ops = opMap.get(name);1101if (ops == null)1102ops = newList();1103ops.add(m);1104opMap.put(name, ops);1105}1106}1107/* Check that getters and setters are consistent. */1108for (Map.Entry<String, AttrMethods> entry : attrMap.entrySet()) {1109AttrMethods am = entry.getValue();1110if (am.getter != null && am.setter != null &&1111am.getter.getReturnType() != am.setter.getParameterTypes()[0]) {1112final String msg = "Getter and setter for " + entry.getKey() +1113" have inconsistent types";1114throw new NotCompliantMBeanException(msg);1115}1116}1117}11181119public Object getAttribute(String attribute)1120throws AttributeNotFoundException, MBeanException, ReflectionException {1121AttrMethods am = attrMap.get(attribute);1122if (am == null || am.getter == null)1123throw new AttributeNotFoundException(attribute);1124return invokeMethod(am.getter);1125}11261127public void setAttribute(Attribute attribute)1128throws AttributeNotFoundException, InvalidAttributeValueException,1129MBeanException, ReflectionException {1130String name = attribute.getName();1131AttrMethods am = attrMap.get(name);1132if (am == null || am.setter == null)1133throw new AttributeNotFoundException(name);1134invokeMethod(am.setter, attribute.getValue());1135}11361137public AttributeList getAttributes(String[] attributes) {1138AttributeList list = new AttributeList();1139for (String attr : attributes) {1140try {1141list.add(new Attribute(attr, getAttribute(attr)));1142} catch (Exception e) {1143// OK: ignore per spec1144}1145}1146return list;1147}11481149public AttributeList setAttributes(AttributeList attributes) {1150AttributeList list = new AttributeList();1151// We carefully avoid using any new stuff from AttributeList here!1152for (Iterator<?> it = attributes.iterator(); it.hasNext(); ) {1153Attribute attr = (Attribute) it.next();1154try {1155setAttribute(attr);1156list.add(attr);1157} catch (Exception e) {1158// OK: ignore per spec1159}1160}1161return list;1162}11631164public Object invoke(String actionName, Object[] params, String[] signature)1165throws MBeanException, ReflectionException {1166if (params == null)1167params = new Object[0];1168if (signature == null)1169signature = new String[0];1170List<Method> methods = opMap.get(actionName);1171if (methods == null) {1172Exception x = new NoSuchMethodException(actionName);1173throw new MBeanException(x);1174}1175Method found = null;1176methodloop:1177for (Method m : methods) {1178Class<?>[] msig = m.getParameterTypes();1179if (msig.length != signature.length)1180continue methodloop;1181for (int i = 0; i < msig.length; i++) {1182if (!msig[i].getName().equals(signature[i]))1183continue methodloop;1184}1185found = m;1186break methodloop;1187}1188if (found == null) {1189Exception x = new NoSuchMethodException(1190actionName + Arrays.toString(signature));1191throw new MBeanException(x);1192}1193return invokeMethod(found, params);1194}11951196public MBeanInfo getMBeanInfo() {1197// Attributes1198List<MBeanAttributeInfo> attrs = newList();1199for (Map.Entry<String, AttrMethods> attr : attrMap.entrySet()) {1200String name = attr.getKey();1201AttrMethods am = attr.getValue();1202try {1203attrs.add(new MBeanAttributeInfo(1204name, name, am.getter, am.setter));1205} catch (IntrospectionException e) { // grrr1206throw new RuntimeException(e);1207}1208}12091210// Operations1211List<MBeanOperationInfo> ops = newList();1212for (Map.Entry<String, List<Method>> op : opMap.entrySet()) {1213String name = op.getKey();1214List<Method> methods = op.getValue();1215for (Method m : methods)1216ops.add(new MBeanOperationInfo(name, m));1217}12181219// Constructors1220List<MBeanConstructorInfo> constrs = newList();1221for (Constructor constr : std.getClass().getConstructors())1222constrs.add(new MBeanConstructorInfo("Constructor", constr));12231224// Notifications1225MBeanNotificationInfo[] notifs;1226if (std instanceof NotificationBroadcaster)1227notifs = ((NotificationBroadcaster) std).getNotificationInfo();1228else1229notifs = null;12301231String className = std.getClass().getName();1232return new MBeanInfo(1233className, className,1234attrs.toArray(new MBeanAttributeInfo[0]),1235constrs.toArray(new MBeanConstructorInfo[0]),1236ops.toArray(new MBeanOperationInfo[0]),1237notifs);1238}12391240private Object invokeMethod(Method m, Object... args)1241throws MBeanException, ReflectionException {1242return invokeSomething(m, std,args);1243}12441245public ObjectName preRegister(MBeanServer server, ObjectName name)1246throws Exception {1247return mbeanRegistration(std).preRegister(server, name);1248}12491250public void postRegister(Boolean registrationDone) {1251mbeanRegistration(std).postRegister(registrationDone);1252}12531254public void preDeregister() throws Exception {1255mbeanRegistration(std).preDeregister();1256}12571258public void postDeregister() {1259mbeanRegistration(std).postDeregister();1260}12611262public Object getWrappedMBean() {1263return std;1264}1265}12661267private DynamicMBean standardToDynamic(Object std)1268throws NotCompliantMBeanException {1269return new StandardWrapper(std);1270}12711272// private static class NotifWrapper1273// implements WrapDynamicMBean, NotificationEmitter {1274// private final DynamicMBean mbean;1275//1276// NotifWrapper(DynamicMBean mbean) {1277// this.mbean = mbean;1278// }1279//1280// public Object getAttribute(String attribute)1281// throws AttributeNotFoundException, MBeanException, ReflectionException {1282// return mbean.getAttribute(attribute);1283// }1284//1285// public void setAttribute(Attribute attribute)1286// throws AttributeNotFoundException, InvalidAttributeValueException,1287// MBeanException, ReflectionException {1288// mbean.setAttribute(attribute);1289// }1290//1291// public AttributeList getAttributes(String[] attributes) {1292// return mbean.getAttributes(attributes);1293// }1294//1295// public AttributeList setAttributes(AttributeList attributes) {1296// return mbean.setAttributes(attributes);1297// }1298//1299// public Object invoke(1300// String actionName, Object[] params, String[] signature)1301// throws MBeanException, ReflectionException {1302// return mbean.invoke(actionName, params, signature);1303// }1304//1305// public MBeanInfo getMBeanInfo() {1306// return mbean.getMBeanInfo();1307// }1308//1309// public void removeNotificationListener(1310// NotificationListener listener, NotificationFilter filter, Object handback)1311// throws ListenerNotFoundException {1312// ((NotificationEmitter) mbean).removeNotificationListener(1313// listener, filter, handback);1314// // ClassCastException if MBean is not an emitter1315// }1316//1317// public void addNotificationListener(1318// NotificationListener listener, NotificationFilter filter, Object handback)1319// throws IllegalArgumentException {1320// ((NotificationBroadcaster) mbean).addNotificationListener(1321// listener, filter, handback);1322// }1323//1324// public void removeNotificationListener(NotificationListener listener)1325// throws ListenerNotFoundException {1326// ((NotificationBroadcaster) mbean).removeNotificationListener(listener);1327// }1328//1329// public MBeanNotificationInfo[] getNotificationInfo() {1330// return ((NotificationBroadcaster) mbean).getNotificationInfo();1331// }1332//1333// public Object getWrappedMBean() {1334// return getUserMBean(mbean);1335// }1336// }13371338private static Object invokeSomething(1339AccessibleObject ao, Object target, Object[] args)1340throws MBeanException, ReflectionException {1341try {1342if (ao instanceof Method)1343return ((Method) ao).invoke(target, args);1344else1345return ((Constructor) ao).newInstance(args);1346} catch (InvocationTargetException e) {1347try {1348throw e.getCause();1349} catch (RuntimeException x) {1350throw new RuntimeMBeanException(x);1351} catch (Error x) {1352throw new RuntimeErrorException(x);1353} catch (Exception x) {1354throw new MBeanException(x);1355} catch (Throwable x) {1356throw new RuntimeException(x); // neither Error nor Exception!1357}1358} catch (Exception e) {1359throw new ReflectionException(e);1360}1361}13621363private static Object getUserMBean(DynamicMBean mbean) {1364if (mbean instanceof WrapDynamicMBean)1365return ((WrapDynamicMBean) mbean).getWrappedMBean();1366return mbean;1367}13681369private Object getUserMBean(ObjectName name)1370throws InstanceNotFoundException {1371return getUserMBean(getMBean(name));1372}13731374private static final MBeanRegistration noRegistration =1375new MBeanRegistration() {1376public ObjectName preRegister(MBeanServer server, ObjectName name) {1377return name;1378}13791380public void postRegister(Boolean registrationDone) {1381}13821383public void preDeregister() throws Exception {1384}13851386public void postDeregister() {1387}1388};13891390private static MBeanRegistration mbeanRegistration(Object object) {1391if (object instanceof MBeanRegistration)1392return (MBeanRegistration) object;1393else1394return noRegistration;1395}13961397private static <E> List<E> newList() {1398return new ArrayList<E>();1399}14001401private static <K, V> Map<K, V> newMap() {1402return new HashMap<K, V>();1403}14041405private static <E> Set<E> newSet() {1406return new HashSet<E>();1407}1408}1409}141014111412