Package net.solosky.maplefetion.net

Source Code of net.solosky.maplefetion.net.TransferService$SipMessageTimeOutCheckTask

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* Project  : MapleFetion2
* Package  : net.solosky.net.maplefetion.net
* File     : TransferService.java
* Author   : solosky < solosky772@qq.com >
* Created  : 2010-1-6
* License  : Apache License 2.0
*/
package net.solosky.maplefetion.net;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;
import java.util.TimerTask;

import net.solosky.maplefetion.FetionConfig;
import net.solosky.maplefetion.FetionContext;
import net.solosky.maplefetion.FetionException;
import net.solosky.maplefetion.chain.AbstractProcessor;
import net.solosky.maplefetion.client.ResponseHandler;
import net.solosky.maplefetion.client.SystemException;
import net.solosky.maplefetion.sipc.SipcHeader;
import net.solosky.maplefetion.sipc.SipcNotify;
import net.solosky.maplefetion.sipc.SipcRequest;
import net.solosky.maplefetion.sipc.SipcResponse;
import net.solosky.maplefetion.sipc.SipcStatus;
import net.solosky.maplefetion.util.SliceSipcResponseHelper;
import net.solosky.maplefetion.util.TimeHelper;

import org.apache.log4j.Logger;

/**
*
* 传输服务 提供发出包和接收包的管理,并处理超时异常
*
* @author solosky <solosky772@qq.com>
*/
public class TransferService extends AbstractProcessor
{

  /**
   * 已发送请求队列
   */
  private Queue<SipcRequest> requestQueue;
 
  /**
   * 分块传输的消息队列
   */
  private Queue<SliceSipcResponseHelper> slicedResponseQueue;
 
  /**
   * 飞信上下文
   */
  private FetionContext context;
 
  /**
   * 主要用操作定时任务
   */
  private TimerTask sipcTimeoutCheckTask;
 
  /**
   * 日志记录
   */
  private static Logger logger = Logger.getLogger(TransferService.class);

  /**
   * 默认构造函数
   */
  public TransferService(FetionContext context)
  {
    this.context = context;
    this.requestQueue = new LinkedList<SipcRequest>();
    this.slicedResponseQueue = new LinkedList<SliceSipcResponseHelper>();
  }

  /**
   * 处理接受的包 在已发送队列中查找相对应的发出包,然后放入接受包中
   */
  @Override
  protected Object doProcessIncoming(Object o) throws FetionException
  {
    //-_-!!! , 好吧,我承认这里判断逻辑有点乱。。
    if (o instanceof SipcResponse) {
      SipcResponse response = (SipcResponse) o;
      //先检查这个回复是不是分块回复的一部分
      SliceSipcResponseHelper helper = this.findSliceResponseHelper(response);
      if(helper!=null){
        //如果是分块回复,就添加到分块回复列表中
        helper.addSliceSipcResponse(response);
        if(helper.isFullSipcResponseRecived()){
          synchronized (slicedResponseQueue) {
            slicedResponseQueue.remove(helper);
          }
         
          //构造新的回复
          SipcResponse some = helper.getFullSipcResponse();
          this.handleFullResponse(some);
         
          return some;  //返回新的完整的请求
        }else{
          return null//分块回复还没接收完,返回null停止处理链
        }
      }else if(response.getStatusCode()==SipcStatus.PARTIAL){  //可能是第一次收到的分块回复
        helper = new SliceSipcResponseHelper(response);
        synchronized (slicedResponseQueue) {
          slicedResponseQueue.add(helper);
        }
        return null;    //第一个分块回复,返回null停止处理链
      }else//不是分块回复的对象就直接进行下一步操作
        this.handleFullResponse(response);
        return response;
      }
    }else if(o instanceof SipcNotify){
      this.handleFullNotify((SipcNotify) o);
      return (SipcNotify) o; 
    }else{
      return null//未知类型,一般不会发生。。
    }
  }

  /**
   * 处理发送的包 如果这个包需要回复,就把这个包加入到已发送的队列中,然后隔一段时间后检查是否超时
   */
  @Override
  protected Object doProcessOutcoming(Object o) throws FetionException
  {
    if (o instanceof SipcRequest) {
      SipcRequest request = (SipcRequest) o;
      //判断需要回复次数大于0才放人队列中
      if(request.getNeedReplyTimes()>0) {
        synchronized(this.requestQueue) {
          this.requestQueue.add(request);
        }
      }
    }
    return super.doProcessOutcoming(o);
  }

  /*
   * (non-Javadoc)
   *
   * @see net.solosky.net.maplefetion.chain.Processor#getProcessorName()
   */
  @Override
  public String getProcessorName()
  {
    return TransferService.class.getName();
  }

  /* (non-Javadoc)
     * @see net.solosky.maplefetion.chain.AbstractProcessor#stopProcessor()
     */
    @Override
    public void stopProcessor(FetionException ex) throws FetionException
    {
      //停止超时检查定时任务
      this.sipcTimeoutCheckTask.cancel();
      this.context.getFetionTimer().clearCanceledTask();
      //通知当前发送队列中的请求都超时
      synchronized (requestQueue) {
        Iterator<SipcRequest> it = this.requestQueue.iterator();
          while(it.hasNext()) {
            SipcRequest request = it.next();
            ResponseHandler handler = request.getResponseHandler();
            if(handler!=null) {
              if(ex==null){
                handler.timeout(request);
              }else if(ex instanceof TransferException){
                handler.ioerror(request);
              }else if(ex instanceof SystemException){
                handler.syserror(request, ex.getCause());
              }else{
                handler.timeout(request);
              }
            }
          }
      }
    }
   
   
  /* (non-Javadoc)
     * @see net.solosky.maplefetion.chain.AbstractProcessor#startProcessor()
     */
    @Override
    public void startProcessor() throws FetionException
    {
      this.sipcTimeoutCheckTask = new SipMessageTimeOutCheckTask();
      int checkTimeoutInterval  = FetionConfig.getInteger("fetion.sip.check-alive-interval")*1000;
      int checkTimeoutDelay     = 50*1000;
      this.context.getFetionTimer().scheduleTask(
                  this.sipcTimeoutCheckTask, checkTimeoutDelay, checkTimeoutInterval);
    }
   

  /**
   *
   * 内部类,实现了超时检查任务 简单的委托给队列管理器处理
   *
   * @author solosky <solosky772@qq.com>
   */
  public class SipMessageTimeOutCheckTask extends TimerTask
  {
    @Override
    public void run()
    {
      try {
        checkTimeOutRequest();
      } catch (FetionException e) {
        raiseException(e);
      }
    }
  }

  /**
   * 在已发送队列中查找对应发送信令
   *
   * @param response
   * @return
   */
  public SipcRequest findRequest(SipcResponse response)
  {
    synchronized(this.requestQueue) {
        Iterator<SipcRequest> it = this.requestQueue.iterator();
        SipcRequest request = null;
        String resCallID = response.getHeader(SipcHeader.CALLID).getValue();
        String resSequence = response.getHeader(SipcHeader.SEQUENCE).getValue();
        String reqCallID = null;
        String reqSequence = null;
        while (it.hasNext()) {
          request = it.next();
          reqCallID = request.getHeader(SipcHeader.CALLID).getValue();
          reqSequence = request.getHeader(SipcHeader.SEQUENCE).getValue();
          //如果callID和sequence都相等的话就找到了指定的请求
          if (resCallID.equals(reqCallID) && resSequence.equals(reqSequence)) {
            return request;
          }
        }
        return null;
    }
  }
 
  /**
   * 查找这个回复是否是分块回复的一部分
   * @param response
   * @return
   */
  private SliceSipcResponseHelper findSliceResponseHelper(SipcResponse response)
  {
    synchronized(this.slicedResponseQueue) {
      Iterator<SliceSipcResponseHelper> it = this.slicedResponseQueue.iterator();
        int resCallID = response.getCallID();
        String resSequence = response.getSequence();
        SliceSipcResponseHelper helper = null;
       
        while (it.hasNext()) {
          helper = it.next();
          if (helper.getCallid()==resCallID && helper.getSequence().equals(resSequence)) {
            return helper;
          }
        }
        return null;
    }
  }
 

  /**
   * 检查超时的包,如果没有超过指定的重发次数,就重发 如果只要有一个包超出了重发的次数,就抛出超时异常
   *
   * @throws FetionException
   */
  private void checkTimeOutRequest() throws FetionException
  {
    int curTime     = TimeHelper.nowTimeUnixStamp();
    int maxTryTimes = FetionConfig.getInteger("fetion.sip.default-retry-times");
    int aliveTime   = FetionConfig.getInteger("fetion.sip.default-alive-time");

    //这里需要同步了。。
    synchronized (this.requestQueue) {
     
      //感觉JAVA集合中的队列怪怪的,特别是命名,peek poll如果不看注释根本不知道是什么含义,接口不明确啊,能望文生义那种接口最好
      //比如getFrist() getLast() addFirst() addLast() peekFirst() peekLast()...
      //更无语的是,如果队列为空调用peek()居然会抛异常,因为这个原因不得不在遍历队列的时候判断下队列的大小..
      //所以这里采用的是集合的遍历方式,更加简洁,代码也更加优美点..
     
      ArrayList<SipcRequest> timeoutList = new ArrayList<SipcRequest>();    //超时的包的列表
      Iterator<SipcRequest> it = this.requestQueue.iterator();
     
      //首先把超时的包找出来
      while(it.hasNext()){
        SipcRequest request = it.next();
        if(request.getAliveTime()<curTime){        //超过了存活期,
          //因为这里如果判断超时并重发,这个包会重新添加到队列中,当前迭代的列表会增加元素,迭代器就会抛出更改异常
          //所以这里重新建立了一个超时列表,并把超时的包放入列表中,在当前迭代结束后才处理超时包
          it.remove();              //先从队列中移除
          timeoutList.add(request);        //添加到重发包列表
        }else{
          //未超过存活期,啥也不干
        }
      }
     
      //遍历超时包列表,并根据条件判断是否重发或者通知超时
      it = timeoutList.iterator();
      while(it.hasNext()){
        SipcRequest request = it.next();
        if(request.getRetryTimes()<maxTryTimes){    //重发次数未超过指定的次数,重新发送这个包
          logger.debug("Request was timeout, now sending it again... Request="+request);
          request.incRetryTimes();          //递增重试次数
          request.setAliveTime(curTime+aliveTime)//更新存活时间
          this.processOutcoming(request);        // 重新发送这个包
        }else{                      //这个包已经超过重发次数,通知超时
          logger.warn("A request was sent three times, handle this timeout exception...Request="+request);
          this.handleRequestTimeout(request);
        }
     
      }
    }
  }

  /**
   * 处理包超时异常
   *
   * @param timeoutMessage
   * @throws FetionException
   */
  private void handleRequestTimeout(SipcRequest request) throws FetionException
  {
    //发出包设置了超时处理器,就调用超时处理器,否则抛出超时异常,结束整个程序
    if (request.getResponseHandler() != null) {
      request.getResponseHandler().timeout(request);
    }else {
      logger.warn("Request already was timeout, but there wasn't a timeout handler, ignore it. Request="+request);
    }
  }
 
  /**
   * 处理收到的完整回复,主要完成查找对应的请求包并注入到回复中
   * @param response
   */
  private boolean handleFullResponse(SipcResponse response)
  {
    // 如果是回复的话,查找对应的请求,并通知回复等待对象
    SipcRequest request = this.findRequest(response);
    response.setRequest(request);
   
    //找到了对应的请求,然后判断是否回复已经到了指定的回复次数,如果到了就从队列中移除,如果没有,就不移除
    if(request!=null) {
      request.incReplyTimes();
      if(request.getNeedReplyTimes()==request.getReplyTimes()) {
        synchronized(this.requestQueue) {
          this.requestQueue.remove(request);
        }
      }
    }
   
    return true;
  }
 
  /**
   * 处理收到完整通知
   * @param notify
   */
  private boolean handleFullNotify(SipcNotify notify)
  {
    //目前什么也不做
    return true;
  }

}
TOP

Related Classes of net.solosky.maplefetion.net.TransferService$SipMessageTimeOutCheckTask

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.