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