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 }