/* * @(#)ArrayType.java 3.24 03/12/19 * * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package javax.management.openmbean; // java import // import java.io.Serializable; // jmx import // /** * The ArrayType class is the open type class whose instances describe * all open data values which are n-dimensional arrays of open data values. * * @version 3.24 03/12/19 * @author Sun Microsystems, Inc. * * @since 1.5 * @since.unbundled JMX 1.1 */ public class ArrayType extends OpenType implements Serializable { /* Serial version */ static final long serialVersionUID = 720504429830309770L; /** * @serial The dimension of arrays described by this {@link ArrayType} instance */ private int dimension; /** * @serial The open type of element values contained in the arrays described by * this {@link ArrayType} instance */ private OpenType elementType; private transient Integer myHashCode = null; // As this instance is immutable, these two values private transient String myToString = null; // need only be calculated once. /* *** Constructor *** */ /** * Constructs an ArrayType instance describing open data values which are * arrays with dimension dimension of elements whose open type is elementType. *

* When invoked on an ArrayType instance, the {@link OpenType#getClassName() getClassName} method * returns the class name of the array instances it describes (following the rules defined by the * {@link Class#getName() getName} method of java.lang.Class), not the class name of the array elements * (which is returned by a call to getElementOpenType().getClassName()). *

* The internal field corresponding to the type name of this ArrayType instance is also set to * the class name of the array instances it describes. * In other words, the methods getClassName and getTypeName return the same string value. * The internal field corresponding to the description of this ArrayType instance is set to a string value * which follows the following template:
* <dimension>-dimension array of <element_class_name> *

* As an example, the following piece of code: *

     * ArrayType t = new ArrayType(3, SimpleType.STRING);
     * System.out.println("array class name       = "+ t.getClassName());
     * System.out.println("element class name     = "+ t.getElementOpenType().getClassName());
     * System.out.println("array type name        = "+ t.getTypeName());
     * System.out.println("array type description = "+ t.getDescription());
     * 
* would produce the following output: *
     * array class name       = [[[java.lang.String;
     * element class name     = java.lang.String
     * array type name        = [[[java.lang.String;
     * array type description = 3-dimension array of java.lang.String
     * 
* * @param dimension the dimension of arrays described by this ArrayType instance; * must be greater than or equal to 1. * * @param elementType the open type of element values contained in the arrays described by * this ArrayType instance; must be an instance of either * SimpleType, CompositeType or TabularType. * * @throws IllegalArgumentException if dimension is not a positive integer * * @throws OpenDataException if elementType is an instance of ArrayType */ public ArrayType(int dimension, OpenType elementType) throws OpenDataException { // Check and construct state defined by parent. // super(buildArrayClassName(dimension, elementType.getClassName()), buildArrayClassName(dimension, elementType.getClassName()), String.valueOf(dimension) +"-dimension array of "+ elementType.getClassName()); // Check and construct state specific to ArrayType // this.dimension = dimension; // already checked >=1 in buildArrayClassName this.elementType = elementType; // cannot be ArrayType: super() would throw exception on the built classname } /** * */ private static String buildArrayClassName(int dimension, String elementClassName) throws OpenDataException { if (dimension < 1) { throw new IllegalArgumentException("Value of argument dimension must be greater than 0"); } StringBuffer result = new StringBuffer(); for (int i=1; iArrayType instance. * * @return the dimension. */ public int getDimension() { return dimension; } /** * Returns the open type of element values contained in the arrays described by this ArrayType instance. * * @return the element type. */ public OpenType getElementOpenType() { return elementType; } /** * Tests whether obj is a value for this ArrayType instance. *

* This method returns true if and only if obj is not null, obj is an array * and any one of the following is true: *

*

* * @param obj the object to be tested. * * @return true if obj is a value for this ArrayType instance. */ public boolean isValue(Object obj) { // if obj is null, return false // if (obj == null) { return false; } Class objClass = obj.getClass(); String objClassName = objClass.getName(); // if obj is not an array, return false // if ( ! objClass.isArray() ) { return false; } // Test if obj's class name is the same as for the array values that this instance describes // (this is fine if elements are of simple types, which are final classes) // if ( this.getClassName().equals(objClassName) ) { return true; } // In case this ArrayType instance describes an array of classes implementing the TabularData or CompositeData interface, // we first check for the assignability of obj to such an array of TabularData or CompositeData, // which ensures that: // . obj is of the the same dimension as this ArrayType instance, // . it is declared as an array of elements which are either all TabularData or all CompositeData. // // If the assignment check is positive, // then we have to check that each element in obj is of the same TabularType or CompositeType // as the one described by this ArrayType instance. // // [About assignment check, note that the call below returns true: ] // [Class.forName("[Lpackage.CompositeData;").isAssignableFrom(Class.forName("[Lpackage.CompositeDataImpl;)")); ] // if ( (this.elementType.getClassName().equals(TabularData.class.getName())) || (this.elementType.getClassName().equals(CompositeData.class.getName())) ) { /* this.getClassName() is * "[Ljavax.management.openmbean.TabularData;" or the same * thing for CompositeData, either one optionally preceded * by n '[' characters. So the class is necessarily known * to the ClassLoader of ArrayType, and Class.forName is * safe. */ Class targetClass; try { targetClass = Class.forName(this.getClassName()); } catch (ClassNotFoundException e) { // should not happen return false; } // assignment check: return false if negative if ( ! targetClass.isAssignableFrom(objClass) ) { return false; } // check that all elements in obj are valid values for this ArrayType if ( ! checkElementsType( (Object[]) obj, this.dimension) ) { // we know obj's dimension is this.dimension return false; } return true; } // if previous tests did not return, then obj is not a value for this ArrayType instance return false; } /** * Returns true if and only if all elements contained in the array argument x_dim_Array of dimension dim * are valid values (ie either null or of the right openType) * for the element open type specified by this ArrayType instance. * * This method's implementation uses recursion to go down the dimensions of the array argument. */ private boolean checkElementsType(Object[] x_dim_Array, int dim) { // if the elements of x_dim_Array are themselves array: go down recursively.... if ( dim > 1 ) { for (int i=0; iobj parameter with this ArrayType instance for equality. *

* Two ArrayType instances are equal if and only if they describes array instances * which have the same dimension and elements' open type. * * @param obj the object to be compared for equality with this ArrayType instance; * if obj is null or is not an instance of the class ArrayType, * equals returns false. * * @return true if the specified object is equal to this ArrayType instance. */ public boolean equals(Object obj) { // if obj is null, return false // if (obj == null) { return false; } // if obj is not an ArrayType, return false // ArrayType other; try { other = (ArrayType) obj; } catch (ClassCastException e) { return false; } // if other's dimension is different than this instance's, return false // if (other.dimension != this.dimension) { return false; } // Test if other's elementType field is the same as for this instance // return this.elementType.equals(other.elementType); } /** * Returns the hash code value for this ArrayType instance. *

* The hash code of a ArrayType instance is the sum of the hash codes * of all elements of information used in equals comparisons * (ie: dimension and elements' type). * This ensures that t1.equals(t2) implies that t1.hashCode()==t2.hashCode() * for any two ArrayType instances t1 and t2, * as required by the general contract of the method * {@link Object#hashCode() Object.hashCode()}. *

* As ArrayType instances are immutable, the hash code for this instance is calculated once, * on the first call to hashCode, and then the same value is returned for subsequent calls. * * @return the hash code value for this ArrayType instance */ public int hashCode() { // Calculate the hash code value if it has not yet been done (ie 1st call to hashCode()) // if (myHashCode == null) { int value = 0; value += this.dimension; value += this.elementType.hashCode(); myHashCode = new Integer(value); } // return always the same hash code for this instance (immutable) // return myHashCode.intValue(); } /** * Returns a string representation of this ArrayType instance. *

* The string representation consists of * the name of this class (ie javax.management.openmbean.ArrayType), the type name, * the dimension and elements' type defined for this instance, *

* As ArrayType instances are immutable, the string representation for this instance is calculated once, * on the first call to toString, and then the same value is returned for subsequent calls. * * @return a string representation of this ArrayType instance */ public String toString() { // Calculate the string representation if it has not yet been done (ie 1st call to toString()) // if (myToString == null) { StringBuffer result = new StringBuffer(); result.append(this.getClass().getName()); result.append("(name="); result.append(getTypeName()); result.append(",dimension="); result.append(String.valueOf(this.dimension)); result.append(",elementType="); result.append(this.elementType.toString()); result.append(")"); myToString = result.toString(); } // return always the same string representation for this instance (immutable) // return myToString; } }