1 /* 2 * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.jmx.mbeanserver; 27 28 import static com.sun.jmx.mbeanserver.Util.*; 29 30 import java.util.Iterator; 31 import java.util.Set; 32 33 import javax.management.InstanceAlreadyExistsException; 34 import javax.management.JMX; 35 import javax.management.MBeanServer; 36 import javax.management.NotCompliantMBeanException; 37 import javax.management.ObjectName; 38 39 /** 40 * Base class for MXBeans. 41 * 42 * @since 1.6 43 */ 44 public class MXBeanSupport extends MBeanSupport<ConvertingMethod> { 45 46 /** 47 <p>Construct an MXBean that wraps the given resource using the 48 given MXBean interface.</p> 49 50 @param resource the underlying resource for the new MXBean. 51 52 @param mxbeanInterface the interface to be used to determine 53 the MXBean's management interface. 54 55 @param <T> a type parameter that allows the compiler to check 56 that {@code resource} implements {@code mxbeanInterface}, 57 provided that {@code mxbeanInterface} is a class constant like 58 {@code SomeMXBean.class}. 59 60 @throws IllegalArgumentException if {@code resource} is null or 61 if it does not implement the class {@code mxbeanInterface} or if 62 that class is not a valid MXBean interface. 63 */ MXBeanSupport(T resource, Class<T> mxbeanInterface)64 public <T> MXBeanSupport(T resource, Class<T> mxbeanInterface) 65 throws NotCompliantMBeanException { 66 super(resource, mxbeanInterface); 67 } 68 69 @Override getMBeanIntrospector()70 MBeanIntrospector<ConvertingMethod> getMBeanIntrospector() { 71 return MXBeanIntrospector.getInstance(); 72 } 73 74 @Override getCookie()75 Object getCookie() { 76 return mxbeanLookup; 77 } 78 findMXBeanInterface(Class<T> resourceClass)79 static <T> Class<? super T> findMXBeanInterface(Class<T> resourceClass) { 80 if (resourceClass == null) 81 throw new IllegalArgumentException("Null resource class"); 82 final Set<Class<?>> intfs = transitiveInterfaces(resourceClass); 83 final Set<Class<?>> candidates = newSet(); 84 for (Class<?> intf : intfs) { 85 if (JMX.isMXBeanInterface(intf)) 86 candidates.add(intf); 87 } 88 reduce: 89 while (candidates.size() > 1) { 90 for (Class<?> intf : candidates) { 91 for (Iterator<Class<?>> it = candidates.iterator(); it.hasNext(); 92 ) { 93 final Class<?> intf2 = it.next(); 94 if (intf != intf2 && intf2.isAssignableFrom(intf)) { 95 it.remove(); 96 continue reduce; 97 } 98 } 99 } 100 final String msg = 101 "Class " + resourceClass.getName() + " implements more than " + 102 "one MXBean interface: " + candidates; 103 throw new IllegalArgumentException(msg); 104 } 105 if (candidates.iterator().hasNext()) { 106 return Util.cast(candidates.iterator().next()); 107 } else { 108 final String msg = 109 "Class " + resourceClass.getName() + 110 " is not a JMX compliant MXBean"; 111 throw new IllegalArgumentException(msg); 112 } 113 } 114 115 /* Return all interfaces inherited by this class, directly or 116 * indirectly through the parent class and interfaces. 117 */ transitiveInterfaces(Class<?> c)118 private static Set<Class<?>> transitiveInterfaces(Class<?> c) { 119 Set<Class<?>> set = newSet(); 120 transitiveInterfaces(c, set); 121 return set; 122 } transitiveInterfaces(Class<?> c, Set<Class<?>> intfs)123 private static void transitiveInterfaces(Class<?> c, Set<Class<?>> intfs) { 124 if (c == null) 125 return; 126 if (c.isInterface()) 127 intfs.add(c); 128 transitiveInterfaces(c.getSuperclass(), intfs); 129 for (Class<?> sup : c.getInterfaces()) 130 transitiveInterfaces(sup, intfs); 131 } 132 133 /* 134 * The sequence of events for tracking inter-MXBean references is 135 * relatively complicated. We use the magical preRegister2 method 136 * which the MBeanServer knows about. The steps during registration 137 * are: 138 * (1) Call user preRegister, if any. If exception, abandon. 139 * (2) Call preRegister2 and hence this register method. If exception, 140 * call postRegister(false) and abandon. 141 * (3) Try to register the MBean. If exception, call registerFailed() 142 * which will call the unregister method. (Also call postRegister(false).) 143 * (4) If we get this far, we can call postRegister(true). 144 * 145 * When we are wrapped in an instance of javax.management.StandardMBean, 146 * things are simpler. That class calls this method from its preRegister, 147 * and propagates any exception. There is no user preRegister in this case. 148 * If this method succeeds but registration subsequently fails, 149 * StandardMBean calls unregister from its postRegister(false) method. 150 */ 151 @Override register(MBeanServer server, ObjectName name)152 public void register(MBeanServer server, ObjectName name) 153 throws InstanceAlreadyExistsException { 154 if (name == null) 155 throw new IllegalArgumentException("Null object name"); 156 // eventually we could have some logic to supply a default name 157 158 synchronized (lock) { 159 this.mxbeanLookup = MXBeanLookup.lookupFor(server); 160 this.mxbeanLookup.addReference(name, getResource()); 161 this.objectName = name; 162 } 163 } 164 165 @Override unregister()166 public void unregister() { 167 synchronized (lock) { 168 if (mxbeanLookup != null) { 169 if (mxbeanLookup.removeReference(objectName, getResource())) 170 objectName = null; 171 } 172 } 173 } 174 private final Object lock = new Object(); // for mxbeanLookup and objectName 175 176 private MXBeanLookup mxbeanLookup; 177 private ObjectName objectName; 178 } 179