package com.chamago.bison; import com.caucho.hessian.io.Hessian2Input; import com.caucho.hessian.io.Hessian2Output; import com.chamago.bison.codec.BeanCallCode; import com.chamago.bison.codec.netty.BisonChannelPipleFactory; import com.chamago.bison.codec.netty.BisonClientNettyHandler; import com.chamago.bison.dbpool.JdbcPoolManager; import com.chamago.bison.helper.BisonObject; import com.chamago.bison.helper.BisonObjectManage; import com.chamago.bison.logger.Logger; import com.chamago.bison.logger.LoggerFactory; import com.chamago.bison.node.BisonNode; import com.chamago.bison.node.BisonGroup; import com.chamago.bison.queue.LinkListQueue; import com.chamago.bison.queue.CallQueueListener; import com.chamago.bison.queue.Handler; import com.chamago.bison.util.ByteUtil; import com.chamago.bison.util.ZipUtil; import com.chamago.bison.util.xml.JXmlWapper; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.Hashtable; import java.util.Iterator; import java.util.Queue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import io.netty.bootstrap.Bootstrap; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioSocketChannel; /** * * @author Gavin.peng * * 2013-10-16 下午02:46:50 × bison-client */ public class BisonContext { private static final int CONNECT_TIMEOUT = 30; private static final boolean ZIP_FLAG = true; private static final String SESSION_NODE_KEY = "bison.conetxt.sesionn.key"; protected final Queue<BisonNode> connectQueue = new ConcurrentLinkedQueue<BisonNode>(); protected final ConcurrentHashMap<String, BisonGroup> groupMaps = new ConcurrentHashMap<String, BisonGroup>(); protected Executor executor; protected Logger logger; public LinkListQueue<BisonObject> sendQueue; public LinkListQueue<Object> recvQueue; public Bootstrap bootstrap; protected BisonObjectManage[] amanager; protected boolean dispose = false; protected Processor processor; private String configFile; private JdbcPoolManager pool; private int handlers = 10; private static BisonContext defaultContext; protected Hashtable<String, Handler<BisonObject>> sThreads; protected Hashtable<String, Handler<Object>> rThreads; public BisonContext(String configFile) { this.configFile = configFile; this.pool = new JdbcPoolManager(configFile); this.pool.loadDataSource(); this.logger = LoggerFactory.getLogger("bison"); this.executor = Executors.newCachedThreadPool(); this.sendQueue = new LinkListQueue<BisonObject>(); this.recvQueue = new LinkListQueue<Object>(); this.sThreads = new Hashtable<String, Handler<BisonObject>>(handlers); this.rThreads = new Hashtable<String, Handler<Object>>(handlers); CallQueueListener<Object> receProxy = new RecvProxy<Object>(); CallQueueListener<BisonObject> sendProxy = new SendProxy<BisonObject>(); for (int i = 0; i < handlers; i++) { Handler<BisonObject> shandler = new Handler<BisonObject>(sendQueue,i,"BisonSendThread"); Handler<Object> rhandler = new Handler<Object>(recvQueue,i,"BisonRecvThread"); shandler.registerListener(sendProxy); rhandler.registerListener(receProxy); shandler.setDaemon(true); rhandler.setDaemon(true); rhandler.start(); shandler.start(); this.sThreads.put(String.valueOf(i), shandler); this.rThreads.put(String.valueOf(i), rhandler); } this.amanager = new BisonObjectManage[10]; Executor executor1 = Executors.newCachedThreadPool(); for (int i = 0; i < 10; i++) { this.amanager[i] = new BisonObjectManage(executor1); } initNettyBootstrap(); load_config(); } public void initNettyBootstrap(){ final BisonClientNettyHandler handler = new BisonClientNettyHandler(this); EventLoopGroup group = new NioEventLoopGroup(); bootstrap = new Bootstrap(); bootstrap.group(group) .channel(NioSocketChannel.class) .option(ChannelOption.TCP_NODELAY, true) .handler(new BisonChannelPipleFactory(this)); } protected synchronized void startProcessor() { if ((this.processor == null) && (!this.dispose)) { this.processor = new Processor(); this.executor.execute(this.processor); } } private void load_config() { JXmlWapper xml = JXmlWapper.parse(new File(this.configFile)); int gcount = xml.countXmlNodes("group"); for (int i = 0; i < gcount; i++) { JXmlWapper gnode = xml.getXmlNode("group[" + i + "]"); String gid = gnode.getStringValue("@id"); String gName = gnode.getStringValue("@name"); BisonGroup objGroup = new BisonGroup(); objGroup.setGroupID(gid); objGroup.setGroupName(gName); int ncount = gnode.countXmlNodes("node"); for (int j = 0; j < ncount; j++) { JXmlWapper node = gnode.getXmlNode("node[" + j + "]"); String nid = node.getStringValue("@id"); String nip = node.getStringValue("@ip"); String name = node.getStringValue("@name"); int port = Integer.parseInt(node.getStringValue("@port")); BisonNode objNode = new BisonNode(); objNode.setNodeID(nid); objNode.setNodeIp(nip); objNode.setPort(port); objNode.setNodeName(name); SocketAddress address = new InetSocketAddress(nip, port); objNode.setRemoteAddress(address); this.connectQueue.offer(objNode); objGroup.addNode(objNode); this.logger.info("加载节点 ---> " + objNode.toString()); } this.groupMaps.put(gid, objGroup); } startProcessor(); } protected int send_message(BisonObject sender) { if (!this.sendQueue.offer(sender)) { System.out.println("发送消息 入队列失败"); } return 0; } private void process_recv_message(Object message) { try { byte[] msg = (byte[])message; int msgID = ByteUtil.readInt(msg, 0); if ((msgID == BeanCallCode.BEAN_CALL_ID) || (msgID == BeanCallCode.INTERFACE_CALL_ID)) { int key = ByteUtil.readInt(msg, 4); int ret = ByteUtil.readInt(msg, 8); int idx = getManagerIdx(key); BisonObject o = this.amanager[idx].findManageObject(key); if (o != null) { Object obj = null; if(ret!=BeanCallCode.CALL_SEROVERLOAD){ ByteArrayInputStream in = new ByteArrayInputStream(msg,12,msg.length); Hessian2Input is = new Hessian2Input(in); obj = is.readObject(); } o._onReceiveMessageEvent(ret, obj); obj = null; } else { this.logger.error("没有找到通知对象 " + key); } this.amanager[idx].removeManageObject(key); o = null; } msg = (byte[])null; message = null; } catch (Exception e) { this.logger.error("处理消息出现异常", e); } message = null; } private int send_message_now(BisonObject obj) { int ret = 0; int idx = getManagerIdx(obj.getKey()); BisonGroup objGroup = (BisonGroup)this.groupMaps.get(obj.getGroupID()); if (objGroup != null) { BisonNode objNode = objGroup.getNode(); if ((objNode != null) && (objNode.isConnected())) { this.amanager[idx].addObjectToManager(obj.getKey(), obj); if (obj.isAsync()) { this.amanager[idx].addToTimeOutMonitor(obj.getKey()); } ret = sendObject(obj, objNode.getChannel()); } else { if(objNode == null){ try { System.out.println("等待和服务端建立连接 "); Thread.sleep(2000); send_message(obj); System.out.println("msg obj:重新 进入发送队列"); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }else{ } System.out.println("没有可以用的接受node"); ret = -7; } } else { System.out.println("没有可以用的接受服务端"); ret = -6; } return ret; } private int sendObject(BisonObject obj, Channel channel) { int ret = 0; try { int callType = obj.getCallType(); if (callType == BeanCallCode.INTERFACE_CALL_ID) { ByteArrayOutputStream bos = new ByteArrayOutputStream(); Hessian2Output out = new Hessian2Output(bos); out.writeObject(obj); out.flush(); byte[] data = bos.toByteArray(); ByteBuf byteBuf = Unpooled.buffer(8 + data.length); byteBuf.writeInt(obj.getCallType()); byteBuf.writeInt(obj.getKey()); byteBuf.writeBytes(data); channel.writeAndFlush(byteBuf); data = null; byteBuf = null; obj = null; } } catch (Exception e) { this.logger.error("sendObject", e); e.printStackTrace(); ret = -5; } return ret; } public void broadcast(Object message, String methodName) { try { // byte[] data = ZipUtil.ZipObject(message, true); // // byte[] buf = new byte[8 + data.length + methodName.length() + 1]; // ByteUtil.writeInt(buf, 0, 34952); // ByteUtil.writeInt(buf, 4, 2147483647); // ByteUtil.writeString(buf, 8, methodName); // System.arraycopy(data, 0, buf, 8 + methodName.length() + 1, data.length); //this.connector.broadcast(buf); // data = (byte[])null; // buf = (byte[])null; message = null; } catch (Exception e) { this.logger.error("broadcast", e); e.printStackTrace(); } } protected void removeManagedObject(int key) { this.amanager[getManagerIdx(key)].removeManageObject(key); } private int getManagerIdx(int key) { return key % 100 / 10; } public void destory() { this.dispose = true; this.connectQueue.clear(); //this.bootstrap. // Map mapt = this.connector.getManagedSessions(); // Iterator iterator = mapt.keySet().iterator(); // while (iterator.hasNext()) { // Long key = (Long)iterator.next(); // ((IoSession)mapt.get(key)).close(true); // } try { Thread.sleep(3000L); } catch (Exception localException) { } this.bootstrap.group().shutdownGracefully(); this.connectQueue.clear(); this.groupMaps.clear(); this.sendQueue.clear(); this.recvQueue.clear(); Iterator siterator = this.sThreads.keySet().iterator(); while (siterator.hasNext()) { Object key = siterator.next(); Handler dt = (Handler)this.sThreads.get(key); dt.stopThread(); dt = null; } Iterator titerator = this.rThreads.keySet().iterator(); while (titerator.hasNext()) { Object key = titerator.next(); Handler dt = (Handler)this.rThreads.get(key); dt.stopThread(); dt = null; } } public static void setDefaultContext(BisonContext context) { defaultContext = context; } public static BisonContext getDefaultContext() { return defaultContext; } private final class RecvProxy<E> implements CallQueueListener<E> { private RecvProxy() { } public void processQueueElement(E o, int threadID) { BisonContext.this.process_recv_message(o); } } private final class SendProxy<E> implements CallQueueListener<E> { private SendProxy() { } public void processQueueElement(E o, int threadID) { BisonContext.this.send_message_now((BisonObject)o); } } private final class Processor implements Runnable { private Processor() { } public void run() { while (true) { BisonNode node = (BisonNode)BisonContext.this.connectQueue.poll(); if ((node == null) && (BisonContext.this.connectQueue.size() == 0)) { BisonContext.this.processor = null; break; } ChannelFuture cf = BisonContext.this.bootstrap.connect(node.getNodeIp(),node.getPort()); //ConnectFuture cf = BisonContext.this.connector.connect(node.getRemoteAddress()); cf.awaitUninterruptibly(); if (!cf.isSuccess()) { BisonContext.this.logger.info("建立连接失败 " + node.toString()); try { if (BisonContext.this.connectQueue.size() == 0) Thread.sleep(5000L); else Thread.sleep(1000L); } catch (Exception localException) { } BisonContext.this.connectQueue.offer(node); continue; } //cf.setAttribute(SESSION_NODE_KEY, node); node.setChannel(cf.channel()); node.setConnected(true); BisonContext.this.logger.info("建立连接成功 " + node.toString()); } } } }