1 4 package org.oddjob.jmx.client; 5 6 import java.io.Serializable ; 7 import java.lang.reflect.Proxy ; 8 import java.util.HashMap ; 9 import java.util.Map ; 10 11 import javax.management.Attribute ; 12 import javax.management.AttributeList ; 13 import javax.management.AttributeNotFoundException ; 14 import javax.management.DynamicMBean ; 15 import javax.management.InstanceNotFoundException ; 16 import javax.management.IntrospectionException ; 17 import javax.management.InvalidAttributeValueException ; 18 import javax.management.MBeanAttributeInfo ; 19 import javax.management.MBeanConstructorInfo ; 20 import javax.management.MBeanException ; 21 import javax.management.MBeanInfo ; 22 import javax.management.MBeanNotificationInfo ; 23 import javax.management.MBeanOperationInfo ; 24 import javax.management.MBeanServer ; 25 import javax.management.MBeanServerFactory ; 26 import javax.management.Notification ; 27 import javax.management.NotificationBroadcasterSupport ; 28 import javax.management.NotificationEmitter ; 29 import javax.management.ObjectName ; 30 import javax.management.ReflectionException ; 31 32 import junit.framework.TestCase; 33 34 import org.apache.commons.beanutils.BeanUtilsBean; 35 import org.apache.commons.beanutils.DynaBean; 36 import org.apache.commons.beanutils.DynaClass; 37 import org.apache.commons.beanutils.DynaProperty; 38 import org.apache.log4j.Logger; 39 import org.oddjob.Iconic; 40 import org.oddjob.Stateful; 41 import org.oddjob.Structural; 42 import org.oddjob.arooa.reflect.BeanUtilsBeanHelper; 43 import org.oddjob.arooa.reflect.DefaultRegistryLookup; 44 import org.oddjob.arooa.reflect.RegistryLookup; 45 import org.oddjob.arooa.registry.ComponentRegistry; 46 import org.oddjob.images.IconEvent; 47 import org.oddjob.images.IconListener; 48 import org.oddjob.images.IconTip; 49 import org.oddjob.jmx.SharedConstants; 50 import org.oddjob.jmx.WaitForChildren; 51 import org.oddjob.jmx.server.IconicInfo; 52 import org.oddjob.jmx.server.InterfaceManagerFactory; 53 import org.oddjob.jmx.server.OddjobMBean; 54 import org.oddjob.jmx.server.ServerContext; 55 import org.oddjob.jmx.server.ServerInfo; 56 import org.oddjob.jmx.server.ServerModel; 57 import org.oddjob.jmx.server.StatefulInfo; 58 import org.oddjob.jmx.server.StructuralInfo; 59 import org.oddjob.monitor.model.Describer; 60 import org.oddjob.state.JobState; 61 import org.oddjob.state.JobStateEvent; 62 import org.oddjob.state.JobStateListener; 63 import org.oddjob.structural.StructuralEvent; 64 import org.oddjob.structural.StructuralListener; 65 import org.oddjob.util.ThreadManager; 66 import org.oddjob.values.types.MapType; 67 68 71 public class ClientNodeTest extends TestCase { 72 public static final Logger logger = Logger.getLogger(ClientNodeTest.class); 73 74 75 public interface OJMBeanInternals { 76 public String toString(); 77 public void resync(); 78 public Class [] interfaces(); 79 public ServerInfo serverInfo(); 80 } 81 82 public abstract class BaseMockOJMBean extends NotificationBroadcasterSupport 83 implements OJMBeanInternals { 84 public void resync() { 85 sendNotification(new Notification (OddjobMBean.RESYNC_STARTED_NOTIF_TYPE, this, 0)); 86 sendNotification(new Notification (OddjobMBean.RESYNC_FINISHED_NOTIF_TYPE, this, 0)); 87 } 88 public ServerInfo serverInfo() { 89 return new ServerInfo(id(), url(), consoleId(), 90 interfaces(), false, null); 91 } 92 public Class [] interfaces() { 93 return new Class [0]; 94 } 95 public String consoleId() { 96 return "test"; 97 } 98 public String url() { 99 return "//test"; 100 } 101 public String id() { 102 return null; 103 } 104 public String toString() { 105 return "MockOJMBean."; 106 } 107 } 108 109 111 public interface SimpleMBean extends OJMBeanInternals { } 112 113 public class Simple extends BaseMockOJMBean 114 implements SimpleMBean { 115 public String toString() { return "test"; } 116 } 117 118 public void testSimple() throws Exception { 119 Simple mb = new Simple(); 120 121 MBeanServer mbs = MBeanServerFactory.createMBeanServer(); 122 ObjectName on = new ObjectName ("oddjob:name=whatever"); 123 mbs.registerMBean(mb, on); 124 125 Object proxy = ClientNode.createProxyFor(on, mbs, this, cr, 126 new DummyNP()); 127 assertEquals("test", proxy.toString()); 128 } 129 130 132 public interface MockRunnableMBean extends Runnable , OJMBeanInternals { 133 } 134 135 public class MockRunnable extends BaseMockOJMBean 136 implements MockRunnableMBean { 137 boolean ran; 138 public MockRunnable() {} 139 public void run() { 140 ran = true; 141 } 142 public Class [] interfaces() { 143 return new Class [] { Runnable .class }; 144 } 145 } 146 147 public interface MockStatefulMBean extends NotificationEmitter , OJMBeanInternals { 148 } 149 150 public class MockStateful extends BaseMockOJMBean 151 implements MockStatefulMBean { 152 public MBeanNotificationInfo [] getNotificationInfo() { 153 return new MBeanNotificationInfo [] { 154 new MBeanNotificationInfo (new String [] { StatefulInfo.STATE_CHANGE_NOTIF_TYPE }, 155 Notification .class.getName(), "Dummy") }; 156 } 157 158 public void foo() { 159 Notification n = new Notification (StatefulInfo.STATE_CHANGE_NOTIF_TYPE, 160 this, 0); 161 n.setUserData(new JobStateEvent(this, JobState.COMPLETE, null)); 162 sendNotification(n); 163 } 164 public Class [] interfaces() { 165 return new Class [] { Stateful.class }; 166 } 167 } 168 169 public interface MockStructuralMBean extends NotificationEmitter , OJMBeanInternals { 170 } 171 172 public class MockStructural extends BaseMockOJMBean 173 implements MockStructuralMBean { 174 public MBeanNotificationInfo [] getNotificationInfo() { 175 return new MBeanNotificationInfo [] { 176 new MBeanNotificationInfo (new String [] { StructuralInfo.CHILD_ADDED_NOTIF_TYPE, 177 StructuralInfo.CHILD_REMOVED_NOTIF_TYPE }, 178 Notification .class.getName(), "Dummy") }; 179 } 180 public void ac(ObjectName c) { 181 Notification n = new Notification (StructuralInfo.CHILD_ADDED_NOTIF_TYPE, 182 this, 2); 183 n.setUserData(new StructuralEvent(this, c, 0)); 184 sendNotification(n); 185 } 186 public void rc(ObjectName c) { 187 Notification n = new Notification (StructuralInfo.CHILD_REMOVED_NOTIF_TYPE, 188 this, 3); 189 n.setUserData(new StructuralEvent(this, c, 0)); 190 sendNotification(n); 191 } 192 public Class [] interfaces() { 193 return new Class [] { Structural.class }; 194 } 195 }; 196 197 public interface MockIconicMBean extends NotificationEmitter , OJMBeanInternals { 198 public IconTip iconForId(String iconId); 199 } 200 201 public class MockIconic extends BaseMockOJMBean 202 implements MockIconicMBean { 203 public MBeanNotificationInfo [] getNotificationInfo() { 204 return new MBeanNotificationInfo [] { 205 new MBeanNotificationInfo (new String [] { IconicInfo.ICON_CHANGED_NOTIF_TYPE }, 206 Notification .class.getName(), "Dummy") }; 207 } 208 public IconTip iconForId(String iconId) { 209 return new IconTip(new byte[0], "foo"); 210 } 211 public void foo() { 212 Notification n = new Notification (IconicInfo.ICON_CHANGED_NOTIF_TYPE, 213 this, 0); 214 n.setUserData(new IconEvent(this, "foo")); 215 sendNotification(n); 216 } 217 public Class [] interfaces() { 218 return new Class [] { Iconic.class }; 219 } 220 } 221 222 private ComponentRegistry cr; 223 224 public void setUp() { 225 logger.debug("================== Running " + getName() + "================"); 226 System.setProperty("mx4j.log.priority", "trace"); 227 cr = new ComponentRegistry(); 228 cr.register("this", this); 229 } 230 231 public void testRunnable() 232 throws Exception { 233 MockRunnable mb = new MockRunnable(); 234 235 MBeanServer mbs = MBeanServerFactory.createMBeanServer(); 236 ObjectName on = new ObjectName ("oddjob:name=whatever"); 237 mbs.registerMBean(mb, on); 238 239 Object proxy = ClientNode.createProxyFor(on, mbs, this, cr, 240 new DummyNP()); 241 assertTrue("Runnable", proxy instanceof Runnable ); 242 243 ((Runnable )proxy).run(); 244 assertTrue("Ran", mb.ran); 245 } 246 247 public void testStateful() 248 throws Exception { 249 class MyStateListener implements JobStateListener { 250 JobStateEvent se; 251 public void jobStateChange(JobStateEvent event) { 252 se = event; 253 } 254 }; 255 MyStateListener ml = new MyStateListener(); 256 257 MockStateful mb = new MockStateful(); 258 259 MBeanServer mbs = MBeanServerFactory.createMBeanServer(); 260 ObjectName on = new ObjectName ("oddjob:name=whatever"); 261 mbs.registerMBean(mb, on); 262 263 Object proxy = ClientNode.createProxyFor(on, mbs, this, cr, 264 new DummyNP()); 265 assertNotNull(proxy); 266 assertTrue("Stateful", proxy instanceof Stateful); 267 268 ((Stateful)proxy).addJobStateListener(ml); 269 mb.foo(); 270 271 assertEquals("source", proxy, ml.se.getSource()); 272 assertEquals("state", JobState.COMPLETE, ml.se.getJobState()); 273 } 274 275 public void testStructural() 276 throws Exception { 277 MockRunnable myChild = new MockRunnable(); 278 279 class MyStructuralListener implements StructuralListener { 280 StructuralEvent se; 281 public void childAdded(StructuralEvent event) { 282 se = event; 283 } 284 public void childRemoved(StructuralEvent event) { 285 se = event; 286 } 287 }; 288 MyStructuralListener ml = new MyStructuralListener(); 289 290 MockStructural mb = new MockStructural(); 291 292 MBeanServer mbs = MBeanServerFactory.createMBeanServer(); 293 ObjectName on = new ObjectName ("oddjob:name=whatever"); 294 mbs.registerMBean(mb, on); 295 296 Object proxy = ClientNode.createProxyFor(on, mbs, this, cr, 297 new DummyNP()); 298 assertTrue("Structural", proxy instanceof Structural); 299 300 ((Structural)proxy).addStructuralListener(ml); 301 302 ObjectName cName = new ObjectName ("oddjob:name=child"); 303 mbs.registerMBean(myChild, cName); 304 305 mb.ac(cName); 307 308 WaitForChildren w = new WaitForChildren(proxy); 310 w.waitFor(1); 311 312 assertEquals("source", proxy, ml.se.getSource()); 313 314 assertEquals("child", myChild.toString(), ml.se.getChild().toString()); 317 assertEquals("index", 0, ml.se.getIndex()); 318 319 mb.rc(cName); 320 321 w.waitFor(0); 323 324 assertEquals("source", proxy, ml.se.getSource()); 325 assertEquals("child", myChild.toString(), ml.se.getChild().toString()); 326 assertEquals("index", 0, ml.se.getIndex()); 327 } 328 329 public void testIconic() 330 throws Exception { 331 class MyIconListener implements IconListener { 332 IconEvent ie; 333 public void iconEvent(IconEvent event) { 334 ie = event; 335 } 336 }; 337 MyIconListener ml = new MyIconListener(); 338 339 MockIconic mb = new MockIconic(); 340 341 MBeanServer mbs = MBeanServerFactory.createMBeanServer(); 342 ObjectName on = new ObjectName ("oddjob:name=whatever"); 343 mbs.registerMBean(mb, on); 344 345 Object proxy = ClientNode.createProxyFor(on, mbs, this, cr, 346 new DummyNP()); 347 assertTrue("Iconic", proxy instanceof Iconic); 348 349 ((Iconic)proxy).addIconListener(ml); 350 mb.foo(); 351 352 assertEquals("source", proxy, ml.ie.getSource()); 353 assertEquals("id", "foo", ml.ie.getIconId()); 354 assertEquals("tool tip", "foo", ((Iconic)proxy).iconForId("foo").getToolTip()); 355 } 356 357 359 public static class Fred implements Serializable { 361 private static final long serialVersionUID = 20051117; 362 public String getFruit() { 363 return "apples"; 364 } 365 } 366 367 public class MyDC implements DynaClass, Serializable { 369 private static final long serialVersionUID = 20051117; 370 public DynaProperty[] getDynaProperties() { 371 return new DynaProperty[] { 372 new DynaProperty("fred", Fred.class), 373 }; 375 } 376 public DynaProperty getDynaProperty(String arg0) { 377 return new DynaProperty(arg0); 378 } 379 public String getName() { 380 return "MyDynaClass"; 381 } 382 public DynaBean newInstance() throws IllegalAccessException , InstantiationException { 383 throw new UnsupportedOperationException ("newInstance"); 384 } 385 } 386 387 public class Bean implements DynaBean { 388 public boolean contains(String name, String key) { 389 logger.debug("contains(" + name + ", " + key + ")"); 390 return false; 391 } 392 public Object get(String name) { 393 logger.debug("get(" + name + ")"); 394 if ("fred".equals(name)) { 395 return new Fred(); 396 } 397 else if ("description".equals(name)) { 398 Map m = new HashMap (); 399 m.put("fooled", "you"); 400 return m; 401 } 402 return null; 403 } 404 public Object get(String name, int index) { 405 logger.debug("get(" + name + ", " + index + ")"); 406 return null; 407 } 408 public Object get(String name, String key) { 409 logger.debug("get(" + name + ", " + key + ")"); 410 return null; 411 } 412 public DynaClass getDynaClass() { 413 logger.debug("getDynaClass"); 414 return new MyDC(); 415 } 416 public void remove(String name, String key) { 417 logger.debug("remove(" + name + ", " + key + ")"); 418 } 419 public void set(String name, int index, Object value) { 420 logger.debug("set(" + name + ", " + index + ", " + value + ")"); 421 } 422 423 public void set(String name, Object value) { 424 logger.debug("set(" + name + ", " + value + ")"); 425 } 426 427 public void set(String name, String key, Object value) { 428 logger.debug("set(" + name + ", " + key + ", " + value + ")"); 429 } 430 } 431 432 public class MyDynamicMBean extends NotificationBroadcasterSupport implements DynamicMBean { 433 public Object getAttribute(String attribute) throws AttributeNotFoundException , MBeanException , ReflectionException { 434 logger.debug("MyDynamicMBean getting attribute [" + attribute + "]"); 435 throw new UnsupportedOperationException (); 436 } 437 public AttributeList getAttributes(String [] attributes) { 438 return null; 439 } 440 public MBeanInfo getMBeanInfo() { 441 return new MBeanInfo (this.getClass().getName(), 442 "Test MBean", 443 new MBeanAttributeInfo [0], 444 new MBeanConstructorInfo [0], 445 new MBeanOperationInfo [0], 446 new MBeanNotificationInfo [0]); 447 } 448 public Object invoke(String actionName, Object [] arguments, String [] signature) throws MBeanException , ReflectionException { 449 logger.debug("MyDynamicMBean invoking [" + actionName + "]"); 450 if ("toString".equals(actionName)) { 451 return "MyDynamicMBean"; 452 } else if ("resync".equals(actionName)){ 453 sendNotification(new Notification (OddjobMBean.RESYNC_STARTED_NOTIF_TYPE, this, 0)); 454 sendNotification(new Notification (OddjobMBean.RESYNC_FINISHED_NOTIF_TYPE, this, 0)); 455 return null; 456 } else if (SharedConstants.SERVER_INFO_METHOD.equals(actionName)){ 457 return new ServerInfo("foo", 458 "//foo/", "foo", 459 new Class [] { DynaBean.class }, 460 true, "foo2"); 461 } else if ("toString".equals(actionName)){ 462 return "MyDynamicMBean"; 463 } else if ("getDynaClass".equals(actionName)) { 464 return new MyDC(); 465 } else if ("get".equals(actionName)) { 466 return new Fred(); 467 } else { 468 throw new MBeanException ( 469 new UnsupportedOperationException ("Unsupported Method [" + actionName + "]")); 470 } 471 } 472 public void setAttribute(Attribute attribute) throws AttributeNotFoundException , InvalidAttributeValueException , MBeanException , ReflectionException { 473 throw new UnsupportedOperationException (); 474 } 475 public AttributeList setAttributes(AttributeList attributes) { 476 throw new UnsupportedOperationException (); 477 } 478 479 } 480 481 public void testSimpleGet() throws Exception { 483 MyDynamicMBean mb = new MyDynamicMBean(); 484 MBeanServer mbs = MBeanServerFactory.createMBeanServer(); 485 ObjectName on = new ObjectName ("oddjob:name=whatever"); 486 mbs.registerMBean(mb, on); 487 488 Object proxy = ClientNode.createProxyFor(on, mbs, this, cr, 489 new DummyNP()); 490 491 BeanUtilsBeanHelper bubh = new BeanUtilsBeanHelper( 492 BeanUtilsBean.getInstance()); 493 494 String fruit = (String ) bubh.getProperty(proxy, "fred.fruit"); 495 assertEquals("apples", fruit); 496 497 RegistryLookup lookup = new DefaultRegistryLookup(cr); 499 Object result; 500 result = lookup.getProperty("this/foo.fred.fruit"); 502 fruit = (String ) result; 503 assertEquals("apples", fruit); 504 505 ObjectName on2 = new ObjectName ("oddjob:name=whatever2"); 508 mbs.registerMBean(mb, on2); 509 ClientNode.createProxyFor(on2, (ClientNode) 510 Proxy.getInvocationHandler(proxy)); 511 fruit = (String ) lookup.getProperty("this/foo/foo2.fred.fruit"); 512 assertEquals("apples", fruit); 513 } 514 515 public void testBean() throws Exception { 517 Object o = new Bean (); 518 ServerModel sm = new ServerModel( 519 "//whatever", 520 new ThreadManager(), 521 new InterfaceManagerFactory()); 522 sm.setRoot(o); 523 ServerContext srvcon = new ServerContext(sm); 524 OddjobMBean mb = new OddjobMBean(o, null, srvcon); 525 526 MBeanServer mbs = MBeanServerFactory.createMBeanServer(); 527 ObjectName on = new ObjectName ("oddjob:name=whatever"); 528 mbs.registerMBean(mb, on); 529 530 Object proxy = ClientNode.createProxyFor(on, mbs, this, cr, 531 new DummyNP()); 532 assertNotNull(proxy); 533 534 Map map = Describer.describe(proxy); 535 assertNotNull(map); 536 537 logger.debug("Describe:\n" + MapType.propertiesFrom(map)); 538 539 BeanUtilsBeanHelper bubh = new BeanUtilsBeanHelper( 540 BeanUtilsBean.getInstance()); 541 542 Object gotten = bubh.getProperty(proxy, "fred.fruit", String .class); 543 assertEquals("apples", gotten); 544 } 545 546 548 static void beanDump(MBeanServer mbs, ObjectName on) 549 throws ReflectionException , InstanceNotFoundException , IntrospectionException { 550 MBeanInfo info = mbs.getMBeanInfo(on); 551 MBeanOperationInfo [] opInfo = info.getOperations(); 552 for (int i = 0; i < opInfo.length; ++i) { 553 logger.debug("Op: " + opInfo[i].getName()); 554 } 555 MBeanAttributeInfo [] atInfo = info.getAttributes(); 556 for (int i = 0; i < opInfo.length; ++i) { 557 logger.debug("At: " + atInfo[i].getName()); 558 } 559 } 560 } 561 | Popular Tags |