package com.foxinmy.weixin4j.dispatcher; import static io.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.http.DefaultFullHttpResponse; import io.netty.handler.codec.http.FullHttpResponse; import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; import java.io.ByteArrayInputStream; import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; import javax.xml.bind.Unmarshaller; import javax.xml.transform.Source; import javax.xml.transform.stream.StreamSource; import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.handler.WeixinMessageHandler; import com.foxinmy.weixin4j.interceptor.WeixinMessageInterceptor; import com.foxinmy.weixin4j.request.WeixinMessage; import com.foxinmy.weixin4j.request.WeixinRequest; import com.foxinmy.weixin4j.response.BlankResponse; import com.foxinmy.weixin4j.response.WeixinResponse; import com.foxinmy.weixin4j.socket.WeixinMessageTransfer; import com.foxinmy.weixin4j.util.ClassUtil; import com.foxinmy.weixin4j.util.HttpUtil; import com.foxinmy.weixin4j.util.ServerToolkits; import com.foxinmy.weixin4j.xml.MessageTransferHandler; /** * 微信消息分发器 * * @className WeixinMessageDispatcher * @author jinyu(foxinmy@gmail.com) * @date 2015年5月7日 * @since JDK 1.6 * @see com.foxinmy.weixin4j.handler.WeixinMessageHandler * @see com.foxinmy.weixin4j.interceptor.WeixinMessageInterceptor * @see com.foxinmy.weixin4j.dispatcher.WeixinMessageMatcher * @see com.foxinmy.weixin4j.dispatcher.MessageHandlerExecutor * @see com.foxinmy.weixin4j.dispatcher.BeanFactory */ public class WeixinMessageDispatcher { private final InternalLogger logger = InternalLoggerFactory .getInstance(getClass()); /** * 消息处理器 */ private List<WeixinMessageHandler> messageHandlerList; private WeixinMessageHandler[] messageHandlers; /** * 消息处理器所在的包 */ private String[] messageHandlerPackages; /** * 消息拦截器 */ private List<WeixinMessageInterceptor> messageInterceptorList; private WeixinMessageInterceptor[] messageInterceptors; /** * 消息拦截器所在的包 */ private String[] messageInterceptorPackages; /** * Bean构造 */ private BeanFactory beanFactory; /** * 消息匹配 */ private WeixinMessageMatcher messageMatcher; /** * 消息转换 */ private Map<Class<? extends WeixinMessage>, Unmarshaller> messageUnmarshaller; /** * 是否总是响应请求,如未匹配到MessageHandler时回复空白消息 */ private boolean alwaysResponse; public WeixinMessageDispatcher() { this(new DefaultMessageMatcher()); } public WeixinMessageDispatcher(WeixinMessageMatcher messageMatcher) { this.messageMatcher = messageMatcher; this.messageUnmarshaller = new ConcurrentHashMap<Class<? extends WeixinMessage>, Unmarshaller>(); } /** * 对消息进行一系列的处理,包括 拦截、匹配、分发等动作 * * @param context * 上下文环境 * @param request * 微信请求 * @param messageTransfer * 微信消息 * @throws WeixinException */ public void doDispatch(final ChannelHandlerContext context, final WeixinRequest request) throws WeixinException { WeixinMessageTransfer messageTransfer = MessageTransferHandler .parser(request); context.channel().attr(ServerToolkits.MESSAGE_TRANSFER_KEY) .set(messageTransfer); WeixinMessageKey messageKey = defineMessageKey(messageTransfer, request); Class<? extends WeixinMessage> targetClass = messageMatcher .match(messageKey); WeixinMessage message = messageRead(request.getOriginalContent(), targetClass); logger.info("define '{}' matched '{}'", messageKey, targetClass); MessageHandlerExecutor handlerExecutor = getHandlerExecutor(context, request, messageKey, message, messageTransfer.getNodeNames()); if (handlerExecutor == null || handlerExecutor.getMessageHandler() == null) { noHandlerFound(context, request, message); return; } if (!handlerExecutor.applyPreHandle(request, message)) { return; } Exception exception = null; WeixinResponse response = null; try { response = handlerExecutor.getMessageHandler().doHandle(request, message, messageTransfer.getNodeNames()); handlerExecutor.applyPostHandle(request, response, message); context.writeAndFlush(response); } catch (Exception e) { exception = e; } handlerExecutor.triggerAfterCompletion(request, response, message, exception); } /** * 声明messagekey * * @param messageTransfer * 基础消息 * @param request * 请求信息 * @return */ protected WeixinMessageKey defineMessageKey( WeixinMessageTransfer messageTransfer, WeixinRequest request) { return new WeixinMessageKey(messageTransfer.getMsgType(), messageTransfer.getEventType(), messageTransfer.getAccountType()); } /** * 未匹配到handler时触发 * * @param context * 上下文环境 * @param request * 微信请求 * @param message * 微信消息 */ protected void noHandlerFound(ChannelHandlerContext context, WeixinRequest request, WeixinMessage message) { logger.warn("no handler found for {}", request); if (alwaysResponse) { context.write(BlankResponse.global); } else { FullHttpResponse response = new DefaultFullHttpResponse( request.getProtocolVersion(), NOT_FOUND); HttpUtil.resolveHeaders(response); context.writeAndFlush(response).addListener( ChannelFutureListener.CLOSE); } } /** * MessageHandlerExecutor * * @param context * 上下文环境 * @param request * 微信请求 * @param messageKey * 消息的key * @param message * 微信消息 * @param nodeNames * 节点名称集合 * @return MessageHandlerExecutor * @see MessageHandlerExecutor * @throws WeixinException */ protected MessageHandlerExecutor getHandlerExecutor( ChannelHandlerContext context, WeixinRequest request, WeixinMessageKey messageKey, WeixinMessage message, Set<String> nodeNames) throws WeixinException { WeixinMessageHandler[] messageHandlers = getMessageHandlers(); if (messageHandlers == null) { return null; } logger.info("resolve message handlers '{}'", this.messageHandlerList); List<WeixinMessageHandler> matchedMessageHandlers = new ArrayList<WeixinMessageHandler>(); for (WeixinMessageHandler handler : messageHandlers) { if (handler.canHandle(request, message, nodeNames)) { matchedMessageHandlers.add(handler); } } if (matchedMessageHandlers.isEmpty()) { return null; } Collections.sort(matchedMessageHandlers, new Comparator<WeixinMessageHandler>() { @Override public int compare(WeixinMessageHandler m1, WeixinMessageHandler m2) { return m2.weight() - m1.weight(); } }); logger.info("matched message handlers '{}'", matchedMessageHandlers); return new MessageHandlerExecutor(context, matchedMessageHandlers.get(0), getMessageInterceptors()); } /** * 获取所有的handler * * @return handler集合 * @see com.foxinmy.weixin4j.handler.WeixinMessageHandler * @throws WeixinException */ public WeixinMessageHandler[] getMessageHandlers() throws WeixinException { if (this.messageHandlers == null) { if (messageHandlerPackages != null) { List<Class<?>> messageHandlerClass = new ArrayList<Class<?>>(); for (String packageName : messageHandlerPackages) { messageHandlerClass.addAll(ClassUtil .getClasses(packageName)); } if (beanFactory != null) { for (Class<?> clazz : messageHandlerClass) { if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers()) || !WeixinMessageHandler.class .isAssignableFrom(clazz)) { continue; } try { messageHandlerList .add((WeixinMessageHandler) beanFactory .getBean(clazz)); } catch (RuntimeException ex) { // multiple for (Object o : beanFactory.getBeans(clazz) .values()) { if (o.getClass() == clazz) { messageHandlerList .add((WeixinMessageHandler) o); break; } } } } } else { for (Class<?> clazz : messageHandlerClass) { if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers()) || !WeixinMessageHandler.class .isAssignableFrom(clazz)) { continue; } try { Constructor<?> ctor = clazz .getDeclaredConstructor(); ServerToolkits.makeConstructorAccessible(ctor); messageHandlerList.add((WeixinMessageHandler) ctor .newInstance((Object[]) null)); } catch (Exception ex) { throw new WeixinException(clazz.getName() + " instantiate fail", ex); } } } } if (messageHandlerList != null && !this.messageHandlerList.isEmpty()) { this.messageHandlers = this.messageHandlerList .toArray(new WeixinMessageHandler[this.messageHandlerList .size()]); } } return this.messageHandlers; } /** * 获取所有的interceptor * * @return interceptor集合 * @throws WeixinException * @see com.foxinmy.weixin4j.interceptor.WeixinMessageInterceptor */ public WeixinMessageInterceptor[] getMessageInterceptors() throws WeixinException { if (this.messageInterceptors == null) { if (this.messageInterceptorPackages != null) { List<Class<?>> messageInterceptorClass = new ArrayList<Class<?>>(); for (String packageName : messageInterceptorPackages) { messageInterceptorClass.addAll(ClassUtil .getClasses(packageName)); } if (beanFactory != null) { for (Class<?> clazz : messageInterceptorClass) { if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers()) || !WeixinMessageInterceptor.class .isAssignableFrom(clazz)) { continue; } try { messageInterceptorList .add((WeixinMessageInterceptor) beanFactory .getBean(clazz)); } catch (RuntimeException ex) { // multiple for (Object o : beanFactory.getBeans(clazz) .values()) { if (o.getClass() == clazz) { messageInterceptorList .add((WeixinMessageInterceptor) o); break; } } } } } else { for (Class<?> clazz : messageInterceptorClass) { if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers()) || !WeixinMessageInterceptor.class .isAssignableFrom(clazz)) { continue; } try { Constructor<?> ctor = clazz .getDeclaredConstructor(); ServerToolkits.makeConstructorAccessible(ctor); messageInterceptorList .add((WeixinMessageInterceptor) ctor .newInstance((Object[]) null)); } catch (Exception ex) { throw new WeixinException(clazz.getName() + " instantiate fail", ex); } } } } if (this.messageInterceptorList != null && !this.messageInterceptorList.isEmpty()) { Collections.sort(messageInterceptorList, new Comparator<WeixinMessageInterceptor>() { @Override public int compare(WeixinMessageInterceptor m1, WeixinMessageInterceptor m2) { return m2.weight() - m1.weight(); } }); this.messageInterceptors = this.messageInterceptorList .toArray(new WeixinMessageInterceptor[this.messageInterceptorList .size()]); } } logger.info("resolve message interceptors '{}'", this.messageInterceptorList); return this.messageInterceptors; } /** * jaxb读取微信消息 * * @param message * xml消息 * @param clazz * 消息类型 * @return 消息对象 * @throws WeixinException */ protected <M extends WeixinMessage> M messageRead(String message, Class<M> clazz) throws WeixinException { if (clazz == null) { return null; } try { Source source = new StreamSource(new ByteArrayInputStream( ServerToolkits.getBytesUtf8(message))); JAXBElement<M> jaxbElement = getUnmarshaller(clazz).unmarshal( source, clazz); return jaxbElement.getValue(); } catch (JAXBException e) { throw new WeixinException(e); } } /** * xml消息转换器 * * @param clazz * 消息类型 * @return 消息转换器 * @throws WeixinException */ protected Unmarshaller getUnmarshaller(Class<? extends WeixinMessage> clazz) throws WeixinException { Unmarshaller unmarshaller = messageUnmarshaller.get(clazz); if (unmarshaller == null) { try { JAXBContext jaxbContext = JAXBContext.newInstance(clazz); unmarshaller = jaxbContext.createUnmarshaller(); messageUnmarshaller.put(clazz, unmarshaller); } catch (JAXBException e) { throw new WeixinException(e); } } return unmarshaller; } public void setMessageHandlerList( List<WeixinMessageHandler> messageHandlerList) { this.messageHandlerList = messageHandlerList; } public void setMessageInterceptorList( List<WeixinMessageInterceptor> messageInterceptorList) { this.messageInterceptorList = messageInterceptorList; } public String[] getMessageHandlerPackages() { return messageHandlerPackages; } public String[] getMessageInterceptorPackages() { return messageInterceptorPackages; } public void setMessageHandlerPackages(String... messageHandlerPackages) { this.messageHandlerPackages = messageHandlerPackages; } public void setMessageInterceptorPackages( String... messageInterceptorPackages) { this.messageInterceptorPackages = messageInterceptorPackages; } public BeanFactory getBeanFactory() { return beanFactory; } public void setBeanFactory(BeanFactory beanFactory) { this.beanFactory = beanFactory; } public void registMessageClass(WeixinMessageKey messageKey, Class<? extends WeixinMessage> messageClass) { messageMatcher.regist(messageKey, messageClass); } public WeixinMessageMatcher getMessageMatcher() { return this.messageMatcher; } /** * 打开总是响应开关,如未匹配到MessageHandler时回复空白消息 */ public void openAlwaysResponse() { this.alwaysResponse = true; } }