Frames | No Frames |
1: /* CompositeData.java -- A composite data structure implementation. 2: Copyright (C) 2006, 2007 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: package javax.management.openmbean; 39: 40: import java.io.Serializable; 41: 42: import java.util.Collection; 43: import java.util.Collections; 44: import java.util.Iterator; 45: import java.util.Map; 46: import java.util.Set; 47: import java.util.SortedMap; 48: import java.util.TreeMap; 49: 50: /** 51: * Provides an implementation of the {@link CompositeData} 52: * interface. 53: * 54: * @author Andrew John Hughes (gnu_andrew@member.fsf.org) 55: * @since 1.5 56: */ 57: public class CompositeDataSupport 58: implements CompositeData, Serializable 59: { 60: 61: /** 62: * Compatible with JDK 1.5 63: */ 64: private static final long serialVersionUID = 8003518976613702244L; 65: 66: /** 67: * Mapping of field names to values. 68: * 69: * @serial the map of field names to values. 70: */ 71: private SortedMap<String, Object> contents; 72: 73: /** 74: * The composite type which represents this composite data instance. 75: * 76: * @serial the type information for this instance. 77: */ 78: private CompositeType compositeType; 79: 80: /** 81: * Constructs a new {@link CompositeDataSupport} instance with the 82: * specified type using field names and values from the supplied map. 83: * The keys of the map become the field names, while the values 84: * become the values of each respective field. This constructor simply 85: * calls the other constructor, with the two arrays formed using the 86: * keys and values of this map, respectively. Thus, the input parameters 87: * given should conform to the same requirements given there (i.e. no 88: * null values or empty strings). 89: * 90: * @param type the composite type of this composite data structure. 91: * @param items a mapping of field names to values. This should match 92: * the mappings given by the type (i.e. for each mapping 93: * in the type, there should be a corresponding field name 94: * with a value of the correct type). 95: * @throws IllegalArgumentException if the type, the map or any of the keys 96: * or values in the map are <code>null</code>, 97: * or if any key from the map is an empty 98: * string. 99: * @throws OpenDataException if a mismatch occurs between the map and the 100: * field name/type specification given by the 101: * {@link CompositeType} instance. This may be 102: * due to the two having a different size, a 103: * mismatch between keys or an incorrectly typed 104: * value. 105: * @throws ArrayStoreException if one of the keys is not a 106: * {@link java.lang.String} (thus calling a failure 107: * in converting the keys to an array of strings). 108: */ 109: public CompositeDataSupport(CompositeType type, Map<String, ?> items) 110: throws OpenDataException 111: { 112: this(type, 113: items.keySet().toArray(new String[items.size()]), 114: items.values().toArray()); 115: } 116: 117: /** 118: * Constructs a new {@link CompositeDataSupport} instance with the 119: * specified type using the supplied arrays of field names and 120: * values. Neither the type, the two arrays or any elements of the 121: * arrays may be <code>null</code>. The {@link java.lang.String}s 122: * within the <code>names</code> array must be non-empty. The 123: * arrays must match in size and order, as each element of the 124: * <code>names</code> array is matched against the corresponding 125: * value in the <code>values</code> array. Internally, the two are 126: * stored in a map, lexographically ordered using the field names. 127: * The data given should also conform to the description of the 128: * instance given by the {@link CompositeType} instance supplied. 129: * 130: * @param type the composite type of this composite data structure. 131: * @param names the field names. 132: * @param values the corresponding values of the fields. 133: * @throws IllegalArgumentException if the type, the arrays or any of the keys 134: * or values in the arrays are <code>null</code>, 135: * or if any key from <code>names</code> is 136: * an empty string. This also occurs if the 137: * arrays differ in length. 138: * @throws OpenDataException if a mismatch occurs between the arrays and the 139: * field name/type specification given by the 140: * {@link CompositeType} instance. This may be 141: * due to a differing number of field names, a 142: * mismatch between names or an incorrectly typed 143: * value. 144: */ 145: public CompositeDataSupport(CompositeType type, String[] names, Object[] values) 146: throws OpenDataException 147: { 148: if (type == null) 149: throw new IllegalArgumentException("The given composite type is null."); 150: compositeType = type; 151: if (names == null) 152: throw new IllegalArgumentException("The names array is null."); 153: if (values == null) 154: throw new IllegalArgumentException("The values array is null."); 155: if (names.length != values.length) 156: throw new IllegalArgumentException("The sizes of the arrays differ."); 157: Set<String> typeKeys = type.keySet(); 158: if (typeKeys.size() != names.length) 159: throw new OpenDataException("The number of field names does not match " + 160: "the type description."); 161: contents = new TreeMap<String, Object>(); 162: for (int a = 0; a < names.length; ++a) 163: { 164: if (names[a] == null) 165: throw new IllegalArgumentException("Element " + a + " of the names " + 166: "array is null."); 167: if (names[a].length() == 0) 168: throw new IllegalArgumentException("Element " + a + " of the names " + 169: "array is an empty string."); 170: if (values[a] == null) 171: throw new IllegalArgumentException("Element " + a + " of the values " + 172: "array is null."); 173: if (!(typeKeys.contains(names[a]))) 174: throw new OpenDataException("The name, " + names[a] + ", is not a " + 175: "field in the given type description."); 176: if (!(type.getType(names[a]).isValue(values[a]))) 177: throw new OpenDataException("The value, " + values[a] + ", is not a " + 178: "valid value for the " + names[a] + " field."); 179: contents.put(names[a], values[a]); 180: } 181: } 182: 183: /** 184: * Returns true if this {@link CompositeData} instance contains 185: * the specified key. This method always returns false for 186: * an input key equal to <code>null</code> or the empty string. 187: * 188: * @param key the key to find in the structure. 189: * @return true if the key exists. 190: */ 191: public boolean containsKey(String key) 192: { 193: if (key == null || key.length() == 0) 194: return false; 195: else 196: return contents.containsKey(key); 197: } 198: 199: /** 200: * Returns true if this {@link CompositeData} instance has 201: * a value equal to that supplied. 202: * 203: * @param value the value to look for. 204: * @return true if the value exists. 205: */ 206: public boolean containsValue(Object value) 207: { 208: return contents.containsValue(value); 209: } 210: 211: 212: /** 213: * Compares the specified object with this object for equality. 214: * The object is judged equivalent if it is non-null, and also 215: * an instance of {@link CompositeData} with the same name-value 216: * mappings and types. The two compared instances may be 217: * equivalent even if they represent different implementations of 218: * {@link CompositeData}. 219: * 220: * @param obj the object to compare for equality. 221: * @return true if <code>obj</code> is equal to <code>this</code>. 222: */ 223: public boolean equals(Object obj) 224: { 225: if (!(obj instanceof CompositeData)) 226: return false; 227: CompositeData data = (CompositeData) obj; 228: if (!(data.getCompositeType().equals(compositeType))) 229: return false; 230: for (String key : contents.keySet()) 231: { 232: if (!(data.containsKey(key))) 233: return false; 234: if (!(data.get(key).equals(contents.get(key)))) 235: return false; 236: } 237: return true; 238: } 239: 240: /** 241: * Retrieves the value for the specified key. 242: * 243: * @param key the key whose value should be returned. 244: * @return the matching value. 245: * @throws IllegalArgumentException if the key is <code>null</code> 246: * or the empty string. 247: * @throws InvalidKeyException if the key does not exist. 248: */ 249: public Object get(String key) 250: { 251: if (key == null) 252: throw new IllegalArgumentException("The supplied key is null."); 253: if (key.length() == 0) 254: throw new IllegalArgumentException("The supplied key is the empty string."); 255: if (!(contents.containsKey(key))) 256: throw new InvalidKeyException("The supplied key does not exist."); 257: return contents.get(key); 258: } 259: 260: /** 261: * Returns the appropriate value for each key in the given array, 262: * using the same ordering. 263: * 264: * @param keys the keys whose values should be returned. 265: * @return the matching values. 266: * @throws IllegalArgumentException if one of the keys is 267: * <code>null</code> or the 268: * empty string. 269: * @throws InvalidKeyException if one of the keys does not exist. 270: */ 271: public Object[] getAll(String[] keys) 272: { 273: Object[] values = new Object[keys.length]; 274: for (int a = 0; a < keys.length; ++a) 275: values[a] = get(keys[a]); 276: return values; 277: } 278: 279: 280: /** 281: * Returns the composite type which corresponds to this instance 282: * of {@link CompositeData}. 283: * 284: * @return the composite type for this instance. 285: */ 286: public CompositeType getCompositeType() 287: { 288: return compositeType; 289: } 290: 291: /** 292: * Returns the hash code of this instance. The hash code is 293: * computed as the sum of the hash codes of all the values plus 294: * the hash code of the composite type. As equality comparisons 295: * take place using this same information, this should ensure that 296: * the property, <code>e1.equals(e2)</code> implies 297: * <code>e1.hashCode() == e2.hashCode(), holds for any pair 298: * of instances, <code>e1</code> and <code>e2</code>. However, 299: * this relies on the other instance implementing the 300: * <code>hashCode</code> method correctly, if it is not an 301: * instance of {@link CompositeDataSupport}. 302: * 303: * @return the hash code of this {@link CompositeData}. 304: * @see Object#equals(Object) 305: */ 306: public int hashCode() 307: { 308: int code = compositeType.hashCode(); 309: for (Object o : contents.values()) 310: code += o.hashCode(); 311: return code; 312: } 313: 314: 315: /** 316: * Returns a textual representation of this instance. The 317: * exact format is left up to the implementation, but it 318: * should contain the name of the implementing class, 319: * the name of the type and a mapping of the form 320: * <code>key=value</code> for each pair of key and value. 321: * 322: * @return a {@link java.lang.String} representation of the 323: * object. 324: */ 325: public String toString() 326: { 327: return getClass().getName() + 328: "[compositeType=" + compositeType + 329: ",contents=" + contents + 330: "]"; 331: } 332: 333: /** 334: * Returns a read-only collection of the values associated with 335: * this instance. The values are sorted using the lexicographic 336: * ordering of the corresponding keys. 337: * 338: * @return the values of this instance. 339: */ 340: public Collection<?> values() 341: { 342: return Collections.unmodifiableCollection(contents.values()); 343: } 344: 345: }