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