1 7 8 package javax.management; 9 10 import java.io.InvalidObjectException ; 11 import java.lang.reflect.Array ; 12 import java.util.Arrays ; 13 import java.util.Comparator ; 14 import java.util.Map ; 15 import java.util.SortedMap ; 16 import java.util.TreeMap ; 17 18 22 public class ImmutableDescriptor implements Descriptor { 23 private static final long serialVersionUID = 8853308591080540165L; 24 25 30 private final String [] names; 31 36 private final Object [] values; 37 38 private transient int hashCode = -1; 39 40 43 public static final ImmutableDescriptor EMPTY_DESCRIPTOR = 44 new ImmutableDescriptor (); 45 46 54 public ImmutableDescriptor(String [] fieldNames, Object [] fieldValues) { 55 this(makeMap(fieldNames, fieldValues)); 56 } 57 58 70 public ImmutableDescriptor(String ... fields) { 71 this(makeMap(fields)); 72 } 73 74 83 public ImmutableDescriptor(Map <String , ?> fields) { 84 if (fields == null) 85 throw new IllegalArgumentException ("Null Map"); 86 SortedMap <String , Object > map = 87 new TreeMap <String , Object >(String.CASE_INSENSITIVE_ORDER); 88 for (Map.Entry <String , ?> entry : fields.entrySet()) { 89 String name = entry.getKey(); 90 if (name == null || name.equals("")) 91 throw new IllegalArgumentException ("Empty or null field name"); 92 if (map.containsKey(name)) 93 throw new IllegalArgumentException ("Duplicate name: " + name); 94 map.put(name, entry.getValue()); 95 } 96 int size = map.size(); 97 this.names = map.keySet().toArray(new String [size]); 98 this.values = map.values().toArray(new Object [size]); 99 } 100 101 111 private Object readResolve() throws InvalidObjectException { 112 if (names.length == 0 && getClass() == ImmutableDescriptor .class) 113 return EMPTY_DESCRIPTOR; 114 115 boolean bad = false; 116 if (names == null || values == null || names.length != values.length) 117 bad = true; 118 if (!bad) { 119 final Comparator <String > compare = String.CASE_INSENSITIVE_ORDER; 120 String lastName = ""; for (int i = 0; i < names.length; i++) { 122 if (names[i] == null || 123 compare.compare(lastName, names[i]) >= 0) { 124 bad = true; 125 break; 126 } 127 lastName = names[i]; 128 } 129 } 130 if (bad) 131 throw new InvalidObjectException ("Bad names or values"); 132 133 return this; 134 } 135 136 private static SortedMap <String , ?> makeMap(String [] fieldNames, 137 Object [] fieldValues) { 138 if (fieldNames == null || fieldValues == null) 139 throw new IllegalArgumentException ("Null array parameter"); 140 if (fieldNames.length != fieldValues.length) 141 throw new IllegalArgumentException ("Different size arrays"); 142 SortedMap <String , Object > map = 143 new TreeMap <String , Object >(String.CASE_INSENSITIVE_ORDER); 144 for (int i = 0; i < fieldNames.length; i++) { 145 String name = fieldNames[i]; 146 if (name == null || name.equals("")) 147 throw new IllegalArgumentException ("Empty or null field name"); 148 Object old = map.put(name, fieldValues[i]); 149 if (old != null) { 150 throw new IllegalArgumentException ("Duplicate field name: " + 151 name); 152 } 153 } 154 return map; 155 } 156 157 private static SortedMap <String , ?> makeMap(String [] fields) { 158 if (fields == null) 159 throw new IllegalArgumentException ("Null fields parameter"); 160 String [] fieldNames = new String [fields.length]; 161 String [] fieldValues = new String [fields.length]; 162 for (int i = 0; i < fields.length; i++) { 163 String field = fields[i]; 164 int eq = field.indexOf('='); 165 if (eq < 0) { 166 throw new IllegalArgumentException ("Missing = character: " + 167 field); 168 } 169 fieldNames[i] = field.substring(0, eq); 170 fieldValues[i] = field.substring(eq + 1); 172 } 173 return makeMap(fieldNames, fieldValues); 174 } 175 176 207 public static ImmutableDescriptor union(Descriptor ... descriptors) { 208 int index = findNonEmpty(descriptors, 0); 211 if (index < 0) 212 return EMPTY_DESCRIPTOR; 213 if (descriptors[index] instanceof ImmutableDescriptor 214 && findNonEmpty(descriptors, index + 1) < 0) 215 return (ImmutableDescriptor ) descriptors[index]; 216 217 Map <String , Object > map = 218 new TreeMap <String , Object >(String.CASE_INSENSITIVE_ORDER); 219 ImmutableDescriptor biggestImmutable = EMPTY_DESCRIPTOR; 220 for (Descriptor d : descriptors) { 221 if (d != null) { 222 String [] names; 223 if (d instanceof ImmutableDescriptor ) { 224 ImmutableDescriptor id = (ImmutableDescriptor ) d; 225 names = id.names; 226 if (id.getClass() == ImmutableDescriptor .class 227 && names.length > biggestImmutable.names.length) 228 biggestImmutable = id; 229 } else 230 names = d.getFieldNames(); 231 for (String n : names) { 232 Object v = d.getFieldValue(n); 233 Object old = map.put(n, v); 234 if (old != null) { 235 boolean equal; 236 if (old.getClass().isArray()) { 237 equal = Arrays.deepEquals(new Object [] {old}, 238 new Object [] {v}); 239 } else 240 equal = old.equals(v); 241 if (!equal) { 242 final String msg = 243 "Inconsistent values for descriptor field " + 244 n + ": " + old + " :: " + v; 245 throw new IllegalArgumentException (msg); 246 } 247 } 248 } 249 } 250 } 251 if (biggestImmutable.names.length == map.size()) 252 return biggestImmutable; 253 return new ImmutableDescriptor (map); 254 } 255 256 private static boolean isEmpty(Descriptor d) { 257 if (d == null) 258 return true; 259 else if (d instanceof ImmutableDescriptor ) 260 return ((ImmutableDescriptor ) d).names.length == 0; 261 else 262 return (d.getFieldNames().length == 0); 263 } 264 265 private static int findNonEmpty(Descriptor [] ds, int start) { 266 for (int i = start; i < ds.length; i++) { 267 if (!isEmpty(ds[i])) 268 return i; 269 } 270 return -1; 271 } 272 273 private int fieldIndex(String name) { 274 return Arrays.binarySearch(names, name, String.CASE_INSENSITIVE_ORDER); 275 } 276 277 public final Object getFieldValue(String fieldName) { 278 checkIllegalFieldName(fieldName); 279 int i = fieldIndex(fieldName); 280 if (i < 0) 281 return null; 282 Object v = values[i]; 283 if (v == null || !v.getClass().isArray()) 284 return v; 285 if (v instanceof Object []) 286 return ((Object []) v).clone(); 287 int len = Array.getLength(v); 289 Object a = Array.newInstance(v.getClass().getComponentType(), len); 290 System.arraycopy(v, 0, a, 0, len); 291 return a; 292 } 293 294 public final String [] getFields() { 295 String [] result = new String [names.length]; 296 for (int i = 0; i < result.length; i++) { 297 Object value = values[i]; 298 if (value == null) 299 value = ""; 300 else if (!(value instanceof String )) 301 value = "(" + value + ")"; 302 result[i] = names[i] + "=" + value; 303 } 304 return result; 305 } 306 307 public final Object [] getFieldValues(String ... fieldNames) { 308 if (fieldNames == null) 309 return values.clone(); 310 Object [] result = new Object [fieldNames.length]; 311 for (int i = 0; i < fieldNames.length; i++) { 312 String name = fieldNames[i]; 313 if (name != null && !name.equals("")) 314 result[i] = getFieldValue(name); 315 } 316 return result; 317 } 318 319 public final String [] getFieldNames() { 320 return names.clone(); 321 } 322 323 345 public boolean equals(Object o) { 348 if (o == this) 349 return true; 350 if (!(o instanceof Descriptor )) 351 return false; 352 String [] onames; 353 if (o instanceof ImmutableDescriptor ) { 354 onames = ((ImmutableDescriptor ) o).names; 355 } else { 356 onames = ((Descriptor ) o).getFieldNames(); 357 Arrays.sort(onames, String.CASE_INSENSITIVE_ORDER); 358 } 359 if (names.length != onames.length) 360 return false; 361 for (int i = 0; i < names.length; i++) { 362 if (!names[i].equalsIgnoreCase(onames[i])) 363 return false; 364 } 365 Object [] ovalues; 366 if (o instanceof ImmutableDescriptor ) 367 ovalues = ((ImmutableDescriptor ) o).values; 368 else 369 ovalues = ((Descriptor ) o).getFieldValues(onames); 370 return Arrays.deepEquals(values, ovalues); 371 } 372 373 393 public int hashCode() { 396 if (hashCode == -1) { 397 int hash = 0; 398 for (int i = 0; i < names.length; i++) { 399 Object v = values[i]; 400 int h; 401 if (v == null) 402 h = 0; 403 else if (v instanceof Object []) 404 h = Arrays.deepHashCode((Object []) v); 405 else if (v.getClass().isArray()) { 406 h = Arrays.deepHashCode(new Object [] {v}) - 31; 407 } else 410 h = v.hashCode(); 411 hash += names[i].toLowerCase().hashCode() ^ h; 412 } 413 hashCode = hash; 414 } 415 return hashCode; 416 } 417 418 public String toString() { 419 StringBuilder sb = new StringBuilder ("{"); 420 for (int i = 0; i < names.length; i++) { 421 if (i > 0) 422 sb.append(", "); 423 sb.append(names[i]).append("="); 424 Object v = values[i]; 425 if (v != null && v.getClass().isArray()) { 426 String s = Arrays.deepToString(new Object [] {v}); 427 s = s.substring(1, s.length() - 1); v = s; 429 } 430 sb.append(String.valueOf(v)); 431 } 432 return sb.append("}").toString(); 433 } 434 435 446 public boolean isValid() { 447 return true; 448 } 449 450 464 public Descriptor clone() { 465 return this; 466 } 467 468 477 public final void setFields(String [] fieldNames, Object [] fieldValues) 478 throws RuntimeOperationsException { 479 if (fieldNames == null || fieldValues == null) 480 illegal("Null argument"); 481 if (fieldNames.length != fieldValues.length) 482 illegal("Different array sizes"); 483 for (int i = 0; i < fieldNames.length; i++) 484 checkIllegalFieldName(fieldNames[i]); 485 for (int i = 0; i < fieldNames.length; i++) 486 setField(fieldNames[i], fieldValues[i]); 487 } 488 489 498 public final void setField(String fieldName, Object fieldValue) 499 throws RuntimeOperationsException { 500 checkIllegalFieldName(fieldName); 501 int i = fieldIndex(fieldName); 502 if (i < 0) 503 unsupported(); 504 Object value = values[i]; 505 if ((value == null) ? 506 (fieldValue != null) : 507 !value.equals(fieldValue)) 508 unsupported(); 509 } 510 511 522 public final void removeField(String fieldName) { 523 if (fieldName != null && fieldIndex(fieldName) >= 0) 524 unsupported(); 525 } 526 527 static Descriptor nonNullDescriptor(Descriptor d) { 528 if (d == null) 529 return EMPTY_DESCRIPTOR; 530 else 531 return d; 532 } 533 534 private static void checkIllegalFieldName(String name) { 535 if (name == null || name.equals("")) 536 illegal("Null or empty field name"); 537 } 538 539 private static void unsupported() { 540 UnsupportedOperationException uoe = 541 new UnsupportedOperationException ("Descriptor is read-only"); 542 throw new RuntimeOperationsException (uoe); 543 } 544 545 private static void illegal(String message) { 546 IllegalArgumentException iae = new IllegalArgumentException (message); 547 throw new RuntimeOperationsException (iae); 548 } 549 } 550 | Popular Tags |