Save This Page
Home » openjdk-7 » javax » management » openmbean » [javadoc | source]
    1   /*
    2    * Copyright 2000-2007 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   
   27   package javax.management.openmbean;
   28   
   29   
   30   // java import
   31   //
   32   import java.util.Set;
   33   import java.util.TreeMap;
   34   import java.util.Collections;
   35   import java.util.Iterator;
   36   
   37   // jmx import
   38   //
   39   
   40   
   41   /**
   42    * The <code>CompositeType</code> class is the <i>open type</i> class
   43    * whose instances describe the types of {@link CompositeData <code>CompositeData</code>} values.
   44    *
   45    *
   46    * @since 1.5
   47    */
   48   public class CompositeType extends OpenType<CompositeData> {
   49   
   50       /* Serial version */
   51       static final long serialVersionUID = -5366242454346948798L;
   52   
   53       /**
   54        * @serial Sorted mapping of the item names to their descriptions
   55        */
   56       private TreeMap<String,String> nameToDescription;
   57   
   58       /**
   59        * @serial Sorted mapping of the item names to their open types
   60        */
   61       private TreeMap<String,OpenType<?>> nameToType;
   62   
   63       /* As this instance is immutable, following three values need only
   64        * be calculated once.  */
   65       private transient Integer myHashCode = null;
   66       private transient String  myToString = null;
   67       private transient Set<String> myNamesSet = null;
   68   
   69   
   70       /* *** Constructor *** */
   71   
   72       /**
   73        * Constructs a <code>CompositeType</code> instance, checking for the validity of the given parameters.
   74        * The validity constraints are described below for each parameter.
   75        * <p>
   76        * Note that the contents of the three array parameters
   77        * <var>itemNames</var>, <var>itemDescriptions</var> and <var>itemTypes</var>
   78        * are internally copied so that any subsequent modification of these arrays by the caller of this constructor
   79        * has no impact on the constructed <code>CompositeType</code> instance.
   80        * <p>
   81        * The Java class name of composite data values this composite type represents
   82        * (ie the class name returned by the {@link OpenType#getClassName() getClassName} method)
   83        * is set to the string value returned by <code>CompositeData.class.getName()</code>.
   84        * <p>
   85        * @param  typeName  The name given to the composite type this instance represents; cannot be a null or empty string.
   86        * <br>&nbsp;
   87        * @param  description  The human readable description of the composite type this instance represents;
   88        *                      cannot be a null or empty string.
   89        * <br>&nbsp;
   90        * @param  itemNames  The names of the items contained in the
   91        *                    composite data values described by this <code>CompositeType</code> instance;
   92        *                    cannot be null and should contain at least one element; no element can be a null or empty string.
   93        *                    Note that the order in which the item names are given is not important to differentiate a
   94        *                    <code>CompositeType</code> instance from another;
   95        *                    the item names are internally stored sorted in ascending alphanumeric order.
   96        * <br>&nbsp;
   97        * @param  itemDescriptions  The descriptions, in the same order as <var>itemNames</var>, of the items contained in the
   98        *                           composite data values described by this <code>CompositeType</code> instance;
   99        *                           should be of the same size as <var>itemNames</var>;
  100        *                           no element can be a null or empty string.
  101        * <br>&nbsp;
  102        * @param  itemTypes  The open type instances, in the same order as <var>itemNames</var>, describing the items contained
  103        *                    in the composite data values described by this <code>CompositeType</code> instance;
  104        *                    should be of the same size as <var>itemNames</var>;
  105        *                    no element can be null.
  106        * <br>&nbsp;
  107        * @throws IllegalArgumentException  If <var>typeName</var> or <var>description</var> is a null or empty string,
  108        *                                   or <var>itemNames</var> or <var>itemDescriptions</var> or <var>itemTypes</var> is null,
  109        *                                   or any element of <var>itemNames</var> or <var>itemDescriptions</var>
  110        *                                   is a null or empty string,
  111        *                                   or any element of <var>itemTypes</var> is null,
  112        *                                   or <var>itemNames</var> or <var>itemDescriptions</var> or <var>itemTypes</var>
  113        *                                   are not of the same size.
  114        * <br>&nbsp;
  115        * @throws OpenDataException  If <var>itemNames</var> contains duplicate item names
  116        *                            (case sensitive, but leading and trailing whitespaces removed).
  117        */
  118       public CompositeType(String        typeName,
  119                            String        description,
  120                            String[]      itemNames,
  121                            String[]      itemDescriptions,
  122                            OpenType<?>[] itemTypes) throws OpenDataException {
  123   
  124           // Check and construct state defined by parent
  125           //
  126           super(CompositeData.class.getName(), typeName, description, false);
  127   
  128           // Check the 3 arrays are not null or empty (ie length==0) and that there is no null element or empty string in them
  129           //
  130           checkForNullElement(itemNames, "itemNames");
  131           checkForNullElement(itemDescriptions, "itemDescriptions");
  132           checkForNullElement(itemTypes, "itemTypes");
  133           checkForEmptyString(itemNames, "itemNames");
  134           checkForEmptyString(itemDescriptions, "itemDescriptions");
  135   
  136           // Check the sizes of the 3 arrays are the same
  137           //
  138           if ( (itemNames.length != itemDescriptions.length) || (itemNames.length != itemTypes.length) ) {
  139               throw new IllegalArgumentException("Array arguments itemNames[], itemDescriptions[] and itemTypes[] "+
  140                                                  "should be of same length (got "+ itemNames.length +", "+
  141                                                  itemDescriptions.length +" and "+ itemTypes.length +").");
  142           }
  143   
  144           // Initialize internal "names to descriptions" and "names to types" sorted maps,
  145           // and, by doing so, check there are no duplicate item names
  146           //
  147           nameToDescription = new TreeMap<String,String>();
  148           nameToType        = new TreeMap<String,OpenType<?>>();
  149           String key;
  150           for (int i=0; i<itemNames.length; i++) {
  151               key = itemNames[i].trim();
  152               if (nameToDescription.containsKey(key)) {
  153                   throw new OpenDataException("Argument's element itemNames["+ i +"]=\""+ itemNames[i] +
  154                                               "\" duplicates a previous item names.");
  155               }
  156               nameToDescription.put(key, itemDescriptions[i].trim());
  157               nameToType.put(key, itemTypes[i]);
  158           }
  159       }
  160   
  161       private static void checkForNullElement(Object[] arg, String argName) {
  162           if ( (arg == null) || (arg.length == 0) ) {
  163               throw new IllegalArgumentException("Argument "+ argName +"[] cannot be null or empty.");
  164           }
  165           for (int i=0; i<arg.length; i++) {
  166               if (arg[i] == null) {
  167                   throw new IllegalArgumentException("Argument's element "+ argName +"["+ i +"] cannot be null.");
  168               }
  169           }
  170       }
  171   
  172       private static void checkForEmptyString(String[] arg, String argName) {
  173           for (int i=0; i<arg.length; i++) {
  174               if (arg[i].trim().equals("")) {
  175                   throw new IllegalArgumentException("Argument's element "+ argName +"["+ i +"] cannot be an empty string.");
  176               }
  177           }
  178       }
  179   
  180       /* *** Composite type specific information methods *** */
  181   
  182       /**
  183        * Returns <code>true</code> if this <code>CompositeType</code> instance defines an item
  184        * whose name is <var>itemName</var>.
  185        *
  186        * @param itemName the name of the item.
  187        *
  188        * @return true if an item of this name is present.
  189        */
  190       public boolean containsKey(String itemName) {
  191   
  192           if (itemName == null) {
  193               return false;
  194           }
  195           return nameToDescription.containsKey(itemName);
  196       }
  197   
  198       /**
  199        * Returns the description of the item whose name is <var>itemName</var>,
  200        * or <code>null</code> if this <code>CompositeType</code> instance does not define any item
  201        * whose name is <var>itemName</var>.
  202        *
  203        * @param itemName the name of the item.
  204        *
  205        * @return the description.
  206        */
  207       public String getDescription(String itemName) {
  208   
  209           if (itemName == null) {
  210               return null;
  211           }
  212           return nameToDescription.get(itemName);
  213       }
  214   
  215       /**
  216        * Returns the <i>open type</i> of the item whose name is <var>itemName</var>,
  217        * or <code>null</code> if this <code>CompositeType</code> instance does not define any item
  218        * whose name is <var>itemName</var>.
  219        *
  220        * @param itemName the name of the time.
  221        *
  222        * @return the type.
  223        */
  224       public OpenType<?> getType(String itemName) {
  225   
  226           if (itemName == null) {
  227               return null;
  228           }
  229           return (OpenType<?>) nameToType.get(itemName);
  230       }
  231   
  232       /**
  233        * Returns an unmodifiable Set view of all the item names defined by this <code>CompositeType</code> instance.
  234        * The set's iterator will return the item names in ascending order.
  235        *
  236        * @return a {@link Set} of {@link String}.
  237        */
  238       public Set<String> keySet() {
  239   
  240           // Initializes myNamesSet on first call
  241           if (myNamesSet == null) {
  242               myNamesSet = Collections.unmodifiableSet(nameToDescription.keySet());
  243           }
  244   
  245           return myNamesSet; // always return the same value
  246       }
  247   
  248   
  249       /**
  250        * Tests whether <var>obj</var> is a value which could be
  251        * described by this <code>CompositeType</code> instance.
  252        *
  253        * <p>If <var>obj</var> is null or is not an instance of
  254        * <code>javax.management.openmbean.CompositeData</code>,
  255        * <code>isValue</code> returns <code>false</code>.</p>
  256        *
  257        * <p>If <var>obj</var> is an instance of
  258        * <code>javax.management.openmbean.CompositeData</code>, then let
  259        * {@code ct} be its {@code CompositeType} as returned by {@link
  260        * CompositeData#getCompositeType()}.  The result is true if
  261        * {@code this} is <em>assignable from</em> {@code ct}.  This
  262        * means that:</p>
  263        *
  264        * <ul>
  265        * <li>{@link #getTypeName() this.getTypeName()} equals
  266        * {@code ct.getTypeName()}, and
  267        * <li>there are no item names present in {@code this} that are
  268        * not also present in {@code ct}, and
  269        * <li>for every item in {@code this}, its type is assignable from
  270        * the type of the corresponding item in {@code ct}.
  271        * </ul>
  272        *
  273        * <p>A {@code TabularType} is assignable from another {@code
  274        * TabularType} if they have the same {@linkplain
  275        * TabularType#getTypeName() typeName} and {@linkplain
  276        * TabularType#getIndexNames() index name list}, and the
  277        * {@linkplain TabularType#getRowType() row type} of the first is
  278        * assignable from the row type of the second.
  279        *
  280        * <p>An {@code ArrayType} is assignable from another {@code
  281        * ArrayType} if they have the same {@linkplain
  282        * ArrayType#getDimension() dimension}; and both are {@linkplain
  283        * ArrayType#isPrimitiveArray() primitive arrays} or neither is;
  284        * and the {@linkplain ArrayType#getElementOpenType() element
  285        * type} of the first is assignable from the element type of the
  286        * second.
  287        *
  288        * <p>In every other case, an {@code OpenType} is assignable from
  289        * another {@code OpenType} only if they are equal.</p>
  290        *
  291        * <p>These rules mean that extra items can be added to a {@code
  292        * CompositeData} without making it invalid for a {@code CompositeType}
  293        * that does not have those items.</p>
  294        *
  295        * @param  obj  the value whose open type is to be tested for compatibility
  296        * with this <code>CompositeType</code> instance.
  297        *
  298        * @return <code>true</code> if <var>obj</var> is a value for this
  299        * composite type, <code>false</code> otherwise.
  300        */
  301       public boolean isValue(Object obj) {
  302   
  303           // if obj is null or not CompositeData, return false
  304           //
  305           if (!(obj instanceof CompositeData)) {
  306               return false;
  307           }
  308   
  309           // if obj is not a CompositeData, return false
  310           //
  311           CompositeData value = (CompositeData) obj;
  312   
  313           // test value's CompositeType is assignable to this CompositeType instance
  314           //
  315           CompositeType valueType = value.getCompositeType();
  316           return this.isAssignableFrom(valueType);
  317       }
  318   
  319       /**
  320        * Tests whether values of the given type can be assigned to this
  321        * open type.  The result is true if the given type is also a
  322        * CompositeType with the same name ({@link #getTypeName()}), and
  323        * every item in this type is also present in the given type with
  324        * the same name and assignable type.  There can be additional
  325        * items in the given type, which are ignored.
  326        *
  327        * @param ot the type to be tested.
  328        *
  329        * @return true if {@code ot} is assignable to this open type.
  330        */
  331       @Override
  332       boolean isAssignableFrom(OpenType ot) {
  333           if (!(ot instanceof CompositeType))
  334               return false;
  335           CompositeType ct = (CompositeType) ot;
  336           if (!ct.getTypeName().equals(getTypeName()))
  337               return false;
  338           for (String key : keySet()) {
  339               OpenType<?> otItemType = ct.getType(key);
  340               OpenType<?> thisItemType = getType(key);
  341               if (otItemType == null ||
  342                       !thisItemType.isAssignableFrom(otItemType))
  343                   return false;
  344           }
  345           return true;
  346       }
  347   
  348   
  349       /* *** Methods overriden from class Object *** */
  350   
  351       /**
  352        * Compares the specified <code>obj</code> parameter with this <code>CompositeType</code> instance for equality.
  353        * <p>
  354        * Two <code>CompositeType</code> instances are equal if and only if all of the following statements are true:
  355        * <ul>
  356        * <li>their type names are equal</li>
  357        * <li>their items' names and types are equal</li>
  358        * </ul>
  359        * <br>&nbsp;
  360        * @param  obj  the object to be compared for equality with this <code>CompositeType</code> instance;
  361        *              if <var>obj</var> is <code>null</code>, <code>equals</code> returns <code>false</code>.
  362        *
  363        * @return  <code>true</code> if the specified object is equal to this <code>CompositeType</code> instance.
  364        */
  365       public boolean equals(Object obj) {
  366   
  367           // if obj is null, return false
  368           //
  369           if (obj == null) {
  370               return false;
  371           }
  372   
  373           // if obj is not a CompositeType, return false
  374           //
  375           CompositeType other;
  376           try {
  377               other = (CompositeType) obj;
  378           } catch (ClassCastException e) {
  379               return false;
  380           }
  381   
  382           // Now, really test for equality between this CompositeType instance and the other
  383           //
  384   
  385           // their names should be equal
  386           if ( ! this.getTypeName().equals(other.getTypeName()) ) {
  387               return false;
  388           }
  389   
  390           // their items names and types should be equal
  391           if ( ! this.nameToType.equals(other.nameToType) ) {
  392               return false;
  393           }
  394   
  395           // All tests for equality were successfull
  396           //
  397           return true;
  398       }
  399   
  400       /**
  401        * Returns the hash code value for this <code>CompositeType</code> instance.
  402        * <p>
  403        * The hash code of a <code>CompositeType</code> instance is the sum of the hash codes
  404        * of all elements of information used in <code>equals</code> comparisons
  405        * (ie: name, items names, items types).
  406        * This ensures that <code> t1.equals(t2) </code> implies that <code> t1.hashCode()==t2.hashCode() </code>
  407        * for any two <code>CompositeType</code> instances <code>t1</code> and <code>t2</code>,
  408        * as required by the general contract of the method
  409        * {@link Object#hashCode() Object.hashCode()}.
  410        * <p>
  411        * As <code>CompositeType</code> instances are immutable, the hash code for this instance is calculated once,
  412        * on the first call to <code>hashCode</code>, and then the same value is returned for subsequent calls.
  413        *
  414        * @return  the hash code value for this <code>CompositeType</code> instance
  415        */
  416       public int hashCode() {
  417   
  418           // Calculate the hash code value if it has not yet been done (ie 1st call to hashCode())
  419           //
  420           if (myHashCode == null) {
  421               int value = 0;
  422               value += this.getTypeName().hashCode();
  423               String key;
  424               for (Iterator k = nameToDescription.keySet().iterator(); k.hasNext();  ) {
  425                   key = (String) k.next();
  426                   value += key.hashCode();
  427                   value += this.nameToType.get(key).hashCode();
  428               }
  429               myHashCode = Integer.valueOf(value);
  430           }
  431   
  432           // return always the same hash code for this instance (immutable)
  433           //
  434           return myHashCode.intValue();
  435       }
  436   
  437       /**
  438        * Returns a string representation of this <code>CompositeType</code> instance.
  439        * <p>
  440        * The string representation consists of
  441        * the name of this class (ie <code>javax.management.openmbean.CompositeType</code>), the type name for this instance,
  442        * and the list of the items names and types string representation of this instance.
  443        * <p>
  444        * As <code>CompositeType</code> instances are immutable, the string representation for this instance is calculated once,
  445        * on the first call to <code>toString</code>, and then the same value is returned for subsequent calls.
  446        *
  447        * @return  a string representation of this <code>CompositeType</code> instance
  448        */
  449       public String toString() {
  450   
  451           // Calculate the string representation if it has not yet been done (ie 1st call to toString())
  452           //
  453           if (myToString == null) {
  454               final StringBuilder result = new StringBuilder();
  455               result.append(this.getClass().getName());
  456               result.append("(name=");
  457               result.append(getTypeName());
  458               result.append(",items=(");
  459               int i=0;
  460               Iterator k=nameToType.keySet().iterator();
  461               String key;
  462               while (k.hasNext()) {
  463                   key = (String) k.next();
  464                   if (i > 0) result.append(",");
  465                   result.append("(itemName=");
  466                   result.append(key);
  467                   result.append(",itemType=");
  468                   result.append(nameToType.get(key).toString() +")");
  469                   i++;
  470               }
  471               result.append("))");
  472               myToString = result.toString();
  473           }
  474   
  475           // return always the same string representation for this instance (immutable)
  476           //
  477           return myToString;
  478       }
  479   
  480   }

Save This Page
Home » openjdk-7 » javax » management » openmbean » [javadoc | source]