1 5 package com.tc.object.dna.impl; 6 7 import com.tc.exception.TCRuntimeException; 8 import com.tc.io.TCDataInput; 9 import com.tc.io.TCDataOutput; 10 import com.tc.logging.TCLogger; 11 import com.tc.logging.TCLogging; 12 import com.tc.object.LiteralValues; 13 import com.tc.object.ObjectID; 14 import com.tc.object.loaders.ClassProvider; 15 import com.tc.object.loaders.NamedClassLoader; 16 import com.tc.util.Assert; 17 18 import gnu.trove.TObjectIntHashMap; 19 20 import java.io.IOException ; 21 import java.io.UnsupportedEncodingException ; 22 import java.lang.reflect.Array ; 23 import java.lang.reflect.Constructor ; 24 import java.lang.reflect.Field ; 25 import java.lang.reflect.InvocationTargetException ; 26 import java.lang.reflect.Method ; 27 import java.math.BigDecimal ; 28 import java.math.BigInteger ; 29 30 33 public class DNAEncoding { 34 35 private static final int WARN_THRESHOLD = 8 * 1000 * 1000; 38 private static final int BOOLEAN_WARN = WARN_THRESHOLD / 1; 39 private static final int BYTE_WARN = WARN_THRESHOLD / 1; 40 private static final int CHAR_WARN = WARN_THRESHOLD / 2; 41 private static final int DOUBLE_WARN = WARN_THRESHOLD / 8; 42 private static final int FLOAT_WARN = WARN_THRESHOLD / 4; 43 private static final int INT_WARN = WARN_THRESHOLD / 4; 44 private static final int LONG_WARN = WARN_THRESHOLD / 8; 45 private static final int SHORT_WARN = WARN_THRESHOLD / 2; 46 private static final int REF_WARN = WARN_THRESHOLD / 4; 47 48 static final byte LOGICAL_ACTION_TYPE = 1; 49 static final byte PHYSICAL_ACTION_TYPE = 2; 50 static final byte ARRAY_ELEMENT_ACTION_TYPE = 3; 51 static final byte ENTIRE_ARRAY_ACTION_TYPE = 4; 52 static final byte LITERAL_VALUE_ACTION_TYPE = 5; 53 static final byte PHYSICAL_ACTION_TYPE_REF_OBJECT = 6; 54 static final byte SUB_ARRAY_ACTION_TYPE = 7; 55 56 private static final LiteralValues literalValues = new LiteralValues(); 57 private static final TCLogger logger = TCLogging.getLogger(DNAEncoding.class); 58 59 private static final byte TYPE_ID_REFERENCE = 1; 60 private static final byte TYPE_ID_BOOLEAN = 2; 61 private static final byte TYPE_ID_BYTE = 3; 62 private static final byte TYPE_ID_CHAR = 4; 63 private static final byte TYPE_ID_DOUBLE = 5; 64 private static final byte TYPE_ID_FLOAT = 6; 65 private static final byte TYPE_ID_INT = 7; 66 private static final byte TYPE_ID_LONG = 10; 67 private static final byte TYPE_ID_SHORT = 11; 68 private static final byte TYPE_ID_STRING = 12; 69 private static final byte TYPE_ID_STRING_BYTES = 13; 70 private static final byte TYPE_ID_ARRAY = 14; 71 private static final byte TYPE_ID_JAVA_LANG_CLASS = 15; 72 private static final byte TYPE_ID_JAVA_LANG_CLASS_HOLDER = 16; 73 private static final byte TYPE_ID_BIG_INTEGER = 17; 74 private static final byte TYPE_ID_STACK_TRACE_ELEMENT = 18; 75 private static final byte TYPE_ID_BIG_DECIMAL = 19; 76 private static final byte TYPE_ID_JAVA_LANG_CLASSLOADER = 20; 77 private static final byte TYPE_ID_JAVA_LANG_CLASSLOADER_HOLDER = 21; 78 private static final byte TYPE_ID_ENUM = 22; 79 private static final byte TYPE_ID_ENUM_HOLDER = 23; 80 81 private static final byte ARRAY_TYPE_PRIMITIVE = 1; 82 private static final byte ARRAY_TYPE_NON_PRIMITIVE = 2; 83 84 91 public static final byte SERIALIZER = 0x00; 92 93 100 public static final byte STORAGE = 0x01; 101 102 109 public static final byte APPLICATOR = 0x02; 110 111 private final ClassProvider classProvider; 112 private final byte policy; 113 114 private static final ClassProvider FAILURE_PROVIDER = new FailureClassProvider(); 115 private static final ClassProvider LOCAL_PROVIDER = new LocalClassProvider(); 116 117 120 public DNAEncoding(ClassProvider classProvider) { 121 this.classProvider = classProvider; 122 this.policy = APPLICATOR; 123 } 124 125 public DNAEncoding(byte policy) { 126 this.policy = policy; 127 if (policy == STORAGE) { 129 this.classProvider = FAILURE_PROVIDER; 130 } else if (policy == SERIALIZER) { 131 this.classProvider = LOCAL_PROVIDER; 132 } else { 133 throw new AssertionError ("Policy not valid : " + policy + " : For APPLICATORS use the other contructor !"); 134 } 135 } 136 137 public byte getPolicy() { 138 return this.policy; 139 } 140 141 public void encodeClassLoader(Object value, TCDataOutput output) { 142 output.writeByte(TYPE_ID_JAVA_LANG_CLASSLOADER); 143 writeString(classProvider.getLoaderDescriptionFor((ClassLoader ) value), output); 144 } 145 146 149 private Object getEnumName(Object enumObject) { 150 try { 151 Method m = enumObject.getClass().getMethod("name", new Class [0]); 152 m.setAccessible(true); 153 Object val; 154 val = m.invoke(enumObject, new Object [0]); 155 return val; 156 } catch (IllegalArgumentException e) { 157 throw new TCRuntimeException(e); 158 } catch (IllegalAccessException e) { 159 throw new TCRuntimeException(e); 160 } catch (InvocationTargetException e) { 161 throw new TCRuntimeException(e); 162 } catch (SecurityException e) { 163 throw new TCRuntimeException(e); 164 } catch (NoSuchMethodException e) { 165 throw new TCRuntimeException(e); 166 } 167 } 168 169 public void encode(Object value, TCDataOutput output) { 170 if (value == null) { 171 throw new IllegalArgumentException ("Object cannot be null"); 173 } 174 175 final int type = literalValues.valueFor(value); 178 179 switch (type) { 180 case LiteralValues.ENUM: 181 output.writeByte(TYPE_ID_ENUM); 182 Class enumClass = value.getClass(); 183 writeString(enumClass.getName(), output); 184 writeString(classProvider.getLoaderDescriptionFor(enumClass), output); 185 186 Object name = getEnumName(value); 187 writeString((String ) name, output); 188 break; 189 case LiteralValues.ENUM_HOLDER: 190 output.writeByte(TYPE_ID_ENUM_HOLDER); 191 writeEnumInstance((EnumInstance) value, output); 192 break; 193 case LiteralValues.JAVA_LANG_CLASSLOADER: 194 encodeClassLoader(value, output); 195 break; 196 case LiteralValues.JAVA_LANG_CLASSLOADER_HOLDER: 197 output.writeByte(TYPE_ID_JAVA_LANG_CLASSLOADER_HOLDER); 198 writeClassLoaderInstance((ClassLoaderInstance) value, output); 199 break; 200 case LiteralValues.JAVA_LANG_CLASS: 201 output.writeByte(TYPE_ID_JAVA_LANG_CLASS); 202 Class c = (Class ) value; 203 writeString(c.getName(), output); 204 writeString(classProvider.getLoaderDescriptionFor(c), output); 205 break; 206 case LiteralValues.JAVA_LANG_CLASS_HOLDER: 207 output.writeByte(TYPE_ID_JAVA_LANG_CLASS_HOLDER); 208 writeClassInstance((ClassInstance) value, output); 209 break; 210 case LiteralValues.BOOLEAN: 211 output.writeByte(TYPE_ID_BOOLEAN); 212 output.writeBoolean(((Boolean ) value).booleanValue()); 213 break; 214 case LiteralValues.BYTE: 215 output.writeByte(TYPE_ID_BYTE); 216 output.writeByte(((Byte ) value).byteValue()); 217 break; 218 case LiteralValues.CHARACTER: 219 output.writeByte(TYPE_ID_CHAR); 220 output.writeChar(((Character ) value).charValue()); 221 break; 222 case LiteralValues.DOUBLE: 223 output.writeByte(TYPE_ID_DOUBLE); 224 output.writeDouble(((Double ) value).doubleValue()); 225 break; 226 case LiteralValues.FLOAT: 227 output.writeByte(TYPE_ID_FLOAT); 228 output.writeFloat(((Float ) value).floatValue()); 229 break; 230 case LiteralValues.INTEGER: 231 output.writeByte(TYPE_ID_INT); 232 output.writeInt(((Integer ) value).intValue()); 233 break; 234 case LiteralValues.LONG: 235 output.writeByte(TYPE_ID_LONG); 236 output.writeLong(((Long ) value).longValue()); 237 break; 238 case LiteralValues.SHORT: 239 output.writeByte(TYPE_ID_SHORT); 240 output.writeShort(((Short ) value).shortValue()); 241 break; 242 case LiteralValues.STRING: 243 output.writeByte(TYPE_ID_STRING); 244 writeString((String ) value, output); 245 break; 246 case LiteralValues.STRING_BYTES: 247 output.writeByte(TYPE_ID_STRING_BYTES); 248 writeByteArray(((UTF8ByteDataHolder) value).getBytes(), output); 249 break; 250 case LiteralValues.OBJECT_ID: 251 output.writeByte(TYPE_ID_REFERENCE); 252 output.writeLong(((ObjectID) value).toLong()); 253 break; 254 case LiteralValues.STACK_TRACE_ELEMENT: 255 output.writeByte(TYPE_ID_STACK_TRACE_ELEMENT); 256 StackTraceElement ste = (StackTraceElement ) value; 257 writeStackTraceElement(ste, output); 258 break; 259 case LiteralValues.BIG_INTEGER: 260 output.writeByte(TYPE_ID_BIG_INTEGER); 261 writeByteArray(((BigInteger ) value).toByteArray(), output); 262 break; 263 case LiteralValues.BIG_DECIMAL: 264 output.writeByte(TYPE_ID_BIG_DECIMAL); 265 writeByteArray(((BigDecimal ) value).toString().getBytes(), output); 266 break; 267 case LiteralValues.ARRAY: 268 encodeArray(value, output); 269 break; 270 default: 271 throw Assert.failure("Illegal type (" + type + "):" + value); 272 } 273 274 } 276 277 private void writeStackTraceElement(StackTraceElement ste, TCDataOutput output) { 278 output.writeString(ste.getClassName()); 279 output.writeString(ste.getMethodName()); 280 output.writeString(ste.getFileName()); 281 output.writeInt(ste.getLineNumber()); 282 } 283 284 private void writeEnumInstance(EnumInstance value, TCDataOutput output) { 285 writeByteArray(value.getClassInstance().getName().getBytes(), output); 286 writeByteArray(value.getClassInstance().getLoaderDef().getBytes(), output); 287 writeByteArray(((UTF8ByteDataHolder) value.getEnumName()).getBytes(), output); 288 } 289 290 private void writeClassLoaderInstance(ClassLoaderInstance value, TCDataOutput output) { 291 writeByteArray(value.getLoaderDef().getBytes(), output); 292 } 293 294 private void writeClassInstance(ClassInstance value, TCDataOutput output) { 295 writeByteArray(value.getName().getBytes(), output); 296 writeByteArray(value.getLoaderDef().getBytes(), output); 297 } 298 299 private void writeString(String string, TCDataOutput output) { 300 try { 301 writeByteArray(string.getBytes("UTF-8"), output); 302 } catch (UnsupportedEncodingException e) { 303 throw new AssertionError (e); 304 } 305 } 306 307 private void writeByteArray(byte bytes[], TCDataOutput output) { 308 output.writeInt(bytes.length); 309 output.write(bytes); 310 } 311 312 313 private byte[] readByteArray(TCDataInput input) throws IOException { 320 int length = input.readInt(); 321 if (length >= BYTE_WARN) { 322 logger.warn("Attempting to allocate a large byte array of size: " + length); 323 } 324 byte[] array = new byte[length]; 325 input.readFully(array); 326 return array; 327 } 328 329 public Object decode(TCDataInput input) throws IOException , ClassNotFoundException { 330 final byte type = input.readByte(); 331 332 switch (type) { 333 case TYPE_ID_ENUM: 334 return readEnum(input, type); 335 case TYPE_ID_ENUM_HOLDER: 336 return readEnum(input, type); 337 case TYPE_ID_JAVA_LANG_CLASSLOADER: 338 return readClassLoader(input, type); 339 case TYPE_ID_JAVA_LANG_CLASSLOADER_HOLDER: 340 return readClassLoader(input, type); 341 case TYPE_ID_JAVA_LANG_CLASS: 342 return readClass(input, type); 343 case TYPE_ID_JAVA_LANG_CLASS_HOLDER: 344 return readClass(input, type); 345 case TYPE_ID_BOOLEAN: 346 return new Boolean (input.readBoolean()); 347 case TYPE_ID_BYTE: 348 return new Byte (input.readByte()); 349 case TYPE_ID_CHAR: 350 return new Character (input.readChar()); 351 case TYPE_ID_DOUBLE: 352 return new Double (input.readDouble()); 353 case TYPE_ID_FLOAT: 354 return new Float (input.readFloat()); 355 case TYPE_ID_INT: 356 return new Integer (input.readInt()); 357 case TYPE_ID_LONG: 358 return new Long (input.readLong()); 359 case TYPE_ID_SHORT: 360 return new Short (input.readShort()); 361 case TYPE_ID_STRING: 362 return readString(input, type); 363 case TYPE_ID_STRING_BYTES: 364 return readString(input, type); 365 case TYPE_ID_REFERENCE: 366 return new ObjectID(input.readLong()); 367 case TYPE_ID_ARRAY: 368 return decodeArray(input); 369 case TYPE_ID_STACK_TRACE_ELEMENT: 370 return readStackTraceElement(input); 371 case TYPE_ID_BIG_INTEGER: 372 byte[] b1 = readByteArray(input); 373 return new BigInteger (b1); 374 case TYPE_ID_BIG_DECIMAL: 375 byte[] b2 = readByteArray(input); 377 return new BigDecimal (new String (b2)); 378 default: 379 throw Assert.failure("Illegal type (" + type + ")"); 380 } 381 382 } 384 385 397 private Object readStackTraceElement(TCDataInput input) throws IOException , ClassNotFoundException { 398 String className = input.readString(); 399 String methodName = input.readString(); 400 String fileName = input.readString(); 401 int lineNumber = input.readInt(); 402 return createStackTraceElement(className, fileName, methodName, lineNumber); 403 } 404 405 409 private Object createStackTraceElement(String className, String fileName, String methodName, int lineNumber) 410 throws ClassNotFoundException , IOException { 411 Class clazz = Class.forName("java.lang.StackTraceElement"); 412 Constructor constructors[] = clazz.getDeclaredConstructors(); 413 for (int i = 0; i < constructors.length; i++) { 414 Class [] types = constructors[i].getParameterTypes(); 415 if (types.length == 0) { 416 return createStackTraceElementJDK14(clazz, constructors[i], className, fileName, methodName, lineNumber); 418 } else if (types.length == 4 && types[0] == String .class && types[1] == String .class && types[2] == String .class 419 && types[3] == int.class) { 420 return createStackTraceElementJDK15(clazz, constructors[i], className, fileName, methodName, lineNumber); 422 } 423 } 424 throw new ClassNotFoundException ("java.lang.StackTraceElement : Both known constructors not found !"); 425 } 426 427 private Object createStackTraceElementJDK14(Class clazz, Constructor constructor, String className, String fileName, 428 String methodName, int lineNumber) throws IOException { 429 try { 430 constructor.setAccessible(true); 431 Object i = constructor.newInstance(new Object [0]); 432 Field [] fields = clazz.getDeclaredFields(); 433 byte set = 0x00; 434 for (int j = 0; j < fields.length; j++) { 435 fields[j].setAccessible(true); 436 if ("declaringClass".equalsIgnoreCase(fields[j].getName())) { 437 fields[j].set(i, className); 438 set |= 0x01; 439 } else if ("methodName".equalsIgnoreCase(fields[j].getName())) { 440 fields[j].set(i, methodName); 441 set |= 0x02; 442 } else if ("fileName".equalsIgnoreCase(fields[j].getName())) { 443 fields[j].set(i, fileName); 444 set |= 0x04; 445 } else if ("lineNumber".equalsIgnoreCase(fields[j].getName())) { 446 fields[j].setInt(i, lineNumber); 447 set |= 0x08; 448 } 449 } 450 Assert.assertTrue(set == 0x0F); 451 return i; 452 } catch (Exception ex) { 453 IOException ioe = new IOException (); 454 ioe.initCause(ex); 455 throw ioe; 456 } 457 } 458 459 private Object createStackTraceElementJDK15(Class clazz, Constructor constructor, String className, String fileName, 460 String methodName, int lineNumber) throws IOException { 461 try { 462 Object params[] = new Object [4]; 463 params[0] = className; 464 params[1] = methodName; 465 params[2] = fileName; 466 params[3] = new Integer (lineNumber); 467 return constructor.newInstance(params); 468 } catch (Exception ex) { 469 IOException ioe = new IOException (); 470 ioe.initCause(ex); 471 throw ioe; 472 } 473 } 474 475 public void encodeArray(Object value, TCDataOutput output) { 476 encodeArray(value, output, value == null ? -1 : Array.getLength(value)); 477 } 478 479 public void encodeArray(Object value, TCDataOutput output, int length) { 480 output.writeByte(TYPE_ID_ARRAY); 481 482 if (value == null) { 483 output.writeInt(-1); 484 return; 485 } else { 486 output.writeInt(length); 487 } 488 489 Class type = value.getClass().getComponentType(); 490 491 if (type.isPrimitive()) { 492 output.writeByte(ARRAY_TYPE_PRIMITIVE); 493 switch (primitiveClassMap.get(type)) { 494 case TYPE_ID_BOOLEAN: 495 encodeBooleanArray((boolean[]) value, output, length); 496 break; 497 case TYPE_ID_BYTE: 498 encodeByteArray((byte[]) value, output, length); 499 break; 500 case TYPE_ID_CHAR: 501 encodeCharArray((char[]) value, output, length); 502 break; 503 case TYPE_ID_SHORT: 504 encodeShortArray((short[]) value, output, length); 505 break; 506 case TYPE_ID_INT: 507 encodeIntArray((int[]) value, output, length); 508 break; 509 case TYPE_ID_LONG: 510 encodeLongArray((long[]) value, output, length); 511 break; 512 case TYPE_ID_FLOAT: 513 encodeFloatArray((float[]) value, output, length); 514 break; 515 case TYPE_ID_DOUBLE: 516 encodeDoubleArray((double[]) value, output, length); 517 break; 518 default: 519 throw Assert.failure("unknown primitive array type: " + type); 520 } 521 } else { 522 output.writeByte(ARRAY_TYPE_NON_PRIMITIVE); 523 encodeObjectArray((Object []) value, output, length); 524 } 525 } 526 527 private void encodeByteArray(byte[] value, TCDataOutput output, int length) { 528 output.writeByte(TYPE_ID_BYTE); 529 530 for (int i = 0; i < length; i++) { 531 output.write(value[i]); 532 } 533 } 534 535 private void encodeObjectArray(Object [] value, TCDataOutput output, int length) { 536 for (int i = 0; i < length; i++) { 537 encode(value[i], output); 538 } 539 } 540 541 private void encodeDoubleArray(double[] value, TCDataOutput output, int length) { 542 output.writeByte(TYPE_ID_DOUBLE); 543 for (int i = 0; i < length; i++) { 544 output.writeDouble(value[i]); 545 } 546 } 547 548 private void encodeFloatArray(float[] value, TCDataOutput output, int length) { 549 output.writeByte(TYPE_ID_FLOAT); 550 for (int i = 0; i < length; i++) { 551 output.writeFloat(value[i]); 552 } 553 } 554 555 private void encodeLongArray(long[] value, TCDataOutput output, int length) { 556 output.writeByte(TYPE_ID_LONG); 557 for (int i = 0; i < length; i++) { 558 output.writeLong(value[i]); 559 } 560 } 561 562 private void encodeIntArray(int[] value, TCDataOutput output, int length) { 563 output.writeByte(TYPE_ID_INT); 564 for (int i = 0; i < length; i++) { 565 output.writeInt(value[i]); 566 } 567 } 568 569 private void encodeShortArray(short[] value, TCDataOutput output, int length) { 570 output.writeByte(TYPE_ID_SHORT); 571 for (int i = 0; i < length; i++) { 572 output.writeShort(value[i]); 573 } 574 } 575 576 private void encodeCharArray(char[] value, TCDataOutput output, int length) { 577 output.writeByte(TYPE_ID_CHAR); 578 for (int i = 0; i < length; i++) { 579 output.writeChar(value[i]); 580 } 581 } 582 583 private void encodeBooleanArray(boolean[] value, TCDataOutput output, int length) { 584 output.writeByte(TYPE_ID_BOOLEAN); 585 for (int i = 0; i < length; i++) { 586 output.writeBoolean(value[i]); 587 } 588 } 589 590 private void checkSize(Class type, int threshold, int len) { 591 if (len >= threshold) { 592 logger.warn("Attempt to read a " + type + " array of len: " + len + "; threshold=" + threshold); 593 } 594 } 595 596 private Object decodeArray(TCDataInput input) throws IOException , ClassNotFoundException { 597 final int len = input.readInt(); 598 if (len < 0) { return null; } 599 600 final byte arrayType = input.readByte(); 601 switch (arrayType) { 602 case ARRAY_TYPE_PRIMITIVE: 603 return decodePrimitiveArray(len, input); 604 case ARRAY_TYPE_NON_PRIMITIVE: 605 return decodeNonPrimitiveArray(len, input); 606 default: 607 throw Assert.failure("unknown array type: " + arrayType); 608 } 609 610 } 612 613 private Object [] decodeNonPrimitiveArray(int len, TCDataInput input) throws IOException , ClassNotFoundException { 614 checkSize(Object .class, REF_WARN, len); 615 Object [] rv = new Object [len]; 616 for (int i = 0, n = rv.length; i < n; i++) { 617 rv[i] = decode(input); 618 } 619 620 return rv; 621 } 622 623 private Object decodePrimitiveArray(int len, TCDataInput input) throws IOException { 624 byte type = input.readByte(); 625 626 switch (type) { 627 case TYPE_ID_BOOLEAN: 628 checkSize(Boolean.TYPE, BOOLEAN_WARN, len); 629 return decodeBooleanArray(len, input); 630 case TYPE_ID_BYTE: 631 checkSize(Byte.TYPE, BYTE_WARN, len); 632 return decodeByteArray(len, input); 633 case TYPE_ID_CHAR: 634 checkSize(Character.TYPE, CHAR_WARN, len); 635 return decodeCharArray(len, input); 636 case TYPE_ID_DOUBLE: 637 checkSize(Double.TYPE, DOUBLE_WARN, len); 638 return decodeDoubleArray(len, input); 639 case TYPE_ID_FLOAT: 640 checkSize(Float.TYPE, FLOAT_WARN, len); 641 return decodeFloatArray(len, input); 642 case TYPE_ID_INT: 643 checkSize(Integer.TYPE, INT_WARN, len); 644 return decodeIntArray(len, input); 645 case TYPE_ID_LONG: 646 checkSize(Long.TYPE, LONG_WARN, len); 647 return decodeLongArray(len, input); 648 case TYPE_ID_SHORT: 649 checkSize(Short.TYPE, SHORT_WARN, len); 650 return decodeShortArray(len, input); 651 default: 652 throw Assert.failure("unknown prim type: " + type); 653 } 654 655 } 657 658 private short[] decodeShortArray(int len, TCDataInput input) throws IOException { 659 short[] rv = new short[len]; 660 for (int i = 0, n = rv.length; i < n; i++) { 661 rv[i] = input.readShort(); 662 } 663 return rv; 664 } 665 666 private long[] decodeLongArray(int len, TCDataInput input) throws IOException { 667 long[] rv = new long[len]; 668 for (int i = 0, n = rv.length; i < n; i++) { 669 rv[i] = input.readLong(); 670 } 671 return rv; 672 } 673 674 private int[] decodeIntArray(int len, TCDataInput input) throws IOException { 675 int[] rv = new int[len]; 676 for (int i = 0, n = rv.length; i < n; i++) { 677 rv[i] = input.readInt(); 678 } 679 return rv; 680 } 681 682 private float[] decodeFloatArray(int len, TCDataInput input) throws IOException { 683 float[] rv = new float[len]; 684 for (int i = 0, n = rv.length; i < n; i++) { 685 rv[i] = input.readFloat(); 686 } 687 return rv; 688 } 689 690 private double[] decodeDoubleArray(int len, TCDataInput input) throws IOException { 691 double[] rv = new double[len]; 692 for (int i = 0, n = rv.length; i < n; i++) { 693 rv[i] = input.readDouble(); 694 } 695 return rv; 696 } 697 698 private char[] decodeCharArray(int len, TCDataInput input) throws IOException { 699 char[] rv = new char[len]; 700 for (int i = 0, n = rv.length; i < n; i++) { 701 rv[i] = input.readChar(); 702 } 703 return rv; 704 } 705 706 private byte[] decodeByteArray(int len, TCDataInput input) throws IOException { 707 byte[] rv = new byte[len]; 708 if (len != 0) { 709 int read = input.read(rv, 0, len); 710 if (read != len) { throw new IOException ("read " + read + " bytes, expected " + len); } 711 } 712 return rv; 713 } 714 715 private boolean[] decodeBooleanArray(int len, TCDataInput input) throws IOException { 716 boolean[] rv = new boolean[len]; 717 for (int i = 0, n = rv.length; i < n; i++) { 718 rv[i] = input.readBoolean(); 719 } 720 return rv; 721 } 722 723 727 private Object enumValueOf(Class enumType, String enumName) { 728 try { 729 Method m = enumType.getMethod("valueOf", new Class [] { Class .class, String .class }); 730 Object enumObj = m.invoke(null, new Object [] { enumType, enumName }); 731 return enumObj; 732 } catch (SecurityException e) { 733 throw new TCRuntimeException(e); 734 } catch (NoSuchMethodException e) { 735 throw new TCRuntimeException(e); 736 } catch (IllegalArgumentException e) { 737 throw new TCRuntimeException(e); 738 } catch (IllegalAccessException e) { 739 throw new TCRuntimeException(e); 740 } catch (InvocationTargetException e) { 741 throw new TCRuntimeException(e); 742 } 743 } 744 745 private Object readEnum(TCDataInput input, byte type) throws IOException , ClassNotFoundException { 746 UTF8ByteDataHolder name = new UTF8ByteDataHolder(readByteArray(input)); 747 UTF8ByteDataHolder def = new UTF8ByteDataHolder(readByteArray(input)); 748 byte[] data = readByteArray(input); 749 750 if ((policy == SERIALIZER && type == TYPE_ID_ENUM) || policy == APPLICATOR) { 751 Class enumType = new ClassInstance(name, def).asClass(classProvider); 752 753 String enumName = new String (data, "UTF-8"); 754 return enumValueOf(enumType, enumName); 755 } else { 756 ClassInstance clazzInstance = new ClassInstance(name, def); 757 UTF8ByteDataHolder enumName = new UTF8ByteDataHolder(data); 758 return new EnumInstance(clazzInstance, enumName); 759 } 760 } 761 762 private Object readClassLoader(TCDataInput input, byte type) throws IOException { 763 UTF8ByteDataHolder def = new UTF8ByteDataHolder(readByteArray(input)); 764 765 if ((policy == SERIALIZER && type == TYPE_ID_JAVA_LANG_CLASSLOADER) || policy == APPLICATOR) { 766 return new ClassLoaderInstance(def).asClassLoader(classProvider); 767 } else { 768 return new ClassLoaderInstance(def); 769 } 770 } 771 772 private Object readClass(TCDataInput input, byte type) throws IOException , ClassNotFoundException { 773 UTF8ByteDataHolder name = new UTF8ByteDataHolder(readByteArray(input)); 774 UTF8ByteDataHolder def = new UTF8ByteDataHolder(readByteArray(input)); 775 776 if ((policy == SERIALIZER && type == TYPE_ID_JAVA_LANG_CLASS) || policy == APPLICATOR) { 777 return new ClassInstance(name, def).asClass(classProvider); 778 } else { 779 return new ClassInstance(name, def); 780 } 781 } 782 783 private Object readString(TCDataInput input, byte type) throws IOException { 784 byte[] data = readByteArray(input); 785 if ((policy == SERIALIZER && type == TYPE_ID_STRING) || policy == APPLICATOR) { 786 return new String (data, "UTF-8"); 787 } else { 788 return new UTF8ByteDataHolder(data); 789 } 790 } 791 792 private static class FailureClassProvider implements ClassProvider { 793 794 public Class getClassFor(String className, String loaderDesc) { 795 throw new AssertionError (); 796 } 797 798 public String getLoaderDescriptionFor(Class clazz) { 799 throw new AssertionError (); 800 } 801 802 public ClassLoader getClassLoader(String loaderDesc) { 803 throw new AssertionError (); 804 } 805 806 public String getLoaderDescriptionFor(ClassLoader loader) { 807 throw new AssertionError (); 808 } 809 810 public void registerNamedLoader(NamedClassLoader loader) { 811 throw new AssertionError (); 812 } 813 } 814 815 private static class LocalClassProvider implements ClassProvider { 816 817 private static final String LOADER_ID = LocalClassProvider.class.getName() + "::CLASSPROVIDER"; 818 819 public Class getClassFor(String className, String loaderDesc) { 822 Assert.assertEquals(LOADER_ID, loaderDesc); 823 try { 824 return Class.forName(className); 825 } catch (ClassNotFoundException e) { 826 throw new AssertionError (e); 827 } 828 } 829 830 public String getLoaderDescriptionFor(Class clazz) { 831 return LOADER_ID; 832 } 833 834 public ClassLoader getClassLoader(String loaderDesc) { 835 Assert.assertEquals(LOADER_ID, loaderDesc); 836 return ClassLoader.getSystemClassLoader(); 837 } 838 839 public String getLoaderDescriptionFor(ClassLoader loader) { 840 return LOADER_ID; 841 } 842 843 public void registerNamedLoader(NamedClassLoader loader) { 844 } 846 } 847 848 private static final TObjectIntHashMap primitiveClassMap = new TObjectIntHashMap(); 849 850 static { 851 primitiveClassMap.put(java.lang.Boolean.TYPE, TYPE_ID_BOOLEAN); 852 primitiveClassMap.put(java.lang.Byte.TYPE, TYPE_ID_BYTE); 853 primitiveClassMap.put(java.lang.Character.TYPE, TYPE_ID_CHAR); 854 primitiveClassMap.put(java.lang.Double.TYPE, TYPE_ID_DOUBLE); 855 primitiveClassMap.put(java.lang.Float.TYPE, TYPE_ID_FLOAT); 856 primitiveClassMap.put(java.lang.Integer.TYPE, TYPE_ID_INT); 857 primitiveClassMap.put(java.lang.Long.TYPE, TYPE_ID_LONG); 858 primitiveClassMap.put(java.lang.Short.TYPE, TYPE_ID_SHORT); 859 } 860 861 } 862 | Popular Tags |