MXBeanMappingFactory.java 7.1 KB
Newer Older
1
/*
X
xdono 已提交
2
 * Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.com if you need additional information or
 * have any questions.
 */

package javax.management.openmbean;

import com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory;
import java.lang.reflect.Type;

/**
 * <p>Defines how types are mapped for a given MXBean or set of MXBeans.
 * An {@code MXBeanMappingFactory} can be specified either through the
 * {@link MXBeanMappingFactoryClass} annotation, or through the
 * {@link javax.management.JMX.MBeanOptions JMX.MBeanOptions} argument to a
 * {@link javax.management.StandardMBean StandardMBean} constructor or MXBean
 * proxy.</p>
 *
 * <p>An {@code MXBeanMappingFactory} must return an {@code MXBeanMapping}
 * for any Java type that appears in the MXBeans that the factory is being
 * used for.  Usually it does that by handling any custom types, and
 * forwarding everything else to the {@linkplain #DEFAULT default mapping
 * factory}.</p>
 *
 * <p>Consider the {@code MyLinkedList} example from the {@link MXBeanMapping}
 * documentation.  If we are unable to change the {@code MyLinkedList} class
 * to add an {@link MXBeanMappingClass} annotation, we could achieve the same
 * effect by defining {@code MyLinkedListMappingFactory} as follows:</p>
 *
 * <pre>
 * public class MyLinkedListMappingFactory implements MXBeanMappingFactory {
 *     public MyLinkedListMappingFactory() {}
 *
 *     public MXBeanMapping mappingForType(Type t, MXBeanMappingFactory f)
 *     throws OpenDataException {
 *         if (t == MyLinkedList.class)
 *             return new MyLinkedListMapping(t);
 *         else
 *             return MXBeanMappingFactory.DEFAULT.mappingForType(t, f);
 *     }
 * }
 * </pre>
 *
 * <p>The mapping factory handles only the {@code MyLinkedList} class.
 * Every other type is forwarded to the default mapping factory.
 * This includes types such as {@code MyLinkedList[]} and
 * {@code List<MyLinkedList>}; the default mapping factory will recursively
 * invoke {@code MyLinkedListMappingFactory} to map the contained
 * {@code MyLinkedList} type.</p>
 *
 * <p>Once we have defined {@code MyLinkedListMappingFactory}, we can use
 * it in an MXBean interface like this:</p>
 *
 * <pre>
 * {@literal @MXBeanMappingFactoryClass}(MyLinkedListMappingFactory.class)
 * public interface SomethingMXBean {
 *     public MyLinkedList getSomething();
 * }
 * </pre>
 *
 * <p>Alternatively we can annotate the package that {@code SomethingMXBean}
 * appears in, or we can supply the factory to a {@link
 * javax.management.StandardMBean StandardMBean} constructor or MXBean
 * proxy.</p>
85 86 87
 *
 * @see <a href="../MXBean.html#custom">MXBean specification, section
 * "Custom MXBean type mappings"</a>
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
 */
public abstract class MXBeanMappingFactory {
    /**
     * <p>Construct an instance of this class.</p>
     */
    protected MXBeanMappingFactory() {}

    /**
     * <p>Mapping factory that applies the default rules for MXBean
     * mappings, as described in the <a
     * href="../MXBean.html#MXBean-spec">MXBean specification</a>.</p>
     */
    public static final MXBeanMappingFactory DEFAULT =
            new DefaultMXBeanMappingFactory();

    /**
     * <p>Determine the appropriate MXBeanMappingFactory to use for the given
     * MXBean interface, based on its annotations.  If the interface has an
     * {@link MXBeanMappingFactoryClass @MXBeanMappingFactoryClass} annotation,
     * that is used to determine the MXBeanMappingFactory.  Otherwise, if the
     * package containing the interface has such an annotation, that is used.
     * Otherwise the MXBeanMappingFactory is the {@linkplain #DEFAULT default}
     * one.</p>
     *
     * @param intf the MXBean interface for which to determine the
     * MXBeanMappingFactory.
     *
     * @return the MXBeanMappingFactory for the given MXBean interface.
     *
     * @throws IllegalArgumentException if {@code intf} is null, or if an
     * exception occurs while trying constructing an MXBeanMappingFactory
     * based on an annotation.  In the second case, the exception will appear
     * in the {@linkplain Throwable#getCause() cause chain} of the
     * {@code IllegalArgumentException}.
     */
    public static MXBeanMappingFactory forInterface(Class<?> intf) {
        if (intf == null)
            throw new IllegalArgumentException("Null interface");
        MXBeanMappingFactoryClass annot =
                intf.getAnnotation(MXBeanMappingFactoryClass.class);
        if (annot == null) {
            Package p = intf.getPackage();
            if (p != null)
                annot = p.getAnnotation(MXBeanMappingFactoryClass.class);
        }
        if (annot == null)
            return MXBeanMappingFactory.DEFAULT;
        Class<? extends MXBeanMappingFactory> factoryClass = annot.value();
        try {
            return annot.value().newInstance();
        } catch (Exception e) {
            throw new IllegalArgumentException(
                    "Could not instantiate MXBeanMappingFactory " +
                    factoryClass.getName() +
                    " from @MXBeanMappingFactoryClass", e);
        }
    }

    /**
     * <p>Return the mapping for the given Java type.  Typically, a
     * mapping factory will return mappings for types it handles, and
     * forward other types to another mapping factory, most often
     * the {@linkplain #DEFAULT default one}.</p>
     * @param t the Java type to be mapped.
     * @param f the original mapping factory that was consulted to do
     * the mapping.  A mapping factory should pass this parameter intact
     * if it forwards a type to another mapping factory.  In the example,
     * this is how {@code MyLinkedListMappingFactory} works for types
     * like {@code MyLinkedList[]} and {@code List<MyLinkedList>}.
     * @return the mapping for the given type.
     * @throws OpenDataException if this type cannot be mapped.  This
     * exception is appropriate if the factory is supposed to handle
     * all types of this sort (for example, all linked lists), but
     * cannot handle this particular type.
     */
    public abstract MXBeanMapping mappingForType(Type t, MXBeanMappingFactory f)
    throws OpenDataException;
}