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 JMXDomainTest.java |
|
26 * @bug 5072476 |
|
27 * @summary Basic test for JMXDomain. |
|
28 * @author Daniel Fuchs |
|
29 * @run clean JMXDomainTest Wombat WombatMBean |
|
30 * @run build JMXDomainTest Wombat WombatMBean |
|
31 * @run main JMXDomainTest |
|
32 */ |
|
33 |
|
34 |
|
35 import java.util.Collections; |
|
36 import java.util.concurrent.ArrayBlockingQueue; |
|
37 import java.util.concurrent.BlockingQueue; |
|
38 import java.util.concurrent.TimeUnit; |
|
39 import java.util.Map; |
|
40 import java.util.Set; |
|
41 import javax.management.Attribute; |
|
42 import javax.management.AttributeList; |
|
43 import javax.management.AttributeNotFoundException; |
|
44 import javax.management.DynamicMBean; |
|
45 import javax.management.InstanceAlreadyExistsException; |
|
46 import javax.management.InstanceNotFoundException; |
|
47 import javax.management.InvalidAttributeValueException; |
|
48 import javax.management.ListenerNotFoundException; |
|
49 import javax.management.MBeanException; |
|
50 import javax.management.MBeanInfo; |
|
51 import javax.management.MBeanNotificationInfo; |
|
52 import javax.management.MBeanRegistration; |
|
53 import javax.management.MBeanRegistrationException; |
|
54 import javax.management.MBeanServer; |
|
55 import javax.management.MBeanServerDelegate; |
|
56 import javax.management.MBeanServerFactory; |
|
57 import javax.management.MBeanServerNotification; |
|
58 import javax.management.NotCompliantMBeanException; |
|
59 import javax.management.Notification; |
|
60 import javax.management.NotificationBroadcaster; |
|
61 import javax.management.NotificationEmitter; |
|
62 import javax.management.NotificationFilter; |
|
63 import javax.management.NotificationListener; |
|
64 import javax.management.ObjectInstance; |
|
65 import javax.management.ObjectName; |
|
66 import javax.management.ReflectionException; |
|
67 import javax.management.namespace.JMXDomain; |
|
68 import javax.management.namespace.MBeanServerSupport; |
|
69 |
|
70 /** |
|
71 * Test simple creation/registration of namespace. |
|
72 * |
|
73 */ |
|
74 public class JMXDomainTest { |
|
75 private static Map<String,Object> emptyEnvMap() { |
|
76 return Collections.emptyMap(); |
|
77 } |
|
78 |
|
79 |
|
80 public static class LocalDomainRepository |
|
81 extends MBeanServerSupport { |
|
82 private final MBeanServer server; |
|
83 private final String domain; |
|
84 |
|
85 public class DynamicMBeanProxy implements DynamicMBean { |
|
86 |
|
87 private final MBeanServer server; |
|
88 private final ObjectName name; |
|
89 |
|
90 public DynamicMBeanProxy(MBeanServer s, ObjectName n) { |
|
91 this.server = s; |
|
92 this.name = n; |
|
93 } |
|
94 |
|
95 public Object getAttribute(String attribute) |
|
96 throws AttributeNotFoundException, |
|
97 MBeanException, ReflectionException { |
|
98 try { |
|
99 return server.getAttribute(name, attribute); |
|
100 } catch (RuntimeException x) { |
|
101 throw x; |
|
102 } catch (Exception x) { |
|
103 throw new RuntimeException(x); |
|
104 } |
|
105 } |
|
106 |
|
107 public void setAttribute(Attribute attribute) |
|
108 throws AttributeNotFoundException, |
|
109 InvalidAttributeValueException, MBeanException, |
|
110 ReflectionException { |
|
111 try { |
|
112 server.setAttribute(name, attribute); |
|
113 } catch (RuntimeException x) { |
|
114 throw x; |
|
115 } catch (Exception x) { |
|
116 throw new RuntimeException(x); |
|
117 } |
|
118 } |
|
119 |
|
120 public AttributeList getAttributes(String[] attributes) { |
|
121 try { |
|
122 return server.getAttributes(name, attributes); |
|
123 } catch (RuntimeException x) { |
|
124 throw x; |
|
125 } catch (Exception x) { |
|
126 throw new RuntimeException(x); |
|
127 } |
|
128 } |
|
129 |
|
130 public AttributeList setAttributes(AttributeList attributes) { |
|
131 try { |
|
132 return server.setAttributes(name, attributes); |
|
133 } catch (RuntimeException x) { |
|
134 throw x; |
|
135 } catch (Exception x) { |
|
136 throw new RuntimeException(x); |
|
137 } |
|
138 } |
|
139 |
|
140 public Object invoke(String actionName, Object[] params, |
|
141 String[] signature) throws MBeanException, |
|
142 ReflectionException { |
|
143 try { |
|
144 return server.invoke(name, actionName, params, signature); |
|
145 } catch (RuntimeException x) { |
|
146 throw x; |
|
147 } catch (Exception x) { |
|
148 throw new RuntimeException(x); |
|
149 } |
|
150 } |
|
151 |
|
152 public MBeanInfo getMBeanInfo() { |
|
153 try { |
|
154 return server.getMBeanInfo(name); |
|
155 } catch (RuntimeException x) { |
|
156 throw x; |
|
157 } catch (Exception x) { |
|
158 throw new RuntimeException(x); |
|
159 } |
|
160 } |
|
161 } |
|
162 |
|
163 public LocalDomainRepository(String domain) { |
|
164 this.server = MBeanServerFactory.newMBeanServer(); |
|
165 this.domain = domain; |
|
166 } |
|
167 |
|
168 @Override |
|
169 protected Set<ObjectName> getNames() { |
|
170 try { |
|
171 final ObjectName name = |
|
172 ObjectName.getInstance(domain+":*"); |
|
173 return server.queryNames(name, null); |
|
174 } catch (RuntimeException x) { |
|
175 throw x; |
|
176 } catch (Exception x) { |
|
177 throw new RuntimeException(x); |
|
178 } |
|
179 } |
|
180 |
|
181 @Override |
|
182 public DynamicMBean getDynamicMBeanFor(ObjectName name) |
|
183 throws InstanceNotFoundException { |
|
184 if (server.isRegistered(name)) |
|
185 return new DynamicMBeanProxy(server, name); |
|
186 throw new InstanceNotFoundException(name); |
|
187 } |
|
188 |
|
189 |
|
190 @Override |
|
191 public NotificationEmitter |
|
192 getNotificationEmitterFor(final ObjectName name) |
|
193 throws InstanceNotFoundException { |
|
194 if (server.isInstanceOf(name, NotificationEmitter.class.getName())) { |
|
195 return new NotificationEmitter() { |
|
196 |
|
197 public void removeNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws ListenerNotFoundException { |
|
198 try { |
|
199 server.removeNotificationListener(name, listener, filter, handback); |
|
200 } catch (InstanceNotFoundException x) { |
|
201 throw new IllegalArgumentException(String.valueOf(name), x); |
|
202 } |
|
203 } |
|
204 |
|
205 public void addNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws IllegalArgumentException { |
|
206 try { |
|
207 server.addNotificationListener(name, listener, filter, handback); |
|
208 } catch (InstanceNotFoundException x) { |
|
209 throw new IllegalArgumentException(String.valueOf(name), x); |
|
210 } |
|
211 } |
|
212 |
|
213 public void removeNotificationListener(NotificationListener listener) throws ListenerNotFoundException { |
|
214 try { |
|
215 server.removeNotificationListener(name, listener); |
|
216 } catch (InstanceNotFoundException x) { |
|
217 throw new IllegalArgumentException(String.valueOf(name), x); |
|
218 } |
|
219 } |
|
220 |
|
221 public MBeanNotificationInfo[] getNotificationInfo() { |
|
222 try { |
|
223 return server.getMBeanInfo(name).getNotifications(); |
|
224 } catch (Exception x) { |
|
225 throw new IllegalArgumentException(String.valueOf(name), x); |
|
226 } |
|
227 } |
|
228 }; |
|
229 } |
|
230 return null; |
|
231 } |
|
232 |
|
233 @Override |
|
234 public ObjectInstance registerMBean(Object object, ObjectName name) |
|
235 throws InstanceAlreadyExistsException, |
|
236 MBeanRegistrationException, NotCompliantMBeanException { |
|
237 return server.registerMBean(object, name); |
|
238 } |
|
239 |
|
240 @Override |
|
241 public void unregisterMBean(ObjectName name) |
|
242 throws InstanceNotFoundException, |
|
243 MBeanRegistrationException { |
|
244 server.unregisterMBean(name); |
|
245 } |
|
246 |
|
247 @Override |
|
248 public ObjectInstance createMBean(String className, |
|
249 ObjectName name, ObjectName loaderName, Object[] params, |
|
250 String[] signature, boolean useCLR) |
|
251 throws ReflectionException, InstanceAlreadyExistsException, |
|
252 MBeanRegistrationException, MBeanException, |
|
253 NotCompliantMBeanException, InstanceNotFoundException { |
|
254 if (useCLR && loaderName == null) { |
|
255 return server.createMBean(className, name, params, signature); |
|
256 } |
|
257 return server.createMBean(className, name, loaderName, |
|
258 params, signature); |
|
259 } |
|
260 |
|
261 |
|
262 } |
|
263 |
|
264 private static MBeanServer newMBeanServer() { |
|
265 return MBeanServerFactory.newMBeanServer(); |
|
266 } |
|
267 |
|
268 public static interface ThingMBean {} |
|
269 public static class Thing implements ThingMBean, MBeanRegistration { |
|
270 public ObjectName preRegister(MBeanServer server, ObjectName name) |
|
271 throws Exception { |
|
272 if (name == null) return new ObjectName(":type=Thing"); |
|
273 else return name; |
|
274 } |
|
275 public void postRegister(Boolean registrationDone) { |
|
276 } |
|
277 |
|
278 public void preDeregister() throws Exception { |
|
279 } |
|
280 public void postDeregister() { |
|
281 } |
|
282 } |
|
283 |
|
284 /** |
|
285 * Test that it is possible to create a dummy MBean with a null |
|
286 * ObjectName - this is just a sanity check - as there are already |
|
287 * other JMX tests that check that. |
|
288 * |
|
289 * @throws java.lang.Exception |
|
290 */ |
|
291 public static void testCreateWithNull() throws Exception { |
|
292 final MBeanServer server = newMBeanServer(); |
|
293 final ObjectInstance oi = server.registerMBean(new Thing(),null); |
|
294 server.unregisterMBean(oi.getObjectName()); |
|
295 System.out.println("testCreateWithNull PASSED"); |
|
296 } |
|
297 |
|
298 public static void testRegisterSimple() throws Exception { |
|
299 final ObjectName name = |
|
300 JMXDomain.getDomainObjectName("gloups"); |
|
301 final JMXDomain jmxDomain = new JMXDomain( |
|
302 MBeanServerFactory.newMBeanServer()); |
|
303 testRegister("testRegisterSimple: ",name,jmxDomain); |
|
304 } |
|
305 |
|
306 public static void testRegisterPseudoVirtual() |
|
307 throws Exception { |
|
308 final ObjectName name = |
|
309 JMXDomain.getDomainObjectName("gloups"); |
|
310 final JMXDomain jmxDomain = new JMXDomain( |
|
311 new LocalDomainRepository("gloups")); |
|
312 testRegister("testRegisterPseudoVirtual: ",name,jmxDomain); |
|
313 } |
|
314 |
|
315 public static void testRegister(final String test, |
|
316 final ObjectName name, |
|
317 final JMXDomain jmxDomain) throws Exception { |
|
318 System.out.println(test+" START"); |
|
319 MBeanServer server = newMBeanServer(); |
|
320 final ObjectInstance oi = |
|
321 server.registerMBean(jmxDomain,name); |
|
322 System.out.println(test+"Succesfully registered namespace: "+name); |
|
323 if (!server.isRegistered(name)) |
|
324 fail(test+name+" is not registered!"); |
|
325 if (!server.queryNames(new ObjectName(name.getDomain()+":*"), null). |
|
326 contains(name)) |
|
327 fail(test+name+" not in queryNames"); |
|
328 |
|
329 final Thing thing = new Thing(); |
|
330 final ObjectName thingName = new ObjectName("gloups:type=Thing"); |
|
331 server.registerMBean(thing,thingName); |
|
332 if (!server.isRegistered(thingName)) |
|
333 fail(test+thingName+" is not registered!"); |
|
334 if (!jmxDomain.getSourceServer().isRegistered(thingName)) |
|
335 fail(test+thingName+" is not registered in domain!"); |
|
336 if (!server.queryNames(new ObjectName(name.getDomain()+":*"), null). |
|
337 contains(thingName)) |
|
338 fail(test+thingName+" not in queryNames"); |
|
339 |
|
340 server.unregisterMBean(name); |
|
341 if (server.isRegistered(thingName)) |
|
342 fail(test+thingName+" is still registered!"); |
|
343 if (server.queryNames(new ObjectName(name.getDomain()+":*"), null). |
|
344 contains(thingName)) |
|
345 fail(test+thingName+" still in queryNames"); |
|
346 |
|
347 server.registerMBean(jmxDomain, name); |
|
348 if (!server.isRegistered(thingName)) |
|
349 fail(test+thingName+" is not registered again!"); |
|
350 |
|
351 System.out.println(test+" PASSED"); |
|
352 } |
|
353 |
|
354 private static MBeanServerNotification pop( |
|
355 BlockingQueue<Notification> queue, |
|
356 String type, |
|
357 ObjectName mbean, |
|
358 String test) |
|
359 throws InterruptedException { |
|
360 final Notification n = queue.poll(1, TimeUnit.SECONDS); |
|
361 if (!(n instanceof MBeanServerNotification)) |
|
362 fail(test+"expected MBeanServerNotification, got "+n); |
|
363 final MBeanServerNotification msn = (MBeanServerNotification)n; |
|
364 if (!type.equals(msn.getType())) |
|
365 fail(test+"expected "+type+", got "+msn.getType()); |
|
366 if (!mbean.apply(msn.getMBeanName())) |
|
367 fail(test+"expected "+mbean+", got "+msn.getMBeanName()); |
|
368 System.out.println(test+" got: "+msn); |
|
369 return msn; |
|
370 } |
|
371 private static MBeanServerNotification popADD( |
|
372 BlockingQueue<Notification> queue, |
|
373 ObjectName mbean, |
|
374 String test) |
|
375 throws InterruptedException { |
|
376 return pop(queue, MBeanServerNotification.REGISTRATION_NOTIFICATION, |
|
377 mbean, test); |
|
378 } |
|
379 |
|
380 private static MBeanServerNotification popREM( |
|
381 BlockingQueue<Notification> queue, |
|
382 ObjectName mbean, |
|
383 String test) |
|
384 throws InterruptedException { |
|
385 return pop(queue, MBeanServerNotification.UNREGISTRATION_NOTIFICATION, |
|
386 mbean, test); |
|
387 } |
|
388 |
|
389 |
|
390 public static void testRegisterNotifSimple() throws Exception { |
|
391 final ObjectName name = |
|
392 JMXDomain.getDomainObjectName("gloups"); |
|
393 final JMXDomain jmxDomain = new JMXDomain( |
|
394 MBeanServerFactory.newMBeanServer()); |
|
395 testRegisterNotif("testRegisterNotifSimple: ",name,jmxDomain); |
|
396 } |
|
397 |
|
398 public static void testRegisterNotifPseudoVirtual() |
|
399 throws Exception { |
|
400 final ObjectName name = |
|
401 JMXDomain.getDomainObjectName("gloups"); |
|
402 final JMXDomain jmxDomain = new JMXDomain( |
|
403 new LocalDomainRepository("gloups")); |
|
404 testRegisterNotif("testRegisterNotifPseudoVirtual: ",name,jmxDomain); |
|
405 } |
|
406 |
|
407 public static void testRegisterNotif(final String test, |
|
408 final ObjectName name, |
|
409 final JMXDomain jmxDomain) throws Exception { |
|
410 System.out.println(test+" START"); |
|
411 MBeanServer server = newMBeanServer(); |
|
412 final ObjectInstance oi = |
|
413 server.registerMBean(jmxDomain,name); |
|
414 System.out.println(test+"Succesfully registered namespace: "+name); |
|
415 if (!server.isRegistered(name)) |
|
416 fail(test+name+" is not registered!"); |
|
417 |
|
418 final BlockingQueue<Notification> queue = |
|
419 new ArrayBlockingQueue<Notification>(10); |
|
420 |
|
421 final NotificationListener l = new NotificationListener() { |
|
422 |
|
423 public void handleNotification(Notification notification, |
|
424 Object handback) { |
|
425 try { |
|
426 if (!queue.offer(notification,5,TimeUnit.SECONDS)) |
|
427 throw new RuntimeException("timeout exceeded"); |
|
428 } catch (Exception x) { |
|
429 fail(test+"failed to handle notif", x); |
|
430 } |
|
431 } |
|
432 }; |
|
433 |
|
434 server.addNotificationListener(MBeanServerDelegate.DELEGATE_NAME, l, |
|
435 null, null); |
|
436 |
|
437 final Thing thing = new Thing(); |
|
438 final ObjectName thingName = new ObjectName("gloups:type=Thing"); |
|
439 |
|
440 server.registerMBean(thing,thingName); |
|
441 if (!jmxDomain.getSourceServer().isRegistered(thingName)) |
|
442 fail(test+thingName+" is not registered in domain!"); |
|
443 popADD(queue, thingName, test); |
|
444 server.unregisterMBean(thingName); |
|
445 if (jmxDomain.getSourceServer().isRegistered(thingName)) |
|
446 fail(test+thingName+" is still registered in domain!"); |
|
447 popREM(queue, thingName, test); |
|
448 if (queue.size() != 0) |
|
449 fail(test+queue.size()+" notifs remain in queue "+queue); |
|
450 |
|
451 server.unregisterMBean(name); |
|
452 popREM(queue, name, test); |
|
453 |
|
454 jmxDomain.getSourceServer().registerMBean(thing,thingName); |
|
455 if (server.isRegistered(thingName)) |
|
456 fail(test+thingName+" is still registered in domain!"); |
|
457 jmxDomain.getSourceServer().unregisterMBean(thingName); |
|
458 if (queue.size() != 0) |
|
459 fail(test+queue.size()+" notifs remain in queue "+queue); |
|
460 |
|
461 server.registerMBean(jmxDomain, name); |
|
462 if (!server.isRegistered(name)) |
|
463 fail(test+name+" is not registered again!"); |
|
464 popADD(queue, name, test); |
|
465 if (queue.size() != 0) |
|
466 fail(test+queue.size()+" notifs remain in queue "+queue); |
|
467 |
|
468 server.registerMBean(thing,thingName); |
|
469 if (!jmxDomain.getSourceServer().isRegistered(thingName)) |
|
470 fail(test+thingName+" is not registered in domain!"); |
|
471 popADD(queue, thingName, test); |
|
472 server.unregisterMBean(thingName); |
|
473 if (jmxDomain.getSourceServer().isRegistered(thingName)) |
|
474 fail(test+thingName+" is still registered in domain!"); |
|
475 popREM(queue, thingName, test); |
|
476 if (queue.size() != 0) |
|
477 fail(test+queue.size()+" notifs remain in queue "+queue); |
|
478 |
|
479 System.out.println(test+" PASSED"); |
|
480 } |
|
481 |
|
482 |
|
483 |
|
484 private static void fail(String msg) { |
|
485 raise(new RuntimeException(msg)); |
|
486 } |
|
487 |
|
488 private static void fail(String msg, Throwable cause) { |
|
489 raise(new RuntimeException(msg,cause)); |
|
490 } |
|
491 |
|
492 private static void raise(RuntimeException x) { |
|
493 lastException = x; |
|
494 exceptionCount++; |
|
495 throw x; |
|
496 } |
|
497 |
|
498 private static volatile Exception lastException = null; |
|
499 private static volatile int exceptionCount = 0; |
|
500 |
|
501 public static void main(String... args) throws Exception { |
|
502 testCreateWithNull(); |
|
503 |
|
504 testRegisterSimple(); |
|
505 testRegisterNotifSimple(); |
|
506 |
|
507 testRegisterPseudoVirtual(); |
|
508 testRegisterNotifPseudoVirtual(); |
|
509 |
|
510 if (lastException != null) |
|
511 throw lastException; |
|
512 } |
|
513 } |
|