1/*
2 * Copyright (c) 2003, 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
24/*
25 * @test
26 * @bug 4940957 8025205
27 * @key intermittent
28 * @summary Tests behaviour when connections break
29 * @author Eamonn McManus
30 *
31 * @run clean BrokenConnectionTest
32 * @run build BrokenConnectionTest
33 * @run main BrokenConnectionTest
34 */
35
36import java.io.*;
37import java.lang.reflect.*;
38import java.nio.channels.ServerSocketChannel;
39import java.net.*;
40import java.rmi.server.*;
41import java.util.*;
42
43import java.rmi.UnmarshalException;
44
45import javax.management.*;
46import javax.management.remote.*;
47import javax.management.remote.rmi.*;
48
49// resolve ambiguity
50import java.lang.reflect.Proxy;
51
52public class BrokenConnectionTest {
53    private static ObjectName DELEGATE_NAME;
54    private static ObjectName BREAK_NAME;
55    private static ObjectName LISTENER_NAME;
56    public static void main(String[] args) throws Exception {
57        DELEGATE_NAME =
58            new ObjectName("JMImplementation:type=MBeanServerDelegate");
59        BREAK_NAME = new ObjectName("test:type=Break");
60        LISTENER_NAME = new ObjectName("test:type=Listener");
61
62        String failed = "";
63
64        final String[] protos = {"rmi", "jmxmp"};
65
66        for (int i = 0; i < protos.length; i++) {
67            final String proto = protos[i];
68            System.out.println();
69            System.out.println("------- Testing for " + proto + " -------");
70            try {
71                if (!test(proto))
72                    failed += " " + proto;
73            } catch (Exception e) {
74                System.out.println("FAILED WITH EXCEPTION:");
75                e.printStackTrace(System.out);
76                failed += " " + proto;
77            }
78        }
79
80        System.out.println();
81
82        if (failed.length() > 0) {
83            System.out.println("TEST FAILED FOR:" + failed);
84            System.exit(1);
85        }
86
87        System.out.println("Test passed");
88    }
89
90    private static boolean test(String proto) throws Exception {
91        if (proto.equals("rmi"))
92            return rmiTest();
93        else if (proto.equals("jmxmp"))
94            return jmxmpTest();
95        else
96            throw new AssertionError(proto);
97    }
98
99    private static interface Breakable {
100        public JMXConnectorServer createConnectorServer(MBeanServer mbs)
101                throws IOException;
102        public void setBroken(boolean broken);
103    }
104
105    private static interface TestAction {
106        public String toString();
107        public boolean test(MBeanServerConnection mbsc, Breakable breakable)
108                throws Exception;
109    }
110
111    private static abstract class Operation implements TestAction {
112        public String toString() {
113            return opName() + ", break, " + opName();
114        }
115        void init(MBeanServerConnection mbsc) throws Exception {}
116        abstract String opName();
117        public boolean test(MBeanServerConnection mbsc, Breakable breakable)
118                throws Exception {
119            init(mbsc);
120            operation(mbsc);
121            System.out.println("Client ran " + opName() + " OK");
122            breakable.setBroken(true);
123            System.out.println("Broke connection, run " + opName() + " again");
124            try {
125                operation(mbsc);
126                System.out.println("TEST FAILED: " + opName() +
127                                   " should fail!");
128                return false;
129            } catch (IOException e) {
130                System.out.println("Got IOException as expected (" + e + ")");
131            }
132            return true;
133        }
134        abstract void operation(MBeanServerConnection mbsc) throws Exception;
135    }
136
137    private static TestAction[] tests = {
138        new Operation() {
139            String opName() {
140                return "getDefaultDomain";
141            }
142            void operation(MBeanServerConnection mbsc) throws Exception {
143                mbsc.getDefaultDomain();
144            }
145        },
146        new Operation() {
147            String opName() {
148                return "addNotificationListener(NL)";
149            }
150            void operation(MBeanServerConnection mbsc) throws Exception {
151                mbsc.addNotificationListener(DELEGATE_NAME,
152                                             new CountListener(), null, null);
153            }
154        },
155        new Operation() {
156            String opName() {
157                return "addNotificationListener(MB)";
158            }
159            void init(MBeanServerConnection mbsc) throws Exception {
160                mbsc.createMBean(CountListener.class.getName(),
161                                 LISTENER_NAME);
162            }
163            void operation(MBeanServerConnection mbsc) throws Exception {
164                mbsc.addNotificationListener(DELEGATE_NAME, LISTENER_NAME,
165                                             null, null);
166            }
167        },
168        new Operation() {
169            String opName() {
170                return "removeNotificationListener(NL)";
171            }
172            void init(MBeanServerConnection mbsc) throws Exception {
173                for (int i = 0; i < NLISTENERS; i++) {
174                    NotificationListener l = new CountListener();
175                    mbsc.addNotificationListener(DELEGATE_NAME, l, null, null);
176                    listeners.add(l);
177                }
178            }
179            void operation(MBeanServerConnection mbsc) throws Exception {
180                NotificationListener l = (NotificationListener)
181                    listeners.remove(0);
182                mbsc.removeNotificationListener(DELEGATE_NAME, l, null, null);
183            }
184            static final int NLISTENERS = 2;
185            List/*<NotificationListener>*/ listeners = new ArrayList();
186        },
187        new Operation() {
188            String opName() {
189                return "removeNotificationListener(MB)";
190            }
191            void init(MBeanServerConnection mbsc) throws Exception {
192                mbsc.createMBean(CountListener.class.getName(),
193                                 LISTENER_NAME);
194            }
195            void operation(MBeanServerConnection mbsc) throws Exception {
196                try {
197                    mbsc.removeNotificationListener(DELEGATE_NAME,
198                                                    LISTENER_NAME,
199                                                    null, null);
200                    throw new IllegalArgumentException("removeNL should not " +
201                                                       "have worked!");
202                } catch (ListenerNotFoundException e) {
203                    // normal - there isn't one!
204                }
205            }
206        },
207        new Operation() {
208            String opName() {
209                return "createMBean(className, objectName)";
210            }
211            void operation(MBeanServerConnection mbsc) throws Exception {
212                ObjectName name =
213                    new ObjectName("test:instance=" + nextInstance());
214                mbsc.createMBean(CountListener.class.getName(), name);
215            }
216            private synchronized int nextInstance() {
217                return ++instance;
218            }
219            private int instance;
220        },
221        new Operation() {
222            String opName() {
223                return "getAttribute";
224            }
225            void operation(MBeanServerConnection mbsc) throws Exception {
226                mbsc.getAttribute(DELEGATE_NAME, "ImplementationName");
227            }
228        },
229        new Operation() {
230            String opName() {
231                return "getAttributes";
232            }
233            void operation(MBeanServerConnection mbsc) throws Exception {
234                mbsc.getAttribute(DELEGATE_NAME, "ImplementationName");
235            }
236        },
237        new Operation() {
238            String opName() {
239                return "getDomains";
240            }
241            void operation(MBeanServerConnection mbsc) throws Exception {
242                mbsc.getDomains();
243            }
244        },
245        new Operation() {
246            String opName() {
247                return "getMBeanCount";
248            }
249            void operation(MBeanServerConnection mbsc) throws Exception {
250                mbsc.getMBeanCount();
251            }
252        },
253        new Operation() {
254            String opName() {
255                return "getMBeanInfo";
256            }
257            void operation(MBeanServerConnection mbsc) throws Exception {
258                mbsc.getMBeanInfo(DELEGATE_NAME);
259            }
260        },
261        new Operation() {
262            String opName() {
263                return "getObjectInstance";
264            }
265            void operation(MBeanServerConnection mbsc) throws Exception {
266                mbsc.getObjectInstance(DELEGATE_NAME);
267            }
268        },
269        new Operation() {
270            String opName() {
271                return "invoke";
272            }
273            void operation(MBeanServerConnection mbsc) throws Exception {
274                mbsc.invoke(BREAK_NAME, "doNothing", new Object[0],
275                            new String[0]);
276            }
277        },
278        new Operation() {
279            String opName() {
280                return "isInstanceOf";
281            }
282            void operation(MBeanServerConnection mbsc) throws Exception {
283                mbsc.isInstanceOf(DELEGATE_NAME, "whatsit");
284            }
285        },
286        new Operation() {
287            String opName() {
288                return "isRegistered";
289            }
290            void operation(MBeanServerConnection mbsc) throws Exception {
291                mbsc.isRegistered(DELEGATE_NAME);
292            }
293        },
294        new Operation() {
295            String opName() {
296                return "queryMBeans";
297            }
298            void operation(MBeanServerConnection mbsc) throws Exception {
299                mbsc.queryMBeans(new ObjectName("*:*"), null);
300            }
301        },
302        new Operation() {
303            String opName() {
304                return "queryNames";
305            }
306            void operation(MBeanServerConnection mbsc) throws Exception {
307                mbsc.queryNames(new ObjectName("*:*"), null);
308            }
309        },
310        new Operation() {
311            String opName() {
312                return "setAttribute";
313            }
314            void operation(MBeanServerConnection mbsc) throws Exception {
315                mbsc.setAttribute(BREAK_NAME,
316                                  new Attribute("Nothing", null));
317            }
318        },
319        new Operation() {
320            String opName() {
321                return "setAttributes";
322            }
323            void operation(MBeanServerConnection mbsc) throws Exception {
324                AttributeList attrs = new AttributeList();
325                attrs.add(new Attribute("Nothing", null));
326                mbsc.setAttributes(BREAK_NAME, attrs);
327            }
328        },
329        new Operation() {
330            String opName() {
331                return "unregisterMBean";
332            }
333            void init(MBeanServerConnection mbsc) throws Exception {
334                for (int i = 0; i < NBEANS; i++) {
335                    ObjectName name = new ObjectName("test:instance=" + i);
336                    mbsc.createMBean(CountListener.class.getName(), name);
337                    names.add(name);
338                }
339            }
340            void operation(MBeanServerConnection mbsc) throws Exception {
341                ObjectName name = (ObjectName) names.remove(0);
342                mbsc.unregisterMBean(name);
343            }
344            private static final int NBEANS = 2;
345            private List/*<ObjectName>*/ names = new ArrayList();
346        },
347        new TestAction() {
348            public String toString() {
349                return "break during send for setAttribute";
350            }
351            public boolean test(MBeanServerConnection mbsc,
352                                Breakable breakable) throws Exception {
353                Attribute attr =
354                    new Attribute("Break", new BreakWhenSerialized(breakable));
355                try {
356                    mbsc.setAttribute(BREAK_NAME, attr);
357                    System.out.println("TEST FAILED: setAttribute with " +
358                                       "BreakWhenSerializable did not fail!");
359                    return false;
360                } catch (IOException e) {
361                    System.out.println("Got IOException as expected: " + e);
362
363                    return true;
364                }
365            }
366        },
367        new TestAction() {
368            public String toString() {
369                return "break during receive for getAttribute";
370            }
371            public boolean test(MBeanServerConnection mbsc,
372                                Breakable breakable) throws Exception {
373                try {
374                    mbsc.getAttribute(BREAK_NAME, "Break");
375                    System.out.println("TEST FAILED: getAttribute of " +
376                                       "BreakWhenSerializable did not fail!");
377                    return false;
378                } catch (IOException e) {
379                    System.out.println("Got IOException as expected: " + e);
380
381                    return true;
382                }
383            }
384        },
385    };
386
387    public static interface BreakMBean {
388        public BreakWhenSerialized getBreak();
389        public void setBreak(BreakWhenSerialized x);
390//      public void breakOnNotify();
391        public void doNothing();
392        public void setNothing(Object x);
393    }
394
395    public static class Break
396            extends NotificationBroadcasterSupport implements BreakMBean {
397        public Break(Breakable breakable) {
398            this.breakable = breakable;
399        }
400
401        public BreakWhenSerialized getBreak() {
402            return new BreakWhenSerialized(breakable);
403        }
404
405        public void setBreak(BreakWhenSerialized x) {
406            throw new IllegalArgumentException("setBreak worked but " +
407                                               "should not!");
408        }
409
410//      public void breakOnNotify() {
411//          Notification broken = new Notification("type", "source", 0L);
412//          broken.setUserData(new BreakWhenSerialized(breakable));
413//          sendNotification(broken);
414//      }
415
416        public void doNothing() {}
417
418        public void setNothing(Object x) {}
419
420        private final Breakable breakable;
421    }
422
423    private static class BreakWhenSerialized implements Serializable {
424        BreakWhenSerialized(Breakable breakable) {
425            this.breakable = breakable;
426        }
427
428        private void writeObject(ObjectOutputStream out) throws IOException {
429            breakable.setBroken(true);
430        }
431
432        private final transient Breakable breakable;
433    }
434
435    private static class FailureNotificationFilter
436            implements NotificationFilter {
437        public boolean isNotificationEnabled(Notification n) {
438            System.out.println("Filter: " + n + " (" + n.getType() + ")");
439
440            final String failed =
441                JMXConnectionNotification.FAILED;
442            return (n instanceof JMXConnectionNotification
443                    && n.getType().equals(JMXConnectionNotification.FAILED));
444        }
445    }
446
447    public static interface CountListenerMBean {}
448
449    public static class CountListener
450            implements CountListenerMBean, NotificationListener {
451        public synchronized void handleNotification(Notification n, Object h) {
452            count++;
453        }
454
455        int count;
456    }
457
458    private static boolean test(Breakable breakable)
459            throws Exception {
460        boolean alreadyMissedFailureNotif = false;
461        String failed = "";
462        for (int i = 1; i <= tests.length; i++) {
463            TestAction ta = tests[i - 1];
464            System.out.println();
465            System.out.println("Test " + i + ": " + ta);
466            MBeanServer mbs = MBeanServerFactory.newMBeanServer();
467            Break breakMBean = new Break(breakable);
468            mbs.registerMBean(breakMBean, BREAK_NAME);
469            JMXConnectorServer cs = breakable.createConnectorServer(mbs);
470            System.out.println("Created and started connector server");
471            JMXServiceURL addr = cs.getAddress();
472            JMXConnector cc = JMXConnectorFactory.connect(addr);
473            CountListener failureListener = new CountListener();
474            NotificationFilter failureFilter = new FailureNotificationFilter();
475            cc.addConnectionNotificationListener(failureListener,
476                                                 failureFilter,
477                                                 null);
478            MBeanServerConnection mbsc = cc.getMBeanServerConnection();
479            System.out.println("Client connected OK");
480            boolean thisok = ta.test(mbsc, breakable);
481
482            try {
483                System.out.println("Stopping server");
484                cs.stop();
485            } catch (IOException e) {
486                System.out.println("Ignoring exception on stop: " + e);
487            }
488            if (thisok) {
489                System.out.println("Waiting for failure notif");
490                // pass or test timeout. see 8025205
491                do {
492                    Thread.sleep(100);
493                } while (failureListener.count < 1);
494
495                Thread.sleep(1000); // if more notif coming ...
496                if (failureListener.count > 1) {
497                    System.out.println("Got too many failure notifs: " +
498                                       failureListener.count);
499                    thisok = false;
500                }
501            }
502            if (!thisok)
503                failed = failed + " " + i;
504            System.out.println("Test " + i + (thisok ? " passed" : " FAILED"));
505            breakable.setBroken(false);
506        }
507        if (failed.equals(""))
508            return true;
509        else {
510            System.out.println("FAILING CASES:" + failed);
511            return false;
512        }
513    }
514
515    private static class BreakableRMI implements Breakable {
516        public JMXConnectorServer createConnectorServer(MBeanServer mbs)
517                throws IOException {
518            JMXServiceURL url = new JMXServiceURL("rmi", null, 0);
519            Map env = new HashMap();
520            env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE,
521                    brssf);
522            JMXConnectorServer cs =
523                JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);
524            cs.start();
525            return cs;
526        }
527
528        public void setBroken(boolean broken) {
529            brssf.setBroken(broken);
530        }
531
532        private final BreakableRMIServerSocketFactory brssf =
533            new BreakableRMIServerSocketFactory();
534    }
535
536    private static boolean rmiTest() throws Exception {
537        System.out.println("RMI broken connection test");
538        Breakable breakable = new BreakableRMI();
539        return test(breakable);
540    }
541
542    private static class BreakableRMIServerSocketFactory
543            implements RMIServerSocketFactory {
544
545        public synchronized ServerSocket createServerSocket(int port)
546                throws IOException {
547            if (broken)
548                throw new IOException("ServerSocket has been broken");
549            BreakableServerSocket bss = new BreakableServerSocket(port);
550            bssList.add(bss);
551            return bss;
552        }
553
554        synchronized void setBroken(boolean broken) {
555            this.broken = broken;
556//          System.out.println("BRSSF.setBroken(" + broken + ")");
557            for (Iterator it = bssList.iterator(); it.hasNext(); ) {
558                BreakableServerSocket bss = (BreakableServerSocket) it.next();
559//              System.out.println((broken ? "" : "un") + "break " + bss);
560                bss.setBroken(broken);
561            }
562        }
563
564        private final List/*<BreakableServerSocket>*/ bssList =
565            new ArrayList();
566        private boolean broken = false;
567    }
568
569    private static class BreakableJMXMP implements Breakable {
570        BreakableJMXMP() throws IOException {
571            bss = new BreakableServerSocket(0);
572        }
573
574        public JMXConnectorServer createConnectorServer(MBeanServer mbs)
575                throws IOException {
576            try {
577                InvocationHandler scsih =
578                    new SocketConnectionServerInvocationHandler(bss);
579                final String mcs =
580                    "javax.management.remote.generic.MessageConnectionServer";
581                final Class messageConnectionServerClass = Class.forName(mcs);
582                final Class[] proxyInterfaces = {messageConnectionServerClass};
583                Object socketConnectionServer =
584                    Proxy.newProxyInstance(this.getClass().getClassLoader(),
585                                           proxyInterfaces,
586                                           scsih);
587                Map env = new HashMap();
588                env.put("jmx.remote.message.connection.server",
589                        socketConnectionServer);
590                final String gcs =
591                    "javax.management.remote.generic.GenericConnectorServer";
592                final Class genericConnectorServerClass = Class.forName(gcs);
593                final Class[] constrTypes = {Map.class, MBeanServer.class};
594                final Constructor constr =
595                    genericConnectorServerClass.getConstructor(constrTypes);
596                JMXConnectorServer cs = (JMXConnectorServer)
597                    constr.newInstance(new Object[] {env, mbs});
598                cs.start();
599                return cs;
600            } catch (Exception e) {
601                e.printStackTrace(System.out);
602                throw new AssertionError(e);
603            }
604        }
605
606        public void setBroken(boolean broken) {
607            bss.setBroken(broken);
608        }
609
610        private final BreakableServerSocket bss;
611    }
612
613    private static boolean jmxmpTest() throws Exception {
614        System.out.println("JMXMP broken connection test");
615        try {
616            Class.forName("javax.management.remote.generic.GenericConnector");
617        } catch (ClassNotFoundException e) {
618            System.out.println("Optional classes not present, skipping test");
619            return true;
620        }
621        Breakable breakable = new BreakableJMXMP();
622        return test(breakable);
623    }
624
625    private static class BreakableServerSocket extends ServerSocket {
626        BreakableServerSocket(int port) throws IOException {
627            super();
628            ss = new ServerSocket(port);
629        }
630
631        synchronized void setBroken(boolean broken) {
632            this.broken = broken;
633//          System.out.println("BSS.setBroken(" + broken + ")");
634            if (!broken)
635                return;
636            for (Iterator it = sList.iterator(); it.hasNext(); ) {
637                Socket s = (Socket) it.next();
638                try {
639//                  System.out.println("Break: " + s);
640                    s.close();
641                } catch (IOException e) {
642                    System.out.println("Unable to close socket: " + s +
643                                       ", ignoring (" + e + ")");
644                }
645                it.remove();
646            }
647        }
648
649        public void bind(SocketAddress endpoint) throws IOException {
650            ss.bind(endpoint);
651        }
652
653        public void bind(SocketAddress endpoint, int backlog)
654                throws IOException {
655            ss.bind(endpoint, backlog);
656        }
657
658        public InetAddress getInetAddress() {
659            return ss.getInetAddress();
660        }
661
662        public int getLocalPort() {
663            return ss.getLocalPort();
664        }
665
666        public SocketAddress getLocalSocketAddress() {
667            return ss.getLocalSocketAddress();
668        }
669
670        public Socket accept() throws IOException {
671//          System.out.println("BSS.accept");
672            Socket s = ss.accept();
673//          System.out.println("BSS.accept returned: " + s);
674            if (broken)
675                s.close();
676            else
677                sList.add(s);
678            return s;
679        }
680
681        public void close() throws IOException {
682            ss.close();
683        }
684
685        public ServerSocketChannel getChannel() {
686            return ss.getChannel();
687        }
688
689        public boolean isBound() {
690            return ss.isBound();
691        }
692
693        public boolean isClosed() {
694            return ss.isClosed();
695        }
696
697        public void setSoTimeout(int timeout) throws SocketException {
698            ss.setSoTimeout(timeout);
699        }
700
701        public int getSoTimeout() throws IOException {
702            return ss.getSoTimeout();
703        }
704
705        public void setReuseAddress(boolean on) throws SocketException {
706            ss.setReuseAddress(on);
707        }
708
709        public boolean getReuseAddress() throws SocketException {
710            return ss.getReuseAddress();
711        }
712
713        public String toString() {
714            return "BreakableServerSocket wrapping " + ss.toString();
715        }
716
717        public void setReceiveBufferSize (int size) throws SocketException {
718            ss.setReceiveBufferSize(size);
719        }
720
721        public int getReceiveBufferSize() throws SocketException {
722            return ss.getReceiveBufferSize();
723        }
724
725        private final ServerSocket ss;
726        private final List/*<Socket>*/ sList = new ArrayList();
727        private boolean broken = false;
728    }
729
730    /* We do a lot of messy reflection stuff here because we don't
731       want to reference the optional parts of the JMX Remote API in
732       an environment (J2SE) where they won't be present.  */
733
734    /* This class implements the logic that allows us to pretend that
735       we have a class that looks like this:
736       class SocketConnectionServer implements MessageConnectionServer {
737           public MessageConnection accept() throws IOException {...}
738           public JMXServiceURL getAddress() {...}
739           public void start(Map env) throws IOException {...}
740           public void stop() throws IOException {...}
741       }
742     */
743    private static class SocketConnectionServerInvocationHandler
744            implements InvocationHandler {
745        SocketConnectionServerInvocationHandler(ServerSocket ss) {
746            this.ss = ss;
747        }
748
749        public Object invoke(Object proxy, Method method, Object[] args)
750                throws Exception {
751            final String mname = method.getName();
752            try {
753                if (mname.equals("accept"))
754                    return accept();
755                else if (mname.equals("getAddress"))
756                    return getAddress();
757                else if (mname.equals("start"))
758                    start((Map) args[0]);
759                else if (mname.equals("stop"))
760                    stop();
761                else // probably a method inherited from Object
762                    return method.invoke(this, args);
763            } catch (InvocationTargetException ite) {
764                Throwable t = ite.getCause();
765                if (t instanceof IOException) {
766                    throw (IOException)t;
767                } else if (t instanceof RuntimeException) {
768                    throw (RuntimeException)t;
769                } else {
770                    throw ite;
771                }
772            }
773
774            return null;
775        }
776
777        private Object/*MessageConnection*/ accept() throws Exception {
778            System.out.println("SCSIH.accept()");
779            Socket s = ss.accept();
780            Class socketConnectionClass =
781                Class.forName("com.sun.jmx.remote.socket.SocketConnection");
782            Constructor constr =
783                socketConnectionClass.getConstructor(new Class[] {Socket.class});
784            return constr.newInstance(new Object[] {s});
785//          InvocationHandler scih = new SocketConnectionInvocationHandler(s);
786//          Class messageConnectionClass =
787//              Class.forName("javax.management.generic.MessageConnection");
788//          return Proxy.newProxyInstance(this.getClass().getClassLoader(),
789//                                        new Class[] {messageConnectionClass},
790//                                        scih);
791        }
792
793        private JMXServiceURL getAddress() throws Exception {
794            System.out.println("SCSIH.getAddress()");
795            return new JMXServiceURL("jmxmp", null, ss.getLocalPort());
796        }
797
798        private void start(Map env) throws IOException {
799            System.out.println("SCSIH.start(" + env + ")");
800        }
801
802        private void stop() throws IOException {
803            System.out.println("SCSIH.stop()");
804        }
805
806        private final ServerSocket ss;
807    }
808}
809