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