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 */ CompositeType(String name, String desc, String[] names, String[] descs, OpenType<?>[] types)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 */ containsKey(String name)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 */ equals(Object obj)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 */ getDescription(String name)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 */ getType(String name)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 */ hashCode()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 */ isValue(Object obj)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 */ keySet()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 */ toString()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 } 321