/* * Copyright (c) 2013, OpenCloudDB/MyCAT and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software;Designed and Developed mainly by many Chinese * opensource volunteers. you can redistribute it and/or modify it under the * terms of the GNU General Public License version 2 only, as published by the * Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Any questions about this component can be directed to it's project Web address * https://code.google.com/p/opencloudb/. * */ package com.talent.nio.communicate; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.net.Proxy; import java.nio.ByteOrder; import java.nio.channels.SocketChannel; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicLong; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.talent.nio.communicate.handler.PacketHandlerProxy; import com.talent.nio.communicate.handler.intf.PacketHandlerIntf; import com.talent.nio.communicate.intf.DecoderIntf; import com.talent.nio.communicate.monitor.vo.StatVo; import com.talent.nio.communicate.receive.DecodeRunnable; import com.talent.nio.communicate.receive.HandlerRunnable; import com.talent.nio.communicate.send.SendRunnable; import com.talent.nio.handler.error.client.DefaultErrorPackageHandler; import com.talent.nio.handler.error.client.ReadIOErrorHandler; import com.talent.nio.handler.error.client.WriteIOErrorHandler; import com.talent.nio.handler.error.intf.ErrorPackageHandlerIntf; import com.talent.nio.handler.error.intf.ReadIOErrorHandlerIntf; import com.talent.nio.handler.error.intf.WriteIOErrorHandlerIntf; import com.talent.nio.listener.ConnectionStateListener; import com.talent.nio.utils.SystemTimer; /** * * @author 谭耀武 * @date 2011-12-23 * */ public class ChannelContext { /** * 链路状态的枚举 * * @author 谭耀武 * @date 2011-12-28 * */ public static enum ConnectionState { /** * 未连接 */ TCP_OFF, /** * TCP正在建链 */ TCP_BUILDING, /** * TCP层已经连上链路 */ TCP_ON, /** * TCP建链失败 */ TCP_LINKFAILED, /** * 应用层链路断开 */ APP_OFF, /** * 应用层正在建链 */ APP_BUILDING, /** * 应用层已经连上链路 */ APP_ON, /** * 应用层建链失败 */ APP_LINKFAILED, /** * 正在注销 */ LOGOUTING, /** * 已经被删除了 */ REMOVED } /** * 便于应用扩展自己的属性 */ private Map<String, Object> props = new HashMap<String, Object>(); /** * connection状态监听者 */ private ConnectionStateListener connectionStateListener = null; public void addProperty(String key, Object value) { props.put(key, value); } public Object getProperty(String key) { return props.get(key); } public Object getProperty(String key, Object dftValue) { if (props.containsKey(key)) { return props.get(key); } else { return dftValue; } } public boolean isNeedRemoved(long interval) { ConnectionState s = this.connectionState; long currTime = SystemTimer.currentTimeMillis(); long compareTime = currTime - interval; boolean ret = (s == ConnectionState.TCP_OFF && statVo.getStateTimeTcpOff().getTime() < compareTime) || (s == ConnectionState.TCP_BUILDING && statVo.getStateTimeTcpBuilding().getTime() < compareTime) || (s == ConnectionState.TCP_ON && statVo.getStateTimeTcpOn().getTime() < compareTime) || (s == ConnectionState.TCP_LINKFAILED && statVo.getStateTimeTcpLinkfailed().getTime() < compareTime) || (s == ConnectionState.APP_OFF && statVo.getStateTimeAppOff().getTime() < compareTime) || (s == ConnectionState.APP_BUILDING && statVo.getStateTimeAppBuilding().getTime() < compareTime) || (s == ConnectionState.APP_LINKFAILED && statVo.getStateTimeAppLinkfailed().getTime() < compareTime); return ret; } public String getString(String key, Object dftValue) { return (String) getProperty(key, dftValue); } public boolean getBoolean(String key, Object dftValue) { return (boolean) Boolean.parseBoolean(getProperty(key, dftValue).toString()); } public int getInt(String key, Object dftValue) { return (int) Integer.parseInt(getProperty(key, dftValue).toString()); } public long getLong(String key, Object dftValue) { return (long)Long.parseLong(getProperty(key, dftValue).toString()) ; } private static final Logger log = LoggerFactory.getLogger(ChannelContext.class); private DecoderIntf decoder = null; // 组包者,应用提供 private DecodeRunnable decodeRunnable = null; // 组包runnable,框架提供 private SendRunnable sendRunnable = null; // 发送消息的runnable,框架提供 private PacketHandlerIntf packetHandler = null; // 收到消息后的handler,应用提供 private HandlerRunnable handlerRunnable = null; // 收到消息后的runnable,框架提供 /** * 发生write io异常时的处理者 */ private WriteIOErrorHandlerIntf writeIOErrorHandler = WriteIOErrorHandler.getInstance(); /** * 发生write io异常时的处理者 */ private ReadIOErrorHandlerIntf readIOErrorHandler = ReadIOErrorHandler.getInstance(); /** * 收到乱包时的处理者 */ private ErrorPackageHandlerIntf errorPackageHandler = DefaultErrorPackageHandler.getInstance(); /** * 是否自动建链(主动建链)。true: 自动建链 */ private boolean isAutoConnection = true; /** * socket通道 */ private SocketChannel socketChannel; /** * 唯一标识 */ private String id = null; private ByteOrder byteOrder = ByteOrder.BIG_ENDIAN; /** * 交互使用的协议名,这个名字可以随便取,但建议取有意义的,譬如smpp,http等 */ private String protocol = null; /** * 链路状态 */ private ConnectionState connectionState = ConnectionState.TCP_OFF; /** * 错误描述 */ private String desc4Err; /** RemoteNode基本信息 */ private RemoteNode remoteNode = null; private StatVo statVo = new StatVo(); /** * */ private String bindIp = null; /** * */ private int bindPort = 0; /** * */ private String myIp = null; /** * */ private int myPort = 0; private Proxy proxy = null; private AtomicLong seqNo = new AtomicLong(); /** * 是否需要记录发送失败的信息。true:需要记录. */ private boolean isNeedRecordSendFailMsg = false; /** * 记录发送失败记录的个数(只记录这么多条发送失败的消息) */ private int countOfRecordSendFail = 50; /** * 需要建链的链路状态集 */ private static Set<ConnectionState> needBuildConnectionStateSet = new HashSet<ConnectionState>(4); static { needBuildConnectionStateSet.add(ConnectionState.TCP_OFF); needBuildConnectionStateSet.add(ConnectionState.TCP_LINKFAILED); needBuildConnectionStateSet.add(ConnectionState.APP_OFF); needBuildConnectionStateSet.add(ConnectionState.APP_LINKFAILED); } /** * 当前状态下是否需要检查建链超时 * * @author tanyaowu * @param connectionState * @return */ public static boolean isNeedCheckBuildTimeout(ConnectionState connectionState) { return (connectionState == ConnectionState.TCP_BUILDING) || (connectionState == ConnectionState.APP_BUILDING); } public static void main(String[] args) { } private PropertyChangeSupport listeners = new PropertyChangeSupport(this); public ChannelContext(RemoteNode remoteNode, String protocol, DecoderIntf packetOgnzerIntf, PacketHandlerIntf packetHandler) { this(null, 0, remoteNode, protocol, packetOgnzerIntf, packetHandler); } /** * * @param myIp * @param myPort * @param remoteNode * @param protocol * @param packetOgnzerIntf * @param packetHandler */ public ChannelContext(String myIp, int myPort, RemoteNode remoteNode, String protocol, DecoderIntf packetOgnzerIntf, PacketHandlerIntf packetHandler) { this(myIp, myPort, remoteNode, protocol, packetOgnzerIntf, packetHandler, null); } /** * * @param myIp * @param myPort * @param remoteNode * @param protocol * @param packetOgnzerIntf * @param packetHandler * @param connectionStateListener */ public ChannelContext(String myIp, int myPort, RemoteNode remoteNode, String protocol, DecoderIntf packetOgnzerIntf, PacketHandlerIntf packetHandler, ConnectionStateListener connectionStateListener) { super(); this.remoteNode = remoteNode; this.protocol = protocol; this.decoder = packetOgnzerIntf; PacketHandlerProxy PacketHandlerProxy = new PacketHandlerProxy(packetHandler); this.packetHandler = PacketHandlerProxy; this.myIp = myIp; this.myPort = myPort; this.decodeRunnable = new DecodeRunnable(this); this.handlerRunnable = new HandlerRunnable(this); this.handlerRunnable.setParent(decodeRunnable); this.sendRunnable = new SendRunnable(this); this.setConnectionStateListener(connectionStateListener); generateId(); } private void addPropertyChangeListener(PropertyChangeListener listener) { listeners.addPropertyChangeListener(listener); } protected void firePropertyChange(String prop, Object old, Object newValue) { listeners.firePropertyChange(prop, old, newValue); } /** * 生成形如"127.0.0.1:9573-->smpp://127.10.12.124:8090"的字符串 * * @param remoteNode * @param procotol * @return */ public void generateId() { StringBuilder builder = new StringBuilder(); builder.append(myIp).append(":").append(myPort).append("-->"); builder.append(this.protocol).append("://").append(remoteNode.getIp()).append(":").append(remoteNode.getPort()); this.setId(builder.toString()); } public String getBindIp() { return bindIp; } public int getBindPort() { return bindPort; } public ConnectionState getConnectionState() { return connectionState; } public int getCountOfRecordSendFail() { return countOfRecordSendFail; } public String getDesc4Err() { return desc4Err; } public ErrorPackageHandlerIntf getErrorPackageHandler() { return errorPackageHandler; } /** * 获取id * * @return String */ public String getId() { return id; } public String getMyIp() { return myIp; } public int getMyPort() { return myPort; } public PacketHandlerIntf getPacketHandler() { return packetHandler; } public HandlerRunnable getHandlerRunnable() { return handlerRunnable; } public DecoderIntf getDecoder() { return decoder; } public DecodeRunnable getDecodeRunnable() { return decodeRunnable; } public String getProtocol() { return protocol; } public Proxy getProxy() { return proxy; } public ReadIOErrorHandlerIntf getReadIOErrorHandler() { return readIOErrorHandler; } /** * 获取Route基本信息 * * @return String */ public RemoteNode getRemoteNode() { return remoteNode; } public AtomicLong getSeqNo() { return seqNo; } public SocketChannel getSocketChannel() { return socketChannel; } public SendRunnable getSendRunnable() { return sendRunnable; } public StatVo getStatVo() { return statVo; } public WriteIOErrorHandlerIntf getWriteIOErrorHandler() { return writeIOErrorHandler; } /** * true : ConnectionState.APP_ON * * @return */ public boolean isAppOn() { return connectionState == ConnectionState.APP_ON; } // public Map<String, HandlerRunnable> // getMapOfMsgtypeAndPacketHandlerTask() // { // return mapOfMsgtypeAndPacketHandlerTask; // } // // public void setMapOfMsgtypeAndPacketHandlerTask(Map<String, // HandlerRunnable> mapOfMsgtypeAndPacketHandlerTask) // { // this.mapOfMsgtypeAndPacketHandlerTask = mapOfMsgtypeAndPacketHandlerTask; // } public boolean isAutoConnection() { return isAutoConnection; } /** * 当前链路状态下,是否需要建链 * * @author tanyaowu * @param connectionState * @return */ public boolean isNeedBuildLink(ConnectionState connectionState) { return isAutoConnection && (needBuildConnectionStateSet.contains(connectionState)); } public boolean isNeedRecordSendFailMsg() { return isNeedRecordSendFailMsg; } public void removePropertyChangeListener(PropertyChangeListener l) { listeners.removePropertyChangeListener(l); } public void setAutoConnection(boolean isAutoConnection) { this.isAutoConnection = isAutoConnection; } public void setBindIp(String bindIp) { this.bindIp = bindIp; } public void setBindPort(int bindPort) { this.bindPort = bindPort; } public void setConnectionState(ConnectionState connectionState) { if (this.connectionState == connectionState) { return; } ConnectionState oldConnectionState = this.connectionState; this.connectionState = connectionState; firePropertyChange("connectionState", oldConnectionState, connectionState); } public void setCountOfRecordSendFail(int countOfRecordSendFail) { this.countOfRecordSendFail = countOfRecordSendFail; } public void setDesc4Err(String desc4Err) { this.desc4Err = desc4Err; } public void setErrorPackageHandler(ErrorPackageHandlerIntf errorPackageHandler) { this.errorPackageHandler = errorPackageHandler; } public void setId(String id) { this.id = id; } public void setMyIp(String myIp) { this.myIp = myIp; } public void setMyPort(int myPort) { this.myPort = myPort; } public void setNeedRecordSendFailMsg(boolean isNeedRecordSendFailMsg) { this.isNeedRecordSendFailMsg = isNeedRecordSendFailMsg; } public void setPacketHandler(PacketHandlerIntf packetHandler) { this.packetHandler = packetHandler; } public void setHandlerRunnable(HandlerRunnable handlerRunnable) { this.handlerRunnable = handlerRunnable; } public void setDecoder(DecoderIntf decoder) { this.decoder = decoder; } public void setDecodeRunnable(DecodeRunnable decodeRunnable) { this.decodeRunnable = decodeRunnable; this.handlerRunnable.setParent(decodeRunnable); } public void setProtocol(String protocol) { this.protocol = protocol; } public void setProxy(Proxy proxy) { this.proxy = proxy; } public void setReadIOErrorHandler(ReadIOErrorHandlerIntf readIOErrorHandler) { this.readIOErrorHandler = readIOErrorHandler; } public void setSeqNo(AtomicLong seqNo) { this.seqNo = seqNo; } public void setSocketChannel(SocketChannel socketChannel) { this.socketChannel = socketChannel; } public void setSendRunnable(SendRunnable sendRunnable) { this.sendRunnable = sendRunnable; } public void setStatVo(StatVo statVo) { this.statVo = statVo; } public void setWriteIOErrorHandler(WriteIOErrorHandlerIntf writeIOErrorHandler) { this.writeIOErrorHandler = writeIOErrorHandler; } @Override public String toString() { return id; } public Map<String, Object> getProps() { return props; } public void setProps(Map<String, Object> props) { this.props = props; } public ConnectionStateListener getConnectionStateListener() { return connectionStateListener; } private static java.util.concurrent.atomic.AtomicLong c = new java.util.concurrent.atomic.AtomicLong(); public void setConnectionStateListener(final ConnectionStateListener connectionStateListener) { this.connectionStateListener = connectionStateListener; if (connectionStateListener != null) { this.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if ("connectionState".equals(evt.getPropertyName())) { ConnectionState newValue = (ConnectionState) evt.getNewValue(); log.info("{}---remote: {}", newValue, ChannelContext.this.getId()); log.warn(newValue + "-" + c.incrementAndGet()); if (newValue == ConnectionState.TCP_OFF) { try { connectionStateListener.onTcpOff(ChannelContext.this); } catch (Exception e) { throw new RuntimeException(e); } } else if (newValue == ConnectionState.TCP_BUILDING) { try { connectionStateListener.onTcpBuilding(ChannelContext.this); } catch (Exception e) { throw new RuntimeException(e); } } else if (newValue == ConnectionState.TCP_ON) { try { connectionStateListener.onTcpOn(ChannelContext.this); } catch (Exception e) { throw new RuntimeException(e); } } else if (newValue == ConnectionState.TCP_LINKFAILED) { try { connectionStateListener.onTcpLinkFailed(ChannelContext.this); } catch (Exception e) { throw new RuntimeException(e); } } else if (newValue == ConnectionState.APP_OFF) { try { connectionStateListener.onAppOff(ChannelContext.this); } catch (Exception e) { throw new RuntimeException(e); } } else if (newValue == ConnectionState.APP_BUILDING) { try { connectionStateListener.onAppBuilding(ChannelContext.this); } catch (Exception e) { throw new RuntimeException(e); } } else if (newValue == ConnectionState.APP_ON) { ChannelContext.this.getStatVo().setStateTimeAppBuilding(SystemTimer.currentTimeMillis()); try { connectionStateListener.onAppOn(ChannelContext.this); } catch (Exception e) { throw new RuntimeException(e); } } else if (newValue == ConnectionState.APP_LINKFAILED) { try { connectionStateListener.onAppLinkFailed(ChannelContext.this); } catch (Exception e) { throw new RuntimeException(e); } } else if (newValue == ConnectionState.LOGOUTING) { try { connectionStateListener.onLogouting(ChannelContext.this); } catch (Exception e) { throw new RuntimeException(e); } } } } }); } } public ByteOrder getByteOrder() { return byteOrder; } public void setByteOrder(ByteOrder byteOrder) { this.byteOrder = byteOrder; } }