1 /*
2 * Copyright 2012 The Netty Project
3 *
4 * The Netty Project licenses this file to you under the Apache License,
5 * version 2.0 (the "License"); you may not use this file except in compliance
6 * with the 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.oio;
17
18 import java.util.concurrent.Executor;
19 import java.util.concurrent.Executors;
20 import java.util.concurrent.RejectedExecutionException;
21
22 import org.jboss.netty.channel.Channel;
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.util.internal.ExecutorUtil;
28
29 /**
30 * A {@link DatagramChannelFactory} which creates a blocking I/O based
31 * {@link DatagramChannel}. It utilizes the good old blocking I/O API which
32 * has support for multicast.
33 *
34 * <h3>How threads work</h3>
35 * <p>
36 * There is only one type of threads in {@link OioDatagramChannelFactory};
37 * worker threads.
38 *
39 * <h4>Worker threads</h4>
40 * <p>
41 * Each {@link Channel} has a dedicated worker thread, just like a
42 * traditional blocking I/O thread model.
43 *
44 * <h3>Life cycle of threads and graceful shutdown</h3>
45 * <p>
46 * Worker threads are acquired from the {@link Executor} which was specified
47 * when a {@link OioDatagramChannelFactory} was created (i.e. {@code workerExecutor}.)
48 * Therefore, you should make sure the specified {@link Executor} is able to
49 * lend the sufficient number of threads.
50 * <p>
51 * Worker threads are acquired lazily, and then released when there's nothing
52 * left to process. All the related resources are also released when the
53 * worker threads are released. Therefore, to shut down a service gracefully,
54 * you should do the following:
55 *
56 * <ol>
57 * <li>close all channels created by the factory usually using
58 * {@link ChannelGroup#close()}, and</li>
59 * <li>call {@link #releaseExternalResources()}.</li>
60 * </ol>
61 *
62 * Please make sure not to shut down the executor until all channels are
63 * closed. Otherwise, you will end up with a {@link RejectedExecutionException}
64 * and the related resources might not be released properly.
65 *
66 * <h3>Limitation</h3>
67 * <p>
68 * A {@link DatagramChannel} created by this factory does not support asynchronous
69 * operations. Any I/O requests such as {@code "write"} will be performed in a
70 * blocking manner.
71 *
72 * @apiviz.landmark
73 */
74 public class OioDatagramChannelFactory implements DatagramChannelFactory {
75
76 private final Executor workerExecutor;
77 final OioDatagramPipelineSink sink;
78
79 /**
80 * Creates a new instance with a {@link Executors#newCachedThreadPool()}
81 *
82 * See {@link #OioDatagramChannelFactory(Executor)}
83 */
84 public OioDatagramChannelFactory() {
85 this(Executors.newCachedThreadPool());
86 }
87
88 /**
89 * Creates a new instance.
90 *
91 * @param workerExecutor
92 * the {@link Executor} which will execute the I/O worker threads
93 */
94 public OioDatagramChannelFactory(Executor workerExecutor) {
95 if (workerExecutor == null) {
96 throw new NullPointerException("workerExecutor");
97 }
98 this.workerExecutor = workerExecutor;
99 sink = new OioDatagramPipelineSink(workerExecutor);
100 }
101
102 public DatagramChannel newChannel(ChannelPipeline pipeline) {
103 return new OioDatagramChannel(this, pipeline, sink);
104 }
105
106 public void releaseExternalResources() {
107 ExecutorUtil.terminate(workerExecutor);
108 }
109 }