/* * 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.spi.SelectorProvider; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.concurrent.ExecutorService; import com.sun.sgs.nio.channels.AsynchronousChannelGroup; import com.sun.sgs.nio.channels.ProtocolFamily; import com.sun.sgs.nio.channels.ThreadPoolFactory; import com.sun.sgs.nio.channels.spi.AsynchronousChannelProvider; /** * Common base implementation of {@link AsynchronousChannelProvider}. * <ul> * <li> * Implements methods to create the default channel group and thread pool * factory as specified by {@link AsynchronousChannelGroup}. * <li> * Checks the channel group passed in to the various channel {@code open()} * methods, substituting the default group if appropriate. * <li> * Manages the default group's {@link UncaughtExceptionHandler}. * </ul> */ abstract class AsyncProviderImpl extends AsynchronousChannelProvider { /** The SelectorProvider. */ private final SelectorProvider selectorProvider; /** The default group, or {@code null} if one has not been created yet. */ private AsyncGroupImpl defaultGroupInstance = null; /** * The default uncaught exception handler (or {@code null} if no handler * is set), until the default group is created. After the default group * has been created, this field is set to {@code null} to avoid pinning * the handler in memory. */ private UncaughtExceptionHandler defaultUncaughtHandler = null; /** * Creates an asynchronous channel provider using the given * {@link SelectorProvider}. If the parameter is {code null}, the * system default {@code SelectorProvider} will be used. * * @param selProvider the {@code SelectorProvider}, or {@code null} to * use the system default {@code SelectorProvider} * * @see SelectorProvider#provider() */ protected AsyncProviderImpl(SelectorProvider selProvider) { selectorProvider = selProvider != null ? selProvider : SelectorProvider.provider(); assert selectorProvider != null; } /** * Returns the {@link SelectorProvider} for this async provider. * * @return the {@code SelectorProvider} for this async provider */ SelectorProvider selectorProvider() { return selectorProvider; } // Methods related to default thread pools and channel groups. /** * Returns the default thread pool factory as specified by the * class documentation for {@link AsynchronousChannelGroup}. * Delegates to {@link #createDefaultThreadPoolFactory()} if the * other factory creation mechanisms fail. * * @return the default {@code ThreadPoolFactory} */ private ThreadPoolFactory getThreadPoolFactory() { return AccessController.doPrivileged( new PrivilegedAction<ThreadPoolFactory>() { public ThreadPoolFactory run() { String cn = System.getProperty( "com.sun.sgs.nio.channels.DefaultThreadPoolFactory"); if (cn != null) { try { Class<?> c = Class.forName(cn, true, ClassLoader.getSystemClassLoader()); return (ThreadPoolFactory) c.newInstance(); } catch (Throwable ignore) { // Any exception will fall-thru and return // the default factory. } } return createDefaultThreadPoolFactory(); } }); } /** * Creates a default {@link ThreadPoolFactory} when none has been * specified by other mechanisms. * * @return a {@code ThreadPoolFactory} */ protected ThreadPoolFactory createDefaultThreadPoolFactory() { return DefaultThreadPoolFactory.create(); } /** * Returns the default {@link AsynchronousChannelGroup} for this * provider, creating one if necessary. * * @return the default channel group for this provider * * @throws IOException if an I/O error occurs */ private AsyncGroupImpl defaultGroup() throws IOException { synchronized (this) { if (defaultGroupInstance == null) { ThreadPoolFactory tpf = getThreadPoolFactory(); ExecutorService executor = tpf.newThreadPool(); defaultGroupInstance = openAsynchronousChannelGroup(executor); defaultGroupInstance.uncaughtHandler = defaultUncaughtHandler; defaultUncaughtHandler = null; } return defaultGroupInstance; } } /** * Checks that the given channel group was created by this provider, * throwing an exception if it was not. * * @param group a channel group, or {@code null} to return the default * group for this provider * @return the given group, if it was created by this provider, or * the default group if {@code null} was given * * @throws IllegalArgumentException if the group was not created * by this provider * @throws IOException if an IO error occurs while constructing * the default group */ private AsyncGroupImpl checkGroup(AsynchronousChannelGroup group) throws IOException { if (group == null) { return defaultGroup(); } if (group.provider() != this) { throw new IllegalArgumentException( "AsynchronousChannelGroup not created by this provider"); } return (AsyncGroupImpl) group; } // AsynchronousChannelProvider methods /** {@inheritDoc} */ @Override public abstract AsyncGroupImpl openAsynchronousChannelGroup(ExecutorService executor) throws IOException; /** {@inheritDoc} */ @Override public AsyncDatagramChannelImpl openAsynchronousDatagramChannel(ProtocolFamily pf, AsynchronousChannelGroup group) throws IOException { return new AsyncDatagramChannelImpl(pf, checkGroup(group)); } /** {@inheritDoc} */ @Override public AsyncServerSocketChannelImpl openAsynchronousServerSocketChannel(AsynchronousChannelGroup group) throws IOException { return new AsyncServerSocketChannelImpl(checkGroup(group)); } /** {@inheritDoc} */ @Override public AsyncSocketChannelImpl openAsynchronousSocketChannel(AsynchronousChannelGroup group) throws IOException { return new AsyncSocketChannelImpl(checkGroup(group)); } /** {@inheritDoc} */ @Override public UncaughtExceptionHandler getUncaughtExceptionHandler() { synchronized (this) { if (defaultGroupInstance != null) { return defaultGroupInstance.uncaughtHandler; } else { return defaultUncaughtHandler; } } } /** {@inheritDoc} */ @Override public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh) { synchronized (this) { if (defaultGroupInstance != null) { defaultGroupInstance.uncaughtHandler = eh; } else { defaultUncaughtHandler = eh; } } } }