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