1 /*
   2  * Copyright (c) 2005, 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 4661545
  27  * @summary Tests to use an executor to send notifications.
  28  * @author Shanliang JIANG
  29  * @modules java.management
  30  * @run clean NotifExecutorTest
  31  * @run build NotifExecutorTest
  32  * @run main NotifExecutorTest
  33  */
  34 
  35 // java imports
  36 //
  37 import java.io.IOException;
  38 import java.util.concurrent.*;
  39 
  40 // JMX imports
  41 //
  42 import javax.management.*;
  43 import javax.management.remote.*;
  44 
  45 public class NotifExecutorTest {
  46 
  47     public static void main(String[] args) throws Exception {
  48         System.out.println("Tests to use an executor to send notifications.");
  49 
  50         final MBeanServer mbs = MBeanServerFactory.createMBeanServer();
  51         final ObjectName mbean = new ObjectName ("Default:name=NotificationEmitter");
  52         final MyListener myLister = new MyListener();
  53         final NotificationListener nullListener = new NotificationListener() {
  54                 public void handleNotification(Notification n, Object hb) {
  55                     // nothing
  56                 }
  57             };
  58         final Object[] params = new Object[] {new Integer(nb)};
  59         final String[] signatures = new String[] {"java.lang.Integer"};
  60 
  61         // test with null executor
  62         System.out.println(">>> Test with a null executor.");
  63         mbs.registerMBean(new NotificationEmitter(null), mbean);
  64 
  65         mbs.addNotificationListener(mbean, myLister, null, null);
  66         mbs.addNotificationListener(mbean, nullListener, null, null);
  67 
  68         mbs.invoke(mbean, "sendNotifications", params, signatures);
  69         check(nb, 0);
  70 
  71         mbs.unregisterMBean(mbean);
  72 
  73         // test with an executor
  74         System.out.println(">>> Test with a executor.");
  75         mbs.registerMBean(new NotificationEmitter(
  76                            new NotifExecutorTest.MyExecutor()), mbean);
  77         mbs.addNotificationListener(mbean, myLister, null, null);
  78         mbs.addNotificationListener(mbean, nullListener, null, null);
  79 
  80         mbs.invoke(mbean, "sendNotifications", params, signatures);
  81 
  82         check(nb, nb*2);
  83 
  84         // test without listener
  85         System.out.println(">>> Test without listener.");
  86 
  87         mbs.removeNotificationListener(mbean, myLister);
  88         mbs.removeNotificationListener(mbean, nullListener);
  89 
  90         mbs.invoke(mbean, "sendNotifications", params, signatures);
  91         check(0, 0);
  92     }
  93 
  94     private static void check(int notifs, int called) throws Exception {
  95         // Waiting...
  96         synchronized (lock) {
  97             for (int i = 0; i < 10; i++) {
  98                 if (receivedNotifs < notifs) {
  99                     lock.wait(1000);
 100                 }
 101             }
 102         }
 103 
 104         // Waiting again to ensure no more notifs
 105         //
 106         Thread.sleep(1000);
 107 
 108         // checking
 109         synchronized (lock) {
 110             if (receivedNotifs != notifs) {
 111                 throw new RuntimeException("The listener expected to receive " +
 112                                            notifs + " notifs, but got " + receivedNotifs);
 113             } else {
 114                 System.out.println(">>> The listener recieved as expected: "+receivedNotifs);
 115             }
 116 
 117             if (calledTimes != called) {
 118                 throw new RuntimeException("The notif executor should be called " +
 119                                            called + " times, but got " + calledTimes);
 120             } else {
 121                 System.out.println(">>> The executor was called as expected: "+calledTimes);
 122             }
 123         }
 124 
 125         // clean
 126         receivedNotifs = 0;
 127         calledTimes = 0;
 128     }
 129 
 130 
 131     //--------------------------
 132     // private classes
 133     //--------------------------
 134     private static class MyListener implements NotificationListener {
 135         public void handleNotification(Notification notif, Object handback) {
 136             synchronized(lock) {
 137                 if(++receivedNotifs >= nb) {
 138                     lock.notifyAll();
 139                 }
 140             }
 141         }
 142     }
 143 
 144     public static class NotificationEmitter
 145         extends NotificationBroadcasterSupport
 146         implements NotificationEmitterMBean {
 147 
 148         public NotificationEmitter(Executor executor) {
 149             super(executor);
 150         }
 151 
 152         /**
 153          * Send a Notification object with the specified times.
 154          * The sequence number will be from zero to times-1.
 155          *
 156          * @param nb The number of notifications to send
 157          */
 158         public void sendNotifications(Integer nb) {
 159             System.out.println(">>> NotificationEmitter: asked to send " +
 160                                "notifications: " + nb);
 161 
 162             Notification notif;
 163             for (int i = 1; i <= nb.intValue(); i++) {
 164                 notif = new Notification(null, this, ++seqno);
 165                 super.sendNotification(notif);
 166             }
 167         }
 168     }
 169 
 170     public interface NotificationEmitterMBean {
 171         public void sendNotifications(Integer nb);
 172     }
 173 
 174     public static class MyExecutor extends ThreadPoolExecutor {
 175         public MyExecutor() {
 176             super(1, 1, 1L, TimeUnit.MILLISECONDS,
 177                   new ArrayBlockingQueue(nb*5));
 178         }
 179 
 180         public synchronized void execute(Runnable job) {
 181             synchronized(lock) {
 182                 calledTimes++;
 183             }
 184 
 185             super.execute(job);
 186         }
 187     }
 188 
 189     private static int nb = 10;
 190     private static int receivedNotifs = 0;
 191     private static int[] lock = new int[0];
 192     private static volatile long seqno;
 193 
 194     private static int calledTimes = 0;
 195 }