jdk/test/javax/management/context/LocaleAwareBroadcasterTest.java
changeset 1570 4165709c91e3
equal deleted inserted replaced
1569:54e1de48703e 1570:4165709c91e3
       
     1 /*
       
     2  * Copyright 2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    20  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    21  * have any questions.
       
    22  */
       
    23 
       
    24 /*
       
    25  * @test
       
    26  * @bug 5072267
       
    27  * @summary Test that an MBean can handle localized Notification messages.
       
    28  * @author Eamonn McManus
       
    29  */
       
    30 
       
    31 import java.util.Collections;
       
    32 import java.util.ListResourceBundle;
       
    33 import java.util.Locale;
       
    34 import java.util.Map;
       
    35 import java.util.MissingResourceException;
       
    36 import java.util.ResourceBundle;
       
    37 import java.util.concurrent.ArrayBlockingQueue;
       
    38 import java.util.concurrent.BlockingQueue;
       
    39 import java.util.concurrent.Callable;
       
    40 import java.util.concurrent.ConcurrentHashMap;
       
    41 import java.util.concurrent.ConcurrentMap;
       
    42 import java.util.concurrent.TimeUnit;
       
    43 import javax.management.ClientContext;
       
    44 import javax.management.JMX;
       
    45 import javax.management.ListenerNotFoundException;
       
    46 import javax.management.MBeanNotificationInfo;
       
    47 import javax.management.MBeanServer;
       
    48 import javax.management.MBeanServerConnection;
       
    49 import javax.management.MBeanServerFactory;
       
    50 import javax.management.Notification;
       
    51 import javax.management.NotificationBroadcasterSupport;
       
    52 import javax.management.NotificationEmitter;
       
    53 import javax.management.NotificationFilter;
       
    54 import javax.management.NotificationListener;
       
    55 import javax.management.ObjectName;
       
    56 import javax.management.SendNotification;
       
    57 import javax.management.remote.JMXConnector;
       
    58 import javax.management.remote.JMXConnectorFactory;
       
    59 import javax.management.remote.JMXConnectorServer;
       
    60 import javax.management.remote.JMXConnectorServerFactory;
       
    61 import javax.management.remote.JMXServiceURL;
       
    62 
       
    63 public class LocaleAwareBroadcasterTest {
       
    64     static final ObjectName mbeanName = ObjectName.valueOf("d:type=LocaleAware");
       
    65 
       
    66     static final String
       
    67             messageKey = "broken.window",
       
    68             defaultMessage = "broken window",
       
    69             frenchMessage = "fen\u00eatre bris\u00e9e",
       
    70             irishMessage = "fuinneog briste";
       
    71 
       
    72     public static class Bundle extends ListResourceBundle {
       
    73         @Override
       
    74         protected Object[][] getContents() {
       
    75             return new Object[][] {
       
    76                 {messageKey, defaultMessage},
       
    77             };
       
    78         }
       
    79     }
       
    80 
       
    81     public static class Bundle_fr extends ListResourceBundle {
       
    82         @Override
       
    83         protected Object[][] getContents() {
       
    84             return new Object[][] {
       
    85                 {messageKey, frenchMessage},
       
    86             };
       
    87         }
       
    88     }
       
    89 
       
    90     public static class Bundle_ga extends ListResourceBundle {
       
    91         @Override
       
    92         protected Object[][] getContents() {
       
    93             return new Object[][] {
       
    94                 {messageKey, irishMessage},
       
    95             };
       
    96         }
       
    97     }
       
    98 
       
    99     static volatile String failure;
       
   100 
       
   101     public static interface LocaleAwareMBean {
       
   102         public void sendNotification(Notification n);
       
   103     }
       
   104 
       
   105     public static class LocaleAware
       
   106             implements LocaleAwareMBean, NotificationEmitter, SendNotification {
       
   107 
       
   108         private final ConcurrentMap<Locale, NotificationBroadcasterSupport>
       
   109                 localeToEmitter = newConcurrentMap();
       
   110 
       
   111         public void sendNotification(Notification n) {
       
   112             for (Map.Entry<Locale, NotificationBroadcasterSupport> entry :
       
   113                     localeToEmitter.entrySet()) {
       
   114                 Notification localizedNotif =
       
   115                         localizeNotification(n, entry.getKey());
       
   116                 entry.getValue().sendNotification(localizedNotif);
       
   117             }
       
   118         }
       
   119 
       
   120         public void addNotificationListener(
       
   121                 NotificationListener listener,
       
   122                 NotificationFilter filter,
       
   123                 Object handback)
       
   124                 throws IllegalArgumentException {
       
   125             Locale locale = ClientContext.getLocale();
       
   126             NotificationBroadcasterSupport broadcaster;
       
   127             broadcaster = localeToEmitter.get(locale);
       
   128             if (broadcaster == null) {
       
   129                 broadcaster = new NotificationBroadcasterSupport();
       
   130                 NotificationBroadcasterSupport old =
       
   131                         localeToEmitter.putIfAbsent(locale, broadcaster);
       
   132                 if (old != null)
       
   133                     broadcaster = old;
       
   134             }
       
   135             broadcaster.addNotificationListener(listener, filter, handback);
       
   136         }
       
   137 
       
   138         public void removeNotificationListener(NotificationListener listener)
       
   139                 throws ListenerNotFoundException {
       
   140             Locale locale = ClientContext.getLocale();
       
   141             NotificationBroadcasterSupport broadcaster =
       
   142                     localeToEmitter.get(locale);
       
   143             if (broadcaster == null)
       
   144                 throw new ListenerNotFoundException();
       
   145             broadcaster.removeNotificationListener(listener);
       
   146         }
       
   147 
       
   148         public void removeNotificationListener(
       
   149                 NotificationListener listener,
       
   150                 NotificationFilter filter,
       
   151                 Object handback)
       
   152                 throws ListenerNotFoundException {
       
   153             Locale locale = ClientContext.getLocale();
       
   154             NotificationBroadcasterSupport broadcaster =
       
   155                     localeToEmitter.get(locale);
       
   156             if (broadcaster == null)
       
   157                 throw new ListenerNotFoundException();
       
   158             broadcaster.removeNotificationListener(listener, filter, handback);
       
   159         }
       
   160 
       
   161         public MBeanNotificationInfo[] getNotificationInfo() {
       
   162             return new MBeanNotificationInfo[0];
       
   163         }
       
   164     }
       
   165 
       
   166     // Localize notif using the convention that the message looks like
       
   167     // [resourcebundlename:resourcekey]defaultmessage
       
   168     // for example [foo.bar.Resources:unknown.problem]
       
   169     static Notification localizeNotification(Notification n, Locale locale) {
       
   170         String msg = n.getMessage();
       
   171         if (!msg.startsWith("["))
       
   172             return n;
       
   173         int close = msg.indexOf(']');
       
   174         if (close < 0)
       
   175             throw new IllegalArgumentException("Bad notification message: " + msg);
       
   176         int colon = msg.indexOf(':');
       
   177         if (colon < 0 || colon > close)
       
   178             throw new IllegalArgumentException("Bad notification message: " + msg);
       
   179         String bundleName = msg.substring(1, colon);
       
   180         String key = msg.substring(colon + 1, close);
       
   181         ClassLoader loader = LocaleAwareBroadcasterTest.class.getClassLoader();
       
   182         ResourceBundle bundle =
       
   183                 ResourceBundle.getBundle(bundleName, locale, loader);
       
   184         try {
       
   185             msg = bundle.getString(key);
       
   186         } catch (MissingResourceException e) {
       
   187             msg = msg.substring(close + 1);
       
   188         }
       
   189         n = (Notification) n.clone();
       
   190         n.setMessage(msg);
       
   191         return n;
       
   192     }
       
   193 
       
   194     public static void main(String[] args) throws Exception {
       
   195         Locale.setDefault(new Locale("en"));
       
   196         testLocal();
       
   197         testRemote();
       
   198         if (failure == null)
       
   199             System.out.println("TEST PASSED");
       
   200         else
       
   201             throw new Exception("TEST FAILED: " + failure);
       
   202     }
       
   203 
       
   204     static interface AddListenerInLocale {
       
   205         public void addListenerInLocale(
       
   206                 MBeanServerConnection mbsc,
       
   207                 NotificationListener listener,
       
   208                 Locale locale) throws Exception;
       
   209     }
       
   210 
       
   211     private static void testLocal() throws Exception {
       
   212         System.out.println("Test local MBeanServer using doWithContext");
       
   213         MBeanServer mbs = makeMBS();
       
   214         AddListenerInLocale addListener = new AddListenerInLocale() {
       
   215             public void addListenerInLocale(
       
   216                     final MBeanServerConnection mbsc,
       
   217                     final NotificationListener listener,
       
   218                     Locale locale) throws Exception {
       
   219                 Map<String, String> localeContext = Collections.singletonMap(
       
   220                         ClientContext.LOCALE_KEY, locale.toString());
       
   221                 ClientContext.doWithContext(
       
   222                         localeContext, new Callable<Void>() {
       
   223                     public Void call() throws Exception {
       
   224                         mbsc.addNotificationListener(
       
   225                                 mbeanName, listener, null, null);
       
   226                         return null;
       
   227                     }
       
   228                 });
       
   229             }
       
   230         };
       
   231         test(mbs, addListener);
       
   232     }
       
   233 
       
   234     private static void testRemote() throws Exception {
       
   235         System.out.println("Test remote MBeanServer using withLocale");
       
   236         MBeanServer mbs = makeMBS();
       
   237         JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://");
       
   238         JMXConnectorServer cs =
       
   239                 JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);
       
   240         cs.start();
       
   241         JMXServiceURL addr = cs.getAddress();
       
   242         JMXConnector cc = JMXConnectorFactory.connect(addr);
       
   243         MBeanServerConnection mbsc = cc.getMBeanServerConnection();
       
   244         AddListenerInLocale addListenerInLocale = new AddListenerInLocale() {
       
   245             public void addListenerInLocale(
       
   246                     MBeanServerConnection mbsc,
       
   247                     NotificationListener listener,
       
   248                     Locale locale) throws Exception {
       
   249                 mbsc = ClientContext.withLocale(mbsc, locale);
       
   250                 mbsc.addNotificationListener(mbeanName, listener, null, null);
       
   251             }
       
   252         };
       
   253         try {
       
   254             test(mbsc, addListenerInLocale);
       
   255         } finally {
       
   256             try {
       
   257                 cc.close();
       
   258             } catch (Exception e) {}
       
   259             cs.stop();
       
   260         }
       
   261     }
       
   262 
       
   263     static class QueueListener implements NotificationListener {
       
   264         final BlockingQueue<Notification> queue =
       
   265                 new ArrayBlockingQueue<Notification>(10);
       
   266 
       
   267         public void handleNotification(Notification notification,
       
   268                                        Object handback) {
       
   269             queue.add(notification);
       
   270         }
       
   271     }
       
   272 
       
   273     private static void test(
       
   274             MBeanServerConnection mbsc, AddListenerInLocale addListener)
       
   275             throws Exception {
       
   276         QueueListener defaultListener = new QueueListener();
       
   277         QueueListener frenchListener = new QueueListener();
       
   278         QueueListener irishListener = new QueueListener();
       
   279         mbsc.addNotificationListener(mbeanName, defaultListener, null, null);
       
   280         addListener.addListenerInLocale(mbsc, frenchListener, new Locale("fr"));
       
   281         addListener.addListenerInLocale(mbsc, irishListener, new Locale("ga"));
       
   282 
       
   283         LocaleAwareMBean proxy =
       
   284                 JMX.newMBeanProxy(mbsc, mbeanName, LocaleAwareMBean.class);
       
   285         String notifMsg = "[" + Bundle.class.getName() + ":" + messageKey + "]" +
       
   286                 "broken window (default message that should never be seen)";
       
   287         Notification notif = new Notification(
       
   288                 "notif.type", mbeanName, 0L, notifMsg);
       
   289         proxy.sendNotification(notif);
       
   290 
       
   291         final Object[][] expected = {
       
   292             {defaultListener, defaultMessage},
       
   293             {frenchListener, frenchMessage},
       
   294             {irishListener, irishMessage},
       
   295         };
       
   296         for (Object[] exp : expected) {
       
   297             QueueListener ql = (QueueListener) exp[0];
       
   298             String msg = (String) exp[1];
       
   299             System.out.println("Checking: " + msg);
       
   300             Notification n = ql.queue.poll(1, TimeUnit.SECONDS);
       
   301             if (n == null)
       
   302                 fail("Did not receive expected notif: " + msg);
       
   303             if (!n.getMessage().equals(msg)) {
       
   304                 fail("Received notif with wrong message: got " +
       
   305                         n.getMessage() + ", expected " + msg);
       
   306             }
       
   307             n = ql.queue.poll(2, TimeUnit.MILLISECONDS);
       
   308             if (n != null)
       
   309                 fail("Received unexpected extra notif: " + n);
       
   310         }
       
   311     }
       
   312 
       
   313     private static MBeanServer makeMBS() throws Exception {
       
   314         MBeanServer mbs = MBeanServerFactory.newMBeanServer();
       
   315         LocaleAware aware = new LocaleAware();
       
   316         mbs.registerMBean(aware, mbeanName);
       
   317         return mbs;
       
   318     }
       
   319 
       
   320     static <K, V> ConcurrentMap<K, V> newConcurrentMap() {
       
   321         return new ConcurrentHashMap<K, V>();
       
   322     }
       
   323 
       
   324     static void fail(String why) {
       
   325         System.out.println("FAIL: " + why);
       
   326         failure = why;
       
   327     }
       
   328 }