/* * 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.io.IOException; import java.lang.Thread.UncaughtExceptionHandler; import java.nio.channels.SelectableChannel; import java.nio.channels.spi.SelectorProvider; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import com.sun.sgs.nio.channels.AsynchronousChannelGroup; import com.sun.sgs.nio.channels.CompletionHandler; import com.sun.sgs.nio.channels.IoFuture; import com.sun.sgs.nio.channels.ShutdownChannelGroupException; /** * Common base implementation of {@link AsynchronousChannelGroup}. */ abstract class AsyncGroupImpl extends AsynchronousChannelGroup { /** The executor service for this group's tasks. */ protected final ExecutorService executor; /** * The UncaughtExceptionHandler for this group, or {@code null}. * * Accessed by AsyncProviderImpl if this is the default group. */ volatile UncaughtExceptionHandler uncaughtHandler = null; /** * Constructs a new instance of this class. * * @param provider the provider * @param executor the executor */ protected AsyncGroupImpl(AsyncProviderImpl provider, ExecutorService executor) { super(provider); if (executor == null) { throw new NullPointerException("null executor"); } this.executor = executor; } /** * Registers the given channel with this group, returning an * {@link AsyncKey} that can be used to invoke asynchronous IO * operations. If this group is shutdown, this method will throw * {@link ShutdownChannelGroupException} and close the channel. * * @param ch the underlying channel for IO operations * @return an {@code AsyncKey} that supports asynchronous operations * on the underlying channel * * @throws IOException if an I/O error occurs * @throws ShutdownChannelGroupException if this group is shutdown */ abstract AsyncKey register(SelectableChannel ch) throws IOException; /** * Returns a runnable that will invoke the given completion handler. * Passes the handler an {@code IoFuture} constructed from the given * future and attachment object. * * @param <R> the result type * @param <A> the attachment type * @param handler the completion handler * @param attachment the attachment, or {@code null} * @param future the result * @return the completion runnable */ <R, A> Runnable completionRunner(CompletionHandler<R, A> handler, A attachment, Future<R> future) { assert future.isDone(); return new CompletionRunner<R, A>(handler, attachment, future); } /** * Invokes the uncaught exception handler of the current thread, if * one is present. Does not re-throw the exception. * * @param <T> the type of the exception * @param exception the exception */ private <T extends Throwable> void uncaught(T exception) { try { final Thread.UncaughtExceptionHandler ueh = uncaughtHandler; if (ueh != null) { ueh.uncaughtException(Thread.currentThread(), exception); } } catch (Throwable ignore) { // Ignore all throwables here, even Errors, as specified // by Thread#UncaughtExceptionHandler#uncaughtException } } /** * A Runnable that invokes its completion handler with the given * {@code IoFuture} result. * * @param <R> the result type * @param <A> the attachment type */ private class CompletionRunner<R, A> implements Runnable { /** The completion handler to invoke. */ private final CompletionHandler<R, A> handler; /** The result to pass to the completion hander. */ private final IoFuture<R, A> result; /** * Creates a new instance to run the given completion handler. * * @param handler the completion handler to invoke * @param attachment the attachment for the future * @param future the future to pass to the completion handler */ CompletionRunner(CompletionHandler<R, A> handler, A attachment, Future<R> future) { this.handler = handler; this.result = AttachedFuture.wrap(future, attachment); } /** {@inheritDoc} */ public void run() { try { handler.completed(result); } catch (RuntimeException e) { uncaught(e); } catch (Error e) { uncaught(e); } } } /** * Returns the {@code SelectorProvider} for this group. * * @return the {@code SelectorProvider} for this group */ SelectorProvider selectorProvider() { return ((AsyncProviderImpl) provider()).selectorProvider(); } /** * Returns the {@code ExecutorService} for this group. * * @return the {@code ExecutorService} for this group */ ExecutorService executor() { return executor; } /** * Invokes {@link AsynchronousChannelGroup#shutdown()} when this * group is no longer referenced. */ @Override protected void finalize() { shutdown(); } }