Path: blob/master/test/jdk/javax/management/MBeanServer/OldMBeanServerTest.java
41149 views
/*1* Copyright (c) 2007, 2020, 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;9394import jdk.test.lib.Utils;9596/*97* @test OldMBeanServerTest.java98* @bug 507226899* @summary Test that nothing assumes a post-1.2 MBeanServer100* @author Eamonn McManus101* @library /test/lib102* @modules java.management.rmi103* @run main/othervm -ea OldMBeanServerTest104*/105106/*107* We defined the MBeanServerBuilder class and the associated system108* property javax.management.builder.initial in version 1.2 of the JMX109* spec. That amounts to a guarantee that someone can set the property110* to an MBeanServer that only knows about JMX 1.2 semantics, and if they111* only do JMX 1.2 operations, everything should work. This test is a112* sanity check that ensures we don't inadvertently make any API changes113* that stop that from being true. It includes a complete (if slow)114* MBeanServer implementation. That implementation doesn't replicate the115* mandated exception behaviour everywhere, though, since there's lots of116* arbitrary cruft in that. Also, the behaviour of concurrent unregisterMBean117* calls is incorrect in detail.118*/119120public class OldMBeanServerTest {121private static MBeanServerConnection mbsc;122private static String failure;123124public static void main(String[] args) throws Exception {125if (!OldMBeanServerTest.class.desiredAssertionStatus())126throw new Exception("Test must be run with -ea");127128System.setProperty("javax.management.builder.initial",129OldMBeanServerBuilder.class.getName());130assert MBeanServerFactory.newMBeanServer() instanceof OldMBeanServer;131132System.out.println("=== RUNNING TESTS WITH LOCAL MBEANSERVER ===");133runTests(new Callable<MBeanServerConnection>() {134public MBeanServerConnection call() {135return MBeanServerFactory.newMBeanServer();136}137}, null);138139System.out.println("=== RUNNING TESTS THROUGH CONNECTOR ===");140ConnectionBuilder builder = new ConnectionBuilder();141runTests(builder, builder);142143if (failure == null)144System.out.println("TEST PASSED");145else146throw new Exception("TEST FAILED: " + failure);147}148149private static class ConnectionBuilder150implements Callable<MBeanServerConnection>, Runnable {151private JMXConnector connector;152public MBeanServerConnection call() {153MBeanServer mbs = MBeanServerFactory.newMBeanServer();154try {155JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://");156JMXConnectorServer cs =157JMXConnectorServerFactory.newJMXConnectorServer(158url, null, mbs);159cs.start();160JMXServiceURL addr = cs.getAddress();161connector = JMXConnectorFactory.connect(addr);162return connector.getMBeanServerConnection();163} catch (IOException e) {164throw new RuntimeException(e);165}166}167public void run() {168if (connector != null) {169try {170connector.close();171} catch (IOException e) {172throw new RuntimeException(e);173}174}175}176}177178private static void runTests(179Callable<MBeanServerConnection> maker, Runnable breaker)180throws Exception {181for (Method m : OldMBeanServerTest.class.getDeclaredMethods()) {182if (Modifier.isStatic(m.getModifiers()) &&183m.getName().startsWith("test") &&184m.getParameterTypes().length == 0) {185ExpectException expexc = m.getAnnotation(ExpectException.class);186mbsc = maker.call();187try {188m.invoke(null);189if (expexc != null) {190failure =191m.getName() + " did not got expected exception " +192expexc.value().getName();193System.out.println(failure);194} else195System.out.println(m.getName() + " OK");196} catch (InvocationTargetException ite) {197Throwable t = ite.getCause();198String prob = null;199if (expexc != null) {200if (expexc.value().isInstance(t)) {201System.out.println(m.getName() + " OK (got expected " +202expexc.value().getName() + ")");203} else204prob = "got wrong exception";205} else206prob = "got exception";207if (prob != null) {208failure = m.getName() + ": " + prob + " " +209t.getClass().getName();210System.out.println(failure);211t.printStackTrace(System.out);212}213} finally {214if (breaker != null)215breaker.run();216}217}218}219}220221@Retention(RetentionPolicy.RUNTIME)222private static @interface ExpectException {223Class<? extends Exception> value();224}225226public static interface BoringMBean {227public String getName();228public int add(int x, int y);229}230231// This class is Serializable so we can createMBean a StandardMBean232// that contains it. Not recommended practice in general --233// should we have a StandardMBean constructor that takes a class234// name and constructor parameters?235public static class Boring implements BoringMBean, Serializable {236public String getName() {237return "Jessica";238}239240public int add(int x, int y) {241return x + y;242}243}244245public static interface BoringNotifierMBean extends BoringMBean {246public void send();247}248249public static class BoringNotifier250extends Boring implements BoringNotifierMBean, NotificationBroadcaster {251private final NotificationBroadcasterSupport nbs =252new NotificationBroadcasterSupport();253254public void addNotificationListener(255NotificationListener listener, NotificationFilter filter, Object handback)256throws IllegalArgumentException {257nbs.addNotificationListener(listener, filter, handback);258}259260public void removeNotificationListener(NotificationListener listener)261throws ListenerNotFoundException {262nbs.removeNotificationListener(listener);263}264265public MBeanNotificationInfo[] getNotificationInfo() {266return null;267}268269public void send() {270Notification n = new Notification("type.type", this, 0L);271nbs.sendNotification(n);272}273}274275private static class CountListener implements NotificationListener {276volatile int count;277public void handleNotification(Notification n, Object h) {278if (h == null)279h = 1;280count += (Integer) h;281}282void waitForCount(int expect) throws InterruptedException {283long deadline = System.currentTimeMillis() + Utils.adjustTimeout(2000);284while (count < expect && System.currentTimeMillis() < deadline)285Thread.sleep(1);286assert count == expect;287}288}289290private static void testBasic() throws Exception {291CountListener countListener = new CountListener();292mbsc.addNotificationListener(293MBeanServerDelegate.DELEGATE_NAME, countListener, null, null);294assert countListener.count == 0;295ObjectName name = new ObjectName("a:b=c");296if (mbsc instanceof MBeanServer)297((MBeanServer) mbsc).registerMBean(new Boring(), name);298else299mbsc.createMBean(Boring.class.getName(), name);300countListener.waitForCount(1);301assert mbsc.isRegistered(name);302assert mbsc.queryNames(null, null).contains(name);303assert mbsc.getAttribute(name, "Name").equals("Jessica");304assert mbsc.invoke(305name, "add", new Object[] {2, 3}, new String[] {"int", "int"})306.equals(5);307mbsc.unregisterMBean(name);308countListener.waitForCount(2);309assert !mbsc.isRegistered(name);310assert !mbsc.queryNames(null, null).contains(name);311312mbsc.createMBean(BoringNotifier.class.getName(), name);313countListener.waitForCount(3);314CountListener boringListener = new CountListener();315class AlwaysNotificationFilter implements NotificationFilter {316public boolean isNotificationEnabled(Notification notification) {317return true;318}319}320mbsc.addNotificationListener(321name, boringListener, new AlwaysNotificationFilter(), 5);322mbsc.invoke(name, "send", null, null);323boringListener.waitForCount(5);324}325326private static void testPrintAttrs() throws Exception {327printAttrs(mbsc, null);328}329330private static void testPlatformMBeanServer() throws Exception {331MBeanServer pmbs = ManagementFactory.getPlatformMBeanServer();332assert pmbs instanceof OldMBeanServer;333// Preceding assertion could be violated if at some stage we wrap334// the Platform MBeanServer. In that case we can still check that335// it is ultimately an OldMBeanServer for example by adding a336// counter to getAttribute and checking that it is incremented337// when we call pmbs.getAttribute.338339printAttrs(pmbs, UnsupportedOperationException.class);340ObjectName memoryMXBeanName =341new ObjectName(ManagementFactory.MEMORY_MXBEAN_NAME);342pmbs.invoke(memoryMXBeanName, "gc", null, null);343}344345private static void printAttrs(346MBeanServerConnection mbsc1, Class<? extends Exception> expectX)347throws Exception {348Set<ObjectName> names = mbsc1.queryNames(null, null);349for (ObjectName name : names) {350System.out.println(name + ":");351MBeanInfo mbi = mbsc1.getMBeanInfo(name);352MBeanAttributeInfo[] mbais = mbi.getAttributes();353for (MBeanAttributeInfo mbai : mbais) {354String attr = mbai.getName();355Object value;356try {357value = mbsc1.getAttribute(name, attr);358} catch (Exception e) {359if (expectX != null && expectX.isInstance(e))360value = "<" + e + ">";361else362throw e;363}364String s = " " + attr + " = " + value;365if (s.length() > 80)366s = s.substring(0, 77) + "...";367System.out.println(s);368}369}370}371372private static void testJavaxManagementStandardMBean() throws Exception {373ObjectName name = new ObjectName("a:b=c");374Object mbean = new StandardMBean(new Boring(), BoringMBean.class);375mbsc.createMBean(376StandardMBean.class.getName(), name,377new Object[] {new Boring(), BoringMBean.class},378new String[] {Object.class.getName(), Class.class.getName()});379assert mbsc.getAttribute(name, "Name").equals("Jessica");380assert mbsc.invoke(381name, "add", new Object[] {2, 3}, new String[] {"int", "int"})382.equals(5);383mbsc.unregisterMBean(name);384}385386private static void testConnector() throws Exception {387}388389public static class OldMBeanServerBuilder extends MBeanServerBuilder {390public MBeanServer newMBeanServer(391String defaultDomain, MBeanServer outer, MBeanServerDelegate delegate) {392return new OldMBeanServer(defaultDomain, delegate);393}394}395396public static class OldMBeanServer implements MBeanServer {397// We pretend there's a ClassLoader MBean representing the Class Loader398// Repository and intercept references to it where necessary to keep up399// the pretence. This allows us to fake the right behaviour for400// the omitted-ClassLoader versions of createMBean and instantiate401// (which are not the same as passing a null for the ClassLoader parameter402// of the versions that have one).403private static final ObjectName clrName;404static {405try {406clrName =407new ObjectName("JMImplementation:type=ClassLoaderRepository");408} catch (MalformedObjectNameException e) {409throw new RuntimeException(e);410}411}412413private final ConcurrentMap<ObjectName, DynamicMBean> mbeans =414new ConcurrentHashMap<ObjectName, DynamicMBean>();415private final ConcurrentMap<ObjectName, ListenerTable> listenerMap =416new ConcurrentHashMap<ObjectName, ListenerTable>();417private final String defaultDomain;418private final MBeanServerDelegate delegate;419private final ClassLoaderRepositoryImpl clr =420new ClassLoaderRepositoryImpl();421422OldMBeanServer(String defaultDomain, MBeanServerDelegate delegate) {423this.defaultDomain = defaultDomain;424this.delegate = delegate;425try {426registerMBean(delegate, MBeanServerDelegate.DELEGATE_NAME);427} catch (Exception e) {428throw new RuntimeException(e);429}430}431432public ObjectInstance createMBean(String className, ObjectName name)433throws ReflectionException, InstanceAlreadyExistsException,434MBeanRegistrationException, MBeanException,435NotCompliantMBeanException {436return createMBean(className, name, null, null);437}438439public ObjectInstance createMBean(440String className, ObjectName name, ObjectName loaderName)441throws ReflectionException, InstanceAlreadyExistsException,442MBeanRegistrationException, MBeanException,443NotCompliantMBeanException, InstanceNotFoundException {444return createMBean(className, name, loaderName, null, null);445}446447public ObjectInstance createMBean(448String className, ObjectName name, Object[] params, String[] signature)449throws ReflectionException, InstanceAlreadyExistsException,450MBeanRegistrationException, MBeanException,451NotCompliantMBeanException {452try {453return createMBean(className, name, clrName, params, signature);454} catch (InstanceNotFoundException ex) {455throw new RuntimeException(ex); // can't happen456}457}458459public ObjectInstance createMBean(460String className, ObjectName name, ObjectName loaderName,461Object[] params, String[] signature)462throws ReflectionException, InstanceAlreadyExistsException,463MBeanRegistrationException, MBeanException,464NotCompliantMBeanException, InstanceNotFoundException {465Object mbean = instantiate(className, loaderName, params, signature);466return registerMBean(mbean, name);467}468469private void forbidJMImpl(ObjectName name) {470if (name.getDomain().equals("JMImplementation") &&471mbeans.containsKey(MBeanServerDelegate.DELEGATE_NAME))472throw new IllegalArgumentException("JMImplementation reserved");473}474475public ObjectInstance registerMBean(Object object, ObjectName name)476throws InstanceAlreadyExistsException, MBeanRegistrationException,477NotCompliantMBeanException {478forbidJMImpl(name);479if (name.isPattern())480throw new IllegalArgumentException(name.toString());481// This is the only place we check for wildcards. Since you482// can't register a wildcard name, other operations that supply483// one will get InstanceNotFoundException when they look it up.484485DynamicMBean mbean;486if (object instanceof DynamicMBean)487mbean = (DynamicMBean) object;488else489mbean = standardToDynamic(object);490MBeanRegistration reg = mbeanRegistration(object);491try {492name = reg.preRegister(this, name);493} catch (Exception e) {494throw new MBeanRegistrationException(e);495}496DynamicMBean put = mbeans.putIfAbsent(name, mbean);497if (put != null) {498reg.postRegister(false);499throw new InstanceAlreadyExistsException(name.toString());500}501reg.postRegister(true);502503if (object instanceof ClassLoader)504clr.addLoader((ClassLoader) object);505506Notification n = new MBeanServerNotification(507MBeanServerNotification.REGISTRATION_NOTIFICATION,508MBeanServerDelegate.DELEGATE_NAME,5090,510name);511delegate.sendNotification(n);512513String className = mbean.getMBeanInfo().getClassName();514return new ObjectInstance(name, className);515}516517public void unregisterMBean(ObjectName name)518throws InstanceNotFoundException, MBeanRegistrationException {519520forbidJMImpl(name);521522DynamicMBean mbean = getMBean(name);523if (mbean == null)524throw new InstanceNotFoundException(name.toString());525526MBeanRegistration reg = mbeanRegistration(mbean);527try {528reg.preDeregister();529} catch (Exception e) {530throw new MBeanRegistrationException(e);531}532if (!mbeans.remove(name, mbean))533throw new InstanceNotFoundException(name.toString());534// This is incorrect because we've invoked preDeregister535536Object userMBean = getUserMBean(mbean);537if (userMBean instanceof ClassLoader)538clr.removeLoader((ClassLoader) userMBean);539540Notification n = new MBeanServerNotification(541MBeanServerNotification.REGISTRATION_NOTIFICATION,542MBeanServerDelegate.DELEGATE_NAME,5430,544name);545delegate.sendNotification(n);546547reg.postDeregister();548}549550public ObjectInstance getObjectInstance(ObjectName name)551throws InstanceNotFoundException {552DynamicMBean mbean = getMBean(name);553return new ObjectInstance(name, mbean.getMBeanInfo().getClassName());554}555556private static class TrueQueryExp implements QueryExp {557public boolean apply(ObjectName name) {558return true;559}560561public void setMBeanServer(MBeanServer s) {}562}563private static final QueryExp trueQuery = new TrueQueryExp();564565public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) {566Set<ObjectInstance> instances = newSet();567if (name == null)568name = ObjectName.WILDCARD;569if (query == null)570query = trueQuery;571MBeanServer oldMBS = QueryEval.getMBeanServer();572try {573query.setMBeanServer(this);574for (ObjectName n : mbeans.keySet()) {575if (name.apply(n)) {576try {577if (query.apply(n))578instances.add(getObjectInstance(n));579} catch (Exception e) {580// OK: Ignore this MBean in the result581}582}583}584} finally {585query.setMBeanServer(oldMBS);586}587return instances;588}589590public Set<ObjectName> queryNames(ObjectName name, QueryExp query) {591Set<ObjectInstance> instances = queryMBeans(name, query);592Set<ObjectName> names = newSet();593for (ObjectInstance instance : instances)594names.add(instance.getObjectName());595return names;596}597598public boolean isRegistered(ObjectName name) {599return mbeans.containsKey(name);600}601602public Integer getMBeanCount() {603return mbeans.size();604}605606public Object getAttribute(ObjectName name, String attribute)607throws MBeanException, AttributeNotFoundException,608InstanceNotFoundException, ReflectionException {609return getMBean(name).getAttribute(attribute);610}611612public AttributeList getAttributes(ObjectName name, String[] attributes)613throws InstanceNotFoundException, ReflectionException {614return getMBean(name).getAttributes(attributes);615}616617public void setAttribute(ObjectName name, Attribute attribute)618throws InstanceNotFoundException, AttributeNotFoundException,619InvalidAttributeValueException, MBeanException,620ReflectionException {621getMBean(name).setAttribute(attribute);622}623624public AttributeList setAttributes(625ObjectName name, AttributeList attributes)626throws InstanceNotFoundException, ReflectionException {627return getMBean(name).setAttributes(attributes);628}629630public Object invoke(631ObjectName name, String operationName, Object[] params,632String[] signature)633throws InstanceNotFoundException, MBeanException, ReflectionException {634return getMBean(name).invoke(operationName, params, signature);635}636637public String getDefaultDomain() {638return defaultDomain;639}640641public String[] getDomains() {642Set<String> domains = newSet();643for (ObjectName name : mbeans.keySet())644domains.add(name.getDomain());645return domains.toArray(new String[0]);646}647648// ClassCastException if MBean is not a NotificationBroadcaster649public void addNotificationListener(650ObjectName name, NotificationListener listener,651NotificationFilter filter, Object handback)652throws InstanceNotFoundException {653NotificationBroadcaster userMBean =654(NotificationBroadcaster) getUserMBean(name);655NotificationListener wrappedListener =656wrappedListener(name, userMBean, listener);657userMBean.addNotificationListener(wrappedListener, filter, handback);658}659660public void addNotificationListener(661ObjectName name, ObjectName listener,662NotificationFilter filter, Object handback)663throws InstanceNotFoundException {664NotificationListener nl =665(NotificationListener) getUserMBean(listener);666addNotificationListener(name, nl, filter, handback);667}668669public void removeNotificationListener(670ObjectName name, ObjectName listener)671throws InstanceNotFoundException, ListenerNotFoundException {672NotificationListener nl =673(NotificationListener) getUserMBean(listener);674removeNotificationListener(name, nl);675}676677public void removeNotificationListener(678ObjectName name, ObjectName listener,679NotificationFilter filter, Object handback)680throws InstanceNotFoundException, ListenerNotFoundException {681NotificationListener nl =682(NotificationListener) getUserMBean(listener);683removeNotificationListener(name, nl, filter, handback);684}685686public void removeNotificationListener(687ObjectName name, NotificationListener listener)688throws InstanceNotFoundException, ListenerNotFoundException {689NotificationBroadcaster userMBean =690(NotificationBroadcaster) getUserMBean(name);691NotificationListener wrappedListener =692wrappedListener(name, userMBean, listener);693userMBean.removeNotificationListener(wrappedListener);694}695696public void removeNotificationListener(697ObjectName name, NotificationListener listener,698NotificationFilter filter, Object handback)699throws InstanceNotFoundException, ListenerNotFoundException {700NotificationEmitter userMBean =701(NotificationEmitter) getMBean(name);702NotificationListener wrappedListener =703wrappedListener(name, userMBean, listener);704userMBean.removeNotificationListener(wrappedListener, filter, handback);705}706707public MBeanInfo getMBeanInfo(ObjectName name)708throws InstanceNotFoundException, IntrospectionException,709ReflectionException {710return getMBean(name).getMBeanInfo();711}712713public boolean isInstanceOf(ObjectName name, String className)714throws InstanceNotFoundException {715DynamicMBean mbean = getMBean(name);716String mbeanClassName = mbean.getMBeanInfo().getClassName();717if (className.equals(mbeanClassName))718return true;719ClassLoader loader = getUserMBean(mbean).getClass().getClassLoader();720try {721Class<?> mbeanClass = Class.forName(mbeanClassName, false, loader);722Class<?> isInstClass = Class.forName(className, false, loader);723return isInstClass.isAssignableFrom(mbeanClass);724} catch (ClassNotFoundException e) {725return false;726}727}728729public Object instantiate(String className)730throws ReflectionException, MBeanException {731return instantiate(className, null, null);732}733734public Object instantiate(String className, ObjectName loaderName)735throws ReflectionException, MBeanException, InstanceNotFoundException {736return instantiate(className, loaderName, null, null);737}738739public Object instantiate(740String className, Object[] params, String[] signature)741throws ReflectionException, MBeanException {742try {743return instantiate(className, clrName, params, signature);744} catch (InstanceNotFoundException e) {745throw new RuntimeException(e); // can't happen746}747}748749public Object instantiate(750String className, ObjectName loaderName,751Object[] params, String[] signature)752throws ReflectionException, MBeanException, InstanceNotFoundException {753754if (params == null)755params = new Object[0];756if (signature == null)757signature = new String[0];758759ClassLoader loader;760if (loaderName == null)761loader = this.getClass().getClassLoader();762else if (loaderName.equals(clrName))763loader = clr;764else765loader = (ClassLoader) getMBean(loaderName);766767Class<?> c;768try {769c = Class.forName(className, false, loader);770} catch (ClassNotFoundException e) {771throw new ReflectionException(e);772}773774Constructor[] constrs = c.getConstructors();775Constructor found = null;776findconstr:777for (Constructor constr : constrs) {778Class<?>[] cTypes = constr.getParameterTypes();779if (cTypes.length == signature.length) {780for (int i = 0; i < cTypes.length; i++) {781if (!cTypes[i].getName().equals(signature[i]))782continue findconstr;783}784found = constr;785break findconstr;786}787}788if (found == null) {789Exception x = new NoSuchMethodException(790className + Arrays.toString(signature));791throw new ReflectionException(x);792}793return invokeSomething(found, null, params);794}795796@Deprecated797public ObjectInputStream deserialize(ObjectName name, byte[] data)798throws InstanceNotFoundException, OperationsException {799throw new UnsupportedOperationException();800}801802@Deprecated803public ObjectInputStream deserialize(String className, byte[] data)804throws OperationsException, ReflectionException {805throw new UnsupportedOperationException();806}807808@Deprecated809public ObjectInputStream deserialize(810String className, ObjectName loaderName, byte[] data)811throws InstanceNotFoundException, OperationsException, ReflectionException {812throw new UnsupportedOperationException();813}814815public ClassLoader getClassLoaderFor(ObjectName mbeanName)816throws InstanceNotFoundException {817DynamicMBean mbean = getMBean(mbeanName);818Object userMBean = getUserMBean(mbean);819return userMBean.getClass().getClassLoader();820}821822public ClassLoader getClassLoader(ObjectName loaderName)823throws InstanceNotFoundException {824return (ClassLoader) getMBean(loaderName);825}826827public ClassLoaderRepository getClassLoaderRepository() {828return new ClassLoaderRepository() {829public Class<?> loadClass(String className)830throws ClassNotFoundException {831return clr.loadClass(className);832}833834public Class<?> loadClassWithout(835ClassLoader exclude, String className)836throws ClassNotFoundException {837return clr.loadClassWithout(exclude, className);838}839840public Class<?> loadClassBefore(841ClassLoader stop, String className)842throws ClassNotFoundException {843return clr.loadClassBefore(stop, className);844}845};846}847848private static class ClassLoaderRepositoryImpl849extends ClassLoader implements ClassLoaderRepository {850private List<ClassLoader> loaders = newList();851{852loaders.add(this.getClass().getClassLoader());853// We also behave as if the system class loader were in854// the repository, since we do nothing to stop delegation855// to the parent, which is the system class loader, and856// that delegation happens before our findClass is called.857}858859void addLoader(ClassLoader loader) {860loaders.add(loader);861}862863void removeLoader(ClassLoader loader) {864if (!loaders.remove(loader))865throw new RuntimeException("Loader was not in CLR!");866}867868public Class<?> loadClassWithout(869ClassLoader exclude, String className)870throws ClassNotFoundException {871return loadClassWithoutBefore(exclude, null, className);872}873874public Class<?> loadClassBefore(ClassLoader stop, String className)875throws ClassNotFoundException {876return loadClassWithoutBefore(null, stop, className);877}878879private Class<?> loadClassWithoutBefore(880ClassLoader exclude, ClassLoader stop, String className)881throws ClassNotFoundException {882for (ClassLoader loader : loaders) {883if (loader == exclude)884continue;885if (loader == stop)886break;887try {888return Class.forName(className, false, loader);889} catch (ClassNotFoundException e) {890// OK: try others891}892}893throw new ClassNotFoundException(className);894}895896@Override897protected Class<?> findClass(String className)898throws ClassNotFoundException {899return loadClassWithout(null, className);900}901}902903/* There is zero or one ListenerTable per MBean.904* The ListenerTable stuff is complicated. We want to rewrite the905* source of notifications so that if the source of a notification906* from the MBean X is a reference to X itself, it gets replaced907* by X's ObjectName. To do this, we wrap the user's listener in908* a RewriteListener. But if the same listener is added a second909* time (perhaps with a different filter or handback) we must910* reuse the same RewriteListener so that the two-argument911* removeNotificationListener(ObjectName,NotificationListener) will912* correctly remove both listeners. This means we must remember the913* mapping from listener to WrappedListener. But if the MBean914* discards its listeners (as a result of removeNL or spontaneously)915* then we don't want to keep a reference to the WrappedListener.916* So we have tons of WeakReferences. The key in the ListenerTable917* is an IdentityListener, which wraps the user's listener to ensure918* that identity and not equality is used during the lookup, even if919* the user's listener has an equals method. The value in the920* ListenerTable is a WeakReference wrapping a RewriteListener wrapping921* the same IdentityListener. Since the RewriteListener is what is922* added to the user's MBean, the WeakReference won't disappear as long923* as the MBean still has this listener. And since it references the924* IdentityListener, that won't disappear either. But once the925* RewriteListener is no longer referenced by the user's MBean,926* there's nothing to stop its WeakReference from being cleared,927* and then corresponding IdentityListener that is now only weakly928* referenced from the key in the table.929*/930private static class ListenerTable931extends WeakHashMap<NotificationListener,932WeakReference<NotificationListener>> {933}934935private static class IdentityListener implements NotificationListener {936private final NotificationListener userListener;937938IdentityListener(NotificationListener userListener) {939this.userListener = userListener;940}941942public void handleNotification(943Notification notification, Object handback) {944userListener.handleNotification(notification, handback);945}946947@Override948public boolean equals(Object o) {949return (this == o);950}951952@Override953public int hashCode() {954return System.identityHashCode(this);955}956}957958private static class RewriteListener implements NotificationListener {959private final ObjectName name;960private final Object userMBean;961private final NotificationListener userListener;962963RewriteListener(964ObjectName name, Object userMBean,965NotificationListener userListener) {966this.name = name;967this.userMBean = userMBean;968this.userListener = userListener;969}970971public void handleNotification(972Notification notification, Object handback) {973if (notification.getSource() == userMBean)974notification.setSource(name);975userListener.handleNotification(notification, handback);976}977}978979private NotificationListener wrappedListener(980ObjectName name, Object userMBean, NotificationListener userListener)981throws InstanceNotFoundException {982ListenerTable table = new ListenerTable();983ListenerTable oldTable = listenerMap.putIfAbsent(name, table);984if (oldTable != null)985table = oldTable;986NotificationListener identityListener =987new IdentityListener(userListener);988synchronized (table) {989NotificationListener rewriteListener = null;990WeakReference<NotificationListener> wr =991table.get(identityListener);992if (wr != null)993rewriteListener = wr.get();994if (rewriteListener == null) {995rewriteListener = new RewriteListener(996name, userMBean, identityListener);997wr = new WeakReference<NotificationListener>(rewriteListener);998table.put(identityListener, wr);999}1000return rewriteListener;1001}1002}10031004private DynamicMBean getMBean(ObjectName name)1005throws InstanceNotFoundException {1006DynamicMBean mbean = mbeans.get(name);1007if (mbean == null)1008throw new InstanceNotFoundException(name.toString());1009return mbean;1010}10111012private static interface WrapDynamicMBean extends DynamicMBean {1013public Object getWrappedMBean();1014}10151016private static class StandardWrapper1017implements WrapDynamicMBean, MBeanRegistration {1018private final Map<String, AttrMethods> attrMap = newMap();1019private final Map<String, List<Method>> opMap = newMap();1020private static class AttrMethods {1021Method getter, setter;1022}10231024private final Object std;10251026StandardWrapper(Object std) throws NotCompliantMBeanException {1027this.std = std;1028Class<?> intf = mbeanInterface(std.getClass());1029try {1030initMaps(intf);1031} catch (NotCompliantMBeanException e) {1032throw e;1033} catch (Exception e) {1034NotCompliantMBeanException x =1035new NotCompliantMBeanException(e.getMessage());1036x.initCause(e);1037throw x;1038}1039}10401041private static Class<?> mbeanInterface(Class<?> c)1042throws NotCompliantMBeanException {1043do {1044Class<?>[] intfs = c.getInterfaces();1045String intfName = c.getName() + "MBean";1046for (Class<?> intf : intfs) {1047if (intf.getName().equals(intfName))1048return intf;1049}1050c = c.getSuperclass();1051} while (c != null);1052throw new NotCompliantMBeanException(1053"Does not match Standard or Dynamic MBean patterns: " +1054c.getName());1055}10561057private void initMaps(Class<?> intf) throws NotCompliantMBeanException {1058Method[] methods = intf.getMethods();10591060for (Method m : methods) {1061final String name = m.getName();1062final int nParams = m.getParameterTypes().length;10631064String attrName = "";1065if (name.startsWith("get"))1066attrName = name.substring(3);1067else if (name.startsWith("is")1068&& m.getReturnType() == boolean.class)1069attrName = name.substring(2);10701071if (attrName.length() != 0 && m.getParameterTypes().length == 01072&& m.getReturnType() != void.class) {1073// It's a getter1074// Check we don't have both isX and getX1075AttrMethods am = attrMap.get(attrName);1076if (am == null)1077am = new AttrMethods();1078else {1079if (am.getter != null) {1080final String msg = "Attribute " + attrName +1081" has more than one getter";1082throw new NotCompliantMBeanException(msg);1083}1084}1085am.getter = m;1086attrMap.put(attrName, am);1087} else if (name.startsWith("set") && name.length() > 31088&& m.getParameterTypes().length == 1 &&1089m.getReturnType() == void.class) {1090// It's a setter1091attrName = name.substring(3);1092AttrMethods am = attrMap.get(attrName);1093if (am == null)1094am = new AttrMethods();1095else if (am.setter != null) {1096final String msg = "Attribute " + attrName +1097" has more than one setter";1098throw new NotCompliantMBeanException(msg);1099}1100am.setter = m;1101attrMap.put(attrName, am);1102} else {1103// It's an operation1104List<Method> ops = opMap.get(name);1105if (ops == null)1106ops = newList();1107ops.add(m);1108opMap.put(name, ops);1109}1110}1111/* Check that getters and setters are consistent. */1112for (Map.Entry<String, AttrMethods> entry : attrMap.entrySet()) {1113AttrMethods am = entry.getValue();1114if (am.getter != null && am.setter != null &&1115am.getter.getReturnType() != am.setter.getParameterTypes()[0]) {1116final String msg = "Getter and setter for " + entry.getKey() +1117" have inconsistent types";1118throw new NotCompliantMBeanException(msg);1119}1120}1121}11221123public Object getAttribute(String attribute)1124throws AttributeNotFoundException, MBeanException, ReflectionException {1125AttrMethods am = attrMap.get(attribute);1126if (am == null || am.getter == null)1127throw new AttributeNotFoundException(attribute);1128return invokeMethod(am.getter);1129}11301131public void setAttribute(Attribute attribute)1132throws AttributeNotFoundException, InvalidAttributeValueException,1133MBeanException, ReflectionException {1134String name = attribute.getName();1135AttrMethods am = attrMap.get(name);1136if (am == null || am.setter == null)1137throw new AttributeNotFoundException(name);1138invokeMethod(am.setter, attribute.getValue());1139}11401141public AttributeList getAttributes(String[] attributes) {1142AttributeList list = new AttributeList();1143for (String attr : attributes) {1144try {1145list.add(new Attribute(attr, getAttribute(attr)));1146} catch (Exception e) {1147// OK: ignore per spec1148}1149}1150return list;1151}11521153public AttributeList setAttributes(AttributeList attributes) {1154AttributeList list = new AttributeList();1155// We carefully avoid using any new stuff from AttributeList here!1156for (Iterator<?> it = attributes.iterator(); it.hasNext(); ) {1157Attribute attr = (Attribute) it.next();1158try {1159setAttribute(attr);1160list.add(attr);1161} catch (Exception e) {1162// OK: ignore per spec1163}1164}1165return list;1166}11671168public Object invoke(String actionName, Object[] params, String[] signature)1169throws MBeanException, ReflectionException {1170if (params == null)1171params = new Object[0];1172if (signature == null)1173signature = new String[0];1174List<Method> methods = opMap.get(actionName);1175if (methods == null) {1176Exception x = new NoSuchMethodException(actionName);1177throw new MBeanException(x);1178}1179Method found = null;1180methodloop:1181for (Method m : methods) {1182Class<?>[] msig = m.getParameterTypes();1183if (msig.length != signature.length)1184continue methodloop;1185for (int i = 0; i < msig.length; i++) {1186if (!msig[i].getName().equals(signature[i]))1187continue methodloop;1188}1189found = m;1190break methodloop;1191}1192if (found == null) {1193Exception x = new NoSuchMethodException(1194actionName + Arrays.toString(signature));1195throw new MBeanException(x);1196}1197return invokeMethod(found, params);1198}11991200public MBeanInfo getMBeanInfo() {1201// Attributes1202List<MBeanAttributeInfo> attrs = newList();1203for (Map.Entry<String, AttrMethods> attr : attrMap.entrySet()) {1204String name = attr.getKey();1205AttrMethods am = attr.getValue();1206try {1207attrs.add(new MBeanAttributeInfo(1208name, name, am.getter, am.setter));1209} catch (IntrospectionException e) { // grrr1210throw new RuntimeException(e);1211}1212}12131214// Operations1215List<MBeanOperationInfo> ops = newList();1216for (Map.Entry<String, List<Method>> op : opMap.entrySet()) {1217String name = op.getKey();1218List<Method> methods = op.getValue();1219for (Method m : methods)1220ops.add(new MBeanOperationInfo(name, m));1221}12221223// Constructors1224List<MBeanConstructorInfo> constrs = newList();1225for (Constructor constr : std.getClass().getConstructors())1226constrs.add(new MBeanConstructorInfo("Constructor", constr));12271228// Notifications1229MBeanNotificationInfo[] notifs;1230if (std instanceof NotificationBroadcaster)1231notifs = ((NotificationBroadcaster) std).getNotificationInfo();1232else1233notifs = null;12341235String className = std.getClass().getName();1236return new MBeanInfo(1237className, className,1238attrs.toArray(new MBeanAttributeInfo[0]),1239constrs.toArray(new MBeanConstructorInfo[0]),1240ops.toArray(new MBeanOperationInfo[0]),1241notifs);1242}12431244private Object invokeMethod(Method m, Object... args)1245throws MBeanException, ReflectionException {1246return invokeSomething(m, std,args);1247}12481249public ObjectName preRegister(MBeanServer server, ObjectName name)1250throws Exception {1251return mbeanRegistration(std).preRegister(server, name);1252}12531254public void postRegister(Boolean registrationDone) {1255mbeanRegistration(std).postRegister(registrationDone);1256}12571258public void preDeregister() throws Exception {1259mbeanRegistration(std).preDeregister();1260}12611262public void postDeregister() {1263mbeanRegistration(std).postDeregister();1264}12651266public Object getWrappedMBean() {1267return std;1268}1269}12701271private DynamicMBean standardToDynamic(Object std)1272throws NotCompliantMBeanException {1273return new StandardWrapper(std);1274}12751276// private static class NotifWrapper1277// implements WrapDynamicMBean, NotificationEmitter {1278// private final DynamicMBean mbean;1279//1280// NotifWrapper(DynamicMBean mbean) {1281// this.mbean = mbean;1282// }1283//1284// public Object getAttribute(String attribute)1285// throws AttributeNotFoundException, MBeanException, ReflectionException {1286// return mbean.getAttribute(attribute);1287// }1288//1289// public void setAttribute(Attribute attribute)1290// throws AttributeNotFoundException, InvalidAttributeValueException,1291// MBeanException, ReflectionException {1292// mbean.setAttribute(attribute);1293// }1294//1295// public AttributeList getAttributes(String[] attributes) {1296// return mbean.getAttributes(attributes);1297// }1298//1299// public AttributeList setAttributes(AttributeList attributes) {1300// return mbean.setAttributes(attributes);1301// }1302//1303// public Object invoke(1304// String actionName, Object[] params, String[] signature)1305// throws MBeanException, ReflectionException {1306// return mbean.invoke(actionName, params, signature);1307// }1308//1309// public MBeanInfo getMBeanInfo() {1310// return mbean.getMBeanInfo();1311// }1312//1313// public void removeNotificationListener(1314// NotificationListener listener, NotificationFilter filter, Object handback)1315// throws ListenerNotFoundException {1316// ((NotificationEmitter) mbean).removeNotificationListener(1317// listener, filter, handback);1318// // ClassCastException if MBean is not an emitter1319// }1320//1321// public void addNotificationListener(1322// NotificationListener listener, NotificationFilter filter, Object handback)1323// throws IllegalArgumentException {1324// ((NotificationBroadcaster) mbean).addNotificationListener(1325// listener, filter, handback);1326// }1327//1328// public void removeNotificationListener(NotificationListener listener)1329// throws ListenerNotFoundException {1330// ((NotificationBroadcaster) mbean).removeNotificationListener(listener);1331// }1332//1333// public MBeanNotificationInfo[] getNotificationInfo() {1334// return ((NotificationBroadcaster) mbean).getNotificationInfo();1335// }1336//1337// public Object getWrappedMBean() {1338// return getUserMBean(mbean);1339// }1340// }13411342private static Object invokeSomething(1343AccessibleObject ao, Object target, Object[] args)1344throws MBeanException, ReflectionException {1345try {1346if (ao instanceof Method)1347return ((Method) ao).invoke(target, args);1348else1349return ((Constructor) ao).newInstance(args);1350} catch (InvocationTargetException e) {1351try {1352throw e.getCause();1353} catch (RuntimeException x) {1354throw new RuntimeMBeanException(x);1355} catch (Error x) {1356throw new RuntimeErrorException(x);1357} catch (Exception x) {1358throw new MBeanException(x);1359} catch (Throwable x) {1360throw new RuntimeException(x); // neither Error nor Exception!1361}1362} catch (Exception e) {1363throw new ReflectionException(e);1364}1365}13661367private static Object getUserMBean(DynamicMBean mbean) {1368if (mbean instanceof WrapDynamicMBean)1369return ((WrapDynamicMBean) mbean).getWrappedMBean();1370return mbean;1371}13721373private Object getUserMBean(ObjectName name)1374throws InstanceNotFoundException {1375return getUserMBean(getMBean(name));1376}13771378private static final MBeanRegistration noRegistration =1379new MBeanRegistration() {1380public ObjectName preRegister(MBeanServer server, ObjectName name) {1381return name;1382}13831384public void postRegister(Boolean registrationDone) {1385}13861387public void preDeregister() throws Exception {1388}13891390public void postDeregister() {1391}1392};13931394private static MBeanRegistration mbeanRegistration(Object object) {1395if (object instanceof MBeanRegistration)1396return (MBeanRegistration) object;1397else1398return noRegistration;1399}14001401private static <E> List<E> newList() {1402return new ArrayList<E>();1403}14041405private static <K, V> Map<K, V> newMap() {1406return new HashMap<K, V>();1407}14081409private static <E> Set<E> newSet() {1410return new HashSet<E>();1411}1412}1413}141414151416