KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tctest > SerializationTest


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

4 package com.tctest;
5
6 import org.apache.commons.io.IOUtils;
7
8 import com.tc.object.BaseDSOTestCase;
9 import com.tc.object.TestClientObjectManager;
10 import com.tc.object.bytecode.Manageable;
11 import com.tc.object.bytecode.TransparentAccess;
12 import com.tc.object.config.DSOClientConfigHelper;
13 import com.tc.object.loaders.IsolationClassLoader;
14 import com.tc.object.tools.BootJar;
15 import com.tc.object.tx.MockTransactionManager;
16 import com.tc.process.LinkedJavaProcess;
17 import com.tc.process.StreamCollector;
18 import com.tc.util.runtime.Vm;
19
20 import java.io.ByteArrayInputStream JavaDoc;
21 import java.io.ByteArrayOutputStream JavaDoc;
22 import java.io.File JavaDoc;
23 import java.io.FileInputStream JavaDoc;
24 import java.io.FileOutputStream JavaDoc;
25 import java.io.IOException JavaDoc;
26 import java.io.InputStream JavaDoc;
27 import java.io.ObjectInputStream JavaDoc;
28 import java.io.ObjectOutputStream JavaDoc;
29 import java.io.ObjectStreamClass JavaDoc;
30 import java.io.Serializable JavaDoc;
31 import java.lang.reflect.Constructor JavaDoc;
32 import java.lang.reflect.Modifier JavaDoc;
33 import java.util.ArrayList JavaDoc;
34 import java.util.Arrays JavaDoc;
35 import java.util.Collection JavaDoc;
36 import java.util.Collections JavaDoc;
37 import java.util.Date JavaDoc;
38 import java.util.HashMap JavaDoc;
39 import java.util.HashSet JavaDoc;
40 import java.util.Hashtable JavaDoc;
41 import java.util.IdentityHashMap JavaDoc;
42 import java.util.Iterator JavaDoc;
43 import java.util.LinkedList JavaDoc;
44 import java.util.List JavaDoc;
45 import java.util.Map JavaDoc;
46 import java.util.Set JavaDoc;
47 import java.util.TreeMap JavaDoc;
48 import java.util.TreeSet JavaDoc;
49
50 /*
51  * TODO:: More tests needed. 1) Populated collections needs to be serialized and deserialized. 2) Serialized
52  * instrumented version of collections/objects should be deserializable by uninstrumented versions and vice versa
53  */

54 public class SerializationTest extends BaseDSOTestCase {
55
56   private static final Set JavaDoc disabled = new HashSet JavaDoc();
57
58   static {
59     disabled.add("java.util.concurrent.ConcurrentHashMap");
60     disabled.add("java.util.concurrent.LinkedBlockingQueue");
61     disabled.add("java.util.concurrent.locks.ReentrantLock");
62   }
63
64   public void testSerialization() throws Exception JavaDoc {
65     BootJar bj = BootJar.getDefaultBootJarForReading();
66
67     Set JavaDoc specs = bj.getAllPreInstrumentedClasses();
68     for (Iterator JavaDoc iter = specs.iterator(); iter.hasNext();) {
69       String JavaDoc className = (String JavaDoc) iter.next();
70       checkSerialization(className);
71     }
72   }
73
74   public void testCollectionInnerClasses() throws Exception JavaDoc {
75     validateSerialization(Collections.EMPTY_LIST);
76     validateSerialization(Collections.EMPTY_SET);
77     validateSerialization(Collections.EMPTY_MAP);
78
79     // this tests Collections$UnmodifiableList
80
validateSerialization(Collections.unmodifiableList(new LinkedList JavaDoc()));
81     // this tests Collections$UnmodifiableRandomAccessList
82
validateSerialization(Collections.unmodifiableList(new ArrayList JavaDoc()));
83
84     validateSerialization(Collections.unmodifiableCollection(new LinkedList JavaDoc()));
85     validateSerialization(Collections.synchronizedList(new LinkedList JavaDoc()));
86     validateSerialization(Collections.synchronizedList(new ArrayList JavaDoc()));
87     validateSerialization(Collections.synchronizedMap(new HashMap JavaDoc()));
88     validateSerialization(Collections.synchronizedSet(new HashSet JavaDoc()));
89     validateSerialization(Collections.synchronizedCollection(new LinkedList JavaDoc()));
90   }
91
92   public void testIfTheTestIsRunningWithBootJar() throws Exception JavaDoc {
93     assertTrue(isHashMapDSOInstrumented());
94   }
95   
96   public void testSubclassOfMapSerialization() throws Exception JavaDoc {
97     validateSubclassOfMapSerialization(MyHashMap.class.getName());
98     
99     validateSubclassOfMapSerialization(MyHashtable.class.getName());
100   }
101   
102   public void testSubclassofCollectionSerialization() throws Exception JavaDoc {
103     validateSubclassOfCollectionSerialization(MyArrayList.class.getName());
104     validateSubclassOfCollectionSerialization(MyHashSet.class.getName());
105   }
106
107   private void validateSubclassOfMapSerialization(String JavaDoc mapclassName) throws Exception JavaDoc {
108     ClassLoader JavaDoc originalLoader = Thread.currentThread().getContextClassLoader();
109
110     try {
111       DSOClientConfigHelper config = createClientConfigHelper();
112       config.addIncludePattern(SerializationTest.class.getName() + "$*");
113
114       TestClientObjectManager testClientObjectManager = new TestClientObjectManager();
115       MockTransactionManager testTransactionManager = new MockTransactionManager();
116       IsolationClassLoader classLoader = new IsolationClassLoader(config, testClientObjectManager,
117                                                                   testTransactionManager);
118       classLoader.init();
119       Thread.currentThread().setContextClassLoader(classLoader);
120
121       Class JavaDoc clazz = classLoader.loadClass(mapclassName);
122       Map JavaDoc o = (Map JavaDoc) clazz.newInstance();
123       o.put("key1", "value1");
124       o.put("key2", "value2");
125       assertTrue(o instanceof Manageable);
126       assertTrue(o instanceof TransparentAccess);
127       validateSerializationForSubclass(o, classLoader);
128     } finally {
129       Thread.currentThread().setContextClassLoader(originalLoader);
130     }
131   }
132   
133   private void validateSubclassOfCollectionSerialization(String JavaDoc mapclassName) throws Exception JavaDoc {
134     ClassLoader JavaDoc originalLoader = Thread.currentThread().getContextClassLoader();
135
136     try {
137       DSOClientConfigHelper config = createClientConfigHelper();
138       config.addIncludePattern(SerializationTest.class.getName() + "$*");
139
140       TestClientObjectManager testClientObjectManager = new TestClientObjectManager();
141       MockTransactionManager testTransactionManager = new MockTransactionManager();
142       IsolationClassLoader classLoader = new IsolationClassLoader(config, testClientObjectManager,
143                                                                   testTransactionManager);
144       classLoader.init();
145       Thread.currentThread().setContextClassLoader(classLoader);
146
147       Class JavaDoc clazz = classLoader.loadClass(mapclassName);
148       Collection JavaDoc o = (Collection JavaDoc) clazz.newInstance();
149       o.add("value1");
150       o.add("value2");
151       assertTrue(o instanceof Manageable);
152       assertTrue(o instanceof TransparentAccess);
153       validateSerializationForSubclass(o, classLoader);
154     } finally {
155       Thread.currentThread().setContextClassLoader(originalLoader);
156     }
157   }
158
159   private static boolean isHashMapDSOInstrumented() {
160     Class JavaDoc c = HashMap JavaDoc.class;
161     Class JavaDoc[] interfaces = c.getInterfaces();
162     for (int i = 0; i < interfaces.length; i++) {
163       if (interfaces[i].getName().equals(Manageable.class.getName())) { return true; }
164     }
165
166     return false;
167   }
168
169   private void checkSerialization(String JavaDoc className) throws Exception JavaDoc {
170     if (className.startsWith("com.tc.") || (className.indexOf('$') > 0)) {
171       // System.err.println("Skipping class " + className);
172
return;
173     }
174
175     Class JavaDoc klass = Class.forName(className);
176
177     int access = klass.getModifiers();
178     if (Modifier.isAbstract(access) || !Modifier.isPublic(access)) {
179       // System.err.println("Skipping " + klass);
180
return;
181     }
182
183     Constructor JavaDoc cstr;
184     try {
185       cstr = klass.getConstructor(new Class JavaDoc[] {});
186     } catch (Exception JavaDoc e) {
187       // System.err.println("No default cstr for " + klass);
188
return;
189     }
190
191     Object JavaDoc o = cstr.newInstance(new Object JavaDoc[] {});
192
193     if (!(o instanceof Serializable JavaDoc)) {
194       System.err.println("Skipping non-serializable " + klass);
195       return;
196     }
197
198     validateSerialization(o);
199
200     if (canValidateExternal(o)) {
201       validateExternalSerialization(o);
202     }
203   }
204
205   private boolean canValidateExternal(Object JavaDoc o) {
206     // Serialization of IdentityHashMap is busted on 1.4.x (http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4821217)
207
if (o.getClass() == IdentityHashMap JavaDoc.class && Vm.isJDK14()) {
208       System.err.println("Skipping " + o.getClass() + " due to Java bug 4821217");
209       return false;
210     }
211     return true;
212   }
213
214   private void validateSerialization(Object JavaDoc o) throws Exception JavaDoc {
215     System.out.println("TESTING " + o.getClass());
216     assertTrue(o instanceof Serializable JavaDoc);
217
218     deserialize(serialize(o), o.getClass().getClassLoader());
219   }
220
221   private void validateSerializationForSubclass(Object JavaDoc o, ClassLoader JavaDoc loader) throws Exception JavaDoc {
222     System.out.println("TESTING " + o.getClass());
223     assertTrue(o instanceof Serializable JavaDoc);
224
225     deserialize(serialize(o), loader);
226   }
227
228   private void validateExternalSerialization(Object JavaDoc o) throws Exception JavaDoc {
229     // TODO:: This needs to be fixed.
230
if (disabled.contains(o.getClass().getName())) {
231       System.out.println("SKIPPING External Serialization : " + o.getClass());
232       return;
233     }
234     System.out.println("TESTING External Serialization : " + o.getClass());
235     populateData(o);
236     Object JavaDoc n = externallySerialize(o);
237     verify(o, n);
238   }
239
240   private void verify(Object JavaDoc o, Object JavaDoc n) {
241     Class JavaDoc co = o.getClass();
242     Class JavaDoc cn = n.getClass();
243     if (co.getName().equals(cn.getName())) {
244       if (o instanceof IdentityHashMap JavaDoc) {
245         // Special check
246
verifyIdentifyHashMap((IdentityHashMap JavaDoc) o, (IdentityHashMap JavaDoc) n);
247       } else if (!equalsMethodPresent(co)) {
248         verifyStringifiedVersion(o, n);
249       } else {
250         assertEquals(o, n);
251       }
252     } else {
253       System.err.println("FATAL : Error trying serialize " + o);
254       System.err.println("FATAL : Recd " + n);
255       throw new AssertionError JavaDoc(n);
256     }
257   }
258
259   private boolean equalsMethodPresent(Class JavaDoc c) {
260     Class JavaDoc oc = Object JavaDoc.class;
261     Class JavaDoc[] params = new Class JavaDoc[] { oc };
262     while (c != oc) {
263       try {
264         c.getDeclaredMethod("equals", params);
265         // Got it
266
break;
267       } catch (SecurityException JavaDoc e) {
268         throw new AssertionError JavaDoc(e);
269       } catch (NoSuchMethodException JavaDoc e) {
270         // try the super class
271
c = c.getSuperclass();
272       }
273     }
274     return c != oc;
275   }
276
277   private void verifyStringifiedVersion(Object JavaDoc o, Object JavaDoc n) {
278     String JavaDoc so = String.valueOf(o);
279     String JavaDoc sn = String.valueOf(n);
280     if (so != null && so.startsWith(o.getClass().getName() + "@")) {
281       // This is a result from Object.toString()
282
assertTrue(sn.startsWith(o.getClass().getName() + "@"));
283     } else {
284       assertEquals(so, sn);
285     }
286   }
287
288   private void verifyIdentifyHashMap(IdentityHashMap JavaDoc map1, IdentityHashMap JavaDoc map2) {
289     Map JavaDoc m1 = new HashMap JavaDoc(map1);
290     Map JavaDoc m2 = new HashMap JavaDoc(map2);
291     assertEquals(m1, m2);
292   }
293
294   private static Object JavaDoc deserialize(byte[] data, ClassLoader JavaDoc loader) throws IOException JavaDoc, ClassNotFoundException JavaDoc {
295     // We need to use a subclass of ObjectInputStream because for when deserializing MyHashMap, we
296
// need to use the instrumented version of MyHashMap and that could be achieved by loading it
297
// using the same classloader that serialize it, i.e., IsolationClassLoader.
298
ObjectInputStream JavaDoc ois = new MyObjectInputStream(new ByteArrayInputStream JavaDoc(data), loader);
299     Object JavaDoc rv = ois.readObject();
300     ois.close();
301     return rv;
302   }
303
304   private static byte[] serialize(Object JavaDoc obj) throws IOException JavaDoc {
305     ByteArrayOutputStream JavaDoc baos = new ByteArrayOutputStream JavaDoc();
306     ObjectOutputStream JavaDoc oos = new ObjectOutputStream JavaDoc(baos);
307     oos.writeObject(obj);
308     oos.close();
309     return baos.toByteArray();
310   }
311
312   private Object JavaDoc externallySerialize(Object JavaDoc m) throws Exception JavaDoc {
313     File JavaDoc base = getTempFile(m.getClass().getName());
314     File JavaDoc out = new File JavaDoc(base.getAbsolutePath() + ".out");
315     File JavaDoc in = new File JavaDoc(base.getAbsolutePath() + ".in");
316
317     FileOutputStream JavaDoc fos = new FileOutputStream JavaDoc(out);
318     fos.write(serialize(m));
319     fos.close();
320
321     LinkedJavaProcess process = new LinkedJavaProcess(ExternalSerializer.class.getName(), new String JavaDoc[] {
322         out.getAbsolutePath(), in.getAbsolutePath() });
323     process.start();
324
325     process.STDIN().close();
326     StreamCollector stdout = new StreamCollector(process.STDOUT());
327     stdout.start();
328     StreamCollector stderr = new StreamCollector(process.STDERR());
329     stderr.start();
330
331     int exitCode = process.waitFor();
332
333     stdout.join();
334     stderr.join();
335
336     if (exitCode != 0) {
337       fail("exit code was " + exitCode + "\n\nSTDOUT:\n" + stdout.toString() + "\nSTDERR:\n" + stderr.toString());
338     }
339
340     ByteArrayOutputStream JavaDoc recvBytes = new ByteArrayOutputStream JavaDoc();
341     FileInputStream JavaDoc fis = new FileInputStream JavaDoc(in);
342     IOUtils.copy(fis, recvBytes);
343     fis.close();
344
345     return deserialize(recvBytes.toByteArray(), this.getClass().getClassLoader());
346   }
347
348   private Object JavaDoc populateData(Object JavaDoc o) {
349     if (o instanceof TreeMap JavaDoc) {
350       populateTreeMap((TreeMap JavaDoc) o);
351     } else if (o instanceof TreeSet JavaDoc) {
352       populateTreeSet((TreeSet JavaDoc) o);
353     } else if (o instanceof Map JavaDoc) {
354       populateMap((Map JavaDoc) o);
355     } else if (o instanceof Set JavaDoc) {
356       populateSet((Set JavaDoc) o);
357     } else if (o instanceof List JavaDoc) {
358       populateList((List JavaDoc) o);
359     }
360     return o;
361   }
362
363   private void populateTreeSet(TreeSet JavaDoc set) {
364     set.add("Saravanan Subbiah");
365     set.add("Tim Eck");
366     set.add("Cindy Fisher");
367     set.add("Steve Harris");
368   }
369
370   private void populateTreeMap(TreeMap JavaDoc map) {
371     map.put("Saravanan", "Subbiah");
372     map.put("Tim", "Eck");
373     map.put("Cindy", "Fisher");
374     map.put("Steve", "Harris");
375   }
376
377   private void populateMap(Map JavaDoc m) {
378     m.put("Hello", "Saro");
379     m.put(new Integer JavaDoc(99), new Long JavaDoc(88));
380     m.put(new Date JavaDoc(), new Double JavaDoc(454.4545));
381   }
382
383   private void populateSet(Set JavaDoc set) {
384     set.add("Hello Saro");
385     set.add(new Integer JavaDoc(343));
386     set.add(new Long JavaDoc(33434343));
387     set.add(new Date JavaDoc());
388     set.add(new Double JavaDoc(34343.23));
389   }
390
391   private void populateList(List JavaDoc list) {
392     list.add("Hey you ");
393     list.add(new Integer JavaDoc(34343));
394     list.add(new Long JavaDoc(33434343));
395     list.add(new Date JavaDoc());
396     list.add(new Double JavaDoc(34343.23));
397   }
398
399   public static class ExternalSerializer {
400
401     public static void main(String JavaDoc args[]) {
402       if (isHashMapDSOInstrumented()) { throw new AssertionError JavaDoc("HashMap is instrumented in the external verifier!"); }
403
404       ExternalSerializer e = new ExternalSerializer();
405       try {
406         e.execute(args);
407       } catch (Throwable JavaDoc t) {
408         t.printStackTrace();
409         System.exit(1);
410       }
411       System.exit(0);
412     }
413
414     private void execute(String JavaDoc[] args) throws Exception JavaDoc {
415       if (args.length != 2) { throw new AssertionError JavaDoc("Bad args: " + Arrays.asList(args)); }
416
417       File JavaDoc readFrom = new File JavaDoc(args[0]);
418       File JavaDoc writeTo = new File JavaDoc(args[1]);
419
420       ByteArrayOutputStream JavaDoc readBytes = new ByteArrayOutputStream JavaDoc();
421       FileInputStream JavaDoc in = new FileInputStream JavaDoc(readFrom);
422       IOUtils.copy(in, readBytes);
423       in.close();
424
425       Object JavaDoc o = deserialize(readBytes.toByteArray(), this.getClass().getClassLoader());
426
427       FileOutputStream JavaDoc out = new FileOutputStream JavaDoc(writeTo);
428       out.write(serialize(o));
429       out.close();
430     }
431   }
432
433   public static class MyHashMap extends HashMap JavaDoc {
434     private Object JavaDoc key;
435     private Object JavaDoc value;
436
437     public MyHashMap() {
438       super();
439     }
440
441     public Object JavaDoc getKey() {
442       return key;
443     }
444
445     public Object JavaDoc getValue() {
446       return value;
447     }
448   }
449   
450   public static class MyHashtable extends Hashtable JavaDoc {
451     private Object JavaDoc key;
452     private Object JavaDoc value;
453
454     public MyHashtable() {
455       super();
456     }
457
458     public Object JavaDoc getKey() {
459       return key;
460     }
461
462     public Object JavaDoc getValue() {
463       return value;
464     }
465   }
466   
467   public static class MyArrayList extends ArrayList JavaDoc {
468     private Object JavaDoc index;
469
470     public MyArrayList() {
471       super();
472     }
473
474     public Object JavaDoc getIndex() {
475       return index;
476     }
477   }
478   
479   public static class MyHashSet extends HashSet JavaDoc {
480     private Object JavaDoc index;
481
482     public MyHashSet() {
483       super();
484     }
485
486     public Object JavaDoc getIndex() {
487       return index;
488     }
489   }
490
491   private static class MyObjectInputStream extends ObjectInputStream JavaDoc {
492     private static final Set JavaDoc useCustomLoaderClasses = new HashSet JavaDoc();
493     private ClassLoader JavaDoc loader;
494     
495     static {
496       useCustomLoaderClasses.add(MyHashMap.class.getName());
497       useCustomLoaderClasses.add(MyHashtable.class.getName());
498       useCustomLoaderClasses.add(MyArrayList.class.getName());
499       useCustomLoaderClasses.add(MyHashSet.class.getName());
500     }
501
502     public MyObjectInputStream(ClassLoader JavaDoc loader) throws IOException JavaDoc {
503       super();
504       this.loader = loader;
505     }
506
507     public MyObjectInputStream(InputStream JavaDoc inputStream, ClassLoader JavaDoc loader) throws IOException JavaDoc {
508       super(inputStream);
509       this.loader = loader;
510     }
511
512     protected Class JavaDoc resolveClass(ObjectStreamClass JavaDoc desc) throws IOException JavaDoc, ClassNotFoundException JavaDoc {
513       if (useCustomLoaderClasses.contains(desc.getName())) {
514         return loader.loadClass(desc.getName());
515       } else {
516         return super.resolveClass(desc);
517       }
518     }
519   }
520
521 }
522
Popular Tags