Package net.solosky.maplefetion.util

Source Code of net.solosky.maplefetion.util.SliceSipcResponseHelper

/*
* 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.maplefetion.util
* File     : SliceSipcResponseHelper.java
* Author   : solosky < solosky772@qq.com >
* Created  : 2010-6-10
* License  : Apache License 2.0
*/
package net.solosky.maplefetion.util;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;

import net.solosky.maplefetion.sipc.SipcBody;
import net.solosky.maplefetion.sipc.SipcHeader;
import net.solosky.maplefetion.sipc.SipcResponse;
import net.solosky.maplefetion.sipc.SipcStatus;

/**
*
* 分块回复消息工具类
*
* 用于把分块的消息组装为一整个消息
* 如果一个的消息的消息体很大,服务器就会分块传输
* 一般说来,一个分块的消息体是有多个消息状态为188 Partial和一个消息状态不为188的消息组成,所有的消息的I和Q都相同
* 通常消息状态不为188的消息是最后发送的,可以使用这个来判断是否已经收到了所有的分块
* 而且每个消息的偏移一般都是先后到达的,也就是说偏移在前的先到,偏移在后的后到,因为飞信服务器是基于流传输,而不是像QQ基于块传输的
* @author solosky <solosky772@qq.com>
*
*/
public class SliceSipcResponseHelper
{
  /**
   * 所有的部分消息列表
   */
  private ArrayList<SipcResponse> sliceReponseList;
 
  /**
   * 分块回复的CallId
   */
  private int callid;
 
  /**
   * 分块回复的Sequence
   */
  private String sequence;
 
  /**
   * 以第一个分块回复构造
   * @param first  第一个分块回复
   */
  public SliceSipcResponseHelper(SipcResponse first)
  {
    this.sliceReponseList = new ArrayList<SipcResponse>();
    this.sliceReponseList.add(first);
    this.callid   = first.getCallID();
    this.sequence = first.getSequence();
  }
 
  /**
   * 添加一个部分回复消息包
   * @param response
   */
  public void addSliceSipcResponse(SipcResponse response)
  {
    if(response.isSlice()){
      this.sliceReponseList.add(response);
      //为了保险起见,这里先对所有的包的分块偏移做个排序
      this.sortBySliceOffset();
    }
  }
 
  /**
   * 判断是否整个消息已经收到所有的分块包
   * 这里通过判断是否有状态不为188的来判断,如果有表明收到了所有的回复否则就没有
   * 因为状态不为188的总是最后一个到达,所以这里可以简单的判断最后一个元素是否是188状态就可以了
   * 本来还应该判断各个偏移是否完整,因为飞信是基于流传输的,这里可以忽略掉
   *
   * @return
   */
  public boolean isFullSipcResponseRecived()
  {
    if(this.sliceReponseList.size()>0){
      SipcResponse res = this.sliceReponseList.get(this.sliceReponseList.size()-1);
      return res.getStatusCode()!=SipcStatus.PARTIAL;
    }else{
      return false;
    }
  }
 
  /**
   * 返回完整的的回复消息包
   * @return
   */
  public SipcResponse getFullSipcResponse()
  {
    //有个问题:这里这么多的分块回复,每个回复都是独立的,那究竟最终的回复是依据第一个还是最后一个呢?
    //这里依据的是最后一个回复
   
    //新建一个回复对象,把最后一个回复的状态和回复消息复制到到新回复对象
    SipcResponse last = this.sliceReponseList.get(this.sliceReponseList.size()-1);
    SipcResponse some = new SipcResponse(last.getStatusCode(), last.getStatusMessage());
   
    //把最后一个回复对象的所有消息头除了Content-Length都复制到新回复对象
    Iterator<SipcHeader> it = last.getHeaders().iterator();
    while(it.hasNext()){
      SipcHeader header = it.next();
      if(!SipcHeader.LENGTH.equals(header.getName())){  //如果不是L域就复制到新的回复头部中
        some.addHeader(header);
      }
    }
   
    //复制所有消息体到新的回复包中
    StringBuffer buffer = new StringBuffer();
    Iterator<SipcResponse> rit = this.sliceReponseList.iterator();
    while(rit.hasNext()){
      SipcResponse res = rit.next();
      if(res.getBody()!=null){
        buffer.append(res.getBody().toSendString());
      }
    }
    some.setBody(new SipcBody(buffer.toString()));
   
    //别忘了设置消息长度,虽然可能用不上。。
    some.addHeader(SipcHeader.LENGTH, Integer.toString(some.getBody().getLength()));
   
    //返回新的回复
    return some;
  }
 
  /**
   * @return the callid
   */
  public int getCallid()
  {
    return callid;
  }

  /**
   * @return the sequence
   */
  public String getSequence()
  {
    return sequence;
  }

  /**
   * 对分块的消息根据分块偏移按从小到大的顺序进行排序
   */
  private void sortBySliceOffset()
  {
    Collections.sort(this.sliceReponseList,new Comparator<SipcResponse>(){
      public int compare(SipcResponse res1, SipcResponse res2){
        if(res1.getSliceOffset()<res2.getSliceOffset()){
          return -1;
        }else if(res1.getSliceOffset()>res2.getSliceOffset()){
          return 1;
        }else{
          return 0;
        }
      }
    });
  }
}
TOP

Related Classes of net.solosky.maplefetion.util.SliceSipcResponseHelper

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.