001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005: package com.tctest;
006:
007: import com.tc.object.config.ConfigVisitor;
008: import com.tc.object.config.DSOClientConfigHelper;
009: import com.tc.object.config.TransparencyClassSpec;
010: import com.tc.simulator.app.ApplicationConfig;
011: import com.tc.simulator.listener.ListenerProvider;
012: import com.tc.util.Assert;
013: import com.tc.util.concurrent.ThreadUtil;
014: import com.tctest.runner.AbstractTransparentApp;
015:
016: import java.util.Arrays;
017: import java.util.HashMap;
018: import java.util.Map;
019: import java.util.concurrent.CyclicBarrier;
020:
021: public class EnumTestApp extends AbstractTransparentApp {
022:
023: private final DataRoot dataRoot = new DataRoot();
024: private final CyclicBarrier barrier;
025: private final Map<String, Object> raceRoot = new HashMap<String, Object>();
026: private final Map<String, ClassWithEnum> shareMap = new HashMap<String, ClassWithEnum>();
027:
028: private State stateRoot;
029:
030: public EnumTestApp(String appId, ApplicationConfig cfg,
031: ListenerProvider listenerProvider) {
032: super (appId, cfg, listenerProvider);
033: barrier = new CyclicBarrier(getParticipantCount());
034: }
035:
036: public void run() {
037: try {
038: int index = barrier.await();
039:
040: shareSubEnumTest(index);
041:
042: barrier.await();
043:
044: rootEnumTest(index);
045:
046: if (index == 0) {
047: stateRoot = State.START;
048: }
049:
050: barrier.await();
051:
052: Assert.assertTrue(stateRoot == State.START);
053:
054: barrier.await();
055:
056: if (index == 1) {
057: stateRoot = State.RUN;
058: }
059:
060: barrier.await();
061:
062: Assert.assertTrue(stateRoot == State.RUN);
063:
064: barrier.await();
065:
066: for (int i = 0; i < 100; i++) {
067: if (index == 0) {
068: stateRoot = State.START;
069: } else {
070: stateRoot = State.RUN;
071: }
072: }
073:
074: barrier.await();
075:
076: if (index == 0) {
077: dataRoot.setState(State.START);
078: }
079:
080: barrier.await();
081:
082: Assert.assertTrue(dataRoot.getState() == State.START);
083: Assert.assertEquals(0, dataRoot.getState().getStateNum());
084:
085: barrier.await();
086:
087: if (index == 1) {
088: dataRoot.setState(State.RUN);
089: dataRoot.getState().setStateNum(10);
090: }
091:
092: barrier.await();
093:
094: Assert.assertTrue(dataRoot.getState() == State.RUN);
095: if (index == 1) {
096: Assert.assertEquals(10, dataRoot.getState()
097: .getStateNum());
098: } else {
099: // Mutation in enum is not supported.
100: Assert.assertEquals(1, dataRoot.getState()
101: .getStateNum());
102: }
103:
104: barrier.await();
105:
106: if (index == 0) {
107: dataRoot.setState(State.STOP);
108: }
109:
110: barrier.await();
111:
112: Assert.assertTrue(dataRoot.getState() == State.STOP);
113: Assert.assertEquals(2, dataRoot.getState().getStateNum());
114:
115: barrier.await();
116:
117: if (index == 0) {
118: dataRoot.setStates(State.values().clone());
119: }
120:
121: barrier.await();
122:
123: Assert.assertEquals(3, dataRoot.getStates().length);
124: Assert.assertTrue(Arrays.equals(State.values(), dataRoot
125: .getStates()));
126:
127: if (index == 0) {
128: testRace();
129: }
130:
131: if (index == 0) {
132: testRace();
133: }
134:
135: System.err
136: .println("Entering final stage : Just to make the test run longer.");
137: for (int i = 0; i < 5000; i++) {
138: switch (i % 3) {
139: case 0:
140: dataRoot.setState(State.RUN);
141: break;
142: case 1:
143: dataRoot.setState(State.START);
144: break;
145: case 2:
146: dataRoot.setState(State.STOP);
147: }
148: ThreadUtil.reallySleep(10);
149: if (i % 500 == 0) {
150: System.err.println(Thread.currentThread().getName()
151: + " : Completed : " + i);
152: }
153: }
154:
155: } catch (Throwable t) {
156: notifyError(t);
157: }
158: }
159:
160: private void shareSubEnumTest(int index) throws Exception {
161: if (index == 0) {
162: synchronized (shareMap) {
163: shareMap.put("classWithEnum", new ClassWithEnum());
164: }
165: }
166:
167: barrier.await();
168:
169: synchronized (shareMap) {
170: ClassWithEnum o = shareMap.get("classWithEnum");
171: Assert.assertEquals(EnumWithSubState.RUN, o.state);
172: }
173:
174: barrier.await();
175: }
176:
177: // Don't reference this enum in any other methods except testRace() please
178: enum EnumForRace {
179: V1, V2, V3;
180: }
181:
182: private static class Ref {
183: private final EnumForRace e;
184:
185: Ref(EnumForRace e) {
186: this .e = e;
187: }
188:
189: public String toString() {
190: return "ref(" + e + ")";
191: }
192: }
193:
194: private void testRace() throws InterruptedException {
195: final Object lock1 = new Object();
196: final Object lock2 = new Object();
197:
198: synchronized (raceRoot) {
199: raceRoot.put("lock1", lock1);
200: raceRoot.put("lock1", lock2);
201: }
202:
203: final CyclicBarrier cb = new CyclicBarrier(2);
204: final EnumForRace enumInstance = EnumForRace.V1;
205:
206: Thread other = new Thread() {
207: public void run() {
208: shareWithLock(lock1, new Ref(enumInstance), raceRoot,
209: cb);
210: }
211: };
212: other.start();
213:
214: shareWithLock(lock2, new Ref(enumInstance), raceRoot, cb);
215:
216: other.join();
217: }
218:
219: private static void shareWithLock(Object lock, Object toShare,
220: Map<String, Object> root, CyclicBarrier barrier) {
221: synchronized (lock) {
222: root.put(String.valueOf(System.identityHashCode(lock)),
223: toShare);
224:
225: try {
226: barrier.await();
227: } catch (Exception e) {
228: throw new RuntimeException(e);
229: }
230: }
231: }
232:
233: private void rootEnumTest(int index) throws Exception {
234: if (index == 0) {
235: stateRoot = State.START;
236: }
237:
238: barrier.await();
239:
240: Assert.assertEquals(State.START, stateRoot);
241:
242: barrier.await();
243:
244: if (index == 1) {
245: stateRoot = State.RUN;
246: }
247:
248: barrier.await();
249:
250: Assert.assertEquals(State.RUN, stateRoot);
251:
252: barrier.await();
253: }
254:
255: public static void visitL1DSOConfig(ConfigVisitor visitor,
256: DSOClientConfigHelper config) {
257: String testClass = EnumTestApp.class.getName();
258: TransparencyClassSpec spec = config.getOrCreateSpec(testClass);
259:
260: config.addIncludePattern(testClass + "$DataRoot*");
261:
262: String methodExpression = "* " + testClass + "*.*(..)";
263: config.addWriteAutolock(methodExpression);
264:
265: methodExpression = "* " + testClass + "$DataRoot*.*(..)";
266: config.addWriteAutolock(methodExpression);
267:
268: spec.addRoot("barrier", "barrier");
269: spec.addRoot("dataRoot", "dataRoot");
270: spec.addRoot("stateRoot", "stateRoot", false);
271: spec.addRoot("raceRoot", "raceRoot");
272: spec.addRoot("shareMap", "shareMap");
273:
274: // explicitly including the enum class here exposes a bug,
275: // generally an enum type doesn't need to be included to be shared
276: config.addIncludePattern(EnumForRace.class.getName());
277: config.addIncludePattern(Ref.class.getName());
278: config.addIncludePattern(ClassWithEnum.class.getName());
279: config.addIncludePattern(EnumWithSubState.class.getName()
280: + "$*");
281: }
282:
283: public enum State {
284: START(0), RUN(1), STOP(2);
285:
286: private int stateNum;
287:
288: State(int stateNum) {
289: this .stateNum = stateNum;
290: }
291:
292: int getStateNum() {
293: return this .stateNum;
294: }
295:
296: void setStateNum(int stateNum) {
297: this .stateNum = stateNum;
298: }
299: }
300:
301: private static class DataRoot {
302: private State state;
303: private State states[];
304:
305: public DataRoot() {
306: super ();
307: }
308:
309: public synchronized void setState(State state) {
310: this .state = state;
311: }
312:
313: public synchronized State getState() {
314: return state;
315: }
316:
317: public synchronized State[] getStates() {
318: return states;
319: }
320:
321: public synchronized void setStates(State[] states) {
322: this .states = states;
323: }
324:
325: }
326:
327: public enum EnumWithSubState {
328: START {
329: void setStateNum(int stateNum) {
330: stateNum = 101;
331: }
332: },
333: RUN {
334: void setStateNum(int stateNum) {
335: stateNum = 102;
336: }
337: },
338: STOP {
339: void setStateNum(int stateNum) {
340: stateNum = 103;
341: }
342: };
343:
344: private int stateNum;
345:
346: int getStateNum() {
347: return this .stateNum;
348: }
349:
350: abstract void setStateNum(int stateNum);
351: }
352:
353: private static class ClassWithEnum {
354: private EnumWithSubState state;
355:
356: public ClassWithEnum() {
357: state = EnumWithSubState.valueOf("RUN");
358: }
359: }
360: }
|