1 package com.foxinmy.weixin4j.startup;
2
3 import java.util.ArrayList;
4 import java.util.Arrays;
5 import java.util.HashMap;
6 import java.util.List;
7 import java.util.Map;
8
9 import com.foxinmy.weixin4j.dispatcher.BeanFactory;
10 import com.foxinmy.weixin4j.dispatcher.DefaultMessageMatcher;
11 import com.foxinmy.weixin4j.dispatcher.WeixinMessageDispatcher;
12 import com.foxinmy.weixin4j.dispatcher.WeixinMessageKey;
13 import com.foxinmy.weixin4j.dispatcher.WeixinMessageMatcher;
14 import com.foxinmy.weixin4j.handler.WeixinMessageHandler;
15 import com.foxinmy.weixin4j.interceptor.WeixinMessageInterceptor;
16 import com.foxinmy.weixin4j.request.WeixinMessage;
17 import com.foxinmy.weixin4j.socket.WeixinServerInitializer;
18 import com.foxinmy.weixin4j.util.AesToken;
19
20 import io.netty.bootstrap.ServerBootstrap;
21 import io.netty.bootstrap.ServerBootstrapConfig;
22 import io.netty.channel.Channel;
23 import io.netty.channel.ChannelOption;
24 import io.netty.channel.nio.NioEventLoopGroup;
25 import io.netty.channel.socket.nio.NioServerSocketChannel;
26 import io.netty.handler.logging.LoggingHandler;
27 import io.netty.util.concurrent.Future;
28 import io.netty.util.concurrent.FutureListener;
29 import io.netty.util.internal.logging.InternalLogger;
30 import io.netty.util.internal.logging.InternalLoggerFactory;
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 public final class WeixinServerBootstrap {
46
47 private final InternalLogger logger = InternalLoggerFactory.getInstance(getClass());
48
49
50
51
52 public final static int DEFAULT_BOSSTHREADS;
53
54
55
56 public final static int DEFAULT_WORKERTHREADS;
57
58
59
60 public final static int DEFAULT_SERVERPORT = 30000;
61
62
63
64 private WeixinMessageDispatcher messageDispatcher;
65
66
67
68 private List<WeixinMessageHandler> messageHandlerList;
69
70
71
72 private List<WeixinMessageInterceptor> messageInterceptorList;
73
74
75
76
77
78 private final Map<String, AesToken> aesTokenMap;
79
80 private ServerBootstrap bootstrap;
81
82 static {
83 DEFAULT_BOSSTHREADS = Runtime.getRuntime().availableProcessors();
84 DEFAULT_WORKERTHREADS = DEFAULT_BOSSTHREADS * 2;
85 }
86
87
88
89
90
91
92
93
94
95 public WeixinServerBootstrap(String token) {
96 this("", token, null);
97 }
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114 public WeixinServerBootstrap(String weixinId, String token, String aesKey) {
115 this(new AesToken(weixinId, token, aesKey));
116 }
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133 public WeixinServerBootstrap(AesToken... aesToken) {
134 this(new DefaultMessageMatcher(), aesToken);
135 }
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154 public WeixinServerBootstrap(WeixinMessageMatcher messageMatcher, AesToken... aesTokens) {
155 if (messageMatcher == null) {
156 throw new IllegalArgumentException("MessageMatcher not be null");
157 }
158 if (aesTokens == null) {
159 throw new IllegalArgumentException("AesToken not be null");
160 }
161 this.aesTokenMap = new HashMap<String, AesToken>();
162 for (AesToken aesToken : aesTokens) {
163 this.aesTokenMap.put(aesToken.getWeixinId(), aesToken);
164 }
165 this.aesTokenMap.put("", aesTokens[0]);
166 this.messageHandlerList = new ArrayList<WeixinMessageHandler>();
167 this.messageInterceptorList = new ArrayList<WeixinMessageInterceptor>();
168 this.messageDispatcher = new WeixinMessageDispatcher(messageMatcher);
169 }
170
171
172
173
174
175 public void startup() {
176 startup(DEFAULT_SERVERPORT);
177 }
178
179
180
181
182
183 public void startup(int serverPort) {
184 startup(DEFAULT_BOSSTHREADS, DEFAULT_WORKERTHREADS, serverPort);
185 }
186
187
188
189
190
191
192
193
194
195
196
197
198
199 public void startup(int bossThreads, int workerThreads, final int serverPort) {
200 messageDispatcher.setMessageHandlerList(messageHandlerList);
201 messageDispatcher.setMessageInterceptorList(messageInterceptorList);
202 try {
203 bootstrap = new ServerBootstrap();
204 bootstrap.option(ChannelOption.SO_BACKLOG, 1024);
205 bootstrap.group(new NioEventLoopGroup(bossThreads), new NioEventLoopGroup(workerThreads))
206 .channel(NioServerSocketChannel.class).handler(new LoggingHandler())
207 .childHandler(new WeixinServerInitializer(aesTokenMap, messageDispatcher));
208 Channel ch = bootstrap.bind(serverPort).addListener(new FutureListener<Void>() {
209 @Override
210 public void operationComplete(Future<Void> future) throws Exception {
211 if (future.isSuccess()) {
212 logger.info("weixin4j server startup OK:{}", serverPort);
213 } else {
214 logger.info("weixin4j server startup FAIL:{}", serverPort);
215 }
216 }
217 }).sync().channel();
218 ch.closeFuture().sync();
219 } catch (InterruptedException e) {
220 throw new RuntimeException(e);
221 } finally {
222 shutdown(false);
223 }
224 }
225
226
227
228
229
230
231
232
233 public boolean shutdown(boolean blocking) {
234 if (bootstrap == null) {
235 return false;
236 }
237 ServerBootstrapConfig c = bootstrap.config();
238 Future<?> bossF = c.group().shutdownGracefully();
239 Future<?> workerF = c.childGroup().shutdownGracefully();
240 if (blocking) {
241 bossF.awaitUninterruptibly();
242 workerF.awaitUninterruptibly();
243 }
244 messageHandlerList = null;
245 messageInterceptorList = null;
246 messageDispatcher = null;
247 bootstrap = null;
248 return true;
249 }
250
251
252
253
254
255
256
257
258 public WeixinServerBootstrap addHandler(WeixinMessageHandler... messageHandler) {
259 if (messageHandler == null) {
260 throw new IllegalArgumentException("messageHandler not be null");
261 }
262 messageHandlerList.addAll(Arrays.asList(messageHandler));
263 return this;
264 }
265
266
267
268
269
270
271
272
273 public WeixinServerBootstrap addInterceptor(WeixinMessageInterceptor... messageInterceptor) {
274 if (messageInterceptor == null) {
275 throw new IllegalArgumentException("messageInterceptor not be null");
276 }
277 messageInterceptorList.addAll(Arrays.asList(messageInterceptor));
278 return this;
279 }
280
281
282
283
284
285
286
287
288 public WeixinServerBootstrap handlerPackagesToScan(String... messageHandlerPackages) {
289 if (messageHandlerPackages == null) {
290 throw new IllegalArgumentException("messageHandlerPackages not be null");
291 }
292 messageDispatcher.setMessageHandlerPackages(messageHandlerPackages);
293 return this;
294 }
295
296
297
298
299
300
301
302
303 public WeixinServerBootstrap interceptorPackagesToScan(String... messageInterceptorPackages) {
304 if (messageInterceptorPackages == null) {
305 throw new IllegalArgumentException("messageInterceptorPackages not be null");
306 }
307 messageDispatcher.setMessageInterceptorPackages(messageInterceptorPackages);
308 return this;
309 }
310
311
312
313
314
315
316
317
318 public WeixinServerBootstrap resolveBeanFactory(BeanFactory beanFactory) {
319 messageDispatcher.setBeanFactory(beanFactory);
320 return this;
321 }
322
323
324
325
326
327
328
329
330
331
332 public WeixinServerBootstrap registMessageClass(WeixinMessageKey messageKey,
333 Class<? extends WeixinMessage> messageClass) {
334 messageDispatcher.registMessageClass(messageKey, messageClass);
335 return this;
336 }
337
338
339
340
341 public WeixinServerBootstrap openAlwaysResponse() {
342 messageDispatcher.openAlwaysResponse();
343 return this;
344 }
345
346
347
348
349
350
351
352 public boolean addAesToken(AesToken aesToken) {
353 if (bootstrap == null) {
354 return false;
355 }
356 ServerBootstrapConfig c = bootstrap.config();
357 ((WeixinServerInitializer) c.childHandler()).addAesToken(aesToken);
358 return true;
359 }
360
361 public final static String VERSION = "1.1.9";
362 }