1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.bootstrap;
17
18 import io.netty.channel.Channel;
19 import io.netty.channel.ChannelConfig;
20 import io.netty.channel.ChannelFuture;
21 import io.netty.channel.ChannelFutureListener;
22 import io.netty.channel.ChannelHandler;
23 import io.netty.channel.ChannelHandlerContext;
24 import io.netty.channel.ChannelInboundHandlerAdapter;
25 import io.netty.channel.ChannelInitializer;
26 import io.netty.channel.ChannelOption;
27 import io.netty.channel.ChannelPipeline;
28 import io.netty.channel.EventLoopGroup;
29 import io.netty.channel.ServerChannel;
30 import io.netty.util.AttributeKey;
31 import io.netty.util.internal.ObjectUtil;
32 import io.netty.util.internal.logging.InternalLogger;
33 import io.netty.util.internal.logging.InternalLoggerFactory;
34
35 import java.util.Collection;
36 import java.util.LinkedHashMap;
37 import java.util.Map;
38 import java.util.Map.Entry;
39 import java.util.concurrent.ConcurrentHashMap;
40 import java.util.concurrent.TimeUnit;
41
42
43
44
45
46 public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerChannel> {
47
48 private static final InternalLogger logger = InternalLoggerFactory.getInstance(ServerBootstrap.class);
49
50
51
52 private final Map<ChannelOption<?>, Object> childOptions = new LinkedHashMap<ChannelOption<?>, Object>();
53 private final Map<AttributeKey<?>, Object> childAttrs = new ConcurrentHashMap<AttributeKey<?>, Object>();
54 private final ServerBootstrapConfig config = new ServerBootstrapConfig(this);
55 private volatile EventLoopGroup childGroup;
56 private volatile ChannelHandler childHandler;
57
58 public ServerBootstrap() { }
59
60 private ServerBootstrap(ServerBootstrap bootstrap) {
61 super(bootstrap);
62 childGroup = bootstrap.childGroup;
63 childHandler = bootstrap.childHandler;
64 synchronized (bootstrap.childOptions) {
65 childOptions.putAll(bootstrap.childOptions);
66 }
67 childAttrs.putAll(bootstrap.childAttrs);
68 }
69
70
71
72
73 @Override
74 public ServerBootstrap group(EventLoopGroup group) {
75 return group(group, group);
76 }
77
78
79
80
81
82
83 public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {
84 super.group(parentGroup);
85 if (this.childGroup != null) {
86 throw new IllegalStateException("childGroup set already");
87 }
88 this.childGroup = ObjectUtil.checkNotNull(childGroup, "childGroup");
89 return this;
90 }
91
92
93
94
95
96
97 public <T> ServerBootstrap childOption(ChannelOption<T> childOption, T value) {
98 ObjectUtil.checkNotNull(childOption, "childOption");
99 synchronized (childOptions) {
100 if (value == null) {
101 childOptions.remove(childOption);
102 } else {
103 childOptions.put(childOption, value);
104 }
105 }
106 return this;
107 }
108
109
110
111
112
113 public <T> ServerBootstrap childAttr(AttributeKey<T> childKey, T value) {
114 ObjectUtil.checkNotNull(childKey, "childKey");
115 if (value == null) {
116 childAttrs.remove(childKey);
117 } else {
118 childAttrs.put(childKey, value);
119 }
120 return this;
121 }
122
123
124
125
126 public ServerBootstrap childHandler(ChannelHandler childHandler) {
127 this.childHandler = ObjectUtil.checkNotNull(childHandler, "childHandler");
128 return this;
129 }
130
131 @Override
132 void init(Channel channel) {
133 setChannelOptions(channel, newOptionsArray(), logger);
134 setAttributes(channel, newAttributesArray());
135
136 ChannelPipeline p = channel.pipeline();
137
138 final EventLoopGroup currentChildGroup = childGroup;
139 final ChannelHandler currentChildHandler = childHandler;
140 final Entry<ChannelOption<?>, Object>[] currentChildOptions = newOptionsArray(childOptions);
141 final Entry<AttributeKey<?>, Object>[] currentChildAttrs = newAttributesArray(childAttrs);
142 final Collection<ChannelInitializerExtension> extensions = getInitializerExtensions();
143
144 p.addLast(new ChannelInitializer<Channel>() {
145 @Override
146 public void initChannel(final Channel ch) {
147 final ChannelPipeline pipeline = ch.pipeline();
148 ChannelHandler handler = config.handler();
149 if (handler != null) {
150 pipeline.addLast(handler);
151 }
152
153 ch.eventLoop().execute(new Runnable() {
154 @Override
155 public void run() {
156 pipeline.addLast(new ServerBootstrapAcceptor(
157 ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs,
158 extensions));
159 }
160 });
161 }
162 });
163 if (!extensions.isEmpty() && channel instanceof ServerChannel) {
164 ServerChannel serverChannel = (ServerChannel) channel;
165 for (ChannelInitializerExtension extension : extensions) {
166 try {
167 extension.postInitializeServerListenerChannel(serverChannel);
168 } catch (Exception e) {
169 logger.warn("Exception thrown from postInitializeServerListenerChannel", e);
170 }
171 }
172 }
173 }
174
175 @Override
176 public ServerBootstrap validate() {
177 super.validate();
178 if (childHandler == null) {
179 throw new IllegalStateException("childHandler not set");
180 }
181 if (childGroup == null) {
182 logger.warn("childGroup is not set. Using parentGroup instead.");
183 childGroup = config.group();
184 }
185 return this;
186 }
187
188 private static class ServerBootstrapAcceptor extends ChannelInboundHandlerAdapter {
189
190 private final EventLoopGroup childGroup;
191 private final ChannelHandler childHandler;
192 private final Entry<ChannelOption<?>, Object>[] childOptions;
193 private final Entry<AttributeKey<?>, Object>[] childAttrs;
194 private final Runnable enableAutoReadTask;
195 private final Collection<ChannelInitializerExtension> extensions;
196
197 ServerBootstrapAcceptor(
198 final Channel channel, EventLoopGroup childGroup, ChannelHandler childHandler,
199 Entry<ChannelOption<?>, Object>[] childOptions, Entry<AttributeKey<?>, Object>[] childAttrs,
200 Collection<ChannelInitializerExtension> extensions) {
201 this.childGroup = childGroup;
202 this.childHandler = childHandler;
203 this.childOptions = childOptions;
204 this.childAttrs = childAttrs;
205 this.extensions = extensions;
206
207
208
209
210
211
212 enableAutoReadTask = new Runnable() {
213 @Override
214 public void run() {
215 channel.config().setAutoRead(true);
216 }
217 };
218 }
219
220 @Override
221 @SuppressWarnings("unchecked")
222 public void channelRead(ChannelHandlerContext ctx, Object msg) {
223 final Channel child = (Channel) msg;
224
225 child.pipeline().addLast(childHandler);
226
227 setChannelOptions(child, childOptions, logger);
228 setAttributes(child, childAttrs);
229
230 if (!extensions.isEmpty()) {
231 for (ChannelInitializerExtension extension : extensions) {
232 try {
233 extension.postInitializeServerChildChannel(child);
234 } catch (Exception e) {
235 logger.warn("Exception thrown from postInitializeServerChildChannel", e);
236 }
237 }
238 }
239
240 try {
241 childGroup.register(child).addListener(new ChannelFutureListener() {
242 @Override
243 public void operationComplete(ChannelFuture future) throws Exception {
244 if (!future.isSuccess()) {
245 forceClose(child, future.cause());
246 }
247 }
248 });
249 } catch (Throwable t) {
250 forceClose(child, t);
251 }
252 }
253
254 private static void forceClose(Channel child, Throwable t) {
255 child.unsafe().closeForcibly();
256 logger.warn("Failed to register an accepted channel: {}", child, t);
257 }
258
259 @Override
260 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
261 final ChannelConfig config = ctx.channel().config();
262 if (config.isAutoRead()) {
263
264
265 config.setAutoRead(false);
266 ctx.channel().eventLoop().schedule(enableAutoReadTask, 1, TimeUnit.SECONDS);
267 }
268
269
270 ctx.fireExceptionCaught(cause);
271 }
272 }
273
274 @Override
275 @SuppressWarnings("CloneDoesntCallSuperClone")
276 public ServerBootstrap clone() {
277 return new ServerBootstrap(this);
278 }
279
280
281
282
283
284
285
286 @Deprecated
287 public EventLoopGroup childGroup() {
288 return childGroup;
289 }
290
291 final ChannelHandler childHandler() {
292 return childHandler;
293 }
294
295 final Map<ChannelOption<?>, Object> childOptions() {
296 synchronized (childOptions) {
297 return copiedMap(childOptions);
298 }
299 }
300
301 final Map<AttributeKey<?>, Object> childAttrs() {
302 return copiedMap(childAttrs);
303 }
304
305 @Override
306 public final ServerBootstrapConfig config() {
307 return config;
308 }
309 }