Frames | No Frames |
1: /* CompositeType.java -- Type descriptor for CompositeData instances. 2: Copyright (C) 2006 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.util.Collections; 41: import java.util.Iterator; 42: import java.util.Map; 43: import java.util.Set; 44: import java.util.TreeMap; 45: 46: /** 47: * The open type descriptor for instances of the 48: * {@link CompositeData} class. 49: * 50: * @author Andrew John Hughes (gnu_andrew@member.fsf.org) 51: * @since 1.5 52: */ 53: public class CompositeType 54: extends OpenType 55: { 56: 57: /** 58: * Compatible with JDK 1.5 59: */ 60: private static final long serialVersionUID = -5366242454346948798L; 61: 62: /** 63: * A map of item names to their descriptions. 64: */ 65: private TreeMap nameToDescription; 66: 67: /** 68: * A map of item names to their types. 69: */ 70: private TreeMap nameToType; 71: 72: /** 73: * The hash code of this instance. 74: */ 75: private transient Integer hashCode; 76: 77: /** 78: * The <code>toString()</code> result of this instance. 79: */ 80: private transient String string; 81: 82: /** 83: * <p> 84: * Constructs a new {@link CompositeType} instance for the given 85: * type name with the specified field names, descriptions and types. 86: * All parameters, and the elements of the array parameters, must be 87: * non-null and {@link java.lang.String} values must be something other 88: * than the empty string. The arrays must be non-empty, and be of 89: * equal size. 90: * </p> 91: * <p> 92: * The result of <code>CompositeData.class.getName()</code> is adopted 93: * as the class name (see {@link OpenType}) and changes to the array 94: * elements following construction of the {@link CompositeType} instance 95: * will <strong>not</strong> affect the values used by the instance. 96: * The field names are sorted in to ascending alphanumeric order internally, 97: * and so ordering can not be used to differentiate between two instances. 98: * </p> 99: * 100: * @param name the name of this composite type. 101: * @param desc a description of this composite type. 102: * @param names the names of each field within the composite type. 103: * @param descs the descriptions of each field within the composite type. 104: * @param types the types of each field within the composite type. 105: * @throws IllegalArgumentException if any validity constraint listed above 106: * is broken. 107: * @throws OpenDataException if duplicate item names are provided. Item names 108: * are case-sensitive, but whitespace is removed 109: * before comparison. 110: */ 111: public CompositeType(String name, String desc, String[] names, 112: String[] descs, OpenType[] types) 113: throws OpenDataException 114: { 115: super(CompositeData.class.getName(), name, desc); 116: if (names.length == 0 117: || names.length != descs.length 118: || names.length != types.length) 119: throw new IllegalArgumentException("Arrays must be non-empty " + 120: "and of equal size."); 121: nameToDescription = new TreeMap(); 122: for (int a = 0; a < names.length; ++a) 123: { 124: if (names[a] == null) 125: throw new IllegalArgumentException("Name " + a + " is null."); 126: if (descs[a] == null) 127: throw new IllegalArgumentException("Description " + a + 128: " is null."); 129: String fieldName = names[a].trim(); 130: if (fieldName.length() == 0) 131: throw new IllegalArgumentException("Name " + a + " is " + 132: "the empty string."); 133: if (descs[a].length() == 0) 134: throw new IllegalArgumentException("Description " + a + " is " + 135: "the empty string."); 136: if (nameToDescription.containsKey(fieldName)) 137: throw new OpenDataException(fieldName + " appears more " + 138: "than once."); 139: nameToDescription.put(fieldName, descs[a]); 140: } 141: nameToType = new TreeMap(); 142: for (int a = 0; a < names.length; ++a) 143: nameToType.put(names[a].trim(), types[a]); 144: } 145: 146: /** 147: * Returns true if this composite data type has a field 148: * with the given name. 149: * 150: * @param name the name of the field to check for. 151: * @return true if a field of that name exists. 152: */ 153: public boolean containsKey(String name) 154: { 155: return nameToDescription.containsKey(name); 156: } 157: 158: /** 159: * <p> 160: * Compares this composite data type with another object 161: * for equality. The objects are judged to be equal if: 162: * </p> 163: * <ul> 164: * <li><code>obj</code> is not null.</li> 165: * <li><code>obj</code> is an instance of 166: * {@link CompositeType}.</li> 167: * <li>The type names are equal.</li> 168: * <li>The fields and their types match.</li> 169: * </ul> 170: * 171: * @param obj the object to compare with. 172: * @return true if the conditions above hold. 173: */ 174: public boolean equals(Object obj) 175: { 176: if (!(obj instanceof CompositeType)) 177: return false; 178: CompositeType ctype = (CompositeType) obj; 179: if (!(ctype.getTypeName().equals(getTypeName()))) 180: return false; 181: Set keys = keySet(); 182: if (!(ctype.keySet().equals(keys))) 183: return false; 184: Iterator it = keys.iterator(); 185: while (it.hasNext()) 186: { 187: String key = (String) it.next(); 188: if (!(ctype.getType(key).equals(getType(key)))) 189: return false; 190: } 191: return true; 192: } 193: 194: /** 195: * Returns the description for the given field name, 196: * or <code>null</code> if the field name does not 197: * exist within this composite data type. 198: * 199: * @param name the name of the field whose description 200: * should be returned. 201: * @return the description, or <code>null</code> if the 202: * field doesn't exist. 203: */ 204: public String getDescription(String name) 205: { 206: return (String) nameToDescription.get(name); 207: } 208: 209: /** 210: * Returns the type for the given field name, 211: * or <code>null</code> if the field name does not 212: * exist within this composite data type. 213: * 214: * @param name the name of the field whose type 215: * should be returned. 216: * @return the type, or <code>null</code> if the 217: * field doesn't exist. 218: */ 219: public OpenType getType(String name) 220: { 221: return (OpenType) nameToType.get(name); 222: } 223: 224: /** 225: * <p> 226: * Returns the hash code of the composite data type. 227: * This is computed as the sum of the hash codes of 228: * each field name and its type, together with the hash 229: * code of the type name. These are the same elements 230: * of the type that are compared as part of the 231: * {@link #equals(java.lang.Object)} method, thus ensuring 232: * that the hashcode is compatible with the equality 233: * test. 234: * </p> 235: * <p> 236: * As instances of this class are immutable, the hash code 237: * is computed just once for each instance and reused 238: * throughout its life. 239: * </p> 240: * 241: * @return the hash code of this instance. 242: */ 243: public int hashCode() 244: { 245: if (hashCode == null) 246: { 247: int elementTotal = 0; 248: Iterator it = nameToType.entrySet().iterator(); 249: while (it.hasNext()) 250: { 251: Map.Entry entry = (Map.Entry) it.next(); 252: elementTotal += (entry.getKey().hashCode() + 253: entry.getValue().hashCode()); 254: } 255: hashCode = Integer.valueOf(elementTotal 256: + getTypeName().hashCode()); 257: } 258: return hashCode.intValue(); 259: } 260: 261: /** 262: * Returns true if the specified object is a member of this 263: * composite type. The object is judged to be so if it is 264: * an instance of {@link CompositeData} with an equivalent 265: * type, according to the definition of 266: * {@link #equals(java.lang.Object)} for {@link CompositeType}. 267: * 268: * @param obj the object to test for membership. 269: * @return true if the object is a member of this type. 270: */ 271: public boolean isValue(Object obj) 272: { 273: if (obj instanceof CompositeData) 274: { 275: CompositeData data = (CompositeData) obj; 276: return equals(data.getCompositeType()); 277: } 278: return false; 279: } 280: 281: /** 282: * Returns an unmodifiable {@link java.util.Set}-based 283: * view of the field names that form part of this 284: * {@link CompositeType} instance. The names are stored 285: * in ascending alphanumeric order. 286: * 287: * @return a unmodifiable set containing the field 288: * name {@link java.lang.String}s. 289: */ 290: public Set keySet() 291: { 292: return Collections.unmodifiableSet(nameToDescription.keySet()); 293: } 294: 295: /** 296: * <p> 297: * Returns a textual representation of this instance. This 298: * is constructed using the class name 299: * (<code>javax.management.openmbean.CompositeType</code>) 300: * and each element of the instance which is relevant to 301: * the definition of {@link equals(java.lang.Object)} and 302: * {@link hashCode()} (i.e. the type name, and the name 303: * and type of each field). 304: * </p> 305: * <p> 306: * As instances of this class are immutable, the return value 307: * is computed just once for each instance and reused 308: * throughout its life. 309: * </p> 310: * 311: * @return a @link{java.lang.String} instance representing 312: * the instance in textual form. 313: */ 314: public String toString() 315: { 316: if (string == null) 317: string = getClass().getName() 318: + "[name=" + getTypeName() 319: + ", fields=" + nameToType 320: + "]"; 321: return string; 322: } 323: 324: }