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