1 /* 2 * Copyright (c) 2005, 2015, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @bug 6175517 6278707 6318827 6305746 6392303 6600709 8010285 27 * @summary General MXBean test. 28 * @author Eamonn McManus 29 * @author Jaroslav Bachorik 30 * @modules java.management.rmi 31 * @run clean MXBeanTest MerlinMXBean TigerMXBean 32 * @run build MXBeanTest MerlinMXBean TigerMXBean 33 * @run main MXBeanTest 34 */ 35 36 import java.lang.reflect.Array; 37 import java.lang.reflect.Field; 38 import java.lang.reflect.InvocationHandler; 39 import java.lang.reflect.Method; 40 import java.lang.reflect.Proxy; 41 import java.util.Arrays; 42 import java.util.Collection; 43 import java.util.HashMap; 44 import java.util.Iterator; 45 import java.util.Map; 46 import java.util.SortedMap; 47 import javax.management.JMX; 48 import javax.management.MBeanAttributeInfo; 49 import javax.management.MBeanInfo; 50 import javax.management.MBeanOperationInfo; 51 import javax.management.MBeanParameterInfo; 52 import javax.management.MBeanServer; 53 import javax.management.MBeanServerConnection; 54 import javax.management.MBeanServerFactory; 55 import javax.management.MBeanServerInvocationHandler; 56 import javax.management.NotCompliantMBeanException; 57 import javax.management.ObjectName; 58 import javax.management.StandardMBean; 59 import javax.management.openmbean.ArrayType; 60 import javax.management.openmbean.CompositeData; 61 import javax.management.openmbean.CompositeDataInvocationHandler; 62 import javax.management.openmbean.OpenType; 63 import javax.management.openmbean.SimpleType; 64 import javax.management.openmbean.TabularData; 65 import javax.management.openmbean.TabularType; 66 import javax.management.remote.JMXConnector; 67 import javax.management.remote.JMXConnectorFactory; 68 import javax.management.remote.JMXConnectorServer; 69 import javax.management.remote.JMXConnectorServerFactory; 70 import javax.management.remote.JMXServiceURL; 71 72 public class MXBeanTest { main(String[] args)73 public static void main(String[] args) throws Exception { 74 testInterface(MerlinMXBean.class, false); 75 testInterface(TigerMXBean.class, false); 76 testInterface(MerlinMXBean.class, true); 77 testInterface(TigerMXBean.class, true); 78 testExplicitMXBean(); 79 testSubclassMXBean(); 80 testIndirectMXBean(); 81 testNonCompliantMXBean("Private", new Private()); 82 testNonCompliantMXBean("NonCompliant", new NonCompliant()); 83 84 if (failures == 0) 85 System.out.println("Test passed"); 86 else 87 throw new Exception("TEST FAILURES: " + failures); 88 } 89 90 private static int failures = 0; 91 92 private static interface PrivateMXBean { getInts()93 public int[] getInts(); 94 } 95 96 public static class Private implements PrivateMXBean { getInts()97 public int[] getInts() { 98 return new int[]{1,2,3}; 99 } 100 } 101 102 public static interface NonCompliantMXBean { getInt()103 public boolean getInt(); isInt()104 public boolean isInt(); setInt(int a)105 public void setInt(int a); setInt(long b)106 public void setInt(long b); 107 } 108 109 public static class NonCompliant implements NonCompliantMXBean { getInt()110 public boolean getInt() { 111 return false; 112 } 113 isInt()114 public boolean isInt() { 115 return true; 116 } 117 setInt(int a)118 public void setInt(int a) { 119 } 120 setInt(long b)121 public void setInt(long b) { 122 } 123 } 124 125 public static interface ExplicitMXBean { getInts()126 public int[] getInts(); 127 } 128 public static class Explicit implements ExplicitMXBean { getInts()129 public int[] getInts() { 130 return new int[] {1, 2, 3}; 131 } 132 } 133 public static class Subclass 134 extends StandardMBean 135 implements ExplicitMXBean { Subclass()136 public Subclass() { 137 super(ExplicitMXBean.class, true); 138 } 139 getInts()140 public int[] getInts() { 141 return new int[] {1, 2, 3}; 142 } 143 } 144 public static interface IndirectInterface extends ExplicitMXBean {} 145 public static class Indirect implements IndirectInterface { getInts()146 public int[] getInts() { 147 return new int[] {1, 2, 3}; 148 } 149 } 150 testNonCompliantMXBean(String type, Object bean)151 private static void testNonCompliantMXBean(String type, Object bean) throws Exception { 152 System.out.println(type + " MXBean test..."); 153 MBeanServer mbs = MBeanServerFactory.newMBeanServer(); 154 ObjectName on = new ObjectName("test:type=" + type); 155 try { 156 mbs.registerMBean(bean, on); 157 failure(bean.getClass().getInterfaces()[0].getName() + " is not a compliant " 158 + "MXBean interface"); 159 } catch (NotCompliantMBeanException e) { 160 success("Non-compliant MXBean not registered"); 161 } 162 } 163 testExplicitMXBean()164 private static void testExplicitMXBean() throws Exception { 165 System.out.println("Explicit MXBean test..."); 166 MBeanServer mbs = MBeanServerFactory.newMBeanServer(); 167 ObjectName on = new ObjectName("test:type=Explicit"); 168 Explicit explicit = new Explicit(); 169 mbs.registerMBean(explicit, on); 170 testMXBean(mbs, on); 171 } 172 testSubclassMXBean()173 private static void testSubclassMXBean() throws Exception { 174 System.out.println("Subclass MXBean test..."); 175 MBeanServer mbs = MBeanServerFactory.newMBeanServer(); 176 ObjectName on = new ObjectName("test:type=Subclass"); 177 Subclass subclass = new Subclass(); 178 mbs.registerMBean(subclass, on); 179 testMXBean(mbs, on); 180 } 181 testIndirectMXBean()182 private static void testIndirectMXBean() throws Exception { 183 System.out.println("Indirect MXBean test..."); 184 MBeanServer mbs = MBeanServerFactory.newMBeanServer(); 185 ObjectName on = new ObjectName("test:type=Indirect"); 186 Indirect indirect = new Indirect(); 187 mbs.registerMBean(indirect, on); 188 testMXBean(mbs, on); 189 } 190 testMXBean(MBeanServer mbs, ObjectName on)191 private static void testMXBean(MBeanServer mbs, ObjectName on) 192 throws Exception { 193 MBeanInfo mbi = mbs.getMBeanInfo(on); 194 MBeanAttributeInfo[] attrs = mbi.getAttributes(); 195 int nattrs = attrs.length; 196 if (mbi.getAttributes().length != 1) 197 failure("wrong number of attributes: " + attrs); 198 else { 199 MBeanAttributeInfo mbai = attrs[0]; 200 if (mbai.getName().equals("Ints") 201 && mbai.isReadable() && !mbai.isWritable() 202 && mbai.getDescriptor().getFieldValue("openType") 203 .equals(new ArrayType<int[]>(SimpleType.INTEGER, true)) 204 && attrs[0].getType().equals("[I")) 205 success("MBeanAttributeInfo"); 206 else 207 failure("MBeanAttributeInfo: " + mbai); 208 } 209 210 int[] ints = (int[]) mbs.getAttribute(on, "Ints"); 211 if (equal(ints, new int[] {1, 2, 3}, null)) 212 success("getAttribute"); 213 else 214 failure("getAttribute: " + Arrays.toString(ints)); 215 216 ExplicitMXBean proxy = 217 JMX.newMXBeanProxy(mbs, on, ExplicitMXBean.class); 218 int[] pints = proxy.getInts(); 219 if (equal(pints, new int[] {1, 2, 3}, null)) 220 success("getAttribute through proxy"); 221 else 222 failure("getAttribute through proxy: " + Arrays.toString(pints)); 223 } 224 225 private static class NamedMXBeans extends HashMap<ObjectName, Object> { 226 private static final long serialVersionUID = 0; 227 NamedMXBeans(MBeanServerConnection mbsc)228 NamedMXBeans(MBeanServerConnection mbsc) { 229 this.mbsc = mbsc; 230 } 231 getMBeanServerConnection()232 MBeanServerConnection getMBeanServerConnection() { 233 return mbsc; 234 } 235 236 private final MBeanServerConnection mbsc; 237 } 238 239 /* This is the core of the test. Given the MXBean interface c, we 240 make an MXBean object that implements that interface by 241 constructing a dynamic proxy. If the interface defines an 242 attribute Foo (with getFoo and setFoo methods), then it must 243 also contain a field (constant) Foo of the same type, and a 244 field (constant) FooType that is an OpenType. The field Foo is 245 a reference value for this case. We check that the attribute 246 does indeed have the given OpenType. The dynamically-created 247 MXBean will return the reference value from the getFoo() 248 method, and we check that that value survives the mapping to 249 open values and back when the attribute is accessed through an 250 MXBean proxy. The MXBean will also check in its setFoo method 251 that the value being set is equal to the reference value, which 252 tests that the mapping and unmapping also works in the other 253 direction. The interface should define an operation opFoo with 254 two parameters and a return value all of the same type as the 255 attribute. The MXBean will check that the two parameters are 256 equal to the reference value, and will return that value. The 257 test checks that calling the operation through an MXBean proxy 258 returns the reference value, again after mapping to and back 259 from open values. 260 261 If any field (constant) in the MXBean interface has a name that 262 ends with ObjectName, say FooObjectName, then its value must be 263 a String containing an ObjectName value. There must be a field 264 (constant) called Foo that is a valid MXBean, and that MXBean 265 will be registered in the MBean Server with the given name before 266 the test starts. This enables us to test that inter-MXBean 267 references are correctly converted to ObjectNames and back. 268 */ testInterface(Class<T> c, boolean nullTest)269 private static <T> void testInterface(Class<T> c, boolean nullTest) 270 throws Exception { 271 272 System.out.println("Testing " + c.getName() + 273 (nullTest ? " for null values" : "") + "..."); 274 275 MBeanServer mbs = MBeanServerFactory.newMBeanServer(); 276 277 JMXServiceURL url = new JMXServiceURL("rmi", null, 0); 278 JMXConnectorServer cs = 279 JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs); 280 cs.start(); 281 JMXServiceURL addr = cs.getAddress(); 282 JMXConnector cc = JMXConnectorFactory.connect(addr); 283 MBeanServerConnection mbsc = cc.getMBeanServerConnection(); 284 285 NamedMXBeans namedMXBeans = new NamedMXBeans(mbsc); 286 InvocationHandler ih = 287 nullTest ? new MXBeanNullImplInvocationHandler(c, namedMXBeans) : 288 new MXBeanImplInvocationHandler(c, namedMXBeans); 289 T impl = c.cast(Proxy.newProxyInstance(c.getClassLoader(), 290 new Class[] {c}, 291 ih)); 292 ObjectName on = new ObjectName("test:type=" + c.getName()); 293 mbs.registerMBean(impl, on); 294 295 System.out.println("Register any MXBeans..."); 296 297 Field[] fields = c.getFields(); 298 for (Field field : fields) { 299 String n = field.getName(); 300 if (n.endsWith("ObjectName")) { 301 String objectNameString = (String) field.get(null); 302 String base = n.substring(0, n.length() - 10); 303 Field f = c.getField(base); 304 Object mxbean = f.get(null); 305 ObjectName objectName = 306 ObjectName.getInstance(objectNameString); 307 mbs.registerMBean(mxbean, objectName); 308 namedMXBeans.put(objectName, mxbean); 309 } 310 } 311 312 try { 313 testInterface(c, mbsc, on, namedMXBeans, nullTest); 314 } finally { 315 try { 316 cc.close(); 317 } finally { 318 cs.stop(); 319 } 320 } 321 } 322 testInterface(Class<T> c, MBeanServerConnection mbsc, ObjectName on, NamedMXBeans namedMXBeans, boolean nullTest)323 private static <T> void testInterface(Class<T> c, 324 MBeanServerConnection mbsc, 325 ObjectName on, 326 NamedMXBeans namedMXBeans, 327 boolean nullTest) 328 throws Exception { 329 330 System.out.println("Type check..."); 331 332 MBeanInfo mbi = mbsc.getMBeanInfo(on); 333 MBeanAttributeInfo[] mbais = mbi.getAttributes(); 334 for (int i = 0; i < mbais.length; i++) { 335 MBeanAttributeInfo mbai = mbais[i]; 336 String name = mbai.getName(); 337 Field typeField = c.getField(name + "Type"); 338 OpenType typeValue = (OpenType) typeField.get(null); 339 OpenType openType = 340 (OpenType) mbai.getDescriptor().getFieldValue("openType"); 341 if (typeValue.equals(openType)) 342 success("attribute " + name); 343 else { 344 final String msg = 345 "Wrong type attribute " + name + ": " + 346 openType + " should be " + typeValue; 347 failure(msg); 348 } 349 } 350 351 MBeanOperationInfo[] mbois = mbi.getOperations(); 352 for (int i = 0; i < mbois.length; i++) { 353 MBeanOperationInfo mboi = mbois[i]; 354 String oname = mboi.getName(); 355 if (!oname.startsWith("op")) 356 throw new Error(); 357 OpenType retType = 358 (OpenType) mboi.getDescriptor().getFieldValue("openType"); 359 MBeanParameterInfo[] params = mboi.getSignature(); 360 MBeanParameterInfo p1i = params[0]; 361 MBeanParameterInfo p2i = params[1]; 362 OpenType p1Type = 363 (OpenType) p1i.getDescriptor().getFieldValue("openType"); 364 OpenType p2Type = 365 (OpenType) p2i.getDescriptor().getFieldValue("openType"); 366 if (!retType.equals(p1Type) || !p1Type.equals(p2Type)) { 367 final String msg = 368 "Parameter and return open types should all be same " + 369 "but are not: " + retType + " " + oname + "(" + p1Type + 370 ", " + p2Type + ")"; 371 failure(msg); 372 continue; 373 } 374 String name = oname.substring(2); 375 Field typeField = c.getField(name + "Type"); 376 OpenType typeValue = (OpenType) typeField.get(null); 377 if (typeValue.equals(retType)) 378 success("operation " + oname); 379 else { 380 final String msg = 381 "Wrong type operation " + oname + ": " + 382 retType + " should be " + typeValue; 383 failure(msg); 384 } 385 } 386 387 388 System.out.println("Mapping check..."); 389 390 Object proxy = 391 JMX.newMXBeanProxy(mbsc, on, c); 392 393 Method[] methods = c.getMethods(); 394 for (int i = 0; i < methods.length; i++) { 395 final Method method = methods[i]; 396 if (method.getDeclaringClass() != c) 397 continue; // skip hashCode() etc inherited from Object 398 final String mname = method.getName(); 399 final int what = getType(method); 400 final String name = getName(method); 401 final Field refField = c.getField(name); 402 if (nullTest && refField.getType().isPrimitive()) 403 continue; 404 final Field openTypeField = c.getField(name + "Type"); 405 final OpenType openType = (OpenType) openTypeField.get(null); 406 final Object refValue = nullTest ? null : refField.get(null); 407 Object setValue = refValue; 408 try { 409 Field onField = c.getField(name + "ObjectName"); 410 String refName = (String) onField.get(null); 411 ObjectName refObjName = ObjectName.getInstance(refName); 412 Class<?> mxbeanInterface = refField.getType(); 413 setValue = nullTest ? null : 414 JMX.newMXBeanProxy(mbsc, refObjName, mxbeanInterface); 415 } catch (Exception e) { 416 // no xObjectName field, setValue == refValue 417 } 418 boolean ok = true; 419 try { 420 switch (what) { 421 case GET: 422 final Object gotOpen = mbsc.getAttribute(on, name); 423 if (nullTest) { 424 if (gotOpen != null) { 425 failure(mname + " got non-null value " + 426 gotOpen); 427 ok = false; 428 } 429 } else if (!openType.isValue(gotOpen)) { 430 if (gotOpen instanceof TabularData) { 431 // detail the mismatch 432 TabularData gotTabular = (TabularData) gotOpen; 433 compareTabularType((TabularType) openType, 434 gotTabular.getTabularType()); 435 } 436 failure(mname + " got open data " + gotOpen + 437 " not valid for open type " + openType); 438 ok = false; 439 } 440 final Object got = method.invoke(proxy, (Object[]) null); 441 if (!equal(refValue, got, namedMXBeans)) { 442 failure(mname + " got " + string(got) + 443 ", should be " + string(refValue)); 444 ok = false; 445 } 446 break; 447 448 case SET: 449 method.invoke(proxy, new Object[] {setValue}); 450 break; 451 452 case OP: 453 final Object opped = 454 method.invoke(proxy, new Object[] {setValue, setValue}); 455 if (!equal(refValue, opped, namedMXBeans)) { 456 failure( 457 mname + " got " + string(opped) + 458 ", should be " + string(refValue) 459 ); 460 ok = false; 461 } 462 break; 463 464 default: 465 throw new Error(); 466 } 467 468 if (ok) 469 success(mname); 470 471 } catch (Exception e) { 472 failure(mname, e); 473 } 474 } 475 } 476 477 success(String what)478 private static void success(String what) { 479 System.out.println("OK: " + what); 480 } 481 failure(String what)482 private static void failure(String what) { 483 System.out.println("FAILED: " + what); 484 failures++; 485 } 486 failure(String what, Exception e)487 private static void failure(String what, Exception e) { 488 System.out.println("FAILED WITH EXCEPTION: " + what); 489 e.printStackTrace(System.out); 490 failures++; 491 } 492 493 private static class MXBeanImplInvocationHandler 494 implements InvocationHandler { MXBeanImplInvocationHandler(Class intf, NamedMXBeans namedMXBeans)495 MXBeanImplInvocationHandler(Class intf, NamedMXBeans namedMXBeans) { 496 this.intf = intf; 497 this.namedMXBeans = namedMXBeans; 498 } 499 invoke(Object proxy, Method method, Object[] args)500 public Object invoke(Object proxy, Method method, Object[] args) 501 throws Throwable { 502 final String mname = method.getName(); 503 final int what = getType(method); 504 final String name = getName(method); 505 final Field refField = intf.getField(name); 506 final Object refValue = getRefValue(refField); 507 508 switch (what) { 509 case GET: 510 assert args == null; 511 return refValue; 512 513 case SET: 514 assert args.length == 1; 515 Object setValue = args[0]; 516 if (!equal(refValue, setValue, namedMXBeans)) { 517 final String msg = 518 mname + "(" + string(setValue) + 519 ") does not match ref: " + string(refValue); 520 throw new IllegalArgumentException(msg); 521 } 522 return null; 523 524 case OP: 525 assert args.length == 2; 526 Object arg1 = args[0]; 527 Object arg2 = args[1]; 528 if (!equal(arg1, arg2, namedMXBeans)) { 529 final String msg = 530 mname + "(" + string(arg1) + ", " + string(arg2) + 531 "): args not equal"; 532 throw new IllegalArgumentException(msg); 533 } 534 if (!equal(refValue, arg1, namedMXBeans)) { 535 final String msg = 536 mname + "(" + string(arg1) + ", " + string(arg2) + 537 "): args do not match ref: " + string(refValue); 538 throw new IllegalArgumentException(msg); 539 } 540 return refValue; 541 default: 542 throw new Error(); 543 } 544 } 545 getRefValue(Field refField)546 Object getRefValue(Field refField) throws Exception { 547 return refField.get(null); 548 } 549 550 private final Class intf; 551 private final NamedMXBeans namedMXBeans; 552 } 553 554 private static class MXBeanNullImplInvocationHandler 555 extends MXBeanImplInvocationHandler { MXBeanNullImplInvocationHandler(Class intf, NamedMXBeans namedMXBeans)556 MXBeanNullImplInvocationHandler(Class intf, NamedMXBeans namedMXBeans) { 557 super(intf, namedMXBeans); 558 } 559 560 @Override getRefValue(Field refField)561 Object getRefValue(Field refField) throws Exception { 562 Class<?> type = refField.getType(); 563 if (type.isPrimitive()) 564 return super.getRefValue(refField); 565 else 566 return null; 567 } 568 } 569 570 571 private static final String[] prefixes = { 572 "get", "set", "op", 573 }; 574 private static final int GET = 0, SET = 1, OP = 2; 575 getName(Method m)576 private static String getName(Method m) { 577 return getName(m.getName()); 578 } 579 getName(String n)580 private static String getName(String n) { 581 for (int i = 0; i < prefixes.length; i++) { 582 if (n.startsWith(prefixes[i])) 583 return n.substring(prefixes[i].length()); 584 } 585 throw new Error(); 586 } 587 getType(Method m)588 private static int getType(Method m) { 589 return getType(m.getName()); 590 } 591 getType(String n)592 private static int getType(String n) { 593 for (int i = 0; i < prefixes.length; i++) { 594 if (n.startsWith(prefixes[i])) 595 return i; 596 } 597 throw new Error(); 598 } 599 equal(Object o1, Object o2, NamedMXBeans namedMXBeans)600 static boolean equal(Object o1, Object o2, NamedMXBeans namedMXBeans) { 601 if (o1 == o2) 602 return true; 603 if (o1 == null || o2 == null) 604 return false; 605 if (o1.getClass().isArray()) { 606 if (!o2.getClass().isArray()) 607 return false; 608 return deepEqual(o1, o2, namedMXBeans); 609 } 610 if (o1 instanceof Map) { 611 if (!(o2 instanceof Map)) 612 return false; 613 return equalMap((Map) o1, (Map) o2, namedMXBeans); 614 } 615 if (o1 instanceof CompositeData && o2 instanceof CompositeData) { 616 return compositeDataEqual((CompositeData) o1, (CompositeData) o2, 617 namedMXBeans); 618 } 619 if (Proxy.isProxyClass(o1.getClass())) { 620 if (Proxy.isProxyClass(o2.getClass())) 621 return proxyEqual(o1, o2, namedMXBeans); 622 InvocationHandler ih = Proxy.getInvocationHandler(o1); 623 // if (ih instanceof MXBeanInvocationHandler) { 624 // return proxyEqualsObject((MXBeanInvocationHandler) ih, 625 // o2, namedMXBeans); 626 if (ih instanceof MBeanServerInvocationHandler) { 627 return true; 628 } else if (ih instanceof CompositeDataInvocationHandler) { 629 return o2.equals(o1); 630 // We assume the other object has a reasonable equals method 631 } 632 } else if (Proxy.isProxyClass(o2.getClass())) 633 return equal(o2, o1, namedMXBeans); 634 return o1.equals(o2); 635 } 636 637 // We'd use Arrays.deepEquals except we want the test to work on 1.4 638 // Note this code assumes no selfreferential arrays 639 // (as does Arrays.deepEquals) deepEqual(Object a1, Object a2, NamedMXBeans namedMXBeans)640 private static boolean deepEqual(Object a1, Object a2, 641 NamedMXBeans namedMXBeans) { 642 int len = Array.getLength(a1); 643 if (len != Array.getLength(a2)) 644 return false; 645 for (int i = 0; i < len; i++) { 646 Object e1 = Array.get(a1, i); 647 Object e2 = Array.get(a2, i); 648 if (!equal(e1, e2, namedMXBeans)) 649 return false; 650 } 651 return true; 652 } 653 equalMap(Map<?,?> m1, Map<?,?> m2, NamedMXBeans namedMXBeans)654 private static boolean equalMap(Map<?,?> m1, Map<?,?> m2, 655 NamedMXBeans namedMXBeans) { 656 if (m1.size() != m2.size()) 657 return false; 658 if ((m1 instanceof SortedMap) != (m2 instanceof SortedMap)) 659 return false; 660 for (Object k1 : m1.keySet()) { 661 if (!m2.containsKey(k1)) 662 return false; 663 if (!equal(m1.get(k1), m2.get(k1), namedMXBeans)) 664 return false; 665 } 666 return true; 667 } 668 669 // This is needed to work around a bug (5095277) 670 // in CompositeDataSupport.equals compositeDataEqual(CompositeData cd1, CompositeData cd2, NamedMXBeans namedMXBeans)671 private static boolean compositeDataEqual(CompositeData cd1, 672 CompositeData cd2, 673 NamedMXBeans namedMXBeans) { 674 if (cd1 == cd2) 675 return true; 676 if (!cd1.getCompositeType().equals(cd2.getCompositeType())) 677 return false; 678 Collection v1 = cd1.values(); 679 Collection v2 = cd2.values(); 680 if (v1.size() != v2.size()) 681 return false; // should not happen 682 for (Iterator i1 = v1.iterator(), i2 = v2.iterator(); 683 i1.hasNext(); ) { 684 if (!equal(i1.next(), i2.next(), namedMXBeans)) 685 return false; 686 } 687 return true; 688 } 689 690 // Also needed for 5095277 proxyEqual(Object proxy1, Object proxy2, NamedMXBeans namedMXBeans)691 private static boolean proxyEqual(Object proxy1, Object proxy2, 692 NamedMXBeans namedMXBeans) { 693 if (proxy1.getClass() != proxy2.getClass()) 694 return proxy1.equals(proxy2); 695 InvocationHandler ih1 = Proxy.getInvocationHandler(proxy1); 696 InvocationHandler ih2 = Proxy.getInvocationHandler(proxy2); 697 if (!(ih1 instanceof CompositeDataInvocationHandler) 698 || !(ih2 instanceof CompositeDataInvocationHandler)) 699 return proxy1.equals(proxy2); 700 CompositeData cd1 = 701 ((CompositeDataInvocationHandler) ih1).getCompositeData(); 702 CompositeData cd2 = 703 ((CompositeDataInvocationHandler) ih2).getCompositeData(); 704 return compositeDataEqual(cd1, cd2, namedMXBeans); 705 } 706 707 // private static boolean proxyEqualsObject(MXBeanInvocationHandler ih, 708 // Object o, 709 // NamedMXBeans namedMXBeans) { 710 // if (namedMXBeans.getMBeanServerConnection() != 711 // ih.getMBeanServerConnection()) 712 // return false; 713 // 714 // ObjectName on = ih.getObjectName(); 715 // Object named = namedMXBeans.get(on); 716 // if (named == null) 717 // return false; 718 // return (o == named && ih.getMXBeanInterface().isInstance(named)); 719 // } 720 721 /* I wanted to call this method toString(Object), but oddly enough 722 this meant that I couldn't call it from the inner class 723 MXBeanImplInvocationHandler, because the inherited Object.toString() 724 prevented that. */ string(Object o)725 static String string(Object o) { 726 if (o == null) 727 return "null"; 728 if (o instanceof String) 729 return '"' + (String) o + '"'; 730 if (o instanceof Collection) 731 return deepToString((Collection) o); 732 if (o.getClass().isArray()) 733 return deepToString(o); 734 return o.toString(); 735 } 736 deepToString(Object o)737 private static String deepToString(Object o) { 738 StringBuffer buf = new StringBuffer(); 739 buf.append("["); 740 int len = Array.getLength(o); 741 for (int i = 0; i < len; i++) { 742 if (i > 0) 743 buf.append(", "); 744 Object e = Array.get(o, i); 745 buf.append(string(e)); 746 } 747 buf.append("]"); 748 return buf.toString(); 749 } 750 deepToString(Collection c)751 private static String deepToString(Collection c) { 752 return deepToString(c.toArray()); 753 } 754 compareTabularType(TabularType t1, TabularType t2)755 private static void compareTabularType(TabularType t1, TabularType t2) { 756 if (t1.equals(t2)) { 757 System.out.println("same tabular type"); 758 return; 759 } 760 if (t1.getClassName().equals(t2.getClassName())) 761 System.out.println("same class name"); 762 if (t1.getDescription().equals(t2.getDescription())) 763 System.out.println("same description"); 764 else { 765 System.out.println("t1 description: " + t1.getDescription()); 766 System.out.println("t2 description: " + t2.getDescription()); 767 } 768 if (t1.getIndexNames().equals(t2.getIndexNames())) 769 System.out.println("same index names"); 770 if (t1.getRowType().equals(t2.getRowType())) 771 System.out.println("same row type"); 772 } 773 } 774