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