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 7654321 27 * @summary Tests whether a listener receives notifs emitted before the 28 * listener is registered. 29 * @author Shanliang JIANG 30 * @modules java.management.rmi 31 * @run clean UnexpectedNotifTest 32 * @run build UnexpectedNotifTest 33 * @run main UnexpectedNotifTest 34 */ 35 36 import java.util.ArrayList; 37 import java.util.Collections; 38 import java.util.List; 39 import java.util.Map; 40 import javax.management.MBeanNotificationInfo; 41 import javax.management.MBeanServer; 42 import javax.management.MBeanServerConnection; 43 import javax.management.MBeanServerFactory; 44 import javax.management.Notification; 45 import javax.management.NotificationBroadcasterSupport; 46 import javax.management.NotificationListener; 47 import javax.management.ObjectName; 48 import javax.management.remote.JMXConnector; 49 import javax.management.remote.JMXConnectorFactory; 50 import javax.management.remote.JMXConnectorServer; 51 import javax.management.remote.JMXConnectorServerFactory; 52 import javax.management.remote.JMXServiceURL; 53 // 54 import javax.management.remote.rmi.RMIConnectorServer; 55 56 public class UnexpectedNotifTest { 57 58 public static void main(String[] args) throws Exception { 59 List<String> protos = new ArrayList<String>(); 60 protos.add("rmi"); 61 try { 62 Class.forName("javax.management.remote.jmxmp.JMXMPConnectorServer"); 63 protos.add("jmxmp"); 64 } catch (ClassNotFoundException e) { 65 // OK: JMXMP not present so don't test it. 66 } 67 for (String proto : protos) 68 test(proto); 69 } 70 71 private static void test(String proto) throws Exception { 72 System.out.println("Unexpected notifications test for protocol " + 73 proto); 74 MBeanServer mbs = null; 75 try { 76 // Create a MBeanServer 77 // 78 mbs = MBeanServerFactory.createMBeanServer(); 79 80 // Create a NotificationEmitter MBean 81 // 82 mbean = new ObjectName ("Default:name=NotificationEmitter"); 83 mbs.registerMBean(new NotificationEmitter(), mbean); 84 85 // Create a connector server 86 // 87 url = new JMXServiceURL("service:jmx:" + proto + "://"); 88 89 server = JMXConnectorServerFactory.newJMXConnectorServer(url, 90 null, 91 mbs); 92 93 mbs.registerMBean( 94 server, 95 new ObjectName("Default:name=ConnectorServer")); 96 97 server.start(); 98 99 url = server.getAddress(); 100 101 for (int j = 0; j < 2; j++) { 102 test(); 103 } 104 } finally { 105 // Stop server 106 // 107 server.stop(); 108 // Release the MBeanServer 109 // 110 MBeanServerFactory.releaseMBeanServer(mbs); 111 } 112 } 113 114 private static void test() throws Exception { 115 // Create client 116 // 117 JMXConnector connector = JMXConnectorFactory.connect(url); 118 MBeanServerConnection client = connector.getMBeanServerConnection(); 119 120 // Add listener at the client side 121 // 122 client.addNotificationListener(mbean, listener, null, null); 123 124 // Cleanup 125 // 126 receivedNotifs = 0; 127 128 // Ask to send notifs 129 // 130 Object[] params = new Object[] {new Integer(nb)}; 131 String[] signatures = new String[] {"java.lang.Integer"}; 132 133 client.invoke(mbean, "sendNotifications", params, signatures); 134 135 // Waiting... 136 // 137 synchronized (lock) { 138 for (int i = 0; i < 10; i++) { 139 if (receivedNotifs < nb) { 140 lock.wait(1000); 141 } 142 } 143 } 144 145 // Waiting again to ensure no more notifs 146 // 147 Thread.sleep(3000); 148 149 synchronized (lock) { 150 if (receivedNotifs != nb) { 151 throw new Exception("The client expected to receive " + 152 nb + " notifs, but got " + receivedNotifs); 153 } 154 } 155 156 // Remove listener 157 // 158 client.removeNotificationListener(mbean, listener); 159 160 connector.close(); 161 } 162 163 //-------------------------- 164 // private classes 165 //-------------------------- 166 167 private static class Listener implements NotificationListener { 168 public void handleNotification(Notification notif, Object handback) { 169 System.out.println("Received: " + notif + " (" + 170 notif.getSequenceNumber() + ")"); 171 synchronized(lock) { 172 if(++receivedNotifs == nb) { 173 lock.notifyAll(); 174 } else if (receivedNotifs > nb) { 175 System.out.println("The client expected to receive " + 176 nb + " notifs, but got at least " + 177 receivedNotifs); 178 System.exit(1); 179 } 180 } 181 } 182 } 183 184 public static class NotificationEmitter 185 extends NotificationBroadcasterSupport 186 implements NotificationEmitterMBean { 187 188 /** 189 * Returns a NotificationInfo object containing the name of the Java 190 * class of the notification and the notification types sent by this 191 * notification broadcaster. 192 */ 193 public MBeanNotificationInfo[] getNotificationInfo() { 194 195 MBeanNotificationInfo[] ntfInfoArray = new MBeanNotificationInfo[1]; 196 197 String[] ntfTypes = new String[1]; 198 ntfTypes[0] = myType; 199 200 ntfInfoArray[0] = new MBeanNotificationInfo( 201 ntfTypes, 202 "javax.management.Notification", 203 "Notifications sent by the NotificationEmitter"); 204 return ntfInfoArray; 205 } 206 207 /** 208 * Send a Notification object with the specified times. 209 * The sequence number will be from zero to times-1. 210 * 211 * @param nb The number of notifications to send 212 */ 213 public void sendNotifications(Integer nb) { 214 System.out.println("NotificationEmitter: asked to send " + 215 "notifications: " + nb); 216 217 Notification notif; 218 for (int i = 1; i <= nb.intValue(); i++) { 219 notif = new Notification(myType, this, ++seqno); 220 sendNotification(notif); 221 } 222 } 223 224 private String myType = "notification.my_notification"; 225 } 226 227 public interface NotificationEmitterMBean { 228 public void sendNotifications(Integer nb); 229 } 230 231 private static JMXConnectorServer server; 232 private static JMXServiceURL url; 233 private static ObjectName mbean; 234 private static NotificationListener listener = new Listener(); 235 236 private static int nb = 10; 237 private static int receivedNotifs = 0; 238 private static int[] lock = new int[0]; 239 private static volatile long seqno; 240 }