0001 /*
0002 * Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
0003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004 *
0005 * This code is free software; you can redistribute it and/or modify it
0006 * under the terms of the GNU General Public License version 2 only, as
0007 * published by the Free Software Foundation. Sun designates this
0008 * particular file as subject to the "Classpath" exception as provided
0009 * by Sun in the LICENSE file that accompanied this code.
0010 *
0011 * This code is distributed in the hope that it will be useful, but WITHOUT
0012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014 * version 2 for more details (a copy is included in the LICENSE file that
0015 * accompanied this code).
0016 *
0017 * You should have received a copy of the GNU General Public License version
0018 * 2 along with this work; if not, write to the Free Software Foundation,
0019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020 *
0021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022 * CA 95054 USA or visit www.sun.com if you need additional information or
0023 * have any questions.
0024 */
0025
0026 package javax.management;
0027
0028 import static com.sun.jmx.defaults.JmxProperties.MISC_LOGGER;
0029 import com.sun.jmx.mbeanserver.DescriptorCache;
0030 import com.sun.jmx.mbeanserver.Introspector;
0031 import com.sun.jmx.mbeanserver.MBeanSupport;
0032 import com.sun.jmx.mbeanserver.MXBeanSupport;
0033 import com.sun.jmx.mbeanserver.StandardMBeanSupport;
0034 import com.sun.jmx.mbeanserver.Util;
0035
0036 import java.io.PrintWriter;
0037 import java.io.StringWriter;
0038 import java.security.AccessController;
0039 import java.security.PrivilegedAction;
0040 import java.util.HashMap;
0041 import java.util.Map;
0042 import java.util.WeakHashMap;
0043 import java.util.logging.Level;
0044 import javax.management.openmbean.OpenMBeanAttributeInfo;
0045 import javax.management.openmbean.OpenMBeanAttributeInfoSupport;
0046 import javax.management.openmbean.OpenMBeanConstructorInfo;
0047 import javax.management.openmbean.OpenMBeanConstructorInfoSupport;
0048 import javax.management.openmbean.OpenMBeanOperationInfo;
0049 import javax.management.openmbean.OpenMBeanOperationInfoSupport;
0050 import javax.management.openmbean.OpenMBeanParameterInfo;
0051 import javax.management.openmbean.OpenMBeanParameterInfoSupport;
0052
0053 /**
0054 * <p>An MBean whose management interface is determined by reflection
0055 * on a Java interface.</p>
0056 *
0057 * <p>This class brings more flexibility to the notion of Management
0058 * Interface in the use of Standard MBeans. Straightforward use of
0059 * the patterns for Standard MBeans described in the JMX Specification
0060 * means that there is a fixed relationship between the implementation
0061 * class of an MBean and its management interface (i.e., if the
0062 * implementation class is Thing, the management interface must be
0063 * ThingMBean). This class makes it possible to keep the convenience
0064 * of specifying the management interface with a Java interface,
0065 * without requiring that there be any naming relationship between the
0066 * implementation and interface classes.</p>
0067 *
0068 * <p>By making a DynamicMBean out of an MBean, this class makes
0069 * it possible to select any interface implemented by the MBean as its
0070 * management interface, provided that it complies with JMX patterns
0071 * (i.e., attributes defined by getter/setter etc...).</p>
0072 *
0073 * <p> This class also provides hooks that make it possible to supply
0074 * custom descriptions and names for the {@link MBeanInfo} returned by
0075 * the DynamicMBean interface.</p>
0076 *
0077 * <p>Using this class, an MBean can be created with any
0078 * implementation class name <i>Impl</i> and with a management
0079 * interface defined (as for current Standard MBeans) by any interface
0080 * <i>Intf</i>, in one of two general ways:</p>
0081 *
0082 * <ul>
0083 *
0084 * <li>Using the public constructor
0085 * {@link #StandardMBean(java.lang.Object, java.lang.Class, boolean)
0086 * StandardMBean(impl,interface)}:
0087 * <pre>
0088 * MBeanServer mbs;
0089 * ...
0090 * Impl impl = new Impl(...);
0091 * StandardMBean mbean = new StandardMBean(impl, Intf.class, false);
0092 * mbs.registerMBean(mbean, objectName);
0093 * </pre></li>
0094 *
0095 * <li>Subclassing StandardMBean:
0096 * <pre>
0097 * public class Impl extends StandardMBean implements Intf {
0098 * public Impl() {
0099 * super(Intf.class, false);
0100 * }
0101 * // implement methods of Intf
0102 * }
0103 *
0104 * [...]
0105 *
0106 * MBeanServer mbs;
0107 * ....
0108 * Impl impl = new Impl();
0109 * mbs.registerMBean(impl, objectName);
0110 * </pre></li>
0111 *
0112 * </ul>
0113 *
0114 * <p>In either case, the class <i>Impl</i> must implement the
0115 * interface <i>Intf</i>.</p>
0116 *
0117 * <p>Standard MBeans based on the naming relationship between
0118 * implementation and interface classes are of course still
0119 * available.</p>
0120 *
0121 * <p>This class may also be used to construct MXBeans. The usage
0122 * is exactly the same as for Standard MBeans except that in the
0123 * examples above, the {@code false} parameter to the constructor or
0124 * {@code super(...)} invocation is instead {@code true}.</p>
0125 *
0126 * @since 1.5
0127 */
0128 public class StandardMBean implements DynamicMBean, MBeanRegistration {
0129
0130 private final static DescriptorCache descriptors = DescriptorCache
0131 .getInstance(JMX.proof);
0132
0133 /**
0134 * The DynamicMBean that wraps the MXBean or Standard MBean implementation.
0135 **/
0136 private volatile MBeanSupport<?> mbean;
0137
0138 /**
0139 * The cached MBeanInfo.
0140 **/
0141 private volatile MBeanInfo cachedMBeanInfo;
0142
0143 /**
0144 * Make a DynamicMBean out of <var>implementation</var>, using the
0145 * specified <var>mbeanInterface</var> class.
0146 * @param implementation The implementation of this MBean.
0147 * If <code>null</code>, and null implementation is allowed,
0148 * then the implementation is assumed to be <var>this</var>.
0149 * @param mbeanInterface The Management Interface exported by this
0150 * MBean's implementation. If <code>null</code>, then this
0151 * object will use standard JMX design pattern to determine
0152 * the management interface associated with the given
0153 * implementation.
0154 * @param nullImplementationAllowed <code>true</code> if a null
0155 * implementation is allowed. If null implementation is allowed,
0156 * and a null implementation is passed, then the implementation
0157 * is assumed to be <var>this</var>.
0158 * @exception IllegalArgumentException if the given
0159 * <var>implementation</var> is null, and null is not allowed.
0160 **/
0161 private <T> void construct(T implementation,
0162 Class<T> mbeanInterface, boolean nullImplementationAllowed,
0163 boolean isMXBean) throws NotCompliantMBeanException {
0164 if (implementation == null) {
0165 // Have to use (T)this rather than mbeanInterface.cast(this)
0166 // because mbeanInterface might be null.
0167 if (nullImplementationAllowed)
0168 implementation = Util.<T> cast(this );
0169 else
0170 throw new IllegalArgumentException(
0171 "implementation is null");
0172 }
0173 if (isMXBean) {
0174 if (mbeanInterface == null) {
0175 mbeanInterface = Util.cast(Introspector
0176 .getMXBeanInterface(implementation.getClass()));
0177 }
0178 this .mbean = new MXBeanSupport(implementation,
0179 mbeanInterface);
0180 } else {
0181 if (mbeanInterface == null) {
0182 mbeanInterface = Util.cast(Introspector
0183 .getStandardMBeanInterface(implementation
0184 .getClass()));
0185 }
0186 this .mbean = new StandardMBeanSupport(implementation,
0187 mbeanInterface);
0188 }
0189 }
0190
0191 /**
0192 * <p>Make a DynamicMBean out of the object
0193 * <var>implementation</var>, using the specified
0194 * <var>mbeanInterface</var> class.</p>
0195 *
0196 * @param implementation The implementation of this MBean.
0197 * @param mbeanInterface The Management Interface exported by this
0198 * MBean's implementation. If <code>null</code>, then this
0199 * object will use standard JMX design pattern to determine
0200 * the management interface associated with the given
0201 * implementation.
0202 * @param <T> Allows the compiler to check
0203 * that {@code implementation} does indeed implement the class
0204 * described by {@code mbeanInterface}. The compiler can only
0205 * check this if {@code mbeanInterface} is a class literal such
0206 * as {@code MyMBean.class}.
0207 *
0208 * @exception IllegalArgumentException if the given
0209 * <var>implementation</var> is null.
0210 * @exception NotCompliantMBeanException if the <var>mbeanInterface</var>
0211 * does not follow JMX design patterns for Management Interfaces, or
0212 * if the given <var>implementation</var> does not implement the
0213 * specified interface.
0214 **/
0215 public <T> StandardMBean(T implementation, Class<T> mbeanInterface)
0216 throws NotCompliantMBeanException {
0217 construct(implementation, mbeanInterface, false, false);
0218 }
0219
0220 /**
0221 * <p>Make a DynamicMBean out of <var>this</var>, using the specified
0222 * <var>mbeanInterface</var> class.</p>
0223 *
0224 * <p>Call {@link #StandardMBean(java.lang.Object, java.lang.Class)
0225 * this(this,mbeanInterface)}.
0226 * This constructor is reserved to subclasses.</p>
0227 *
0228 * @param mbeanInterface The Management Interface exported by this
0229 * MBean.
0230 *
0231 * @exception NotCompliantMBeanException if the <var>mbeanInterface</var>
0232 * does not follow JMX design patterns for Management Interfaces, or
0233 * if <var>this</var> does not implement the specified interface.
0234 **/
0235 protected StandardMBean(Class<?> mbeanInterface)
0236 throws NotCompliantMBeanException {
0237 construct(null, mbeanInterface, true, false);
0238 }
0239
0240 /**
0241 * <p>Make a DynamicMBean out of the object
0242 * <var>implementation</var>, using the specified
0243 * <var>mbeanInterface</var> class. This constructor can be used
0244 * to make either Standard MBeans or MXBeans. Unlike the
0245 * constructor {@link #StandardMBean(Object, Class)}, it
0246 * does not throw NotCompliantMBeanException.</p>
0247 *
0248 * @param implementation The implementation of this MBean.
0249 * @param mbeanInterface The Management Interface exported by this
0250 * MBean's implementation. If <code>null</code>, then this
0251 * object will use standard JMX design pattern to determine
0252 * the management interface associated with the given
0253 * implementation.
0254 * @param isMXBean If true, the {@code mbeanInterface} parameter
0255 * names an MXBean interface and the resultant MBean is an MXBean.
0256 * @param <T> Allows the compiler to check
0257 * that {@code implementation} does indeed implement the class
0258 * described by {@code mbeanInterface}. The compiler can only
0259 * check this if {@code mbeanInterface} is a class literal such
0260 * as {@code MyMBean.class}.
0261 *
0262 * @exception IllegalArgumentException if the given
0263 * <var>implementation</var> is null, or if the <var>mbeanInterface</var>
0264 * does not follow JMX design patterns for Management Interfaces, or
0265 * if the given <var>implementation</var> does not implement the
0266 * specified interface.
0267 *
0268 * @since 1.6
0269 **/
0270 public <T> StandardMBean(T implementation, Class<T> mbeanInterface,
0271 boolean isMXBean) {
0272 try {
0273 construct(implementation, mbeanInterface, false, isMXBean);
0274 } catch (NotCompliantMBeanException e) {
0275 throw new IllegalArgumentException(e);
0276 }
0277 }
0278
0279 /**
0280 * <p>Make a DynamicMBean out of <var>this</var>, using the specified
0281 * <var>mbeanInterface</var> class. This constructor can be used
0282 * to make either Standard MBeans or MXBeans. Unlike the
0283 * constructor {@link #StandardMBean(Object, Class)}, it
0284 * does not throw NotCompliantMBeanException.</p>
0285 *
0286 * <p>Call {@link #StandardMBean(java.lang.Object, java.lang.Class, boolean)
0287 * this(this, mbeanInterface, isMXBean)}.
0288 * This constructor is reserved to subclasses.</p>
0289 *
0290 * @param mbeanInterface The Management Interface exported by this
0291 * MBean.
0292 * @param isMXBean If true, the {@code mbeanInterface} parameter
0293 * names an MXBean interface and the resultant MBean is an MXBean.
0294 *
0295 * @exception IllegalArgumentException if the <var>mbeanInterface</var>
0296 * does not follow JMX design patterns for Management Interfaces, or
0297 * if <var>this</var> does not implement the specified interface.
0298 *
0299 * @since 1.6
0300 **/
0301 protected StandardMBean(Class<?> mbeanInterface, boolean isMXBean) {
0302 try {
0303 construct(null, mbeanInterface, true, isMXBean);
0304 } catch (NotCompliantMBeanException e) {
0305 throw new IllegalArgumentException(e);
0306 }
0307 }
0308
0309 /**
0310 * <p>Replace the implementation object wrapped in this object.</p>
0311 *
0312 * @param implementation The new implementation of this Standard MBean
0313 * (or MXBean). The <code>implementation</code> object must implement
0314 * the Standard MBean (or MXBean) interface that was supplied when this
0315 * <code>StandardMBean</code> was constructed.
0316 *
0317 * @exception IllegalArgumentException if the given
0318 * <var>implementation</var> is null.
0319 *
0320 * @exception NotCompliantMBeanException if the given
0321 * <var>implementation</var> does not implement the
0322 * Standard MBean (or MXBean) interface that was
0323 * supplied at construction.
0324 *
0325 * @see #getImplementation
0326 **/
0327 public void setImplementation(Object implementation)
0328 throws NotCompliantMBeanException {
0329
0330 if (implementation == null)
0331 throw new IllegalArgumentException("implementation is null");
0332
0333 if (isMXBean()) {
0334 this .mbean = new MXBeanSupport(implementation, Util
0335 .<Class<Object>> cast(getMBeanInterface()));
0336 } else {
0337 this .mbean = new StandardMBeanSupport(implementation, Util
0338 .<Class<Object>> cast(getMBeanInterface()));
0339 }
0340 }
0341
0342 /**
0343 * Get the implementation of this Standard MBean (or MXBean).
0344 * @return The implementation of this Standard MBean (or MXBean).
0345 *
0346 * @see #setImplementation
0347 **/
0348 public Object getImplementation() {
0349 return mbean.getResource();
0350 }
0351
0352 /**
0353 * Get the Management Interface of this Standard MBean (or MXBean).
0354 * @return The management interface of this Standard MBean (or MXBean).
0355 **/
0356 public final Class<?> getMBeanInterface() {
0357 return mbean.getMBeanInterface();
0358 }
0359
0360 /**
0361 * Get the class of the implementation of this Standard MBean (or MXBean).
0362 * @return The class of the implementation of this Standard MBean (or MXBean).
0363 **/
0364 public Class<?> getImplementationClass() {
0365 return mbean.getResource().getClass();
0366 }
0367
0368 // ------------------------------------------------------------------
0369 // From the DynamicMBean interface.
0370 // ------------------------------------------------------------------
0371 public Object getAttribute(String attribute)
0372 throws AttributeNotFoundException, MBeanException,
0373 ReflectionException {
0374 return mbean.getAttribute(attribute);
0375 }
0376
0377 // ------------------------------------------------------------------
0378 // From the DynamicMBean interface.
0379 // ------------------------------------------------------------------
0380 public void setAttribute(Attribute attribute)
0381 throws AttributeNotFoundException,
0382 InvalidAttributeValueException, MBeanException,
0383 ReflectionException {
0384 mbean.setAttribute(attribute);
0385 }
0386
0387 // ------------------------------------------------------------------
0388 // From the DynamicMBean interface.
0389 // ------------------------------------------------------------------
0390 public AttributeList getAttributes(String[] attributes) {
0391 return mbean.getAttributes(attributes);
0392 }
0393
0394 // ------------------------------------------------------------------
0395 // From the DynamicMBean interface.
0396 // ------------------------------------------------------------------
0397 public AttributeList setAttributes(AttributeList attributes) {
0398 return mbean.setAttributes(attributes);
0399 }
0400
0401 // ------------------------------------------------------------------
0402 // From the DynamicMBean interface.
0403 // ------------------------------------------------------------------
0404 public Object invoke(String actionName, Object params[],
0405 String signature[]) throws MBeanException,
0406 ReflectionException {
0407 return mbean.invoke(actionName, params, signature);
0408 }
0409
0410 /**
0411 * Get the {@link MBeanInfo} for this MBean.
0412 * <p>
0413 * This method implements
0414 * {@link javax.management.DynamicMBean#getMBeanInfo()
0415 * DynamicMBean.getMBeanInfo()}.
0416 * <p>
0417 * This method first calls {@link #getCachedMBeanInfo()} in order to
0418 * retrieve the cached MBeanInfo for this MBean, if any. If the
0419 * MBeanInfo returned by {@link #getCachedMBeanInfo()} is not null,
0420 * then it is returned.<br>
0421 * Otherwise, this method builds a default MBeanInfo for this MBean,
0422 * using the Management Interface specified for this MBean.
0423 * <p>
0424 * While building the MBeanInfo, this method calls the customization
0425 * hooks that make it possible for subclasses to supply their custom
0426 * descriptions, parameter names, etc...<br>
0427 * Finally, it calls {@link #cacheMBeanInfo(javax.management.MBeanInfo)
0428 * cacheMBeanInfo()} in order to cache the new MBeanInfo.
0429 * @return The cached MBeanInfo for that MBean, if not null, or a
0430 * newly built MBeanInfo if none was cached.
0431 **/
0432 public MBeanInfo getMBeanInfo() {
0433 try {
0434 final MBeanInfo cached = getCachedMBeanInfo();
0435 if (cached != null)
0436 return cached;
0437 } catch (RuntimeException x) {
0438 if (MISC_LOGGER.isLoggable(Level.FINEST)) {
0439 MISC_LOGGER.logp(Level.FINEST, MBeanServerFactory.class
0440 .getName(), "getMBeanInfo",
0441 "Failed to get cached MBeanInfo", x);
0442 }
0443 }
0444
0445 if (MISC_LOGGER.isLoggable(Level.FINER)) {
0446 MISC_LOGGER.logp(Level.FINER, MBeanServerFactory.class
0447 .getName(), "getMBeanInfo",
0448 "Building MBeanInfo for "
0449 + getImplementationClass().getName());
0450 }
0451
0452 MBeanSupport msupport = mbean;
0453 final MBeanInfo bi = msupport.getMBeanInfo();
0454 final Object impl = msupport.getResource();
0455
0456 final boolean immutableInfo = immutableInfo(this .getClass());
0457
0458 final String cname = getClassName(bi);
0459 final String text = getDescription(bi);
0460 final MBeanConstructorInfo[] ctors = getConstructors(bi, impl);
0461 final MBeanAttributeInfo[] attrs = getAttributes(bi);
0462 final MBeanOperationInfo[] ops = getOperations(bi);
0463 final MBeanNotificationInfo[] ntfs = getNotifications(bi);
0464 final Descriptor desc = getDescriptor(bi, immutableInfo);
0465
0466 final MBeanInfo nmbi = new MBeanInfo(cname, text, attrs, ctors,
0467 ops, ntfs, desc);
0468 try {
0469 cacheMBeanInfo(nmbi);
0470 } catch (RuntimeException x) {
0471 if (MISC_LOGGER.isLoggable(Level.FINEST)) {
0472 MISC_LOGGER.logp(Level.FINEST, MBeanServerFactory.class
0473 .getName(), "getMBeanInfo",
0474 "Failed to cache MBeanInfo", x);
0475 }
0476 }
0477
0478 return nmbi;
0479 }
0480
0481 /**
0482 * Customization hook:
0483 * Get the className that will be used in the MBeanInfo returned by
0484 * this MBean.
0485 * <br>
0486 * Subclasses may redefine this method in order to supply their
0487 * custom class name. The default implementation returns
0488 * {@link MBeanInfo#getClassName() info.getClassName()}.
0489 * @param info The default MBeanInfo derived by reflection.
0490 * @return the class name for the new MBeanInfo.
0491 **/
0492 protected String getClassName(MBeanInfo info) {
0493 if (info == null)
0494 return getImplementationClass().getName();
0495 return info.getClassName();
0496 }
0497
0498 /**
0499 * Customization hook:
0500 * Get the description that will be used in the MBeanInfo returned by
0501 * this MBean.
0502 * <br>
0503 * Subclasses may redefine this method in order to supply their
0504 * custom MBean description. The default implementation returns
0505 * {@link MBeanInfo#getDescription() info.getDescription()}.
0506 * @param info The default MBeanInfo derived by reflection.
0507 * @return the description for the new MBeanInfo.
0508 **/
0509 protected String getDescription(MBeanInfo info) {
0510 if (info == null)
0511 return null;
0512 return info.getDescription();
0513 }
0514
0515 /**
0516 * <p>Customization hook:
0517 * Get the description that will be used in the MBeanFeatureInfo
0518 * returned by this MBean.</p>
0519 *
0520 * <p>Subclasses may redefine this method in order to supply
0521 * their custom description. The default implementation returns
0522 * {@link MBeanFeatureInfo#getDescription()
0523 * info.getDescription()}.</p>
0524 *
0525 * <p>This method is called by
0526 * {@link #getDescription(MBeanAttributeInfo)},
0527 * {@link #getDescription(MBeanOperationInfo)},
0528 * {@link #getDescription(MBeanConstructorInfo)}.</p>
0529 *
0530 * @param info The default MBeanFeatureInfo derived by reflection.
0531 * @return the description for the given MBeanFeatureInfo.
0532 **/
0533 protected String getDescription(MBeanFeatureInfo info) {
0534 if (info == null)
0535 return null;
0536 return info.getDescription();
0537 }
0538
0539 /**
0540 * Customization hook:
0541 * Get the description that will be used in the MBeanAttributeInfo
0542 * returned by this MBean.
0543 *
0544 * <p>Subclasses may redefine this method in order to supply their
0545 * custom description. The default implementation returns {@link
0546 * #getDescription(MBeanFeatureInfo)
0547 * getDescription((MBeanFeatureInfo) info)}.
0548 * @param info The default MBeanAttributeInfo derived by reflection.
0549 * @return the description for the given MBeanAttributeInfo.
0550 **/
0551 protected String getDescription(MBeanAttributeInfo info) {
0552 return getDescription((MBeanFeatureInfo) info);
0553 }
0554
0555 /**
0556 * Customization hook:
0557 * Get the description that will be used in the MBeanConstructorInfo
0558 * returned by this MBean.
0559 * <br>
0560 * Subclasses may redefine this method in order to supply their
0561 * custom description.
0562 * The default implementation returns {@link
0563 * #getDescription(MBeanFeatureInfo)
0564 * getDescription((MBeanFeatureInfo) info)}.
0565 * @param info The default MBeanConstructorInfo derived by reflection.
0566 * @return the description for the given MBeanConstructorInfo.
0567 **/
0568 protected String getDescription(MBeanConstructorInfo info) {
0569 return getDescription((MBeanFeatureInfo) info);
0570 }
0571
0572 /**
0573 * Customization hook:
0574 * Get the description that will be used for the <var>sequence</var>
0575 * MBeanParameterInfo of the MBeanConstructorInfo returned by this MBean.
0576 * <br>
0577 * Subclasses may redefine this method in order to supply their
0578 * custom description. The default implementation returns
0579 * {@link MBeanParameterInfo#getDescription() param.getDescription()}.
0580 *
0581 * @param ctor The default MBeanConstructorInfo derived by reflection.
0582 * @param param The default MBeanParameterInfo derived by reflection.
0583 * @param sequence The sequence number of the parameter considered
0584 * ("0" for the first parameter, "1" for the second parameter,
0585 * etc...).
0586 * @return the description for the given MBeanParameterInfo.
0587 **/
0588 protected String getDescription(MBeanConstructorInfo ctor,
0589 MBeanParameterInfo param, int sequence) {
0590 if (param == null)
0591 return null;
0592 return param.getDescription();
0593 }
0594
0595 /**
0596 * Customization hook:
0597 * Get the name that will be used for the <var>sequence</var>
0598 * MBeanParameterInfo of the MBeanConstructorInfo returned by this MBean.
0599 * <br>
0600 * Subclasses may redefine this method in order to supply their
0601 * custom parameter name. The default implementation returns
0602 * {@link MBeanParameterInfo#getName() param.getName()}.
0603 *
0604 * @param ctor The default MBeanConstructorInfo derived by reflection.
0605 * @param param The default MBeanParameterInfo derived by reflection.
0606 * @param sequence The sequence number of the parameter considered
0607 * ("0" for the first parameter, "1" for the second parameter,
0608 * etc...).
0609 * @return the name for the given MBeanParameterInfo.
0610 **/
0611 protected String getParameterName(MBeanConstructorInfo ctor,
0612 MBeanParameterInfo param, int sequence) {
0613 if (param == null)
0614 return null;
0615 return param.getName();
0616 }
0617
0618 /**
0619 * Customization hook:
0620 * Get the description that will be used in the MBeanOperationInfo
0621 * returned by this MBean.
0622 * <br>
0623 * Subclasses may redefine this method in order to supply their
0624 * custom description. The default implementation returns
0625 * {@link #getDescription(MBeanFeatureInfo)
0626 * getDescription((MBeanFeatureInfo) info)}.
0627 * @param info The default MBeanOperationInfo derived by reflection.
0628 * @return the description for the given MBeanOperationInfo.
0629 **/
0630 protected String getDescription(MBeanOperationInfo info) {
0631 return getDescription((MBeanFeatureInfo) info);
0632 }
0633
0634 /**
0635 * Customization hook:
0636 * Get the <var>impact</var> flag of the operation that will be used in
0637 * the MBeanOperationInfo returned by this MBean.
0638 * <br>
0639 * Subclasses may redefine this method in order to supply their
0640 * custom impact flag. The default implementation returns
0641 * {@link MBeanOperationInfo#getImpact() info.getImpact()}.
0642 * @param info The default MBeanOperationInfo derived by reflection.
0643 * @return the impact flag for the given MBeanOperationInfo.
0644 **/
0645 protected int getImpact(MBeanOperationInfo info) {
0646 if (info == null)
0647 return MBeanOperationInfo.UNKNOWN;
0648 return info.getImpact();
0649 }
0650
0651 /**
0652 * Customization hook:
0653 * Get the name that will be used for the <var>sequence</var>
0654 * MBeanParameterInfo of the MBeanOperationInfo returned by this MBean.
0655 * <br>
0656 * Subclasses may redefine this method in order to supply their
0657 * custom parameter name. The default implementation returns
0658 * {@link MBeanParameterInfo#getName() param.getName()}.
0659 *
0660 * @param op The default MBeanOperationInfo derived by reflection.
0661 * @param param The default MBeanParameterInfo derived by reflection.
0662 * @param sequence The sequence number of the parameter considered
0663 * ("0" for the first parameter, "1" for the second parameter,
0664 * etc...).
0665 * @return the name to use for the given MBeanParameterInfo.
0666 **/
0667 protected String getParameterName(MBeanOperationInfo op,
0668 MBeanParameterInfo param, int sequence) {
0669 if (param == null)
0670 return null;
0671 return param.getName();
0672 }
0673
0674 /**
0675 * Customization hook:
0676 * Get the description that will be used for the <var>sequence</var>
0677 * MBeanParameterInfo of the MBeanOperationInfo returned by this MBean.
0678 * <br>
0679 * Subclasses may redefine this method in order to supply their
0680 * custom description. The default implementation returns
0681 * {@link MBeanParameterInfo#getDescription() param.getDescription()}.
0682 *
0683 * @param op The default MBeanOperationInfo derived by reflection.
0684 * @param param The default MBeanParameterInfo derived by reflection.
0685 * @param sequence The sequence number of the parameter considered
0686 * ("0" for the first parameter, "1" for the second parameter,
0687 * etc...).
0688 * @return the description for the given MBeanParameterInfo.
0689 **/
0690 protected String getDescription(MBeanOperationInfo op,
0691 MBeanParameterInfo param, int sequence) {
0692 if (param == null)
0693 return null;
0694 return param.getDescription();
0695 }
0696
0697 /**
0698 * Customization hook:
0699 * Get the MBeanConstructorInfo[] that will be used in the MBeanInfo
0700 * returned by this MBean.
0701 * <br>
0702 * By default, this method returns <code>null</code> if the wrapped
0703 * implementation is not <var>this</var>. Indeed, if the wrapped
0704 * implementation is not this object itself, it will not be possible
0705 * to recreate a wrapped implementation by calling the implementation
0706 * constructors through <code>MBeanServer.createMBean(...)</code>.<br>
0707 * Otherwise, if the wrapped implementation is <var>this</var>,
0708 * <var>ctors</var> is returned.
0709 * <br>
0710 * Subclasses may redefine this method in order to modify this
0711 * behavior, if needed.
0712 * @param ctors The default MBeanConstructorInfo[] derived by reflection.
0713 * @param impl The wrapped implementation. If <code>null</code> is
0714 * passed, the wrapped implementation is ignored and
0715 * <var>ctors</var> is returned.
0716 * @return the MBeanConstructorInfo[] for the new MBeanInfo.
0717 **/
0718 protected MBeanConstructorInfo[] getConstructors(
0719 MBeanConstructorInfo[] ctors, Object impl) {
0720 if (ctors == null)
0721 return null;
0722 if (impl != null && impl != this )
0723 return null;
0724 return ctors;
0725 }
0726
0727 /**
0728 * Customization hook:
0729 * Get the MBeanNotificationInfo[] that will be used in the MBeanInfo
0730 * returned by this MBean.
0731 * <br>
0732 * Subclasses may redefine this method in order to supply their
0733 * custom notifications.
0734 * @param info The default MBeanInfo derived by reflection.
0735 * @return the MBeanNotificationInfo[] for the new MBeanInfo.
0736 **/
0737 MBeanNotificationInfo[] getNotifications(MBeanInfo info) {
0738 return null;
0739 }
0740
0741 /**
0742 * <p>Get the Descriptor that will be used in the MBeanInfo
0743 * returned by this MBean.</p>
0744 *
0745 * <p>Subclasses may redefine this method in order to supply
0746 * their custom descriptor.</p>
0747 *
0748 * <p>The default implementation of this method returns a Descriptor
0749 * that contains at least the field {@code interfaceClassName}, with
0750 * value {@link #getMBeanInterface()}.getName(). It may also contain
0751 * the field {@code immutableInfo}, with a value that is the string
0752 * {@code "true"} if the implementation can determine that the
0753 * {@code MBeanInfo} returned by {@link #getMBeanInfo()} will always
0754 * be the same. It may contain other fields: fields defined by the
0755 * JMX specification must have appropriate values, and other fields
0756 * must follow the conventions for non-standard field names.</p>
0757 *
0758 * @param info The default MBeanInfo derived by reflection.
0759 * @return the Descriptor for the new MBeanInfo.
0760 */
0761 Descriptor getDescriptor(MBeanInfo info, boolean immutableInfo) {
0762 ImmutableDescriptor desc = null;
0763 if (info == null || info.getDescriptor() == null
0764 || info.getDescriptor().getFieldNames().length == 0) {
0765 final String interfaceClassNameS = "interfaceClassName="
0766 + getMBeanInterface().getName();
0767 final String immutableInfoS = "immutableInfo="
0768 + immutableInfo;
0769 desc = new ImmutableDescriptor(interfaceClassNameS,
0770 immutableInfoS);
0771 desc = descriptors.get(desc);
0772 } else {
0773 Descriptor d = info.getDescriptor();
0774 Map<String, Object> fields = new HashMap<String, Object>();
0775 for (String fieldName : d.getFieldNames()) {
0776 if (fieldName.equals("immutableInfo")) {
0777 // Replace immutableInfo as the underlying MBean/MXBean
0778 // could already implement NotificationBroadcaster and
0779 // return immutableInfo=true in its MBeanInfo.
0780 fields.put(fieldName, Boolean
0781 .toString(immutableInfo));
0782 } else {
0783 fields.put(fieldName, d.getFieldValue(fieldName));
0784 }
0785 }
0786 desc = new ImmutableDescriptor(fields);
0787 }
0788 return desc;
0789 }
0790
0791 /**
0792 * Customization hook:
0793 * Return the MBeanInfo cached for this object.
0794 *
0795 * <p>Subclasses may redefine this method in order to implement their
0796 * own caching policy. The default implementation stores one
0797 * {@link MBeanInfo} object per instance.
0798 *
0799 * @return The cached MBeanInfo, or null if no MBeanInfo is cached.
0800 *
0801 * @see #cacheMBeanInfo(MBeanInfo)
0802 **/
0803 protected MBeanInfo getCachedMBeanInfo() {
0804 return cachedMBeanInfo;
0805 }
0806
0807 /**
0808 * Customization hook:
0809 * cache the MBeanInfo built for this object.
0810 *
0811 * <p>Subclasses may redefine this method in order to implement
0812 * their own caching policy. The default implementation stores
0813 * <code>info</code> in this instance. A subclass can define
0814 * other policies, such as not saving <code>info</code> (so it is
0815 * reconstructed every time {@link #getMBeanInfo()} is called) or
0816 * sharing a unique {@link MBeanInfo} object when several
0817 * <code>StandardMBean</code> instances have equal {@link
0818 * MBeanInfo} values.
0819 *
0820 * @param info the new <code>MBeanInfo</code> to cache. Any
0821 * previously cached value is discarded. This parameter may be
0822 * null, in which case there is no new cached value.
0823 **/
0824 protected void cacheMBeanInfo(MBeanInfo info) {
0825 cachedMBeanInfo = info;
0826 }
0827
0828 private boolean isMXBean() {
0829 return mbean.isMXBean();
0830 }
0831
0832 private static <T> boolean identicalArrays(T[] a, T[] b) {
0833 if (a == b)
0834 return true;
0835 if (a == null || b == null || a.length != b.length)
0836 return false;
0837 for (int i = 0; i < a.length; i++) {
0838 if (a[i] != b[i])
0839 return false;
0840 }
0841 return true;
0842 }
0843
0844 private static <T> boolean equal(T a, T b) {
0845 if (a == b)
0846 return true;
0847 if (a == null || b == null)
0848 return false;
0849 return a.equals(b);
0850 }
0851
0852 private static MBeanParameterInfo customize(MBeanParameterInfo pi,
0853 String name, String description) {
0854 if (equal(name, pi.getName())
0855 && equal(description, pi.getDescription()))
0856 return pi;
0857 else if (pi instanceof OpenMBeanParameterInfo) {
0858 OpenMBeanParameterInfo opi = (OpenMBeanParameterInfo) pi;
0859 return new OpenMBeanParameterInfoSupport(name, description,
0860 opi.getOpenType(), pi.getDescriptor());
0861 } else {
0862 return new MBeanParameterInfo(name, pi.getType(),
0863 description, pi.getDescriptor());
0864 }
0865 }
0866
0867 private static MBeanConstructorInfo customize(
0868 MBeanConstructorInfo ci, String description,
0869 MBeanParameterInfo[] signature) {
0870 if (equal(description, ci.getDescription())
0871 && identicalArrays(signature, ci.getSignature()))
0872 return ci;
0873 if (ci instanceof OpenMBeanConstructorInfo) {
0874 OpenMBeanParameterInfo[] oparams = paramsToOpenParams(signature);
0875 return new OpenMBeanConstructorInfoSupport(ci.getName(),
0876 description, oparams, ci.getDescriptor());
0877 } else {
0878 return new MBeanConstructorInfo(ci.getName(), description,
0879 signature, ci.getDescriptor());
0880 }
0881 }
0882
0883 private static MBeanOperationInfo customize(MBeanOperationInfo oi,
0884 String description, MBeanParameterInfo[] signature,
0885 int impact) {
0886 if (equal(description, oi.getDescription())
0887 && identicalArrays(signature, oi.getSignature())
0888 && impact == oi.getImpact())
0889 return oi;
0890 if (oi instanceof OpenMBeanOperationInfo) {
0891 OpenMBeanOperationInfo ooi = (OpenMBeanOperationInfo) oi;
0892 OpenMBeanParameterInfo[] oparams = paramsToOpenParams(signature);
0893 return new OpenMBeanOperationInfoSupport(oi.getName(),
0894 description, oparams, ooi.getReturnOpenType(),
0895 impact, oi.getDescriptor());
0896 } else {
0897 return new MBeanOperationInfo(oi.getName(), description,
0898 signature, oi.getReturnType(), impact, oi
0899 .getDescriptor());
0900 }
0901 }
0902
0903 private static MBeanAttributeInfo customize(MBeanAttributeInfo ai,
0904 String description) {
0905 if (equal(description, ai.getDescription()))
0906 return ai;
0907 if (ai instanceof OpenMBeanAttributeInfo) {
0908 OpenMBeanAttributeInfo oai = (OpenMBeanAttributeInfo) ai;
0909 return new OpenMBeanAttributeInfoSupport(ai.getName(),
0910 description, oai.getOpenType(), ai.isReadable(), ai
0911 .isWritable(), ai.isIs(), ai
0912 .getDescriptor());
0913 } else {
0914 return new MBeanAttributeInfo(ai.getName(), ai.getType(),
0915 description, ai.isReadable(), ai.isWritable(), ai
0916 .isIs(), ai.getDescriptor());
0917 }
0918 }
0919
0920 private static OpenMBeanParameterInfo[] paramsToOpenParams(
0921 MBeanParameterInfo[] params) {
0922 if (params instanceof OpenMBeanParameterInfo[])
0923 return (OpenMBeanParameterInfo[]) params;
0924 OpenMBeanParameterInfo[] oparams = new OpenMBeanParameterInfoSupport[params.length];
0925 System.arraycopy(params, 0, oparams, 0, params.length);
0926 return oparams;
0927 }
0928
0929 // ------------------------------------------------------------------
0930 // Build the custom MBeanConstructorInfo[]
0931 // ------------------------------------------------------------------
0932 private MBeanConstructorInfo[] getConstructors(MBeanInfo info,
0933 Object impl) {
0934 final MBeanConstructorInfo[] ctors = getConstructors(info
0935 .getConstructors(), impl);
0936 if (ctors == null)
0937 return null;
0938 final int ctorlen = ctors.length;
0939 final MBeanConstructorInfo[] nctors = new MBeanConstructorInfo[ctorlen];
0940 for (int i = 0; i < ctorlen; i++) {
0941 final MBeanConstructorInfo c = ctors[i];
0942 final MBeanParameterInfo[] params = c.getSignature();
0943 final MBeanParameterInfo[] nps;
0944 if (params != null) {
0945 final int plen = params.length;
0946 nps = new MBeanParameterInfo[plen];
0947 for (int ii = 0; ii < plen; ii++) {
0948 MBeanParameterInfo p = params[ii];
0949 nps[ii] = customize(p, getParameterName(c, p, ii),
0950 getDescription(c, p, ii));
0951 }
0952 } else {
0953 nps = null;
0954 }
0955 nctors[i] = customize(c, getDescription(c), nps);
0956 }
0957 return nctors;
0958 }
0959
0960 // ------------------------------------------------------------------
0961 // Build the custom MBeanOperationInfo[]
0962 // ------------------------------------------------------------------
0963 private MBeanOperationInfo[] getOperations(MBeanInfo info) {
0964 final MBeanOperationInfo[] ops = info.getOperations();
0965 if (ops == null)
0966 return null;
0967 final int oplen = ops.length;
0968 final MBeanOperationInfo[] nops = new MBeanOperationInfo[oplen];
0969 for (int i = 0; i < oplen; i++) {
0970 final MBeanOperationInfo o = ops[i];
0971 final MBeanParameterInfo[] params = o.getSignature();
0972 final MBeanParameterInfo[] nps;
0973 if (params != null) {
0974 final int plen = params.length;
0975 nps = new MBeanParameterInfo[plen];
0976 for (int ii = 0; ii < plen; ii++) {
0977 MBeanParameterInfo p = params[ii];
0978 nps[ii] = customize(p, getParameterName(o, p, ii),
0979 getDescription(o, p, ii));
0980 }
0981 } else {
0982 nps = null;
0983 }
0984 nops[i] = customize(o, getDescription(o), nps, getImpact(o));
0985 }
0986 return nops;
0987 }
0988
0989 // ------------------------------------------------------------------
0990 // Build the custom MBeanAttributeInfo[]
0991 // ------------------------------------------------------------------
0992 private MBeanAttributeInfo[] getAttributes(MBeanInfo info) {
0993 final MBeanAttributeInfo[] atts = info.getAttributes();
0994 if (atts == null)
0995 return null; // should not happen
0996 final MBeanAttributeInfo[] natts;
0997 final int attlen = atts.length;
0998 natts = new MBeanAttributeInfo[attlen];
0999 for (int i = 0; i < attlen; i++) {
1000 final MBeanAttributeInfo a = atts[i];
1001 natts[i] = customize(a, getDescription(a));
1002 }
1003 return natts;
1004 }
1005
1006 /**
1007 * <p>Allows the MBean to perform any operations it needs before
1008 * being registered in the MBean server. If the name of the MBean
1009 * is not specified, the MBean can provide a name for its
1010 * registration. If any exception is raised, the MBean will not be
1011 * registered in the MBean server.</p>
1012 *
1013 * <p>The default implementation of this method returns the {@code name}
1014 * parameter. It does nothing else for
1015 * Standard MBeans. For MXBeans, it records the {@code MBeanServer}
1016 * and {@code ObjectName} parameters so they can be used to translate
1017 * inter-MXBean references.</p>
1018 *
1019 * <p>It is good practice for a subclass that overrides this method
1020 * to call the overridden method via {@code super.preRegister(...)}.
1021 * This is necessary if this object is an MXBean that is referenced
1022 * by attributes or operations in other MXBeans.</p>
1023 *
1024 * @param server The MBean server in which the MBean will be registered.
1025 *
1026 * @param name The object name of the MBean. This name is null if
1027 * the name parameter to one of the <code>createMBean</code> or
1028 * <code>registerMBean</code> methods in the {@link MBeanServer}
1029 * interface is null. In that case, this method must return a
1030 * non-null ObjectName for the new MBean.
1031 *
1032 * @return The name under which the MBean is to be registered.
1033 * This value must not be null. If the <code>name</code>
1034 * parameter is not null, it will usually but not necessarily be
1035 * the returned value.
1036 *
1037 * @throws IllegalArgumentException if this is an MXBean and
1038 * {@code name} is null.
1039 *
1040 * @throws InstanceAlreadyExistsException if this is an MXBean and
1041 * it has already been registered under another name (in this
1042 * MBean Server or another).
1043 *
1044 * @throws Exception no other checked exceptions are thrown by
1045 * this method but {@code Exception} is declared so that subclasses
1046 * can override the method and throw their own exceptions.
1047 *
1048 * @since 1.6
1049 */
1050 public ObjectName preRegister(MBeanServer server, ObjectName name)
1051 throws Exception {
1052 mbean.register(server, name);
1053 return name;
1054 }
1055
1056 /**
1057 * <p>Allows the MBean to perform any operations needed after having been
1058 * registered in the MBean server or after the registration has failed.</p>
1059 *
1060 * <p>The default implementation of this method does nothing for
1061 * Standard MBeans. For MXBeans, it undoes any work done by
1062 * {@link #preRegister preRegister} if registration fails.</p>
1063 *
1064 * <p>It is good practice for a subclass that overrides this method
1065 * to call the overridden method via {@code super.postRegister(...)}.
1066 * This is necessary if this object is an MXBean that is referenced
1067 * by attributes or operations in other MXBeans.</p>
1068 *
1069 * @param registrationDone Indicates whether or not the MBean has
1070 * been successfully registered in the MBean server. The value
1071 * false means that the registration phase has failed.
1072 *
1073 * @since 1.6
1074 */
1075 public void postRegister(Boolean registrationDone) {
1076 if (!registrationDone)
1077 mbean.unregister();
1078 }
1079
1080 /**
1081 * <p>Allows the MBean to perform any operations it needs before
1082 * being unregistered by the MBean server.</p>
1083 *
1084 * <p>The default implementation of this method does nothing.</p>
1085 *
1086 * <p>It is good practice for a subclass that overrides this method
1087 * to call the overridden method via {@code super.preDeegister(...)}.</p>
1088 *
1089 * @throws Exception no checked exceptions are throw by this method
1090 * but {@code Exception} is declared so that subclasses can override
1091 * this method and throw their own exceptions.
1092 *
1093 * @since 1.6
1094 */
1095 public void preDeregister() throws Exception {
1096 }
1097
1098 /**
1099 * <p>Allows the MBean to perform any operations needed after having been
1100 * unregistered in the MBean server.</p>
1101 *
1102 * <p>The default implementation of this method does nothing for
1103 * Standard MBeans. For MXBeans, it removes any information that
1104 * was recorded by the {@link #preRegister preRegister} method.</p>
1105 *
1106 * <p>It is good practice for a subclass that overrides this method
1107 * to call the overridden method via {@code super.postRegister(...)}.
1108 * This is necessary if this object is an MXBean that is referenced
1109 * by attributes or operations in other MXBeans.</p>
1110 *
1111 * @since 1.6
1112 */
1113 public void postDeregister() {
1114 mbean.unregister();
1115 }
1116
1117 //
1118 // MBeanInfo immutability
1119 //
1120
1121 /**
1122 * Cached results of previous calls to immutableInfo. This is
1123 * a WeakHashMap so that we don't prevent a class from being
1124 * garbage collected just because we know whether its MBeanInfo
1125 * is immutable.
1126 */
1127 private static final Map<Class, Boolean> mbeanInfoSafeMap = new WeakHashMap<Class, Boolean>();
1128
1129 /**
1130 * Return true if {@code subclass} is known to preserve the immutability
1131 * of the {@code MBeanInfo}. The {@code subclass} is considered to have
1132 * an immutable {@code MBeanInfo} if it does not override any of the
1133 * getMBeanInfo, getCachedMBeanInfo, cacheMBeanInfo and getNotificationInfo
1134 * methods.
1135 */
1136 static boolean immutableInfo(Class<? extends StandardMBean> subclass) {
1137 if (subclass == StandardMBean.class
1138 || subclass == StandardEmitterMBean.class)
1139 return true;
1140 synchronized (mbeanInfoSafeMap) {
1141 Boolean safe = mbeanInfoSafeMap.get(subclass);
1142 if (safe == null) {
1143 try {
1144 MBeanInfoSafeAction action = new MBeanInfoSafeAction(
1145 subclass);
1146 safe = AccessController.doPrivileged(action);
1147 } catch (Exception e) { // e.g. SecurityException
1148 /* We don't know, so we assume it isn't. */
1149 safe = false;
1150 }
1151 mbeanInfoSafeMap.put(subclass, safe);
1152 }
1153 return safe;
1154 }
1155 }
1156
1157 static boolean overrides(Class<?> subclass, Class<?> super class,
1158 String name, Class<?>... params) {
1159 for (Class<?> c = subclass; c != super class; c = c
1160 .getSuperclass()) {
1161 try {
1162 c.getDeclaredMethod(name, params);
1163 return true;
1164 } catch (NoSuchMethodException e) {
1165 // OK: this class doesn't override it
1166 }
1167 }
1168 return false;
1169 }
1170
1171 private static class MBeanInfoSafeAction implements
1172 PrivilegedAction<Boolean> {
1173
1174 private final Class subclass;
1175
1176 MBeanInfoSafeAction(Class subclass) {
1177 this .subclass = subclass;
1178 }
1179
1180 public Boolean run() {
1181 // Check for "void cacheMBeanInfo(MBeanInfo)" method.
1182 //
1183 if (overrides(subclass, StandardMBean.class,
1184 "cacheMBeanInfo", MBeanInfo.class))
1185 return false;
1186
1187 // Check for "MBeanInfo getCachedMBeanInfo()" method.
1188 //
1189 if (overrides(subclass, StandardMBean.class,
1190 "getCachedMBeanInfo", (Class[]) null))
1191 return false;
1192
1193 // Check for "MBeanInfo getMBeanInfo()" method.
1194 //
1195 if (overrides(subclass, StandardMBean.class,
1196 "getMBeanInfo", (Class[]) null))
1197 return false;
1198
1199 // Check for "MBeanNotificationInfo[] getNotificationInfo()"
1200 // method.
1201 //
1202 // This method is only taken into account for the MBeanInfo
1203 // immutability checks if and only if the given subclass is
1204 // StandardEmitterMBean itself or can be assigned to
1205 // StandardEmitterMBean.
1206 //
1207 if (StandardEmitterMBean.class.isAssignableFrom(subclass))
1208 if (overrides(subclass, StandardEmitterMBean.class,
1209 "getNotificationInfo", (Class[]) null))
1210 return false;
1211 return true;
1212 }
1213 }
1214
1215 }
|