API Overview API Index Package Overview Direct link to this page
JDK 1.6
  javax.management.openmbean. TabularDataSupport View Javadoc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888

/*
 * @(#)TabularDataSupport.java	3.36 06/03/29
 * 
 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */


package javax.management.openmbean;


// java import
//
import java.io.IOException;
import java.io.Serializable;
import java.io.ObjectInputStream;
import java.util.Iterator;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.Collection;
import java.util.Collections;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;

// jmx import
//


/**
 * The <tt>TabularDataSupport</tt> class is the <i>open data</i> class which implements the <tt>TabularData</tt> 
 * and the <tt>Map</tt> interfaces, and which is internally based on a hash map data structure.
 *
 * @version     3.36  06/03/29
 * @author      Sun Microsystems, Inc.
 *
 * @since 1.5
 * @since.unbundled JMX 1.1
 */
/* It would make much more sense to implement
   Map<List<?>,CompositeData> here, but unfortunately we cannot for
   compatibility reasons.  If we did that, then we would have to
   define e.g.
   CompositeData remove(Object)
   instead of
   Object remove(Object).

   That would mean that if any existing code subclassed
   TabularDataSupport and overrode
   Object remove(Object),
   it would (a) no longer compile and (b) not actually override
   CompositeData remove(Object)
   in binaries compiled before the change.
*/
public class TabularDataSupport implements TabularData, Map<Object,Object>,
               Cloneable, Serializable { 
    
    
    /* Serial version */
    static final long serialVersionUID = 5720150593236309827L;


    /**
     * @serial This tabular data instance's contents: a {@link HashMap}
     */
    private Map<Object,CompositeData> dataMap;
    
    /**
     * @serial This tabular data instance's tabular type
     */
    private TabularType tabularType;

    /**
     * The array of item names that define the index used for rows (convenience field)
     */
    private transient String[] indexNamesArray;
    


    /* *** Constructors *** */


    /**
     * Creates an empty <tt>TabularDataSupport</tt> instance whose open-type is <var>tabularType</var>, 
     * and whose underlying <tt>HashMap</tt> has a default initial capacity (101) and default load factor (0.75).
     * <p>
     * This constructor simply calls <tt>this(tabularType, 101, 0.75f);</tt>
     *
     * @param  tabularType 		 the <i>tabular type</i> describing this <tt>TabularData</tt> instance;
     *					 cannot be null.
     *
     * @throws IllegalArgumentException  if the tabular type is null. 
     */
    public TabularDataSupport(TabularType tabularType) {

	this(tabularType, 101, 0.75f);
    }

    /**
     * Creates an empty <tt>TabularDataSupport</tt> instance whose open-type is <var>tabularType</var>, 
     * and whose underlying <tt>HashMap</tt> has the specified initial capacity and load factor.
     *
     * @param  tabularType		 the <i>tabular type</i> describing this <tt>TabularData</tt> instance;
     *				 cannot be null.
     *
     * @param  initialCapacity   the initial capacity of the HashMap.
     * 
     * @param  loadFactor        the load factor of the HashMap
     * 
     * @throws IllegalArgumentException  if the initial capacity is less than zero, 
     *					 or the load factor is nonpositive,
     *					 or the tabular type is null.
     */
    public TabularDataSupport(TabularType tabularType, int initialCapacity, float loadFactor) {

	// Check tabularType is not null
	//
	if (tabularType == null) {
	    throw new IllegalArgumentException("Argument tabularType cannot be null.");
	}

	// Initialize this.tabularType (and indexNamesArray for convenience)
	//
	this.tabularType = tabularType;
	List<String> tmpNames = tabularType.getIndexNames();
	this.indexNamesArray = tmpNames.toArray(new String[tmpNames.size()]);
	
	// Construct the empty contents HashMap
	//
	this.dataMap =
	    new HashMap<Object,CompositeData>(initialCapacity, loadFactor);
    }




    /* *** TabularData specific information methods *** */


    /**
     * Returns the <i>tabular type</i> describing this <tt>TabularData</tt> instance.
     */
    public TabularType getTabularType() {

	return tabularType;
    }

    /**
     * Calculates the index that would be used in this <tt>TabularData</tt> instance to refer to the specified
     * composite data <var>value</var> parameter if it were added to this instance.
     * This method checks for the type validity of the specified <var>value</var>, 
     * but does not check if the calculated index is already used to refer to a value in this <tt>TabularData</tt> instance.
     *
     * @param  value			  the composite data value whose index in this 
     *					  <tt>TabularData</tt> instance is to be calculated;
     *					  must be of the same composite type as this instance's row type;
     *					  must not be null.
     *
     * @return the index that the specified <var>value</var> would have in this <tt>TabularData</tt> instance.
     * 
     * @throws NullPointerException       if <var>value</var> is <tt>null</tt>. 
     * 
     * @throws InvalidOpenTypeException   if <var>value</var> does not conform to this <tt>TabularData</tt> instance's 
     *				          row type definition.
     */
    public Object[] calculateIndex(CompositeData value) {

	// Check value is valid
	//
	checkValueType(value);

	// Return its calculated index
	//
	return internalCalculateIndex(value).toArray();
    }




    /* *** Content information query methods *** */


    /**
     * Returns <tt>true</tt> if and only if this <tt>TabularData</tt> instance contains a <tt>CompositeData</tt> value 
     * (ie a row) whose index is the specified <var>key</var>. If <var>key</var> cannot be cast to a one dimension array
     * of Object instances, this method simply returns <tt>false</tt>; otherwise it returns the the result of the call to
     * <tt>this.containsKey((Object[]) key)</tt>.
     * 
     * @param  key  the index value whose presence in this <tt>TabularData</tt> instance is to be tested.
     *
     * @return  <tt>true</tt> if this <tt>TabularData</tt> indexes a row value with the specified key.
     */ 
    public boolean containsKey(Object key) { 

	// if key is not an array of Object instances, return false
	//
	Object[] k;
	try {
	    k = (Object[]) key;
	} catch (ClassCastException e) {
	    return false;
	}

	return  this.containsKey(k);
    }

    /**
     * Returns <tt>true</tt> if and only if this <tt>TabularData</tt> instance contains a <tt>CompositeData</tt> value 
     * (ie a row) whose index is the specified <var>key</var>. If <var>key</var> is <tt>null</tt> or does not conform to
     * this <tt>TabularData</tt> instance's <tt>TabularType</tt> definition, this method simply returns <tt>false</tt>.
     * 
     * @param  key  the index value whose presence in this <tt>TabularData</tt> instance is to be tested.
     *
     * @return  <tt>true</tt> if this <tt>TabularData</tt> indexes a row value with the specified key.
     */ 
    public boolean containsKey(Object[] key) { 

	return  ( key == null ? false : dataMap.containsKey(Arrays.asList(key)));
    }

    /**
     * Returns <tt>true</tt> if and only if this <tt>TabularData</tt> instance contains the specified
     * <tt>CompositeData</tt> value. If <var>value</var> is <tt>null</tt> or does not conform to
     * this <tt>TabularData</tt> instance's row type definition, this method simply returns <tt>false</tt>.
     *
     * @param  value  the row value whose presence in this <tt>TabularData</tt> instance is to be tested.
     *
     * @return  <tt>true</tt> if this <tt>TabularData</tt> instance contains the specified row value.
     */
    public boolean containsValue(CompositeData value) { 

	return dataMap.containsValue(value);
    }

    /**
     * Returns <tt>true</tt> if and only if this <tt>TabularData</tt> instance contains the specified
     * value.
     *
     * @param  value  the row value whose presence in this <tt>TabularData</tt> instance is to be tested.
     *
     * @return  <tt>true</tt> if this <tt>TabularData</tt> instance contains the specified row value.
     */
    public boolean containsValue(Object value) { 

	return dataMap.containsValue(value);
    }

    /**
     * This method simply calls <tt>get((Object[]) key)</tt>.
     *
     * @throws NullPointerException  if the <var>key</var> is <tt>null</tt> 
     * @throws ClassCastException    if the <var>key</var> is not of the type <tt>Object[]</tt>
     * @throws InvalidKeyException   if the <var>key</var> does not conform to this <tt>TabularData</tt> instance's 
     *				     <tt>TabularType</tt> definition 
     */
    public Object get(Object key) {

	return get((Object[]) key);
    }

    /**
     * Returns the <tt>CompositeData</tt> value whose index is
     * <var>key</var>, or <tt>null</tt> if there is no value mapping
     * to <var>key</var>, in this <tt>TabularData</tt> instance.
     *
     * @param key the index of the value to get in this
     * <tt>TabularData</tt> instance; * must be valid with this
     * <tt>TabularData</tt> instance's row type definition; * must not
     * be null.
     *
     * @return the value corresponding to <var>key</var>.
     * 
     * @throws NullPointerException  if the <var>key</var> is <tt>null</tt> 
     * @throws InvalidKeyException   if the <var>key</var> does not conform to this <tt>TabularData</tt> instance's 
     *				     <tt>TabularType</tt> type definition.
     */
    public CompositeData get(Object[] key) { 

	// Check key is not null and valid with tabularType 
	// (throws NullPointerException, InvalidKeyException)
	//
	checkKeyType(key);

	// Return the mapping stored in the parent HashMap
	//
	return (CompositeData) dataMap.get(Arrays.asList(key));
    }




    /* *** Content modification operations (one element at a time) *** */


    /**
     * This method simply calls <tt>put((CompositeData) value)</tt> and  
     * therefore ignores its <var>key</var> parameter which can be <tt>null</tt>.
     *
     * @param key an ignored parameter.
     * @param value the {@link CompositeData} to put.
     *
     * @return the value which is put
     *
     * @throws NullPointerException  if the <var>value</var> is <tt>null</tt> 
     * @throws ClassCastException if the <var>value</var> is not of
     * the type <tt>CompositeData</tt>
     * @throws InvalidOpenTypeException if the <var>value</var> does
     * not conform to this <tt>TabularData</tt> instance's
     * <tt>TabularType</tt> definition
     * @throws KeyAlreadyExistsException if the key for the
     * <var>value</var> parameter, calculated according to this
     * <tt>TabularData</tt> instance's <tt>TabularType</tt> definition
     * already maps to an existing value
     */
    public Object put(Object key, Object value) {
	internalPut((CompositeData) value);
	return value; // should be return internalPut(...); (5090566)
    }

    public void put(CompositeData value) {
	internalPut(value);
    }

    private CompositeData internalPut(CompositeData value) {
	// Check value is not null, value's type is the same as this instance's row type, 
	// and calculate the value's index according to this instance's tabularType and
	// check it is not already used for a mapping in the parent HashMap
	//
	List<?> index = checkValueAndIndex(value);

	// store the (key, value) mapping in the dataMap HashMap
	//
	return dataMap.put(index, value);
    }

    /**
     * This method simply calls <tt>remove((Object[]) key)</tt>.
     *
     * @param key an <tt>Object[]</tt> representing the key to remove.
     *
     * @return previous value associated with specified key, or <tt>null</tt>
     *	       if there was no mapping for key.  
     *
     * @throws NullPointerException  if the <var>key</var> is <tt>null</tt> 
     * @throws ClassCastException    if the <var>key</var> is not of the type <tt>Object[]</tt>
     * @throws InvalidKeyException   if the <var>key</var> does not conform to this <tt>TabularData</tt> instance's 
     *				     <tt>TabularType</tt> definition 
     */
    public Object remove(Object key) {

	return remove((Object[]) key);
    }

    /**
     * Removes the <tt>CompositeData</tt> value whose index is <var>key</var> from this <tt>TabularData</tt> instance,
     * and returns the removed value, or returns <tt>null</tt> if there is no value whose index is <var>key</var>.
     *
     * @param  key  the index of the value to get in this <tt>TabularData</tt> instance;
     *		    must be valid with this <tt>TabularData</tt> instance's row type definition;
     *		    must not be null.
     * 
     * @return previous value associated with specified key, or <tt>null</tt>
     *	       if there was no mapping for key.  
     *
     * @throws NullPointerException  if the <var>key</var> is <tt>null</tt> 
     * @throws InvalidKeyException   if the <var>key</var> does not conform to this <tt>TabularData</tt> instance's 
     *				     <tt>TabularType</tt> definition 
     */
    public CompositeData remove(Object[] key) { 

	// Check key is not null and valid with tabularType 
	// (throws NullPointerException, InvalidKeyException)
	//
	checkKeyType(key);

	// Removes the (key, value) mapping in the parent HashMap
	//
	return dataMap.remove(Arrays.asList(key));
    }



    /* ***   Content modification bulk operations   *** */


    /**
     * Add all the values contained in the specified map <var>t</var>
     * to this <tt>TabularData</tt> instance.  This method converts
     * the collection of values contained in this map into an array of
     * <tt>CompositeData</tt> values, if possible, and then call the
     * method <tt>putAll(CompositeData[])</tt>. Note that the keys
     * used in the specified map <var>t</var> are ignored. This method
     * allows, for example to add the content of another
     * <tt>TabularData</tt> instance with the same row type (but
     * possibly different index names) into this instance.
     *
     * @param t the map whose values are to be added as new rows to
     * this <tt>TabularData</tt> instance; if <var>t</var> is
     * <tt>null</tt> or empty, this method returns without doing
     * anything.
     * 
     * @throws NullPointerException if a value in <var>t</var> is
     * <tt>null</tt>.
     * @throws ClassCastException if a value in <var>t</var> is not an
     * instance of <tt>CompositeData</tt>.
     * @throws InvalidOpenTypeException if a value in <var>t</var>
     * does not conform to this <tt>TabularData</tt> instance's row
     * type definition.
     * @throws KeyAlreadyExistsException if the index for a value in
     * <var>t</var>, calculated according to this
     * <tt>TabularData</tt> instance's <tt>TabularType</tt> definition
     * already maps to an existing value in this instance, or two
     * values in <var>t</var> have the same index.
     */
    public void putAll(Map<?,?> t) {

	// if t is null or empty, just return
	//
	if ( (t == null) || (t.size() == 0) ) {
	    return;
	}

	// Convert the values in t into an array of <tt>CompositeData</tt>
	//
	CompositeData[] values;
	try {
	    values = (CompositeData[])
                t.values().toArray(new CompositeData[t.size()]);
	} catch (java.lang.ArrayStoreException e) {
	    throw new ClassCastException("Map argument t contains values which are not instances of <tt>CompositeData</tt>");
	}
	
	// Add the array of values
	//
	putAll(values);
    }

    /**
     * Add all the elements in <var>values</var> to this
     * <tt>TabularData</tt> instance.  If any element in
     * <var>values</var> does not satisfy the constraints defined in
     * {@link #put(CompositeData) <tt>put</tt>}, or if any two
     * elements in <var>values</var> have the same index calculated
     * according to this <tt>TabularData</tt> instance's
     * <tt>TabularType</tt> definition, then an exception describing
     * the failure is thrown and no element of <var>values</var> is
     * added, thus leaving this <tt>TabularData</tt> instance
     * unchanged.
     *
     * @param values the array of composite data values to be added as
     * new rows to this <tt>TabularData</tt> instance; if
     * <var>values</var> is <tt>null</tt> or empty, this method
     * returns without doing anything.
     * 
     * @throws NullPointerException if an element of <var>values</var>
     * is <tt>null</tt>
     * @throws InvalidOpenTypeException if an element of
     * <var>values</var> does not conform to this
     * <tt>TabularData</tt> instance's row type definition (ie its
     * <tt>TabularType</tt> definition)
     * @throws KeyAlreadyExistsException if the index for an element
     * of <var>values</var>, calculated according to this
     * <tt>TabularData</tt> instance's <tt>TabularType</tt> definition
     * already maps to an existing value in this instance, or two
     * elements of <var>values</var> have the same index
     */
    public void putAll(CompositeData[] values) {

	// if values is null or empty, just return
	//
	if ( (values == null) || (values.length == 0) ) {
	    return;
	}

	// create the list of indexes corresponding to each value
	List<List<?>> indexes =
	    new ArrayList<List<?>>(values.length + 1);

	// Check all elements in values and build index list 
	//
	List<?> index;
	for (int i=0; i<values.length; i++) {
	    // check value and calculate index
	    index = checkValueAndIndex(values[i]);
	    // check index is different of those previously calculated
	    if (indexes.contains(index)) {
		throw new KeyAlreadyExistsException("Argument elements values["+ i +"] and values["+ indexes.indexOf(index) +
						    "] have the same indexes, "+
						    "calculated according to this TabularData instance's tabularType.");
	    }
	    // add to index list
	    indexes.add(index);
	}

	// store all (index, value) mappings in the dataMap HashMap
	//
	for (int i=0; i<values.length; i++) {
	    dataMap.put(indexes.get(i), values[i]);
	}
    }

    /**
     * Removes all rows from this <code>TabularDataSupport</code> instance.
     */
    public void clear() {

        dataMap.clear();
    }



    /* ***  Informational methods from java.util.Map  *** */
    
    /**
     * Returns the number of rows in this <code>TabularDataSupport</code> instance.
     *
     * @return the number of rows in this <code>TabularDataSupport</code> instance.
     */
    public int size() {
    
	return dataMap.size();
    }

    /**
     * Returns <tt>true</tt> if this <code>TabularDataSupport</code> instance contains no rows.
     *
     * @return <tt>true</tt> if this <code>TabularDataSupport</code> instance contains no rows.
     */
    public boolean isEmpty() {
    
	return (this.size() == 0);
    }
    


    /* ***  Collection views from java.util.Map  *** */
    
    /**
     * Returns a set view of the keys contained in the underlying map of this
     * {@code TabularDataSupport} instance used to index the rows.
     * Each key contained in this {@code Set} is an unmodifiable {@code List<?>}
     * so the returned set view is a {@code Set<List<?>>} but is declared as a
     * {@code Set<Object>} for compatibility reasons.
     * The set is backed by the underlying map of this
     * {@code TabularDataSupport} instance, so changes to the
     * {@code TabularDataSupport} instance are reflected in the
     * set, and vice-versa.
     *
     * The set supports element removal, which removes the corresponding
     * row from this {@code TabularDataSupport} instance, via the
     * {@link Iterator#remove}, {@link Set#remove}, {@link Set#removeAll},
     * {@link Set#retainAll}, and {@link Set#clear} operations. It does
     *  not support the {@link Set#add} or {@link Set#addAll} operations.
     *
     * @return a set view ({@code Set<List<?>>}) of the keys used to index
     * the rows of this {@code TabularDataSupport} instance.
     */
    public Set<Object> keySet() {
    
        return dataMap.keySet() ;
    }
    
    /**
     * Returns a collection view of the rows contained in this
     * {@code TabularDataSupport} instance. The returned {@code Collection}
     * is a {@code Collection<CompositeData>} but is declared as a
     * {@code Collection<Object>} for compatibility reasons.
     * The returned collection can be used to iterate over the values.
     * The collection is backed by the underlying map, so changes to the
     * {@code TabularDataSupport} instance are reflected in the collection,
     * and vice-versa.
     *
     * The collection supports element removal, which removes the corresponding
     * index to row mapping from this {@code TabularDataSupport} instance, via
     * the {@link Iterator#remove}, {@link Collection#remove},
     * {@link Collection#removeAll}, {@link Collection#retainAll},
     * and {@link Collection#clear} operations. It does not support
     * the {@link Collection#add} or {@link Collection#addAll} operations.
     *
     * @return a collection view ({@code Collection<CompositeData>}) of
     * the values contained in this {@code TabularDataSupport} instance.
     */
    public Collection<Object> values() {
    
        return (Collection) dataMap.values() ;
    }
    
        
    /**
     * Returns a collection view of the index to row mappings
     * contained in this {@code TabularDataSupport} instance.
     * Each element in the returned collection is
     * a {@code Map.Entry<List<?>,CompositeData>} but
     * is declared as a {@code Map.Entry<Object,Object>}
     * for compatibility reasons. Each of the map entry
     * keys is an unmodifiable {@code List<?>}.
     * The collection is backed by the underlying map of this
     * {@code TabularDataSupport} instance, so changes to the
     * {@code TabularDataSupport} instance are reflected in
     * the collection, and vice-versa.
     * The collection supports element removal, which removes
     * the corresponding mapping from the map, via the
     * {@link Iterator#remove}, {@link Collection#remove},
     * {@link Collection#removeAll}, {@link Collection#retainAll},
     * and {@link Collection#clear} operations. It does not support
     * the {@link Collection#add} or {@link Collection#addAll}
     * operations.
     * <p>
     * <b>IMPORTANT NOTICE</b>: Do not use the {@code setValue} method of the
     * {@code Map.Entry} elements contained in the returned collection view.
     * Doing so would corrupt the index to row mappings contained in this
     * {@code TabularDataSupport} instance.
     *
     * @return a collection view ({@code Set<Map.Entry<List<?>,CompositeData>>})
     * of the mappings contained in this map.
     * @see java.util.Map.Entry
     */
    public Set<Map.Entry<Object,Object>> entrySet() {
    
        return (Set) dataMap.entrySet();
    }


    /* ***  Commodity methods from java.lang.Object  *** */


    /**
     * Returns a clone of this <code>TabularDataSupport</code> instance: 
     * the clone is obtained by calling <tt>super.clone()</tt>, and then cloning the underlying map.
     * 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.
     */
    /* We cannot use covariance here and return TabularDataSupport
       because this would fail with existing code that subclassed
       TabularDataSupport and overrode Object clone().  It would not
       override the new clone().  */
    public Object clone() {
	try {
	    TabularDataSupport c = (TabularDataSupport) super.clone();
	    c.dataMap = new HashMap<Object,CompositeData>(c.dataMap);
	    return c;
	}
	catch (CloneNotSupportedException e) {
	    throw new InternalError(e.toString());
	}
    }


    /**
     * Compares the specified <var>obj</var> parameter with this <code>TabularDataSupport</code> instance for equality. 
     * <p>
     * Returns <tt>true</tt> if and only if all of the following statements are true:
     * <ul>
     * <li><var>obj</var> is non null,</li>
     * <li><var>obj</var> also implements the <code>TabularData</code> interface,</li>
     * <li>their tabular types are equal</li>
     * <li>their contents (ie all CompositeData values) are equal.</li>
     * </ul>
     * This ensures that this <tt>equals</tt> method works properly for <var>obj</var> parameters which are
     * different implementations of the <code>TabularData</code> interface.
     * <br>&nbsp;
     * @param  obj  the object to be compared for equality with this <code>TabularDataSupport</code> instance;
     * 
     * @return  <code>true</code> if the specified object is equal to this <code>TabularDataSupport</code> instance.
     */
    public boolean equals(Object obj) { 

	// if obj is null, return false
	//
	if (obj == null) {
	    return false;
	}

	// if obj is not a TabularData, return false
	//
	TabularData other;
	try {
	    other = (TabularData) obj;
	} catch (ClassCastException e) {
	    return false;
	}

	// Now, really test for equality between this TabularData implementation and the other:
	//
	
	// their tabularType should be equal
	if ( ! this.getTabularType().equals(other.getTabularType()) ) {
	    return false;
	}

	// their contents should be equal: 
	// . same size
	// . values in this instance are in the other (we know there are no duplicate elements possible)
	// (row values comparison is enough, because keys are calculated according to tabularType)
	
	if (this.size() != other.size()) {
	    return false;
	}
	for (Iterator iter = this.values().iterator(); iter.hasNext();  ) {
	    CompositeData value = (CompositeData) iter.next();
	    if ( ! other.containsValue(value) ) {
		return false;
	    }
	}
       
	// All tests for equality were successfull
	//
	return true;
    }

    /**
     * Returns the hash code value for this <code>TabularDataSupport</code> instance. 
     * <p>
     * The hash code of a <code>TabularDataSupport</code> instance is the sum of the hash codes
     * of all elements of information used in <code>equals</code> comparisons 
     * (ie: its <i>tabular type</i> and its content, where the content is defined as all the CompositeData values). 
     * <p>
     * This ensures that <code> t1.equals(t2) </code> implies that <code> t1.hashCode()==t2.hashCode() </code> 
     * for any two <code>TabularDataSupport</code> instances <code>t1</code> and <code>t2</code>, 
     * as required by the general contract of the method
     * {@link Object#hashCode() Object.hashCode()}.
     * <p>
     * However, note that another instance of a class implementing the <code>TabularData</code> interface
     * may be equal to this <code>TabularDataSupport</code> instance as defined by {@link #equals}, 
     * but may have a different hash code if it is calculated differently.
     *
     * @return  the hash code value for this <code>TabularDataSupport</code> instance
     */
   public int hashCode() { 

	int result = 0;

	result += this.tabularType.hashCode();
	for (Iterator iter = this.values().iterator(); iter.hasNext();  ) {
	    result += ((CompositeData)iter.next()).hashCode();
	}

	return result;

    }

    /**
     * Returns a string representation of this <code>TabularDataSupport</code> instance. 
     * <p>
     * The string representation consists of the name of this class (ie <code>javax.management.openmbean.TabularDataSupport</code>), 
     * the string representation of the tabular type of this instance, and the string representation of the contents
     * (ie list the key=value mappings as returned by a call to
     * <tt>dataMap.</tt>{@link java.util.HashMap#toString() toString()}).
     * 
     * @return  a string representation of this <code>TabularDataSupport</code> instance
     */
    public String toString() { 

	return new StringBuffer()
	    .append(this.getClass().getName())
	    .append("(tabularType=")
	    .append(tabularType.toString())
	    .append(",contents=")
	    .append(dataMap.toString())
	    .append(")")
	    .toString();
    }




    /* *** TabularDataSupport internal utility methods *** */


    /**
     * Returns the index for value, assuming value is valid for this <tt>TabularData</tt> instance 
     * (ie value is not null, and its composite type is equal to row type).
     * 
     * The index is a List, and not an array, so that an index.equals(otherIndex) call will actually compare contents,
     * not just the objects references as is done for an array object.
     *
     * The returned List is unmodifiable so that once a row has been put into the dataMap, its index cannot be modified,
     * for example by a user that would attempt to modify an index contained in the Set returned by keySet(). 
     */
    private List<?> internalCalculateIndex(CompositeData value) {

	return Collections.unmodifiableList(Arrays.asList(value.getAll(this.indexNamesArray)));
    }

    /**
     * Checks if the specified key is valid for this <tt>TabularData</tt> instance.
     *
     * @throws  NullPointerException
     * @throws  InvalidOpenTypeException
     */
    private void checkKeyType(Object[] key) { 
	
	// Check key is neither null nor empty
	//
	if ( (key == null) || (key.length == 0) ) {
	    throw new NullPointerException("Argument key cannot be null or empty.");
	}

	/* Now check key is valid with tabularType index and row type definitions: */

	// key[] should have the size expected for an index 
	//
	if (key.length != this.indexNamesArray.length) {
	    throw new InvalidKeyException("Argument key's length="+ key.length +
					  " is different from the number of item values, which is "+ indexNamesArray.length +
					  ", specified for the indexing rows in this TabularData instance.");
	}

	// each element in key[] should be a value for its corresponding open type specified in rowType
	//
	OpenType<?> keyElementType;
	for (int i=0; i<key.length; i++) {
	    keyElementType = tabularType.getRowType().getType(this.indexNamesArray[i]);
	    if ( (key[i] != null) && (! keyElementType.isValue(key[i])) ) {
		throw new InvalidKeyException("Argument element key["+ i +"] is not a value for the open type expected for "+
					      "this element of the index, whose name is \""+ indexNamesArray[i] +
					      "\" and whose open type is "+ keyElementType);
	    }
	}
    }

    /**
     * Checks the specified value's type is valid for this <tt>TabularData</tt> instance 
     * (ie value is not null, and its composite type is equal to row type).
     *
     * @throws  NullPointerException
     * @throws  InvalidOpenTypeException
     */
    private void checkValueType(CompositeData value) {

	// Check value is not null
	//
	if (value == null) {
	    throw new NullPointerException("Argument value cannot be null.");
	}
	
	// if value's type is not the same as this instance's row type, throw InvalidOpenTypeException
	//
	if (!tabularType.getRowType().isValue(value)) {
	    throw new InvalidOpenTypeException("Argument value's composite type ["+ value.getCompositeType() +
					       "] is not assignable to "+
					       "this TabularData instance's row type ["+ tabularType.getRowType() +"].");
	}
    }

    /**
     * Checks if the specified value can be put (ie added) in this <tt>TabularData</tt> instance
     * (ie value is not null, its composite type is equal to row type, and its index is not already used),
     * and returns the index calculated for this value. 
     * 
     * The index is a List, and not an array, so that an index.equals(otherIndex) call will actually compare contents,
     * not just the objects references as is done for an array object.
     *
     * @throws  NullPointerException
     * @throws  InvalidOpenTypeException
     * @throws  KeyAlreadyExistsException
     */
    private List<?> checkValueAndIndex(CompositeData value) {

	// Check value is valid
	//
	checkValueType(value);

	// Calculate value's index according to this instance's tabularType
	// and check it is not already used for a mapping in the parent HashMap
	//
	List<?> index = internalCalculateIndex(value);
	
	if (dataMap.containsKey(index)) {
	    throw new KeyAlreadyExistsException("Argument value's index, calculated according to this TabularData "+
						"instance's tabularType, already refers to a value in this table.");
	}
	
	// The check is OK, so return the index
	//
	return index;
    }

    /**
     * Deserializes a {@link TabularDataSupport} from an {@link ObjectInputStream}.
     */
    private void readObject(ObjectInputStream in)
	    throws IOException, ClassNotFoundException {
      in.defaultReadObject();
      List<String> tmpNames = tabularType.getIndexNames();
      indexNamesArray = tmpNames.toArray(new String[tmpNames.size()]);
    }
}

Generated By: JavaOnTracks Doclet 0.1.4     ©Thibaut Colar