1 /*
   2  * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 import java.io.IOException;
  25 import java.io.ObjectInputStream;
  26 import java.io.Serializable;
  27 import java.lang.annotation.Retention;
  28 import java.lang.annotation.RetentionPolicy;
  29 import java.lang.management.ManagementFactory;
  30 import java.lang.ref.WeakReference;
  31 import java.lang.reflect.AccessibleObject;
  32 import java.lang.reflect.Constructor;
  33 import java.lang.reflect.InvocationTargetException;
  34 import java.lang.reflect.Method;
  35 import java.lang.reflect.Modifier;
  36 import java.util.ArrayList;
  37 import java.util.Arrays;
  38 import java.util.HashMap;
  39 import java.util.HashSet;
  40 import java.util.Iterator;
  41 import java.util.List;
  42 import java.util.Map;
  43 import java.util.Set;
  44 import java.util.WeakHashMap;
  45 import java.util.concurrent.Callable;
  46 import java.util.concurrent.ConcurrentHashMap;
  47 import java.util.concurrent.ConcurrentMap;
  48 import javax.management.Attribute;
  49 import javax.management.AttributeList;
  50 import javax.management.AttributeNotFoundException;
  51 import javax.management.DynamicMBean;
  52 import javax.management.InstanceAlreadyExistsException;
  53 import javax.management.InstanceNotFoundException;
  54 import javax.management.IntrospectionException;
  55 import javax.management.InvalidAttributeValueException;
  56 import javax.management.ListenerNotFoundException;
  57 import javax.management.MBeanAttributeInfo;
  58 import javax.management.MBeanConstructorInfo;
  59 import javax.management.MBeanException;
  60 import javax.management.MBeanInfo;
  61 import javax.management.MBeanNotificationInfo;
  62 import javax.management.MBeanOperationInfo;
  63 import javax.management.MBeanRegistration;
  64 import javax.management.MBeanRegistrationException;
  65 import javax.management.MBeanServer;
  66 import javax.management.MBeanServerBuilder;
  67 import javax.management.MBeanServerConnection;
  68 import javax.management.MBeanServerDelegate;
  69 import javax.management.MBeanServerFactory;
  70 import javax.management.MBeanServerNotification;
  71 import javax.management.MalformedObjectNameException;
  72 import javax.management.NotCompliantMBeanException;
  73 import javax.management.Notification;
  74 import javax.management.NotificationBroadcaster;
  75 import javax.management.NotificationBroadcasterSupport;
  76 import javax.management.NotificationEmitter;
  77 import javax.management.NotificationFilter;
  78 import javax.management.NotificationListener;
  79 import javax.management.ObjectInstance;
  80 import javax.management.ObjectName;
  81 import javax.management.OperationsException;
  82 import javax.management.QueryEval;
  83 import javax.management.QueryExp;
  84 import javax.management.ReflectionException;
  85 import javax.management.RuntimeErrorException;
  86 import javax.management.RuntimeMBeanException;
  87 import javax.management.StandardMBean;
  88 import javax.management.loading.ClassLoaderRepository;
  89 import javax.management.remote.JMXConnector;
  90 import javax.management.remote.JMXConnectorFactory;
  91 import javax.management.remote.JMXConnectorServer;
  92 import javax.management.remote.JMXConnectorServerFactory;
  93 import javax.management.remote.JMXServiceURL;
  94 
  95 /*
  96  * @test OldMBeanServerTest.java
  97  * @bug 5072268
  98  * @summary Test that nothing assumes a post-1.2 MBeanServer
  99  * @author Eamonn McManus
 100  * @run main/othervm -ea OldMBeanServerTest
 101  */
 102 
 103 /*
 104  * We defined the MBeanServerBuilder class and the associated system
 105  * property javax.management.builder.initial in version 1.2 of the JMX
 106  * spec.  That amounts to a guarantee that someone can set the property
 107  * to an MBeanServer that only knows about JMX 1.2 semantics, and if they
 108  * only do JMX 1.2 operations, everything should work.  This test is a
 109  * sanity check that ensures we don't inadvertently make any API changes
 110  * that stop that from being true.  It includes a complete (if slow)
 111  * MBeanServer implementation.  That implementation doesn't replicate the
 112  * mandated exception behaviour everywhere, though, since there's lots of
 113  * arbitrary cruft in that.  Also, the behaviour of concurrent unregisterMBean
 114  * calls is incorrect in detail.
 115  */
 116 
 117 public class OldMBeanServerTest {
 118     private static MBeanServerConnection mbsc;
 119     private static String failure;
 120 
 121     public static void main(String[] args) throws Exception {
 122         if (!OldMBeanServerTest.class.desiredAssertionStatus())
 123             throw new Exception("Test must be run with -ea");
 124 
 125         System.setProperty("javax.management.builder.initial",
 126                 OldMBeanServerBuilder.class.getName());
 127         assert MBeanServerFactory.newMBeanServer() instanceof OldMBeanServer;
 128 
 129         System.out.println("=== RUNNING TESTS WITH LOCAL MBEANSERVER ===");
 130         runTests(new Callable<MBeanServerConnection>() {
 131             public MBeanServerConnection call() {
 132                 return MBeanServerFactory.newMBeanServer();
 133             }
 134         }, null);
 135 
 136         System.out.println("=== RUNNING TESTS THROUGH CONNECTOR ===");
 137         ConnectionBuilder builder = new ConnectionBuilder();
 138         runTests(builder, builder);
 139 
 140         if (failure == null)
 141             System.out.println("TEST PASSED");
 142         else
 143             throw new Exception("TEST FAILED: " + failure);
 144     }
 145 
 146     private static class ConnectionBuilder
 147             implements Callable<MBeanServerConnection>, Runnable {
 148         private JMXConnector connector;
 149         public MBeanServerConnection call() {
 150             MBeanServer mbs = MBeanServerFactory.newMBeanServer();
 151             try {
 152                 JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://");
 153                 JMXConnectorServer cs =
 154                     JMXConnectorServerFactory.newJMXConnectorServer(
 155                         url, null, mbs);
 156                 cs.start();
 157                 JMXServiceURL addr = cs.getAddress();
 158                 connector = JMXConnectorFactory.connect(addr);
 159                 return connector.getMBeanServerConnection();
 160             } catch (IOException e) {
 161                 throw new RuntimeException(e);
 162             }
 163         }
 164         public void run() {
 165             if (connector != null) {
 166                 try {
 167                     connector.close();
 168                 } catch (IOException e) {
 169                     throw new RuntimeException(e);
 170                 }
 171             }
 172         }
 173     }
 174 
 175     private static void runTests(
 176             Callable<MBeanServerConnection> maker, Runnable breaker)
 177     throws Exception {
 178         for (Method m : OldMBeanServerTest.class.getDeclaredMethods()) {
 179             if (Modifier.isStatic(m.getModifiers()) &&
 180                     m.getName().startsWith("test") &&
 181                     m.getParameterTypes().length == 0) {
 182                 ExpectException expexc = m.getAnnotation(ExpectException.class);
 183                 mbsc = maker.call();
 184                 try {
 185                     m.invoke(null);
 186                     if (expexc != null) {
 187                         failure =
 188                                 m.getName() + " did not got expected exception " +
 189                                 expexc.value().getName();
 190                         System.out.println(failure);
 191                     } else
 192                         System.out.println(m.getName() + " OK");
 193                 } catch (InvocationTargetException ite) {
 194                     Throwable t = ite.getCause();
 195                     String prob = null;
 196                     if (expexc != null) {
 197                         if (expexc.value().isInstance(t)) {
 198                             System.out.println(m.getName() + " OK (got expected " +
 199                                     expexc.value().getName() + ")");
 200                         } else
 201                             prob = "got wrong exception";
 202                     } else
 203                         prob = "got exception";
 204                     if (prob != null) {
 205                         failure = m.getName() + ": " + prob + " " +
 206                                 t.getClass().getName();
 207                         System.out.println(failure);
 208                         t.printStackTrace(System.out);
 209                     }
 210                 } finally {
 211                     if (breaker != null)
 212                         breaker.run();
 213                 }
 214             }
 215         }
 216     }
 217 
 218     @Retention(RetentionPolicy.RUNTIME)
 219     private static @interface ExpectException {
 220         Class<? extends Exception> value();
 221     }
 222 
 223     public static interface BoringMBean {
 224         public String getName();
 225         public int add(int x, int y);
 226     }
 227 
 228     // This class is Serializable so we can createMBean a StandardMBean
 229     // that contains it.  Not recommended practice in general --
 230     // should we have a StandardMBean constructor that takes a class
 231     // name and constructor parameters?
 232     public static class Boring implements BoringMBean, Serializable {
 233         public String getName() {
 234             return "Jessica";
 235         }
 236 
 237         public int add(int x, int y) {
 238             return x + y;
 239         }
 240     }
 241 
 242     public static interface BoringNotifierMBean extends BoringMBean {
 243         public void send();
 244     }
 245 
 246     public static class BoringNotifier
 247             extends Boring implements BoringNotifierMBean, NotificationBroadcaster {
 248         private final NotificationBroadcasterSupport nbs =
 249                 new NotificationBroadcasterSupport();
 250 
 251         public void addNotificationListener(
 252                 NotificationListener listener, NotificationFilter filter, Object handback)
 253         throws IllegalArgumentException {
 254             nbs.addNotificationListener(listener, filter, handback);
 255         }
 256 
 257         public void removeNotificationListener(NotificationListener listener)
 258         throws ListenerNotFoundException {
 259             nbs.removeNotificationListener(listener);
 260         }
 261 
 262         public MBeanNotificationInfo[] getNotificationInfo() {
 263             return null;
 264         }
 265 
 266         public void send() {
 267             Notification n = new Notification("type.type", this, 0L);
 268             nbs.sendNotification(n);
 269         }
 270     }
 271 
 272     private static class CountListener implements NotificationListener {
 273         volatile int count;
 274         public void handleNotification(Notification n, Object h) {
 275             if (h == null)
 276                 h = 1;
 277             count += (Integer) h;
 278         }
 279         void waitForCount(int expect) throws InterruptedException {
 280             long deadline = System.currentTimeMillis() + 2000L;
 281             while (count < expect && System.currentTimeMillis() < deadline)
 282                 Thread.sleep(1);
 283             assert count == expect;
 284         }
 285     }
 286 
 287     private static void testBasic() throws Exception {
 288         CountListener countListener = new CountListener();
 289         mbsc.addNotificationListener(
 290                 MBeanServerDelegate.DELEGATE_NAME, countListener, null, null);
 291         assert countListener.count == 0;
 292         ObjectName name = new ObjectName("a:b=c");
 293         if (mbsc instanceof MBeanServer)
 294             ((MBeanServer) mbsc).registerMBean(new Boring(), name);
 295         else
 296             mbsc.createMBean(Boring.class.getName(), name);
 297         countListener.waitForCount(1);
 298         assert mbsc.isRegistered(name);
 299         assert mbsc.queryNames(null, null).contains(name);
 300         assert mbsc.getAttribute(name, "Name").equals("Jessica");
 301         assert mbsc.invoke(
 302                 name, "add", new Object[] {2, 3}, new String[] {"int", "int"})
 303                 .equals(5);
 304         mbsc.unregisterMBean(name);
 305         countListener.waitForCount(2);
 306         assert !mbsc.isRegistered(name);
 307         assert !mbsc.queryNames(null, null).contains(name);
 308 
 309         mbsc.createMBean(BoringNotifier.class.getName(), name);
 310         countListener.waitForCount(3);
 311         CountListener boringListener = new CountListener();
 312         class AlwaysNotificationFilter implements NotificationFilter {
 313             public boolean isNotificationEnabled(Notification notification) {
 314                 return true;
 315             }
 316         }
 317         mbsc.addNotificationListener(
 318                 name, boringListener, new AlwaysNotificationFilter(), 5);
 319         mbsc.invoke(name, "send", null, null);
 320         boringListener.waitForCount(5);
 321     }
 322 
 323     private static void testPrintAttrs() throws Exception {
 324         printAttrs(mbsc, null);
 325     }
 326 
 327     private static void testPlatformMBeanServer() throws Exception {
 328         MBeanServer pmbs = ManagementFactory.getPlatformMBeanServer();
 329         assert pmbs instanceof OldMBeanServer;
 330         // Preceding assertion could be violated if at some stage we wrap
 331         // the Platform MBeanServer.  In that case we can still check that
 332         // it is ultimately an OldMBeanServer for example by adding a
 333         // counter to getAttribute and checking that it is incremented
 334         // when we call pmbs.getAttribute.
 335 
 336         printAttrs(pmbs, UnsupportedOperationException.class);
 337         ObjectName memoryMXBeanName =
 338                 new ObjectName(ManagementFactory.MEMORY_MXBEAN_NAME);
 339         pmbs.invoke(memoryMXBeanName, "gc", null, null);
 340     }
 341 
 342     private static void printAttrs(
 343             MBeanServerConnection mbsc1, Class<? extends Exception> expectX)
 344     throws Exception {
 345         Set<ObjectName> names = mbsc1.queryNames(null, null);
 346         for (ObjectName name : names) {
 347             System.out.println(name + ":");
 348             MBeanInfo mbi = mbsc1.getMBeanInfo(name);
 349             MBeanAttributeInfo[] mbais = mbi.getAttributes();
 350             for (MBeanAttributeInfo mbai : mbais) {
 351                 String attr = mbai.getName();
 352                 Object value;
 353                 try {
 354                     value = mbsc1.getAttribute(name, attr);
 355                 } catch (Exception e) {
 356                     if (expectX != null && expectX.isInstance(e))
 357                         value = "<" + e + ">";
 358                     else
 359                         throw e;
 360                 }
 361                 String s = "  " + attr + " = " + value;
 362                 if (s.length() > 80)
 363                     s = s.substring(0, 77) + "...";
 364                 System.out.println(s);
 365             }
 366         }
 367     }
 368 
 369     private static void testJavaxManagementStandardMBean() throws Exception {
 370         ObjectName name = new ObjectName("a:b=c");
 371         Object mbean = new StandardMBean(new Boring(), BoringMBean.class);
 372         mbsc.createMBean(
 373                 StandardMBean.class.getName(), name,
 374                 new Object[] {new Boring(), BoringMBean.class},
 375                 new String[] {Object.class.getName(), Class.class.getName()});
 376         assert mbsc.getAttribute(name, "Name").equals("Jessica");
 377         assert mbsc.invoke(
 378                 name, "add", new Object[] {2, 3}, new String[] {"int", "int"})
 379                 .equals(5);
 380         mbsc.unregisterMBean(name);
 381     }
 382 
 383     private static void testConnector() throws Exception {
 384     }
 385 
 386     public static class OldMBeanServerBuilder extends MBeanServerBuilder {
 387         public MBeanServer newMBeanServer(
 388                 String defaultDomain, MBeanServer outer, MBeanServerDelegate delegate) {
 389             return new OldMBeanServer(defaultDomain, delegate);
 390         }
 391     }
 392 
 393     public static class OldMBeanServer implements MBeanServer {
 394         // We pretend there's a ClassLoader MBean representing the Class Loader
 395         // Repository and intercept references to it where necessary to keep up
 396         // the pretence.  This allows us to fake the right behaviour for
 397         // the omitted-ClassLoader versions of createMBean and instantiate
 398         // (which are not the same as passing a null for the ClassLoader parameter
 399         // of the versions that have one).
 400         private static final ObjectName clrName;
 401         static {
 402             try {
 403                 clrName =
 404                         new ObjectName("JMImplementation:type=ClassLoaderRepository");
 405             } catch (MalformedObjectNameException e) {
 406                 throw new RuntimeException(e);
 407             }
 408         }
 409 
 410         private final ConcurrentMap<ObjectName, DynamicMBean> mbeans =
 411                 new ConcurrentHashMap<ObjectName, DynamicMBean>();
 412         private final ConcurrentMap<ObjectName, ListenerTable> listenerMap =
 413                 new ConcurrentHashMap<ObjectName, ListenerTable>();
 414         private final String defaultDomain;
 415         private final MBeanServerDelegate delegate;
 416         private final ClassLoaderRepositoryImpl clr =
 417                 new ClassLoaderRepositoryImpl();
 418 
 419         OldMBeanServer(String defaultDomain, MBeanServerDelegate delegate) {
 420             this.defaultDomain = defaultDomain;
 421             this.delegate = delegate;
 422             try {
 423                 registerMBean(delegate, MBeanServerDelegate.DELEGATE_NAME);
 424             } catch (Exception e) {
 425                 throw new RuntimeException(e);
 426             }
 427         }
 428 
 429         public ObjectInstance createMBean(String className, ObjectName name)
 430         throws ReflectionException, InstanceAlreadyExistsException,
 431                 MBeanRegistrationException, MBeanException,
 432                 NotCompliantMBeanException {
 433             return createMBean(className, name, null, null);
 434         }
 435 
 436         public ObjectInstance createMBean(
 437                 String className, ObjectName name, ObjectName loaderName)
 438         throws ReflectionException, InstanceAlreadyExistsException,
 439                 MBeanRegistrationException, MBeanException,
 440                 NotCompliantMBeanException, InstanceNotFoundException {
 441             return createMBean(className, name, loaderName, null, null);
 442         }
 443 
 444         public ObjectInstance createMBean(
 445                 String className, ObjectName name, Object[] params, String[] signature)
 446         throws ReflectionException, InstanceAlreadyExistsException,
 447                 MBeanRegistrationException, MBeanException,
 448                 NotCompliantMBeanException {
 449             try {
 450                 return createMBean(className, name, clrName, params, signature);
 451             } catch (InstanceNotFoundException ex) {
 452                 throw new RuntimeException(ex);  // can't happen
 453             }
 454         }
 455 
 456         public ObjectInstance createMBean(
 457                 String className, ObjectName name, ObjectName loaderName,
 458                 Object[] params, String[] signature)
 459         throws ReflectionException, InstanceAlreadyExistsException,
 460                 MBeanRegistrationException, MBeanException,
 461                 NotCompliantMBeanException, InstanceNotFoundException {
 462             Object mbean = instantiate(className, loaderName, params, signature);
 463             return registerMBean(mbean, name);
 464         }
 465 
 466         private void forbidJMImpl(ObjectName name) {
 467             if (name.getDomain().equals("JMImplementation") &&
 468                     mbeans.containsKey(MBeanServerDelegate.DELEGATE_NAME))
 469                 throw new IllegalArgumentException("JMImplementation reserved");
 470         }
 471 
 472         public ObjectInstance registerMBean(Object object, ObjectName name)
 473         throws InstanceAlreadyExistsException, MBeanRegistrationException,
 474                 NotCompliantMBeanException {
 475             forbidJMImpl(name);
 476             if (name.isPattern())
 477                 throw new IllegalArgumentException(name.toString());
 478             // This is the only place we check for wildcards.  Since you
 479             // can't register a wildcard name, other operations that supply
 480             // one will get InstanceNotFoundException when they look it up.
 481 
 482             DynamicMBean mbean;
 483             if (object instanceof DynamicMBean)
 484                 mbean = (DynamicMBean) object;
 485             else
 486                 mbean = standardToDynamic(object);
 487             MBeanRegistration reg = mbeanRegistration(object);
 488             try {
 489                 name = reg.preRegister(this, name);
 490             } catch (Exception e) {
 491                 throw new MBeanRegistrationException(e);
 492             }
 493             DynamicMBean put = mbeans.putIfAbsent(name, mbean);
 494             if (put != null) {
 495                 reg.postRegister(false);
 496                 throw new InstanceAlreadyExistsException(name.toString());
 497             }
 498             reg.postRegister(true);
 499 
 500             if (object instanceof ClassLoader)
 501                 clr.addLoader((ClassLoader) object);
 502 
 503             Notification n = new MBeanServerNotification(
 504                     MBeanServerNotification.REGISTRATION_NOTIFICATION,
 505                     MBeanServerDelegate.DELEGATE_NAME,
 506                     0,
 507                     name);
 508             delegate.sendNotification(n);
 509 
 510             String className = mbean.getMBeanInfo().getClassName();
 511             return new ObjectInstance(name, className);
 512         }
 513 
 514         public void unregisterMBean(ObjectName name)
 515         throws InstanceNotFoundException, MBeanRegistrationException {
 516 
 517             forbidJMImpl(name);
 518 
 519             DynamicMBean mbean = getMBean(name);
 520             if (mbean == null)
 521                 throw new InstanceNotFoundException(name.toString());
 522 
 523             MBeanRegistration reg = mbeanRegistration(mbean);
 524             try {
 525                 reg.preDeregister();
 526             } catch (Exception e) {
 527                 throw new MBeanRegistrationException(e);
 528             }
 529             if (!mbeans.remove(name, mbean))
 530                 throw new InstanceNotFoundException(name.toString());
 531                 // This is incorrect because we've invoked preDeregister
 532 
 533             Object userMBean = getUserMBean(mbean);
 534             if (userMBean instanceof ClassLoader)
 535                 clr.removeLoader((ClassLoader) userMBean);
 536 
 537             Notification n = new MBeanServerNotification(
 538                     MBeanServerNotification.REGISTRATION_NOTIFICATION,
 539                     MBeanServerDelegate.DELEGATE_NAME,
 540                     0,
 541                     name);
 542             delegate.sendNotification(n);
 543 
 544             reg.postDeregister();
 545         }
 546 
 547         public ObjectInstance getObjectInstance(ObjectName name)
 548         throws InstanceNotFoundException {
 549             DynamicMBean mbean = getMBean(name);
 550             return new ObjectInstance(name, mbean.getMBeanInfo().getClassName());
 551         }
 552 
 553         private static class TrueQueryExp implements QueryExp {
 554             public boolean apply(ObjectName name) {
 555                 return true;
 556             }
 557 
 558             public void setMBeanServer(MBeanServer s) {}
 559         }
 560         private static final QueryExp trueQuery = new TrueQueryExp();
 561 
 562         public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) {
 563             Set<ObjectInstance> instances = newSet();
 564             if (name == null)
 565                 name = ObjectName.WILDCARD;
 566             if (query == null)
 567                 query = trueQuery;
 568             MBeanServer oldMBS = QueryEval.getMBeanServer();
 569             try {
 570                 query.setMBeanServer(this);
 571                 for (ObjectName n : mbeans.keySet()) {
 572                     if (name.apply(n)) {
 573                         try {
 574                             if (query.apply(n))
 575                                 instances.add(getObjectInstance(n));
 576                         } catch (Exception e) {
 577                             // OK: Ignore this MBean in the result
 578                         }
 579                     }
 580                 }
 581             } finally {
 582                 query.setMBeanServer(oldMBS);
 583             }
 584             return instances;
 585         }
 586 
 587         public Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
 588             Set<ObjectInstance> instances = queryMBeans(name, query);
 589             Set<ObjectName> names = newSet();
 590             for (ObjectInstance instance : instances)
 591                 names.add(instance.getObjectName());
 592             return names;
 593         }
 594 
 595         public boolean isRegistered(ObjectName name) {
 596             return mbeans.containsKey(name);
 597         }
 598 
 599         public Integer getMBeanCount() {
 600             return mbeans.size();
 601         }
 602 
 603         public Object getAttribute(ObjectName name, String attribute)
 604         throws MBeanException, AttributeNotFoundException,
 605                 InstanceNotFoundException, ReflectionException {
 606             return getMBean(name).getAttribute(attribute);
 607         }
 608 
 609         public AttributeList getAttributes(ObjectName name, String[] attributes)
 610         throws InstanceNotFoundException, ReflectionException {
 611             return getMBean(name).getAttributes(attributes);
 612         }
 613 
 614         public void setAttribute(ObjectName name, Attribute attribute)
 615         throws InstanceNotFoundException, AttributeNotFoundException,
 616                 InvalidAttributeValueException, MBeanException,
 617                 ReflectionException {
 618             getMBean(name).setAttribute(attribute);
 619         }
 620 
 621         public AttributeList setAttributes(
 622                 ObjectName name, AttributeList attributes)
 623         throws InstanceNotFoundException, ReflectionException {
 624             return getMBean(name).setAttributes(attributes);
 625         }
 626 
 627         public Object invoke(
 628                 ObjectName name, String operationName, Object[] params,
 629                 String[] signature)
 630         throws InstanceNotFoundException, MBeanException, ReflectionException {
 631             return getMBean(name).invoke(operationName, params, signature);
 632         }
 633 
 634         public String getDefaultDomain() {
 635             return defaultDomain;
 636         }
 637 
 638         public String[] getDomains() {
 639             Set<String> domains = newSet();
 640             for (ObjectName name : mbeans.keySet())
 641                 domains.add(name.getDomain());
 642             return domains.toArray(new String[0]);
 643         }
 644 
 645         // ClassCastException if MBean is not a NotificationBroadcaster
 646         public void addNotificationListener(
 647                 ObjectName name, NotificationListener listener,
 648                 NotificationFilter filter, Object handback)
 649                 throws InstanceNotFoundException {
 650             NotificationBroadcaster userMBean =
 651                     (NotificationBroadcaster) getUserMBean(name);
 652             NotificationListener wrappedListener =
 653                   wrappedListener(name, userMBean, listener);
 654             userMBean.addNotificationListener(wrappedListener, filter, handback);
 655         }
 656 
 657         public void addNotificationListener(
 658                 ObjectName name, ObjectName listener,
 659                 NotificationFilter filter, Object handback)
 660                 throws InstanceNotFoundException {
 661             NotificationListener nl =
 662                     (NotificationListener) getUserMBean(listener);
 663             addNotificationListener(name, nl, filter, handback);
 664         }
 665 
 666         public void removeNotificationListener(
 667                 ObjectName name, ObjectName listener)
 668                 throws InstanceNotFoundException, ListenerNotFoundException {
 669             NotificationListener nl =
 670                     (NotificationListener) getUserMBean(listener);
 671             removeNotificationListener(name, nl);
 672         }
 673 
 674         public void removeNotificationListener(
 675                 ObjectName name, ObjectName listener,
 676                 NotificationFilter filter, Object handback)
 677                 throws InstanceNotFoundException, ListenerNotFoundException {
 678             NotificationListener nl =
 679                     (NotificationListener) getUserMBean(listener);
 680             removeNotificationListener(name, nl, filter, handback);
 681         }
 682 
 683         public void removeNotificationListener(
 684                 ObjectName name, NotificationListener listener)
 685                 throws InstanceNotFoundException, ListenerNotFoundException {
 686             NotificationBroadcaster userMBean =
 687                     (NotificationBroadcaster) getUserMBean(name);
 688             NotificationListener wrappedListener =
 689                   wrappedListener(name, userMBean, listener);
 690             userMBean.removeNotificationListener(wrappedListener);
 691         }
 692 
 693         public void removeNotificationListener(
 694                 ObjectName name, NotificationListener listener,
 695                 NotificationFilter filter, Object handback)
 696                 throws InstanceNotFoundException, ListenerNotFoundException {
 697             NotificationEmitter userMBean =
 698                     (NotificationEmitter) getMBean(name);
 699             NotificationListener wrappedListener =
 700                   wrappedListener(name, userMBean, listener);
 701             userMBean.removeNotificationListener(wrappedListener, filter, handback);
 702         }
 703 
 704         public MBeanInfo getMBeanInfo(ObjectName name)
 705         throws InstanceNotFoundException, IntrospectionException,
 706                 ReflectionException {
 707             return getMBean(name).getMBeanInfo();
 708         }
 709 
 710         public boolean isInstanceOf(ObjectName name, String className)
 711         throws InstanceNotFoundException {
 712             DynamicMBean mbean = getMBean(name);
 713             String mbeanClassName = mbean.getMBeanInfo().getClassName();
 714             if (className.equals(mbeanClassName))
 715                 return true;
 716             ClassLoader loader = getUserMBean(mbean).getClass().getClassLoader();
 717             try {
 718                 Class<?> mbeanClass = Class.forName(mbeanClassName, false, loader);
 719                 Class<?> isInstClass = Class.forName(className, false, loader);
 720                 return isInstClass.isAssignableFrom(mbeanClass);
 721             } catch (ClassNotFoundException e) {
 722                 return false;
 723             }
 724         }
 725 
 726         public Object instantiate(String className)
 727         throws ReflectionException, MBeanException {
 728             return instantiate(className, null, null);
 729         }
 730 
 731         public Object instantiate(String className, ObjectName loaderName)
 732         throws ReflectionException, MBeanException, InstanceNotFoundException {
 733             return instantiate(className, loaderName, null, null);
 734         }
 735 
 736         public Object instantiate(
 737                 String className, Object[] params, String[] signature)
 738         throws ReflectionException, MBeanException {
 739             try {
 740                 return instantiate(className, clrName, params, signature);
 741             } catch (InstanceNotFoundException e) {
 742                 throw new RuntimeException(e);  // can't happen
 743             }
 744         }
 745 
 746         public Object instantiate(
 747                 String className, ObjectName loaderName,
 748                 Object[] params, String[] signature)
 749         throws ReflectionException, MBeanException, InstanceNotFoundException {
 750 
 751             if (params == null)
 752                 params = new Object[0];
 753             if (signature == null)
 754                 signature = new String[0];
 755 
 756             ClassLoader loader;
 757             if (loaderName == null)
 758                 loader = this.getClass().getClassLoader();
 759             else if (loaderName.equals(clrName))
 760                 loader = clr;
 761             else
 762                 loader = (ClassLoader) getMBean(loaderName);
 763 
 764             Class<?> c;
 765             try {
 766                 c = Class.forName(className, false, loader);
 767             } catch (ClassNotFoundException e) {
 768                 throw new ReflectionException(e);
 769             }
 770 
 771             Constructor[] constrs = c.getConstructors();
 772             Constructor found = null;
 773             findconstr:
 774             for (Constructor constr : constrs) {
 775                 Class<?>[] cTypes = constr.getParameterTypes();
 776                 if (cTypes.length == signature.length) {
 777                     for (int i = 0; i < cTypes.length; i++) {
 778                         if (!cTypes[i].getName().equals(signature[i]))
 779                             continue findconstr;
 780                     }
 781                     found = constr;
 782                     break findconstr;
 783                 }
 784             }
 785             if (found == null) {
 786                 Exception x = new NoSuchMethodException(
 787                         className + Arrays.toString(signature));
 788                 throw new ReflectionException(x);
 789             }
 790             return invokeSomething(found, null, params);
 791         }
 792 
 793         @Deprecated
 794         public ObjectInputStream deserialize(ObjectName name, byte[] data)
 795         throws InstanceNotFoundException, OperationsException {
 796             throw new UnsupportedOperationException();
 797         }
 798 
 799         @Deprecated
 800         public ObjectInputStream deserialize(String className, byte[] data)
 801         throws OperationsException, ReflectionException {
 802             throw new UnsupportedOperationException();
 803         }
 804 
 805         @Deprecated
 806         public ObjectInputStream deserialize(
 807                 String className, ObjectName loaderName, byte[] data)
 808         throws InstanceNotFoundException, OperationsException, ReflectionException {
 809             throw new UnsupportedOperationException();
 810         }
 811 
 812         public ClassLoader getClassLoaderFor(ObjectName mbeanName)
 813         throws InstanceNotFoundException {
 814             DynamicMBean mbean = getMBean(mbeanName);
 815             Object userMBean = getUserMBean(mbean);
 816             return userMBean.getClass().getClassLoader();
 817         }
 818 
 819         public ClassLoader getClassLoader(ObjectName loaderName)
 820         throws InstanceNotFoundException {
 821             return (ClassLoader) getMBean(loaderName);
 822         }
 823 
 824         public ClassLoaderRepository getClassLoaderRepository() {
 825             return new ClassLoaderRepository() {
 826                 public Class<?> loadClass(String className)
 827                 throws ClassNotFoundException {
 828                     return clr.loadClass(className);
 829                 }
 830 
 831                 public Class<?> loadClassWithout(
 832                         ClassLoader exclude, String className)
 833                 throws ClassNotFoundException {
 834                     return clr.loadClassWithout(exclude, className);
 835                 }
 836 
 837                 public Class<?> loadClassBefore(
 838                         ClassLoader stop, String className)
 839                 throws ClassNotFoundException {
 840                     return clr.loadClassBefore(stop, className);
 841                 }
 842             };
 843         }
 844 
 845         private static class ClassLoaderRepositoryImpl
 846                 extends ClassLoader implements ClassLoaderRepository {
 847             private List<ClassLoader> loaders = newList();
 848             {
 849                 loaders.add(this.getClass().getClassLoader());
 850                 // We also behave as if the system class loader were in
 851                 // the repository, since we do nothing to stop delegation
 852                 // to the parent, which is the system class loader, and
 853                 // that delegation happens before our findClass is called.
 854             }
 855 
 856             void addLoader(ClassLoader loader) {
 857                 loaders.add(loader);
 858             }
 859 
 860             void removeLoader(ClassLoader loader) {
 861                 if (!loaders.remove(loader))
 862                     throw new RuntimeException("Loader was not in CLR!");
 863             }
 864 
 865             public Class<?> loadClassWithout(
 866                     ClassLoader exclude, String className)
 867                     throws ClassNotFoundException {
 868                 return loadClassWithoutBefore(exclude, null, className);
 869             }
 870 
 871             public Class<?> loadClassBefore(ClassLoader stop, String className)
 872             throws ClassNotFoundException {
 873                 return loadClassWithoutBefore(null, stop, className);
 874             }
 875 
 876             private Class<?> loadClassWithoutBefore(
 877                     ClassLoader exclude, ClassLoader stop, String className)
 878                     throws ClassNotFoundException {
 879                 for (ClassLoader loader : loaders) {
 880                     if (loader == exclude)
 881                         continue;
 882                     if (loader == stop)
 883                         break;
 884                     try {
 885                         return Class.forName(className, false, loader);
 886                     } catch (ClassNotFoundException e) {
 887                         // OK: try others
 888                     }
 889                 }
 890                 throw new ClassNotFoundException(className);
 891             }
 892 
 893             @Override
 894             protected Class<?> findClass(String className)
 895             throws ClassNotFoundException {
 896                 return loadClassWithout(null, className);
 897             }
 898         }
 899 
 900         /* There is zero or one ListenerTable per MBean.
 901          * The ListenerTable stuff is complicated.  We want to rewrite the
 902          * source of notifications so that if the source of a notification
 903          * from the MBean X is a reference to X itself, it gets replaced
 904          * by X's ObjectName.  To do this, we wrap the user's listener in
 905          * a RewriteListener.  But if the same listener is added a second
 906          * time (perhaps with a different filter or handback) we must
 907          * reuse the same RewriteListener so that the two-argument
 908          * removeNotificationListener(ObjectName,NotificationListener) will
 909          * correctly remove both listeners. This means we must remember the
 910          * mapping from listener to WrappedListener.  But if the MBean
 911          * discards its listeners (as a result of removeNL or spontaneously)
 912          * then we don't want to keep a reference to the WrappedListener.
 913          * So we have tons of WeakReferences.  The key in the ListenerTable
 914          * is an IdentityListener, which wraps the user's listener to ensure
 915          * that identity and not equality is used during the lookup, even if
 916          * the user's listener has an equals method.  The value in the
 917          * ListenerTable is a WeakReference wrapping a RewriteListener wrapping
 918          * the same IdentityListener.  Since the RewriteListener is what is
 919          * added to the user's MBean, the WeakReference won't disappear as long
 920          * as the MBean still has this listener.  And since it references the
 921          * IdentityListener, that won't disappear either.  But once the
 922          * RewriteListener is no longer referenced by the user's MBean,
 923          * there's nothing to stop its WeakReference from being cleared,
 924          * and then corresponding IdentityListener that is now only weakly
 925          * referenced from the key in the table.
 926          */
 927         private static class ListenerTable
 928                 extends WeakHashMap<NotificationListener,
 929                                     WeakReference<NotificationListener>> {
 930         }
 931 
 932         private static class IdentityListener implements NotificationListener {
 933             private final NotificationListener userListener;
 934 
 935             IdentityListener(NotificationListener userListener) {
 936                 this.userListener = userListener;
 937             }
 938 
 939             public void handleNotification(
 940                     Notification notification, Object handback) {
 941                 userListener.handleNotification(notification, handback);
 942             }
 943 
 944             @Override
 945             public boolean equals(Object o) {
 946                 return (this == o);
 947             }
 948 
 949             @Override
 950             public int hashCode() {
 951                 return System.identityHashCode(this);
 952             }
 953         }
 954 
 955         private static class RewriteListener implements NotificationListener {
 956             private final ObjectName name;
 957             private final Object userMBean;
 958             private final NotificationListener userListener;
 959 
 960             RewriteListener(
 961                     ObjectName name, Object userMBean,
 962                     NotificationListener userListener) {
 963                 this.name = name;
 964                 this.userMBean = userMBean;
 965                 this.userListener = userListener;
 966             }
 967 
 968             public void handleNotification(
 969                     Notification notification, Object handback) {
 970                 if (notification.getSource() == userMBean)
 971                     notification.setSource(name);
 972                 userListener.handleNotification(notification, handback);
 973             }
 974         }
 975 
 976         private NotificationListener wrappedListener(
 977                 ObjectName name, Object userMBean, NotificationListener userListener)
 978         throws InstanceNotFoundException {
 979             ListenerTable table = new ListenerTable();
 980             ListenerTable oldTable = listenerMap.putIfAbsent(name, table);
 981             if (oldTable != null)
 982                 table = oldTable;
 983             NotificationListener identityListener =
 984                     new IdentityListener(userListener);
 985             synchronized (table) {
 986                 NotificationListener rewriteListener = null;
 987                 WeakReference<NotificationListener> wr =
 988                         table.get(identityListener);
 989                 if (wr != null)
 990                     rewriteListener = wr.get();
 991                 if (rewriteListener == null) {
 992                     rewriteListener = new RewriteListener(
 993                             name, userMBean, identityListener);
 994                     wr = new WeakReference<NotificationListener>(rewriteListener);
 995                     table.put(identityListener, wr);
 996                 }
 997                 return rewriteListener;
 998             }
 999         }
1000 
1001         private DynamicMBean getMBean(ObjectName name)
1002         throws InstanceNotFoundException {
1003             DynamicMBean mbean = mbeans.get(name);
1004             if (mbean == null)
1005                 throw new InstanceNotFoundException(name.toString());
1006             return mbean;
1007         }
1008 
1009         private static interface WrapDynamicMBean extends DynamicMBean {
1010             public Object getWrappedMBean();
1011         }
1012 
1013         private static class StandardWrapper
1014                 implements WrapDynamicMBean, MBeanRegistration {
1015             private final Map<String, AttrMethods> attrMap = newMap();
1016             private final Map<String, List<Method>> opMap = newMap();
1017             private static class AttrMethods {
1018                 Method getter, setter;
1019             }
1020 
1021             private final Object std;
1022 
1023             StandardWrapper(Object std) throws NotCompliantMBeanException {
1024                 this.std = std;
1025                 Class<?> intf = mbeanInterface(std.getClass());
1026                 try {
1027                     initMaps(intf);
1028                 } catch (NotCompliantMBeanException e) {
1029                     throw e;
1030                 } catch (Exception e) {
1031                     NotCompliantMBeanException x =
1032                             new NotCompliantMBeanException(e.getMessage());
1033                     x.initCause(e);
1034                     throw x;
1035                 }
1036             }
1037 
1038             private static Class<?> mbeanInterface(Class<?> c)
1039             throws NotCompliantMBeanException {
1040                 do {
1041                     Class<?>[] intfs = c.getInterfaces();
1042                     String intfName = c.getName() + "MBean";
1043                     for (Class<?> intf : intfs) {
1044                         if (intf.getName().equals(intfName))
1045                             return intf;
1046                     }
1047                     c = c.getSuperclass();
1048                 } while (c != null);
1049                 throw new NotCompliantMBeanException(
1050                         "Does not match Standard or Dynamic MBean patterns: " +
1051                         c.getName());
1052             }
1053 
1054             private void initMaps(Class<?> intf) throws NotCompliantMBeanException {
1055                 Method[] methods = intf.getMethods();
1056 
1057                 for (Method m : methods) {
1058                     final String name = m.getName();
1059                     final int nParams = m.getParameterTypes().length;
1060 
1061                     String attrName = "";
1062                     if (name.startsWith("get"))
1063                         attrName = name.substring(3);
1064                     else if (name.startsWith("is")
1065                     && m.getReturnType() == boolean.class)
1066                         attrName = name.substring(2);
1067 
1068                     if (attrName.length() != 0 && m.getParameterTypes().length == 0
1069                             && m.getReturnType() != void.class) {
1070                         // It's a getter
1071                         // Check we don't have both isX and getX
1072                         AttrMethods am = attrMap.get(attrName);
1073                         if (am == null)
1074                             am = new AttrMethods();
1075                         else {
1076                             if (am.getter != null) {
1077                                 final String msg = "Attribute " + attrName +
1078                                         " has more than one getter";
1079                                 throw new NotCompliantMBeanException(msg);
1080                             }
1081                         }
1082                         am.getter = m;
1083                         attrMap.put(attrName, am);
1084                     } else if (name.startsWith("set") && name.length() > 3
1085                             && m.getParameterTypes().length == 1 &&
1086                             m.getReturnType() == void.class) {
1087                         // It's a setter
1088                         attrName = name.substring(3);
1089                         AttrMethods am = attrMap.get(attrName);
1090                         if (am == null)
1091                             am = new AttrMethods();
1092                         else if (am.setter != null) {
1093                             final String msg = "Attribute " + attrName +
1094                                     " has more than one setter";
1095                             throw new NotCompliantMBeanException(msg);
1096                         }
1097                         am.setter = m;
1098                         attrMap.put(attrName, am);
1099                     } else {
1100                         // It's an operation
1101                         List<Method> ops = opMap.get(name);
1102                         if (ops == null)
1103                             ops = newList();
1104                         ops.add(m);
1105                         opMap.put(name, ops);
1106                     }
1107                 }
1108                 /* Check that getters and setters are consistent. */
1109                 for (Map.Entry<String, AttrMethods> entry : attrMap.entrySet()) {
1110                     AttrMethods am = entry.getValue();
1111                     if (am.getter != null && am.setter != null &&
1112                             am.getter.getReturnType() != am.setter.getParameterTypes()[0]) {
1113                         final String msg = "Getter and setter for " + entry.getKey() +
1114                                 " have inconsistent types";
1115                         throw new NotCompliantMBeanException(msg);
1116                     }
1117                 }
1118             }
1119 
1120             public Object getAttribute(String attribute)
1121             throws AttributeNotFoundException, MBeanException, ReflectionException {
1122                 AttrMethods am = attrMap.get(attribute);
1123                 if (am == null || am.getter == null)
1124                     throw new AttributeNotFoundException(attribute);
1125                 return invokeMethod(am.getter);
1126             }
1127 
1128             public void setAttribute(Attribute attribute)
1129             throws AttributeNotFoundException, InvalidAttributeValueException,
1130                     MBeanException, ReflectionException {
1131                 String name = attribute.getName();
1132                 AttrMethods am = attrMap.get(name);
1133                 if (am == null || am.setter == null)
1134                     throw new AttributeNotFoundException(name);
1135                 invokeMethod(am.setter, attribute.getValue());
1136             }
1137 
1138             public AttributeList getAttributes(String[] attributes) {
1139                 AttributeList list = new AttributeList();
1140                 for (String attr : attributes) {
1141                     try {
1142                         list.add(new Attribute(attr, getAttribute(attr)));
1143                     } catch (Exception e) {
1144                         // OK: ignore per spec
1145                     }
1146                 }
1147                 return list;
1148             }
1149 
1150             public AttributeList setAttributes(AttributeList attributes) {
1151                 AttributeList list = new AttributeList();
1152                 // We carefully avoid using any new stuff from AttributeList here!
1153                 for (Iterator<?> it = attributes.iterator(); it.hasNext(); ) {
1154                     Attribute attr = (Attribute) it.next();
1155                     try {
1156                         setAttribute(attr);
1157                         list.add(attr);
1158                     } catch (Exception e) {
1159                         // OK: ignore per spec
1160                     }
1161                 }
1162                 return list;
1163             }
1164 
1165             public Object invoke(String actionName, Object[] params, String[] signature)
1166             throws MBeanException, ReflectionException {
1167                 if (params == null)
1168                     params = new Object[0];
1169                 if (signature == null)
1170                     signature = new String[0];
1171                 List<Method> methods = opMap.get(actionName);
1172                 if (methods == null) {
1173                     Exception x = new NoSuchMethodException(actionName);
1174                     throw new MBeanException(x);
1175                 }
1176                 Method found = null;
1177                 methodloop:
1178                 for (Method m : methods) {
1179                     Class<?>[] msig = m.getParameterTypes();
1180                     if (msig.length != signature.length)
1181                         continue methodloop;
1182                     for (int i = 0; i < msig.length; i++) {
1183                         if (!msig[i].getName().equals(signature[i]))
1184                             continue methodloop;
1185                     }
1186                     found = m;
1187                     break methodloop;
1188                 }
1189                 if (found == null) {
1190                     Exception x = new NoSuchMethodException(
1191                             actionName + Arrays.toString(signature));
1192                     throw new MBeanException(x);
1193                 }
1194                 return invokeMethod(found, params);
1195             }
1196 
1197             public MBeanInfo getMBeanInfo() {
1198                 // Attributes
1199                 List<MBeanAttributeInfo> attrs = newList();
1200                 for (Map.Entry<String, AttrMethods> attr : attrMap.entrySet()) {
1201                     String name = attr.getKey();
1202                     AttrMethods am = attr.getValue();
1203                     try {
1204                         attrs.add(new MBeanAttributeInfo(
1205                                 name, name, am.getter, am.setter));
1206                     } catch (IntrospectionException e) { // grrr
1207                         throw new RuntimeException(e);
1208                     }
1209                 }
1210 
1211                 // Operations
1212                 List<MBeanOperationInfo> ops = newList();
1213                 for (Map.Entry<String, List<Method>> op : opMap.entrySet()) {
1214                     String name = op.getKey();
1215                     List<Method> methods = op.getValue();
1216                     for (Method m : methods)
1217                         ops.add(new MBeanOperationInfo(name, m));
1218                 }
1219 
1220                 // Constructors
1221                 List<MBeanConstructorInfo> constrs = newList();
1222                 for (Constructor constr : std.getClass().getConstructors())
1223                     constrs.add(new MBeanConstructorInfo("Constructor", constr));
1224 
1225                 // Notifications
1226                 MBeanNotificationInfo[] notifs;
1227                 if (std instanceof NotificationBroadcaster)
1228                     notifs = ((NotificationBroadcaster) std).getNotificationInfo();
1229                 else
1230                     notifs = null;
1231 
1232                 String className = std.getClass().getName();
1233                 return new MBeanInfo(
1234                         className, className,
1235                         attrs.toArray(new MBeanAttributeInfo[0]),
1236                         constrs.toArray(new MBeanConstructorInfo[0]),
1237                         ops.toArray(new MBeanOperationInfo[0]),
1238                         notifs);
1239             }
1240 
1241             private Object invokeMethod(Method m, Object... args)
1242             throws MBeanException, ReflectionException {
1243                 return invokeSomething(m, std,args);
1244             }
1245 
1246             public ObjectName preRegister(MBeanServer server, ObjectName name)
1247             throws Exception {
1248                 return mbeanRegistration(std).preRegister(server, name);
1249             }
1250 
1251             public void postRegister(Boolean registrationDone) {
1252                 mbeanRegistration(std).postRegister(registrationDone);
1253             }
1254 
1255             public void preDeregister() throws Exception {
1256                 mbeanRegistration(std).preDeregister();
1257             }
1258 
1259             public void postDeregister() {
1260                 mbeanRegistration(std).postDeregister();
1261             }
1262 
1263             public Object getWrappedMBean() {
1264                 return std;
1265             }
1266         }
1267 
1268         private DynamicMBean standardToDynamic(Object std)
1269         throws NotCompliantMBeanException {
1270             return new StandardWrapper(std);
1271         }
1272 
1273 //        private static class NotifWrapper
1274 //                implements WrapDynamicMBean, NotificationEmitter {
1275 //            private final DynamicMBean mbean;
1276 //
1277 //            NotifWrapper(DynamicMBean mbean) {
1278 //                this.mbean = mbean;
1279 //            }
1280 //
1281 //            public Object getAttribute(String attribute)
1282 //            throws AttributeNotFoundException, MBeanException, ReflectionException {
1283 //                return mbean.getAttribute(attribute);
1284 //            }
1285 //
1286 //            public void setAttribute(Attribute attribute)
1287 //            throws AttributeNotFoundException, InvalidAttributeValueException,
1288 //                    MBeanException, ReflectionException {
1289 //                mbean.setAttribute(attribute);
1290 //            }
1291 //
1292 //            public AttributeList getAttributes(String[] attributes) {
1293 //                return mbean.getAttributes(attributes);
1294 //            }
1295 //
1296 //            public AttributeList setAttributes(AttributeList attributes) {
1297 //                return mbean.setAttributes(attributes);
1298 //            }
1299 //
1300 //            public Object invoke(
1301 //                    String actionName, Object[] params, String[] signature)
1302 //                    throws MBeanException, ReflectionException {
1303 //                return mbean.invoke(actionName, params, signature);
1304 //            }
1305 //
1306 //            public MBeanInfo getMBeanInfo() {
1307 //                return mbean.getMBeanInfo();
1308 //            }
1309 //
1310 //            public void removeNotificationListener(
1311 //                    NotificationListener listener, NotificationFilter filter, Object handback)
1312 //            throws ListenerNotFoundException {
1313 //                ((NotificationEmitter) mbean).removeNotificationListener(
1314 //                        listener, filter, handback);
1315 //                // ClassCastException if MBean is not an emitter
1316 //            }
1317 //
1318 //            public void addNotificationListener(
1319 //                    NotificationListener listener, NotificationFilter filter, Object handback)
1320 //            throws IllegalArgumentException {
1321 //                ((NotificationBroadcaster) mbean).addNotificationListener(
1322 //                        listener, filter, handback);
1323 //            }
1324 //
1325 //            public void removeNotificationListener(NotificationListener listener)
1326 //            throws ListenerNotFoundException {
1327 //                ((NotificationBroadcaster) mbean).removeNotificationListener(listener);
1328 //            }
1329 //
1330 //            public MBeanNotificationInfo[] getNotificationInfo() {
1331 //                return ((NotificationBroadcaster) mbean).getNotificationInfo();
1332 //            }
1333 //
1334 //            public Object getWrappedMBean() {
1335 //                return getUserMBean(mbean);
1336 //            }
1337 //        }
1338 
1339         private static Object invokeSomething(
1340                 AccessibleObject ao, Object target, Object[] args)
1341         throws MBeanException, ReflectionException {
1342             try {
1343                 if (ao instanceof Method)
1344                     return ((Method) ao).invoke(target, args);
1345                 else
1346                     return ((Constructor) ao).newInstance(args);
1347             } catch (InvocationTargetException e) {
1348                 try {
1349                     throw e.getCause();
1350                 } catch (RuntimeException x) {
1351                     throw new RuntimeMBeanException(x);
1352                 } catch (Error x) {
1353                     throw new RuntimeErrorException(x);
1354                 } catch (Exception x) {
1355                     throw new MBeanException(x);
1356                 } catch (Throwable x) {
1357                     throw new RuntimeException(x); // neither Error nor Exception!
1358                 }
1359             } catch (Exception e) {
1360                 throw new ReflectionException(e);
1361             }
1362         }
1363 
1364         private static Object getUserMBean(DynamicMBean mbean) {
1365             if (mbean instanceof WrapDynamicMBean)
1366                 return ((WrapDynamicMBean) mbean).getWrappedMBean();
1367             return mbean;
1368         }
1369 
1370         private Object getUserMBean(ObjectName name)
1371         throws InstanceNotFoundException {
1372             return getUserMBean(getMBean(name));
1373         }
1374 
1375         private static final MBeanRegistration noRegistration =
1376                 new MBeanRegistration() {
1377             public ObjectName preRegister(MBeanServer server, ObjectName name) {
1378                 return name;
1379             }
1380 
1381             public void postRegister(Boolean registrationDone) {
1382             }
1383 
1384             public void preDeregister() throws Exception {
1385             }
1386 
1387             public void postDeregister() {
1388             }
1389         };
1390 
1391         private static MBeanRegistration mbeanRegistration(Object object) {
1392             if (object instanceof MBeanRegistration)
1393                 return (MBeanRegistration) object;
1394             else
1395                 return noRegistration;
1396         }
1397 
1398         private static <E> List<E> newList() {
1399             return new ArrayList<E>();
1400         }
1401 
1402         private static <K, V> Map<K, V> newMap() {
1403             return new HashMap<K, V>();
1404         }
1405 
1406         private static <E> Set<E> newSet() {
1407             return new HashSet<E>();
1408         }
1409     }
1410 }