1 /* 2 * Copyright (c) 2007, 2008, 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 import java.io.IOException; 25 import java.io.ObjectInputStream; 26 import java.io.Serializable; 27 import java.lang.annotation.Retention; 28 import java.lang.annotation.RetentionPolicy; 29 import java.lang.management.ManagementFactory; 30 import java.lang.ref.WeakReference; 31 import java.lang.reflect.AccessibleObject; 32 import java.lang.reflect.Constructor; 33 import java.lang.reflect.InvocationTargetException; 34 import java.lang.reflect.Method; 35 import java.lang.reflect.Modifier; 36 import java.util.ArrayList; 37 import java.util.Arrays; 38 import java.util.HashMap; 39 import java.util.HashSet; 40 import java.util.Iterator; 41 import java.util.List; 42 import java.util.Map; 43 import java.util.Set; 44 import java.util.WeakHashMap; 45 import java.util.concurrent.Callable; 46 import java.util.concurrent.ConcurrentHashMap; 47 import java.util.concurrent.ConcurrentMap; 48 import javax.management.Attribute; 49 import javax.management.AttributeList; 50 import javax.management.AttributeNotFoundException; 51 import javax.management.DynamicMBean; 52 import javax.management.InstanceAlreadyExistsException; 53 import javax.management.InstanceNotFoundException; 54 import javax.management.IntrospectionException; 55 import javax.management.InvalidAttributeValueException; 56 import javax.management.ListenerNotFoundException; 57 import javax.management.MBeanAttributeInfo; 58 import javax.management.MBeanConstructorInfo; 59 import javax.management.MBeanException; 60 import javax.management.MBeanInfo; 61 import javax.management.MBeanNotificationInfo; 62 import javax.management.MBeanOperationInfo; 63 import javax.management.MBeanRegistration; 64 import javax.management.MBeanRegistrationException; 65 import javax.management.MBeanServer; 66 import javax.management.MBeanServerBuilder; 67 import javax.management.MBeanServerConnection; 68 import javax.management.MBeanServerDelegate; 69 import javax.management.MBeanServerFactory; 70 import javax.management.MBeanServerNotification; 71 import javax.management.MalformedObjectNameException; 72 import javax.management.NotCompliantMBeanException; 73 import javax.management.Notification; 74 import javax.management.NotificationBroadcaster; 75 import javax.management.NotificationBroadcasterSupport; 76 import javax.management.NotificationEmitter; 77 import javax.management.NotificationFilter; 78 import javax.management.NotificationListener; 79 import javax.management.ObjectInstance; 80 import javax.management.ObjectName; 81 import javax.management.OperationsException; 82 import javax.management.QueryEval; 83 import javax.management.QueryExp; 84 import javax.management.ReflectionException; 85 import javax.management.RuntimeErrorException; 86 import javax.management.RuntimeMBeanException; 87 import javax.management.StandardMBean; 88 import javax.management.loading.ClassLoaderRepository; 89 import javax.management.remote.JMXConnector; 90 import javax.management.remote.JMXConnectorFactory; 91 import javax.management.remote.JMXConnectorServer; 92 import javax.management.remote.JMXConnectorServerFactory; 93 import javax.management.remote.JMXServiceURL; 94 95 /* 96 * @test OldMBeanServerTest.java 97 * @bug 5072268 98 * @summary Test that nothing assumes a post-1.2 MBeanServer 99 * @author Eamonn McManus 100 * @run main/othervm -ea OldMBeanServerTest 101 */ 102 103 /* 104 * We defined the MBeanServerBuilder class and the associated system 105 * property javax.management.builder.initial in version 1.2 of the JMX 106 * spec. That amounts to a guarantee that someone can set the property 107 * to an MBeanServer that only knows about JMX 1.2 semantics, and if they 108 * only do JMX 1.2 operations, everything should work. This test is a 109 * sanity check that ensures we don't inadvertently make any API changes 110 * that stop that from being true. It includes a complete (if slow) 111 * MBeanServer implementation. That implementation doesn't replicate the 112 * mandated exception behaviour everywhere, though, since there's lots of 113 * arbitrary cruft in that. Also, the behaviour of concurrent unregisterMBean 114 * calls is incorrect in detail. 115 */ 116 117 public class OldMBeanServerTest { 118 private static MBeanServerConnection mbsc; 119 private static String failure; 120 121 public static void main(String[] args) throws Exception { 122 if (!OldMBeanServerTest.class.desiredAssertionStatus()) 123 throw new Exception("Test must be run with -ea"); 124 125 System.setProperty("javax.management.builder.initial", 126 OldMBeanServerBuilder.class.getName()); 127 assert MBeanServerFactory.newMBeanServer() instanceof OldMBeanServer; 128 129 System.out.println("=== RUNNING TESTS WITH LOCAL MBEANSERVER ==="); 130 runTests(new Callable<MBeanServerConnection>() { 131 public MBeanServerConnection call() { 132 return MBeanServerFactory.newMBeanServer(); 133 } 134 }, null); 135 136 System.out.println("=== RUNNING TESTS THROUGH CONNECTOR ==="); 137 ConnectionBuilder builder = new ConnectionBuilder(); 138 runTests(builder, builder); 139 140 if (failure == null) 141 System.out.println("TEST PASSED"); 142 else 143 throw new Exception("TEST FAILED: " + failure); 144 } 145 146 private static class ConnectionBuilder 147 implements Callable<MBeanServerConnection>, Runnable { 148 private JMXConnector connector; 149 public MBeanServerConnection call() { 150 MBeanServer mbs = MBeanServerFactory.newMBeanServer(); 151 try { 152 JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://"); 153 JMXConnectorServer cs = 154 JMXConnectorServerFactory.newJMXConnectorServer( 155 url, null, mbs); 156 cs.start(); 157 JMXServiceURL addr = cs.getAddress(); 158 connector = JMXConnectorFactory.connect(addr); 159 return connector.getMBeanServerConnection(); 160 } catch (IOException e) { 161 throw new RuntimeException(e); 162 } 163 } 164 public void run() { 165 if (connector != null) { 166 try { 167 connector.close(); 168 } catch (IOException e) { 169 throw new RuntimeException(e); 170 } 171 } 172 } 173 } 174 175 private static void runTests( 176 Callable<MBeanServerConnection> maker, Runnable breaker) 177 throws Exception { 178 for (Method m : OldMBeanServerTest.class.getDeclaredMethods()) { 179 if (Modifier.isStatic(m.getModifiers()) && 180 m.getName().startsWith("test") && 181 m.getParameterTypes().length == 0) { 182 ExpectException expexc = m.getAnnotation(ExpectException.class); 183 mbsc = maker.call(); 184 try { 185 m.invoke(null); 186 if (expexc != null) { 187 failure = 188 m.getName() + " did not got expected exception " + 189 expexc.value().getName(); 190 System.out.println(failure); 191 } else 192 System.out.println(m.getName() + " OK"); 193 } catch (InvocationTargetException ite) { 194 Throwable t = ite.getCause(); 195 String prob = null; 196 if (expexc != null) { 197 if (expexc.value().isInstance(t)) { 198 System.out.println(m.getName() + " OK (got expected " + 199 expexc.value().getName() + ")"); 200 } else 201 prob = "got wrong exception"; 202 } else 203 prob = "got exception"; 204 if (prob != null) { 205 failure = m.getName() + ": " + prob + " " + 206 t.getClass().getName(); 207 System.out.println(failure); 208 t.printStackTrace(System.out); 209 } 210 } finally { 211 if (breaker != null) 212 breaker.run(); 213 } 214 } 215 } 216 } 217 218 @Retention(RetentionPolicy.RUNTIME) 219 private static @interface ExpectException { 220 Class<? extends Exception> value(); 221 } 222 223 public static interface BoringMBean { 224 public String getName(); 225 public int add(int x, int y); 226 } 227 228 // This class is Serializable so we can createMBean a StandardMBean 229 // that contains it. Not recommended practice in general -- 230 // should we have a StandardMBean constructor that takes a class 231 // name and constructor parameters? 232 public static class Boring implements BoringMBean, Serializable { 233 public String getName() { 234 return "Jessica"; 235 } 236 237 public int add(int x, int y) { 238 return x + y; 239 } 240 } 241 242 public static interface BoringNotifierMBean extends BoringMBean { 243 public void send(); 244 } 245 246 public static class BoringNotifier 247 extends Boring implements BoringNotifierMBean, NotificationBroadcaster { 248 private final NotificationBroadcasterSupport nbs = 249 new NotificationBroadcasterSupport(); 250 251 public void addNotificationListener( 252 NotificationListener listener, NotificationFilter filter, Object handback) 253 throws IllegalArgumentException { 254 nbs.addNotificationListener(listener, filter, handback); 255 } 256 257 public void removeNotificationListener(NotificationListener listener) 258 throws ListenerNotFoundException { 259 nbs.removeNotificationListener(listener); 260 } 261 262 public MBeanNotificationInfo[] getNotificationInfo() { 263 return null; 264 } 265 266 public void send() { 267 Notification n = new Notification("type.type", this, 0L); 268 nbs.sendNotification(n); 269 } 270 } 271 272 private static class CountListener implements NotificationListener { 273 volatile int count; 274 public void handleNotification(Notification n, Object h) { 275 if (h == null) 276 h = 1; 277 count += (Integer) h; 278 } 279 void waitForCount(int expect) throws InterruptedException { 280 long deadline = System.currentTimeMillis() + 2000L; 281 while (count < expect && System.currentTimeMillis() < deadline) 282 Thread.sleep(1); 283 assert count == expect; 284 } 285 } 286 287 private static void testBasic() throws Exception { 288 CountListener countListener = new CountListener(); 289 mbsc.addNotificationListener( 290 MBeanServerDelegate.DELEGATE_NAME, countListener, null, null); 291 assert countListener.count == 0; 292 ObjectName name = new ObjectName("a:b=c"); 293 if (mbsc instanceof MBeanServer) 294 ((MBeanServer) mbsc).registerMBean(new Boring(), name); 295 else 296 mbsc.createMBean(Boring.class.getName(), name); 297 countListener.waitForCount(1); 298 assert mbsc.isRegistered(name); 299 assert mbsc.queryNames(null, null).contains(name); 300 assert mbsc.getAttribute(name, "Name").equals("Jessica"); 301 assert mbsc.invoke( 302 name, "add", new Object[] {2, 3}, new String[] {"int", "int"}) 303 .equals(5); 304 mbsc.unregisterMBean(name); 305 countListener.waitForCount(2); 306 assert !mbsc.isRegistered(name); 307 assert !mbsc.queryNames(null, null).contains(name); 308 309 mbsc.createMBean(BoringNotifier.class.getName(), name); 310 countListener.waitForCount(3); 311 CountListener boringListener = new CountListener(); 312 class AlwaysNotificationFilter implements NotificationFilter { 313 public boolean isNotificationEnabled(Notification notification) { 314 return true; 315 } 316 } 317 mbsc.addNotificationListener( 318 name, boringListener, new AlwaysNotificationFilter(), 5); 319 mbsc.invoke(name, "send", null, null); 320 boringListener.waitForCount(5); 321 } 322 323 private static void testPrintAttrs() throws Exception { 324 printAttrs(mbsc, null); 325 } 326 327 private static void testPlatformMBeanServer() throws Exception { 328 MBeanServer pmbs = ManagementFactory.getPlatformMBeanServer(); 329 assert pmbs instanceof OldMBeanServer; 330 // Preceding assertion could be violated if at some stage we wrap 331 // the Platform MBeanServer. In that case we can still check that 332 // it is ultimately an OldMBeanServer for example by adding a 333 // counter to getAttribute and checking that it is incremented 334 // when we call pmbs.getAttribute. 335 336 printAttrs(pmbs, UnsupportedOperationException.class); 337 ObjectName memoryMXBeanName = 338 new ObjectName(ManagementFactory.MEMORY_MXBEAN_NAME); 339 pmbs.invoke(memoryMXBeanName, "gc", null, null); 340 } 341 342 private static void printAttrs( 343 MBeanServerConnection mbsc1, Class<? extends Exception> expectX) 344 throws Exception { 345 Set<ObjectName> names = mbsc1.queryNames(null, null); 346 for (ObjectName name : names) { 347 System.out.println(name + ":"); 348 MBeanInfo mbi = mbsc1.getMBeanInfo(name); 349 MBeanAttributeInfo[] mbais = mbi.getAttributes(); 350 for (MBeanAttributeInfo mbai : mbais) { 351 String attr = mbai.getName(); 352 Object value; 353 try { 354 value = mbsc1.getAttribute(name, attr); 355 } catch (Exception e) { 356 if (expectX != null && expectX.isInstance(e)) 357 value = "<" + e + ">"; 358 else 359 throw e; 360 } 361 String s = " " + attr + " = " + value; 362 if (s.length() > 80) 363 s = s.substring(0, 77) + "..."; 364 System.out.println(s); 365 } 366 } 367 } 368 369 private static void testJavaxManagementStandardMBean() throws Exception { 370 ObjectName name = new ObjectName("a:b=c"); 371 Object mbean = new StandardMBean(new Boring(), BoringMBean.class); 372 mbsc.createMBean( 373 StandardMBean.class.getName(), name, 374 new Object[] {new Boring(), BoringMBean.class}, 375 new String[] {Object.class.getName(), Class.class.getName()}); 376 assert mbsc.getAttribute(name, "Name").equals("Jessica"); 377 assert mbsc.invoke( 378 name, "add", new Object[] {2, 3}, new String[] {"int", "int"}) 379 .equals(5); 380 mbsc.unregisterMBean(name); 381 } 382 383 private static void testConnector() throws Exception { 384 } 385 386 public static class OldMBeanServerBuilder extends MBeanServerBuilder { 387 public MBeanServer newMBeanServer( 388 String defaultDomain, MBeanServer outer, MBeanServerDelegate delegate) { 389 return new OldMBeanServer(defaultDomain, delegate); 390 } 391 } 392 393 public static class OldMBeanServer implements MBeanServer { 394 // We pretend there's a ClassLoader MBean representing the Class Loader 395 // Repository and intercept references to it where necessary to keep up 396 // the pretence. This allows us to fake the right behaviour for 397 // the omitted-ClassLoader versions of createMBean and instantiate 398 // (which are not the same as passing a null for the ClassLoader parameter 399 // of the versions that have one). 400 private static final ObjectName clrName; 401 static { 402 try { 403 clrName = 404 new ObjectName("JMImplementation:type=ClassLoaderRepository"); 405 } catch (MalformedObjectNameException e) { 406 throw new RuntimeException(e); 407 } 408 } 409 410 private final ConcurrentMap<ObjectName, DynamicMBean> mbeans = 411 new ConcurrentHashMap<ObjectName, DynamicMBean>(); 412 private final ConcurrentMap<ObjectName, ListenerTable> listenerMap = 413 new ConcurrentHashMap<ObjectName, ListenerTable>(); 414 private final String defaultDomain; 415 private final MBeanServerDelegate delegate; 416 private final ClassLoaderRepositoryImpl clr = 417 new ClassLoaderRepositoryImpl(); 418 419 OldMBeanServer(String defaultDomain, MBeanServerDelegate delegate) { 420 this.defaultDomain = defaultDomain; 421 this.delegate = delegate; 422 try { 423 registerMBean(delegate, MBeanServerDelegate.DELEGATE_NAME); 424 } catch (Exception e) { 425 throw new RuntimeException(e); 426 } 427 } 428 429 public ObjectInstance createMBean(String className, ObjectName name) 430 throws ReflectionException, InstanceAlreadyExistsException, 431 MBeanRegistrationException, MBeanException, 432 NotCompliantMBeanException { 433 return createMBean(className, name, null, null); 434 } 435 436 public ObjectInstance createMBean( 437 String className, ObjectName name, ObjectName loaderName) 438 throws ReflectionException, InstanceAlreadyExistsException, 439 MBeanRegistrationException, MBeanException, 440 NotCompliantMBeanException, InstanceNotFoundException { 441 return createMBean(className, name, loaderName, null, null); 442 } 443 444 public ObjectInstance createMBean( 445 String className, ObjectName name, Object[] params, String[] signature) 446 throws ReflectionException, InstanceAlreadyExistsException, 447 MBeanRegistrationException, MBeanException, 448 NotCompliantMBeanException { 449 try { 450 return createMBean(className, name, clrName, params, signature); 451 } catch (InstanceNotFoundException ex) { 452 throw new RuntimeException(ex); // can't happen 453 } 454 } 455 456 public ObjectInstance createMBean( 457 String className, ObjectName name, ObjectName loaderName, 458 Object[] params, String[] signature) 459 throws ReflectionException, InstanceAlreadyExistsException, 460 MBeanRegistrationException, MBeanException, 461 NotCompliantMBeanException, InstanceNotFoundException { 462 Object mbean = instantiate(className, loaderName, params, signature); 463 return registerMBean(mbean, name); 464 } 465 466 private void forbidJMImpl(ObjectName name) { 467 if (name.getDomain().equals("JMImplementation") && 468 mbeans.containsKey(MBeanServerDelegate.DELEGATE_NAME)) 469 throw new IllegalArgumentException("JMImplementation reserved"); 470 } 471 472 public ObjectInstance registerMBean(Object object, ObjectName name) 473 throws InstanceAlreadyExistsException, MBeanRegistrationException, 474 NotCompliantMBeanException { 475 forbidJMImpl(name); 476 if (name.isPattern()) 477 throw new IllegalArgumentException(name.toString()); 478 // This is the only place we check for wildcards. Since you 479 // can't register a wildcard name, other operations that supply 480 // one will get InstanceNotFoundException when they look it up. 481 482 DynamicMBean mbean; 483 if (object instanceof DynamicMBean) 484 mbean = (DynamicMBean) object; 485 else 486 mbean = standardToDynamic(object); 487 MBeanRegistration reg = mbeanRegistration(object); 488 try { 489 name = reg.preRegister(this, name); 490 } catch (Exception e) { 491 throw new MBeanRegistrationException(e); 492 } 493 DynamicMBean put = mbeans.putIfAbsent(name, mbean); 494 if (put != null) { 495 reg.postRegister(false); 496 throw new InstanceAlreadyExistsException(name.toString()); 497 } 498 reg.postRegister(true); 499 500 if (object instanceof ClassLoader) 501 clr.addLoader((ClassLoader) object); 502 503 Notification n = new MBeanServerNotification( 504 MBeanServerNotification.REGISTRATION_NOTIFICATION, 505 MBeanServerDelegate.DELEGATE_NAME, 506 0, 507 name); 508 delegate.sendNotification(n); 509 510 String className = mbean.getMBeanInfo().getClassName(); 511 return new ObjectInstance(name, className); 512 } 513 514 public void unregisterMBean(ObjectName name) 515 throws InstanceNotFoundException, MBeanRegistrationException { 516 517 forbidJMImpl(name); 518 519 DynamicMBean mbean = getMBean(name); 520 if (mbean == null) 521 throw new InstanceNotFoundException(name.toString()); 522 523 MBeanRegistration reg = mbeanRegistration(mbean); 524 try { 525 reg.preDeregister(); 526 } catch (Exception e) { 527 throw new MBeanRegistrationException(e); 528 } 529 if (!mbeans.remove(name, mbean)) 530 throw new InstanceNotFoundException(name.toString()); 531 // This is incorrect because we've invoked preDeregister 532 533 Object userMBean = getUserMBean(mbean); 534 if (userMBean instanceof ClassLoader) 535 clr.removeLoader((ClassLoader) userMBean); 536 537 Notification n = new MBeanServerNotification( 538 MBeanServerNotification.REGISTRATION_NOTIFICATION, 539 MBeanServerDelegate.DELEGATE_NAME, 540 0, 541 name); 542 delegate.sendNotification(n); 543 544 reg.postDeregister(); 545 } 546 547 public ObjectInstance getObjectInstance(ObjectName name) 548 throws InstanceNotFoundException { 549 DynamicMBean mbean = getMBean(name); 550 return new ObjectInstance(name, mbean.getMBeanInfo().getClassName()); 551 } 552 553 private static class TrueQueryExp implements QueryExp { 554 public boolean apply(ObjectName name) { 555 return true; 556 } 557 558 public void setMBeanServer(MBeanServer s) {} 559 } 560 private static final QueryExp trueQuery = new TrueQueryExp(); 561 562 public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) { 563 Set<ObjectInstance> instances = newSet(); 564 if (name == null) 565 name = ObjectName.WILDCARD; 566 if (query == null) 567 query = trueQuery; 568 MBeanServer oldMBS = QueryEval.getMBeanServer(); 569 try { 570 query.setMBeanServer(this); 571 for (ObjectName n : mbeans.keySet()) { 572 if (name.apply(n)) { 573 try { 574 if (query.apply(n)) 575 instances.add(getObjectInstance(n)); 576 } catch (Exception e) { 577 // OK: Ignore this MBean in the result 578 } 579 } 580 } 581 } finally { 582 query.setMBeanServer(oldMBS); 583 } 584 return instances; 585 } 586 587 public Set<ObjectName> queryNames(ObjectName name, QueryExp query) { 588 Set<ObjectInstance> instances = queryMBeans(name, query); 589 Set<ObjectName> names = newSet(); 590 for (ObjectInstance instance : instances) 591 names.add(instance.getObjectName()); 592 return names; 593 } 594 595 public boolean isRegistered(ObjectName name) { 596 return mbeans.containsKey(name); 597 } 598 599 public Integer getMBeanCount() { 600 return mbeans.size(); 601 } 602 603 public Object getAttribute(ObjectName name, String attribute) 604 throws MBeanException, AttributeNotFoundException, 605 InstanceNotFoundException, ReflectionException { 606 return getMBean(name).getAttribute(attribute); 607 } 608 609 public AttributeList getAttributes(ObjectName name, String[] attributes) 610 throws InstanceNotFoundException, ReflectionException { 611 return getMBean(name).getAttributes(attributes); 612 } 613 614 public void setAttribute(ObjectName name, Attribute attribute) 615 throws InstanceNotFoundException, AttributeNotFoundException, 616 InvalidAttributeValueException, MBeanException, 617 ReflectionException { 618 getMBean(name).setAttribute(attribute); 619 } 620 621 public AttributeList setAttributes( 622 ObjectName name, AttributeList attributes) 623 throws InstanceNotFoundException, ReflectionException { 624 return getMBean(name).setAttributes(attributes); 625 } 626 627 public Object invoke( 628 ObjectName name, String operationName, Object[] params, 629 String[] signature) 630 throws InstanceNotFoundException, MBeanException, ReflectionException { 631 return getMBean(name).invoke(operationName, params, signature); 632 } 633 634 public String getDefaultDomain() { 635 return defaultDomain; 636 } 637 638 public String[] getDomains() { 639 Set<String> domains = newSet(); 640 for (ObjectName name : mbeans.keySet()) 641 domains.add(name.getDomain()); 642 return domains.toArray(new String[0]); 643 } 644 645 // ClassCastException if MBean is not a NotificationBroadcaster 646 public void addNotificationListener( 647 ObjectName name, NotificationListener listener, 648 NotificationFilter filter, Object handback) 649 throws InstanceNotFoundException { 650 NotificationBroadcaster userMBean = 651 (NotificationBroadcaster) getUserMBean(name); 652 NotificationListener wrappedListener = 653 wrappedListener(name, userMBean, listener); 654 userMBean.addNotificationListener(wrappedListener, filter, handback); 655 } 656 657 public void addNotificationListener( 658 ObjectName name, ObjectName listener, 659 NotificationFilter filter, Object handback) 660 throws InstanceNotFoundException { 661 NotificationListener nl = 662 (NotificationListener) getUserMBean(listener); 663 addNotificationListener(name, nl, filter, handback); 664 } 665 666 public void removeNotificationListener( 667 ObjectName name, ObjectName listener) 668 throws InstanceNotFoundException, ListenerNotFoundException { 669 NotificationListener nl = 670 (NotificationListener) getUserMBean(listener); 671 removeNotificationListener(name, nl); 672 } 673 674 public void removeNotificationListener( 675 ObjectName name, ObjectName listener, 676 NotificationFilter filter, Object handback) 677 throws InstanceNotFoundException, ListenerNotFoundException { 678 NotificationListener nl = 679 (NotificationListener) getUserMBean(listener); 680 removeNotificationListener(name, nl, filter, handback); 681 } 682 683 public void removeNotificationListener( 684 ObjectName name, NotificationListener listener) 685 throws InstanceNotFoundException, ListenerNotFoundException { 686 NotificationBroadcaster userMBean = 687 (NotificationBroadcaster) getUserMBean(name); 688 NotificationListener wrappedListener = 689 wrappedListener(name, userMBean, listener); 690 userMBean.removeNotificationListener(wrappedListener); 691 } 692 693 public void removeNotificationListener( 694 ObjectName name, NotificationListener listener, 695 NotificationFilter filter, Object handback) 696 throws InstanceNotFoundException, ListenerNotFoundException { 697 NotificationEmitter userMBean = 698 (NotificationEmitter) getMBean(name); 699 NotificationListener wrappedListener = 700 wrappedListener(name, userMBean, listener); 701 userMBean.removeNotificationListener(wrappedListener, filter, handback); 702 } 703 704 public MBeanInfo getMBeanInfo(ObjectName name) 705 throws InstanceNotFoundException, IntrospectionException, 706 ReflectionException { 707 return getMBean(name).getMBeanInfo(); 708 } 709 710 public boolean isInstanceOf(ObjectName name, String className) 711 throws InstanceNotFoundException { 712 DynamicMBean mbean = getMBean(name); 713 String mbeanClassName = mbean.getMBeanInfo().getClassName(); 714 if (className.equals(mbeanClassName)) 715 return true; 716 ClassLoader loader = getUserMBean(mbean).getClass().getClassLoader(); 717 try { 718 Class<?> mbeanClass = Class.forName(mbeanClassName, false, loader); 719 Class<?> isInstClass = Class.forName(className, false, loader); 720 return isInstClass.isAssignableFrom(mbeanClass); 721 } catch (ClassNotFoundException e) { 722 return false; 723 } 724 } 725 726 public Object instantiate(String className) 727 throws ReflectionException, MBeanException { 728 return instantiate(className, null, null); 729 } 730 731 public Object instantiate(String className, ObjectName loaderName) 732 throws ReflectionException, MBeanException, InstanceNotFoundException { 733 return instantiate(className, loaderName, null, null); 734 } 735 736 public Object instantiate( 737 String className, Object[] params, String[] signature) 738 throws ReflectionException, MBeanException { 739 try { 740 return instantiate(className, clrName, params, signature); 741 } catch (InstanceNotFoundException e) { 742 throw new RuntimeException(e); // can't happen 743 } 744 } 745 746 public Object instantiate( 747 String className, ObjectName loaderName, 748 Object[] params, String[] signature) 749 throws ReflectionException, MBeanException, InstanceNotFoundException { 750 751 if (params == null) 752 params = new Object[0]; 753 if (signature == null) 754 signature = new String[0]; 755 756 ClassLoader loader; 757 if (loaderName == null) 758 loader = this.getClass().getClassLoader(); 759 else if (loaderName.equals(clrName)) 760 loader = clr; 761 else 762 loader = (ClassLoader) getMBean(loaderName); 763 764 Class<?> c; 765 try { 766 c = Class.forName(className, false, loader); 767 } catch (ClassNotFoundException e) { 768 throw new ReflectionException(e); 769 } 770 771 Constructor[] constrs = c.getConstructors(); 772 Constructor found = null; 773 findconstr: 774 for (Constructor constr : constrs) { 775 Class<?>[] cTypes = constr.getParameterTypes(); 776 if (cTypes.length == signature.length) { 777 for (int i = 0; i < cTypes.length; i++) { 778 if (!cTypes[i].getName().equals(signature[i])) 779 continue findconstr; 780 } 781 found = constr; 782 break findconstr; 783 } 784 } 785 if (found == null) { 786 Exception x = new NoSuchMethodException( 787 className + Arrays.toString(signature)); 788 throw new ReflectionException(x); 789 } 790 return invokeSomething(found, null, params); 791 } 792 793 @Deprecated 794 public ObjectInputStream deserialize(ObjectName name, byte[] data) 795 throws InstanceNotFoundException, OperationsException { 796 throw new UnsupportedOperationException(); 797 } 798 799 @Deprecated 800 public ObjectInputStream deserialize(String className, byte[] data) 801 throws OperationsException, ReflectionException { 802 throw new UnsupportedOperationException(); 803 } 804 805 @Deprecated 806 public ObjectInputStream deserialize( 807 String className, ObjectName loaderName, byte[] data) 808 throws InstanceNotFoundException, OperationsException, ReflectionException { 809 throw new UnsupportedOperationException(); 810 } 811 812 public ClassLoader getClassLoaderFor(ObjectName mbeanName) 813 throws InstanceNotFoundException { 814 DynamicMBean mbean = getMBean(mbeanName); 815 Object userMBean = getUserMBean(mbean); 816 return userMBean.getClass().getClassLoader(); 817 } 818 819 public ClassLoader getClassLoader(ObjectName loaderName) 820 throws InstanceNotFoundException { 821 return (ClassLoader) getMBean(loaderName); 822 } 823 824 public ClassLoaderRepository getClassLoaderRepository() { 825 return new ClassLoaderRepository() { 826 public Class<?> loadClass(String className) 827 throws ClassNotFoundException { 828 return clr.loadClass(className); 829 } 830 831 public Class<?> loadClassWithout( 832 ClassLoader exclude, String className) 833 throws ClassNotFoundException { 834 return clr.loadClassWithout(exclude, className); 835 } 836 837 public Class<?> loadClassBefore( 838 ClassLoader stop, String className) 839 throws ClassNotFoundException { 840 return clr.loadClassBefore(stop, className); 841 } 842 }; 843 } 844 845 private static class ClassLoaderRepositoryImpl 846 extends ClassLoader implements ClassLoaderRepository { 847 private List<ClassLoader> loaders = newList(); 848 { 849 loaders.add(this.getClass().getClassLoader()); 850 // We also behave as if the system class loader were in 851 // the repository, since we do nothing to stop delegation 852 // to the parent, which is the system class loader, and 853 // that delegation happens before our findClass is called. 854 } 855 856 void addLoader(ClassLoader loader) { 857 loaders.add(loader); 858 } 859 860 void removeLoader(ClassLoader loader) { 861 if (!loaders.remove(loader)) 862 throw new RuntimeException("Loader was not in CLR!"); 863 } 864 865 public Class<?> loadClassWithout( 866 ClassLoader exclude, String className) 867 throws ClassNotFoundException { 868 return loadClassWithoutBefore(exclude, null, className); 869 } 870 871 public Class<?> loadClassBefore(ClassLoader stop, String className) 872 throws ClassNotFoundException { 873 return loadClassWithoutBefore(null, stop, className); 874 } 875 876 private Class<?> loadClassWithoutBefore( 877 ClassLoader exclude, ClassLoader stop, String className) 878 throws ClassNotFoundException { 879 for (ClassLoader loader : loaders) { 880 if (loader == exclude) 881 continue; 882 if (loader == stop) 883 break; 884 try { 885 return Class.forName(className, false, loader); 886 } catch (ClassNotFoundException e) { 887 // OK: try others 888 } 889 } 890 throw new ClassNotFoundException(className); 891 } 892 893 @Override 894 protected Class<?> findClass(String className) 895 throws ClassNotFoundException { 896 return loadClassWithout(null, className); 897 } 898 } 899 900 /* There is zero or one ListenerTable per MBean. 901 * The ListenerTable stuff is complicated. We want to rewrite the 902 * source of notifications so that if the source of a notification 903 * from the MBean X is a reference to X itself, it gets replaced 904 * by X's ObjectName. To do this, we wrap the user's listener in 905 * a RewriteListener. But if the same listener is added a second 906 * time (perhaps with a different filter or handback) we must 907 * reuse the same RewriteListener so that the two-argument 908 * removeNotificationListener(ObjectName,NotificationListener) will 909 * correctly remove both listeners. This means we must remember the 910 * mapping from listener to WrappedListener. But if the MBean 911 * discards its listeners (as a result of removeNL or spontaneously) 912 * then we don't want to keep a reference to the WrappedListener. 913 * So we have tons of WeakReferences. The key in the ListenerTable 914 * is an IdentityListener, which wraps the user's listener to ensure 915 * that identity and not equality is used during the lookup, even if 916 * the user's listener has an equals method. The value in the 917 * ListenerTable is a WeakReference wrapping a RewriteListener wrapping 918 * the same IdentityListener. Since the RewriteListener is what is 919 * added to the user's MBean, the WeakReference won't disappear as long 920 * as the MBean still has this listener. And since it references the 921 * IdentityListener, that won't disappear either. But once the 922 * RewriteListener is no longer referenced by the user's MBean, 923 * there's nothing to stop its WeakReference from being cleared, 924 * and then corresponding IdentityListener that is now only weakly 925 * referenced from the key in the table. 926 */ 927 private static class ListenerTable 928 extends WeakHashMap<NotificationListener, 929 WeakReference<NotificationListener>> { 930 } 931 932 private static class IdentityListener implements NotificationListener { 933 private final NotificationListener userListener; 934 935 IdentityListener(NotificationListener userListener) { 936 this.userListener = userListener; 937 } 938 939 public void handleNotification( 940 Notification notification, Object handback) { 941 userListener.handleNotification(notification, handback); 942 } 943 944 @Override 945 public boolean equals(Object o) { 946 return (this == o); 947 } 948 949 @Override 950 public int hashCode() { 951 return System.identityHashCode(this); 952 } 953 } 954 955 private static class RewriteListener implements NotificationListener { 956 private final ObjectName name; 957 private final Object userMBean; 958 private final NotificationListener userListener; 959 960 RewriteListener( 961 ObjectName name, Object userMBean, 962 NotificationListener userListener) { 963 this.name = name; 964 this.userMBean = userMBean; 965 this.userListener = userListener; 966 } 967 968 public void handleNotification( 969 Notification notification, Object handback) { 970 if (notification.getSource() == userMBean) 971 notification.setSource(name); 972 userListener.handleNotification(notification, handback); 973 } 974 } 975 976 private NotificationListener wrappedListener( 977 ObjectName name, Object userMBean, NotificationListener userListener) 978 throws InstanceNotFoundException { 979 ListenerTable table = new ListenerTable(); 980 ListenerTable oldTable = listenerMap.putIfAbsent(name, table); 981 if (oldTable != null) 982 table = oldTable; 983 NotificationListener identityListener = 984 new IdentityListener(userListener); 985 synchronized (table) { 986 NotificationListener rewriteListener = null; 987 WeakReference<NotificationListener> wr = 988 table.get(identityListener); 989 if (wr != null) 990 rewriteListener = wr.get(); 991 if (rewriteListener == null) { 992 rewriteListener = new RewriteListener( 993 name, userMBean, identityListener); 994 wr = new WeakReference<NotificationListener>(rewriteListener); 995 table.put(identityListener, wr); 996 } 997 return rewriteListener; 998 } 999 } 1000 1001 private DynamicMBean getMBean(ObjectName name) 1002 throws InstanceNotFoundException { 1003 DynamicMBean mbean = mbeans.get(name); 1004 if (mbean == null) 1005 throw new InstanceNotFoundException(name.toString()); 1006 return mbean; 1007 } 1008 1009 private static interface WrapDynamicMBean extends DynamicMBean { 1010 public Object getWrappedMBean(); 1011 } 1012 1013 private static class StandardWrapper 1014 implements WrapDynamicMBean, MBeanRegistration { 1015 private final Map<String, AttrMethods> attrMap = newMap(); 1016 private final Map<String, List<Method>> opMap = newMap(); 1017 private static class AttrMethods { 1018 Method getter, setter; 1019 } 1020 1021 private final Object std; 1022 1023 StandardWrapper(Object std) throws NotCompliantMBeanException { 1024 this.std = std; 1025 Class<?> intf = mbeanInterface(std.getClass()); 1026 try { 1027 initMaps(intf); 1028 } catch (NotCompliantMBeanException e) { 1029 throw e; 1030 } catch (Exception e) { 1031 NotCompliantMBeanException x = 1032 new NotCompliantMBeanException(e.getMessage()); 1033 x.initCause(e); 1034 throw x; 1035 } 1036 } 1037 1038 private static Class<?> mbeanInterface(Class<?> c) 1039 throws NotCompliantMBeanException { 1040 do { 1041 Class<?>[] intfs = c.getInterfaces(); 1042 String intfName = c.getName() + "MBean"; 1043 for (Class<?> intf : intfs) { 1044 if (intf.getName().equals(intfName)) 1045 return intf; 1046 } 1047 c = c.getSuperclass(); 1048 } while (c != null); 1049 throw new NotCompliantMBeanException( 1050 "Does not match Standard or Dynamic MBean patterns: " + 1051 c.getName()); 1052 } 1053 1054 private void initMaps(Class<?> intf) throws NotCompliantMBeanException { 1055 Method[] methods = intf.getMethods(); 1056 1057 for (Method m : methods) { 1058 final String name = m.getName(); 1059 final int nParams = m.getParameterTypes().length; 1060 1061 String attrName = ""; 1062 if (name.startsWith("get")) 1063 attrName = name.substring(3); 1064 else if (name.startsWith("is") 1065 && m.getReturnType() == boolean.class) 1066 attrName = name.substring(2); 1067 1068 if (attrName.length() != 0 && m.getParameterTypes().length == 0 1069 && m.getReturnType() != void.class) { 1070 // It's a getter 1071 // Check we don't have both isX and getX 1072 AttrMethods am = attrMap.get(attrName); 1073 if (am == null) 1074 am = new AttrMethods(); 1075 else { 1076 if (am.getter != null) { 1077 final String msg = "Attribute " + attrName + 1078 " has more than one getter"; 1079 throw new NotCompliantMBeanException(msg); 1080 } 1081 } 1082 am.getter = m; 1083 attrMap.put(attrName, am); 1084 } else if (name.startsWith("set") && name.length() > 3 1085 && m.getParameterTypes().length == 1 && 1086 m.getReturnType() == void.class) { 1087 // It's a setter 1088 attrName = name.substring(3); 1089 AttrMethods am = attrMap.get(attrName); 1090 if (am == null) 1091 am = new AttrMethods(); 1092 else if (am.setter != null) { 1093 final String msg = "Attribute " + attrName + 1094 " has more than one setter"; 1095 throw new NotCompliantMBeanException(msg); 1096 } 1097 am.setter = m; 1098 attrMap.put(attrName, am); 1099 } else { 1100 // It's an operation 1101 List<Method> ops = opMap.get(name); 1102 if (ops == null) 1103 ops = newList(); 1104 ops.add(m); 1105 opMap.put(name, ops); 1106 } 1107 } 1108 /* Check that getters and setters are consistent. */ 1109 for (Map.Entry<String, AttrMethods> entry : attrMap.entrySet()) { 1110 AttrMethods am = entry.getValue(); 1111 if (am.getter != null && am.setter != null && 1112 am.getter.getReturnType() != am.setter.getParameterTypes()[0]) { 1113 final String msg = "Getter and setter for " + entry.getKey() + 1114 " have inconsistent types"; 1115 throw new NotCompliantMBeanException(msg); 1116 } 1117 } 1118 } 1119 1120 public Object getAttribute(String attribute) 1121 throws AttributeNotFoundException, MBeanException, ReflectionException { 1122 AttrMethods am = attrMap.get(attribute); 1123 if (am == null || am.getter == null) 1124 throw new AttributeNotFoundException(attribute); 1125 return invokeMethod(am.getter); 1126 } 1127 1128 public void setAttribute(Attribute attribute) 1129 throws AttributeNotFoundException, InvalidAttributeValueException, 1130 MBeanException, ReflectionException { 1131 String name = attribute.getName(); 1132 AttrMethods am = attrMap.get(name); 1133 if (am == null || am.setter == null) 1134 throw new AttributeNotFoundException(name); 1135 invokeMethod(am.setter, attribute.getValue()); 1136 } 1137 1138 public AttributeList getAttributes(String[] attributes) { 1139 AttributeList list = new AttributeList(); 1140 for (String attr : attributes) { 1141 try { 1142 list.add(new Attribute(attr, getAttribute(attr))); 1143 } catch (Exception e) { 1144 // OK: ignore per spec 1145 } 1146 } 1147 return list; 1148 } 1149 1150 public AttributeList setAttributes(AttributeList attributes) { 1151 AttributeList list = new AttributeList(); 1152 // We carefully avoid using any new stuff from AttributeList here! 1153 for (Iterator<?> it = attributes.iterator(); it.hasNext(); ) { 1154 Attribute attr = (Attribute) it.next(); 1155 try { 1156 setAttribute(attr); 1157 list.add(attr); 1158 } catch (Exception e) { 1159 // OK: ignore per spec 1160 } 1161 } 1162 return list; 1163 } 1164 1165 public Object invoke(String actionName, Object[] params, String[] signature) 1166 throws MBeanException, ReflectionException { 1167 if (params == null) 1168 params = new Object[0]; 1169 if (signature == null) 1170 signature = new String[0]; 1171 List<Method> methods = opMap.get(actionName); 1172 if (methods == null) { 1173 Exception x = new NoSuchMethodException(actionName); 1174 throw new MBeanException(x); 1175 } 1176 Method found = null; 1177 methodloop: 1178 for (Method m : methods) { 1179 Class<?>[] msig = m.getParameterTypes(); 1180 if (msig.length != signature.length) 1181 continue methodloop; 1182 for (int i = 0; i < msig.length; i++) { 1183 if (!msig[i].getName().equals(signature[i])) 1184 continue methodloop; 1185 } 1186 found = m; 1187 break methodloop; 1188 } 1189 if (found == null) { 1190 Exception x = new NoSuchMethodException( 1191 actionName + Arrays.toString(signature)); 1192 throw new MBeanException(x); 1193 } 1194 return invokeMethod(found, params); 1195 } 1196 1197 public MBeanInfo getMBeanInfo() { 1198 // Attributes 1199 List<MBeanAttributeInfo> attrs = newList(); 1200 for (Map.Entry<String, AttrMethods> attr : attrMap.entrySet()) { 1201 String name = attr.getKey(); 1202 AttrMethods am = attr.getValue(); 1203 try { 1204 attrs.add(new MBeanAttributeInfo( 1205 name, name, am.getter, am.setter)); 1206 } catch (IntrospectionException e) { // grrr 1207 throw new RuntimeException(e); 1208 } 1209 } 1210 1211 // Operations 1212 List<MBeanOperationInfo> ops = newList(); 1213 for (Map.Entry<String, List<Method>> op : opMap.entrySet()) { 1214 String name = op.getKey(); 1215 List<Method> methods = op.getValue(); 1216 for (Method m : methods) 1217 ops.add(new MBeanOperationInfo(name, m)); 1218 } 1219 1220 // Constructors 1221 List<MBeanConstructorInfo> constrs = newList(); 1222 for (Constructor constr : std.getClass().getConstructors()) 1223 constrs.add(new MBeanConstructorInfo("Constructor", constr)); 1224 1225 // Notifications 1226 MBeanNotificationInfo[] notifs; 1227 if (std instanceof NotificationBroadcaster) 1228 notifs = ((NotificationBroadcaster) std).getNotificationInfo(); 1229 else 1230 notifs = null; 1231 1232 String className = std.getClass().getName(); 1233 return new MBeanInfo( 1234 className, className, 1235 attrs.toArray(new MBeanAttributeInfo[0]), 1236 constrs.toArray(new MBeanConstructorInfo[0]), 1237 ops.toArray(new MBeanOperationInfo[0]), 1238 notifs); 1239 } 1240 1241 private Object invokeMethod(Method m, Object... args) 1242 throws MBeanException, ReflectionException { 1243 return invokeSomething(m, std,args); 1244 } 1245 1246 public ObjectName preRegister(MBeanServer server, ObjectName name) 1247 throws Exception { 1248 return mbeanRegistration(std).preRegister(server, name); 1249 } 1250 1251 public void postRegister(Boolean registrationDone) { 1252 mbeanRegistration(std).postRegister(registrationDone); 1253 } 1254 1255 public void preDeregister() throws Exception { 1256 mbeanRegistration(std).preDeregister(); 1257 } 1258 1259 public void postDeregister() { 1260 mbeanRegistration(std).postDeregister(); 1261 } 1262 1263 public Object getWrappedMBean() { 1264 return std; 1265 } 1266 } 1267 1268 private DynamicMBean standardToDynamic(Object std) 1269 throws NotCompliantMBeanException { 1270 return new StandardWrapper(std); 1271 } 1272 1273 // private static class NotifWrapper 1274 // implements WrapDynamicMBean, NotificationEmitter { 1275 // private final DynamicMBean mbean; 1276 // 1277 // NotifWrapper(DynamicMBean mbean) { 1278 // this.mbean = mbean; 1279 // } 1280 // 1281 // public Object getAttribute(String attribute) 1282 // throws AttributeNotFoundException, MBeanException, ReflectionException { 1283 // return mbean.getAttribute(attribute); 1284 // } 1285 // 1286 // public void setAttribute(Attribute attribute) 1287 // throws AttributeNotFoundException, InvalidAttributeValueException, 1288 // MBeanException, ReflectionException { 1289 // mbean.setAttribute(attribute); 1290 // } 1291 // 1292 // public AttributeList getAttributes(String[] attributes) { 1293 // return mbean.getAttributes(attributes); 1294 // } 1295 // 1296 // public AttributeList setAttributes(AttributeList attributes) { 1297 // return mbean.setAttributes(attributes); 1298 // } 1299 // 1300 // public Object invoke( 1301 // String actionName, Object[] params, String[] signature) 1302 // throws MBeanException, ReflectionException { 1303 // return mbean.invoke(actionName, params, signature); 1304 // } 1305 // 1306 // public MBeanInfo getMBeanInfo() { 1307 // return mbean.getMBeanInfo(); 1308 // } 1309 // 1310 // public void removeNotificationListener( 1311 // NotificationListener listener, NotificationFilter filter, Object handback) 1312 // throws ListenerNotFoundException { 1313 // ((NotificationEmitter) mbean).removeNotificationListener( 1314 // listener, filter, handback); 1315 // // ClassCastException if MBean is not an emitter 1316 // } 1317 // 1318 // public void addNotificationListener( 1319 // NotificationListener listener, NotificationFilter filter, Object handback) 1320 // throws IllegalArgumentException { 1321 // ((NotificationBroadcaster) mbean).addNotificationListener( 1322 // listener, filter, handback); 1323 // } 1324 // 1325 // public void removeNotificationListener(NotificationListener listener) 1326 // throws ListenerNotFoundException { 1327 // ((NotificationBroadcaster) mbean).removeNotificationListener(listener); 1328 // } 1329 // 1330 // public MBeanNotificationInfo[] getNotificationInfo() { 1331 // return ((NotificationBroadcaster) mbean).getNotificationInfo(); 1332 // } 1333 // 1334 // public Object getWrappedMBean() { 1335 // return getUserMBean(mbean); 1336 // } 1337 // } 1338 1339 private static Object invokeSomething( 1340 AccessibleObject ao, Object target, Object[] args) 1341 throws MBeanException, ReflectionException { 1342 try { 1343 if (ao instanceof Method) 1344 return ((Method) ao).invoke(target, args); 1345 else 1346 return ((Constructor) ao).newInstance(args); 1347 } catch (InvocationTargetException e) { 1348 try { 1349 throw e.getCause(); 1350 } catch (RuntimeException x) { 1351 throw new RuntimeMBeanException(x); 1352 } catch (Error x) { 1353 throw new RuntimeErrorException(x); 1354 } catch (Exception x) { 1355 throw new MBeanException(x); 1356 } catch (Throwable x) { 1357 throw new RuntimeException(x); // neither Error nor Exception! 1358 } 1359 } catch (Exception e) { 1360 throw new ReflectionException(e); 1361 } 1362 } 1363 1364 private static Object getUserMBean(DynamicMBean mbean) { 1365 if (mbean instanceof WrapDynamicMBean) 1366 return ((WrapDynamicMBean) mbean).getWrappedMBean(); 1367 return mbean; 1368 } 1369 1370 private Object getUserMBean(ObjectName name) 1371 throws InstanceNotFoundException { 1372 return getUserMBean(getMBean(name)); 1373 } 1374 1375 private static final MBeanRegistration noRegistration = 1376 new MBeanRegistration() { 1377 public ObjectName preRegister(MBeanServer server, ObjectName name) { 1378 return name; 1379 } 1380 1381 public void postRegister(Boolean registrationDone) { 1382 } 1383 1384 public void preDeregister() throws Exception { 1385 } 1386 1387 public void postDeregister() { 1388 } 1389 }; 1390 1391 private static MBeanRegistration mbeanRegistration(Object object) { 1392 if (object instanceof MBeanRegistration) 1393 return (MBeanRegistration) object; 1394 else 1395 return noRegistration; 1396 } 1397 1398 private static <E> List<E> newList() { 1399 return new ArrayList<E>(); 1400 } 1401 1402 private static <K, V> Map<K, V> newMap() { 1403 return new HashMap<K, V>(); 1404 } 1405 1406 private static <E> Set<E> newSet() { 1407 return new HashSet<E>(); 1408 } 1409 } 1410 }