Last active
January 30, 2019 16:36
-
-
Save mpilone/6156009 to your computer and use it in GitHub Desktop.
Revisions
-
mpilone revised this gist
Aug 5, 2013 . 1 changed file with 17 additions and 7 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -3,6 +3,7 @@ import java.util.concurrent.*; import java.util.concurrent.locks.Lock; import com.vaadin.server.VaadinSession; import com.vaadin.ui.UI; import com.vaadin.ui.UIDetachedException; @@ -13,7 +14,6 @@ * {@link #doUiUpdate(Throwable)} method. * * @author mpilone */ public abstract class BackgroundUiTask implements RunnableFuture<Void> { @@ -50,8 +50,9 @@ protected void doUiUpdate() { protected abstract void doWork(); /** * A simple runnable that executes the first of two parts of a * {@link BackgroundUiTask}. The {@link BackgroundUiTask#doWork()} method will * be called and the {@link BackgroundUiTask#doneLatch} will be decremented. * * @author mpilone */ @@ -78,8 +79,10 @@ public void run() { } /** * A simple runnable that executes the second of two parts of a * {@link BackgroundUiTask}. The * {@link BackgroundUiTask#doUiUpdate(Throwable)} method will be called and * the {@link BackgroundUiTask#doneLatch} will be decremented. * * @author mpilone */ @@ -150,6 +153,9 @@ public BackgroundUiTask() { public BackgroundUiTask(UI ui) { this.ui = ui; // We wrap the runnable in a future task to get a common API to which to // delegate. The task also handles all the tricky exception handling and // thread safe cancellation. this.future = new FutureTask<Void>(new DoWorkRunnable(), null); } @@ -230,23 +236,27 @@ public boolean isDone() { @Override public void run() { // Run the initial future, the doWork runnable. ((FutureTask<Void>) future).run(); synchronized (FUTURE_MUTEX) { Throwable exception = null; try { // Check if we got an exception during execution. future.get(); } catch (Throwable ex) { exception = ex; } if (future.isCancelled()) { // Cancelled during doWork so we'll skip doUiUpdate and simply count // down. doneLatch.countDown(); } else { // Fire up doUiUpdate runnable which gets us the second future of the // task. future = ui.access(new DoUiUpdateRunnable(exception)); } } -
mpilone revised this gist
Aug 5, 2013 . 1 changed file with 12 additions and 4 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -111,16 +111,24 @@ public void run() { } } /** * The mutex for swapping futures to ensure that the active future is safely * accessed during all delegated calls. */ private final Object FUTURE_MUTEX = new Object(); /** * The active future that is running/will be run. When the future is complete, * it must count down the {@link #doneLatch}. */ private Future<Void> future; /** * The count down latch used to keep track of the number of futures that need * to execute before this task is considered complete. Calls to {@link #get()} * will block on this latch until it reaches 0. */ private CountDownLatch doneLatch = new CountDownLatch(2); /** * The UI to synchronize with when updating from a background thread. -
mpilone revised this gist
Aug 5, 2013 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -18,8 +18,8 @@ public abstract class BackgroundUiTask implements RunnableFuture<Void> { /** * Called when a lock has been obtained on the UI's {@link VaadinSession} and * it is safe to apply UI updates. This method will only be called after * {@link #doWork()} is complete and the task hasn't been cancelled. The * default implementation calls {@link #doUiUpdate()}. This method will be * called even if {@link #doWork()} throws an exception to give the task a -
mpilone revised this gist
Aug 5, 2013 . 1 changed file with 2 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -9,7 +9,8 @@ /** * A background task that handles synchronizing to the UI when performing * updates from a background thread. The common use case is to create a * background task, add it to a thread pool and then update the UI in the safe, * {@link #doUiUpdate(Throwable)} method. * * @author mpilone * -
mpilone created this gist
Aug 5, 2013 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,245 @@ package org.mpilone.vaadin; import java.util.concurrent.*; import java.util.concurrent.locks.Lock; import com.vaadin.ui.UI; import com.vaadin.ui.UIDetachedException; /** * A background task that handles synchronizing to the UI when performing * updates from a background thread. The common use case is to create a * background task, add it to a thread poo and then update the UI wh * * @author mpilone * */ public abstract class BackgroundUiTask implements RunnableFuture<Void> { /** * Called when a lock has been obtained on the UI {@link VaadinServiceSession} * and it is safe to apply UI updates. This method will only be called after * {@link #doWork()} is complete and the task hasn't been cancelled. The * default implementation calls {@link #doUiUpdate()}. This method will be * called even if {@link #doWork()} throws an exception to give the task a * chance to cleanup the UI. * * @param ex * the exception raised in {@link #doWork()} or null if no exception * was raised */ protected void doUiUpdate(Throwable ex) { doUiUpdate(); } /** * A convenience method that will be called by {@link #doUiUpdate(Throwable)}. * The default implementation does nothing but subclasses can override this * method if the value of the exception is not important. */ protected void doUiUpdate() { } /** * Called when the task is started. All time consuming work should be done in * this method. No UI updates are permitted in this method because it is not * synchronized to the {@link VaadinServiceSession}. Good implementations * should attempt to stop if the task is cancelled while processing. */ protected abstract void doWork(); /** * A simple runnable that executes the two parts of a * {@link BackgroundUiWorker}, aborting if the outer task is cancelled. * * @author mpilone */ private class DoWorkRunnable implements Runnable { /* * (non-Javadoc) * * @see java.lang.Runnable#run() */ @Override public void run() { try { if (ui == null) { throw new UIDetachedException("No UI available for " + "background synchronization."); } doWork(); } finally { doneLatch.countDown(); } } } /** * A simple runnable that executes the two parts of a * {@link BackgroundUiWorker}, aborting if the outer task is cancelled. * * @author mpilone */ private class DoUiUpdateRunnable implements Runnable { private Throwable exception; public DoUiUpdateRunnable(Throwable exception) { this.exception = exception; } /* * (non-Javadoc) * * @see java.lang.Runnable#run() */ @Override public void run() { try { if (ui == null) { throw new UIDetachedException("No UI available for " + "background synchronization."); } doUiUpdate(exception); } finally { doneLatch.countDown(); } } } private final Object FUTURE_MUTEX = new Object(); private Future<Void> future; private CountDownLatch doneLatch = new CountDownLatch(2); /** * The logger for this class. */ // private final Logger log = LoggerFactory.getLogger(getClass()); /** * The UI to synchronize with when updating from a background thread. */ private UI ui; /** * Constructs the background task which will synchronized with the UI * available at {@link UI#getCurrent()}. The task must be initially * constructed in the main thread where the UI is available. */ public BackgroundUiTask() { this(UI.getCurrent()); } /** * Constructs the background task which will synchronized with the given UI. */ public BackgroundUiTask(UI ui) { this.ui = ui; this.future = new FutureTask<Void>(new DoWorkRunnable(), null); } /* * (non-Javadoc) * * @see java.util.concurrent.Future#cancel(boolean) */ @Override public boolean cancel(boolean mayInterruptIfRunning) { synchronized (FUTURE_MUTEX) { return future.cancel(mayInterruptIfRunning); } } /** * A convenience method for {@link #cancel(boolean)} with a value of false. */ public void cancel() { cancel(false); } /* * (non-Javadoc) * * @see java.util.concurrent.Future#get() */ @Override public Void get() throws InterruptedException, ExecutionException { doneLatch.await(); return future.get(); } /* * (non-Javadoc) * * @see java.util.concurrent.Future#get(long, java.util.concurrent.TimeUnit) */ @Override public Void get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { if (doneLatch.await(timeout, unit)) { return future.get(timeout, unit); } else { throw new TimeoutException(); } } /* * (non-Javadoc) * * @see java.util.concurrent.Future#isCancelled() */ @Override public boolean isCancelled() { synchronized (FUTURE_MUTEX) { return future.isCancelled(); } } /* * (non-Javadoc) * * @see java.util.concurrent.Future#isDone() */ @Override public boolean isDone() { return doneLatch.getCount() == 0 && future.isDone(); } /* * (non-Javadoc) * * @see java.util.concurrent.RunnableFuture#run() */ @Override public void run() { ((FutureTask<Void>) future).run(); synchronized (FUTURE_MUTEX) { Throwable exception = null; try { future.get(); } catch (Throwable ex) { exception = ex; } if (future.isCancelled()) { // Cancelled during doWork so we'll skip doUiUpdate. doneLatch.countDown(); } else { // Fire up doUiUpdate. future = ui.access(new DoUiUpdateRunnable(exception)); } } } }