| 1 7 8 package com.sun.jmx.mbeanserver; 9 10 import static com.sun.jmx.mbeanserver.Util.*; 11 12 import com.sun.jmx.remote.util.EnvHelp; 13 14 import java.beans.ConstructorProperties ; 15 import java.io.InvalidObjectException ; 16 import java.lang.ref.WeakReference ; 17 import java.lang.reflect.Array ; 18 import java.lang.reflect.Constructor ; 19 import java.lang.reflect.Field ; 20 import java.lang.reflect.GenericArrayType ; 21 import java.lang.reflect.Method ; 22 import java.lang.reflect.Modifier ; 23 import java.lang.reflect.ParameterizedType ; 24 import java.lang.reflect.Proxy ; 25 import java.lang.reflect.Type ; 26 import java.util.Arrays ; 27 import java.util.ArrayList ; 28 import java.util.BitSet ; 29 import java.util.Collection ; 30 import java.util.Comparator ; 31 import java.util.HashSet ; 32 import java.util.List ; 33 import java.util.Map ; 34 import java.util.Set ; 35 import java.util.SortedMap ; 36 import java.util.SortedSet ; 37 import java.util.TreeSet ; 38 import java.util.WeakHashMap ; 39 import javax.management.JMX ; 40 import javax.management.ObjectName ; 41 import javax.management.openmbean.ArrayType ; 42 import javax.management.openmbean.CompositeData ; 43 import javax.management.openmbean.CompositeDataInvocationHandler ; 44 import javax.management.openmbean.CompositeDataSupport ; 45 import javax.management.openmbean.CompositeDataView ; 46 import javax.management.openmbean.CompositeType ; 47 import javax.management.openmbean.OpenDataException ; 48 import javax.management.openmbean.OpenType ; 49 import javax.management.openmbean.SimpleType ; 50 import javax.management.openmbean.TabularData ; 51 import javax.management.openmbean.TabularDataSupport ; 52 import javax.management.openmbean.TabularType ; 53 import static javax.management.openmbean.SimpleType .*; 54 55 96 public abstract class OpenConverter { 97 private OpenConverter(Type targetType, OpenType openType, 98 Class openClass) { 99 this.targetType = targetType; 100 this.openType = openType; 101 this.openClass = openClass; 102 } 103 104 105 public final Object fromOpenValue(MXBeanLookup lookup, Object value) 106 throws InvalidObjectException { 107 if (value == null) 108 return null; 109 else 110 return fromNonNullOpenValue(lookup, value); 111 } 112 113 abstract Object fromNonNullOpenValue(MXBeanLookup lookup, Object value) 114 throws InvalidObjectException ; 115 116 118 void checkReconstructible() throws InvalidObjectException { 119 } 121 122 123 final Object toOpenValue(MXBeanLookup lookup, Object value) 124 throws OpenDataException { 125 if (value == null) 126 return null; 127 else 128 return toNonNullOpenValue(lookup, value); 129 } 130 131 abstract Object toNonNullOpenValue(MXBeanLookup lookup, Object value) 132 throws OpenDataException ; 133 134 136 boolean isIdentity() { 137 return false; 138 } 139 140 final Type getTargetType() { 141 return targetType; 142 } 143 144 final OpenType getOpenType() { 145 return openType; 146 } 147 148 151 final Class getOpenClass() { 152 return openClass; 153 } 154 155 private final Type targetType; 156 private final OpenType openType; 157 private final Class openClass; 158 159 private static final class ConverterMap 160 extends WeakHashMap <Type , WeakReference <OpenConverter>> {} 161 162 private static final ConverterMap converterMap = new ConverterMap(); 163 164 166 private static final List <OpenConverter> permanentConverters = newList(); 167 168 private static synchronized OpenConverter getConverter(Type type) { 169 if (type instanceof GenericArrayType ) { 171 Type component = ((GenericArrayType ) type).getGenericComponentType(); 172 if (component instanceof Class ) 173 type = Array.newInstance((Class <?>) component, 0).getClass(); 174 } 175 176 WeakReference <OpenConverter> wr = converterMap.get(type); 177 return (wr == null) ? null : wr.get(); 178 } 179 180 private static synchronized void putConverter(Type type, 181 OpenConverter conv) { 182 WeakReference <OpenConverter> wr = 183 new WeakReference <OpenConverter>(conv); 184 converterMap.put(type, wr); 185 } 186 187 private static synchronized void putPermanentConverter(Type type, 188 OpenConverter conv) { 189 putConverter(type, conv); 190 permanentConverters.add(conv); 191 } 192 193 static { 194 195 196 final OpenType [] simpleTypes = { 197 BIGDECIMAL, BIGINTEGER, BOOLEAN, BYTE, CHARACTER, DATE, 198 DOUBLE, FLOAT, INTEGER, LONG, OBJECTNAME, SHORT, STRING, 199 VOID, 200 }; 201 202 for (int i = 0; i < simpleTypes.length; i++) { 203 final OpenType t = simpleTypes[i]; 204 Class c; 205 try { 206 c = Class.forName(t.getClassName(), false, 207 ObjectName .class.getClassLoader()); 208 } catch (ClassNotFoundException e) { 209 throw new Error (e); 211 } 212 final OpenConverter conv = new IdentityConverter(c, t, c); 213 putPermanentConverter(c, conv); 214 215 if (c.getName().startsWith("java.lang.")) { 216 try { 217 final Field typeField = c.getField("TYPE"); 218 final Class primitiveType = (Class ) typeField.get(null); 219 final OpenConverter primitiveConv = 220 new IdentityConverter(primitiveType, t, primitiveType); 221 putPermanentConverter(primitiveType, 222 primitiveConv); 223 if (primitiveType != void.class) { 224 final Class primitiveArrayType = 225 Array.newInstance(primitiveType, 0).getClass(); 226 final OpenType primitiveArrayOpenType = 227 ArrayType.getPrimitiveArrayType(primitiveArrayType); 228 final OpenConverter primitiveArrayConv = 229 new IdentityConverter(primitiveArrayType, 230 primitiveArrayOpenType, 231 primitiveArrayType); 232 putPermanentConverter(primitiveArrayType, 233 primitiveArrayConv); 234 } 235 } catch (NoSuchFieldException e) { 236 } catch (IllegalAccessException e) { 238 assert(false); 240 } 241 } 242 } 243 } 244 245 246 public static synchronized OpenConverter toConverter(Type objType) 247 throws OpenDataException { 248 249 if (inProgress.containsKey(objType)) 250 throw new OpenDataException ("Recursive data structure"); 251 252 OpenConverter conv; 253 254 conv = getConverter(objType); 255 if (conv != null) 256 return conv; 257 258 inProgress.put(objType, objType); 259 try { 260 conv = makeConverter(objType); 261 } finally { 262 inProgress.remove(objType); 263 } 264 265 putConverter(objType, conv); 266 return conv; 267 } 268 269 private static OpenConverter makeConverter(Type objType) 270 throws OpenDataException { 271 272 275 if (objType instanceof GenericArrayType ) { 276 Type componentType = 277 ((GenericArrayType ) objType).getGenericComponentType(); 278 return makeArrayOrCollectionConverter(objType, componentType); 279 } else if (objType instanceof Class ) { 280 Class objClass = (Class <?>) objType; 281 if (objClass.isEnum()) { 282 return makeEnumConverter(objClass); 283 } else if (objClass.isArray()) { 284 Type componentType = objClass.getComponentType(); 285 return makeArrayOrCollectionConverter(objClass, componentType); 286 } else if (JMX.isMXBeanInterface(objClass)) { 287 return makeMXBeanConverter(objClass); 288 } else { 289 return makeCompositeConverter(objClass); 290 } 291 } else if (objType instanceof ParameterizedType ) { 292 return makeParameterizedConverter((ParameterizedType ) objType); 293 } else 294 throw new OpenDataException ("Cannot map type: " + objType); 295 } 296 297 private static <T extends Enum <T>> OpenConverter 298 makeEnumConverter(Class <T> enumClass) { 299 return new EnumConverter<T>(enumClass); 300 } 301 302 307 private static OpenConverter 308 makeArrayOrCollectionConverter(Type collectionType, Type elementType) 309 throws OpenDataException { 310 311 final OpenConverter elementConverter = toConverter(elementType); 312 final OpenType elementOpenType = elementConverter.getOpenType(); 313 final ArrayType openType = new ArrayType (1, elementOpenType); 314 final Class elementOpenClass = elementConverter.getOpenClass(); 315 316 final Class openArrayClass; 317 final String openArrayClassName; 318 if (elementOpenClass.isArray()) 319 openArrayClassName = "[" + elementOpenClass.getName(); 320 else 321 openArrayClassName = "[L" + elementOpenClass.getName() + ";"; 322 try { 323 openArrayClass = Class.forName(openArrayClassName); 324 } catch (ClassNotFoundException e) { 325 throw openDataException("Cannot obtain array class", e); 326 } 327 328 if (collectionType instanceof ParameterizedType ) { 329 return new CollectionConverter(collectionType, 330 openType, openArrayClass, 331 elementConverter); 332 } else { 333 if (elementConverter.isIdentity()) { 334 return new IdentityConverter(collectionType, 335 openType, 336 openArrayClass); 337 } else { 338 return new ArrayConverter(collectionType, 339 openType, 340 openArrayClass, 341 elementConverter); 342 } 343 } 344 } 345 346 private static final String [] keyArray = {"key"}; 347 private static final String [] keyValueArray = {"key", "value"}; 348 349 private static OpenConverter 350 makeTabularConverter(Type objType, boolean sortedMap, 351 Type keyType, Type valueType) 352 throws OpenDataException { 353 354 final String objTypeName = objType.toString(); 355 final OpenConverter keyConverter = toConverter(keyType); 356 final OpenConverter valueConverter = toConverter(valueType); 357 final OpenType keyOpenType = keyConverter.getOpenType(); 358 final OpenType valueOpenType = valueConverter.getOpenType(); 359 final CompositeType rowType = 360 new CompositeType (objTypeName, 361 objTypeName, 362 keyValueArray, 363 keyValueArray, 364 new OpenType [] {keyOpenType, valueOpenType}); 365 final TabularType tabularType = 366 new TabularType (objTypeName, objTypeName, rowType, keyArray); 367 return new TabularConverter(objType, sortedMap, tabularType, 368 keyConverter, valueConverter); 369 } 370 371 376 private static OpenConverter 377 makeParameterizedConverter(ParameterizedType objType) throws OpenDataException { 378 379 final Type rawType = objType.getRawType(); 380 381 if (rawType instanceof Class ) { 382 Class c = (Class <?>) rawType; 383 if (c == List .class || c == Set .class || c == SortedSet .class) { 384 Type [] actuals = 385 ((ParameterizedType ) objType).getActualTypeArguments(); 386 assert(actuals.length == 1); 387 if (c == SortedSet .class) 388 mustBeComparable(c, actuals[0]); 389 return makeArrayOrCollectionConverter(objType, actuals[0]); 390 } else { 391 boolean sortedMap = (c == SortedMap .class); 392 if (c == Map .class || sortedMap) { 393 Type [] actuals = 394 ((ParameterizedType ) objType).getActualTypeArguments(); 395 assert(actuals.length == 2); 396 if (sortedMap) 397 mustBeComparable(c, actuals[0]); 398 return makeTabularConverter(objType, sortedMap, 399 actuals[0], actuals[1]); 400 } 401 } 402 } 403 throw new OpenDataException ("Cannot convert type: " + objType); 404 } 405 406 private static OpenConverter makeMXBeanConverter(Type t) 407 throws OpenDataException { 408 return new MXBeanConverter(t); 409 } 410 411 private static OpenConverter makeCompositeConverter(Class c) 412 throws OpenDataException { 413 414 final boolean gcInfoHack = 418 (c.getName().equals("com.sun.management.GcInfo") && 419 c.getClassLoader() == null); 420 421 final List <Method > methods = 422 MBeanAnalyzer.eliminateCovariantMethods(c.getMethods()); 423 final SortedMap <String ,Method > getterMap = newSortedMap(); 424 425 428 for (Method method : methods) { 429 final String propertyName = propertyName(method); 430 431 if (propertyName == null) 432 continue; 433 if (gcInfoHack && propertyName.equals("CompositeType")) 434 continue; 435 436 Method old = 437 getterMap.put(decapitalize(propertyName), 438 method); 439 if (old != null) { 440 final String msg = 441 "Class " + c.getName() + " has method name clash: " + 442 old.getName() + ", " + method.getName(); 443 throw new OpenDataException (msg); 444 } 445 } 446 447 final int nitems = getterMap.size(); 448 449 if (nitems == 0) { 450 throw new OpenDataException ("Can't map " + c.getName() + 451 " to an open data type"); 452 } 453 454 final Method [] getters = new Method [nitems]; 455 final String [] itemNames = new String [nitems]; 456 final OpenType [] openTypes = new OpenType [nitems]; 457 int i = 0; 458 for (Map.Entry <String ,Method > entry : getterMap.entrySet()) { 459 itemNames[i] = entry.getKey(); 460 final Method getter = entry.getValue(); 461 getters[i] = getter; 462 final Type retType = getter.getGenericReturnType(); 463 openTypes[i] = toConverter(retType).getOpenType(); 464 i++; 465 } 466 467 CompositeType compositeType = 468 new CompositeType (c.getName(), 469 c.getName(), 470 itemNames, itemNames, openTypes); 473 474 return new CompositeConverter(c, 475 compositeType, 476 itemNames, 477 getters); 478 } 479 480 486 private static final class IdentityConverter extends OpenConverter { 487 IdentityConverter(Type targetType, OpenType openType, 488 Class openClass) { 489 super(targetType, openType, openClass); 490 } 491 492 boolean isIdentity() { 493 return true; 494 } 495 496 final Object toNonNullOpenValue(MXBeanLookup lookup, Object value) { 497 return value; 498 } 499 500 public final Object fromNonNullOpenValue(MXBeanLookup lookup, Object value) { 501 return value; 502 } 503 } 504 505 private static final class EnumConverter<T extends Enum <T>> 506 extends OpenConverter { 507 508 EnumConverter(Class <T> enumClass) { 509 super(enumClass, SimpleType.STRING, String .class); 510 this.enumClass = enumClass; 511 } 512 513 final Object toNonNullOpenValue(MXBeanLookup lookup, Object value) { 514 return ((Enum ) value).name(); 515 } 516 517 public final Object fromNonNullOpenValue(MXBeanLookup lookup, Object value) 520 throws InvalidObjectException { 521 try { 522 return Enum.valueOf(enumClass, (String ) value); 523 } catch (Exception e) { 524 throw invalidObjectException("Cannot convert to enum: " + 525 value, e); 526 } 527 } 528 529 private final Class <T> enumClass; 530 } 531 532 private static final class ArrayConverter extends OpenConverter { 533 ArrayConverter(Type targetType, 534 ArrayType openArrayType, Class openArrayClass, 535 OpenConverter elementConverter) { 536 super(targetType, openArrayType, openArrayClass); 537 this.elementConverter = elementConverter; 538 } 539 540 final Object toNonNullOpenValue(MXBeanLookup lookup, Object value) 541 throws OpenDataException { 542 Object [] valueArray = (Object []) value; 543 final int len = valueArray.length; 544 final Object [] openArray = (Object []) 545 Array.newInstance(getOpenClass().getComponentType(), len); 546 for (int i = 0; i < len; i++) { 547 openArray[i] = 548 elementConverter.toOpenValue(lookup, valueArray[i]); 549 } 550 return openArray; 551 } 552 553 public final Object fromNonNullOpenValue(MXBeanLookup lookup, Object openValue) 554 throws InvalidObjectException { 555 final Object [] openArray = (Object []) openValue; 556 final Type targetType = getTargetType(); 557 final Object [] valueArray; 558 final Type componentType; 559 if (targetType instanceof GenericArrayType ) { 560 componentType = 561 ((GenericArrayType ) targetType).getGenericComponentType(); 562 } else if (targetType instanceof Class && 563 ((Class <?>) targetType).isArray()) { 564 componentType = ((Class <?>) targetType).getComponentType(); 565 } else { 566 throw new IllegalArgumentException ("Not an array: " + 567 targetType); 568 } 569 valueArray = (Object []) Array.newInstance((Class <?>) componentType, 570 openArray.length); 571 for (int i = 0; i < openArray.length; i++) { 572 valueArray[i] = 573 elementConverter.fromOpenValue(lookup, openArray[i]); 574 } 575 return valueArray; 576 } 577 578 void checkReconstructible() throws InvalidObjectException { 579 elementConverter.checkReconstructible(); 580 } 581 582 585 private final OpenConverter elementConverter; 586 } 587 588 private static final class CollectionConverter extends OpenConverter { 589 CollectionConverter(Type targetType, 590 ArrayType openArrayType, 591 Class openArrayClass, 592 OpenConverter elementConverter) { 593 super(targetType, openArrayType, openArrayClass); 594 this.elementConverter = elementConverter; 595 596 600 Type raw = ((ParameterizedType ) targetType).getRawType(); 601 Class c = (Class <?>) raw; 602 |