1 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 ; 21 import java.io.ByteArrayOutputStream ; 22 import java.io.File ; 23 import java.io.FileInputStream ; 24 import java.io.FileOutputStream ; 25 import java.io.IOException ; 26 import java.io.InputStream ; 27 import java.io.ObjectInputStream ; 28 import java.io.ObjectOutputStream ; 29 import java.io.ObjectStreamClass ; 30 import java.io.Serializable ; 31 import java.lang.reflect.Constructor ; 32 import java.lang.reflect.Modifier ; 33 import java.util.ArrayList ; 34 import java.util.Arrays ; 35 import java.util.Collection ; 36 import java.util.Collections ; 37 import java.util.Date ; 38 import java.util.HashMap ; 39 import java.util.HashSet ; 40 import java.util.Hashtable ; 41 import java.util.IdentityHashMap ; 42 import java.util.Iterator ; 43 import java.util.LinkedList ; 44 import java.util.List ; 45 import java.util.Map ; 46 import java.util.Set ; 47 import java.util.TreeMap ; 48 import java.util.TreeSet ; 49 50 54 public class SerializationTest extends BaseDSOTestCase { 55 56 private static final Set disabled = new HashSet (); 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 { 65 BootJar bj = BootJar.getDefaultBootJarForReading(); 66 67 Set specs = bj.getAllPreInstrumentedClasses(); 68 for (Iterator iter = specs.iterator(); iter.hasNext();) { 69 String className = (String ) iter.next(); 70 checkSerialization(className); 71 } 72 } 73 74 public void testCollectionInnerClasses() throws Exception { 75 validateSerialization(Collections.EMPTY_LIST); 76 validateSerialization(Collections.EMPTY_SET); 77 validateSerialization(Collections.EMPTY_MAP); 78 79 validateSerialization(Collections.unmodifiableList(new LinkedList ())); 81 validateSerialization(Collections.unmodifiableList(new ArrayList ())); 83 84 validateSerialization(Collections.unmodifiableCollection(new LinkedList ())); 85 validateSerialization(Collections.synchronizedList(new LinkedList ())); 86 validateSerialization(Collections.synchronizedList(new ArrayList ())); 87 validateSerialization(Collections.synchronizedMap(new HashMap ())); 88 validateSerialization(Collections.synchronizedSet(new HashSet ())); 89 validateSerialization(Collections.synchronizedCollection(new LinkedList ())); 90 } 91 92 public void testIfTheTestIsRunningWithBootJar() throws Exception { 93 assertTrue(isHashMapDSOInstrumented()); 94 } 95 96 public void testSubclassOfMapSerialization() throws Exception { 97 validateSubclassOfMapSerialization(MyHashMap.class.getName()); 98 99 validateSubclassOfMapSerialization(MyHashtable.class.getName()); 100 } 101 102 public void testSubclassofCollectionSerialization() throws Exception { 103 validateSubclassOfCollectionSerialization(MyArrayList.class.getName()); 104 validateSubclassOfCollectionSerialization(MyHashSet.class.getName()); 105 } 106 107 private void validateSubclassOfMapSerialization(String mapclassName) throws Exception { 108 ClassLoader 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 clazz = classLoader.loadClass(mapclassName); 122 Map o = (Map ) 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 mapclassName) throws Exception { 134 ClassLoader 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 clazz = classLoader.loadClass(mapclassName); 148 Collection o = (Collection ) 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 c = HashMap .class; 161 Class [] 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 className) throws Exception { 170 if (className.startsWith("com.tc.") || (className.indexOf('$') > 0)) { 171 return; 173 } 174 175 Class klass = Class.forName(className); 176 177 int access = klass.getModifiers(); 178 if (Modifier.isAbstract(access) || !Modifier.isPublic(access)) { 179 return; 181 } 182 183 Constructor cstr; 184 try { 185 cstr = klass.getConstructor(new Class [] {}); 186 } catch (Exception e) { 187 return; 189 } 190 191 Object o = cstr.newInstance(new Object [] {}); 192 193 if (!(o instanceof Serializable )) { 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 o) { 206 if (o.getClass() == IdentityHashMap .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 o) throws Exception { 215 System.out.println("TESTING " + o.getClass()); 216 assertTrue(o instanceof Serializable ); 217 218 deserialize(serialize(o), o.getClass().getClassLoader()); 219 } 220 221 private void validateSerializationForSubclass(Object o, ClassLoader loader) throws Exception { 222 System.out.println("TESTING " + o.getClass()); 223 assertTrue(o instanceof Serializable ); 224 225 deserialize(serialize(o), loader); 226 } 227 228 private void validateExternalSerialization(Object o) throws Exception { 229 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 n = externallySerialize(o); 237 verify(o, n); 238 } 239 240 private void verify(Object o, Object n) { 241 Class co = o.getClass(); 242 Class cn = n.getClass(); 243 if (co.getName().equals(cn.getName())) { 244 if (o instanceof IdentityHashMap ) { 245 verifyIdentifyHashMap((IdentityHashMap ) o, (IdentityHashMap ) 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 (n); 256 } 257 } 258 259 private boolean equalsMethodPresent(Class c) { 260 Class oc = Object .class; 261 Class [] params = new Class [] { oc }; 262 while (c != oc) { 263 try { 264 c.getDeclaredMethod("equals", params); 265 break; 267 } catch (SecurityException e) { 268 throw new AssertionError (e); 269 } catch (NoSuchMethodException e) { 270 c = c.getSuperclass(); 272 } 273 } 274 return c != oc; 275 } 276 277 private void verifyStringifiedVersion(Object o, Object n) { 278 String so = String.valueOf(o); 279 String sn = String.valueOf(n); 280 if (so != null && so.startsWith(o.getClass().getName() + "@")) { 281 assertTrue(sn.startsWith(o.getClass().getName() + "@")); 283 } else { 284 assertEquals(so, sn); 285 } 286 } 287 288 private void verifyIdentifyHashMap(IdentityHashMap map1, IdentityHashMap map2) { 289 Map m1 = new HashMap (map1); 290 Map m2 = new HashMap (map2); 291 assertEquals(m1, m2); 292 } 293 294 private static Object deserialize(byte[] data, ClassLoader loader) throws IOException , ClassNotFoundException { 295 ObjectInputStream ois = new MyObjectInputStream(new ByteArrayInputStream (data), loader); 299 Object rv = ois.readObject(); 300 ois.close(); 301 return rv; 302 } 303 304 private static byte[] serialize(Object obj) throws IOException { 305 ByteArrayOutputStream baos = new ByteArrayOutputStream (); 306 ObjectOutputStream oos = new ObjectOutputStream (baos); 307 oos.writeObject(obj); 308 oos.close(); 309 return baos.toByteArray(); 310 } 311 312 private Object externallySerialize(Object m) throws Exception { 313 File base = getTempFile(m.getClass().getName()); 314 File out = new File (base.getAbsolutePath() + ".out"); 315 File in = new File (base.getAbsolutePath() + ".in"); 316 317 FileOutputStream fos = new FileOutputStream (out); 318 fos.write(serialize(m)); 319 fos.close(); 320 321 LinkedJavaProcess process = new LinkedJavaProcess(ExternalSerializer.class.getName(), new String [] { 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 recvBytes = new ByteArrayOutputStream (); 341 FileInputStream fis = new FileInputStream (in); 342 IOUtils.copy(fis, recvBytes); 343 fis.close(); 344 345 return deserialize(recvBytes.toByteArray(), this.getClass().getClassLoader()); 346 } 347 348 private Object populateData(Object o) { 349 if (o instanceof TreeMap ) { 350 populateTreeMap((TreeMap ) o); 351 } else if (o instanceof TreeSet ) { 352 populateTreeSet((TreeSet ) o); 353 } else if (o instanceof Map ) { 354 populateMap((Map ) o); 355 } else if (o instanceof Set ) { 356 populateSet((Set ) o); 357 } else if (o instanceof List ) { 358 populateList((List ) o); 359 } 360 return o; 361 } 362 363 private void populateTreeSet(TreeSet 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 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 m) { 378 m.put("Hello", "Saro"); 379 m.put(new Integer (99), new Long (88)); 380 m.put(new Date (), new Double (454.4545)); 381 } 382 383 private void populateSet(Set set) { 384 set.add("Hello Saro"); 385 set.add(new Integer (343)); 386 set.add(new Long (33434343)); 387 set.add(new Date ()); 388 set.add(new Double (34343.23)); 389 } 390 391 private void populateList(List list) { 392 list.add("Hey you "); 393 list.add(new Integer (34343)); 394 list.add(new Long (33434343)); 395 list.add(new Date ()); 396 list.add(new Double (34343.23)); 397 } 398 399 public static class ExternalSerializer { 400 401 public static void main(String args[]) { 402 if (isHashMapDSOInstrumented()) { throw new AssertionError ("HashMap is instrumented in the external verifier!"); } 403 404 ExternalSerializer e = new ExternalSerializer(); 405 try { 406 e.execute(args); 407 } catch (Throwable t) { 408 t.printStackTrace(); 409 System.exit(1); 410 } 411 System.exit(0); 412 } 413 414 private void execute(String [] args) throws Exception { 415 if (args.length != 2) { throw new AssertionError ("Bad args: " + Arrays.asList(args)); } 416 417 File readFrom = new File (args[0]); 418 File writeTo = new File (args[1]); 419 420 ByteArrayOutputStream readBytes = new ByteArrayOutputStream (); 421 FileInputStream in = new FileInputStream (readFrom); 422 IOUtils.copy(in, readBytes); 423 in.close(); 424 425 Object o = deserialize(readBytes.toByteArray(), this.getClass().getClassLoader()); 426 427 FileOutputStream out = new FileOutputStream (writeTo); 428 out.write(serialize(o)); 429 out.close(); 430 } 431 } 432 433 public static class MyHashMap extends HashMap { 434 private Object key; 435 private Object value; 436 437 public MyHashMap() { 438 super(); 439 } 440 441 public Object getKey() { 442 return key; 443 } 444 445 public Object getValue() { 446 return value; 447 } 448 } 449 450 public static class MyHashtable extends Hashtable { 451 private Object key; 452 private Object value; 453 454 public MyHashtable() { 455 super(); 456 } 457 458 public Object getKey() { 459 return key; 460 } 461 462 public Object getValue() { 463 return value; 464 } 465 } 466 467 public static class MyArrayList extends ArrayList { 468 private Object index; 469 470 public MyArrayList() { 471 super(); 472 } 473 474 public Object getIndex() { 475 return index; 476 } 477 } 478 479 public static class MyHashSet extends HashSet { 480 private Object index; 481 482 public MyHashSet() { 483 super(); 484 } 485 486 public Object getIndex() { 487 return index; 488 } 489 } 490 491 private static class MyObjectInputStream extends ObjectInputStream { 492 private static final Set useCustomLoaderClasses = new HashSet (); 493 private ClassLoader 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 loader) throws IOException { 503 super(); 504 this.loader = loader; 505 } 506 507 public MyObjectInputStream(InputStream inputStream, ClassLoader loader) throws IOException { 508 super(inputStream); 509 this.loader = loader; 510 } 511 512 protected Class resolveClass(ObjectStreamClass desc) throws IOException , ClassNotFoundException { 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 |