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.tc.simulator.container;
006:
007: import EDU.oswego.cs.dl.util.concurrent.SynchronizedBoolean;
008:
009: import com.tc.simulator.app.Application;
010: import com.tc.simulator.app.ApplicationBuilder;
011: import com.tc.simulator.app.ApplicationInstantiationException;
012: import com.tc.simulator.app.ErrorContext;
013: import com.tc.simulator.app.GlobalIdGenerator;
014: import com.tc.simulator.control.Control;
015: import com.tc.simulator.control.TCBrokenBarrierException;
016: import com.tc.simulator.listener.MutationCompletionListener;
017: import com.tc.simulator.listener.OutputListener;
018: import com.tc.simulator.listener.ResultsListener;
019: import com.tc.simulator.listener.StatsListenerFactory;
020: import com.tc.util.Assert;
021: import com.tcsimulator.ControlImpl;
022: import com.tcsimulator.listener.ApplicationListenerProvider;
023:
024: import java.util.ArrayList;
025: import java.util.Iterator;
026: import java.util.List;
027:
028: public final class Container implements Runnable {
029: private static final boolean DEBUG = false;
030:
031: private final ContainerConfig config;
032: private final ContainerState containerState;
033: private final GlobalIdGenerator idGenerator;
034: private final Control control;
035: private final ResultsListener resultsListener;
036: private final ApplicationBuilder applicationBuilder;
037: private final String globalId;
038: private final boolean isMutateValidateTest;
039: private final boolean isMutator;
040: private final MutationCompletionListener mutationCompletionListener;
041: private final ControlImpl applicationControl;
042:
043: public Container(ContainerConfig config,
044: ContainerStateFactory containerStateFactory,
045: GlobalIdGenerator idGenerator, Control control,
046: ResultsListener resultsListener,
047: ApplicationBuilder applicationBuilder) {
048: this (config, containerStateFactory, idGenerator, control,
049: resultsListener, applicationBuilder, false, true);
050: }
051:
052: public Container(ContainerConfig config,
053: ContainerStateFactory containerStateFactory,
054: GlobalIdGenerator idGenerator, Control control,
055: ResultsListener resultsListener,
056: ApplicationBuilder applicationBuilder,
057: boolean isMutateValidateTest, boolean isMutator) {
058: this .config = config;
059: this .idGenerator = idGenerator;
060: this .control = control;
061: this .resultsListener = resultsListener;
062: this .applicationBuilder = applicationBuilder;
063: this .isMutateValidateTest = isMutateValidateTest;
064: this .isMutator = isMutator;
065: this .globalId = this .idGenerator.nextId() + "";
066:
067: applicationControl = new ControlImpl(this .config
068: .getApplicationInstanceCount(), this .control);
069: applicationControl.setExecutionTimeout(this .config
070: .getApplicationExecutionTimeout());
071:
072: mutationCompletionListener = applicationControl;
073:
074: this .containerState = containerStateFactory
075: .newContainerState(this .globalId);
076: Assert.assertNoNullElements(new Object[] { this .config,
077: this .idGenerator, this .control, this .resultsListener,
078: this .applicationBuilder });
079: }
080:
081: /**
082: * Make applications go.
083: */
084: public synchronized void run() {
085: debugPrintln("isMutateValidateTest=[" + isMutateValidateTest
086: + "]");
087:
088: Thread.currentThread().setContextClassLoader(
089: applicationBuilder.getContextClassLoader());
090:
091: SynchronizedBoolean isRunning = new SynchronizedBoolean(true);
092: try {
093: if (!validateConfig())
094: return;
095: debugPrintln("***** config is alright");
096:
097: if (isMutator) {
098: debugPrintln("******* isMutator=[" + isMutator + "]");
099: if (!waitForStart())
100: return;
101: } else {
102: if (!waitForMutationCompleteTestWide())
103: return;
104: }
105:
106: ContainerExecutionInstance containerExecution = new ContainerExecutionInstance();
107:
108: startInstances(containerExecution);
109:
110: if (isMutateValidateTest) {
111: if (isMutator) {
112: // wait for all app instances to complete mutation
113: if (!waitForMutationComplete())
114: return;
115: control.notifyMutationComplete();
116: }
117: if (!waitForValidationStart())
118: return;
119: control.notifyValidationStart();
120: }
121:
122: if (!waitForAllComplete())
123: return;
124:
125: notifyResult(containerExecution);
126:
127: } catch (Throwable t) {
128: notifyError("Unexpected error executing application.", t);
129: } finally {
130: isRunning.set(false);
131: control.notifyComplete();
132: try {
133: this .control.waitForAllComplete(this .config
134: .getApplicationExecutionTimeout());
135: } catch (InterruptedException e) {
136: e.printStackTrace();
137: }
138: }
139: }
140:
141: private void debugPrintln(String s) {
142: if (DEBUG) {
143: System.err.println(s);
144: }
145: }
146:
147: private boolean validateConfig() {
148: if (this .config.getContainerStartTimeout() < 1) {
149: notifyError(new ContainerConfigException(
150: "Container start timeout must be greater than zero.",
151: ContainerConfigException.INVALID_CONTAINER_START_TIMEOUT));
152: return false;
153: }
154: if (this .config.getApplicationStartTimeout() < 1) {
155: notifyError(new ContainerConfigException(
156: "Application start timeout must be greater than zero.",
157: ContainerConfigException.INVALID_APPLICATION_START_TIMEOUT));
158: return false;
159: }
160: if (this .config.getApplicationExecutionTimeout() == 0) {
161: notifyError(new ContainerConfigException(
162: "Application execution timeout must be greater than or less than zero.",
163: ContainerConfigException.INVALID_APPLICATION_EXECUTION_TIMEOUT));
164: return false;
165: }
166: if (this .config.getApplicationInstanceCount() < 1) {
167: notifyError(new ContainerConfigException(
168: "Application instance count must be greater than zero.",
169: ContainerConfigException.INVALID_APPLICATION_INSTANCE_COUNT));
170: return false;
171: }
172: return true;
173: }
174:
175: private boolean waitForStart() throws TCBrokenBarrierException,
176: InterruptedException {
177: boolean rv = false;
178: println("Waiting for all containers to start...");
179: this .control.waitForStart();
180: rv = true;
181: println("Done waiting for all containers to start.");
182: return rv;
183: }
184:
185: private boolean waitForMutationCompleteTestWide()
186: throws InterruptedException {
187: boolean rv = false;
188: println("Waiting for all containers to finish mutation...");
189: this .control.waitForMutationComplete(config
190: .getApplicationExecutionTimeout());
191: rv = true;
192: println("Done waiting for all containers to finish mutation.");
193: return rv;
194: }
195:
196: /*********************************************************************************************************************
197: * Private stuff
198: */
199:
200: private ApplicationExecutionInstance newExecutionInstance(
201: ContainerExecutionInstance containerExecution)
202: throws ApplicationInstantiationException {
203: String appId = this .idGenerator.nextId() + "";
204: System.err.println("Creating new execution instance: " + appId);
205: OutputListener outputListener = this .containerState
206: .newOutputListener();
207: ApplicationExecutionInstance executionInstance = new ApplicationExecutionInstance(
208: containerExecution, applicationControl,
209: this .containerState);
210:
211: ApplicationListenerProvider appListeners = new ApplicationListenerProvider(
212: outputListener, executionInstance,
213: this .mutationCompletionListener, this .containerState);
214:
215: if (isMutateValidateTest) {
216: debugPrintln("****** Container: appId=[" + appId
217: + "] isMutator=[" + isMutator
218: + "] isMutateValidateTest=[" + isMutateValidateTest
219: + "]");
220: applicationBuilder.setAppConfigAttribute(appId, ""
221: + isMutator);
222: }
223:
224: Application application = applicationBuilder.newApplication(
225: appId, appListeners);
226: executionInstance.setApplication(application);
227:
228: return executionInstance;
229: }
230:
231: private void println(String msg) {
232: System.out.println("Container: " + msg);
233: }
234:
235: private void startInstances(
236: ContainerExecutionInstance containerExecution)
237: throws ApplicationInstantiationException {
238: println("Starting application execution...");
239: for (int i = 0; i < config.getApplicationInstanceCount(); i++) {
240: println("exeution " + (i + 1) + " of "
241: + config.getApplicationInstanceCount());
242: ApplicationExecutionInstance executionInstance = newExecutionInstance(containerExecution);
243: containerExecution.addExecution(executionInstance);
244: executionInstance.start();
245: }
246: println("All application executions are started.");
247: }
248:
249: private boolean waitForAllComplete() throws InterruptedException {
250: println("Waiting for all applications to complete. Timeout: "
251: + config.getApplicationExecutionTimeout());
252: if (!applicationControl.waitForAllComplete(config
253: .getApplicationExecutionTimeout())) {
254: resultsListener.notifyExecutionTimeout();
255: notifyFailure();
256: println("Application execution timed out.");
257: return false;
258: }
259: println("Application execution completed.");
260: return true;
261: }
262:
263: private boolean waitForMutationComplete()
264: throws InterruptedException {
265: println("Waiting for all applications to finish mutation. Timeout: "
266: + config.getApplicationExecutionTimeout());
267: if (!applicationControl.waitForMutationComplete(config
268: .getApplicationExecutionTimeout())) {
269: resultsListener.notifyExecutionTimeout();
270: notifyFailure();
271: println("Application execution timed out.");
272: return false;
273: }
274: println("Application mutation completed.");
275: return true;
276: }
277:
278: private boolean waitForValidationStart()
279: throws InterruptedException {
280: println("Waiting for all applications/participants to be ready to begin validation. Timeout: "
281: + config.getApplicationExecutionTimeout());
282: if (!applicationControl.waitForValidationStart(config
283: .getApplicationExecutionTimeout())) {
284: resultsListener.notifyExecutionTimeout();
285: notifyFailure();
286: println("Application execution timed out.");
287: return false;
288: }
289: println("Application ready to start validation.");
290: return true;
291: }
292:
293: private void notifyError(Throwable t) {
294: notifyError("", t);
295: }
296:
297: private void notifyError(String message, Throwable t) {
298: notifyError(new ErrorContext(message, t));
299: }
300:
301: private void notifyError(ErrorContext ctxt) {
302: ctxt.dump(System.err);
303: this .resultsListener.notifyError(ctxt);
304: notifyFailure();
305: }
306:
307: private void notifyFailure() {
308: System.err.println(Thread.currentThread() + ": failure");
309: Thread.dumpStack();
310: this .resultsListener.notifyResult(new ContainerResult());
311: }
312:
313: private void notifyResult(
314: ContainerExecutionInstance containerExecution) {
315: this .resultsListener.notifyResult(new ContainerResult(
316: containerExecution));
317: }
318:
319: private ApplicationRunner newApplicationRunner(Control appControl,
320: ResultsListener appRunnerResultsListener,
321: Application application,
322: StatsListenerFactory statsListenerFactory) {
323:
324: ApplicationRunnerConfig exeConfig = new ApplicationRunnerConfig() {
325: public long getStartTimeout() {
326: return config.getApplicationStartTimeout();
327: }
328: };
329:
330: ApplicationRunner runner = new ApplicationRunner(exeConfig,
331: appControl, appRunnerResultsListener, application,
332: statsListenerFactory);
333:
334: return runner;
335: }
336:
337: /*********************************************************************************************************************
338: * Helper classes.
339: */
340:
341: static final class ContainerExecutionInstance {
342: private final List executions = new ArrayList();
343: private boolean applicationStartTimeout = false;
344: private boolean applicationExecutionTimeout = false;
345:
346: synchronized void addExecution(
347: ApplicationExecutionInstance execution) {
348: this .executions.add(execution);
349: }
350:
351: synchronized int getExecutionCount() {
352: return this .executions.size();
353: }
354:
355: synchronized void notifyApplicationStartTimeout() {
356: this .applicationStartTimeout = true;
357: }
358:
359: synchronized void notifyApplicationExecutionTimeout() {
360: this .applicationExecutionTimeout = true;
361: }
362:
363: private synchronized boolean compileResults() {
364: boolean result = true;
365: for (Iterator i = executions.iterator(); i.hasNext();) {
366: ApplicationExecutionInstance execution = (ApplicationExecutionInstance) i
367: .next();
368: if (!execution.application
369: .interpretResult(execution.result))
370: result = false;
371: }
372: return result;
373: }
374:
375: synchronized boolean getResult() {
376: boolean compiledResults = compileResults();
377: System.err.println("start timeout: "
378: + this .applicationStartTimeout);
379: System.err.println("execution timeout: "
380: + this .applicationExecutionTimeout);
381: System.err.println("compiled results: " + compiledResults);
382: return !this .applicationStartTimeout
383: && !this .applicationExecutionTimeout
384: && compiledResults;
385: }
386: }
387:
388: final class ApplicationExecutionInstance implements ResultsListener {
389: private final ContainerExecutionInstance containerExecution;
390: private final Control appControl;
391: private Application application;
392: private Object result;
393: private final StatsListenerFactory statsListenerFactory;
394:
395: ApplicationExecutionInstance(
396: ContainerExecutionInstance containerExecution,
397: Control control,
398: StatsListenerFactory statsListenerFactory) {
399: this .containerExecution = containerExecution;
400: this .appControl = control;
401: this .statsListenerFactory = statsListenerFactory;
402: }
403:
404: void setApplication(Application app) {
405: this .application = app;
406: }
407:
408: void start() {
409: ApplicationRunner runner = newApplicationRunner(appControl,
410: this , this .application, this .statsListenerFactory);
411:
412: ClassLoader loader = application.getClass()
413: .getClassLoader();
414: Thread thread = new Thread(runner);
415: thread.setContextClassLoader(loader);
416: thread.start();
417: }
418:
419: Application getApplication() {
420: return this .application;
421: }
422:
423: public void setGlobalId(long globalId) {
424: return;
425: }
426:
427: public void notifyStartTimeout() {
428: this .containerExecution.notifyApplicationStartTimeout();
429: }
430:
431: public void notifyExecutionTimeout() {
432: this .containerExecution.notifyApplicationExecutionTimeout();
433: }
434:
435: public void notifyError(ErrorContext ectxt) {
436: Container.this .notifyError(ectxt);
437: }
438:
439: public void notifyResult(Object theResult) {
440: this .result = theResult;
441: }
442:
443: Object getResult() {
444: return this.result;
445: }
446:
447: }
448:
449: }
|