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 private boolean shutdownExecutor;
79
80 /**
81 * Creates a new instance with a {@link Executors#newCachedThreadPool()}
82 *
83 * See {@link #OioDatagramChannelFactory(Executor)}
84 */
85 public OioDatagramChannelFactory() {
86 this(Executors.newCachedThreadPool());
87 shutdownExecutor = true;
88 }
89
90 /**
91 * Creates a new instance.
92 *
93 * @param workerExecutor
94 * the {@link Executor} which will execute the I/O worker threads
95 */
96 public OioDatagramChannelFactory(Executor workerExecutor) {
97 if (workerExecutor == null) {
98 throw new NullPointerException("workerExecutor");
99 }
100 this.workerExecutor = workerExecutor;
101 sink = new OioDatagramPipelineSink(workerExecutor);
102 }
103
104 public DatagramChannel newChannel(ChannelPipeline pipeline) {
105 return new OioDatagramChannel(this, pipeline, sink);
106 }
107
108 public void shutdown() {
109 if (shutdownExecutor) {
110 ExecutorUtil.terminate(workerExecutor);
111 }
112 }
113
114 public void releaseExternalResources() {
115 shutdown();
116 ExecutorUtil.terminate(workerExecutor);
117 }
118 }