/* * Copyright 2007-2010 Sun Microsystems, Inc. * * This file is part of Project Darkstar Server. * * Project Darkstar Server is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation and * distributed hereunder to you. * * Project Darkstar Server 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 this program. If not, see <http://www.gnu.org/licenses/>. * * -- */ package com.sun.sgs.impl.nio; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import com.sun.sgs.nio.channels.IoFuture; /** * An implementation of {@link IoFuture} that adds an object attachment * to an arbitrary {@link java.util.concurrent.Future}. * * @param <R> the result type * @param <A> the attachment type */ public class AttachedFuture<R, A> implements IoFuture<R, A> { /** * The underlying {@code Future}. */ private final Future<R> future; /** * The attachment for this {@code IoFuture}. This field is * {@code volatile} to match the attachment implementation in * {@link java.nio.channels.SelectionKey}. */ private volatile A attachment; /** * Creates an {@code AttachedFuture} from the given future * and attachment. Provided as a static factory method so that * the template types can be inferred by the compiler. * * @param <R> the result type * @param <A> the attachment type * @param future the {@code Future} to wrap * @param attachment the initial attachment, or {@code null} * @return a new {@code AttachedFuture} */ public static <R, A> AttachedFuture<R, A> wrap(Future<R> future, A attachment) { return new AttachedFuture<R, A>(future, attachment); } /** * Creates an {@code AttachedFuture} from the given future * and attachment. * * @param future the {@code Future} to wrap * @param attachment the initial attachment, or {@code null} */ protected AttachedFuture(Future<R> future, A attachment) { this.future = future; this.attachment = attachment; } // Implement IoFuture /** {@inheritDoc} */ public A attach(A ob) { A previous = attachment; attachment = ob; return previous; } /** {@inheritDoc} */ public A attachment() { return attachment; } /** {@inheritDoc} */ public boolean cancel(boolean mayInterruptIfRunning) { return future.cancel(mayInterruptIfRunning); } /** {@inheritDoc} */ public R getNow() throws ExecutionException { if (!isDone()) { throw new IllegalStateException("not done"); } /* * The Future is done, so a result should be available immediately. * The following idiom appears in "Java Concurrency in Practice" to * handle the case where this thread has been interrupted, but a * result must be obtained regardless. */ boolean wasInterrupted = false; try { while (true) { try { return get(); } catch (InterruptedException e) { wasInterrupted = true; // fall through and retry } } } finally { if (wasInterrupted) { Thread.currentThread().interrupt(); } } } /** {@inheritDoc} */ public R get() throws InterruptedException, ExecutionException { return future.get(); } /** {@inheritDoc} */ public R get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { return future.get(timeout, unit); } /** {@inheritDoc} */ public boolean isCancelled() { return future.isCancelled(); } /** {@inheritDoc} */ public boolean isDone() { return future.isDone(); } }