View Javadoc
1   package com.foxinmy.weixin4j.dispatcher;
2   
3   import static io.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND;
4   
5   import java.io.ByteArrayInputStream;
6   import java.lang.reflect.Constructor;
7   import java.lang.reflect.Modifier;
8   import java.util.ArrayList;
9   import java.util.Collections;
10  import java.util.Comparator;
11  import java.util.List;
12  import java.util.Map;
13  import java.util.Set;
14  import java.util.concurrent.ConcurrentHashMap;
15  
16  import javax.xml.bind.JAXBContext;
17  import javax.xml.bind.JAXBElement;
18  import javax.xml.bind.JAXBException;
19  import javax.xml.bind.Unmarshaller;
20  import javax.xml.transform.Source;
21  import javax.xml.transform.stream.StreamSource;
22  
23  import com.foxinmy.weixin4j.handler.WeixinMessageHandler;
24  import com.foxinmy.weixin4j.interceptor.WeixinMessageInterceptor;
25  import com.foxinmy.weixin4j.request.WeixinMessage;
26  import com.foxinmy.weixin4j.request.WeixinRequest;
27  import com.foxinmy.weixin4j.response.BlankResponse;
28  import com.foxinmy.weixin4j.response.WeixinResponse;
29  import com.foxinmy.weixin4j.socket.WeixinMessageTransfer;
30  import com.foxinmy.weixin4j.util.ClassUtil;
31  import com.foxinmy.weixin4j.util.HttpUtil;
32  import com.foxinmy.weixin4j.util.ServerToolkits;
33  import com.foxinmy.weixin4j.xml.MessageTransferHandler;
34  
35  import io.netty.channel.ChannelFutureListener;
36  import io.netty.channel.ChannelHandlerContext;
37  import io.netty.handler.codec.http.DefaultFullHttpResponse;
38  import io.netty.handler.codec.http.FullHttpResponse;
39  import io.netty.util.internal.logging.InternalLogger;
40  import io.netty.util.internal.logging.InternalLoggerFactory;
41  
42  /**
43   * 微信消息分发器
44   *
45   * @className WeixinMessageDispatcher
46   * @author jinyu(foxinmy@gmail.com)
47   * @date 2015年5月7日
48   * @since JDK 1.6
49   * @see com.foxinmy.weixin4j.handler.WeixinMessageHandler
50   * @see com.foxinmy.weixin4j.interceptor.WeixinMessageInterceptor
51   * @see com.foxinmy.weixin4j.dispatcher.WeixinMessageMatcher
52   * @see com.foxinmy.weixin4j.dispatcher.MessageHandlerExecutor
53   * @see com.foxinmy.weixin4j.dispatcher.BeanFactory
54   */
55  public class WeixinMessageDispatcher {
56  
57      private final InternalLogger logger = InternalLoggerFactory.getInstance(getClass());
58  
59      /**
60       * 消息处理器
61       */
62      private List<WeixinMessageHandler> messageHandlerList;
63      private WeixinMessageHandler[] messageHandlers;
64      /**
65       * 消息处理器所在的包
66       */
67      private String[] messageHandlerPackages;
68  
69      /**
70       * 消息拦截器
71       */
72      private List<WeixinMessageInterceptor> messageInterceptorList;
73      private WeixinMessageInterceptor[] messageInterceptors;
74      /**
75       * 消息拦截器所在的包
76       */
77      private String[] messageInterceptorPackages;
78  
79      /**
80       * Bean构造
81       */
82      private BeanFactory beanFactory;
83  
84      /**
85       * 消息匹配
86       */
87      private WeixinMessageMatcher messageMatcher;
88      /**
89       * 消息转换
90       */
91      private Map<Class<? extends WeixinMessage>, Unmarshaller> messageUnmarshaller;
92      /**
93       * 是否总是响应请求,如未匹配到MessageHandler时回复空白消息
94       */
95      private boolean alwaysResponse;
96  
97      public WeixinMessageDispatcher() {
98          this(new DefaultMessageMatcher());
99      }
100 
101     public WeixinMessageDispatcher(WeixinMessageMatcher messageMatcher) {
102         this.messageMatcher = messageMatcher;
103         this.messageUnmarshaller = new ConcurrentHashMap<Class<? extends WeixinMessage>, Unmarshaller>();
104     }
105 
106     /**
107      * 对消息进行一系列的处理,包括 拦截、匹配、分发等动作
108      *
109      * @param context
110      *            上下文环境
111      * @param request
112      *            微信请求
113      * @param messageTransfer
114      *            微信消息 @
115      */
116     public void doDispatch(final ChannelHandlerContext context, final WeixinRequest request) {
117         WeixinMessageTransfer messageTransfer = MessageTransferHandler.parser(request);
118         context.channel().attr(ServerToolkits.MESSAGE_TRANSFER_KEY).set(messageTransfer);
119         WeixinMessageKey messageKey = defineMessageKey(messageTransfer, request);
120         Class<? extends WeixinMessage> targetClass = messageMatcher.match(messageKey);
121         WeixinMessage message = messageRead(request.getOriginalContent(), targetClass);
122         logger.info("define '{}' matched '{}'", messageKey, targetClass);
123         MessageHandlerExecutor handlerExecutor = getHandlerExecutor(context, request, messageKey, message,
124                 messageTransfer.getNodeNames());
125         if (handlerExecutor == null || handlerExecutor.getMessageHandler() == null) {
126             noHandlerFound(context, request, message);
127             return;
128         }
129         if (!handlerExecutor.applyPreHandle(request, message)) {
130             return;
131         }
132         Exception exception = null;
133         WeixinResponse response = null;
134         try {
135             response = handlerExecutor.getMessageHandler().doHandle(request, message);
136             handlerExecutor.applyPostHandle(request, response, message);
137             context.writeAndFlush(response);
138         } catch (Exception e) {
139             exception = e;
140         }
141         handlerExecutor.triggerAfterCompletion(request, response, message, exception);
142     }
143 
144     /**
145      * 声明messagekey
146      *
147      * @param messageTransfer
148      *            基础消息
149      * @param request
150      *            请求信息
151      * @return
152      */
153     protected WeixinMessageKey defineMessageKey(WeixinMessageTransfer messageTransfer, WeixinRequest request) {
154         return new WeixinMessageKey(messageTransfer.getMsgType(), messageTransfer.getEventType(),
155                 messageTransfer.getAccountType());
156     }
157 
158     /**
159      * 未匹配到handler时触发
160      *
161      * @param context
162      *            上下文环境
163      * @param request
164      *            微信请求
165      * @param message
166      *            微信消息
167      */
168     protected void noHandlerFound(ChannelHandlerContext context, WeixinRequest request, WeixinMessage message) {
169         logger.warn("no handler found for {}", request);
170         if (alwaysResponse) {
171             context.write(BlankResponse.global);
172         } else {
173             FullHttpResponse response = new DefaultFullHttpResponse(request.getProtocolVersion(), NOT_FOUND);
174             HttpUtil.resolveHeaders(response);
175             context.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
176         }
177     }
178 
179     /**
180      * MessageHandlerExecutor
181      *
182      * @param context
183      *            上下文环境
184      * @param request
185      *            微信请求
186      * @param messageKey
187      *            消息的key
188      * @param message
189      *            微信消息
190      * @param nodeNames
191      *            节点名称集合
192      * @return MessageHandlerExecutor
193      * @see MessageHandlerExecutor @
194      */
195     protected MessageHandlerExecutor getHandlerExecutor(ChannelHandlerContext context, WeixinRequest request,
196             WeixinMessageKey messageKey, WeixinMessage message, Set<String> nodeNames) {
197         WeixinMessageHandler[] messageHandlers = getMessageHandlers();
198         if (messageHandlers == null) {
199             return null;
200         }
201         logger.info("resolve message handlers '{}'", this.messageHandlerList);
202         List<WeixinMessageHandler> matchedMessageHandlers = new ArrayList<WeixinMessageHandler>();
203         for (WeixinMessageHandler handler : messageHandlers) {
204             if (handler.canHandle(request, message, nodeNames)) {
205                 matchedMessageHandlers.add(handler);
206             }
207         }
208         if (matchedMessageHandlers.isEmpty()) {
209             return null;
210         }
211         Collections.sort(matchedMessageHandlers, new Comparator<WeixinMessageHandler>() {
212             @Override
213             public int compare(WeixinMessageHandler m1, WeixinMessageHandler m2) {
214                 return m2.weight() - m1.weight();
215             }
216         });
217         logger.info("matched message handlers '{}'", matchedMessageHandlers);
218         return new MessageHandlerExecutor(context, matchedMessageHandlers.get(0), getMessageInterceptors());
219     }
220 
221     /**
222      * 获取所有的handler
223      *
224      * @return handler集合
225      * @see com.foxinmy.weixin4j.handler.WeixinMessageHandler @
226      */
227     public WeixinMessageHandler[] getMessageHandlers() {
228         if (this.messageHandlers == null) {
229             if (messageHandlerPackages != null) {
230                 List<Class<?>> messageHandlerClass = new ArrayList<Class<?>>();
231                 for (String packageName : messageHandlerPackages) {
232                     messageHandlerClass.addAll(ClassUtil.getClasses(packageName));
233                 }
234                 if (beanFactory != null) {
235                     for (Class<?> clazz : messageHandlerClass) {
236                         if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())
237                                 || !WeixinMessageHandler.class.isAssignableFrom(clazz)) {
238                             continue;
239                         }
240                         try {
241                             messageHandlerList.add((WeixinMessageHandler) beanFactory.getBean(clazz));
242                         } catch (RuntimeException ex) { // multiple
243                             for (Object o : beanFactory.getBeans(clazz).values()) {
244                                 if (o.getClass() == clazz) {
245                                     messageHandlerList.add((WeixinMessageHandler) o);
246                                     break;
247                                 }
248                             }
249                         }
250                     }
251                 } else {
252                     for (Class<?> clazz : messageHandlerClass) {
253                         if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())
254                                 || !WeixinMessageHandler.class.isAssignableFrom(clazz)) {
255                             continue;
256                         }
257                         try {
258                             Constructor<?> ctor = clazz.getDeclaredConstructor();
259                             ServerToolkits.makeConstructorAccessible(ctor);
260                             messageHandlerList.add((WeixinMessageHandler) ctor.newInstance((Object[]) null));
261                         } catch (Exception ex) {
262                             throw new RuntimeException(clazz.getName() + " instantiate fail", ex);
263                         }
264                     }
265                 }
266             }
267             if (messageHandlerList != null && !this.messageHandlerList.isEmpty()) {
268                 this.messageHandlers = this.messageHandlerList
269                         .toArray(new WeixinMessageHandler[this.messageHandlerList.size()]);
270             }
271         }
272         return this.messageHandlers;
273     }
274 
275     /**
276      * 获取所有的interceptor
277      *
278      * @return interceptor集合
279      * @ @see com.foxinmy.weixin4j.interceptor.WeixinMessageInterceptor
280      */
281     public WeixinMessageInterceptor[] getMessageInterceptors() {
282         if (this.messageInterceptors == null) {
283             if (this.messageInterceptorPackages != null) {
284                 List<Class<?>> messageInterceptorClass = new ArrayList<Class<?>>();
285                 for (String packageName : messageInterceptorPackages) {
286                     messageInterceptorClass.addAll(ClassUtil.getClasses(packageName));
287                 }
288                 if (beanFactory != null) {
289                     for (Class<?> clazz : messageInterceptorClass) {
290                         if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())
291                                 || !WeixinMessageInterceptor.class.isAssignableFrom(clazz)) {
292                             continue;
293                         }
294                         try {
295                             messageInterceptorList.add((WeixinMessageInterceptor) beanFactory.getBean(clazz));
296                         } catch (RuntimeException ex) { // multiple
297                             for (Object o : beanFactory.getBeans(clazz).values()) {
298                                 if (o.getClass() == clazz) {
299                                     messageInterceptorList.add((WeixinMessageInterceptor) o);
300                                     break;
301                                 }
302                             }
303                         }
304                     }
305                 } else {
306                     for (Class<?> clazz : messageInterceptorClass) {
307                         if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())
308                                 || !WeixinMessageInterceptor.class.isAssignableFrom(clazz)) {
309                             continue;
310                         }
311                         try {
312                             Constructor<?> ctor = clazz.getDeclaredConstructor();
313                             ServerToolkits.makeConstructorAccessible(ctor);
314                             messageInterceptorList.add((WeixinMessageInterceptor) ctor.newInstance((Object[]) null));
315                         } catch (Exception ex) {
316                             throw new RuntimeException(clazz.getName() + " instantiate fail", ex);
317                         }
318                     }
319                 }
320             }
321             if (this.messageInterceptorList != null && !this.messageInterceptorList.isEmpty()) {
322                 Collections.sort(messageInterceptorList, new Comparator<WeixinMessageInterceptor>() {
323                     @Override
324                     public int compare(WeixinMessageInterceptor m1, WeixinMessageInterceptor m2) {
325                         return m2.weight() - m1.weight();
326                     }
327                 });
328                 this.messageInterceptors = this.messageInterceptorList
329                         .toArray(new WeixinMessageInterceptor[this.messageInterceptorList.size()]);
330             }
331         }
332         logger.info("resolve message interceptors '{}'", this.messageInterceptorList);
333         return this.messageInterceptors;
334     }
335 
336     /**
337      * jaxb读取微信消息
338      *
339      * @param message
340      *            xml消息
341      * @param clazz
342      *            消息类型
343      * @return 消息对象 @
344      */
345     protected <M extends WeixinMessage> M messageRead(String message, Class<M> clazz) {
346         if (clazz == null) {
347             return null;
348         }
349         try {
350             Source source = new StreamSource(new ByteArrayInputStream(ServerToolkits.getBytesUtf8(message)));
351             JAXBElement<M> jaxbElement = getUnmarshaller(clazz).unmarshal(source, clazz);
352             return jaxbElement.getValue();
353         } catch (JAXBException e) {
354             throw new RuntimeException(e);
355         }
356     }
357 
358     /**
359      * xml消息转换器
360      *
361      * @param clazz
362      *            消息类型
363      * @return 消息转换器 @
364      */
365     protected Unmarshaller getUnmarshaller(Class<? extends WeixinMessage> clazz) {
366         Unmarshaller unmarshaller = messageUnmarshaller.get(clazz);
367         if (unmarshaller == null) {
368             try {
369                 JAXBContext jaxbContext = JAXBContext.newInstance(clazz);
370                 unmarshaller = jaxbContext.createUnmarshaller();
371                 messageUnmarshaller.put(clazz, unmarshaller);
372             } catch (JAXBException e) {
373                 throw new RuntimeException(e);
374             }
375         }
376         return unmarshaller;
377     }
378 
379     public void setMessageHandlerList(List<WeixinMessageHandler> messageHandlerList) {
380         this.messageHandlerList = messageHandlerList;
381     }
382 
383     public void setMessageInterceptorList(List<WeixinMessageInterceptor> messageInterceptorList) {
384         this.messageInterceptorList = messageInterceptorList;
385     }
386 
387     public String[] getMessageHandlerPackages() {
388         return messageHandlerPackages;
389     }
390 
391     public String[] getMessageInterceptorPackages() {
392         return messageInterceptorPackages;
393     }
394 
395     public void setMessageHandlerPackages(String... messageHandlerPackages) {
396         this.messageHandlerPackages = messageHandlerPackages;
397     }
398 
399     public void setMessageInterceptorPackages(String... messageInterceptorPackages) {
400         this.messageInterceptorPackages = messageInterceptorPackages;
401     }
402 
403     public BeanFactory getBeanFactory() {
404         return beanFactory;
405     }
406 
407     public void setBeanFactory(BeanFactory beanFactory) {
408         this.beanFactory = beanFactory;
409     }
410 
411     public void registMessageClass(WeixinMessageKey messageKey, Class<? extends WeixinMessage> messageClass) {
412         messageMatcher.regist(messageKey, messageClass);
413     }
414 
415     public WeixinMessageMatcher getMessageMatcher() {
416         return this.messageMatcher;
417     }
418 
419     /**
420      * 打开总是响应开关,如未匹配到MessageHandler时回复空白消息
421      */
422     public void openAlwaysResponse() {
423         this.alwaysResponse = true;
424     }
425 }