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 }