1 /* 2 * Copyright (c) 2003, 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 * @bug 7654321 27 * @summary Tests the NotificationBuffer class. 28 * @author Eamonn McManus 29 * @run clean NotificationBufferTest 30 * @run build NotificationBufferTest NotificationSender NotificationSenderMBean 31 * @run main NotificationBufferTest 32 */ 33 34 import java.util.Arrays; 35 import java.util.Collections; 36 import java.util.HashSet; 37 import java.util.List; 38 import java.util.Set; 39 import java.util.HashMap; 40 41 import javax.management.MBeanServer; 42 import javax.management.MBeanServerFactory; 43 import javax.management.MBeanServerInvocationHandler; 44 import javax.management.MBeanServerNotification; 45 import javax.management.Notification; 46 import javax.management.NotificationFilter; 47 import javax.management.NotificationFilterSupport; 48 import javax.management.ObjectName; 49 import javax.management.loading.MLet; 50 51 import javax.management.remote.NotificationResult; 52 import javax.management.remote.TargetedNotification; 53 54 import com.sun.jmx.remote.internal.ArrayNotificationBuffer; 55 import com.sun.jmx.remote.internal.NotificationBufferFilter; 56 import com.sun.jmx.remote.internal.NotificationBuffer; 57 58 public class NotificationBufferTest { 59 60 public static void main(String[] args) { 61 // System.setProperty("java.util.logging.config.file", 62 // "../../../../logging.properties"); 63 // // we are in <workspace>/build/test/JTwork/scratch 64 try { 65 // java.util.logging.LogManager.getLogManager().readConfiguration(); 66 boolean ok = test(); 67 if (ok) { 68 System.out.println("Test completed"); 69 return; 70 } else { 71 System.out.println("Test failed!"); 72 System.exit(1); 73 } 74 } catch (Exception e) { 75 System.err.println("Unexpected exception: " + e); 76 e.printStackTrace(); 77 System.exit(1); 78 } 79 } 80 81 private static boolean test() throws Exception { 82 MBeanServer mbs = MBeanServerFactory.createMBeanServer(); 83 84 Integer queuesize = new Integer(10); 85 HashMap env = new HashMap(); 86 env.put(com.sun.jmx.remote.util.EnvHelp.BUFFER_SIZE_PROPERTY, queuesize); 87 final NotificationBuffer nb = 88 ArrayNotificationBuffer.getNotificationBuffer(mbs, env); 89 90 final ObjectName senderName = new ObjectName("dom:type=sender"); 91 final ObjectName wildcardName = new ObjectName("*:*"); 92 final String notifType = 93 MBeanServerNotification.REGISTRATION_NOTIFICATION; 94 95 Integer allListenerId = new Integer(99); 96 NotificationBufferFilter allListenerFilter = 97 makeFilter(allListenerId, wildcardName, null); 98 NotificationFilterSupport regFilter = new NotificationFilterSupport(); 99 regFilter.enableType(notifType); 100 101 // Get initial sequence number 102 NotificationResult nr = 103 nb.fetchNotifications(allListenerFilter, 0, 0L, 0); 104 int nnotifs = nr.getTargetedNotifications().length; 105 if (nnotifs > 0) { 106 System.out.println("Expected 0 notifs for initial fetch, " + 107 "got " + nnotifs); 108 return false; 109 } 110 System.out.println("Got 0 notifs for initial fetch, OK"); 111 112 long earliest = nr.getEarliestSequenceNumber(); 113 long next = nr.getNextSequenceNumber(); 114 if (earliest != next) { 115 System.out.println("Expected earliest==next in initial fetch, " + 116 "earliest=" + earliest + "; next=" + next); 117 return false; 118 } 119 System.out.println("Got earliest==next in initial fetch, OK"); 120 121 mbs.createMBean(MLet.class.getName(), null); 122 mbs.createMBean(NotificationSender.class.getName(), senderName); 123 124 NotificationSenderMBean sender = (NotificationSenderMBean) 125 MBeanServerInvocationHandler.newProxyInstance(mbs, 126 senderName, 127 NotificationSenderMBean.class, 128 false); 129 130 /* We test here that MBeans already present when the 131 NotificationBuffer was created get a listener for the 132 buffer, as do MBeans created later. The 133 MBeanServerDelegate was already present, while the 134 NotificationSender was created later. */ 135 136 // Check that the NotificationSender does indeed have a listener 137 /* Note we are dependent on the specifics of our JMX 138 implementation here. There is no guarantee that the MBean 139 creation listeners will have run to completion when 140 creation of the MBean returns. */ 141 int nlisteners = sender.getListenerCount(); 142 if (nlisteners != 1) { 143 System.out.println("Notification sender should have 1 listener, " + 144 "has " + nlisteners); 145 return false; 146 } 147 System.out.println("Notification sender has 1 listener, OK"); 148 149 // Now we should see two creation notifications 150 nr = nb.fetchNotifications(allListenerFilter, next, 0L, 151 Integer.MAX_VALUE); 152 TargetedNotification[] tns = nr.getTargetedNotifications(); 153 if (tns.length != 2) { 154 System.out.println("Expected 2 notifs, got: " + 155 Arrays.asList(tns)); 156 return false; 157 } 158 if (!(tns[0].getNotification() instanceof MBeanServerNotification) 159 || !(tns[1].getNotification() instanceof MBeanServerNotification)) 160 { 161 System.out.println("Expected 2 MBeanServerNotifications, got: " + 162 Arrays.asList(tns)); 163 return false; 164 } 165 if (!tns[0].getListenerID().equals(tns[1].getListenerID()) 166 || !tns[0].getListenerID().equals(allListenerId)) { 167 System.out.println("Bad listener IDs: " + Arrays.asList(tns)); 168 return false; 169 } 170 System.out.println("Got 2 different MBeanServerNotifications, OK"); 171 172 // If we ask for max 1 notifs, we should only get one 173 nr = nb.fetchNotifications(allListenerFilter, next, 0L, 1); 174 tns = nr.getTargetedNotifications(); 175 if (tns.length != 1) { 176 System.out.println("Expected 1 notif, got: " + Arrays.asList(tns)); 177 return false; 178 } 179 TargetedNotification tn1 = tns[0]; 180 System.out.println("Got 1 notif when asked for 1, OK"); 181 182 // Now we should get the other one 183 nr = nb.fetchNotifications(allListenerFilter, nr.getNextSequenceNumber(), 184 0L, 1); 185 tns = nr.getTargetedNotifications(); 186 if (tns.length != 1) { 187 System.out.println("Expected 1 notif, got: " + Arrays.asList(tns)); 188 return false; 189 } 190 TargetedNotification tn2 = tns[0]; 191 System.out.println("Got 1 notif when asked for 1 again, OK"); 192 193 if (tn1.getNotification() == tn2.getNotification()) { 194 System.out.println("Returned same notif twice: " + tn1); 195 return false; 196 } 197 System.out.println("2 creation notifs are different, OK"); 198 199 // Now we should get none (timeout is 0) 200 long oldNext = nr.getNextSequenceNumber(); 201 nr = nb.fetchNotifications(allListenerFilter, oldNext, 0L, 202 Integer.MAX_VALUE); 203 tns = nr.getTargetedNotifications(); 204 if (tns.length != 0) { 205 System.out.println("Expected 0 notifs, got: " + 206 Arrays.asList(tns)); 207 return false; 208 } 209 System.out.println("Got 0 notifs with 0 timeout, OK"); 210 if (nr.getNextSequenceNumber() != oldNext) { 211 System.out.println("Sequence number changed: " + oldNext + " -> " + 212 nr.getNextSequenceNumber()); 213 return false; 214 } 215 System.out.println("Next seqno unchanged with 0 timeout, OK"); 216 217 // Check that timeouts work 218 long startTime = System.currentTimeMillis(); 219 nr = nb.fetchNotifications(allListenerFilter, oldNext, 250L, 220 Integer.MAX_VALUE); 221 tns = nr.getTargetedNotifications(); 222 if (tns.length != 0) { 223 System.out.println("Expected 0 notifs, got: " + 224 Arrays.asList(tns)); 225 return false; 226 } 227 long endTime = System.currentTimeMillis(); 228 long elapsed = endTime - startTime; 229 if (elapsed < 250L) { 230 System.out.println("Elapsed time shorter than timeout: " + 231 elapsed); 232 return false; 233 } 234 System.out.println("Timeout worked, OK"); 235 236 // Check that notification filtering works 237 NotificationFilter senderFilter = new NotificationFilter() { 238 public boolean isNotificationEnabled(Notification n) { 239 if (!(n instanceof MBeanServerNotification)) 240 return false; 241 MBeanServerNotification mbsn = (MBeanServerNotification) n; 242 return (mbsn.getMBeanName().equals(senderName)); 243 } 244 }; 245 Integer senderListenerId = new Integer(88); 246 NotificationBufferFilter senderListenerFilter = 247 makeFilter(senderListenerId, wildcardName, senderFilter); 248 nr = nb.fetchNotifications(senderListenerFilter, 0, 1000L, 249 Integer.MAX_VALUE); 250 tns = nr.getTargetedNotifications(); 251 if (tns.length != 1) { 252 System.out.println("Expected 1 notif, got: " + Arrays.asList(tns)); 253 return false; 254 } 255 MBeanServerNotification mbsn = 256 (MBeanServerNotification) tns[0].getNotification(); 257 if (!mbsn.getMBeanName().equals(senderName)) { 258 System.out.println("Expected notif with senderName, got: " + 259 mbsn + " (" + mbsn.getMBeanName() + ")"); 260 return false; 261 } 262 System.out.println("Successfully applied NotificationFilter, OK"); 263 264 // Now send 8 notifs to fill up our 10-element buffer 265 sender.sendNotifs("tiddly.pom", 8); 266 nr = nb.fetchNotifications(allListenerFilter, 0, 1000L, 267 Integer.MAX_VALUE); 268 tns = nr.getTargetedNotifications(); 269 if (tns.length != 10) { 270 System.out.println("Expected 10 notifs, got: " + 271 Arrays.asList(tns)); 272 return false; 273 } 274 System.out.println("Got full buffer of 10 notifications, OK"); 275 276 // Check that the 10 notifs are the ones we expected 277 for (int i = 0; i < 10; i++) { 278 String expected = 279 (i < 2) ? notifType : "tiddly.pom"; 280 String found = tns[i].getNotification().getType(); 281 if (!found.equals(expected)) { 282 System.out.println("Notif " + i + " bad type: expected <" + 283 expected + ">, found <" + found + ">"); 284 return false; 285 } 286 } 287 System.out.println("Notifs have right types, OK"); 288 289 // Check that ObjectName filtering works 290 NotificationBufferFilter senderNameFilter = 291 makeFilter(new Integer(66), senderName, null); 292 nr = nb.fetchNotifications(senderNameFilter, 0, 0L, 293 Integer.MAX_VALUE); 294 tns = nr.getTargetedNotifications(); 295 if (tns.length != 8) { 296 System.out.println("Bad result from ObjectName filtering: " + 297 Arrays.asList(tns)); 298 return false; 299 } 300 System.out.println("ObjectName filtering works, OK"); 301 302 // Send one more notif, which should cause the oldest one to drop 303 sender.sendNotifs("foo.bar", 1); 304 nr = nb.fetchNotifications(allListenerFilter, 0, 1000L, 305 Integer.MAX_VALUE); 306 if (nr.getEarliestSequenceNumber() <= earliest) { 307 System.out.println("Expected earliest to increase: " + 308 nr.getEarliestSequenceNumber() + " should be > " 309 + earliest); 310 return false; 311 } 312 System.out.println("Earliest notif dropped, OK"); 313 314 // Check that the 10 notifs are the ones we expected 315 tns = nr.getTargetedNotifications(); 316 for (int i = 0; i < 10; i++) { 317 String expected = 318 (i < 1) ? notifType 319 : (i < 9) ? "tiddly.pom" : "foo.bar"; 320 String found = tns[i].getNotification().getType(); 321 if (!found.equals(expected)) { 322 System.out.println("Notif " + i + " bad type: expected <" + 323 expected + ">, found <" + found + ">"); 324 return false; 325 } 326 } 327 System.out.println("Notifs have right types, OK"); 328 329 // Apply a filter that only selects the first notif, with max notifs 1, 330 // then check that it skipped past the others even though it already 331 // had its 1 notif 332 NotificationBufferFilter firstFilter = 333 makeFilter(new Integer(55), wildcardName, regFilter); 334 nr = nb.fetchNotifications(firstFilter, 0, 1000L, 1); 335 tns = nr.getTargetedNotifications(); 336 if (tns.length != 1 337 || !tns[0].getNotification().getType().equals(notifType)) { 338 System.out.println("Unexpected return from filtered call: " + 339 Arrays.asList(tns)); 340 return false; 341 } 342 nr = nb.fetchNotifications(allListenerFilter, nr.getNextSequenceNumber(), 343 0L, 1000); 344 tns = nr.getTargetedNotifications(); 345 if (tns.length != 0) { 346 System.out.println("Expected 0 notifs, got: " + 347 Arrays.asList(tns)); 348 return false; 349 } 350 351 // Create a second, larger buffer, which should share the same notifs 352 nr = nb.fetchNotifications(allListenerFilter, 0, 353 1000L, Integer.MAX_VALUE); 354 queuesize = new Integer(20); 355 env.put(com.sun.jmx.remote.util.EnvHelp.BUFFER_SIZE_PROPERTY, queuesize); 356 NotificationBuffer nb2 = 357 ArrayNotificationBuffer.getNotificationBuffer(mbs, env); 358 NotificationResult nr2 = 359 nb2.fetchNotifications(allListenerFilter, 0, 360 1000L, Integer.MAX_VALUE); 361 if (nr.getEarliestSequenceNumber() != nr2.getEarliestSequenceNumber() 362 || nr.getNextSequenceNumber() != nr2.getNextSequenceNumber() 363 || !sameTargetedNotifs(nr.getTargetedNotifications(), 364 nr2.getTargetedNotifications())) 365 return false; 366 System.out.println("Adding second buffer preserved notif list, OK"); 367 368 // Check that the capacity is now 20 369 sender.sendNotifs("propter.hoc", 10); 370 nr2 = nb2.fetchNotifications(allListenerFilter, 0, 371 1000L, Integer.MAX_VALUE); 372 if (nr.getEarliestSequenceNumber() != 373 nr2.getEarliestSequenceNumber()) { 374 System.out.println("Earliest seq number changed after notifs " + 375 "that should have fit"); 376 return false; 377 } 378 TargetedNotification[] tns2 = new TargetedNotification[10]; 379 Arrays.asList(nr2.getTargetedNotifications()).subList(0, 10).toArray(tns2); 380 if (!sameTargetedNotifs(nr.getTargetedNotifications(), tns2)) { 381 System.out.println("Early notifs changed after notifs " + 382 "that should have fit"); 383 return false; 384 } 385 System.out.println("New notifications fit in now-larger buffer, OK"); 386 387 // Drop the second buffer and check that the capacity shrinks 388 nb2.dispose(); 389 NotificationResult nr3 = 390 nb.fetchNotifications(allListenerFilter, 0, 391 1000L, Integer.MAX_VALUE); 392 if (nr3.getEarliestSequenceNumber() != nr.getNextSequenceNumber()) { 393 System.out.println("After shrink, notifs not dropped as expected"); 394 return false; 395 } 396 if (nr3.getNextSequenceNumber() != nr2.getNextSequenceNumber()) { 397 System.out.println("After shrink, next seq no does not match"); 398 return false; 399 } 400 tns2 = new TargetedNotification[10]; 401 Arrays.asList(nr2.getTargetedNotifications()).subList(10, 20).toArray(tns2); 402 if (!sameTargetedNotifs(nr3.getTargetedNotifications(), tns2)) { 403 System.out.println("Later notifs not preserved after shrink"); 404 return false; 405 } 406 System.out.println("Dropping second buffer shrank capacity, OK"); 407 408 // Final test: check that destroying the final shared buffer 409 // removes its listeners 410 nb.dispose(); 411 nlisteners = sender.getListenerCount(); 412 if (nlisteners != 0) { 413 System.out.println("Disposing buffer should leave 0 listeners, " + 414 "but notification sender has " + nlisteners); 415 return false; 416 } 417 System.out.println("Dropping first buffer drops listeners, OK"); 418 419 return true; 420 } 421 422 private static boolean sameTargetedNotifs(TargetedNotification[] tn1, 423 TargetedNotification[] tn2) { 424 if (tn1.length != tn2.length) { 425 System.out.println("Not same length"); 426 return false; 427 } 428 for (int i = 0; i < tn1.length; i++) { 429 TargetedNotification n1 = tn1[i]; 430 TargetedNotification n2 = tn2[i]; 431 if (n1.getNotification() != n2.getNotification() 432 || !n1.getListenerID().equals(n2.getListenerID())) 433 return false; 434 } 435 return true; 436 } 437 438 private static NotificationBufferFilter makeFilter(final Integer id, 439 final ObjectName pattern, 440 final NotificationFilter filter) { 441 return new NotificationBufferFilter() { 442 public void apply(List<TargetedNotification> notifs, 443 ObjectName source, Notification notif) { 444 if (pattern.apply(source)) { 445 if (filter == null || filter.isNotificationEnabled(notif)) 446 notifs.add(new TargetedNotification(notif, id)); 447 } 448 } 449 }; 450 }; 451 }