1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
\r
3 * in Industry THTH ry.
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
13 package org.simantics.utils.threads.ua;
\r
15 import java.util.concurrent.Callable;
\r
16 import java.util.concurrent.CancellationException;
\r
17 import java.util.concurrent.ExecutionException;
\r
18 import java.util.concurrent.RunnableFuture;
\r
19 import java.util.concurrent.TimeUnit;
\r
20 import java.util.concurrent.TimeoutException;
\r
23 * Add stateful monitoring features to runnable and callable.
\r
25 * Executing two work instances in parallel causes RuntimeException.
\r
27 * @author Toni Kalajainen (toni.kalajainen@vtt.fi)
\r
29 public class Work<T> extends AbstractState<WorkState, RuntimeException> implements WorkMonitor, RunnableFuture<T> {
\r
31 public static Work<Object> createMonitor(Runnable r)
\r
33 return new Work<Object>(r);
\r
36 public static Work<Object> createMonitor(Runnable r, StateListener<WorkState> listener)
\r
38 Work<Object> result = new Work<Object>(r);
\r
39 result.addStateListener(listener);
\r
43 public static <T> Work<T> createMonitor(Callable<T> r)
\r
45 return new Work<T>(r);
\r
48 public static <T> Work<T> createMonitor(Callable<T> r, StateListener<WorkState> listener)
\r
50 Work<T> result = new Work<T>(r);
\r
51 result.addStateListener(listener);
\r
59 transient Exception error;
\r
63 public Work(Runnable runnable) {
\r
64 super(WorkState.Ready);
\r
65 if (runnable == null)
\r
66 throw new IllegalArgumentException("null arg");
\r
71 public Work(Runnable runnable, T result) {
\r
72 super(WorkState.Ready);
\r
73 if (runnable == null)
\r
74 throw new IllegalArgumentException("null arg");
\r
77 this.result = result;
\r
80 public Work(Callable<T> c) {
\r
81 super(WorkState.Ready);
\r
83 throw new IllegalArgumentException("null arg");
\r
90 WorkState s = getState();
\r
91 if (s!=WorkState.Ready)
\r
92 throw new RuntimeException("Work must be restarted before it can be reused");
\r
93 thread = Thread.currentThread();
\r
94 if (setState(WorkState.Working, null, WorkState.READY_STATE)==WorkState.Working) return;
\r
100 } catch (Exception e) {
\r
102 setState(WorkState.Error);
\r
104 WorkState newState = WorkState.Complete;
\r
105 synchronized(this) {
\r
107 if (s==WorkState.Interrupting) {
\r
108 Thread.interrupted();
\r
109 newState = WorkState.Interrupted;
\r
112 setState(newState);
\r
116 public boolean cancel(boolean mayInterruptIfRunning) {
\r
117 synchronized(this) {
\r
118 WorkState s = getState();
\r
119 if (s != WorkState.Ready && s != WorkState.Working) return false;
\r
122 if (attemptSetState(WorkState.READY_STATE, WorkState.Canceled)==WorkState.Ready) {
\r
126 // Attempt interrupt
\r
127 if (mayInterruptIfRunning &&
\r
128 attemptSetState(WorkState.WORKING_STATE, WorkState.Interrupting)==WorkState.Working)
\r
131 thread.interrupt();
\r
138 protected boolean isStateTransitionAllowed(WorkState oldState, WorkState newState) {
\r
142 // Raise visibility
\r
144 public void setError(RuntimeException error)
\r
146 super.setError(error);
\r
150 * Reset work for reuse.
\r
152 public synchronized void restart()
\r
154 WorkState s = getState();
\r
155 if (s==WorkState.Ready) return;
\r
156 if (!s.isFinalState())
\r
157 throw new RuntimeException("Work cannot be restarted until the previous run has completed.");
\r
158 setState(WorkState.Ready);
\r
162 public Runnable getRunnable() {
\r
167 public T get() throws InterruptedException, ExecutionException {
\r
168 WorkState s = waitForState(WorkState.FINAL_STATES);
\r
169 if (s==WorkState.Canceled)
\r
170 throw new CancellationException();
\r
171 if (s==WorkState.Interrupted)
\r
172 throw new InterruptedException();
\r
173 if (s==WorkState.Error)
\r
174 throw new ExecutionException(error);
\r
179 public T get(long timeout, TimeUnit unit) throws InterruptedException,
\r
180 ExecutionException, TimeoutException {
\r
181 WorkState s = waitForState(WorkState.FINAL_STATES, timeout, unit);
\r
182 if (s==WorkState.Canceled)
\r
183 throw new CancellationException();
\r
184 if (s==WorkState.Interrupted)
\r
185 throw new InterruptedException();
\r
186 if (s==WorkState.Error)
\r
187 throw new ExecutionException(error);
\r
192 public boolean isCancelled() {
\r
197 public boolean isDone() {
\r
198 return WorkState.FINAL_STATES.contains(getState());
\r