diff -r 54e1de48703e -r 4165709c91e3 jdk/test/javax/management/context/LocaleAwareBroadcasterTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/management/context/LocaleAwareBroadcasterTest.java Fri Nov 07 11:48:07 2008 +0100 @@ -0,0 +1,328 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 5072267 + * @summary Test that an MBean can handle localized Notification messages. + * @author Eamonn McManus + */ + +import java.util.Collections; +import java.util.ListResourceBundle; +import java.util.Locale; +import java.util.Map; +import java.util.MissingResourceException; +import java.util.ResourceBundle; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.TimeUnit; +import javax.management.ClientContext; +import javax.management.JMX; +import javax.management.ListenerNotFoundException; +import javax.management.MBeanNotificationInfo; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerFactory; +import javax.management.Notification; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationEmitter; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.SendNotification; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXConnectorServerFactory; +import javax.management.remote.JMXServiceURL; + +public class LocaleAwareBroadcasterTest { + static final ObjectName mbeanName = ObjectName.valueOf("d:type=LocaleAware"); + + static final String + messageKey = "broken.window", + defaultMessage = "broken window", + frenchMessage = "fen\u00eatre bris\u00e9e", + irishMessage = "fuinneog briste"; + + public static class Bundle extends ListResourceBundle { + @Override + protected Object[][] getContents() { + return new Object[][] { + {messageKey, defaultMessage}, + }; + } + } + + public static class Bundle_fr extends ListResourceBundle { + @Override + protected Object[][] getContents() { + return new Object[][] { + {messageKey, frenchMessage}, + }; + } + } + + public static class Bundle_ga extends ListResourceBundle { + @Override + protected Object[][] getContents() { + return new Object[][] { + {messageKey, irishMessage}, + }; + } + } + + static volatile String failure; + + public static interface LocaleAwareMBean { + public void sendNotification(Notification n); + } + + public static class LocaleAware + implements LocaleAwareMBean, NotificationEmitter, SendNotification { + + private final ConcurrentMap + localeToEmitter = newConcurrentMap(); + + public void sendNotification(Notification n) { + for (Map.Entry entry : + localeToEmitter.entrySet()) { + Notification localizedNotif = + localizeNotification(n, entry.getKey()); + entry.getValue().sendNotification(localizedNotif); + } + } + + public void addNotificationListener( + NotificationListener listener, + NotificationFilter filter, + Object handback) + throws IllegalArgumentException { + Locale locale = ClientContext.getLocale(); + NotificationBroadcasterSupport broadcaster; + broadcaster = localeToEmitter.get(locale); + if (broadcaster == null) { + broadcaster = new NotificationBroadcasterSupport(); + NotificationBroadcasterSupport old = + localeToEmitter.putIfAbsent(locale, broadcaster); + if (old != null) + broadcaster = old; + } + broadcaster.addNotificationListener(listener, filter, handback); + } + + public void removeNotificationListener(NotificationListener listener) + throws ListenerNotFoundException { + Locale locale = ClientContext.getLocale(); + NotificationBroadcasterSupport broadcaster = + localeToEmitter.get(locale); + if (broadcaster == null) + throw new ListenerNotFoundException(); + broadcaster.removeNotificationListener(listener); + } + + public void removeNotificationListener( + NotificationListener listener, + NotificationFilter filter, + Object handback) + throws ListenerNotFoundException { + Locale locale = ClientContext.getLocale(); + NotificationBroadcasterSupport broadcaster = + localeToEmitter.get(locale); + if (broadcaster == null) + throw new ListenerNotFoundException(); + broadcaster.removeNotificationListener(listener, filter, handback); + } + + public MBeanNotificationInfo[] getNotificationInfo() { + return new MBeanNotificationInfo[0]; + } + } + + // Localize notif using the convention that the message looks like + // [resourcebundlename:resourcekey]defaultmessage + // for example [foo.bar.Resources:unknown.problem] + static Notification localizeNotification(Notification n, Locale locale) { + String msg = n.getMessage(); + if (!msg.startsWith("[")) + return n; + int close = msg.indexOf(']'); + if (close < 0) + throw new IllegalArgumentException("Bad notification message: " + msg); + int colon = msg.indexOf(':'); + if (colon < 0 || colon > close) + throw new IllegalArgumentException("Bad notification message: " + msg); + String bundleName = msg.substring(1, colon); + String key = msg.substring(colon + 1, close); + ClassLoader loader = LocaleAwareBroadcasterTest.class.getClassLoader(); + ResourceBundle bundle = + ResourceBundle.getBundle(bundleName, locale, loader); + try { + msg = bundle.getString(key); + } catch (MissingResourceException e) { + msg = msg.substring(close + 1); + } + n = (Notification) n.clone(); + n.setMessage(msg); + return n; + } + + public static void main(String[] args) throws Exception { + Locale.setDefault(new Locale("en")); + testLocal(); + testRemote(); + if (failure == null) + System.out.println("TEST PASSED"); + else + throw new Exception("TEST FAILED: " + failure); + } + + static interface AddListenerInLocale { + public void addListenerInLocale( + MBeanServerConnection mbsc, + NotificationListener listener, + Locale locale) throws Exception; + } + + private static void testLocal() throws Exception { + System.out.println("Test local MBeanServer using doWithContext"); + MBeanServer mbs = makeMBS(); + AddListenerInLocale addListener = new AddListenerInLocale() { + public void addListenerInLocale( + final MBeanServerConnection mbsc, + final NotificationListener listener, + Locale locale) throws Exception { + Map localeContext = Collections.singletonMap( + ClientContext.LOCALE_KEY, locale.toString()); + ClientContext.doWithContext( + localeContext, new Callable() { + public Void call() throws Exception { + mbsc.addNotificationListener( + mbeanName, listener, null, null); + return null; + } + }); + } + }; + test(mbs, addListener); + } + + private static void testRemote() throws Exception { + System.out.println("Test remote MBeanServer using withLocale"); + MBeanServer mbs = makeMBS(); + JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://"); + JMXConnectorServer cs = + JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs); + cs.start(); + JMXServiceURL addr = cs.getAddress(); + JMXConnector cc = JMXConnectorFactory.connect(addr); + MBeanServerConnection mbsc = cc.getMBeanServerConnection(); + AddListenerInLocale addListenerInLocale = new AddListenerInLocale() { + public void addListenerInLocale( + MBeanServerConnection mbsc, + NotificationListener listener, + Locale locale) throws Exception { + mbsc = ClientContext.withLocale(mbsc, locale); + mbsc.addNotificationListener(mbeanName, listener, null, null); + } + }; + try { + test(mbsc, addListenerInLocale); + } finally { + try { + cc.close(); + } catch (Exception e) {} + cs.stop(); + } + } + + static class QueueListener implements NotificationListener { + final BlockingQueue queue = + new ArrayBlockingQueue(10); + + public void handleNotification(Notification notification, + Object handback) { + queue.add(notification); + } + } + + private static void test( + MBeanServerConnection mbsc, AddListenerInLocale addListener) + throws Exception { + QueueListener defaultListener = new QueueListener(); + QueueListener frenchListener = new QueueListener(); + QueueListener irishListener = new QueueListener(); + mbsc.addNotificationListener(mbeanName, defaultListener, null, null); + addListener.addListenerInLocale(mbsc, frenchListener, new Locale("fr")); + addListener.addListenerInLocale(mbsc, irishListener, new Locale("ga")); + + LocaleAwareMBean proxy = + JMX.newMBeanProxy(mbsc, mbeanName, LocaleAwareMBean.class); + String notifMsg = "[" + Bundle.class.getName() + ":" + messageKey + "]" + + "broken window (default message that should never be seen)"; + Notification notif = new Notification( + "notif.type", mbeanName, 0L, notifMsg); + proxy.sendNotification(notif); + + final Object[][] expected = { + {defaultListener, defaultMessage}, + {frenchListener, frenchMessage}, + {irishListener, irishMessage}, + }; + for (Object[] exp : expected) { + QueueListener ql = (QueueListener) exp[0]; + String msg = (String) exp[1]; + System.out.println("Checking: " + msg); + Notification n = ql.queue.poll(1, TimeUnit.SECONDS); + if (n == null) + fail("Did not receive expected notif: " + msg); + if (!n.getMessage().equals(msg)) { + fail("Received notif with wrong message: got " + + n.getMessage() + ", expected " + msg); + } + n = ql.queue.poll(2, TimeUnit.MILLISECONDS); + if (n != null) + fail("Received unexpected extra notif: " + n); + } + } + + private static MBeanServer makeMBS() throws Exception { + MBeanServer mbs = MBeanServerFactory.newMBeanServer(); + LocaleAware aware = new LocaleAware(); + mbs.registerMBean(aware, mbeanName); + return mbs; + } + + static ConcurrentMap newConcurrentMap() { + return new ConcurrentHashMap(); + } + + static void fail(String why) { + System.out.println("FAIL: " + why); + failure = why; + } +}