36 import javax.annotation.Resource; |
36 import javax.annotation.Resource; |
37 import javax.management.AttributeChangeNotification; |
37 import javax.management.AttributeChangeNotification; |
38 import javax.management.Description; |
38 import javax.management.Description; |
39 import javax.management.Descriptor; |
39 import javax.management.Descriptor; |
40 import javax.management.ImmutableDescriptor; |
40 import javax.management.ImmutableDescriptor; |
|
41 import javax.management.ListenerNotFoundException; |
41 import javax.management.MBean; |
42 import javax.management.MBean; |
42 import javax.management.MBeanInfo; |
43 import javax.management.MBeanInfo; |
43 import javax.management.MBeanNotificationInfo; |
44 import javax.management.MBeanNotificationInfo; |
44 import javax.management.MBeanServer; |
45 import javax.management.MBeanServer; |
45 import javax.management.MXBean; |
46 import javax.management.MXBean; |
|
47 import javax.management.Notification; |
|
48 import javax.management.NotificationBroadcaster; |
46 import javax.management.NotificationBroadcasterSupport; |
49 import javax.management.NotificationBroadcasterSupport; |
|
50 import javax.management.NotificationFilter; |
47 import javax.management.NotificationInfo; |
51 import javax.management.NotificationInfo; |
48 import javax.management.NotificationInfos; |
52 import javax.management.NotificationInfos; |
|
53 import javax.management.NotificationListener; |
49 import javax.management.ObjectName; |
54 import javax.management.ObjectName; |
50 import javax.management.SendNotification; |
55 import javax.management.SendNotification; |
51 |
56 |
52 public class AnnotatedNotificationInfoTest { |
57 public class AnnotatedNotificationInfoTest { |
53 // Data for the first test. This tests that MBeanNotificationInfo |
58 |
|
59 static final Descriptor expectedDescriptor = new ImmutableDescriptor( |
|
60 "foo=bar", "descriptionResourceBundleBaseName=bundle", |
|
61 "descriptionResourceKey=key"); |
|
62 static final MBeanNotificationInfo expected = new MBeanNotificationInfo( |
|
63 new String[] {"foo", "bar"}, |
|
64 AttributeChangeNotification.class.getName(), |
|
65 "description", |
|
66 expectedDescriptor); |
|
67 |
|
68 // Data for the first kind of test. This tests that MBeanNotificationInfo |
54 // is correctly derived from @NotificationInfo. |
69 // is correctly derived from @NotificationInfo. |
55 // Every static field called mbean* is expected to be an MBean |
70 // Every static field called mbean* is expected to be an MBean |
56 // with a single MBeanNotificationInfo that has the same value |
71 // with a single MBeanNotificationInfo that has the same value |
57 // in each case. |
72 // in each case. |
58 |
73 |
252 @MXBean |
267 @MXBean |
253 public static class MXBean2 extends ParentImpl {} |
268 public static class MXBean2 extends ParentImpl {} |
254 |
269 |
255 private static Object mbeanMXBean2 = new MXBean2(); |
270 private static Object mbeanMXBean2 = new MXBean2(); |
256 |
271 |
257 // Classes for the second test. This tests the simplest case, which is |
272 // Test that @NotificationInfo and @NotificationInfos are ignored if |
258 // the first example in the javadoc for @NotificationInfo. Notice that |
273 // the MBean returns a non-empty MBeanNotificationInfo[] from its |
259 // this MBean is not a NotificationBroadcaster and does not inject a |
274 // NotificationBroadcaster.getNotifications() implementation. |
260 // SendNotification! That should possibly be an error, but it's currently |
275 |
261 // allowed by the spec. |
276 @NotificationInfo(types={"blim", "blam"}) |
|
277 public static interface Explicit1MBean {} |
|
278 |
|
279 public static class Explicit1 |
|
280 extends NotificationBroadcasterSupport implements Explicit1MBean { |
|
281 public Explicit1() { |
|
282 super(expected); |
|
283 } |
|
284 } |
|
285 |
|
286 private static Object mbeanExplicit1 = new Explicit1(); |
|
287 |
|
288 @NotificationInfos( |
|
289 { |
|
290 @NotificationInfo(types="blim"), @NotificationInfo(types="blam") |
|
291 } |
|
292 ) |
|
293 public static interface Explicit2MXBean {} |
|
294 |
|
295 public static class Explicit2 |
|
296 implements NotificationBroadcaster, Explicit2MXBean { |
|
297 public void addNotificationListener(NotificationListener listener, |
|
298 NotificationFilter filter, Object handback) {} |
|
299 |
|
300 public void removeNotificationListener(NotificationListener listener) |
|
301 throws ListenerNotFoundException {} |
|
302 |
|
303 public MBeanNotificationInfo[] getNotificationInfo() { |
|
304 return new MBeanNotificationInfo[] {expected}; |
|
305 } |
|
306 } |
|
307 |
|
308 // Data for the second kind of test. This tests that @NotificationInfo is |
|
309 // ignored if the MBean is not a notification source. Every static |
|
310 // field called ignoredMBean* is expected to be an MBean on which |
|
311 // isInstanceOf(NotificationBroadcaster.class.getName() is false, |
|
312 // addNotificationListener produces an exception, and the |
|
313 // MBeanNotificationInfo array is empty. |
262 @NotificationInfo(types={"com.example.notifs.create", |
314 @NotificationInfo(types={"com.example.notifs.create", |
263 "com.example.notifs.destroy"}) |
315 "com.example.notifs.destroy"}) |
264 public static interface CacheMBean { |
316 public static interface CacheMBean { |
265 public int getCachedNum(); |
317 public int getCachedNum(); |
266 } |
318 } |
269 public int getCachedNum() { |
321 public int getCachedNum() { |
270 return 0; |
322 return 0; |
271 } |
323 } |
272 } |
324 } |
273 |
325 |
|
326 private static Object ignoredMBean1 = new Cache(); |
|
327 |
|
328 @NotificationInfos( |
|
329 @NotificationInfo(types={"foo", "bar"}) |
|
330 ) |
|
331 public static interface Cache2MBean { |
|
332 public int getCachedNum(); |
|
333 } |
|
334 |
|
335 public static class Cache2 implements Cache2MBean { |
|
336 public int getCachedNum() { |
|
337 return 0; |
|
338 } |
|
339 } |
|
340 |
|
341 private static Object ignoredMBean2 = new Cache2(); |
|
342 |
|
343 private static final NotificationListener nullListener = |
|
344 new NotificationListener() { |
|
345 public void handleNotification( |
|
346 Notification notification, Object handback) {} |
|
347 }; |
|
348 |
|
349 // Test that inheriting inconsistent @NotificationInfo annotations is |
|
350 // an error, but not if they are overridden by a non-empty getNotifications() |
|
351 |
|
352 @NotificationInfo(types={"blim"}) |
|
353 public static interface Inconsistent1 {} |
|
354 |
|
355 @NotificationInfo(types={"blam"}) |
|
356 public static interface Inconsistent2 {} |
|
357 |
|
358 public static interface InconsistentMBean extends Inconsistent1, Inconsistent2 {} |
|
359 |
|
360 public static class Inconsistent |
|
361 extends NotificationBroadcasterSupport implements InconsistentMBean {} |
|
362 |
|
363 public static class Consistent |
|
364 extends Inconsistent implements NotificationBroadcaster { |
|
365 public void addNotificationListener(NotificationListener listener, |
|
366 NotificationFilter filter, Object handback) {} |
|
367 |
|
368 public void removeNotificationListener(NotificationListener listener) |
|
369 throws ListenerNotFoundException {} |
|
370 |
|
371 public MBeanNotificationInfo[] getNotificationInfo() { |
|
372 return new MBeanNotificationInfo[] {expected}; |
|
373 } |
|
374 } |
|
375 |
|
376 private static Object mbeanConsistent = new Consistent(); |
|
377 |
|
378 @NotificationInfo( |
|
379 types = {"foo", "bar"}, |
|
380 notificationClass = AttributeChangeNotification.class, |
|
381 description = @Description( |
|
382 value = "description", |
|
383 bundleBaseName = "bundle", |
|
384 key = "key"), |
|
385 descriptorFields = {"foo=bar"}) |
|
386 public static interface Consistent2MBean extends Inconsistent1, Inconsistent2 {} |
|
387 |
|
388 public static class Consistent2 |
|
389 extends NotificationBroadcasterSupport implements Consistent2MBean {} |
|
390 |
|
391 private static Object mbeanConsistent2 = new Consistent2(); |
|
392 |
274 public static void main(String[] args) throws Exception { |
393 public static void main(String[] args) throws Exception { |
275 if (!AnnotatedNotificationInfoTest.class.desiredAssertionStatus()) |
394 if (!AnnotatedNotificationInfoTest.class.desiredAssertionStatus()) |
276 throw new Exception("Test must be run with -ea"); |
395 throw new Exception("Test must be run with -ea"); |
277 |
396 |
278 MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); |
397 MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); |
279 ObjectName on = new ObjectName("a:b=c"); |
398 ObjectName on = new ObjectName("a:b=c"); |
280 |
399 |
281 Descriptor expectedDescriptor = new ImmutableDescriptor( |
|
282 "foo=bar", "descriptionResourceBundleBaseName=bundle", |
|
283 "descriptionResourceKey=key"); |
|
284 MBeanNotificationInfo expected = new MBeanNotificationInfo( |
|
285 new String[] {"foo", "bar"}, |
|
286 AttributeChangeNotification.class.getName(), |
|
287 "description", |
|
288 expectedDescriptor); |
|
289 |
|
290 System.out.println("Testing MBeans..."); |
400 System.out.println("Testing MBeans..."); |
291 for (Field mbeanField : |
401 for (Field mbeanField : |
292 AnnotatedNotificationInfoTest.class.getDeclaredFields()) { |
402 AnnotatedNotificationInfoTest.class.getDeclaredFields()) { |
293 if (!mbeanField.getName().startsWith("mbean")) |
403 boolean notifier; |
|
404 if (mbeanField.getName().startsWith("mbean")) |
|
405 notifier = true; |
|
406 else if (mbeanField.getName().startsWith("ignoredMBean")) |
|
407 notifier = false; |
|
408 else |
294 continue; |
409 continue; |
295 System.out.println("..." + mbeanField.getName()); |
410 System.out.println("..." + mbeanField.getName()); |
296 Object mbean = mbeanField.get(null); |
411 Object mbean = mbeanField.get(null); |
297 mbs.registerMBean(mbean, on); |
412 mbs.registerMBean(mbean, on); |
298 MBeanInfo mbi = mbs.getMBeanInfo(on); |
413 MBeanInfo mbi = mbs.getMBeanInfo(on); |
299 MBeanNotificationInfo[] mbnis = mbi.getNotifications(); |
414 MBeanNotificationInfo[] mbnis = mbi.getNotifications(); |
300 assert mbnis.length == 1 : mbnis.length; |
415 if (notifier) { |
301 assert mbnis[0].equals(expected) : mbnis[0]; |
416 assert mbnis.length == 1 : mbnis.length; |
|
417 assert mbnis[0].equals(expected) : mbnis[0]; |
|
418 } else { |
|
419 assert mbnis.length == 0 : mbnis.length; |
|
420 assert !mbs.isInstanceOf(on, NotificationBroadcaster.class.getName()); |
|
421 try { |
|
422 mbs.addNotificationListener(on, nullListener, null, null); |
|
423 assert false : "addNotificationListener works"; |
|
424 } catch (Exception e) { |
|
425 // OK: addNL correctly refused |
|
426 } |
|
427 } |
302 mbs.unregisterMBean(on); |
428 mbs.unregisterMBean(on); |
303 } |
429 } |
304 |
430 |
305 mbs.registerMBean(new Cache(), on); |
431 // Test that inconsistent @NotificationInfo annotations produce an |
306 MBeanInfo mbi = mbs.getMBeanInfo(on); |
432 // error. |
307 MBeanNotificationInfo[] mbnis = mbi.getNotifications(); |
433 try { |
308 assert mbnis.length == 1 : mbnis.length; |
434 mbs.registerMBean(new Inconsistent(), on); |
309 String[] types = mbnis[0].getNotifTypes(); |
435 System.out.println(mbs.getMBeanInfo(on)); |
310 String[] expectedTypes = |
436 assert false : "Inconsistent @NotificationInfo not detected"; |
311 CacheMBean.class.getAnnotation(NotificationInfo.class).types(); |
437 } catch (Exception e) { |
312 assert Arrays.equals(types, expectedTypes) : Arrays.toString(types); |
438 System.out.println( |
|
439 "Inconsistent @NotificationInfo correctly produced " + e); |
|
440 } |
313 } |
441 } |
314 } |
442 } |