Source for javax.management.openmbean.ArrayType

   1: /* ArrayType.java -- Open type descriptor for an array.
   2:    Copyright (C) 2006 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: package javax.management.openmbean;
  39: 
  40: import java.lang.reflect.Array;
  41: 
  42: import java.util.Arrays;
  43: 
  44: /**
  45:  * The open type descriptor for arrays of open data values.
  46:  * 
  47:  * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
  48:  * @since 1.5
  49:  */
  50: public class ArrayType
  51:   extends OpenType
  52: {
  53:   
  54:   /**
  55:    * Compatible with JDK 1.5
  56:    */
  57:   private static final long serialVersionUID = 720504429830309770L;
  58: 
  59:   /**
  60:    * The number of dimensions arrays of this type has.
  61:    */
  62:   private int dimension;
  63: 
  64:   /**
  65:    * The element type of arrays of this type.
  66:    */
  67:   private OpenType elementType;
  68: 
  69:   /**
  70:    * The hash code of this instance.
  71:    */
  72:   private transient Integer hashCode;
  73: 
  74:   /**
  75:    * The <code>toString()</code> result of this instance.
  76:    */
  77:   private transient String string;
  78: 
  79:   /**
  80:    * Returns the class name of the array, given the element
  81:    * class name and its dimensions.
  82:    *
  83:    * @param className the name of the class used by the
  84:    *                  array's elements.
  85:    * @param dim the dimensions of the array.
  86:    * @return the array's class name.
  87:    */
  88:   private static String getArrayClassName(String className, int dim)
  89:   {
  90:     char[] brackets = new char[dim];
  91:     Arrays.fill(brackets, '[');
  92:     return String.valueOf(brackets) + "L" + className;
  93:   }
  94: 
  95:   /**
  96:    * <p>
  97:    * Constructs a new {@link ArrayType} instance for an array of the
  98:    * specified type with the supplied number of dimensions.  The attributes
  99:    * used by the superclass, {@link OpenType}, are automatically defined,
 100:    * based on these values.  Both the class name and type name are set
 101:    * to the value returned by the {@link java.lang.Class#getName()} of
 102:    * the array's class (i.e. the element type, preceded by n instances of
 103:    * '[' and an 'L', where n is the number of dimensions the array has).
 104:    * The description is based upon the template <code>n-dimension array
 105:    * of e</code>, where n is the number of dimensions of the array, and
 106:    * e is the element type.  The class name of the actual elements is
 107:    * obtainable by calling {@link OpenType#getClassName()} on the result
 108:    * of {@link #getElementOpenType()}.
 109:    * </p>
 110:    * <p>
 111:    * As an example, the array type returned by
 112:    * <code>new ArrayType(6, SimpleType.INTEGER)</code> has the following
 113:    * values:
 114:    * </p>
 115:    * <table>
 116:    * <th><td>Attribute</td><td>Value</td></th>
 117:    * <tr><td>Class Name</td><td><code>[[[[[[Ljava.lang.Integer;</code>
 118:    * </td></tr>
 119:    * <tr><td>Type Name</td><td><code>[[[[[[Ljava.lang.Integer;</code>
 120:    * </td></tr>
 121:    * <tr><td>Description</td><td><code>6-dimension array of
 122:    * java.lang.Integer</code></td></tr>
 123:    * <tr><td>Element Type Class Name</td><td><code>java.lang.Integer</code>
 124:    * </td></tr>
 125:    * </table>
 126:    * <p>
 127:    * The dimensions of the array must be equal to or greater than 1.  The
 128:    * element type must be an instance of {@link SimpleType},
 129:    * {@link CompositeType} or {@link TabularType}.
 130:    * </p>
 131:    *
 132:    * @param dim the dimensions of the array.
 133:    * @param elementType the type of the elements of the array.
 134:    * @throws IllegalArgumentException if <code>dim</code> is less than 1.
 135:    * @throws OpenDataException if the element type is not an instance of either
 136:    *                           {@link SimpleType}, {@link CompositeType}
 137:    *                           or {@link TabularType}.
 138:    */
 139:   public ArrayType(int dim, OpenType elementType)
 140:     throws OpenDataException
 141:   {
 142:     super(getArrayClassName(elementType.getClassName(), dim),
 143:       getArrayClassName(elementType.getClassName(), dim),
 144:       dim + "-dimension array of " + elementType.getClassName());
 145:     if (dim < 1)
 146:       throw new IllegalArgumentException("Dimensions must be greater " +
 147:                      "than or equal to 1.");
 148:     if (!(elementType instanceof SimpleType ||
 149:       elementType instanceof CompositeType ||
 150:       elementType instanceof TabularType))
 151:       throw new OpenDataException("The element type must be a simple " +
 152:                   "type, a composite type or a tabular " +
 153:                   "type.");
 154:     dimension = dim;
 155:     this.elementType = elementType;
 156:   }
 157: 
 158:   /**
 159:    * <p>
 160:    * Compares this array type with another object
 161:    * for equality.  The objects are judged to be equal if:
 162:    * </p>
 163:    * <ul>
 164:    * <li><code>obj</code> is not null.</li>
 165:    * <li><code>obj</code> is an instance of
 166:    * {@link ArrayType}.</li>
 167:    * <li>The dimensions are equal.</li>
 168:    * <li>The element types are equal.</li>
 169:    * </ul>
 170:    * 
 171:    * @param obj the object to compare with.
 172:    * @return true if the conditions above hold.
 173:    */
 174:   public boolean equals(Object obj)
 175:   {
 176:     if (!(obj instanceof ArrayType))
 177:       return false;
 178:     ArrayType atype = (ArrayType) obj;
 179:     return (atype.getDimension() == dimension &&
 180:         atype.getElementOpenType().equals(elementType));
 181:   }
 182: 
 183:   /**
 184:    * Returns the number of dimensions used by arrays
 185:    * of this type.
 186:    *
 187:    * @return the number of dimensions.
 188:    */
 189:   public int getDimension()
 190:   {
 191:     return dimension;
 192:   }
 193: 
 194:   /**
 195:    * Returns the open type descriptor which describes
 196:    * the type of the elements of this array type.
 197:    *
 198:    * @return the type of the elements.
 199:    */
 200:   public OpenType getElementOpenType()
 201:   {
 202:     return elementType;
 203:   }
 204: 
 205:   /**
 206:    * <p>
 207:    * Returns the hash code of the array type.
 208:    * This is computed as the sum of the hash code of the
 209:    * element type together with the number of dimensions
 210:    * the array has.  These are the same elements
 211:    * of the type that are compared as part of the
 212:    * {@link #equals(java.lang.Object)} method, thus ensuring
 213:    * that the hashcode is compatible with the equality
 214:    * test.
 215:    * </p>
 216:    * <p>
 217:    * As instances of this class are immutable, the hash code
 218:    * is computed just once for each instance and reused
 219:    * throughout its life.
 220:    * </p>
 221:    *
 222:    * @return the hash code of this instance.
 223:    */
 224:   public int hashCode()
 225:   {
 226:     if (hashCode == null)
 227:       hashCode = Integer.valueOf(dimension + elementType.hashCode());
 228:     return hashCode.intValue();
 229:   }
 230: 
 231:   /**
 232:    * <p>
 233:    * Returns true if the specified object is a member of this
 234:    * array type.  The object is judged to be so if it is
 235:    * non-null, an array and one of the following two conditions
 236:    * holds:
 237:    * </p>
 238:    * <ul>
 239:    * <li>This {@link ArrayType} instance has a {@link SimpleType}
 240:    * as its element type.  Thus, the object must have the same
 241:    * class name as that returned by {@link SimpleType#getClassName()}
 242:    * for this class.</li>
 243:    * <li>This {@link ArrayType} instance has a {@link CompositeType}
 244:    * or a {@link TabularType} as its element type.  Thus, the object
 245:    * must be assignable to such an array, and have elements which
 246:    * are either null or valid values for the element type.</li>
 247:    * </ul>
 248:    *
 249:    * @param obj the object to test for membership.
 250:    * @return true if the object is a member of this type.
 251:    */
 252:   public boolean isValue(Object obj)
 253:   {
 254:     if (obj == null)
 255:       return false;
 256:     Class objClass = obj.getClass();
 257:     if (!(objClass.isArray()))
 258:       return false;
 259:     if (elementType instanceof SimpleType)
 260:       return getClassName().equals(objClass.getName());
 261:     Class elementClass = null;
 262:     try
 263:       {
 264:     elementClass = Class.forName(getClassName());
 265:       }
 266:     catch (ClassNotFoundException e)
 267:       {
 268:     throw new IllegalStateException("The array type's element " +
 269:                     "class could not be found.", e);
 270:       }
 271:     if (!(elementClass.isAssignableFrom(objClass)))
 272:       return false;
 273:     for (int a = 0; a < Array.getLength(obj); ++a)
 274:       {
 275:     Object elem = Array.get(obj, a);
 276:     if (elem != null &&
 277:         (!(elementType.isValue(elem))))
 278:       return false;
 279:       }
 280:     return true;
 281:   }
 282: 
 283:   /**
 284:    * <p>
 285:    * Returns a textual representation of this instance.  This
 286:    * is constructed using the class name
 287:    * (<code>javax.management.openmbean.ArrayType</code>)
 288:    * and each element of the instance which is relevant to
 289:    * the definition of {@link equals(java.lang.Object)} and
 290:    * {@link hashCode()} (i.e. the type name, the number of
 291:    * dimensions and the element type).
 292:    * </p>
 293:    * <p>
 294:    * As instances of this class are immutable, the return value
 295:    * is computed just once for each instance and reused
 296:    * throughout its life.
 297:    * </p>
 298:    *
 299:    * @return a @link{java.lang.String} instance representing
 300:    *         the instance in textual form.
 301:    */
 302:   public String toString()
 303:   {
 304:     if (string == null)
 305:       string = getClass().getName()
 306:     + "[name=" + getTypeName()
 307:     + ", dimension=" + dimension
 308:     + ", elementType=" + elementType
 309:     + "]";
 310:     return string;
 311:   }
 312: 
 313: }