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 
main(String[] args)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;
call()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         }
run()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 
runTests( Callable<MBeanServerConnection> maker, Runnable breaker)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 {
value()220         Class<? extends Exception> value();
221     }
222 
223     public static interface BoringMBean {
getName()224         public String getName();
add(int x, int y)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 {
getName()233         public String getName() {
234             return "Jessica";
235         }
236 
add(int x, int y)237         public int add(int x, int y) {
238             return x + y;
239         }
240     }
241 
242     public static interface BoringNotifierMBean extends BoringMBean {
send()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 
addNotificationListener( NotificationListener listener, NotificationFilter filter, Object handback)251         public void addNotificationListener(
252                 NotificationListener listener, NotificationFilter filter, Object handback)
253         throws IllegalArgumentException {
254             nbs.addNotificationListener(listener, filter, handback);
255         }
256 
removeNotificationListener(NotificationListener listener)257         public void removeNotificationListener(NotificationListener listener)
258         throws ListenerNotFoundException {
259             nbs.removeNotificationListener(listener);
260         }
261 
getNotificationInfo()262         public MBeanNotificationInfo[] getNotificationInfo() {
263             return null;
264         }
265 
send()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;
handleNotification(Notification n, Object h)274         public void handleNotification(Notification n, Object h) {
275             if (h == null)
276                 h = 1;
277             count += (Integer) h;
278         }
waitForCount(int expect)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 
testBasic()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 
testPrintAttrs()323     private static void testPrintAttrs() throws Exception {
324         printAttrs(mbsc, null);
325     }
326 
testPlatformMBeanServer()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 
printAttrs( MBeanServerConnection mbsc1, Class<? extends Exception> expectX)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 
testJavaxManagementStandardMBean()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 
testConnector()383     private static void testConnector() throws Exception {
384     }
385 
386     public static class OldMBeanServerBuilder extends MBeanServerBuilder {
newMBeanServer( String defaultDomain, MBeanServer outer, MBeanServerDelegate delegate)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 
OldMBeanServer(String defaultDomain, MBeanServerDelegate delegate)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 
createMBean(String className, ObjectName name)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 
createMBean( String className, ObjectName name, ObjectName loaderName)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 
createMBean( String className, ObjectName name, Object[] params, String[] signature)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 
createMBean( String className, ObjectName name, ObjectName loaderName, Object[] params, String[] signature)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 
forbidJMImpl(ObjectName name)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 
registerMBean(Object object, ObjectName name)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 
unregisterMBean(ObjectName name)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 
getObjectInstance(ObjectName name)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 {
apply(ObjectName name)554             public boolean apply(ObjectName name) {
555                 return true;
556             }
557 
setMBeanServer(MBeanServer s)558             public void setMBeanServer(MBeanServer s) {}
559         }
560         private static final QueryExp trueQuery = new TrueQueryExp();
561 
queryMBeans(ObjectName name, QueryExp query)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 
queryNames(ObjectName name, QueryExp query)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 
isRegistered(ObjectName name)595         public boolean isRegistered(ObjectName name) {
596             return mbeans.containsKey(name);
597         }
598 
getMBeanCount()599         public Integer getMBeanCount() {
600             return mbeans.size();
601         }
602 
getAttribute(ObjectName name, String attribute)603         public Object getAttribute(ObjectName name, String attribute)
604         throws MBeanException, AttributeNotFoundException,
605                 InstanceNotFoundException, ReflectionException {
606             return getMBean(name).getAttribute(attribute);
607         }
608 
getAttributes(ObjectName name, String[] attributes)609         public AttributeList getAttributes(ObjectName name, String[] attributes)
610         throws InstanceNotFoundException, ReflectionException {
611             return getMBean(name).getAttributes(attributes);
612         }
613 
setAttribute(ObjectName name, Attribute attribute)614         public void setAttribute(ObjectName name, Attribute attribute)
615         throws InstanceNotFoundException, AttributeNotFoundException,
616                 InvalidAttributeValueException, MBeanException,
617                 ReflectionException {
618             getMBean(name).setAttribute(attribute);
619         }
620 
setAttributes( ObjectName name, AttributeList attributes)621         public AttributeList setAttributes(
622                 ObjectName name, AttributeList attributes)
623         throws InstanceNotFoundException, ReflectionException {
624             return getMBean(name).setAttributes(attributes);
625         }
626 
invoke( ObjectName name, String operationName, Object[] params, String[] signature)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 
getDefaultDomain()634         public String getDefaultDomain() {
635             return defaultDomain;
636         }
637 
getDomains()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
addNotificationListener( ObjectName name, NotificationListener listener, NotificationFilter filter, Object handback)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 
addNotificationListener( ObjectName name, ObjectName listener, NotificationFilter filter, Object handback)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 
removeNotificationListener( ObjectName name, ObjectName listener)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 
removeNotificationListener( ObjectName name, ObjectName listener, NotificationFilter filter, Object handback)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 
removeNotificationListener( ObjectName name, NotificationListener listener)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 
removeNotificationListener( ObjectName name, NotificationListener listener, NotificationFilter filter, Object handback)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 
getMBeanInfo(ObjectName name)704         public MBeanInfo getMBeanInfo(ObjectName name)
705         throws InstanceNotFoundException, IntrospectionException,
706                 ReflectionException {
707             return getMBean(name).getMBeanInfo();
708         }
709 
isInstanceOf(ObjectName name, String className)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 
instantiate(String className)726         public Object instantiate(String className)
727         throws ReflectionException, MBeanException {
728             return instantiate(className, null, null);
729         }
730 
instantiate(String className, ObjectName loaderName)731         public Object instantiate(String className, ObjectName loaderName)
732         throws ReflectionException, MBeanException, InstanceNotFoundException {
733             return instantiate(className, loaderName, null, null);
734         }
735 
instantiate( String className, Object[] params, String[] signature)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 
instantiate( String className, ObjectName loaderName, Object[] params, String[] signature)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
deserialize(ObjectName name, byte[] data)794         public ObjectInputStream deserialize(ObjectName name, byte[] data)
795         throws InstanceNotFoundException, OperationsException {
796             throw new UnsupportedOperationException();
797         }
798 
799         @Deprecated
deserialize(String className, byte[] data)800         public ObjectInputStream deserialize(String className, byte[] data)
801         throws OperationsException, ReflectionException {
802             throw new UnsupportedOperationException();
803         }
804 
805         @Deprecated
deserialize( String className, ObjectName loaderName, byte[] data)806         public ObjectInputStream deserialize(
807                 String className, ObjectName loaderName, byte[] data)
808         throws InstanceNotFoundException, OperationsException, ReflectionException {
809             throw new UnsupportedOperationException();
810         }
811 
getClassLoaderFor(ObjectName mbeanName)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 
getClassLoader(ObjectName loaderName)819         public ClassLoader getClassLoader(ObjectName loaderName)
820         throws InstanceNotFoundException {
821             return (ClassLoader) getMBean(loaderName);
822         }
823 
getClassLoaderRepository()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 
addLoader(ClassLoader loader)856             void addLoader(ClassLoader loader) {
857                 loaders.add(loader);
858             }
859 
removeLoader(ClassLoader loader)860             void removeLoader(ClassLoader loader) {
861                 if (!loaders.remove(loader))
862                     throw new RuntimeException("Loader was not in CLR!");
863             }
864 
loadClassWithout( ClassLoader exclude, String className)865             public Class<?> loadClassWithout(
866                     ClassLoader exclude, String className)
867                     throws ClassNotFoundException {
868                 return loadClassWithoutBefore(exclude, null, className);
869             }
870 
loadClassBefore(ClassLoader stop, String className)871             public Class<?> loadClassBefore(ClassLoader stop, String className)
872             throws ClassNotFoundException {
873                 return loadClassWithoutBefore(null, stop, className);
874             }
875 
loadClassWithoutBefore( ClassLoader exclude, ClassLoader stop, String className)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
findClass(String className)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 
IdentityListener(NotificationListener userListener)935             IdentityListener(NotificationListener userListener) {
936                 this.userListener = userListener;
937             }
938 
handleNotification( Notification notification, Object handback)939             public void handleNotification(
940                     Notification notification, Object handback) {
941                 userListener.handleNotification(notification, handback);
942             }
943 
944             @Override
equals(Object o)945             public boolean equals(Object o) {
946                 return (this == o);
947             }
948 
949             @Override
hashCode()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 
RewriteListener( ObjectName name, Object userMBean, NotificationListener userListener)960             RewriteListener(
961                     ObjectName name, Object userMBean,
962                     NotificationListener userListener) {
963                 this.name = name;
964                 this.userMBean = userMBean;
965                 this.userListener = userListener;
966             }
967 
handleNotification( Notification notification, Object handback)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 
wrappedListener( ObjectName name, Object userMBean, NotificationListener userListener)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 
getMBean(ObjectName name)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 {
getWrappedMBean()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 
StandardWrapper(Object std)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 
mbeanInterface(Class<?> c)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 
initMaps(Class<?> intf)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 
getAttribute(String attribute)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 
setAttribute(Attribute attribute)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 
getAttributes(String[] attributes)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 
setAttributes(AttributeList attributes)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 
invoke(String actionName, Object[] params, String[] signature)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 
getMBeanInfo()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 
invokeMethod(Method m, Object... args)1241             private Object invokeMethod(Method m, Object... args)
1242             throws MBeanException, ReflectionException {
1243                 return invokeSomething(m, std,args);
1244             }
1245 
preRegister(MBeanServer server, ObjectName name)1246             public ObjectName preRegister(MBeanServer server, ObjectName name)
1247             throws Exception {
1248                 return mbeanRegistration(std).preRegister(server, name);
1249             }
1250 
postRegister(Boolean registrationDone)1251             public void postRegister(Boolean registrationDone) {
1252                 mbeanRegistration(std).postRegister(registrationDone);
1253             }
1254 
preDeregister()1255             public void preDeregister() throws Exception {
1256                 mbeanRegistration(std).preDeregister();
1257             }
1258 
postDeregister()1259             public void postDeregister() {
1260                 mbeanRegistration(std).postDeregister();
1261             }
1262 
getWrappedMBean()1263             public Object getWrappedMBean() {
1264                 return std;
1265             }
1266         }
1267 
standardToDynamic(Object std)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 
invokeSomething( AccessibleObject ao, Object target, Object[] args)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 
getUserMBean(DynamicMBean mbean)1364         private static Object getUserMBean(DynamicMBean mbean) {
1365             if (mbean instanceof WrapDynamicMBean)
1366                 return ((WrapDynamicMBean) mbean).getWrappedMBean();
1367             return mbean;
1368         }
1369 
getUserMBean(ObjectName name)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 
mbeanRegistration(Object object)1391         private static MBeanRegistration mbeanRegistration(Object object) {
1392             if (object instanceof MBeanRegistration)
1393                 return (MBeanRegistration) object;
1394             else
1395                 return noRegistration;
1396         }
1397 
newList()1398         private static <E> List<E> newList() {
1399             return new ArrayList<E>();
1400         }
1401 
newMap()1402         private static <K, V> Map<K, V> newMap() {
1403             return new HashMap<K, V>();
1404         }
1405 
newSet()1406         private static <E> Set<E> newSet() {
1407             return new HashSet<E>();
1408         }
1409     }
1410 }
1411