001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package com.tctest.transparency;
005:
006: import org.apache.commons.collections.ArrayStack;
007: import org.apache.commons.collections.MultiHashMap;
008:
009: import com.tc.exception.TCNonPortableObjectError;
010: import com.tc.object.config.ConfigVisitor;
011: import com.tc.object.config.DSOClientConfigHelper;
012: import com.tc.object.config.TransparencyClassSpec;
013: import com.tc.simulator.app.ApplicationConfig;
014: import com.tc.simulator.listener.ListenerProvider;
015: import com.tc.util.SequenceID;
016: import com.tctest.runner.AbstractTransparentApp;
017:
018: import java.util.ArrayList;
019: import java.util.Collection;
020: import java.util.Date;
021: import java.util.HashMap;
022: import java.util.LinkedList;
023: import java.util.List;
024: import java.util.Map;
025: import java.util.Stack;
026: import java.util.TreeMap;
027: import java.util.Vector;
028:
029: public class ClassNotPortableTestApp extends AbstractTransparentApp {
030:
031: SubClassA root1;
032: SubClassB root2;
033: SubClassC root3;
034:
035: SuperClassWithFields root4;
036:
037: Object root5;
038: List root6;
039:
040: Collection root7;
041: Map root8;
042: Worker root9;
043:
044: public ClassNotPortableTestApp(String appId, ApplicationConfig cfg,
045: ListenerProvider listenerProvider) {
046: super (appId, cfg, listenerProvider);
047: }
048:
049: public static void visitL1DSOConfig(ConfigVisitor visitor,
050: DSOClientConfigHelper config) {
051: String testClass = ClassNotPortableTestApp.class.getName();
052: TransparencyClassSpec spec = config.getOrCreateSpec(testClass);
053: String methodExpression = "* " + testClass + "*.*(..)";
054: config.addIncludePattern(testClass);
055: config.addWriteAutolock(methodExpression);
056: spec.addRoot("root1", "root1");
057: spec.addRoot("root2", "root2");
058: spec.addRoot("root3", "root3");
059: spec.addRoot("root4", "root4");
060: spec.addRoot("root5", "root5");
061: spec.addRoot("root6", "root6");
062: spec.addRoot("root7", "root7");
063: spec.addRoot("root8", "root8");
064: spec.addRoot("root9", "root9");
065:
066: // Only the Subclass is instructed and its super classes are not instructed.
067: String classname1 = SubClassA.class.getName();
068: String classname2 = SubClassB.class.getName();
069: String classname3 = SubClassC.class.getName();
070:
071: String classname4 = Worker.class.getName();
072:
073: String classname5 = ArrayStack.class.getName();
074: String classname6 = MultiHashMap.class.getName();
075:
076: String classname7 = Thread.class.getName();
077:
078: config.addIncludePattern(classname1);
079: config.addIncludePattern(classname2);
080: config.addIncludePattern(classname3);
081: config.addIncludePattern(classname4);
082: config.addIncludePattern(classname5);
083: config.addIncludePattern(classname6);
084:
085: config.addIncludePattern(classname7);
086: config.addIncludePattern(ReferenceHolder.class.getName());
087: config.addIncludePattern(TreeNode.class.getName());
088:
089: config.addWriteAutolock("* " + classname1 + ".*(..)");
090: config.addWriteAutolock("* " + classname2 + ".*(..)");
091: config.addWriteAutolock("* " + classname3 + ".*(..)");
092: }
093:
094: public void run() {
095:
096: testSuperClassNotPortable();
097:
098: testNonPortableClassAddedToSharedGraph();
099:
100: //testSubclassOfCollections();
101:
102: testThreadAndSubClassOfThreads();
103:
104: testSetAndGetOnPortableAdaptableClasses();
105:
106: testComplexReferenceGraphAddedToSharedMap();
107: }
108:
109: // This test is half baked in the sense that out of 6 possible failure cases, it would probably
110: // catch 3. In the other 3 cases, it woudl still work except it might be a little slow.
111: // I dont know how to verify those cases with doing a ASM inspect on the instrumented code.
112: private void testSetAndGetOnPortableAdaptableClasses() {
113: SubClassC cc = new SubClassC();
114: cc.checkedUnCheckedSetsAndGets();
115:
116: Worker w = new Worker();
117: w.checkedUnCheckedSetsAndGets();
118: }
119:
120: private void testSuperClassNotPortable() {
121: // Should fail - behavior changed. We dont check for fields anymore
122: try {
123: root1 = new SubClassA();
124: root1.method1();
125: throw new AssertionError("Should have failed");
126: } catch (TCNonPortableObjectError tcp) {
127: // Expected
128: }
129:
130: // Should fail even if it doesnt change any of the superclasses' fields.
131: try {
132: root2 = new SubClassB();
133: root2.method1();
134: throw new AssertionError("Should have failed");
135: } catch (TCNonPortableObjectError tcp) {
136: // Expected
137: }
138:
139: // Should fail
140: try {
141: root3 = new SubClassC();
142: root3.method1();
143: throw new AssertionError("Should have failed");
144: } catch (TCNonPortableObjectError tcp) {
145: // Expected
146: }
147:
148: }
149:
150: private void testNonPortableClassAddedToSharedGraph() {
151: try {
152: root4 = new SuperClassWithFields();
153: throw new AssertionError("Should have failed");
154: } catch (TCNonPortableObjectError tcp) {
155: // Expected
156: }
157:
158: try {
159: root5 = new SuperClassWithFields();
160: throw new AssertionError("Should have failed");
161: } catch (TCNonPortableObjectError tcp) {
162: // Expected
163: }
164:
165: try {
166: root5 = new SubClassD();
167: throw new AssertionError("Should have failed");
168: } catch (TCNonPortableObjectError tcp) {
169: // Expected
170: }
171:
172: root6 = new ArrayList();
173:
174: synchronized (root6) {
175: try {
176: // Adding non-portable object to a shared object.
177: root6.add(new SuperClassWithNoFields());
178: throw new AssertionError("Should have failed");
179: } catch (TCNonPortableObjectError tcp) {
180: // Expected
181: }
182:
183: Map m = new HashMap();
184: m.put(new Integer(10), new SuperClassWithFields());
185:
186: try {
187: // Adding non-portable Map to a shared object.
188: root6.add(m);
189: throw new AssertionError("Should have failed");
190: } catch (TCNonPortableObjectError tcp) {
191: // Expected
192: }
193:
194: Map tm = new TreeMap();
195: root6.add(tm);
196:
197: try {
198: tm.put(new Integer(10), new SuperClassWithFields());
199: // Adding non-portable Map to a shared object.
200: throw new AssertionError("Should have failed");
201: } catch (TCNonPortableObjectError tcp) {
202: // Expected
203: }
204:
205: ReferenceHolder ref = new ReferenceHolder(new Integer(120));
206: root6.add(ref);
207: try {
208: ref.setReference(new SuperClassWithNoFields());
209: throw new AssertionError("Should have failed");
210: } catch (TCNonPortableObjectError tcp) {
211: // Expected
212: }
213:
214: ReferenceHolder refs[] = new ReferenceHolder[2];
215: root6.add(refs);
216: refs[0] = new ReferenceHolder("Hello String literal !");
217: try {
218: // Adding non-portable Object to a shared object.
219: refs[1] = new ReferenceHolder(
220: new SuperClassWithFields());
221: throw new AssertionError("Should have failed");
222: } catch (TCNonPortableObjectError tcp) {
223: // Expected
224: }
225:
226: // Try adding TC classes to see that it fails
227: try {
228: root6.add(new SequenceID(10));
229: throw new AssertionError("Should have failed");
230: } catch (TCNonPortableObjectError tcp) {
231: // Expected
232: }
233: }
234: }
235:
236: private void testSubclassOfCollections() {
237: int count = 13;
238: try {
239: root7 = new SubClassOfArrayList(count);
240: addSomething(root7, count);
241: System.err.println(root7);
242: throw new AssertionError("Should have failed");
243: } catch (TCNonPortableObjectError tcp) {
244: // Expected
245: }
246:
247: // Should go thru fine
248: root7 = new Stack();
249: synchronized (root7) {
250: addSomething(root7, count);
251: System.err.println(root7);
252:
253: root7.add(addSomething(new ArrayList(), 2));
254: root7.add(addSomething(new LinkedList(), 2));
255:
256: try {
257: root7.add(addSomething(new ArrayStack(), 9));
258: throw new AssertionError("Should have failed");
259: } catch (TCNonPortableObjectError tcp) {
260: // Expected
261: }
262:
263: root8 = new HashMap();
264: putSomething(root8, 3);
265: synchronized (root8) {
266:
267: root8.put(new Long(count++), new TreeMap());
268: // root8.put(new Long(count ++ ), new TObjectByteHashMap());
269:
270: try {
271: root8.put(new Long(count++), new MultiHashMap());
272: throw new AssertionError("Should have failed");
273: } catch (TCNonPortableObjectError tcp) {
274: // Expected
275: }
276: }
277:
278: // System.err.println(root8);
279: }
280: }
281:
282: private void testThreadAndSubClassOfThreads() {
283: if (root8 == null) {
284: root8 = new HashMap();
285: }
286: try {
287: synchronized (root8) {
288: root8.put("Hello Thread ", new Thread("hello (1)\n"));
289: }
290: throw new AssertionError("Should have failed");
291: } catch (TCNonPortableObjectError tcp) {
292: // Expected
293: }
294:
295: try {
296: root9 = new Worker();
297: throw new AssertionError("Should have failed");
298: } catch (TCNonPortableObjectError tcp) {
299: // Expected
300: }
301: }
302:
303: private void testComplexReferenceGraphAddedToSharedMap() {
304: if (root8 == null) {
305: root8 = new HashMap();
306: }
307: Vector v = new Vector();
308: synchronized (root8) {
309: root8.put("Shared Vector", v);
310: }
311: Object o = buildComplexStructure();
312: try {
313: synchronized (v) {
314: v.add(o);
315: }
316: throw new AssertionError("Should have failed");
317: } catch (TCNonPortableObjectError ex) {
318: // Expected
319: }
320: }
321:
322: private Object buildComplexStructure() {
323: int level = 6;
324: TreeNode root = new TreeNode();
325: buildRecursively(root, level);
326: return new ReferenceHolder(root);
327: }
328:
329: private void buildRecursively(TreeNode root, int level) {
330: root.left = new TreeNode();
331: root.right = new TreeNode();
332: level--;
333: if (level == 1) {
334: root.left = new Date();
335: root.right = getNonPortableList();
336: } else {
337: buildRecursively((TreeNode) root.left, level);
338: buildRecursively((TreeNode) root.right, level);
339: }
340: }
341:
342: private Object getNonPortableList() {
343: List l = new ArrayList();
344: int c = 10;
345: while (c-- > 0) {
346: l.add(new Date());
347: }
348: l.add(new SubClassC());
349: return l;
350: }
351:
352: private Collection addSomething(Collection root, int count) {
353: while (count > 0) {
354: synchronized (root) {
355: root.add(new Long(count--));
356: }
357: }
358: return root;
359: }
360:
361: private Map putSomething(Map root, int count) {
362: while (count > 0) {
363: synchronized (root) {
364: root.put(new Long(count), new Long(count--));
365: }
366: }
367: return root;
368: }
369:
370: static class TreeNode {
371: Object left;
372: Object right;
373:
374: TreeNode() {
375: super ();
376: }
377:
378: TreeNode(Object l, Object r) {
379: this .left = l;
380: this .right = r;
381: }
382: }
383:
384: static class ReferenceHolder {
385: Object reference;
386:
387: public ReferenceHolder(Object o) {
388: setReference(o);
389: }
390:
391: public Object getReference() {
392: return reference;
393: }
394:
395: public void setReference(Object reference) {
396: this .reference = reference;
397: }
398:
399: }
400:
401: static class SubClassOfArrayList extends ArrayList {
402: private int localint;
403:
404: SubClassOfArrayList(int localint) {
405: this .localint = localint;
406: }
407:
408: int getLocalInt() {
409: return this .localint;
410: }
411:
412: void setLocalInt(int i) {
413: this .localint = i;
414: }
415:
416: public String toString() {
417: return "SubClassOfArrayList(" + localint + "):"
418: + super .toString();
419: }
420: }
421:
422: static class SubClassOfHashMap extends HashMap {
423: private int localint;
424:
425: SubClassOfHashMap(int localint) {
426: this .localint = localint;
427: }
428:
429: int getLocalInt() {
430: return this .localint;
431: }
432:
433: void setLocalInt(int i) {
434: this .localint = i;
435: }
436:
437: public String toString() {
438: return "SubClassOfHashMap(" + localint + "):"
439: + super .toString();
440: }
441: }
442:
443: static class Worker extends Thread {
444: private List works = new ArrayList();
445: private boolean stop = false;
446:
447: private int k;
448:
449: public synchronized void addWork(Runnable r) {
450: works.add(r);
451: notifyAll();
452: }
453:
454: public void checkedUnCheckedSetsAndGets() {
455: // these should not be modified.
456: int newk = k + 109;
457: k = newk;
458:
459: // This should be checked
460: SubClassD d = new SubClassD();
461: d.d = d.d++;
462: }
463:
464: public void notSynchronizedOnMethod(Object o) {
465: synchronized (o) {
466: o.notifyAll();
467: }
468: }
469:
470: public synchronized void requestStop() {
471: stop = true;
472: notifyAll();
473: }
474:
475: public void run() {
476: while (true) {
477: while (works.isEmpty() && !stop) {
478: try {
479: wait();
480: } catch (InterruptedException e) {
481: throw new RuntimeException(e);
482: }
483: }
484: if (stop)
485: break;
486: Runnable r = (Runnable) works.remove(0);
487: r.run();
488: }
489: }
490: }
491:
492: }
|