001: /* JFox, the OpenSource J2EE Application Server
002: *
003: * Copyright (C) 2002 huihoo.org
004: * Distributable under GNU LGPL license
005: * See the GNU Lesser General Public License for more details.
006: */
007:
008: package javax.management.openmbean;
009:
010: import java.io.Serializable;
011:
012: /**
013: * The <code>ArrayType</code> class is the <i>open type</i> class whose instances describe
014: * all <i>open data</i> values which are n-dimensional arrays of <i>open data</i> values.
015: *
016: * @author <a href="mailto:young_yy@hotmail.org">Young Yang</a>
017: */
018:
019: public class ArrayType extends OpenType implements Serializable {
020:
021: /**
022: * @serial The dimension of arrays described by this {@link ArrayType} instance
023: */
024: private int dimension = 0;
025: /**
026: * @serial The <i>open type</i> of element values contained in the arrays described by
027: * this {@link ArrayType} instance
028: */
029: private OpenType elementType = null;
030: private transient Integer myHashCode = null;
031: private transient String myToString = null;
032:
033: /**
034: * Constructs an <tt>ArrayType</tt> instance describing <i>open data</i> values which are
035: * arrays with dimension <var>dimension</var> of elements whose <i>open type</i> is <var>elementType</var>.
036: * <p>
037: * When invoked on an <tt>ArrayType</tt> instance, the {@link OpenType#getClassName() getClassName} method
038: * returns the class name of the array instances it describes (following the rules defined by the
039: * {@link <a href="http://java.sun.com/j2se/1.3/docs/api/java/lang/Class.html#getNameSpace()">
040: * <code>getNameSpace</code></a>} method of <code>java.lang.Class</code>), not the class name of the array elements
041: * (which is returned by a call to <tt>getElementOpenType().getClassName()</tt>).
042: * <p>
043: * The internal field corresponding to the type name of this <code>ArrayType</code> instance is also set to
044: * the class name of the array instances it describes.
045: * In other words, the methods <code>getClassName</code> and <code>getTypeName</code> return the same string value.
046: * The internal field corresponding to the description of this <code>ArrayType</code> instance is set to a string value
047: * which follows the following template:<br>
048: * <tt><i><dimension></i>-dimension array of <i><element_class_name></i></tt>
049: * <p>
050: * As an example, the following piece of code:
051: * <pre>
052: * ArrayType t = new ArrayType(3, SimpleType.STRING);
053: * System.out.println("array class name = "+ t.getClassName());
054: * System.out.println("element class name = "+ t.getElementOpenType().getClassName());
055: * System.out.println("array type name = "+ t.getTypeName());
056: * System.out.println("array type description = "+ t.getDescription());
057: * </pre>
058: * would produce the following output:
059: * <pre>
060: * array class name = [[[java.lang.String;
061: * element class name = java.lang.String
062: * array type name = [[[java.lang.String;
063: * array type description = 3-dimension array of java.lang.String
064: * </pre>
065: *
066: * @param dimension the dimension of arrays described by this <tt>ArrayType</tt> instance;
067: * must be greater than or equal to 1.
068: *
069: * @param elementType the <i>open type</i> of element values contained in the arrays described by
070: * this <tt>ArrayType</tt> instance; must be an instance of either
071: * <tt>SimpleType</tt>, <tt>CompositeType</tt> or <tt>TabularType</tt>.
072: *
073: * @throws IllegalArgumentException if <var>dimension</var> is not a positive integer
074: *
075: * @throws OpenDataException if <var>elementType</var> is an instance of <tt>ArrayType</tt>
076: */
077: public ArrayType(int dimension, OpenType elementType)
078: throws OpenDataException {
079: super (
080: buildArrayClassName(dimension, elementType
081: .getClassName()), buildArrayClassName(
082: dimension, elementType.getClassName()), String
083: .valueOf(dimension)
084: + "-dimension array of "
085: + elementType.getClassName());
086: this .dimension = dimension;
087: this .elementType = elementType;
088:
089: }
090:
091: private static String buildArrayClassName(int dim, String className) {
092: if (dim < 1)
093: throw new IllegalArgumentException(
094: "Value of argument dimension must be greater than 0");
095: StringBuffer sb = new StringBuffer();
096: for (int i = 1; i < dim; i++)
097: sb.append('[');
098:
099: sb.append("[L");
100: sb.append(className);
101: sb.append(';');
102: return sb.toString();
103: }
104:
105: /**
106: * Returns the dimension of arrays described by this <tt>ArrayType</tt> instance.
107: *
108: * @return the dimension.
109: */
110: public int getDimension() {
111: return dimension;
112: }
113:
114: /**
115: * Returns the <i>open type</i> of element values contained in the arrays described by this <tt>ArrayType</tt> instance.
116: *
117: * @return the element type.
118: */
119: public OpenType getElementOpenType() {
120: return elementType;
121: }
122:
123: /**
124: * Tests whether <var>obj</var> is a value for this <code>ArrayType</code> instance.
125: * <p>
126: * This method returns <code>true</code> if and only if <var>obj</var> is not null, <var>obj</var> is an array
127: * and any one of the following is <tt>true</tt>:
128: * <p><ul>
129: * <li>if this <code>ArrayType</code> instance describes an array of <tt>SimpleType</tt> elements,
130: * <var>obj</var>'s class name is the same as the className field defined for this <code>ArrayType</code> instance
131: * (ie the class name returned by the {@link OpenType#getClassName() getClassName} method,
132: * which includes the dimension information),<br>
133: * </li>
134: * <li>if this <code>ArrayType</code> instance describes an array
135: * of classes implementing the TabularData interface or the CompositeData interface,
136: * <var>obj</var> is assignable to such a declared array,
137: * and each element contained in <var>obj</var> is either null or a valid value for the element's open type
138: * specified by this <code>ArrayType</code> instance.
139: * </li></ul>
140: * <p>
141: *
142: * @param obj the object to be tested.
143: *
144: * @return <code>true</code> if <var>obj</var> is a value for this <code>ArrayType</code> instance.
145: */
146: public boolean isValue(Object obj) {
147: if (obj == null)
148: return false;
149: Class cls = obj.getClass();
150: String className = cls.getName();
151: if (!cls.isArray())
152: return false; // not array class
153:
154: if (elementType instanceof SimpleType) { // SimpleType array
155: if (getClassName().equals(className))
156: return true;
157: return false;
158: } else if (elementType instanceof TabularData
159: || elementType instanceof CompositeData) {
160: Class arrClass = null; // is a array class of TabularData or CompositeData
161: try {
162: arrClass = Class.forName(getClassName()); // load the array class
163: } catch (ClassNotFoundException e) {
164: return false;
165: }
166: if (!arrClass.isAssignableFrom(cls))
167: return false;
168: return checkElementsType((Object[]) obj, dimension);
169: } else {
170: return false;
171: }
172: }
173:
174: /**
175: * Returns true if and only if all elements contained in the array argument x_dim_Array of dimension dim
176: * are valid values (ie either null or of the right openType)
177: * for the element open type specified by this ArrayType instance.
178: *
179: * This method's implementation uses recursion to go down the dimensions of the array argument.
180: */
181: private boolean checkElementsType(Object[] objArray, int dim) {
182: if (dim > 1) { // multi dimension
183: for (int j = 0; j < objArray.length; j++)
184: if (!checkElementsType((Object[]) objArray[j], dim - 1))
185: return false;
186:
187: return true;
188: }
189: for (int k = 0; k < objArray.length; k++)
190: if (objArray[k] != null
191: && !getElementOpenType().isValue(objArray[k]))
192: return false;
193:
194: return true;
195: }
196:
197: /**
198: * Compares the specified <code>obj</code> parameter with this <code>ArrayType</code> instance for equality.
199: * <p>
200: * Two <code>ArrayType</code> instances are equal if and only if they describes array instances
201: * which have the same dimension and elements' open type.
202: *
203: * @param obj the object to be compared for equality with this <code>ArrayType</code> instance;
204: * if <var>obj</var> is <code>null</code> or is not an instance of the class <code>ArrayType</code>,
205: * <code>equals</code> returns <code>false</code>.
206: *
207: * @return <code>true</code> if the specified object is equal to this <code>ArrayType</code> instance.
208: */
209: public boolean equals(Object obj) {
210: if (obj == null)
211: return false;
212: ArrayType arrType = null;
213: try {
214: arrType = (ArrayType) obj;
215: } catch (ClassCastException classcastexception) {
216: return false;
217: }
218: if (arrType.dimension != dimension)
219: return false;
220: else
221: return elementType.equals(arrType.elementType);
222: }
223:
224: /**
225: * Returns the hash code value for this <code>ArrayType</code> instance.
226: * <p>
227: * The hash code of a <code>ArrayType</code> instance is the sum of the hash codes
228: * of all elements of information used in <code>equals</code> comparisons
229: * (ie: dimension and elements' type).
230: * This ensures that <code> t1.equals(t2) </code> implies that <code> t1.hashCode()==t2.hashCode() </code>
231: * for any two <code>ArrayType</code> instances <code>t1</code> and <code>t2</code>,
232: * as required by the general contract of the method
233: * {@link <a href="http://java.sun.com/j2se/1.3/docs/api/java/lang/Object.html#hashCode()">
234: * <code>Object.hashCode</code> </a>}.
235: * <p>
236: * As <code>ArrayType</code> instances are immutable, the hash code for this instance is calculated once,
237: * on the first call to <code>hashCode</code>, and then the same value is returned for subsequent calls.
238: *
239: * @return the hash code value for this <code>ArrayType</code> instance
240: */
241: public int hashCode() {
242: if (myHashCode == null) {
243: int i = 0;
244: i += dimension;
245: i += elementType.hashCode();
246: myHashCode = new Integer(i);
247: }
248: return myHashCode.intValue();
249: }
250:
251: public String toString() {
252: if (myToString == null) {
253: myToString = getClass().getName() + "(name="
254: + getTypeName() + ",dimension=" + dimension
255: + ",elementType=" + elementType.toString() + ")";
256: }
257: return myToString;
258: }
259:
260: public static void main(String[] args) throws Exception {
261: System.out.println(new ArrayType(2, SimpleType.STRING)
262: .getElementOpenType() instanceof SimpleType);
263: }
264: }
|