KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > object > dna > impl > DNAEncoding


1 /*
2  * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
3  * notice. All rights reserved.
4  */

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 JavaDoc;
21 import java.io.UnsupportedEncodingException JavaDoc;
22 import java.lang.reflect.Array JavaDoc;
23 import java.lang.reflect.Constructor JavaDoc;
24 import java.lang.reflect.Field JavaDoc;
25 import java.lang.reflect.InvocationTargetException JavaDoc;
26 import java.lang.reflect.Method JavaDoc;
27 import java.math.BigDecimal JavaDoc;
28 import java.math.BigInteger JavaDoc;
29
30 /**
31  * Utility for encoding/decoding DNA
32  */

33 public class DNAEncoding {
34
35   // XXX: These warning thresholds should be done in a non-static way so they can be made configurable
36
// and architecture sensitive.
37
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   /**
85    * When the policy is set to SERIALIZER then the DNAEncoding.decode() will return the exact Objects that where
86    * encoded. For Example if UTF8ByteDataHolder is serialized to a stream, then when it is deserialized, you get an
87    * UTF8ByteDataHolder object. Same goes for String or ClassHolder etc.
88    * <p>
89    * You may want such a policy in TCObjectInputStream, for example.
90    */

91   public static final byte SERIALIZER = 0x00;
92
93   /**
94    * When the policy is set to STORAGE then the DNAEncoding.decode() may return Objects that represent the original
95    * objects for performance/memory. For Example if String is serialized to a stream, then when it is deserialized, you
96    * may get UTF8ByteDataHolder instead.
97    * <p>
98    * As the name says, you may want such a policy for storage in the L2.
99    */

100   public static final byte STORAGE = 0x01;
101
102   /**
103    * When the policy is set to APPLICATOR then the DNAEncoding.decode() will return the original Objects that were
104    * encoded in the orinal stream. For Example if UTF8ByteDataHolder is serialized to a stream, then when it is
105    * deserialized, you get a String object.
106    * <p>
107    * You may want such a policy in TCObjectInputStream, for example.
108    */

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   /**
118    * Used in the Applicators. The policy is set to APPLICATOR.
119    */

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     // you only want this version on the server where you won't be expanding java.lang.Class instances
128
if (policy == STORAGE) {
129       this.classProvider = FAILURE_PROVIDER;
130     } else if (policy == SERIALIZER) {
131       this.classProvider = LOCAL_PROVIDER;
132     } else {
133       throw new AssertionError JavaDoc("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 JavaDoc value, TCDataOutput output) {
142     output.writeByte(TYPE_ID_JAVA_LANG_CLASSLOADER);
143     writeString(classProvider.getLoaderDescriptionFor((ClassLoader JavaDoc) value), output);
144   }
145
146   /**
147    * The reason that we use reflection here is that Enum is a jdk 1.5 construct and this project is jdk 1.4 compliance.
148    */

149   private Object JavaDoc getEnumName(Object JavaDoc enumObject) {
150     try {
151       Method JavaDoc m = enumObject.getClass().getMethod("name", new Class JavaDoc[0]);
152       m.setAccessible(true);
153       Object JavaDoc val;
154       val = m.invoke(enumObject, new Object JavaDoc[0]);
155       return val;
156     } catch (IllegalArgumentException JavaDoc e) {
157       throw new TCRuntimeException(e);
158     } catch (IllegalAccessException JavaDoc e) {
159       throw new TCRuntimeException(e);
160     } catch (InvocationTargetException JavaDoc e) {
161       throw new TCRuntimeException(e);
162     } catch (SecurityException JavaDoc e) {
163       throw new TCRuntimeException(e);
164     } catch (NoSuchMethodException JavaDoc e) {
165       throw new TCRuntimeException(e);
166     }
167   }
168
169   public void encode(Object JavaDoc value, TCDataOutput output) {
170     if (value == null) {
171       // Null values should have already been converted to null ObjectID
172
throw new IllegalArgumentException JavaDoc("Object cannot be null");
173     }
174
175     // final Class valueClass = value.getClass();
176
// final int type = literalValues.valueFor(valueClass.getName());
177
final int type = literalValues.valueFor(value);
178
179     switch (type) {
180       case LiteralValues.ENUM:
181         output.writeByte(TYPE_ID_ENUM);
182         Class JavaDoc enumClass = value.getClass();
183         writeString(enumClass.getName(), output);
184         writeString(classProvider.getLoaderDescriptionFor(enumClass), output);
185
186         Object JavaDoc name = getEnumName(value);
187         writeString((String JavaDoc) 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 JavaDoc c = (Class JavaDoc) 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 JavaDoc) value).booleanValue());
213         break;
214       case LiteralValues.BYTE:
215         output.writeByte(TYPE_ID_BYTE);
216         output.writeByte(((Byte JavaDoc) value).byteValue());
217         break;
218       case LiteralValues.CHARACTER:
219         output.writeByte(TYPE_ID_CHAR);
220         output.writeChar(((Character JavaDoc) value).charValue());
221         break;
222       case LiteralValues.DOUBLE:
223         output.writeByte(TYPE_ID_DOUBLE);
224         output.writeDouble(((Double JavaDoc) value).doubleValue());
225         break;
226       case LiteralValues.FLOAT:
227         output.writeByte(TYPE_ID_FLOAT);
228         output.writeFloat(((Float JavaDoc) value).floatValue());
229         break;
230       case LiteralValues.INTEGER:
231         output.writeByte(TYPE_ID_INT);
232         output.writeInt(((Integer JavaDoc) value).intValue());
233         break;
234       case LiteralValues.LONG:
235         output.writeByte(TYPE_ID_LONG);
236         output.writeLong(((Long JavaDoc) value).longValue());
237         break;
238       case LiteralValues.SHORT:
239         output.writeByte(TYPE_ID_SHORT);
240         output.writeShort(((Short JavaDoc) value).shortValue());
241         break;
242       case LiteralValues.STRING:
243         output.writeByte(TYPE_ID_STRING);
244         writeString((String JavaDoc) 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 JavaDoc ste = (StackTraceElement JavaDoc) value;
257         writeStackTraceElement(ste, output);
258         break;
259       case LiteralValues.BIG_INTEGER:
260         output.writeByte(TYPE_ID_BIG_INTEGER);
261         writeByteArray(((BigInteger JavaDoc) value).toByteArray(), output);
262         break;
263       case LiteralValues.BIG_DECIMAL:
264         output.writeByte(TYPE_ID_BIG_DECIMAL);
265         writeByteArray(((BigDecimal JavaDoc) 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     // unreachable
275
}
276
277   private void writeStackTraceElement(StackTraceElement JavaDoc 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 JavaDoc string, TCDataOutput output) {
300     try {
301       writeByteArray(string.getBytes("UTF-8"), output);
302     } catch (UnsupportedEncodingException JavaDoc e) {
303       throw new AssertionError JavaDoc(e);
304     }
305   }
306
307   private void writeByteArray(byte bytes[], TCDataOutput output) {
308     output.writeInt(bytes.length);
309     output.write(bytes);
310   }
311
312   /* This method is an optimized method for writing char array when no check is needed */
313   // private void writeCharArray(char[] chars, TCDataOutput output) {
314
// output.writeInt(chars.length);
315
// for (int i = 0, n = chars.length; i < n; i++) {
316
// output.writeChar(chars[i]);
317
// }
318
// }
319
private byte[] readByteArray(TCDataInput input) throws IOException JavaDoc {
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 JavaDoc decode(TCDataInput input) throws IOException JavaDoc, ClassNotFoundException JavaDoc {
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 JavaDoc(input.readBoolean());
347       case TYPE_ID_BYTE:
348         return new Byte JavaDoc(input.readByte());
349       case TYPE_ID_CHAR:
350         return new Character JavaDoc(input.readChar());
351       case TYPE_ID_DOUBLE:
352         return new Double JavaDoc(input.readDouble());
353       case TYPE_ID_FLOAT:
354         return new Float JavaDoc(input.readFloat());
355       case TYPE_ID_INT:
356         return new Integer JavaDoc(input.readInt());
357       case TYPE_ID_LONG:
358         return new Long JavaDoc(input.readLong());
359       case TYPE_ID_SHORT:
360         return new Short JavaDoc(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 JavaDoc(b1);
374       case TYPE_ID_BIG_DECIMAL:
375         // char[] chars = readCharArray(input); // Unfortunately this is 1.5 specific
376
byte[] b2 = readByteArray(input);
377         return new BigDecimal JavaDoc(new String JavaDoc(b2));
378       default:
379         throw Assert.failure("Illegal type (" + type + ")");
380     }
381
382     // unreachable
383
}
384
385   // private char[] readCharArray(TCDataInput input) throws IOException {
386
// int length = input.readInt();
387
// if (length >= CHAR_WARN) {
388
// logger.warn("Attempting to allocate a large char array of size: " + length);
389
// }
390
// char[] array = new char[length];
391
// for (int i = 0, n = array.length; i < n; i++) {
392
// array[i] = input.readChar();
393
// }
394
// return array;
395
// }
396

397   private Object JavaDoc readStackTraceElement(TCDataInput input) throws IOException JavaDoc, ClassNotFoundException JavaDoc {
398     String JavaDoc className = input.readString();
399     String JavaDoc methodName = input.readString();
400     String JavaDoc fileName = input.readString();
401     int lineNumber = input.readInt();
402     return createStackTraceElement(className, fileName, methodName, lineNumber);
403   }
404
405   /*
406    * This method uses reflection as 1.4 doesnt have a public constructor for stack trace element and 1.5 removed the
407    * private no arg constructor. XXX::This is an ugly hack that I would like to getaway from
408    */

409   private Object JavaDoc createStackTraceElement(String JavaDoc className, String JavaDoc fileName, String JavaDoc methodName, int lineNumber)
410       throws ClassNotFoundException JavaDoc, IOException JavaDoc {
411     Class JavaDoc clazz = Class.forName("java.lang.StackTraceElement");
412     Constructor JavaDoc constructors[] = clazz.getDeclaredConstructors();
413     for (int i = 0; i < constructors.length; i++) {
414       Class JavaDoc[] types = constructors[i].getParameterTypes();
415       if (types.length == 0) {
416         // This is 1.4
417
return createStackTraceElementJDK14(clazz, constructors[i], className, fileName, methodName, lineNumber);
418       } else if (types.length == 4 && types[0] == String JavaDoc.class && types[1] == String JavaDoc.class && types[2] == String JavaDoc.class
419                  && types[3] == int.class) {
420         // This is 1.5
421
return createStackTraceElementJDK15(clazz, constructors[i], className, fileName, methodName, lineNumber);
422       }
423     }
424     throw new ClassNotFoundException JavaDoc("java.lang.StackTraceElement : Both known constructors not found !");
425   }
426
427   private Object JavaDoc createStackTraceElementJDK14(Class JavaDoc clazz, Constructor JavaDoc constructor, String JavaDoc className, String JavaDoc fileName,
428                                               String JavaDoc methodName, int lineNumber) throws IOException JavaDoc {
429     try {
430       constructor.setAccessible(true);
431       Object JavaDoc i = constructor.newInstance(new Object JavaDoc[0]);
432       Field JavaDoc[] 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 JavaDoc ex) {
453       IOException JavaDoc ioe = new IOException JavaDoc();
454       ioe.initCause(ex);
455       throw ioe;
456     }
457   }
458
459   private Object JavaDoc createStackTraceElementJDK15(Class JavaDoc clazz, Constructor JavaDoc constructor, String JavaDoc className, String JavaDoc fileName,
460                                               String JavaDoc methodName, int lineNumber) throws IOException JavaDoc {
461     try {
462       Object JavaDoc params[] = new Object JavaDoc[4];
463       params[0] = className;
464       params[1] = methodName;
465       params[2] = fileName;
466       params[3] = new Integer JavaDoc(lineNumber);
467       return constructor.newInstance(params);
468     } catch (Exception JavaDoc ex) {
469       IOException JavaDoc ioe = new IOException JavaDoc();
470       ioe.initCause(ex);
471       throw ioe;
472     }
473   }
474
475   public void encodeArray(Object JavaDoc value, TCDataOutput output) {
476     encodeArray(value, output, value == null ? -1 : Array.getLength(value));
477   }
478
479   public void encodeArray(Object JavaDoc 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 JavaDoc 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 JavaDoc[]) 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 JavaDoc[] 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 JavaDoc 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 JavaDoc decodeArray(TCDataInput input) throws IOException JavaDoc, ClassNotFoundException JavaDoc {
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     // unreachable
611
}
612
613   private Object JavaDoc[] decodeNonPrimitiveArray(int len, TCDataInput input) throws IOException JavaDoc, ClassNotFoundException JavaDoc {
614     checkSize(Object JavaDoc.class, REF_WARN, len);
615     Object JavaDoc[] rv = new Object JavaDoc[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 JavaDoc decodePrimitiveArray(int len, TCDataInput input) throws IOException JavaDoc {
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     // unreachable
656
}
657
658   private short[] decodeShortArray(int len, TCDataInput input) throws IOException JavaDoc {
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 JavaDoc {
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 JavaDoc {
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 JavaDoc {
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 JavaDoc {
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 JavaDoc {
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 JavaDoc {
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 JavaDoc("read " + read + " bytes, expected " + len); }
711     }
712     return rv;
713   }
714
715   private boolean[] decodeBooleanArray(int len, TCDataInput input) throws IOException JavaDoc {
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   /**
724    * The reason that we use reflection here is because Enum is a jdk 1.5 construct and this project is jdk 1.4
725    * compliance.
726    */

727   private Object JavaDoc enumValueOf(Class JavaDoc enumType, String JavaDoc enumName) {
728     try {
729       Method JavaDoc m = enumType.getMethod("valueOf", new Class JavaDoc[] { Class JavaDoc.class, String JavaDoc.class });
730       Object JavaDoc enumObj = m.invoke(null, new Object JavaDoc[] { enumType, enumName });
731       return enumObj;
732     } catch (SecurityException JavaDoc e) {
733       throw new TCRuntimeException(e);
734     } catch (NoSuchMethodException JavaDoc e) {
735       throw new TCRuntimeException(e);
736     } catch (IllegalArgumentException JavaDoc e) {
737       throw new TCRuntimeException(e);
738     } catch (IllegalAccessException JavaDoc e) {
739       throw new TCRuntimeException(e);
740     } catch (InvocationTargetException JavaDoc e) {
741       throw new TCRuntimeException(e);
742     }
743   }
744
745   private Object JavaDoc readEnum(TCDataInput input, byte type) throws IOException JavaDoc, ClassNotFoundException JavaDoc {
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 JavaDoc enumType = new ClassInstance(name, def).asClass(classProvider);
752
753       String JavaDoc enumName = new String JavaDoc(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 JavaDoc readClassLoader(TCDataInput input, byte type) throws IOException JavaDoc {
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 JavaDoc readClass(TCDataInput input, byte type) throws IOException JavaDoc, ClassNotFoundException JavaDoc {
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 JavaDoc readString(TCDataInput input, byte type) throws IOException JavaDoc {
784     byte[] data = readByteArray(input);
785     if ((policy == SERIALIZER && type == TYPE_ID_STRING) || policy == APPLICATOR) {
786       return new String JavaDoc(data, "UTF-8");
787     } else {
788       return new UTF8ByteDataHolder(data);
789     }
790   }
791
792   private static class FailureClassProvider implements ClassProvider {
793
794     public Class JavaDoc getClassFor(String JavaDoc className, String JavaDoc loaderDesc) {
795       throw new AssertionError JavaDoc();
796     }
797
798     public String JavaDoc getLoaderDescriptionFor(Class JavaDoc clazz) {
799       throw new AssertionError JavaDoc();
800     }
801
802     public ClassLoader JavaDoc getClassLoader(String JavaDoc loaderDesc) {
803       throw new AssertionError JavaDoc();
804     }
805
806     public String JavaDoc getLoaderDescriptionFor(ClassLoader JavaDoc loader) {
807       throw new AssertionError JavaDoc();
808     }
809
810     public void registerNamedLoader(NamedClassLoader loader) {
811       throw new AssertionError JavaDoc();
812     }
813   }
814
815   private static class LocalClassProvider implements ClassProvider {
816
817     private static final String JavaDoc LOADER_ID = LocalClassProvider.class.getName() + "::CLASSPROVIDER";
818
819     // This method assumes the Class is visible in this VM and can be loaded by the same class loader as this
820
// object. Only used in SERIALIZER policy
821
public Class JavaDoc getClassFor(String JavaDoc className, String JavaDoc loaderDesc) {
822       Assert.assertEquals(LOADER_ID, loaderDesc);
823       try {
824         return Class.forName(className);
825       } catch (ClassNotFoundException JavaDoc e) {
826         throw new AssertionError JavaDoc(e);
827       }
828     }
829
830     public String JavaDoc getLoaderDescriptionFor(Class JavaDoc clazz) {
831       return LOADER_ID;
832     }
833
834     public ClassLoader JavaDoc getClassLoader(String JavaDoc loaderDesc) {
835       Assert.assertEquals(LOADER_ID, loaderDesc);
836       return ClassLoader.getSystemClassLoader();
837     }
838
839     public String JavaDoc getLoaderDescriptionFor(ClassLoader JavaDoc loader) {
840       return LOADER_ID;
841     }
842
843     public void registerNamedLoader(NamedClassLoader loader) {
844       // do nothing
845
}
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