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.StringUtil;
32 import io.netty.util.internal.logging.InternalLogger;
33 import io.netty.util.internal.logging.InternalLoggerFactory;
34
35 import java.util.LinkedHashMap;
36 import java.util.Map;
37 import java.util.Map.Entry;
38 import java.util.concurrent.TimeUnit;
39
40
41
42
43
44 public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerChannel> {
45
46 private static final InternalLogger logger = InternalLoggerFactory.getInstance(ServerBootstrap.class);
47
48 private final Map<ChannelOption<?>, Object> childOptions = new LinkedHashMap<ChannelOption<?>, Object>();
49 private final Map<AttributeKey<?>, Object> childAttrs = new LinkedHashMap<AttributeKey<?>, Object>();
50 private volatile EventLoopGroup childGroup;
51 private volatile ChannelHandler childHandler;
52
53 public ServerBootstrap() { }
54
55 private ServerBootstrap(ServerBootstrap bootstrap) {
56 super(bootstrap);
57 childGroup = bootstrap.childGroup;
58 childHandler = bootstrap.childHandler;
59 synchronized (bootstrap.childOptions) {
60 childOptions.putAll(bootstrap.childOptions);
61 }
62 synchronized (bootstrap.childAttrs) {
63 childAttrs.putAll(bootstrap.childAttrs);
64 }
65 }
66
67
68
69
70 @Override
71 public ServerBootstrap group(EventLoopGroup group) {
72 return group(group, group);
73 }
74
75
76
77
78
79
80 public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {
81 super.group(parentGroup);
82 if (childGroup == null) {
83 throw new NullPointerException("childGroup");
84 }
85 if (this.childGroup != null) {
86 throw new IllegalStateException("childGroup set already");
87 }
88 this.childGroup = childGroup;
89 return this;
90 }
91
92
93
94
95
96
97 public <T> ServerBootstrap childOption(ChannelOption<T> childOption, T value) {
98 if (childOption == null) {
99 throw new NullPointerException("childOption");
100 }
101 if (value == null) {
102 synchronized (childOptions) {
103 childOptions.remove(childOption);
104 }
105 } else {
106 synchronized (childOptions) {
107 childOptions.put(childOption, value);
108 }
109 }
110 return this;
111 }
112
113
114
115
116
117 public <T> ServerBootstrap childAttr(AttributeKey<T> childKey, T value) {
118 if (childKey == null) {
119 throw new NullPointerException("childKey");
120 }
121 if (value == null) {
122 childAttrs.remove(childKey);
123 } else {
124 childAttrs.put(childKey, value);
125 }
126 return this;
127 }
128
129
130
131
132 public ServerBootstrap childHandler(ChannelHandler childHandler) {
133 if (childHandler == null) {
134 throw new NullPointerException("childHandler");
135 }
136 this.childHandler = childHandler;
137 return this;
138 }
139
140
141
142
143
144 public EventLoopGroup childGroup() {
145 return childGroup;
146 }
147
148 @Override
149 void init(Channel channel) throws Exception {
150 final Map<ChannelOption<?>, Object> options = options();
151 synchronized (options) {
152 setChannelOptions(channel, options, logger);
153 }
154
155 final Map<AttributeKey<?>, Object> attrs = attrs();
156 synchronized (attrs) {
157 for (Entry<AttributeKey<?>, Object> e: attrs.entrySet()) {
158 @SuppressWarnings("unchecked")
159 AttributeKey<Object> key = (AttributeKey<Object>) e.getKey();
160 channel.attr(key).set(e.getValue());
161 }
162 }
163
164 ChannelPipeline p = channel.pipeline();
165
166 final EventLoopGroup currentChildGroup = childGroup;
167 final ChannelHandler currentChildHandler = childHandler;
168 final Entry<ChannelOption<?>, Object>[] currentChildOptions;
169 final Entry<AttributeKey<?>, Object>[] currentChildAttrs;
170 synchronized (childOptions) {
171 currentChildOptions = childOptions.entrySet().toArray(newOptionArray(childOptions.size()));
172 }
173 synchronized (childAttrs) {
174 currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(childAttrs.size()));
175 }
176
177 p.addLast(new ChannelInitializer<Channel>() {
178 @Override
179 public void initChannel(final Channel ch) throws Exception {
180 final ChannelPipeline pipeline = ch.pipeline();
181 ChannelHandler handler = handler();
182 if (handler != null) {
183 pipeline.addLast(handler);
184 }
185
186 ch.eventLoop().execute(new Runnable() {
187 @Override
188 public void run() {
189 pipeline.addLast(new ServerBootstrapAcceptor(
190 ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
191 }
192 });
193 }
194 });
195 }
196
197 @Override
198 public ServerBootstrap validate() {
199 super.validate();
200 if (childHandler == null) {
201 throw new IllegalStateException("childHandler not set");
202 }
203 if (childGroup == null) {
204 logger.warn("childGroup is not set. Using parentGroup instead.");
205 childGroup = group();
206 }
207 return this;
208 }
209
210 @SuppressWarnings("unchecked")
211 private static Entry<AttributeKey<?>, Object>[] newAttrArray(int size) {
212 return new Entry[size];
213 }
214
215 @SuppressWarnings("unchecked")
216 private static Map.Entry<ChannelOption<?>, Object>[] newOptionArray(int size) {
217 return new Map.Entry[size];
218 }
219
220 private static class ServerBootstrapAcceptor extends ChannelInboundHandlerAdapter {
221
222 private final EventLoopGroup childGroup;
223 private final ChannelHandler childHandler;
224 private final Entry<ChannelOption<?>, Object>[] childOptions;
225 private final Entry<AttributeKey<?>, Object>[] childAttrs;
226 private final Runnable enableAutoReadTask;
227
228 ServerBootstrapAcceptor(
229 final Channel channel, EventLoopGroup childGroup, ChannelHandler childHandler,
230 Entry<ChannelOption<?>, Object>[] childOptions, Entry<AttributeKey<?>, Object>[] childAttrs) {
231 this.childGroup = childGroup;
232 this.childHandler = childHandler;
233 this.childOptions = childOptions;
234 this.childAttrs = childAttrs;
235
236
237
238
239
240
241 enableAutoReadTask = new Runnable() {
242 @Override
243 public void run() {
244 channel.config().setAutoRead(true);
245 }
246 };
247 }
248
249 @Override
250 @SuppressWarnings("unchecked")
251 public void channelRead(ChannelHandlerContext ctx, Object msg) {
252 final Channel child = (Channel) msg;
253
254 child.pipeline().addLast(childHandler);
255
256 setChannelOptions(child, childOptions, logger);
257
258 for (Entry<AttributeKey<?>, Object> e: childAttrs) {
259 child.attr((AttributeKey<Object>) e.getKey()).set(e.getValue());
260 }
261
262 try {
263 childGroup.register(child).addListener(new ChannelFutureListener() {
264 @Override
265 public void operationComplete(ChannelFuture future) throws Exception {
266 if (!future.isSuccess()) {
267 forceClose(child, future.cause());
268 }
269 }
270 });
271 } catch (Throwable t) {
272 forceClose(child, t);
273 }
274 }
275
276 private static void forceClose(Channel child, Throwable t) {
277 child.unsafe().closeForcibly();
278 logger.warn("Failed to register an accepted channel: " + child, t);
279 }
280
281 @Override
282 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
283 final ChannelConfig config = ctx.channel().config();
284 if (config.isAutoRead()) {
285
286
287 config.setAutoRead(false);
288 ctx.channel().eventLoop().schedule(enableAutoReadTask, 1, TimeUnit.SECONDS);
289 }
290
291
292 ctx.fireExceptionCaught(cause);
293 }
294 }
295
296 @Override
297 @SuppressWarnings("CloneDoesntCallSuperClone")
298 public ServerBootstrap clone() {
299 return new ServerBootstrap(this);
300 }
301
302 @Override
303 public String toString() {
304 StringBuilder buf = new StringBuilder(super.toString());
305 buf.setLength(buf.length() - 1);
306 buf.append(", ");
307 if (childGroup != null) {
308 buf.append("childGroup: ");
309 buf.append(StringUtil.simpleClassName(childGroup));
310 buf.append(", ");
311 }
312 synchronized (childOptions) {
313 if (!childOptions.isEmpty()) {
314 buf.append("childOptions: ");
315 buf.append(childOptions);
316 buf.append(", ");
317 }
318 }
319 synchronized (childAttrs) {
320 if (!childAttrs.isEmpty()) {
321 buf.append("childAttrs: ");
322 buf.append(childAttrs);
323 buf.append(", ");
324 }
325 }
326 if (childHandler != null) {
327 buf.append("childHandler: ");
328 buf.append(childHandler);
329 buf.append(", ");
330 }
331 if (buf.charAt(buf.length() - 1) == '(') {
332 buf.append(')');
333 } else {
334 buf.setCharAt(buf.length() - 2, ')');
335 buf.setLength(buf.length() - 1);
336 }
337
338 return buf.toString();
339 }
340 }