/* Copyright 2014 Julia s.r.l. This file is part of BeeDeeDee. BeeDeeDee is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. BeeDeeDee is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with BeeDeeDee. If not, see <http://www.gnu.org/licenses/>. */ package com.juliasoft.utils.concurrent; import static com.juliasoft.julia.checkers.nullness.assertions.NullnessAssertions.assertNonNull; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; /** * A task. It represents a computation that is not yet completed. * * @author <A HREF="mailto:fausto.spoto@univr.it">Fausto Spoto</A> */ public class Task<T> { /** * The future of the computation. */ private volatile Future<T> future; /** * The result of the computation, when available. */ private volatile T result; /** * Builds a task with the given future. * * @param future the future */ protected Task(Future<T> future) { assertNonNull(future); this.future = future; } /** * Yields a task that yields the given result. This means that * the task is not really running, but has already completed when * it is created. * * @param result the result */ public Task(final T result) { this(new Future<T>() { @Override public boolean cancel(boolean arg0) { return false; } @Override public T get() { return result; } @Override public T get(long arg0, TimeUnit arg1) { return result; } @Override public boolean isCancelled() { return false; } @Override public boolean isDone() { return true; } }); } /** * Yields the result of the task. Blocks if the result is * not yet available. Any exception thrown during the * computation of the result is wrapped inside a * runtime exception. * * @return the result of the task */ public T get() { if (result != null) return result; synchronized(this) { try { // future might be null if get() is called twice and the first time the result was null if (result == null && future != null) { result = future.get(); future = null; } return result; } // we transform any exception in a runtime exception // so that we do not have to put a throws clause // in a lot of methods catch (InterruptedException e) { Throwable cause = e.getCause(); throw cause instanceof RuntimeException ? (RuntimeException) cause : new RuntimeException(cause); } catch (ExecutionException e) { throw new RuntimeException(e.getCause()); } } } }