org.assertj.swing.edt.GuiActionRunner Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of assertj-swing Show documentation
Show all versions of assertj-swing Show documentation
Fluent interface for functional GUI testing
/**
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* Copyright 2012-2015 the original author or authors.
*/
package org.assertj.swing.edt;
import static javax.swing.SwingUtilities.invokeLater;
import static javax.swing.SwingUtilities.isEventDispatchThread;
import static org.assertj.core.util.Throwables.appendStackTraceInCurrentThreadToThrowable;
import static org.assertj.swing.exception.UnexpectedException.unexpected;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
/**
* Executes instances of {@link GuiQuery} and {@link GuiTask}.
*
* @author Alex Ruiz
*/
@ThreadSafe
public class GuiActionRunner {
@GuardedBy("this")
private static boolean executeInEDT = true;
/**
* Indicates {@link GuiActionRunner} whether instances of {@link GuiQuery} and {@link GuiTask} should be executed in
* the event dispatch thread (EDT).
*
* @param b if {@code true}, GUI actions are executed in the event dispatch thread (EDT). If {@code false}, GUI
* actions are executed in the current thread.
*/
public static synchronized void executeInEDT(boolean b) {
executeInEDT = b;
}
/**
* Indicates whether instances of {@link GuiQuery} and {@link GuiTask} should be executed in the event dispatch thread
* (EDT).
*
* @return {@code true} if GUI actions are executed in the event dispatch thread, {@code false} otherwise.
*/
public static synchronized boolean executeInEDT() {
return executeInEDT;
}
/**
* Executes the given callable in the event dispatch thread (EDT). This method waits until the query has finished its
* execution.
*
* @param query the query to execute.
* @param the return type of the action to execute.
* @return the result of the query executed in the main thread.
* @throws org.assertj.swing.exception.UnexpectedException wrapping any checked exception thrown when executing
* the given query in the event dispatch thread (EDT). Unchecked exceptions are re-thrown without any
* wrapping.
* @see #execute(GuiQuery)
*/
public static @Nullable T execute(@Nonnull Callable query) {
return execute(new GuiQuery() {
@Override
protected T executeInEDT() throws Throwable {
return query.call();
}
});
}
/**
* Executes the given query in the event dispatch thread (EDT). This method waits until the query has finished its
* execution.
*
* @param query the query to execute.
* @param the return type of the action to execute.
* @return the result of the query executed in the main thread.
* @throws org.assertj.swing.exception.UnexpectedException wrapping any checked exception thrown when executing
* the given query in the
* event dispatch thread (EDT). Unchecked exceptions are re-thrown without any wrapping.
* @see #executeInEDT()
* @see #execute(Callable)
*/
public static @Nullable T execute(@Nonnull GuiQuery query) {
if (!executeInEDT) {
return executeInCurrentThread(query);
}
run(query);
return resultOf(query);
}
private static @Nullable T executeInCurrentThread(@Nonnull GuiQuery query) {
try {
return query.executeInEDT();
} catch (Throwable e) {
throw unexpected(e);
}
}
/**
* Executes the given runnable in the event dispatch thread (EDT). This method waits until the task has finished its
* execution.
*
* @param task the task to execute.
* @throws org.assertj.swing.exception.UnexpectedException wrapping any checked exception thrown when executing
* the given query in the event dispatch thread (EDT). Unchecked exceptions are re-thrown without any
* wrapping.
* @see #executeInEDT()
* @see #execute(GuiTask)
*/
public static void execute(@Nonnull GuiActionRunnable task) {
execute(new GuiTask() {
@Override
protected void executeInEDT() throws Throwable {
task.run();
}
});
}
/**
* Executes the given task in the event dispatch thread (EDT). This method waits until the task has finished its
* execution.
*
* @param task the task to execute.
* @throws org.assertj.swing.exception.UnexpectedException wrapping any checked exception thrown when executing
* the given query in the
* event dispatch thread (EDT). Unchecked exceptions are re-thrown without any wrapping.
* @see #executeInEDT()
* @see #execute(Runnable)
*/
public static void execute(@Nonnull GuiTask task) {
if (!executeInEDT) {
executeInCurrentThread(task);
return;
}
run(task);
rethrowCaughtExceptionIn(task);
}
private static void executeInCurrentThread(@Nonnull GuiTask task) {
try {
task.executeInEDT();
} catch (Throwable e) {
throw unexpected(e);
}
}
private static void run(@Nonnull final GuiAction action) {
if (isEventDispatchThread()) {
action.run();
return;
}
final CountDownLatch latch = new CountDownLatch(1);
action.executionNotification(latch);
invokeLater(action);
try {
latch.await();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
private static @Nullable T resultOf(@Nonnull GuiQuery query) {
T result = query.result();
query.clearResult();
rethrowCaughtExceptionIn(query);
return result;
}
/**
* Wraps, with a {@link UnexpectedException}, and re-throws any caught exception in the given action.
*
* @param action the given action that may have a caught exception during its execution.
* @throws UnexpectedException wrapping any checked exception thrown when executing the given query in the
* event dispatch thread (EDT). Unchecked exceptions are re-thrown without any wrapping.
*/
private static void rethrowCaughtExceptionIn(@Nonnull GuiAction action) {
Throwable caughtException = action.catchedException();
action.clearCaughtException();
if (caughtException == null) {
return;
}
if (caughtException instanceof RuntimeException) {
appendStackTraceInCurrentThreadToThrowable(caughtException, "execute");
throw (RuntimeException) caughtException;
}
if (caughtException instanceof Error) {
caughtException.fillInStackTrace();
throw (Error) caughtException;
}
throw unexpected(caughtException);
}
}