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