summaryrefslogtreecommitdiff
path: root/javax/management/openmbean/CompositeDataSupport.java
blob: 5d5adb727f64d27b3ccddce58f292f0ed6e711c3 (plain)
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
/* CompositeData.java -- A composite data structure implementation.
   Copyright (C) 2006 Free Software Foundation, Inc.

This file is part of GNU Classpath.

GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING.  If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.

Linking this library statically or dynamically with other modules is
making a combined work based on this library.  Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.

As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module.  An independent module is a module which is not derived from
or based on this library.  If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so.  If you do not wish to do so, delete this
exception statement from your version. */

package javax.management.openmbean;

import java.io.Serializable;

import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

/**
 * Provides an implementation of the {@link CompositeData}
 * interface.
 *
 * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
 * @since 1.5
 */
public class CompositeDataSupport
  implements CompositeData, Serializable
{

  /**
   * Compatible with JDK 1.5
   */
  private static final long serialVersionUID = 8003518976613702244L;

  /**
   * Mapping of field names to values.
   *
   * @serial the map of field names to values.
   */
  private SortedMap contents;

  /**
   * The composite type which represents this composite data instance.
   *
   * @serial the type information for this instance.
   */
  private CompositeType compositeType;

  /**
   * Constructs a new {@link CompositeDataSupport} instance with the
   * specified type using field names and values from the supplied map.
   * The keys of the map become the field names, while the values
   * become the values of each respective field.  This constructor simply
   * calls the other constructor, with the two arrays formed using the
   * keys and values of this map, respectively.  Thus, the input parameters
   * given should conform to the same requirements given there (i.e. no
   * null values or empty strings).
   *
   * @param type the composite type of this composite data structure.
   * @param items a mapping of field names to values.  This should match
   *              the mappings given by the type (i.e. for each mapping
   *              in the type, there should be a corresponding field name
   *              with a value of the correct type).
   * @throws IllegalArgumentException if the type, the map or any of the keys
   *                                  or values in the map are <code>null</code>,
   *                                  or if any key from the map is an empty
   *                                  string.
   * @throws OpenDataException if a mismatch occurs between the map and the
   *                           field name/type specification given by the
   *                           {@link CompositeType} instance.  This may be
   *                           due to the two having a different size, a
   *                           mismatch between keys or an incorrectly typed
   *                           value.
   * @throws ArrayStoreException if one of the keys is not a
   *                             {@link java.lang.String} (thus calling a failure
   *                             in converting the keys to an array of strings).
   */
  public CompositeDataSupport(CompositeType type, Map items)
    throws OpenDataException
  {
    this(type, 
	 (String[]) items.keySet().toArray(new String[items.size()]),
	 items.values().toArray());
  }

  /**
   * Constructs a new {@link CompositeDataSupport} instance with the
   * specified type using the supplied arrays of field names and
   * values.  Neither the type, the two arrays or any elements of the
   * arrays may be <code>null</code>.  The {@link java.lang.String}s
   * within the <code>names</code> array must be non-empty.  The
   * arrays must match in size and order, as each element of the
   * <code>names</code> array is matched against the corresponding
   * value in the <code>values</code> array.  Internally, the two are
   * stored in a map, lexographically ordered using the field names.
   * The data given should also conform to the description of the
   * instance given by the {@link CompositeType} instance supplied.
   *
   * @param type the composite type of this composite data structure.
   * @param names the field names.
   * @param values the corresponding values of the fields.
   * @throws IllegalArgumentException if the type, the arrays or any of the keys
   *                                  or values in the arrays are <code>null</code>,
   *                                  or if any key from <code>names</code> is
   *                                  an empty string.  This also occurs if the
   *                                  arrays differ in length.
   * @throws OpenDataException if a mismatch occurs between the arrays and the
   *                           field name/type specification given by the
   *                           {@link CompositeType} instance.  This may be
   *                           due to a differing number of field names, a
   *                           mismatch between names or an incorrectly typed
   *                           value.
   */
  public CompositeDataSupport(CompositeType type, String[] names, Object[] values)
    throws OpenDataException
  {
    if (type == null)
      throw new IllegalArgumentException("The given composite type is null.");
    compositeType = type;
    if (names == null)
      throw new IllegalArgumentException("The names array is null.");
    if (values == null)
      throw new IllegalArgumentException("The values array is null.");
    if (names.length != values.length)
      throw new IllegalArgumentException("The sizes of the arrays differ.");
    Set typeKeys = type.keySet();
    if (typeKeys.size() != names.length)
      throw new OpenDataException("The number of field names does not match " +
				  "the type description.");
    contents = new TreeMap();
    for (int a = 0; a < names.length; ++a)
      {
	if (names[a] == null)
	  throw new IllegalArgumentException("Element " + a + " of the names " +
					     "array is null.");
	if (names[a].length() == 0)
	  throw new IllegalArgumentException("Element " + a + " of the names " +
					     "array is an empty string.");
	if (values[a] == null)
	  throw new IllegalArgumentException("Element " + a + " of the values " +
					     "array is null.");
	if (!(typeKeys.contains(names[a])))
	  throw new OpenDataException("The name, " + names[a] + ", is not a " +
				      "field in the given type description.");
	if (!(type.getType(names[a]).isValue(values[a])))
	  throw new OpenDataException("The value, " + values[a] + ", is not a " +
				      "valid value for the " + names[a] + " field.");
	contents.put(names[a], values[a]);
      }
  }

  /**
   * Returns true if this {@link CompositeData} instance contains
   * the specified key.  This method always returns false for
   * an input key equal to <code>null</code> or the empty string.
   *
   * @param key the key to find in the structure.
   * @return true if the key exists.
   */
  public boolean containsKey(String key)
  {
    if (key == null || key.length() == 0)
      return false;
    else
      return contents.containsKey(key);
  }

  /**
   * Returns true if this {@link CompositeData} instance has
   * a value equal to that supplied.
   *
   * @param value the value to look for.
   * @return true if the value exists.
   */
  public boolean containsValue(Object value)
  {
    return contents.containsValue(value);
  }


  /**
   * Compares the specified object with this object for equality.
   * The object is judged equivalent if it is non-null, and also
   * an instance of {@link CompositeData} with the same name-value
   * mappings and types.  The two compared instances may be
   * equivalent even if they represent different implementations of
   * {@link CompositeData}.
   *
   * @param obj the object to compare for equality.
   * @return true if <code>obj</code> is equal to <code>this</code>.
   */
  public boolean equals(Object obj)
  {
    if (!(obj instanceof CompositeData))
      return false;
    CompositeData data = (CompositeData) obj;
    if (!(data.getCompositeType().equals(compositeType)))
      return false;
    Iterator it = contents.keySet().iterator();
    while (it.hasNext())
      {
	String key = (String) it.next();
	if (!(data.containsKey(key)))
	  return false;
	if (!(data.get(key).equals(contents.get(key))))
	  return false;
      }
    return true;
  }

  /**
   * Retrieves the value for the specified key.
   *
   * @param key the key whose value should be returned.
   * @return the matching value.
   * @throws IllegalArgumentException if the key is <code>null</code>
   *                                  or the empty string.
   * @throws InvalidKeyException if the key does not exist.
   */
  public Object get(String key)
  {
    if (key == null)
      throw new IllegalArgumentException("The supplied key is null.");
    if (key.length() == 0)
      throw new IllegalArgumentException("The supplied key is the empty string.");
    if (!(contents.containsKey(key)))
      throw new InvalidKeyException("The supplied key does not exist.");
    return contents.get(key);
  }

  /**
   * Returns the appropriate value for each key in the given array,
   * using the same ordering.
   *
   * @param keys the keys whose values should be returned.
   * @return the matching values.
   * @throws IllegalArgumentException if one of the keys is
   *                                  <code>null</code> or the
   *                                  empty string.
   * @throws InvalidKeyException if one of the keys does not exist.
   */
  public Object[] getAll(String[] keys)
  {
    Object[] values = new Object[keys.length];
    for (int a = 0; a < keys.length; ++a)
      values[a] = get(keys[a]);
    return values;
  }


  /**
   * Returns the composite type which corresponds to this instance
   * of {@link CompositeData}.
   *
   * @return the composite type for this instance.
   */
  public CompositeType getCompositeType()
  {
    return compositeType;
  }

  /**
   * Returns the hash code of this instance.  The hash code is
   * computed as the sum of the hash codes of all the values plus
   * the hash code of the composite type.  As equality comparisons
   * take place using this same information, this should ensure that
   * the property, <code>e1.equals(e2)</code> implies
   * <code>e1.hashCode() == e2.hashCode(), holds for any pair
   * of instances, <code>e1</code> and <code>e2</code>. However,
   * this relies on the other instance implementing the
   * <code>hashCode</code> method correctly, if it is not an
   * instance of {@link CompositeDataSupport}.
   *
   * @return the hash code of this {@link CompositeData}.
   * @see Object#equals(Object)
   */
  public int hashCode()
  {
    int code = compositeType.hashCode();
    Iterator it = values().iterator();
    while (it.hasNext())
      code += it.next().hashCode();
    return code;
  }


  /**
   * Returns a textual representation of this instance.  The
   * exact format is left up to the implementation, but it
   * should contain the name of the implementing class,
   * the name of the type and a mapping of the form
   * <code>key=value</code> for each pair of key and value.
   *
   * @return a {@link java.lang.String} representation of the
   *         object.
   */
  public String toString()
  {
    return getClass().getName() +
      "[compositeType=" + compositeType +
      ",contents=" + contents +
      "]";
  }

  /**
   * Returns a read-only collection of the values associated with
   * this instance.  The values are sorted using the lexicographic
   * ordering of the corresponding keys.
   *
   * @return the values of this instance.
   */
  public Collection values()
  {
    return Collections.unmodifiableCollection(contents.values());
  }

}