Package cn.sunsharp.ycpn.server.xmpp.net

Source Code of cn.sunsharp.ycpn.server.xmpp.net.Connection$ThreadLocalEncoder

package cn.sunsharp.ycpn.server.xmpp.net;

import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;

import org.apache.log4j.Logger;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.dom4j.io.OutputFormat;
import org.jivesoftware.util.XMLWriter;
import org.xmpp.packet.Packet;

import cn.sunsharp.ycpn.server.xmpp.session.Session;

/**
* 一个Connect代表一个xmpp和server的连接
* @author sunsharp
*/
public class Connection {
  private static final Logger log = Logger.getLogger(Connection.class);
  // 声明一个mina中用于通信的session
  private IoSession ioSession;
  // 自定义session
  private Session session;
  // 声明通信语言
  private String language;
  // 连接是否已经关闭
  private Boolean closed =Boolean.TRUE;
  // 指定xmpp协议的版本(主要版本) <?xml version="1.0"?>
    private int majorVersion = 1;
    // 指定xmpp协议的版本(小版本)  <?xml version="1.0"?>
    private int minorVersion = 0;
  // 声明一个线程安全的encoder
  @SuppressWarnings("rawtypes")
  private ThreadLocal encoder = new ThreadLocalEncoder();
  //
    private ConnectionCloseListener closeListener;
 
  /**
   * 构造方法为创建一个连接,需要传入Server的session,并且打开连状态
   * @param ioSession
   * @param closed
   */
  public Connection(IoSession ioSession) {
    this.ioSession = ioSession;
    this.closed = Boolean.FALSE;
  }
  public void init(Session session){
    this.session = session;
  }
  /**
   * 关闭连接,包括相关的套接字连接
   * 通知所有连接的listeners通道已经关闭
   */
  public void closeConnect(){
    // 连接成功关闭标标记
    boolean closedSuccessfully = Boolean.FALSE;
    synchronized(this){
      if(!isConnectClosed()){
        // 发送结束标志
        deliverRawText("</stream:stream>", false);
        if(null !=session){
          session.setSessionStatus(Session.SESSION_CLOSED);
        }
        ioSession.close(Boolean.FALSE);
        closed = closedSuccessfully = Boolean.TRUE;
      }
    }
    if(closedSuccessfully){
      notifyCloseListeners();
    }
  }
  /**
   * 注册一个监听器当连接关闭的时候能够通知到
   * @param listener 要监听连接事件
   */
    public void registerCloseListener(ConnectionCloseListener listener) {
        if (closeListener != null) {
            throw new IllegalStateException("listener 已经注册了");
        }
        if (isConnectClosed()) {
            listener.onConnectionClose(session);
        } else {
            closeListener = listener;
        }
    }
    /**
     * 移除已经注册了的监听事件
     * @param listener
     */
    public void unregisterCloseListener(ConnectionCloseListener listener) {
        if (closeListener == listener) {
            closeListener = null;
        }
    }
    /**
     * 通知监听者,连接关闭了
     */
    private void notifyCloseListeners() {
        if (closeListener != null) {
            try {
                closeListener.onConnectionClose(session);
            } catch (Exception e) {
                log.error("通知监听失败!: " + closeListener, e);
                e.printStackTrace();
            }
        }
    }
  /**
   * 向当前连接发送一个包(这是client端并没有进行auth验证)
   * @param packet
   */
  public void deliver(Packet packet){
    log.debug("Connection发送packet SENT:"+packet.toXML());
    if(!isConnectClosed()){
      boolean deliverSuccessfully = false;
      // IoBuffer这个接口是对JAVA NIO 的ByteBuffer的封装
      IoBuffer buffer = IoBuffer.allocate(4096);
      // 设置缓冲区大小不够的时候可以自己扩大
          buffer.setAutoExpand(true);
         
          try {
            /**
             * 这里重写了sun中IO类的writer方法,将其中实现改为MINA提供的方法,用于XMLWriter
             * XMLWriter把packet中的xml文件转换成一个流,写进IoBuffer在通过session向client端发送
             *
             */
        XMLWriter xmlSerializer = new XMLWriter(new IoBufferWriter(
            buffer, (CharsetEncoder) encoder.get()),
            new OutputFormat());
        xmlSerializer.write(packet.getElement());
              xmlSerializer.flush();
              // IoBuffer流写完
              buffer.flip();
              // 通过session向外写
              ioSession.write(buffer);
              deliverSuccessfully = true;
      } catch (Exception e) {
        log.error("Connection:向发送packet的时候出错 了!"+this.toString());
        e.printStackTrace();
      }
          // 发送失败就关闭连接
          if(deliverSuccessfully){
            // 记录server发送packet数量
            session.incrementServerPacketCount();
          }else{
            closeConnect();
          }
    }
  }
  /**
   * 向client发送一个原始的文本数据(字符串)
   * @param text
   */
    public void deliverRawText(String text) {
        deliverRawText(text, true);
    }
    /**
     * 可选择异步发送还是同步发送
     * 异步:无需client响应
     * 同步 :需要client响应
     * @param text
     * @param asynchronous
     */
    private void deliverRawText(String text, boolean asynchronous) {
      log.info("Connection发送普通文本 SENT:"+text);
    if (!isConnectClosed()) {
      IoBuffer buffer = IoBuffer.allocate(text.length());
          buffer.setAutoExpand(true);
         
          boolean deliverSuccessfully = false;
          try {
        buffer.put(text.getBytes("UTF-8"));
        buffer.flip();
        if(asynchronous){
          // 异步
          ioSession.write(buffer);
        }else{
          // 同步,设置等待client响应时间
            boolean response = ioSession.write(buffer).awaitUninterruptibly(9000);
            if(!response){
             log.warn("Connection发送raw text时超过响应时间"+this.toString());
            }
        }
      deliverSuccessfully = true;
       } catch (UnsupportedEncodingException e) {
        log.error("Connection:向发送raw text的时候出错 了!"+this.toString());
        e.printStackTrace();
       }
         // 发送失败后关闭连接 
         if((!deliverSuccessfully) && asynchronous){
           closeConnect();
         }
    }
    }
  /**
   * 如果session关闭就返回true
   * @return
   */
  private Boolean isConnectClosed(){
    if(session ==null){
      return closed;
    }
    // 查看session状态是否已经关闭,反之为false
    return session.getSessionStatus() == Session.SESSION_CLOSED;
  }
  /**
   * 这个内部类的作用是返回一个字符编码,因为这里用线程安全的原因是IoBffer向外写的时候不是线程安全的
   * 所以这里用一个线程安全的ThreadLocal来返回一个字符编码一达到IoBuffer写的时候线程是安全的
   * @author sunsharp
   *
   */
  @SuppressWarnings("rawtypes")
  private static class ThreadLocalEncoder extends ThreadLocal{
    // 重写ThreadLocal的initialValue方法
    @Override
    protected Object initialValue() {
       return Charset.forName("UTF-8").newEncoder();
    }
  }
  public String getLanguage() {
    return language;
  }
  public void setLanguage(String language) {
    this.language = language;
  }
  /**
   * 构建xmpp 版本信息 <?xml version="1.0"?>
   * @param majorVersion
   * @param minorVersion
   */
  public void setXMPPVersion(int majorVersion, int minorVersion) {
        this.majorVersion = majorVersion;
        this.minorVersion = minorVersion;
  }
  /**
   * 指定xmpp协议的版本(主要版本) <?xml version="1.0"?>
   * 用于通信前构建xml
   * @return
   */
  public int getMajorVersion() {
    return majorVersion;
  }
  /**
   * 指定xmpp协议的版本(小版本) <?xml version="1.0"?>
   * 用于通信前构建xml
   * @return
   */
  public int getMinorVersion() {
    return minorVersion;
  }
}
TOP

Related Classes of cn.sunsharp.ycpn.server.xmpp.net.Connection$ThreadLocalEncoder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.