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.logging.InternalLogger;
32 import io.netty.util.internal.logging.InternalLoggerFactory;
33
34 import java.util.LinkedHashMap;
35 import java.util.Map;
36 import java.util.Map.Entry;
37 import java.util.concurrent.TimeUnit;
38
39
40
41
42
43 public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerChannel> {
44
45 private static final InternalLogger logger = InternalLoggerFactory.getInstance(ServerBootstrap.class);
46
47 private final Map<ChannelOption<?>, Object> childOptions = new LinkedHashMap<ChannelOption<?>, Object>();
48 private final Map<AttributeKey<?>, Object> childAttrs = new LinkedHashMap<AttributeKey<?>, Object>();
49 private final ServerBootstrapConfig config = new ServerBootstrapConfig(this);
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 @Override
141 void init(Channel channel) throws Exception {
142 final Map<ChannelOption<?>, Object> options = options0();
143 synchronized (options) {
144 setChannelOptions(channel, options, logger);
145 }
146
147 final Map<AttributeKey<?>, Object> attrs = attrs0();
148 synchronized (attrs) {
149 for (Entry<AttributeKey<?>, Object> e: attrs.entrySet()) {
150 @SuppressWarnings("unchecked")
151 AttributeKey<Object> key = (AttributeKey<Object>) e.getKey();
152 channel.attr(key).set(e.getValue());
153 }
154 }
155
156 ChannelPipeline p = channel.pipeline();
157
158 final EventLoopGroup currentChildGroup = childGroup;
159 final ChannelHandler currentChildHandler = childHandler;
160 final Entry<ChannelOption<?>, Object>[] currentChildOptions;
161 final Entry<AttributeKey<?>, Object>[] currentChildAttrs;
162 synchronized (childOptions) {
163 currentChildOptions = childOptions.entrySet().toArray(newOptionArray(childOptions.size()));
164 }
165 synchronized (childAttrs) {
166 currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(childAttrs.size()));
167 }
168
169 p.addLast(new ChannelInitializer<Channel>() {
170 @Override
171 public void initChannel(final Channel ch) throws Exception {
172 final ChannelPipeline pipeline = ch.pipeline();
173 ChannelHandler handler = config.handler();
174 if (handler != null) {
175 pipeline.addLast(handler);
176 }
177
178 ch.eventLoop().execute(new Runnable() {
179 @Override
180 public void run() {
181 pipeline.addLast(new ServerBootstrapAcceptor(
182 ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
183 }
184 });
185 }
186 });
187 }
188
189 @Override
190 public ServerBootstrap validate() {
191 super.validate();
192 if (childHandler == null) {
193 throw new IllegalStateException("childHandler not set");
194 }
195 if (childGroup == null) {
196 logger.warn("childGroup is not set. Using parentGroup instead.");
197 childGroup = config.group();
198 }
199 return this;
200 }
201
202 @SuppressWarnings("unchecked")
203 private static Entry<AttributeKey<?>, Object>[] newAttrArray(int size) {
204 return new Entry[size];
205 }
206
207 @SuppressWarnings("unchecked")
208 private static Map.Entry<ChannelOption<?>, Object>[] newOptionArray(int size) {
209 return new Map.Entry[size];
210 }
211
212 private static class ServerBootstrapAcceptor extends ChannelInboundHandlerAdapter {
213
214 private final EventLoopGroup childGroup;
215 private final ChannelHandler childHandler;
216 private final Entry<ChannelOption<?>, Object>[] childOptions;
217 private final Entry<AttributeKey<?>, Object>[] childAttrs;
218 private final Runnable enableAutoReadTask;
219
220 ServerBootstrapAcceptor(
221 final Channel channel, EventLoopGroup childGroup, ChannelHandler childHandler,
222 Entry<ChannelOption<?>, Object>[] childOptions, Entry<AttributeKey<?>, Object>[] childAttrs) {
223 this.childGroup = childGroup;
224 this.childHandler = childHandler;
225 this.childOptions = childOptions;
226 this.childAttrs = childAttrs;
227
228
229
230
231
232
233 enableAutoReadTask = new Runnable() {
234 @Override
235 public void run() {
236 channel.config().setAutoRead(true);
237 }
238 };
239 }
240
241 @Override
242 @SuppressWarnings("unchecked")
243 public void channelRead(ChannelHandlerContext ctx, Object msg) {
244 final Channel child = (Channel) msg;
245
246 child.pipeline().addLast(childHandler);
247
248 setChannelOptions(child, childOptions, logger);
249
250 for (Entry<AttributeKey<?>, Object> e: childAttrs) {
251 child.attr((AttributeKey<Object>) e.getKey()).set(e.getValue());
252 }
253
254 try {
255 childGroup.register(child).addListener(new ChannelFutureListener() {
256 @Override
257 public void operationComplete(ChannelFuture future) throws Exception {
258 if (!future.isSuccess()) {
259 forceClose(child, future.cause());
260 }
261 }
262 });
263 } catch (Throwable t) {
264 forceClose(child, t);
265 }
266 }
267
268 private static void forceClose(Channel child, Throwable t) {
269 child.unsafe().closeForcibly();
270 logger.warn("Failed to register an accepted channel: {}", child, t);
271 }
272
273 @Override
274 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
275 final ChannelConfig config = ctx.channel().config();
276 if (config.isAutoRead()) {
277
278
279 config.setAutoRead(false);
280 ctx.channel().eventLoop().schedule(enableAutoReadTask, 1, TimeUnit.SECONDS);
281 }
282
283
284 ctx.fireExceptionCaught(cause);
285 }
286 }
287
288 @Override
289 @SuppressWarnings("CloneDoesntCallSuperClone")
290 public ServerBootstrap clone() {
291 return new ServerBootstrap(this);
292 }
293
294
295
296
297
298
299
300 @Deprecated
301 public EventLoopGroup childGroup() {
302 return childGroup;
303 }
304
305 final ChannelHandler childHandler() {
306 return childHandler;
307 }
308
309 final Map<ChannelOption<?>, Object> childOptions() {
310 return copiedMap(childOptions);
311 }
312
313 final Map<AttributeKey<?>, Object> childAttrs() {
314 return copiedMap(childAttrs);
315 }
316
317 @Override
318 public final ServerBootstrapConfig config() {
319 return config;
320 }
321 }