History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/javax/management/openmbean/ArrayType.java (1 of 18352 files). Show all

Unified · Split

java/pkg/javax/management/openmbean/ArrayType.java+1027−0
@@ -0,0 +1,1027 @@
1+/*
2+ * Copyright (c) 2000, 2008, Oracle and/or its affiliates. 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. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package javax.management.openmbean;
27+
28+import java.io.ObjectStreamException;
29+import java.lang.reflect.Array;
30+
31+/**
32+ * The <code>ArrayType</code> class is the <i>open type</i> class whose instances describe
33+ * all <i>open data</i> values which are n-dimensional arrays of <i>open data</i> values.
34+ * <p>
35+ * Examples of valid {@code ArrayType} instances are:
36+ * <pre>
37+ * // 2-dimension array of java.lang.String
38+ * ArrayType<String[][]> a1 = new ArrayType<String[][]>(2, SimpleType.STRING);
39+ *
40+ * // 1-dimension array of int
41+ * ArrayType<int[]> a2 = new ArrayType<int[]>(SimpleType.INTEGER, true);
42+ *
43+ * // 1-dimension array of java.lang.Integer
44+ * ArrayType<Integer[]> a3 = new ArrayType<Integer[]>(SimpleType.INTEGER, false);
45+ *
46+ * // 4-dimension array of int
47+ * ArrayType<int[][][][]> a4 = new ArrayType<int[][][][]>(3, a2);
48+ *
49+ * // 4-dimension array of java.lang.Integer
50+ * ArrayType<Integer[][][][]> a5 = new ArrayType<Integer[][][][]>(3, a3);
51+ *
52+ * // 1-dimension array of java.lang.String
53+ * ArrayType<String[]> a6 = new ArrayType<String[]>(SimpleType.STRING, false);
54+ *
55+ * // 1-dimension array of long
56+ * ArrayType<long[]> a7 = new ArrayType<long[]>(SimpleType.LONG, true);
57+ *
58+ * // 1-dimension array of java.lang.Integer
59+ * ArrayType<Integer[]> a8 = ArrayType.getArrayType(SimpleType.INTEGER);
60+ *
61+ * // 2-dimension array of java.lang.Integer
62+ * ArrayType<Integer[][]> a9 = ArrayType.getArrayType(a8);
63+ *
64+ * // 2-dimension array of int
65+ * ArrayType<int[][]> a10 = ArrayType.getPrimitiveArrayType(int[][].class);
66+ *
67+ * // 3-dimension array of int
68+ * ArrayType<int[][][]> a11 = ArrayType.getArrayType(a10);
69+ *
70+ * // 1-dimension array of float
71+ * ArrayType<float[]> a12 = ArrayType.getPrimitiveArrayType(float[].class);
72+ *
73+ * // 2-dimension array of float
74+ * ArrayType<float[][]> a13 = ArrayType.getArrayType(a12);
75+ *
76+ * // 1-dimension array of javax.management.ObjectName
77+ * ArrayType<ObjectName[]> a14 = ArrayType.getArrayType(SimpleType.OBJECTNAME);
78+ *
79+ * // 2-dimension array of javax.management.ObjectName
80+ * ArrayType<ObjectName[][]> a15 = ArrayType.getArrayType(a14);
81+ *
82+ * // 3-dimension array of java.lang.String
83+ * ArrayType<String[][][]> a16 = new ArrayType<String[][][]>(3, SimpleType.STRING);
84+ *
85+ * // 1-dimension array of java.lang.String
86+ * ArrayType<String[]> a17 = new ArrayType<String[]>(1, SimpleType.STRING);
87+ *
88+ * // 2-dimension array of java.lang.String
89+ * ArrayType<String[][]> a18 = new ArrayType<String[][]>(1, a17);
90+ *
91+ * // 3-dimension array of java.lang.String
92+ * ArrayType<String[][][]> a19 = new ArrayType<String[][][]>(1, a18);
93+ * </pre>
94+ *
95+ *
96+ * @since 1.5
97+ */
98+/*
99+ Generification note: we could have defined a type parameter that is the
100+ element type, with class ArrayType<E> extends OpenType<E[]>. However,
101+ that doesn't buy us all that much. We can't say
102+ public OpenType<E> getElementOpenType()
103+ because this ArrayType could be a multi-dimensional array.
104+ For example, if we had
105+ ArrayType(2, SimpleType.INTEGER)
106+ then E would have to be Integer[], while getElementOpenType() would
107+ return SimpleType.INTEGER, which is an OpenType<Integer>.
108+
109+ Furthermore, we would like to support int[] (as well as Integer[]) as
110+ an Open Type (RFE 5045358). We would want this to be an OpenType<int[]>
111+ which can't be expressed as <E[]> because E can't be a primitive type
112+ like int.
113+ */
114+public class ArrayType<T> extends OpenType<T> {
115+
116+ /* Serial version */
117+ static final long serialVersionUID = 720504429830309770L;
118+
119+ /**
120+ * @serial The dimension of arrays described by this {@link ArrayType}
121+ * instance.
122+ */
123+ private int dimension;
124+
125+ /**
126+ * @serial The <i>open type</i> of element values contained in the arrays
127+ * described by this {@link ArrayType} instance.
128+ */
129+ private OpenType<?> elementType;
130+
131+ /**
132+ * @serial This flag indicates whether this {@link ArrayType}
133+ * describes a primitive array.
134+ *
135+ * @since 1.6
136+ */
137+ private boolean primitiveArray;
138+
139+ private transient Integer myHashCode = null; // As this instance is immutable, these two values
140+ private transient String myToString = null; // need only be calculated once.
141+
142+ // indexes refering to columns in the PRIMITIVE_ARRAY_TYPES table.
143+ private static final int PRIMITIVE_WRAPPER_NAME_INDEX = 0;
144+ private static final int PRIMITIVE_TYPE_NAME_INDEX = 1;
145+ private static final int PRIMITIVE_TYPE_KEY_INDEX = 2;
146+ private static final int PRIMITIVE_OPEN_TYPE_INDEX = 3;
147+
148+ private static final Object[][] PRIMITIVE_ARRAY_TYPES = {
149+ { Boolean.class.getName(), boolean.class.getName(), "Z", SimpleType.BOOLEAN },
150+ { Character.class.getName(), char.class.getName(), "C", SimpleType.CHARACTER },
151+ { Byte.class.getName(), byte.class.getName(), "B", SimpleType.BYTE },
152+ { Short.class.getName(), short.class.getName(), "S", SimpleType.SHORT },
153+ { Integer.class.getName(), int.class.getName(), "I", SimpleType.INTEGER },
154+ { Long.class.getName(), long.class.getName(), "J", SimpleType.LONG },
155+ { Float.class.getName(), float.class.getName(), "F", SimpleType.FLOAT },
156+ { Double.class.getName(), double.class.getName(), "D", SimpleType.DOUBLE }
157+ };
158+
159+ static boolean isPrimitiveContentType(final String primitiveKey) {
160+ for (Object[] typeDescr : PRIMITIVE_ARRAY_TYPES) {
161+ if (typeDescr[PRIMITIVE_TYPE_KEY_INDEX].equals(primitiveKey)) {
162+ return true;
163+ }
164+ }
165+ return false;
166+ }
167+
168+ /**
169+ * Return the key used to identify the element type in
170+ * arrays - e.g. "Z" for boolean, "C" for char etc...
171+ * @param elementClassName the wrapper class name of the array
172+ * element ("Boolean", "Character", etc...)
173+ * @return the key corresponding to the given type ("Z", "C", etc...)
174+ * return null if the given elementClassName is not a primitive
175+ * wrapper class name.
176+ **/
177+ static String getPrimitiveTypeKey(String elementClassName) {
178+ for (Object[] typeDescr : PRIMITIVE_ARRAY_TYPES) {
179+ if (elementClassName.equals(typeDescr[PRIMITIVE_WRAPPER_NAME_INDEX]))
180+ return (String)typeDescr[PRIMITIVE_TYPE_KEY_INDEX];
181+ }
182+ return null;
183+ }
184+
185+ /**
186+ * Return the primitive type name corresponding to the given wrapper class.
187+ * e.g. "boolean" for "Boolean", "char" for "Character" etc...
188+ * @param elementClassName the type of the array element ("Boolean",
189+ * "Character", etc...)
190+ * @return the primitive type name corresponding to the given wrapper class
191+ * ("boolean", "char", etc...)
192+ * return null if the given elementClassName is not a primitive
193+ * wrapper type name.
194+ **/
195+ static String getPrimitiveTypeName(String elementClassName) {
196+ for (Object[] typeDescr : PRIMITIVE_ARRAY_TYPES) {
197+ if (elementClassName.equals(typeDescr[PRIMITIVE_WRAPPER_NAME_INDEX]))
198+ return (String)typeDescr[PRIMITIVE_TYPE_NAME_INDEX];
199+ }
200+ return null;
201+ }
202+
203+ /**
204+ * Return the primitive open type corresponding to the given primitive type.
205+ * e.g. SimpleType.BOOLEAN for "boolean", SimpleType.CHARACTER for
206+ * "char", etc...
207+ * @param primitiveTypeName the primitive type of the array element ("boolean",
208+ * "char", etc...)
209+ * @return the OpenType corresponding to the given primitive type name
210+ * (SimpleType.BOOLEAN, SimpleType.CHARACTER, etc...)
211+ * return null if the given elementClassName is not a primitive
212+ * type name.
213+ **/
214+ static SimpleType<?> getPrimitiveOpenType(String primitiveTypeName) {
215+ for (Object[] typeDescr : PRIMITIVE_ARRAY_TYPES) {
216+ if (primitiveTypeName.equals(typeDescr[PRIMITIVE_TYPE_NAME_INDEX]))
217+ return (SimpleType<?>)typeDescr[PRIMITIVE_OPEN_TYPE_INDEX];
218+ }
219+ return null;
220+ }
221+
222+ /* *** Constructor *** */
223+
224+ /**
225+ * Constructs an <tt>ArrayType</tt> instance describing <i>open data</i> values which are
226+ * arrays with dimension <var>dimension</var> of elements whose <i>open type</i> is <var>elementType</var>.
227+ * <p>
228+ * When invoked on an <tt>ArrayType</tt> instance, the {@link OpenType#getClassName() getClassName} method
229+ * returns the class name of the array instances it describes (following the rules defined by the
230+ * {@link Class#getName() getName} method of <code>java.lang.Class</code>), not the class name of the array elements
231+ * (which is returned by a call to <tt>getElementOpenType().getClassName()</tt>).
232+ * <p>
233+ * The internal field corresponding to the type name of this <code>ArrayType</code> instance is also set to
234+ * the class name of the array instances it describes.
235+ * In other words, the methods <code>getClassName</code> and <code>getTypeName</code> return the same string value.
236+ * The internal field corresponding to the description of this <code>ArrayType</code> instance is set to a string value
237+ * which follows the following template:
238+ * <ul>
239+ * <li>if non-primitive array: <tt><i>&lt;dimension&gt;</i>-dimension array of <i>&lt;element_class_name&gt;</i></tt></li>
240+ * <li>if primitive array: <tt><i>&lt;dimension&gt;</i>-dimension array of <i>&lt;primitive_type_of_the_element_class_name&gt;</i></tt></li>
241+ * </ul>
242+ * <p>
243+ * As an example, the following piece of code:
244+ * <pre>
245+ * ArrayType<String[][][]> t = new ArrayType<String[][][]>(3, SimpleType.STRING);
246+ * System.out.println("array class name = " + t.getClassName());
247+ * System.out.println("element class name = " + t.getElementOpenType().getClassName());
248+ * System.out.println("array type name = " + t.getTypeName());
249+ * System.out.println("array type description = " + t.getDescription());
250+ * </pre>
251+ * would produce the following output:
252+ * <pre>
253+ * array class name = [[[Ljava.lang.String;
254+ * element class name = java.lang.String
255+ * array type name = [[[Ljava.lang.String;
256+ * array type description = 3-dimension array of java.lang.String
257+ * </pre>
258+ * And the following piece of code which is equivalent to the one listed
259+ * above would also produce the same output:
260+ * <pre>
261+ * ArrayType<String[]> t1 = new ArrayType<String[]>(1, SimpleType.STRING);
262+ * ArrayType<String[][]> t2 = new ArrayType<String[][]>(1, t1);
263+ * ArrayType<String[][][]> t3 = new ArrayType<String[][][]>(1, t2);
264+ * System.out.println("array class name = " + t3.getClassName());
265+ * System.out.println("element class name = " + t3.getElementOpenType().getClassName());
266+ * System.out.println("array type name = " + t3.getTypeName());
267+ * System.out.println("array type description = " + t3.getDescription());
268+ * </pre>
269+ *
270+ * @param dimension the dimension of arrays described by this <tt>ArrayType</tt> instance;
271+ * must be greater than or equal to 1.
272+ *
273+ * @param elementType the <i>open type</i> of element values contained
274+ * in the arrays described by this <tt>ArrayType</tt>
275+ * instance; must be an instance of either
276+ * <tt>SimpleType</tt>, <tt>CompositeType</tt>,
277+ * <tt>TabularType</tt> or another <tt>ArrayType</tt>
278+ * with a <tt>SimpleType</tt>, <tt>CompositeType</tt>
279+ * or <tt>TabularType</tt> as its <tt>elementType</tt>.
280+ *
281+ * @throws IllegalArgumentException if {@code dimension} is not a positive
282+ * integer.
283+ * @throws OpenDataException if <var>elementType's className</var> is not
284+ * one of the allowed Java class names for open
285+ * data.
286+ */
287+ public ArrayType(int dimension,
288+ OpenType<?> elementType) throws OpenDataException {
289+ // Check and construct state defined by parent.
290+ // We can't use the package-private OpenType constructor because
291+ // we don't know if the elementType parameter is sane.
292+ super(buildArrayClassName(dimension, elementType),
293+ buildArrayClassName(dimension, elementType),
294+ buildArrayDescription(dimension, elementType));
295+
296+ // Check and construct state specific to ArrayType
297+ //
298+ if (elementType.isArray()) {
299+ ArrayType<?> at = (ArrayType<?>) elementType;
300+ this.dimension = at.getDimension() + dimension;
301+ this.elementType = at.getElementOpenType();
302+ this.primitiveArray = at.isPrimitiveArray();
303+ } else {
304+ this.dimension = dimension;
305+ this.elementType = elementType;
306+ this.primitiveArray = false;
307+ }
308+ }
309+
310+ /**
311+ * Constructs a unidimensional {@code ArrayType} instance for the
312+ * supplied {@code SimpleType}.
313+ * <p>
314+ * This constructor supports the creation of arrays of primitive
315+ * types when {@code primitiveArray} is {@code true}.
316+ * <p>
317+ * For primitive arrays the {@link #getElementOpenType()} method
318+ * returns the {@link SimpleType} corresponding to the wrapper
319+ * type of the primitive type of the array.
320+ * <p>
321+ * When invoked on an <tt>ArrayType</tt> instance, the {@link OpenType#getClassName() getClassName} method
322+ * returns the class name of the array instances it describes (following the rules defined by the
323+ * {@link Class#getName() getName} method of <code>java.lang.Class</code>), not the class name of the array elements
324+ * (which is returned by a call to <tt>getElementOpenType().getClassName()</tt>).
325+ * <p>
326+ * The internal field corresponding to the type name of this <code>ArrayType</code> instance is also set to
327+ * the class name of the array instances it describes.
328+ * In other words, the methods <code>getClassName</code> and <code>getTypeName</code> return the same string value.
329+ * The internal field corresponding to the description of this <code>ArrayType</code> instance is set to a string value
330+ * which follows the following template:
331+ * <ul>
332+ * <li>if non-primitive array: <tt>1-dimension array of <i>&lt;element_class_name&gt;</i></tt></li>
333+ * <li>if primitive array: <tt>1-dimension array of <i>&lt;primitive_type_of_the_element_class_name&gt;</i></tt></li>
334+ * </ul>
335+ * <p>
336+ * As an example, the following piece of code:
337+ * <pre>
338+ * ArrayType<int[]> t = new ArrayType<int[]>(SimpleType.INTEGER, true);
339+ * System.out.println("array class name = " + t.getClassName());
340+ * System.out.println("element class name = " + t.getElementOpenType().getClassName());
341+ * System.out.println("array type name = " + t.getTypeName());
342+ * System.out.println("array type description = " + t.getDescription());
343+ * </pre>
344+ * would produce the following output:
345+ * <pre>
346+ * array class name = [I
347+ * element class name = java.lang.Integer
348+ * array type name = [I
349+ * array type description = 1-dimension array of int
350+ * </pre>
351+ *
352+ * @param elementType the {@code SimpleType} of the element values
353+ * contained in the arrays described by this
354+ * {@code ArrayType} instance.
355+ *
356+ * @param primitiveArray {@code true} when this array describes
357+ * primitive arrays.
358+ *
359+ * @throws IllegalArgumentException if {@code dimension} is not a positive
360+ * integer.
361+ * @throws OpenDataException if {@code primitiveArray} is {@code true} and
362+ * {@code elementType} is not a valid {@code SimpleType} for a primitive
363+ * type.
364+ *
365+ * @since 1.6
366+ */
367+ public ArrayType(SimpleType<?> elementType,
368+ boolean primitiveArray) throws OpenDataException {
369+
370+ // Check and construct state defined by parent.
371+ // We can call the package-private OpenType constructor because the
372+ // set of SimpleTypes is fixed and SimpleType can't be subclassed.
373+ super(buildArrayClassName(1, elementType, primitiveArray),
374+ buildArrayClassName(1, elementType, primitiveArray),
375+ buildArrayDescription(1, elementType, primitiveArray),
376+ true);
377+
378+ // Check and construct state specific to ArrayType
379+ //
380+ this.dimension = 1;
381+ this.elementType = elementType;
382+ this.primitiveArray = primitiveArray;
383+ }
384+
385+ /* Package-private constructor for callers we trust to get it right. */
386+ ArrayType(String className, String typeName, String description,
387+ int dimension, OpenType<?> elementType,
388+ boolean primitiveArray) {
389+ super(className, typeName, description, true);
390+ this.dimension = dimension;
391+ this.elementType = elementType;
392+ this.primitiveArray = primitiveArray;
393+ }
394+
395+ private static String buildArrayClassName(int dimension,
396+ OpenType<?> elementType)
397+ throws OpenDataException {
398+ boolean isPrimitiveArray = false;
399+ if (elementType.isArray()) {
400+ isPrimitiveArray = ((ArrayType<?>) elementType).isPrimitiveArray();
401+ }
402+ return buildArrayClassName(dimension, elementType, isPrimitiveArray);
403+ }
404+
405+ private static String buildArrayClassName(int dimension,
406+ OpenType<?> elementType,
407+ boolean isPrimitiveArray)
408+ throws OpenDataException {
409+ if (dimension < 1) {
410+ throw new IllegalArgumentException(
411+ "Value of argument dimension must be greater than 0");
412+ }
413+ StringBuilder result = new StringBuilder();
414+ String elementClassName = elementType.getClassName();
415+ // Add N (= dimension) additional '[' characters to the existing array
416+ for (int i = 1; i <= dimension; i++) {
417+ result.append('[');
418+ }
419+ if (elementType.isArray()) {
420+ result.append(elementClassName);
421+ } else {
422+ if (isPrimitiveArray) {
423+ final String key = getPrimitiveTypeKey(elementClassName);
424+ // Ideally we should throw an IllegalArgumentException here,
425+ // but for compatibility reasons we throw an OpenDataException.
426+ // (used to be thrown by OpenType() constructor).
427+ //
428+ if (key == null)
429+ throw new OpenDataException("Element type is not primitive: "
430+ + elementClassName);
431+ result.append(key);
432+ } else {
433+ result.append("L");
434+ result.append(elementClassName);
435+ result.append(';');
436+ }
437+ }
438+ return result.toString();
439+ }
440+
441+ private static String buildArrayDescription(int dimension,
442+ OpenType<?> elementType)
443+ throws OpenDataException {
444+ boolean isPrimitiveArray = false;
445+ if (elementType.isArray()) {
446+ isPrimitiveArray = ((ArrayType<?>) elementType).isPrimitiveArray();
447+ }
448+ return buildArrayDescription(dimension, elementType, isPrimitiveArray);
449+ }
450+
451+ private static String buildArrayDescription(int dimension,
452+ OpenType<?> elementType,
453+ boolean isPrimitiveArray)
454+ throws OpenDataException {
455+ if (elementType.isArray()) {
456+ ArrayType<?> at = (ArrayType<?>) elementType;
457+ dimension += at.getDimension();
458+ elementType = at.getElementOpenType();
459+ isPrimitiveArray = at.isPrimitiveArray();
460+ }
461+ StringBuilder result =
462+ new StringBuilder(dimension + "-dimension array of ");
463+ final String elementClassName = elementType.getClassName();
464+ if (isPrimitiveArray) {
465+ // Convert from wrapper type to primitive type
466+ final String primitiveType =
467+ getPrimitiveTypeName(elementClassName);
468+
469+ // Ideally we should throw an IllegalArgumentException here,
470+ // but for compatibility reasons we throw an OpenDataException.
471+ // (used to be thrown by OpenType() constructor).
472+ //
473+ if (primitiveType == null)
474+ throw new OpenDataException("Element is not a primitive type: "+
475+ elementClassName);
476+ result.append(primitiveType);
477+ } else {
478+ result.append(elementClassName);
479+ }
480+ return result.toString();
481+ }
482+
483+ /* *** ArrayType specific information methods *** */
484+
485+ /**
486+ * Returns the dimension of arrays described by this <tt>ArrayType</tt> instance.
487+ *
488+ * @return the dimension.
489+ */
490+ public int getDimension() {
491+
492+ return dimension;
493+ }
494+
495+ /**
496+ * Returns the <i>open type</i> of element values contained in the arrays described by this <tt>ArrayType</tt> instance.
497+ *
498+ * @return the element type.
499+ */
500+ public OpenType<?> getElementOpenType() {
501+
502+ return elementType;
503+ }
504+
505+ /**
506+ * Returns <code>true</code> if the open data values this open
507+ * type describes are primitive arrays, <code>false</code> otherwise.
508+ *
509+ * @return true if this is a primitive array type.
510+ *
511+ * @since 1.6
512+ */
513+ public boolean isPrimitiveArray() {
514+
515+ return primitiveArray;
516+ }
517+
518+ /**
519+ * Tests whether <var>obj</var> is a value for this <code>ArrayType</code>
520+ * instance.
521+ * <p>
522+ * This method returns <code>true</code> if and only if <var>obj</var>
523+ * is not null, <var>obj</var> is an array and any one of the following
524+ * is <tt>true</tt>:
525+ *
526+ * <ul>
527+ * <li>if this <code>ArrayType</code> instance describes an array of
528+ * <tt>SimpleType</tt> elements or their corresponding primitive types,
529+ * <var>obj</var>'s class name is the same as the className field defined
530+ * for this <code>ArrayType</code> instance (i.e. the class name returned
531+ * by the {@link OpenType#getClassName() getClassName} method, which
532+ * includes the dimension information),<br>&nbsp;</li>
533+ * <li>if this <code>ArrayType</code> instance describes an array of
534+ * classes implementing the {@code TabularData} interface or the
535+ * {@code CompositeData} interface, <var>obj</var> is assignable to
536+ * such a declared array, and each element contained in <var>obj</var>
537+ * is either null or a valid value for the element's open type specified
538+ * by this <code>ArrayType</code> instance.</li>
539+ * </ul>
540+ *
541+ * @param obj the object to be tested.
542+ *
543+ * @return <code>true</code> if <var>obj</var> is a value for this
544+ * <code>ArrayType</code> instance.
545+ */
546+ public boolean isValue(Object obj) {
547+
548+ // if obj is null, return false
549+ //
550+ if (obj == null) {
551+ return false;
552+ }
553+
554+ Class<?> objClass = obj.getClass();
555+ String objClassName = objClass.getName();
556+
557+ // if obj is not an array, return false
558+ //
559+ if ( ! objClass.isArray() ) {
560+ return false;
561+ }
562+
563+ // Test if obj's class name is the same as for the array values that this instance describes
564+ // (this is fine if elements are of simple types, which are final classes)
565+ //
566+ if ( this.getClassName().equals(objClassName) ) {
567+ return true;
568+ }
569+
570+ // In case this ArrayType instance describes an array of classes implementing the TabularData or CompositeData interface,
571+ // we first check for the assignability of obj to such an array of TabularData or CompositeData,
572+ // which ensures that:
573+ // . obj is of the the same dimension as this ArrayType instance,
574+ // . it is declared as an array of elements which are either all TabularData or all CompositeData.
575+ //
576+ // If the assignment check is positive,
577+ // then we have to check that each element in obj is of the same TabularType or CompositeType
578+ // as the one described by this ArrayType instance.
579+ //
580+ // [About assignment check, note that the call below returns true: ]
581+ // [Class.forName("[Lpackage.CompositeData;").isAssignableFrom(Class.forName("[Lpackage.CompositeDataImpl;)")); ]
582+ //
583+ if ( (this.elementType.getClassName().equals(TabularData.class.getName())) ||
584+ (this.elementType.getClassName().equals(CompositeData.class.getName())) ) {
585+
586+ boolean isTabular =
587+ (elementType.getClassName().equals(TabularData.class.getName()));
588+ int[] dims = new int[getDimension()];
589+ Class<?> elementClass = isTabular ? TabularData.class : CompositeData.class;
590+ Class<?> targetClass = Array.newInstance(elementClass, dims).getClass();
591+
592+ // assignment check: return false if negative
593+ if ( ! targetClass.isAssignableFrom(objClass) ) {
594+ return false;
595+ }
596+
597+ // check that all elements in obj are valid values for this ArrayType
598+ if ( ! checkElementsType( (Object[]) obj, this.dimension) ) { // we know obj's dimension is this.dimension
599+ return false;
600+ }
601+
602+ return true;
603+ }
604+
605+ // if previous tests did not return, then obj is not a value for this ArrayType instance
606+ return false;
607+ }
608+
609+ /**
610+ * Returns true if and only if all elements contained in the array argument x_dim_Array of dimension dim
611+ * are valid values (ie either null or of the right openType)
612+ * for the element open type specified by this ArrayType instance.
613+ *
614+ * This method's implementation uses recursion to go down the dimensions of the array argument.
615+ */
616+ private boolean checkElementsType(Object[] x_dim_Array, int dim) {
617+
618+ // if the elements of x_dim_Array are themselves array: go down recursively....
619+ if ( dim > 1 ) {
620+ for (int i=0; i<x_dim_Array.length; i++) {
621+ if ( ! checkElementsType((Object[])x_dim_Array[i], dim-1) ) {
622+ return false;
623+ }
624+ }
625+ return true;
626+ }
627+ // ...else, for a non-empty array, each element must be a valid value: either null or of the right openType
628+ else {
629+ for (int i=0; i<x_dim_Array.length; i++) {
630+ if ( (x_dim_Array[i] != null) && (! this.getElementOpenType().isValue(x_dim_Array[i])) ) {
631+ return false;
632+ }
633+ }
634+ return true;
635+ }
636+ }
637+
638+ @Override
639+ boolean isAssignableFrom(OpenType<?> ot) {
640+ if (!(ot instanceof ArrayType<?>))
641+ return false;
642+ ArrayType<?> at = (ArrayType<?>) ot;
643+ return (at.getDimension() == getDimension() &&
644+ at.isPrimitiveArray() == isPrimitiveArray() &&
645+ at.getElementOpenType().isAssignableFrom(getElementOpenType()));
646+ }
647+
648+
649+ /* *** Methods overriden from class Object *** */
650+
651+ /**
652+ * Compares the specified <code>obj</code> parameter with this
653+ * <code>ArrayType</code> instance for equality.
654+ * <p>
655+ * Two <code>ArrayType</code> instances are equal if and only if they
656+ * describe array instances which have the same dimension, elements'
657+ * open type and primitive array flag.
658+ *
659+ * @param obj the object to be compared for equality with this
660+ * <code>ArrayType</code> instance; if <var>obj</var>
661+ * is <code>null</code> or is not an instance of the
662+ * class <code>ArrayType</code> this method returns
663+ * <code>false</code>.
664+ *
665+ * @return <code>true</code> if the specified object is equal to
666+ * this <code>ArrayType</code> instance.
667+ */
668+ public boolean equals(Object obj) {
669+
670+ // if obj is null, return false
671+ //
672+ if (obj == null) {
673+ return false;
674+ }
675+
676+ // if obj is not an ArrayType, return false
677+ //
678+ if (!(obj instanceof ArrayType<?>))
679+ return false;
680+ ArrayType<?> other = (ArrayType<?>) obj;
681+
682+ // if other's dimension is different than this instance's, return false
683+ //
684+ if (this.dimension != other.dimension) {
685+ return false;
686+ }
687+
688+ // Test if other's elementType field is the same as for this instance
689+ //
690+ if (!this.elementType.equals(other.elementType)) {
691+ return false;
692+ }
693+
694+ // Test if other's primitiveArray flag is the same as for this instance
695+ //
696+ return this.primitiveArray == other.primitiveArray;
697+ }
698+
699+ /**
700+ * Returns the hash code value for this <code>ArrayType</code> instance.
701+ * <p>
702+ * The hash code of an <code>ArrayType</code> instance is the sum of the
703+ * hash codes of all the elements of information used in <code>equals</code>
704+ * comparisons (i.e. dimension, elements' open type and primitive array flag).
705+ * The hashcode for a primitive value is the hashcode of the corresponding boxed
706+ * object (e.g. the hashcode for <tt>true</tt> is <tt>Boolean.TRUE.hashCode()</tt>).
707+ * This ensures that <code> t1.equals(t2) </code> implies that
708+ * <code> t1.hashCode()==t2.hashCode() </code> for any two
709+ * <code>ArrayType</code> instances <code>t1</code> and <code>t2</code>,
710+ * as required by the general contract of the method
711+ * {@link Object#hashCode() Object.hashCode()}.
712+ * <p>
713+ * As <code>ArrayType</code> instances are immutable, the hash
714+ * code for this instance is calculated once, on the first call
715+ * to <code>hashCode</code>, and then the same value is returned
716+ * for subsequent calls.
717+ *
718+ * @return the hash code value for this <code>ArrayType</code> instance
719+ */
720+ public int hashCode() {
721+
722+ // Calculate the hash code value if it has not yet been done (ie 1st call to hashCode())
723+ //
724+ if (myHashCode == null) {
725+ int value = 0;
726+ value += dimension;
727+ value += elementType.hashCode();
728+ value += Boolean.valueOf(primitiveArray).hashCode();
729+ myHashCode = Integer.valueOf(value);
730+ }
731+
732+ // return always the same hash code for this instance (immutable)
733+ //
734+ return myHashCode.intValue();
735+ }
736+
737+ /**
738+ * Returns a string representation of this <code>ArrayType</code> instance.
739+ * <p>
740+ * The string representation consists of the name of this class (i.e.
741+ * <code>javax.management.openmbean.ArrayType</code>), the type name,
742+ * the dimension, the elements' open type and the primitive array flag
743+ * defined for this instance.
744+ * <p>
745+ * As <code>ArrayType</code> instances are immutable, the
746+ * string representation for this instance is calculated
747+ * once, on the first call to <code>toString</code>, and
748+ * then the same value is returned for subsequent calls.
749+ *
750+ * @return a string representation of this <code>ArrayType</code> instance
751+ */
752+ public String toString() {
753+
754+ // Calculate the string representation if it has not yet been done (ie 1st call to toString())
755+ //
756+ if (myToString == null) {
757+ myToString = getClass().getName() +
758+ "(name=" + getTypeName() +
759+ ",dimension=" + dimension +
760+ ",elementType=" + elementType +
761+ ",primitiveArray=" + primitiveArray + ")";
762+ }
763+
764+ // return always the same string representation for this instance (immutable)
765+ //
766+ return myToString;
767+ }
768+
769+ /**
770+ * Create an {@code ArrayType} instance in a type-safe manner.
771+ * <p>
772+ * Multidimensional arrays can be built up by calling this method as many
773+ * times as necessary.
774+ * <p>
775+ * Calling this method twice with the same parameters may return the same
776+ * object or two equal but not identical objects.
777+ * <p>
778+ * As an example, the following piece of code:
779+ * <pre>
780+ * ArrayType<String[]> t1 = ArrayType.getArrayType(SimpleType.STRING);
781+ * ArrayType<String[][]> t2 = ArrayType.getArrayType(t1);
782+ * ArrayType<String[][][]> t3 = ArrayType.getArrayType(t2);
783+ * System.out.println("array class name = " + t3.getClassName());
784+ * System.out.println("element class name = " + t3.getElementOpenType().getClassName());
785+ * System.out.println("array type name = " + t3.getTypeName());
786+ * System.out.println("array type description = " + t3.getDescription());
787+ * </pre>
788+ * would produce the following output:
789+ * <pre>
790+ * array class name = [[[Ljava.lang.String;
791+ * element class name = java.lang.String
792+ * array type name = [[[Ljava.lang.String;
793+ * array type description = 3-dimension array of java.lang.String
794+ * </pre>
795+ *
796+ * @param elementType the <i>open type</i> of element values contained
797+ * in the arrays described by this <tt>ArrayType</tt>
798+ * instance; must be an instance of either
799+ * <tt>SimpleType</tt>, <tt>CompositeType</tt>,
800+ * <tt>TabularType</tt> or another <tt>ArrayType</tt>
801+ * with a <tt>SimpleType</tt>, <tt>CompositeType</tt>
802+ * or <tt>TabularType</tt> as its <tt>elementType</tt>.
803+ *
804+ * @throws OpenDataException if <var>elementType's className</var> is not
805+ * one of the allowed Java class names for open
806+ * data.
807+ *
808+ * @since 1.6
809+ */
810+ public static <E> ArrayType<E[]> getArrayType(OpenType<E> elementType)
811+ throws OpenDataException {
812+ return new ArrayType<E[]>(1, elementType);
813+ }
814+
815+ /**
816+ * Create an {@code ArrayType} instance in a type-safe manner.
817+ * <p>
818+ * Calling this method twice with the same parameters may return the
819+ * same object or two equal but not identical objects.
820+ * <p>
821+ * As an example, the following piece of code:
822+ * <pre>
823+ * ArrayType<int[][][]> t = ArrayType.getPrimitiveArrayType(int[][][].class);
824+ * System.out.println("array class name = " + t.getClassName());
825+ * System.out.println("element class name = " + t.getElementOpenType().getClassName());
826+ * System.out.println("array type name = " + t.getTypeName());
827+ * System.out.println("array type description = " + t.getDescription());
828+ * </pre>
829+ * would produce the following output:
830+ * <pre>
831+ * array class name = [[[I
832+ * element class name = java.lang.Integer
833+ * array type name = [[[I
834+ * array type description = 3-dimension array of int
835+ * </pre>
836+ *
837+ * @param arrayClass a primitive array class such as {@code int[].class},
838+ * {@code boolean[][].class}, etc. The {@link
839+ * #getElementOpenType()} method of the returned
840+ * {@code ArrayType} returns the {@link SimpleType}
841+ * corresponding to the wrapper type of the primitive
842+ * type of the array.
843+ *
844+ * @throws IllegalArgumentException if <var>arrayClass</var> is not
845+ * a primitive array.
846+ *
847+ * @since 1.6
848+ */
849+ @SuppressWarnings("unchecked") // can't get appropriate T for primitive array
850+ public static <T> ArrayType<T> getPrimitiveArrayType(Class<T> arrayClass) {
851+ // Check if the supplied parameter is an array
852+ //
853+ if (!arrayClass.isArray()) {
854+ throw new IllegalArgumentException("arrayClass must be an array");
855+ }
856+
857+ // Calculate array dimension and component type name
858+ //
859+ int n = 1;
860+ Class<?> componentType = arrayClass.getComponentType();
861+ while (componentType.isArray()) {
862+ n++;
863+ componentType = componentType.getComponentType();
864+ }
865+ String componentTypeName = componentType.getName();
866+
867+ // Check if the array's component type is a primitive type
868+ //
869+ if (!componentType.isPrimitive()) {
870+ throw new IllegalArgumentException(
871+ "component type of the array must be a primitive type");
872+ }
873+
874+ // Map component type name to corresponding SimpleType
875+ //
876+ final SimpleType<?> simpleType =
877+ getPrimitiveOpenType(componentTypeName);
878+
879+ // Build primitive array
880+ //
881+ try {
882+ @SuppressWarnings("rawtypes")
883+ ArrayType at = new ArrayType(simpleType, true);
884+ if (n > 1)
885+ at = new ArrayType<T>(n - 1, at);
886+ return at;
887+ } catch (OpenDataException e) {
888+ throw new IllegalArgumentException(e); // should not happen
889+ }
890+ }
891+
892+ /**
893+ * Replace/resolve the object read from the stream before it is returned
894+ * to the caller.
895+ *
896+ * @serialData The new serial form of this class defines a new serializable
897+ * {@code boolean} field {@code primitiveArray}. In order to guarantee the
898+ * interoperability with previous versions of this class the new serial
899+ * form must continue to refer to primitive wrapper types even when the
900+ * {@code ArrayType} instance describes a primitive type array. So when
901+ * {@code primitiveArray} is {@code true} the {@code className},
902+ * {@code typeName} and {@code description} serializable fields
903+ * are converted into primitive types before the deserialized
904+ * {@code ArrayType} instance is return to the caller. The
905+ * {@code elementType} field always returns the {@code SimpleType}
906+ * corresponding to the primitive wrapper type of the array's
907+ * primitive type.
908+ * <p>
909+ * Therefore the following serializable fields are deserialized as follows:
910+ * <ul>
911+ * <li>if {@code primitiveArray} is {@code true} the {@code className}
912+ * field is deserialized by replacing the array's component primitive
913+ * wrapper type by the corresponding array's component primitive type,
914+ * e.g. {@code "[[Ljava.lang.Integer;"} will be deserialized as
915+ * {@code "[[I"}.</li>
916+ * <li>if {@code primitiveArray} is {@code true} the {@code typeName}
917+ * field is deserialized by replacing the array's component primitive
918+ * wrapper type by the corresponding array's component primitive type,
919+ * e.g. {@code "[[Ljava.lang.Integer;"} will be deserialized as
920+ * {@code "[[I"}.</li>
921+ * <li>if {@code primitiveArray} is {@code true} the {@code description}
922+ * field is deserialized by replacing the array's component primitive
923+ * wrapper type by the corresponding array's component primitive type,
924+ * e.g. {@code "2-dimension array of java.lang.Integer"} will be
925+ * deserialized as {@code "2-dimension array of int"}.</li>
926+ * </ul>
927+ *
928+ * @since 1.6
929+ */
930+ private Object readResolve() throws ObjectStreamException {
931+ if (primitiveArray) {
932+ return convertFromWrapperToPrimitiveTypes();
933+ } else {
934+ return this;
935+ }
936+ }
937+
938+ private <T> ArrayType<T> convertFromWrapperToPrimitiveTypes() {
939+ String cn = getClassName();
940+ String tn = getTypeName();
941+ String d = getDescription();
942+ for (Object[] typeDescr : PRIMITIVE_ARRAY_TYPES) {
943+ if (cn.indexOf((String)typeDescr[PRIMITIVE_WRAPPER_NAME_INDEX]) != -1) {
944+ cn = cn.replaceFirst(
945+ "L" + typeDescr[PRIMITIVE_WRAPPER_NAME_INDEX] + ";",
946+ (String) typeDescr[PRIMITIVE_TYPE_KEY_INDEX]);
947+ tn = tn.replaceFirst(
948+ "L" + typeDescr[PRIMITIVE_WRAPPER_NAME_INDEX] + ";",
949+ (String) typeDescr[PRIMITIVE_TYPE_KEY_INDEX]);
950+ d = d.replaceFirst(
951+ (String) typeDescr[PRIMITIVE_WRAPPER_NAME_INDEX],
952+ (String) typeDescr[PRIMITIVE_TYPE_NAME_INDEX]);
953+ break;
954+ }
955+ }
956+ return new ArrayType<T>(cn, tn, d,
957+ dimension, elementType, primitiveArray);
958+ }
959+
960+ /**
961+ * Nominate a replacement for this object in the stream before the object
962+ * is written.
963+ *
964+ * @serialData The new serial form of this class defines a new serializable
965+ * {@code boolean} field {@code primitiveArray}. In order to guarantee the
966+ * interoperability with previous versions of this class the new serial
967+ * form must continue to refer to primitive wrapper types even when the
968+ * {@code ArrayType} instance describes a primitive type array. So when
969+ * {@code primitiveArray} is {@code true} the {@code className},
970+ * {@code typeName} and {@code description} serializable fields
971+ * are converted into wrapper types before the serialized
972+ * {@code ArrayType} instance is written to the stream. The
973+ * {@code elementType} field always returns the {@code SimpleType}
974+ * corresponding to the primitive wrapper type of the array's
975+ * primitive type.
976+ * <p>
977+ * Therefore the following serializable fields are serialized as follows:
978+ * <ul>
979+ * <li>if {@code primitiveArray} is {@code true} the {@code className}
980+ * field is serialized by replacing the array's component primitive
981+ * type by the corresponding array's component primitive wrapper type,
982+ * e.g. {@code "[[I"} will be serialized as
983+ * {@code "[[Ljava.lang.Integer;"}.</li>
984+ * <li>if {@code primitiveArray} is {@code true} the {@code typeName}
985+ * field is serialized by replacing the array's component primitive
986+ * type by the corresponding array's component primitive wrapper type,
987+ * e.g. {@code "[[I"} will be serialized as
988+ * {@code "[[Ljava.lang.Integer;"}.</li>
989+ * <li>if {@code primitiveArray} is {@code true} the {@code description}
990+ * field is serialized by replacing the array's component primitive
991+ * type by the corresponding array's component primitive wrapper type,
992+ * e.g. {@code "2-dimension array of int"} will be serialized as
993+ * {@code "2-dimension array of java.lang.Integer"}.</li>
994+ * </ul>
995+ *
996+ * @since 1.6
997+ */
998+ private Object writeReplace() throws ObjectStreamException {
999+ if (primitiveArray) {
1000+ return convertFromPrimitiveToWrapperTypes();
1001+ } else {
1002+ return this;
1003+ }
1004+ }
1005+
1006+ private <T> ArrayType<T> convertFromPrimitiveToWrapperTypes() {
1007+ String cn = getClassName();
1008+ String tn = getTypeName();
1009+ String d = getDescription();
1010+ for (Object[] typeDescr : PRIMITIVE_ARRAY_TYPES) {
1011+ if (cn.indexOf((String) typeDescr[PRIMITIVE_TYPE_KEY_INDEX]) != -1) {
1012+ cn = cn.replaceFirst(
1013+ (String) typeDescr[PRIMITIVE_TYPE_KEY_INDEX],
1014+ "L" + typeDescr[PRIMITIVE_WRAPPER_NAME_INDEX] + ";");
1015+ tn = tn.replaceFirst(
1016+ (String) typeDescr[PRIMITIVE_TYPE_KEY_INDEX],
1017+ "L" + typeDescr[PRIMITIVE_WRAPPER_NAME_INDEX] + ";");
1018+ d = d.replaceFirst(
1019+ (String) typeDescr[PRIMITIVE_TYPE_NAME_INDEX],
1020+ (String) typeDescr[PRIMITIVE_WRAPPER_NAME_INDEX]);
1021+ break;
1022+ }
1023+ }
1024+ return new ArrayType<T>(cn, tn, d,
1025+ dimension, elementType, primitiveArray);
1026+ }
1027+}