Frames | No Frames |
1: /* CompositeType.java -- Type descriptor for CompositeData instances. 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.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<CompositeData> 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<String,String> nameToDescription; 66: 67: /** 68: * A map of item names to their types. 69: */ 70: private TreeMap<String,OpenType<?>> 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<String,String>(); 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<String,OpenType<?>>(); 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<String> keys = keySet(); 182: if (!(ctype.keySet().equals(keys))) 183: return false; 184: for (String key : keys) 185: { 186: if (!(ctype.getType(key).equals(getType(key)))) 187: return false; 188: } 189: return true; 190: } 191: 192: /** 193: * Returns the description for the given field name, 194: * or <code>null</code> if the field name does not 195: * exist within this composite data type. 196: * 197: * @param name the name of the field whose description 198: * should be returned. 199: * @return the description, or <code>null</code> if the 200: * field doesn't exist. 201: */ 202: public String getDescription(String name) 203: { 204: return nameToDescription.get(name); 205: } 206: 207: /** 208: * Returns the type for the given field name, 209: * or <code>null</code> if the field name does not 210: * exist within this composite data type. 211: * 212: * @param name the name of the field whose type 213: * should be returned. 214: * @return the type, or <code>null</code> if the 215: * field doesn't exist. 216: */ 217: public OpenType<?> getType(String name) 218: { 219: return nameToType.get(name); 220: } 221: 222: /** 223: * <p> 224: * Returns the hash code of the composite data type. 225: * This is computed as the sum of the hash codes of 226: * each field name and its type, together with the hash 227: * code of the type name. These are the same elements 228: * of the type that are compared as part of the 229: * {@link #equals(java.lang.Object)} method, thus ensuring 230: * that the hashcode is compatible with the equality 231: * test. 232: * </p> 233: * <p> 234: * As instances of this class are immutable, the hash code 235: * is computed just once for each instance and reused 236: * throughout its life. 237: * </p> 238: * 239: * @return the hash code of this instance. 240: */ 241: public int hashCode() 242: { 243: if (hashCode == null) 244: { 245: int elementTotal = 0; 246: for (Map.Entry<String,OpenType<?>> entry : nameToType.entrySet()) 247: { 248: elementTotal += (entry.getKey().hashCode() + 249: entry.getValue().hashCode()); 250: } 251: hashCode = Integer.valueOf(elementTotal 252: + getTypeName().hashCode()); 253: } 254: return hashCode.intValue(); 255: } 256: 257: /** 258: * Returns true if the specified object is a member of this 259: * composite type. The object is judged to be so if it is 260: * an instance of {@link CompositeData} with an equivalent 261: * type, according to the definition of 262: * {@link #equals(java.lang.Object)} for {@link CompositeType}. 263: * 264: * @param obj the object to test for membership. 265: * @return true if the object is a member of this type. 266: */ 267: public boolean isValue(Object obj) 268: { 269: if (obj instanceof CompositeData) 270: { 271: CompositeData data = (CompositeData) obj; 272: return equals(data.getCompositeType()); 273: } 274: return false; 275: } 276: 277: /** 278: * Returns an unmodifiable {@link java.util.Set}-based 279: * view of the field names that form part of this 280: * {@link CompositeType} instance. The names are stored 281: * in ascending alphanumeric order. 282: * 283: * @return a unmodifiable set containing the field 284: * name {@link java.lang.String}s. 285: */ 286: public Set<String> keySet() 287: { 288: return Collections.unmodifiableSet(nameToDescription.keySet()); 289: } 290: 291: /** 292: * <p> 293: * Returns a textual representation of this instance. This 294: * is constructed using the class name 295: * (<code>javax.management.openmbean.CompositeType</code>) 296: * and each element of the instance which is relevant to 297: * the definition of {@link equals(java.lang.Object)} and 298: * {@link hashCode()} (i.e. the type name, and the name 299: * and type of each field). 300: * </p> 301: * <p> 302: * As instances of this class are immutable, the return value 303: * is computed just once for each instance and reused 304: * throughout its life. 305: * </p> 306: * 307: * @return a @link{java.lang.String} instance representing 308: * the instance in textual form. 309: */ 310: public String toString() 311: { 312: if (string == null) 313: string = getClass().getName() 314: + "[name=" + getTypeName() 315: + ", fields=" + nameToType 316: + "]"; 317: return string; 318: } 319: 320: }