KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > management > openmbean > TabularDataSupport


1 /*
2  * @(#)TabularDataSupport.java 3.30 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8
9 package javax.management.openmbean;
10
11
12 // java import
13
//
14
import java.io.IOException JavaDoc;
15 import java.io.Serializable JavaDoc;
16 import java.io.ObjectInputStream JavaDoc;
17 import java.util.Iterator JavaDoc;
18 import java.util.HashMap JavaDoc;
19 import java.util.Map JavaDoc;
20 import java.util.Set JavaDoc;
21 import java.util.Collection JavaDoc;
22 import java.util.Collections JavaDoc;
23 import java.util.Arrays JavaDoc;
24 import java.util.ArrayList JavaDoc;
25 import java.util.List JavaDoc;
26
27 // jmx import
28
//
29

30
31 /**
32  * The <tt>TabularDataSupport</tt> class is the <i>open data</i> class which implements the <tt>TabularData</tt>
33  * and the <tt>Map</tt> interfaces, and which is internally based on a hash map data structure.
34  *
35  * @version 3.30 03/12/19
36  * @author Sun Microsystems, Inc.
37  *
38  * @since 1.5
39  * @since.unbundled JMX 1.1
40  */

41 public class TabularDataSupport
42     implements TabularData JavaDoc, Map JavaDoc, Cloneable JavaDoc, Serializable JavaDoc {
43     
44     
45     /* Serial version */
46     static final long serialVersionUID = 5720150593236309827L;
47
48
49     /**
50      * @serial This tabular data instance's contents: a {@link HashMap}
51      */

52     private Map JavaDoc dataMap;
53     
54     /**
55      * @serial This tabular data instance's tabular type
56      */

57     private TabularType JavaDoc tabularType;
58
59     /**
60      * @serial The array of item names that define the index used for rows (convenience field)
61      */

62     private transient String JavaDoc[] indexNamesArray;
63     
64
65
66     /* *** Constructors *** */
67
68
69     /**
70      * Creates an empty <tt>TabularDataSupport</tt> instance whose open-type is <var>tabularType</var>,
71      * and whose underlying <tt>HashMap</tt> has a default initial capacity (101) and default load factor (0.75).
72      * <p>
73      * This constructor simply calls <tt>this(tabularType, 101, 0.75f);</tt>
74      *
75      * @param tabularType the <i>tabular type</i> describing this <tt>TabularData</tt> instance;
76      * cannot be null.
77      *
78      * @throws IllegalArgumentException if the tabular type is null.
79      */

80     public TabularDataSupport(TabularType JavaDoc tabularType) {
81
82     this(tabularType, 101, 0.75f);
83     }
84
85     /**
86      * Creates an empty <tt>TabularDataSupport</tt> instance whose open-type is <var>tabularType</var>,
87      * and whose underlying <tt>HashMap</tt> has the specified initial capacity and load factor.
88      *
89      * @param tabularType the <i>tabular type</i> describing this <tt>TabularData</tt> instance;
90      * cannot be null.
91      *
92      * @param initialCapacity the initial capacity of the HashMap.
93      *
94      * @param loadFactor the load factor of the HashMap
95      *
96      * @throws IllegalArgumentException if the initial capacity is less than zero,
97      * or the load factor is nonpositive,
98      * or the tabular type is null.
99      */

100     public TabularDataSupport(TabularType JavaDoc tabularType, int initialCapacity, float loadFactor) {
101
102     // Check tabularType is not null
103
//
104
if (tabularType == null) {
105         throw new IllegalArgumentException JavaDoc("Argument tabularType cannot be null.");
106     }
107
108     // Initialize this.tabularType (and indexNamesArray for convenience)
109
//
110
this.tabularType = tabularType;
111     List JavaDoc tmpNames = tabularType.getIndexNames();
112     this.indexNamesArray = (String JavaDoc[]) tmpNames.toArray(new String JavaDoc[tmpNames.size()]);
113     
114     // Construct the empty contents HashMap
115
//
116
this.dataMap = new HashMap JavaDoc(initialCapacity, loadFactor);
117     }
118
119
120
121
122     /* *** TabularData specific information methods *** */
123
124
125     /**
126      * Returns the <i>tabular type</i> describing this <tt>TabularData</tt> instance.
127      */

128     public TabularType JavaDoc getTabularType() {
129
130     return tabularType;
131     }
132
133     /**
134      * Calculates the index that would be used in this <tt>TabularData</tt> instance to refer to the specified
135      * composite data <var>value</var> parameter if it were added to this instance.
136      * This method checks for the type validity of the specified <var>value</var>,
137      * but does not check if the calculated index is already used to refer to a value in this <tt>TabularData</tt> instance.
138      *
139      * @param value the composite data value whose index in this
140      * <tt>TabularData</tt> instance is to be calculated;
141      * must be of the same composite type as this instance's row type;
142      * must not be null.
143      *
144      * @return the index that the specified <var>value</var> would have in this <tt>TabularData</tt> instance.
145      *
146      * @throws NullPointerException if <var>value</var> is <tt>null</tt>.
147      *
148      * @throws InvalidOpenTypeException if <var>value</var> does not conform to this <tt>TabularData</tt> instance's
149      * row type definition.
150      */

151     public Object JavaDoc[] calculateIndex(CompositeData JavaDoc value) {
152
153     // Check value is valid
154
//
155
checkValueType(value);
156
157     // Return its calculated index
158
//
159
return internalCalculateIndex(value).toArray();
160     }
161
162
163
164
165     /* *** Content information query methods *** */
166
167
168     /**
169      * Returns <tt>true</tt> if and only if this <tt>TabularData</tt> instance contains a <tt>CompositeData</tt> value
170      * (ie a row) whose index is the specified <var>key</var>. If <var>key</var> cannot be cast to a one dimension array
171      * of Object instances, this method simply returns <tt>false</tt>; otherwise it returns the the result of the call to
172      * <tt>this.containsKey((Object[]) key)</tt>.
173      *
174      * @param key the index value whose presence in this <tt>TabularData</tt> instance is to be tested.
175      *
176      * @return <tt>true</tt> if this <tt>TabularData</tt> indexes a row value with the specified key.
177      */

178     public boolean containsKey(Object JavaDoc key) {
179
180     // if key is not an array of Object instances, return false
181
//
182
Object JavaDoc[] k;
183     try {
184         k = (Object JavaDoc[]) key;
185     } catch (ClassCastException JavaDoc e) {
186         return false;
187     }
188
189     return this.containsKey(k);
190     }
191
192     /**
193      * Returns <tt>true</tt> if and only if this <tt>TabularData</tt> instance contains a <tt>CompositeData</tt> value
194      * (ie a row) whose index is the specified <var>key</var>. If <var>key</var> is <tt>null</tt> or does not conform to
195      * this <tt>TabularData</tt> instance's <tt>TabularType</tt> definition, this method simply returns <tt>false</tt>.
196      *
197      * @param key the index value whose presence in this <tt>TabularData</tt> instance is to be tested.
198      *
199      * @return <tt>true</tt> if this <tt>TabularData</tt> indexes a row value with the specified key.
200      */

201     public boolean containsKey(Object JavaDoc[] key) {
202
203     return ( key == null ? false : dataMap.containsKey(Arrays.asList(key)) );
204     }
205
206     /**
207      * Returns <tt>true</tt> if and only if this <tt>TabularData</tt> instance contains the specified
208      * <tt>CompositeData</tt> value. If <var>value</var> is <tt>null</tt> or does not conform to
209      * this <tt>TabularData</tt> instance's row type definition, this method simply returns <tt>false</tt>.
210      *
211      * @param value the row value whose presence in this <tt>TabularData</tt> instance is to be tested.
212      *
213      * @return <tt>true</tt> if this <tt>TabularData</tt> instance contains the specified row value.
214      */

215     public boolean containsValue(CompositeData JavaDoc value) {
216
217     return dataMap.containsValue(value);
218     }
219
220     /**
221      * Returns <tt>true</tt> if and only if this <tt>TabularData</tt> instance contains the specified
222      * value.
223      *
224      * @param value the row value whose presence in this <tt>TabularData</tt> instance is to be tested.
225      *
226      * @return <tt>true</tt> if this <tt>TabularData</tt> instance contains the specified row value.
227      */

228     public boolean containsValue(Object JavaDoc value) {
229
230     return dataMap.containsValue(value);
231     }
232
233     /**
234      * This method simply calls <tt>get((Object[]) key)</tt>.
235      *
236      * @throws NullPointerException if the <var>key</var> is <tt>null</tt>
237      * @throws ClassCastException if the <var>key</var> is not of the type <tt>Object[]</tt>
238      * @throws InvalidKeyException if the <var>key</var> does not conform to this <tt>TabularData</tt> instance's
239      * <tt>TabularType</tt> definition
240      */

241     public Object JavaDoc get(Object JavaDoc key) {
242
243     return get((Object JavaDoc[]) key);
244     }
245
246     /**
247      * Returns the <tt>CompositeData</tt> value whose index is
248      * <var>key</var>, or <tt>null</tt> if there is no value mapping
249      * to <var>key</var>, in this <tt>TabularData</tt> instance.
250      *
251      * @param key the index of the value to get in this
252      * <tt>TabularData</tt> instance; * must be valid with this
253      * <tt>TabularData</tt> instance's row type definition; * must not
254      * be null.
255      *
256      * @return the value corresponding to <var>key</var>.
257      *
258      * @throws NullPointerException if the <var>key</var> is <tt>null</tt>
259      * @throws InvalidKeyException if the <var>key</var> does not conform to this <tt>TabularData</tt> instance's
260      * <tt>TabularType</tt> type definition.
261      */

262     public CompositeData JavaDoc get(Object JavaDoc[] key) {
263
264     // Check key is not null and valid with tabularType
265
// (throws NullPointerException, InvalidKeyException)
266
//
267
checkKeyType(key);
268
269     // Return the mapping stored in the parent HashMap
270
//
271
return (CompositeData JavaDoc) dataMap.get(Arrays.asList(key));
272     }
273
274
275
276
277     /* *** Content modification operations (one element at a time) *** */
278
279
280     /**
281      * This method simply calls <tt>put((CompositeData) value)</tt> and
282      * therefore ignores its <var>key</var> parameter which can be <tt>null</tt>.
283      *
284      * @param key an ignored parameter.
285      * @param value the {@link CompositeData} to put.
286      *
287      * @return the value which is put
288      *
289      * @throws NullPointerException if the <var>value</var> is <tt>null</tt>
290      * @throws ClassCastException if the <var>value</var> is not of the type <tt>CompositeData</tt>
291      * @throws InvalidOpenTypeException if the <var>value</var> does not conform to this <tt>TabularData</tt> instance's
292      * <tt>TabularType</tt> definition
293      * @throws KeyAlreadyExistsException if the key for the <var>value</var> parameter, calculated according to
294      * this <tt>TabularData</tt> instance's <tt>TabularType</tt> definition
295      * already maps to an existing value
296      */

297     public Object JavaDoc put(Object JavaDoc key, Object JavaDoc value) {
298
299     put((CompositeData JavaDoc) value);
300     return value;
301     }
302
303     public void put(CompositeData JavaDoc value) {
304
305     // Check value is not null, value's type is the same as this instance's row type,
306
// and calculate the value's index according to this instance's tabularType and
307
// check it is not already used for a mapping in the parent HashMap
308
//
309
List JavaDoc index = checkValueAndIndex(value);
310
311     // store the (key, value) mapping in the dataMap HashMap
312
//
313
dataMap.put(index, value);
314     }
315
316     /**
317      * This method simply calls <tt>remove((Object[]) key)</tt>.
318      *
319      * @param key an <tt>Object[]</tt> representing the key to remove.
320      *
321      * @return previous value associated with specified key, or <tt>null</tt>
322      * if there was no mapping for key.
323      *
324      * @throws NullPointerException if the <var>key</var> is <tt>null</tt>
325      * @throws ClassCastException if the <var>key</var> is not of the type <tt>Object[]</tt>
326      * @throws InvalidKeyException if the <var>key</var> does not conform to this <tt>TabularData</tt> instance's
327      * <tt>TabularType</tt> definition
328      */

329     public Object JavaDoc remove(Object JavaDoc key) {
330
331     return remove((Object JavaDoc[]) key);
332     }
333
334     /**
335      * Removes the <tt>CompositeData</tt> value whose index is <var>key</var> from this <tt>TabularData</tt> instance,
336      * and returns the removed value, or returns <tt>null</tt> if there is no value whose index is <var>key</var>.
337      *
338      * @param key the index of the value to get in this <tt>TabularData</tt> instance;
339      * must be valid with this <tt>TabularData</tt> instance's row type definition;
340      * must not be null.
341      *
342      * @return previous value associated with specified key, or <tt>null</tt>
343      * if there was no mapping for key.
344      *
345      * @throws NullPointerException if the <var>key</var> is <tt>null</tt>
346      * @throws InvalidKeyException if the <var>key</var> does not conform to this <tt>TabularData</tt> instance's
347      * <tt>TabularType</tt> definition
348      */

349     public CompositeData JavaDoc remove(Object JavaDoc[] key) {
350
351     // Check key is not null and valid with tabularType
352
// (throws NullPointerException, InvalidKeyException)
353
//
354
checkKeyType(key);
355
356     // Removes the (key, value) mapping in the parent HashMap
357
//
358
return (CompositeData JavaDoc) dataMap.remove(Arrays.asList(key));
359     }
360
361
362
363
364     /* *** Content modification bulk operations *** */
365
366
367     /**
368      * Add all the values contained in the specified map <var>t</var> to this <tt>TabularData</tt> instance.
369      * This method converts the collection of values contained in this map into an array of <tt>CompositeData</tt> values,
370      * if possible, and then call the method <tt>putAll(CompositeData[])</tt>. Note that the keys used in the specified
371      * map <var>t</var> are ignored. This method allows, for example to add the content of another <tt>TabularData</tt>
372      * instance with the same row type (but possibly different index names) into this instance.
373      *
374      * @param t the map whose values are to be added as new rows to this <tt>TabularData</tt> instance;
375      * if <var>t</var> is <tt>null</tt> or empty, this method returns without doing anything.
376      *
377      * @throws NullPointerException if a value in <var>t</var> is <tt>null</tt>.
378      * @throws ClassCastException if a value in <var>t</var> is not an instance of <tt>CompositeData</tt>.
379      * @throws InvalidOpenTypeException if a value in <var>t</var> does not conform to
380      * this <tt>TabularData</tt> instance's row type definition.
381      * @throws KeyAlreadyExistsException if the index for a value in <var>t</var>, calculated according to
382      * this <tt>TabularData</tt> instance's <tt>TabularType</tt> definition
383      * already maps to an existing value in this instance,
384      * or two values in <var>t</var> have the same index.
385      */

386     public void putAll(Map JavaDoc t) {
387
388     // if t is null or empty, just return
389
//
390
if ( (t == null) || (t.size() == 0) ) {
391         return;
392     }
393
394     // Convert the values in t into an array of <tt>CompositeData</tt>
395
//
396
CompositeData JavaDoc[] values;
397     try {
398         values = (CompositeData JavaDoc[]) t.values().toArray(new CompositeData JavaDoc[t.size()]);
399     } catch (java.lang.ArrayStoreException JavaDoc e) {
400         throw new ClassCastException JavaDoc("Map argument t contains values which are not instances of <tt>CompositeData</tt>");
401     }
402     
403     // Add the array of values
404
//
405
putAll(values);
406     }
407
408     /**
409      * Add all the elements in <var>values</var> to this <tt>TabularData</tt> instance.
410      * If any element in <var>values</var> does not satisfy the constraints defined in {@link #put(CompositeData) <tt>put</tt>},
411      * or if any two elements in <var>values</var> have the same index calculated according to this <tt>TabularData</tt>
412      * instance's <tt>TabularType</tt> definition, then an exception describing the failure is thrown
413      * and no element of <var>values</var> is added, thus leaving this <tt>TabularData</tt> instance unchanged.
414      *
415      * @param values the array of composite data values to be added as new rows to this <tt>TabularData</tt> instance;
416      * if <var>values</var> is <tt>null</tt> or empty, this method returns without doing anything.
417      *
418      * @throws NullPointerException if an element of <var>values</var> is <tt>null</tt>
419      * @throws InvalidOpenTypeException if an element of <var>values</var> does not conform to
420      * this <tt>TabularData</tt> instance's row type definition
421      * (ie its <tt>TabularType</tt> definition)
422      * @throws KeyAlreadyExistsException if the index for an element of <var>values</var>, calculated according to
423      * this <tt>TabularData</tt> instance's <tt>TabularType</tt> definition
424      * already maps to an existing value in this instance,
425      * or two elements of <var>values</var> have the same index
426      */

427     public void putAll(CompositeData JavaDoc[] values) {
428
429     // if values is null or empty, just return
430
//
431
if ( (values == null) || (values.length == 0) ) {
432         return;
433     }
434
435     // create the list of indexes corresponding to each value
436
ArrayList JavaDoc indexes = new ArrayList JavaDoc(values.length + 1);
437
438     // Check all elements in values and build index list
439
//
440
List JavaDoc index;
441     for (int i=0; i<values.length; i++) {
442         // check value and calculate index
443
index = checkValueAndIndex(values[i]);
444         // check index is different of those previously calculated
445
if (indexes.contains(index)) {
446         throw new KeyAlreadyExistsException JavaDoc("Argument elements values["+ i +"] and values["+ indexes.indexOf(index) +
447                             "] have the same indexes, "+
448                             "calculated according to this TabularData instance's tabularType.");
449         }
450         // add to index list
451
indexes.add(index);
452     }
453
454     // store all (index, value) mappings in the dataMap HashMap
455
//
456
for (int i=0; i<values.length; i++) {
457         dataMap.put(indexes.get(i), values[i]);
458     }
459     }
460
461     /**
462      * Removes all rows from this <code>TabularDataSupport</code> instance.
463      */

464     public void clear() {
465
466         dataMap.clear();
467     }
468
469
470
471     /* *** Informational methods from java.util.Map *** */
472     
473     /**
474      * Returns the number of rows in this <code>TabularDataSupport</code> instance.
475      *
476      * @return the number of rows in this <code>TabularDataSupport</code> instance.
477      */

478     public int size() {
479     
480     return dataMap.size();
481     }
482
483     /**
484      * Returns <tt>true</tt> if this <code>TabularDataSupport</code> instance contains no rows.
485      *
486      * @return <tt>true</tt> if this <code>TabularDataSupport</code> instance contains no rows.
487      */

488     public boolean isEmpty() {
489     
490     return (this.size() == 0);
491     }
492     
493
494
495     /* *** Collection views from java.util.Map *** */
496     
497     /**
498      * Returns a set view of the keys contained in the underlying map of this <code>TabularDataSupport</code> instance,
499      * and used to index the rows. Each key contained in this set is an unmodifiable List.
500      * The set is backed by the underlying map of this <code>TabularDataSupport</code> instance,
501      * so changes to the <code>TabularDataSupport</code> instance are reflected in the set, and vice-versa.
502      *
503      * The set supports element removal, which removes the
504      * corresponding row from this <code>TabularDataSupport</code> instance, via the <tt>Iterator.remove</tt>,
505      * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt>, and
506      * <tt>clear</tt> operations.
507      * It does not support the <tt>add</tt> or <tt>addAll</tt> operations
508      *
509      * @return a set view of the keys used to index the rows of this <code>TabularDataSupport</code> instance.
510      */

511     public Set JavaDoc keySet() {
512     
513         return dataMap.keySet() ;
514     }
515     
516     /**
517      * Returns a collection view of the rows contained in this <code>TabularDataSupport</code> instance.
518      * The collection is backed by the underlying map, so changes to the <code>TabularDataSupport</code> instance
519      * are reflected in the collection, and vice-versa.
520      *
521      * The collection supports element removal,
522      * which removes the corresponding index to row mapping from this <code>TabularDataSupport</code> instance,
523      * via the <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>,
524      * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> operations.
525      * It does not support the <tt>add</tt> or <tt>addAll</tt> operations.
526      *
527      * @return a collection view of the values contained in this <code>TabularDataSupport</code> instance.
528      */

529     public Collection JavaDoc values() {
530     
531         return dataMap.values() ;
532     }
533     
534         
535     /**
536      * Returns a collection view of the index to row mappings contained in this <code>TabularDataSupport</code> instance.
537      * Each element in the returned collection is a <tt>Map.Entry</tt>.
538      * The collection is backed by the underlying map of this <code>TabularDataSupport</code> instance, in
539      * so changes to the <code>TabularDataSupport</code> instance are reflected the collection, and vice-versa.
540      * The collection supports element removal, which removes the corresponding mapping from the map, via the
541      * <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>,
542      * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> operations.
543      * It does not support the <tt>add</tt> or <tt>addAll</tt> operations.
544      * <p>
545      * <b>IMPORTANT NOTICE</b>: Do not use the <tt>SetValue</tt> method of <tt>Map.Entry</tt> elements contained in the returned
546      * collection view. Doing so would corrupt the index to row mappings contained in this <code>TabularDataSupport</code> instance.
547      * <p>
548      *
549      * @return a collection view of the mappings contained in this map.
550      * @see java.util.Map.Entry
551      */

552     public Set JavaDoc entrySet() {
553     
554         return dataMap.entrySet();
555     }
556
557
558     /* *** Commodity methods from java.lang.Object *** */
559
560
561     /**
562      * Returns a clone of this <code>TabularDataSupport</code> instance:
563      * the clone is obtained by calling <tt>super.clone()</tt>, and then cloning the underlying map.
564      * Only a shallow clone of the underlying map is made, i.e. no cloning of the indexes and row values is made as they are immutable.
565      */

566     public Object JavaDoc clone() {
567     try {
568         TabularDataSupport JavaDoc c = (TabularDataSupport JavaDoc) super.clone();
569         c.dataMap = (HashMap JavaDoc) ((HashMap JavaDoc) c.dataMap).clone();
570         return c;
571     }
572     catch (CloneNotSupportedException JavaDoc e) {
573         throw new InternalError JavaDoc(e.toString());
574     }
575     }
576
577
578     /**
579      * Compares the specified <var>obj</var> parameter with this <code>TabularDataSupport</code> instance for equality.
580      * <p>
581      * Returns <tt>true</tt> if and only if all of the following statements are true:
582      * <ul>
583      * <li><var>obj</var> is non null,</li>
584      * <li><var>obj</var> also implements the <code>TabularData</code> interface,</li>
585      * <li>their tabular types are equal</li>
586      * <li>their contents (ie all CompositeData values) are equal.</li>
587      * </ul>
588      * This ensures that this <tt>equals</tt> method works properly for <var>obj</var> parameters which are
589      * different implementations of the <code>TabularData</code> interface.
590      * <br>&nbsp;
591      * @param obj the object to be compared for equality with this <code>TabularDataSupport</code> instance;
592      *
593      * @return <code>true</code> if the specified object is equal to this <code>TabularDataSupport</code> instance.
594      */

595     public boolean equals(Object JavaDoc obj) {
596
597     // if obj is null, return false
598
//
599
if (obj == null) {
600         return false;
601     }
602
603     // if obj is not a TabularData, return false
604
//
605
TabularData JavaDoc other;
606     try {
607         other = (TabularData JavaDoc) obj;
608     } catch (ClassCastException JavaDoc e) {
609         return false;
610     }
611
612     // Now, really test for equality between this TabularData implementation and the other:
613
//
614

615     // their tabularType should be equal
616
if ( ! this.getTabularType().equals(other.getTabularType()) ) {
617         return false;
618     }
619
620     // their contents should be equal:
621
// . same size
622
// . values in this instance are in the other (we know there are no duplicate elements possible)
623
// (row values comparison is enough, because keys are calculated according to tabularType)
624

625     if (this.size() != other.size()) {
626         return false;
627     }
628     for (Iterator JavaDoc iter = this.values().iterator(); iter.hasNext(); ) {
629         CompositeData JavaDoc value = (CompositeData JavaDoc) iter.next();
630         if ( ! other.containsValue(value) ) {
631         return false;
632         }
633     }
634        
635     // All tests for equality were successfull
636
//
637
return true;
638     }
639
640     /**
641      * Returns the hash code value for this <code>TabularDataSupport</code> instance.
642      * <p>
643      * The hash code of a <code>TabularDataSupport</code> instance is the sum of the hash codes
644      * of all elements of information used in <code>equals</code> comparisons
645      * (ie: its <i>tabular type</i> and its content, where the content is defined as all the CompositeData values).
646      * <p>
647      * This ensures that <code> t1.equals(t2) </code> implies that <code> t1.hashCode()==t2.hashCode() </code>
648      * for any two <code>TabularDataSupport</code> instances <code>t1</code> and <code>t2</code>,
649      * as required by the general contract of the method
650      * {@link Object#hashCode() Object.hashCode()}.
651      * <p>
652      * However, note that another instance of a class implementing the <code>TabularData</code> interface
653      * may be equal to this <code>TabularDataSupport</code> instance as defined by {@link #equals},
654      * but may have a different hash code if it is calculated differently.
655      *
656      * @return the hash code value for this <code>TabularDataSupport</code> instance
657      */

658    public int hashCode() {
659
660     int result = 0;
661
662     result += this.tabularType.hashCode();
663     for (Iterator JavaDoc iter = this.values().iterator(); iter.hasNext(); ) {
664         result += ((CompositeData JavaDoc)iter.next()).hashCode();
665     }
666
667     return result;
668
669     }
670
671     /**
672      * Returns a string representation of this <code>TabularDataSupport</code> instance.
673      * <p>
674      * The string representation consists of the name of this class (ie <code>javax.management.openmbean.TabularDataSupport</code>),
675      * the string representation of the tabular type of this instance, and the string representation of the contents
676      * (ie list the key=value mappings as returned by a call to
677      * <tt>dataMap.</tt>{@link java.util.HashMap#toString() toString()}).
678      *
679      * @return a string representation of this <code>TabularDataSupport</code> instance
680      */

681     public String JavaDoc toString() {
682
683     return new StringBuffer JavaDoc()
684         .append(this.getClass().getName())
685         .append("(tabularType=")
686         .append(tabularType.toString())
687         .append(",contents=")
688         .append(dataMap.toString())
689         .append(")")
690         .toString();
691     }
692
693
694
695
696     /* *** TabularDataSupport internal utility methods *** */
697
698
699     /**
700      * Returns the index for value, assuming value is valid for this <tt>TabularData</tt> instance
701      * (ie value is not null, and its composite type is equal to row type).
702      *
703      * The index is a List, and not an array, so that an index.equals(otherIndex) call will actually compare contents,
704      * not just the objects references as is done for an array object.
705      *
706      * The returned List is unmodifiable so that once a row has been put into the dataMap, its index cannot be modified,
707      * for example by a user that would attempt to modify an index contained in the Set returned by keySet().
708      */

709     private List JavaDoc internalCalculateIndex(CompositeData JavaDoc value) {
710
711     return Collections.unmodifiableList(Arrays.asList(value.getAll(this.indexNamesArray)));
712     }
713
714     /**
715      * Checks if the specified key is valid for this <tt>TabularData</tt> instance.
716      *
717      * @throws NullPointerException
718      * @throws InvalidOpenTypeException
719      */

720     private void checkKeyType(Object JavaDoc[] key) {
721     
722     // Check key is neither null nor empty
723
//
724
if ( (key == null) || (key.length == 0) ) {
725         throw new NullPointerException JavaDoc("Argument key cannot be null or empty.");
726     }
727
728     /* Now check key is valid with tabularType index and row type definitions: */
729
730     // key[] should have the size expected for an index
731
//
732
if (key.length != this.indexNamesArray.length) {
733         throw new InvalidKeyException JavaDoc("Argument key's length="+ key.length +
734                       " is different from the number of item values, which is "+ indexNamesArray.length +
735                       ", specified for the indexing rows in this TabularData instance.");
736     }
737
738     // each element in key[] should be a value for its corresponding open type specified in rowType
739
//
740
OpenType JavaDoc keyElementType;
741     for (int i=0; i<key.length; i++) {
742         keyElementType = tabularType.getRowType().getType(this.indexNamesArray[i]);
743         if ( (key[i] != null) && (! keyElementType.isValue(key[i])) ) {
744         throw new InvalidKeyException JavaDoc("Argument element key["+ i +"] is not a value for the open type expected for "+
745                           "this element of the index, whose name is \""+ indexNamesArray[i] +
746                           "\" and whose open type is "+ keyElementType);
747         }
748     }
749     }
750
751     /**
752      * Checks the specified value's type is valid for this <tt>TabularData</tt> instance
753      * (ie value is not null, and its composite type is equal to row type).
754      *
755      * @throws NullPointerException
756      * @throws InvalidOpenTypeException
757      */

758     private void checkValueType(CompositeData JavaDoc value) {
759
760     // Check value is not null
761
//
762
if (value == null) {
763         throw new NullPointerException JavaDoc("Argument value cannot be null.");
764     }
765     
766     // if value's type is not the same as this instance's row type, throw InvalidOpenTypeException
767
//
768
if ( ! value.getCompositeType().equals(tabularType.getRowType()) ) {
769         throw new InvalidOpenTypeException JavaDoc("Argument value's composite type ["+ value.getCompositeType() +
770                            "] is not equal to "+
771                            "this TabularData instance's row type ["+ tabularType.getRowType() +"].");
772     }
773     }
774
775     /**
776      * Checks if the specified value can be put (ie added) in this <tt>TabularData</tt> instance
777      * (ie value is not null, its composite type is equal to row type, and its index is not already used),
778      * and returns the index calculated for this value.
779      *
780      * The index is a List, and not an array, so that an index.equals(otherIndex) call will actually compare contents,
781      * not just the objects references as is done for an array object.
782      *
783      * @throws NullPointerException
784      * @throws InvalidOpenTypeException
785      * @throws KeyAlreadyExistsException
786      */

787     private List JavaDoc checkValueAndIndex(CompositeData JavaDoc value) {
788
789     // Check value is valid
790
//
791
checkValueType(value);
792
793     // Calculate value's index according to this instance's tabularType
794
// and check it is not already used for a mapping in the parent HashMap
795
//
796
List JavaDoc index = internalCalculateIndex(value);
797     
798     if (dataMap.containsKey(index)) {
799         throw new KeyAlreadyExistsException JavaDoc("Argument value's index, calculated according to this TabularData "+
800                         "instance's tabularType, already refers to a value in this table.");
801     }
802     
803     // The check is OK, so return the index
804
//
805
return index;
806     }
807
808     /**
809      * Deserializes a {@link TabularDataSupport} from an {@link ObjectInputStream}.
810      */

811     private void readObject(ObjectInputStream JavaDoc in)
812         throws IOException JavaDoc, ClassNotFoundException JavaDoc {
813       in.defaultReadObject();
814       List JavaDoc tmpNames = tabularType.getIndexNames();
815       indexNamesArray = (String JavaDoc[]) tmpNames.toArray(new String JavaDoc[tmpNames.size()]);
816     }
817 }
818
Popular Tags