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