1 /*
   2  * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @bug 7654321
  27  * @summary Tests whether a listener receives notifs emitted before the
  28  * listener is registered.
  29  * @author Shanliang JIANG
  30  * @run clean UnexpectedNotifTest
  31  * @run build UnexpectedNotifTest
  32  * @run main UnexpectedNotifTest
  33  */
  34 
  35 import java.util.ArrayList;
  36 import java.util.Collections;
  37 import java.util.List;
  38 import java.util.Map;
  39 import javax.management.MBeanNotificationInfo;
  40 import javax.management.MBeanServer;
  41 import javax.management.MBeanServerConnection;
  42 import javax.management.MBeanServerFactory;
  43 import javax.management.Notification;
  44 import javax.management.NotificationBroadcasterSupport;
  45 import javax.management.NotificationListener;
  46 import javax.management.ObjectName;
  47 import javax.management.remote.JMXConnector;
  48 import javax.management.remote.JMXConnectorFactory;
  49 import javax.management.remote.JMXConnectorServer;
  50 import javax.management.remote.JMXConnectorServerFactory;
  51 import javax.management.remote.JMXServiceURL;
  52 //
  53 import javax.management.remote.rmi.RMIConnectorServer;
  54 
  55 public class UnexpectedNotifTest {
  56 
  57     public static void main(String[] args) throws Exception {
  58         List<String> protos = new ArrayList<String>();
  59         protos.add("rmi");
  60         try {
  61             Class.forName("javax.management.remote.jmxmp.JMXMPConnectorServer");
  62             protos.add("jmxmp");
  63         } catch (ClassNotFoundException e) {
  64             // OK: JMXMP not present so don't test it.
  65         }
  66         for (String proto : protos)
  67             test(proto);
  68     }
  69 
  70     private static void test(String proto) throws Exception {
  71         System.out.println("Unexpected notifications test for protocol " +
  72                            proto);
  73         MBeanServer mbs = null;
  74         try {
  75             // Create a MBeanServer
  76             //
  77             mbs = MBeanServerFactory.createMBeanServer();
  78 
  79             // Create a NotificationEmitter MBean
  80             //
  81             mbean = new ObjectName ("Default:name=NotificationEmitter");
  82             mbs.registerMBean(new NotificationEmitter(), mbean);
  83 
  84             // Create a connector server
  85             //
  86             url = new JMXServiceURL("service:jmx:" + proto + "://");
  87 
  88             server = JMXConnectorServerFactory.newJMXConnectorServer(url,
  89                                                                      null,
  90                                                                      mbs);
  91 
  92             mbs.registerMBean(
  93                         server,
  94                         new ObjectName("Default:name=ConnectorServer"));
  95 
  96             server.start();
  97 
  98             url = server.getAddress();
  99 
 100             for (int j = 0; j < 2; j++) {
 101                 test();
 102             }
 103         } finally {
 104             // Stop server
 105             //
 106             server.stop();
 107             // Release the MBeanServer
 108             //
 109             MBeanServerFactory.releaseMBeanServer(mbs);
 110         }
 111     }
 112 
 113     private static void test() throws Exception {
 114         // Create client
 115         //
 116         JMXConnector connector = JMXConnectorFactory.connect(url);
 117         MBeanServerConnection client = connector.getMBeanServerConnection();
 118 
 119         // Add listener at the client side
 120         //
 121         client.addNotificationListener(mbean, listener, null, null);
 122 
 123         // Cleanup
 124         //
 125         receivedNotifs = 0;
 126 
 127         // Ask to send notifs
 128         //
 129         Object[] params = new Object[] {new Integer(nb)};
 130         String[] signatures = new String[] {"java.lang.Integer"};
 131 
 132         client.invoke(mbean, "sendNotifications", params, signatures);
 133 
 134         // Waiting...
 135         //
 136         synchronized (lock) {
 137             for (int i = 0; i < 10; i++) {
 138                 if (receivedNotifs < nb) {
 139                     lock.wait(1000);
 140                 }
 141             }
 142         }
 143 
 144         // Waiting again to ensure no more notifs
 145         //
 146         Thread.sleep(3000);
 147 
 148         synchronized (lock) {
 149             if (receivedNotifs != nb) {
 150                 throw new Exception("The client expected to receive " +
 151                                     nb + " notifs, but got " + receivedNotifs);
 152             }
 153         }
 154 
 155         // Remove listener
 156         //
 157         client.removeNotificationListener(mbean, listener);
 158 
 159         connector.close();
 160     }
 161 
 162     //--------------------------
 163     // private classes
 164     //--------------------------
 165 
 166     private static class Listener implements NotificationListener {
 167         public void handleNotification(Notification notif, Object handback) {
 168             System.out.println("Received: " + notif + " (" +
 169                                notif.getSequenceNumber() + ")");
 170             synchronized(lock) {
 171                 if(++receivedNotifs == nb) {
 172                     lock.notifyAll();
 173                 } else if (receivedNotifs > nb) {
 174                     System.out.println("The client expected to receive " +
 175                                        nb + " notifs, but got at least " +
 176                                        receivedNotifs);
 177                     System.exit(1);
 178                 }
 179             }
 180         }
 181     }
 182 
 183     public static class NotificationEmitter
 184         extends NotificationBroadcasterSupport
 185         implements NotificationEmitterMBean {
 186 
 187         /**
 188          * Returns a NotificationInfo object containing the name of the Java
 189          * class of the notification and the notification types sent by this
 190          * notification broadcaster.
 191          */
 192         public MBeanNotificationInfo[] getNotificationInfo() {
 193 
 194             MBeanNotificationInfo[] ntfInfoArray = new MBeanNotificationInfo[1];
 195 
 196             String[] ntfTypes = new String[1];
 197             ntfTypes[0] = myType;
 198 
 199             ntfInfoArray[0] = new MBeanNotificationInfo(
 200                               ntfTypes,
 201                               "javax.management.Notification",
 202                               "Notifications sent by the NotificationEmitter");
 203             return ntfInfoArray;
 204         }
 205 
 206         /**
 207          * Send a Notification object with the specified times.
 208          * The sequence number will be from zero to times-1.
 209          *
 210          * @param nb The number of notifications to send
 211          */
 212         public void sendNotifications(Integer nb) {
 213             System.out.println("NotificationEmitter: asked to send " +
 214                                "notifications: " + nb);
 215 
 216             Notification notif;
 217             for (int i = 1; i <= nb.intValue(); i++) {
 218                 notif = new Notification(myType, this, ++seqno);
 219                 sendNotification(notif);
 220             }
 221         }
 222 
 223         private String myType = "notification.my_notification";
 224     }
 225 
 226     public interface NotificationEmitterMBean {
 227         public void sendNotifications(Integer nb);
 228     }
 229 
 230     private static JMXConnectorServer server;
 231     private static JMXServiceURL url;
 232     private static ObjectName mbean;
 233     private static NotificationListener listener = new Listener();
 234 
 235     private static int nb = 10;
 236     private static int receivedNotifs = 0;
 237     private static int[] lock = new int[0];
 238     private static volatile long seqno;
 239 }