1 /*
   2  * Copyright (c) 2006, 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  * @summary Test that we can create proxies which are NotificationEmitters.
  27  * @bug 6411747
  28  * @author Daniel Fuchs
  29  * @run clean NotificationEmitterProxy
  30  * @run build NotificationEmitterProxy
  31  * @run main NotificationEmitterProxy
  32  */
  33 
  34 import java.lang.management.ManagementFactory;
  35 
  36 import javax.management.*;
  37 import javax.management.remote.*;
  38 import javax.naming.NoPermissionException;
  39 
  40 public class NotificationEmitterProxy {
  41 
  42     public static class Counter {
  43         int count;
  44         public synchronized int count() {
  45             count++;
  46             notifyAll();
  47             return count;
  48         }
  49         public synchronized int peek() {
  50             return count;
  51         }
  52         public synchronized int waitfor(int max, long timeout)
  53             throws InterruptedException {
  54             final long start = System.currentTimeMillis();
  55             while (count < max && timeout > 0) {
  56                 final long rest = timeout -
  57                         (System.currentTimeMillis() - start);
  58                 if (rest <= 0) break;
  59                 wait(rest);
  60             }
  61             return count;
  62         }
  63     }
  64 
  65     public static class CounterListener
  66             implements NotificationListener {
  67         final private Counter counter;
  68         public CounterListener(Counter counter) {
  69             this.counter = counter;
  70         }
  71         public void handleNotification(Notification notification,
  72                         Object handback) {
  73                System.out.println("Received notif from " + handback +
  74                                   ":\n\t" + notification);
  75                counter.count();
  76         }
  77     }
  78 
  79     public static void main(String[] args) throws Exception {
  80         System.out.println("<<< Register for notification from a proxy");
  81 
  82         MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
  83         final ObjectName name = new ObjectName(":class=Simple");
  84 
  85         JMXServiceURL url = new JMXServiceURL("rmi", null, 0);
  86         final JMXConnectorServer server =
  87             JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);
  88         server.start();
  89         url = server.getAddress();
  90 
  91         final JMXConnector client = JMXConnectorFactory.connect(url);
  92 
  93         final Counter counter = new Counter();
  94         final CounterListener listener = new CounterListener(counter);
  95         final Counter mxcounter = new Counter();
  96         final CounterListener mxlistener = new CounterListener(mxcounter);
  97         final NotificationFilterSupport filter =
  98                 new NotificationFilterSupport();
  99         filter.enableType(MBeanServerNotification.REGISTRATION_NOTIFICATION);
 100         filter.enableType(MBeanServerNotification.UNREGISTRATION_NOTIFICATION);
 101         int registered = 0;
 102         try {
 103             final MBeanServerDelegateMBean delegate =
 104                 JMX.newMBeanProxy(client.getMBeanServerConnection(),
 105                        MBeanServerDelegate.DELEGATE_NAME,
 106                        MBeanServerDelegateMBean.class,
 107                        true);
 108 
 109             NotificationEmitter emitter = (NotificationEmitter)delegate;
 110             emitter.addNotificationListener(listener,filter,"JMX.newMBeanProxy");
 111         } catch (Exception x) {
 112             throw new RuntimeException("Failed to register listener with "+
 113                     " JMX.newMBeanProxy: " + x, x);
 114         }
 115 
 116         try {
 117             final MBeanServerDelegateMBean delegate =
 118                 MBeanServerInvocationHandler.newProxyInstance(mbs,
 119                        MBeanServerDelegate.DELEGATE_NAME,
 120                        MBeanServerDelegateMBean.class,
 121                        true);
 122 
 123             NotificationEmitter emitter = (NotificationEmitter)delegate;
 124             emitter.addNotificationListener(listener,filter,
 125                     "MBeanServerInvocationHandler.newProxyInstance");
 126         } catch (Exception x) {
 127             throw new RuntimeException("Failed to register listener with "+
 128                     " MBeanServerInvocationHandler.newProxyInstance: " + x, x);
 129         }
 130 
 131         System.out.println("<<< Register an MBean.");
 132 
 133         final Simple simple = new Simple();
 134         mbs.registerMBean(simple, name);
 135         registered++;
 136 
 137         SimpleMXBean simple0 =
 138            JMX.newMXBeanProxy(client.getMBeanServerConnection(),
 139                               name,
 140                               SimpleMXBean.class,
 141                               true);
 142 
 143         SimpleMXBean simple1 =
 144             JMX.newMXBeanProxy(mbs,
 145                                name,
 146                                SimpleMXBean.class,
 147                                false);
 148 
 149         final int expected = 2*registered;
 150         final int reg = counter.waitfor(expected,3000);
 151         if (reg != expected)
 152             throw new RuntimeException("Bad notification count: " + reg +
 153                     ", expected " +expected);
 154         System.out.println("Received expected "+reg+
 155                 " notifs after registerMBean");
 156 
 157         ((NotificationEmitter)simple0)
 158             .addNotificationListener(mxlistener,null,name);
 159         simple1.equals("Are you a Wombat?");
 160         final int mxnotifs = mxcounter.waitfor(1,3000);
 161         if (mxnotifs != 1)
 162              throw new RuntimeException("Bad MXBean notification count: " +
 163                      mxnotifs);
 164         System.out.println("Received expected "+mxnotifs+
 165                 " notifs from MXBean");
 166 
 167         mbs.unregisterMBean(name);
 168         final int unreg = counter.waitfor(expected+reg,3000);
 169         if (unreg != (expected+reg))
 170             throw new RuntimeException("Bad notification count: " + unreg +
 171                     ", expected " +expected+reg);
 172         System.out.println("Received expected "+(unreg-reg)+
 173                 " notifs after unregisterMBean");
 174         System.out.println("Total notifs received: " + unreg);
 175 
 176 
 177     }
 178 
 179     public static interface Simplest {
 180 
 181     }
 182 
 183     public static interface SimpleMXBean extends Simplest {
 184         public String equals(String x);
 185     }
 186 
 187     private static class Simple extends NotificationBroadcasterSupport
 188             implements SimpleMXBean {
 189         public static final String NOTIF_TYPE = "simple.equals";
 190         private static long seq=0;
 191         private static synchronized long seq() { return ++seq; };
 192         public String equals(String x) {
 193             sendNotification(new Notification(NOTIF_TYPE,this,seq(),x));
 194             return x;
 195         }
 196 
 197     }
 198 
 199 
 200 
 201  }