blob: ad1bb91f9f93edc5428bc5a471c378deb28b8cae [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009 by SAP AG, Walldorf.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* SAP AG - initial API and implementation
*******************************************************************************/
package org.eclipse.jst.ws.jaxws.testutils.threading;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jst.ws.jaxws.utils.ContractChecker;
import org.eclipse.jst.ws.jaxws.utils.logging.Logger;
import org.eclipse.swt.widgets.Display;
/**
* {@link Thread} extender which is capable of providing event loop processing while the runnable is executed<br>
* A typical usage of this class should be:
*
* <pre>
* TestContextThread t = new TestContextThread(someRunnable());
* t.start();
* t.block();
* </pre>
*
* The implementation of this thread resembles to the ModalContextThread with the difference that it does not call {@link Display#sleep()} and is simplified in order to meet test requirements. The reason not to call {@link Display#sleep()} is that under certain conditions putting the display to
* sleep causes junit tests to wait forever
*
* @author Danail Branekov
*/
class TestContextThread extends Thread
{
private boolean isRunning;
private Throwable errorThrowable;
private final IProgressMonitor monitor;
private final IRunnableWithProgress runnable;
private final Display display;
TestContextThread(final IRunnableWithProgress runnable, final IProgressMonitor monitor, final Display display)
{
super();
ContractChecker.nullCheckParam(runnable, "runnable");
ContractChecker.nullCheckParam(monitor, "monitor");
isRunning = true;
this.monitor = monitor;
this.runnable = runnable;
this.setName("TestContext");
this.setDaemon(true);
this.display = display;
}
/**
* Retrieves the error throwable which happened during execution
*
* @return the error throwable or null if none
*/
public Throwable getError()
{
return errorThrowable;
}
@Override
public void run()
{
isRunning = true;
try
{
runnable.run(monitor);
} catch (Throwable t)
{
errorThrowable = t;
} finally
{
// Make sure that asynchronous events are processed by the event loop via sync execution of an "empty" runnable
display().syncExec(new Runnable()
{
public void run()
{
}
});
isRunning = false;
// Force the display to wake up
display().asyncExec(null);
}
}
/**
* Blocks the caller while the {@link Runnable} specified in the constructor is being executed.<br>
* If the caller is the UI thread, {@link Display#readAndDispatch()} is invoked in order to ensure that the event loop is processed<br>
* If the caller is not a UI thread, this method simply joins. <br>
*
* @throws IllegalStateException
* in case the method is invoked within its own thread
*/
public void block()
{
if (Thread.currentThread() == this)
{
throw new IllegalStateException("The method should not be called from inside the same thread");
}
if (Display.getCurrent() == null)
{
try
{
join();
} catch (Throwable e)
{
errorThrowable = e;
}
} else
{
while (isRunning)
{
if(!display().readAndDispatch())
{
try
{
Thread.sleep(50);
} catch (InterruptedException e)
{
// ignore
(new Logger()).logDebug(e.getMessage(), e);
}
}
}
}
}
private Display display()
{
return display;
}
}