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