jdk/src/share/classes/javax/management/openmbean/MXBeanMapping.java
changeset 4159 9e3aae7675f1
parent 4158 0b4d21bc8b5c
parent 4156 acaa49a2768a
child 4160 bda0a85afcb7
equal deleted inserted replaced
4158:0b4d21bc8b5c 4159:9e3aae7675f1
     1 /*
       
     2  * Copyright 2007-2008 Sun Microsystems, Inc.  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.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 package javax.management.openmbean;
       
    27 
       
    28 import java.io.InvalidObjectException;
       
    29 import java.lang.reflect.Type;
       
    30 
       
    31 /**
       
    32  * <p>A custom mapping between Java types and Open types for use in MXBeans.
       
    33  * To define such a mapping, subclass this class and define at least the
       
    34  * {@link #fromOpenValue fromOpenValue} and {@link #toOpenValue toOpenValue}
       
    35  * methods, and optionally the {@link #checkReconstructible} method.
       
    36  * Then either use an {@link MXBeanMappingClass} annotation on your custom
       
    37  * Java types, or include this MXBeanMapping in an
       
    38  * {@link MXBeanMappingFactory}.</p>
       
    39  *
       
    40  * <p>For example, suppose we have a class {@code MyLinkedList}, which looks
       
    41  * like this:</p>
       
    42  *
       
    43  * <pre>
       
    44  * public class MyLinkedList {
       
    45  *     public MyLinkedList(String name, MyLinkedList next) {...}
       
    46  *     public String getName() {...}
       
    47  *     public MyLinkedList getNext() {...}
       
    48  * }
       
    49  * </pre>
       
    50  *
       
    51  * <p>This is not a valid type for MXBeans, because it contains a
       
    52  * self-referential property "next" defined by the {@code getNext()}
       
    53  * method.  MXBeans do not support recursive types.  So we would like
       
    54  * to specify a mapping for {@code MyLinkedList} explicitly. When an
       
    55  * MXBean interface contains {@code MyLinkedList}, that will be mapped
       
    56  * into a {@code String[]}, which is a valid Open Type.</p>
       
    57  *
       
    58  * <p>To define this mapping, we first subclass {@code MXBeanMapping}:</p>
       
    59  *
       
    60  * <pre>
       
    61  * public class MyLinkedListMapping extends MXBeanMapping {
       
    62  *     public MyLinkedListMapping(Type type) throws OpenDataException {
       
    63  *         super(MyLinkedList.class, ArrayType.getArrayType(SimpleType.STRING));
       
    64  *         if (type != MyLinkedList.class)
       
    65  *             throw new OpenDataException("Mapping only valid for MyLinkedList");
       
    66  *     }
       
    67  *
       
    68  *     {@literal @Override}
       
    69  *     public Object fromOpenValue(Object openValue) throws InvalidObjectException {
       
    70  *         String[] array = (String[]) openValue;
       
    71  *         MyLinkedList list = null;
       
    72  *         for (int i = array.length - 1; i &gt;= 0; i--)
       
    73  *             list = new MyLinkedList(array[i], list);
       
    74  *         return list;
       
    75  *     }
       
    76  *
       
    77  *     {@literal @Override}
       
    78  *     public Object toOpenValue(Object javaValue) throws OpenDataException {
       
    79  *         ArrayList&lt;String&gt; array = new ArrayList&lt;String&gt;();
       
    80  *         for (MyLinkedList list = (MyLinkedList) javaValue; list != null;
       
    81  *              list = list.getNext())
       
    82  *             array.add(list.getName());
       
    83  *         return array.toArray(new String[0]);
       
    84  *     }
       
    85  * }
       
    86  * </pre>
       
    87  *
       
    88  * <p>The call to the superclass constructor specifies what the
       
    89  * original Java type is ({@code MyLinkedList.class}) and what Open
       
    90  * Type it is mapped to ({@code
       
    91  * ArrayType.getArrayType(SimpleType.STRING)}). The {@code
       
    92  * fromOpenValue} method says how we go from the Open Type ({@code
       
    93  * String[]}) to the Java type ({@code MyLinkedList}), and the {@code
       
    94  * toOpenValue} method says how we go from the Java type to the Open
       
    95  * Type.</p>
       
    96  *
       
    97  * <p>With this mapping defined, we can annotate the {@code MyLinkedList}
       
    98  * class appropriately:</p>
       
    99  *
       
   100  * <pre>
       
   101  * {@literal @MXBeanMappingClass}(MyLinkedListMapping.class)
       
   102  * public class MyLinkedList {...}
       
   103  * </pre>
       
   104  *
       
   105  * <p>Now we can use {@code MyLinkedList} in an MXBean interface and it
       
   106  * will work.</p>
       
   107  *
       
   108  * <p>If we are unable to modify the {@code MyLinkedList} class,
       
   109  * we can define an {@link MXBeanMappingFactory}.  See the documentation
       
   110  * of that class for further details.</p>
       
   111  *
       
   112  * @see <a href="../MXBean.html#custom">MXBean specification, section
       
   113  * "Custom MXBean type mappings"</a>
       
   114  */
       
   115 public abstract class MXBeanMapping {
       
   116     private final Type javaType;
       
   117     private final OpenType<?> openType;
       
   118     private final Class<?> openClass;
       
   119 
       
   120     /**
       
   121      * <p>Construct a mapping between the given Java type and the given
       
   122      * Open Type.</p>
       
   123      *
       
   124      * @param javaType the Java type (for example, {@code MyLinkedList}).
       
   125      * @param openType the Open Type (for example, {@code
       
   126      * ArrayType.getArrayType(SimpleType.STRING)})
       
   127      *
       
   128      * @throws NullPointerException if either argument is null.
       
   129      */
       
   130     protected MXBeanMapping(Type javaType, OpenType<?> openType) {
       
   131         if (javaType == null || openType == null)
       
   132             throw new NullPointerException("Null argument");
       
   133         this.javaType = javaType;
       
   134         this.openType = openType;
       
   135         this.openClass = makeOpenClass(javaType, openType);
       
   136     }
       
   137 
       
   138     /**
       
   139      * <p>The Java type that was supplied to the constructor.</p>
       
   140      * @return the Java type that was supplied to the constructor.
       
   141      */
       
   142     public final Type getJavaType() {
       
   143         return javaType;
       
   144     }
       
   145 
       
   146     /**
       
   147      * <p>The Open Type that was supplied to the constructor.</p>
       
   148      * @return the Open Type that was supplied to the constructor.
       
   149      */
       
   150     public final OpenType<?> getOpenType() {
       
   151         return openType;
       
   152     }
       
   153 
       
   154     /**
       
   155      * <p>The Java class that corresponds to instances of the
       
   156      * {@linkplain #getOpenType() Open Type} for this mapping.</p>
       
   157      * @return the Java class that corresponds to instances of the
       
   158      * Open Type for this mapping.
       
   159      * @see OpenType#getClassName
       
   160      */
       
   161     public final Class<?> getOpenClass() {
       
   162         return openClass;
       
   163     }
       
   164 
       
   165     private static Class<?> makeOpenClass(Type javaType, OpenType<?> openType) {
       
   166         if (javaType instanceof Class<?> && ((Class<?>) javaType).isPrimitive())
       
   167             return (Class<?>) javaType;
       
   168         try {
       
   169             String className = OpenType.validClassName(openType.getClassName());
       
   170             return Class.forName(className, false, null);
       
   171         } catch (ClassNotFoundException e) {
       
   172             throw new RuntimeException(e);  // should not happen
       
   173         } catch (OpenDataException e) {
       
   174             throw new IllegalArgumentException("Bad OpenType: " + openType, e);
       
   175         }
       
   176     }
       
   177 
       
   178     /**
       
   179      * <p>Convert an instance of the Open Type into the Java type.
       
   180      * @param openValue the value to be converted.
       
   181      * @return the converted value.
       
   182      * @throws InvalidObjectException if the value cannot be converted.
       
   183      */
       
   184     public abstract Object fromOpenValue(Object openValue)
       
   185     throws InvalidObjectException;
       
   186 
       
   187     /**
       
   188      * <p>Convert an instance of the Java type into the Open Type.
       
   189      * @param javaValue the value to be converted.
       
   190      * @return the converted value.
       
   191      * @throws OpenDataException if the value cannot be converted.
       
   192      */
       
   193     public abstract Object toOpenValue(Object javaValue)
       
   194     throws OpenDataException;
       
   195 
       
   196 
       
   197     /**
       
   198      * <p>Throw an appropriate InvalidObjectException if we will not
       
   199      * be able to convert back from the open data to the original Java
       
   200      * object.  The {@link #fromOpenValue fromOpenValue} throws an
       
   201      * exception if a given open data value cannot be converted.  This
       
   202      * method throws an exception if <em>no</em> open data values can
       
   203      * be converted.  The default implementation of this method never
       
   204      * throws an exception.  Subclasses can override it as
       
   205      * appropriate.</p>
       
   206      * @throws InvalidObjectException if {@code fromOpenValue} will throw
       
   207      * an exception no matter what its argument is.
       
   208      */
       
   209     public void checkReconstructible() throws InvalidObjectException {}
       
   210 }