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