View Javadoc

    1   /*
    2    * Copyright 2009 Red Hat, Inc.
    3    *
    4    * Red Hat licenses this file to you under the Apache License, version 2.0
    5    * (the "License"); you may not use this file except in compliance with the
    6    * License.  You may obtain a copy of the License at:
    7    *
    8    *    http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
    13   * License for the specific language governing permissions and limitations
    14   * under the License.
    15   */
    16  package org.jboss.netty.channel.socket.nio;
    17
    18  import java.nio.channels.Selector;
    19  import java.util.concurrent.Executor;
    20  import java.util.concurrent.Executors;
    21  import java.util.concurrent.RejectedExecutionException;
    22
    23  import org.jboss.netty.channel.ChannelPipeline;
    24  import org.jboss.netty.channel.group.ChannelGroup;
    25  import org.jboss.netty.channel.socket.DatagramChannel;
    26  import org.jboss.netty.channel.socket.DatagramChannelFactory;
    27  import org.jboss.netty.channel.socket.oio.OioDatagramChannelFactory;
    28  import org.jboss.netty.util.internal.ExecutorUtil;
    29
    30  /**
    31   * A {@link DatagramChannelFactory} that creates a NIO-based connectionless
    32   * {@link DatagramChannel}. It utilizes the non-blocking I/O mode which
    33   * was introduced with NIO to serve many number of concurrent connections
    34   * efficiently.
    35   *
    36   * <h3>How threads work</h3>
    37   * <p>
    38   * There is only one thread type in a {@link NioDatagramChannelFactory};
    39   * worker threads.
    40   *
    41   * <h4>Worker threads</h4>
    42   * <p>
    43   * One {@link NioDatagramChannelFactory} can have one or more worker
    44   * threads.  A worker thread performs non-blocking read and write for one or
    45   * more {@link DatagramChannel}s in a non-blocking mode.
    46   *
    47   * <h3>Life cycle of threads and graceful shutdown</h3>
    48   * <p>
    49   * All worker threads are acquired from the {@link Executor} which was specified
    50   * when a {@link NioDatagramChannelFactory} was created.  Therefore, you should
    51   * make sure the specified {@link Executor} is able to lend the sufficient
    52   * number of threads.  It is the best bet to specify
    53   * {@linkplain Executors#newCachedThreadPool() a cached thread pool}.
    54   * <p>
    55   * All worker threads are acquired lazily, and then released when there's
    56   * nothing left to process.  All the related resources such as {@link Selector}
    57   * are also released when the worker threads are released.  Therefore, to shut
    58   * down a service gracefully, you should do the following:
    59   *
    60   * <ol>
    61   * <li>close all channels created by the factory usually using
    62   *     {@link ChannelGroup#close()}, and</li>
    63   * <li>call {@link #releaseExternalResources()}.</li>
    64   * </ol>
    65   *
    66   * Please make sure not to shut down the executor until all channels are
    67   * closed.  Otherwise, you will end up with a {@link RejectedExecutionException}
    68   * and the related resources might not be released properly.
    69   *
    70   * <h3>Limitation</h3>
    71   * <p>
    72   * Multicast is not supported.  Please use {@link OioDatagramChannelFactory}
    73   * instead.
    74   *
    75   * @author <a href="http://www.jboss.org/netty/">The Netty Project</a>
    76   * @author <a href="http://gleamynode.net/">Trustin Lee</a>
    77   * @author Daniel Bevenius (dbevenius@jboss.com)
    78   *
    79   * @version $Rev: 2200 $, $Date: 2010-02-23 14:42:39 +0900 (Tue, 23 Feb 2010) $
    80   *
    81   * @apiviz.landmark
    82   */
    83  public class NioDatagramChannelFactory implements DatagramChannelFactory {
    84
    85      private final Executor workerExecutor;
    86      private final NioDatagramPipelineSink sink;
    87
    88      /**
    89       * Creates a new instance.  Calling this constructor is same with calling
    90       * {@link #NioDatagramChannelFactory(Executor, int)} with 2 * the number of
    91       * available processors in the machine.  The number of available processors
    92       * is obtained by {@link Runtime#availableProcessors()}.
    93       *
    94       * @param workerExecutor
    95       *        the {@link Executor} which will execute the I/O worker threads
    96       */
    97      public NioDatagramChannelFactory(final Executor workerExecutor) {
    98          this(workerExecutor, SelectorUtil.DEFAULT_IO_THREADS);
    99      }
    100
    101     /**
    102      * Creates a new instance.
    103      *
    104      * @param workerExecutor
    105      *        the {@link Executor} which will execute the I/O worker threads
    106      * @param workerCount
    107      *        the maximum number of I/O worker threads
    108      */
    109     public NioDatagramChannelFactory(final Executor workerExecutor,
    110             final int workerCount) {
    111         if (workerCount <= 0) {
    112             throw new IllegalArgumentException(String
    113                     .format("workerCount (%s) must be a positive integer.",
    114                             workerCount));
    115         }
    116
    117         if (workerExecutor == null) {
    118             throw new NullPointerException(
    119                     "workerExecutor argument must not be null");
    120         }
    121         this.workerExecutor = workerExecutor;
    122
    123         sink = new NioDatagramPipelineSink(workerExecutor, workerCount);
    124     }
    125
    126     public DatagramChannel newChannel(final ChannelPipeline pipeline) {
    127         return new NioDatagramChannel(this, pipeline, sink, sink.nextWorker());
    128     }
    129
    130     public void releaseExternalResources() {
    131         ExecutorUtil.terminate(workerExecutor);
    132     }
    133 }