File: NotificationBufferTest.java

package info (click to toggle)
openjdk-11 11.0.4%2B11-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 757,028 kB
  • sloc: java: 5,016,041; xml: 1,191,974; cpp: 934,731; ansic: 555,697; sh: 24,299; objc: 12,703; python: 3,602; asm: 3,415; makefile: 2,772; awk: 351; sed: 172; perl: 114; jsp: 24; csh: 3
file content (453 lines) | stat: -rw-r--r-- 19,946 bytes parent folder | download | duplicates (9)
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));
                }
            }
        };
    };
}