📄 abstractport.java
字号:
/*
* LumaQQ - Java QQ Client
*
* Copyright (C) 2004 notXX
* luma <stubma@163.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package edu.tsinghua.lumaqq.qq;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Vector;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.tsinghua.lumaqq.qq.events.PacketEvent;
import edu.tsinghua.lumaqq.qq.events.PacketListener;
import edu.tsinghua.lumaqq.qq.events.QQEvent;
import edu.tsinghua.lumaqq.qq.events.QQListener;
import edu.tsinghua.lumaqq.qq.packets.InPacket;
import edu.tsinghua.lumaqq.qq.packets.OutPacket;
/**
* 部分实现包收发.
*
* @author notxx
* @author 马若劼
*/
abstract class AbstractPort implements IPort {
private static final Log log = LogFactory.getLog(AbstractPort.class);
/** 包事件监听器 */
protected Vector listeners;
/** 维护线程 */
protected Porter porter;
/** 发送缓冲区 */
protected static ByteBuffer sendBuf = ByteBuffer.allocateDirect(QQ.MAX_PACKET_SIZE);
/** 接收缓冲区 */
protected static ByteBuffer receiveBuf = ByteBuffer.allocateDirect(QQ.MAX_PACKET_SIZE);
/** 发送队列 */
protected LinkedList sendQueue;
/** 接收队列 */
protected LinkedList receiveQueue;
/** 包事件监听线程 */
protected ListenerThread listenerThread;
/** 重发线程 */
protected Resender resender;
/** QQ事件监听器 */
protected Vector qqListeners, qqListenersBackup;
/**
* <pre>
* 是否监听器有改变,这是为了处理同步问题而设置的,在实际fireQQEvent时,
* 不使用qqListeners,而是用backup,这样在事件触发期间如果要修改
* 监听器也是可以的,不然有可能造成并发修改异常。如果有更好的办法当
* 然,目前只想出这种办法
* </pre>
*/
private boolean listenerChanged;
/**
* 构造函数
*/
public AbstractPort() {
listeners = new Vector();
qqListeners = new Vector();
qqListenersBackup = new Vector();
porter = new Porter();
receiveQueue = new LinkedList();
sendQueue = new LinkedList();
}
/* (non-Javadoc)
* @see edu.tsinghua.lumaqq.qq.IPort#add(notxx.lumaqq.qq.packet.OutPacket)
*/
public synchronized void add(OutPacket packet) {
addS(packet);
}
/**
* 添加一个包到接收队列
* @param packet
*/
protected synchronized void addR(InPacket packet) {
if(packet == null) return;
receiveQueue.addLast(packet);
synchronized(listenerThread) {
listenerThread.notify();
}
}
/* (non-Javadoc)
* @see edu.tsinghua.lumaqq.qq.IPort#clear()
*/
public synchronized void clear() {
sendQueue.clear();
receiveQueue.clear();
}
/* (non-Javadoc)
* @see edu.tsinghua.lumaqq.qq.IPort#start()
*/
public synchronized void start() {
log.trace("AbstractPort start");
listenerThread = new ListenerThread(this);
listenerThread.start();
resender = new Resender(this);
resender.start();
porter.start();
}
/* (non-Javadoc)
* @see edu.tsinghua.lumaqq.qq.IPort#dispose()
*/
public synchronized void dispose() throws IOException {
porter.shutdown();
listenerThread.setStop(true);
resender.setStop(true);
}
/**
* 添加一个包到发送队列
* @param packet
*/
protected synchronized void addS(OutPacket packet) {
sendQueue.addLast(packet);
porter.wakeup();
}
/* (non-Javadoc)
* @see edu.tsinghua.lumaqq.qq.IPort#get()
*/
public synchronized InPacket get() {
return getR();
}
/* (non-Javadoc)
* @see edu.tsinghua.lumaqq.qq.IPort#pushBack(edu.tsinghua.lumaqq.qq.packets.InPacket)
*/
public synchronized void pushBack(InPacket in) {
if(in == null) return;
receiveQueue.addLast(in);
}
/**
* 从接收队列中得到第一个包,并且不把这个包从队列中移除
* @return 接收队列的第一个包,没有返回null
*/
protected synchronized InPacket getR() {
InPacket packet = (InPacket) receiveQueue.getFirst();
return packet;
}
/**
* 从发送队列中得到第一个包,并且不把这个包从队列中移除
* @return 发送队列的第一个包,没有返回null
*/
protected synchronized OutPacket getS() {
OutPacket packet = (OutPacket) sendQueue.getFirst();
return packet;
}
/* (non-Javadoc)
* @see edu.tsinghua.lumaqq.qq.IPort#isEmpty()
*/
public synchronized boolean isEmpty() {
return isEmptyS();
}
/**
* @return true表示接收队列为空
*/
protected synchronized boolean isEmptyR() {
return receiveQueue.isEmpty();
}
/**
* @return true表示发送队列为空
*/
protected synchronized boolean isEmptyS() {
return sendQueue.isEmpty();
}
/* (non-Javadoc)
* @see edu.tsinghua.lumaqq.qq.IPort#remove()
*/
public synchronized InPacket remove() {
return removeR();
}
/**
* 从接收队列中得到第一个包,并且把这个包从队列中移除
* @return 接收队列的第一个包,没有返回null
*/
protected synchronized InPacket removeR() {
if(receiveQueue.size() == 0) return null;
InPacket packet = (InPacket) receiveQueue.removeFirst();
return packet;
}
/**
* 从发送队列中得到第一个包,并且把这个包从队列中移除
* @return 发送队列的第一个包,没有返回null
*/
protected synchronized OutPacket removeS() {
OutPacket packet = (OutPacket) sendQueue.removeFirst();
return packet;
}
/* (non-Javadoc)
* @see edu.tsinghua.lumaqq.qq.IPort#removeResend(edu.tsinghua.lumaqq.qq.packets.InPacket)
*/
public void removeResend(InPacket in) {
resender.remove(in);
}
/* (non-Javadoc)
* @see edu.tsinghua.lumaqq.qq.IPort#addPacketListener(edu.tsinghua.lumaqq.qq.events.PacketListener)
*/
public void addPacketListener(PacketListener listener) {
listeners.add(listener);
}
/* (non-Javadoc)
* @see edu.tsinghua.lumaqq.qq.IPort#removePacketListener(edu.tsinghua.lumaqq.qq.events.PacketListener)
*/
public void removePacketListener(PacketListener listener) {
listeners.remove(listener);
}
/* (non-Javadoc)
* @see edu.tsinghua.lumaqq.qq.IPort#firePacketArrivedEvent(edu.tsinghua.lumaqq.qq.events.PacketEvent)
*/
public void firePacketArrivedEvent(PacketEvent e) {
Iterator iter = listeners.iterator();
while(iter.hasNext())
((PacketListener)iter.next()).packetArrived(e);
}
/* (non-Javadoc)
* @see edu.tsinghua.lumaqq.qq.IPort#firePacketSentEvent(edu.tsinghua.lumaqq.qq.events.PacketEvent)
*/
public void firePacketSentEvent(PacketEvent e) {
Iterator iter = listeners.iterator();
while(iter.hasNext())
((PacketListener)iter.next()).packetSent(e);
}
/* (non-Javadoc)
* @see edu.tsinghua.lumaqq.ISender#addQQListener(edu.tsinghua.lumaqq.QQListener)
*/
public void addQQListener(QQListener listener) {
qqListeners.add(listener);
setListenerChanged(true);
}
/* (non-Javadoc)
* @see edu.tsinghua.lumaqq.ISender#fireQQEvent(edu.tsinghua.lumaqq.QQEvent)
*/
public void fireQQEvent(QQEvent e) {
checkListenerChange();
Iterator iter = qqListeners.iterator();
while(iter.hasNext())
((QQListener)iter.next()).qqEvent(e);
}
/* (non-Javadoc)
* @see edu.tsinghua.lumaqq.ISender#removeQQListener(edu.tsinghua.lumaqq.QQListener)
*/
public void removeQQListener(QQListener listener) {
qqListeners.remove(listener);
setListenerChanged(true);
}
/* (non-Javadoc)
* @see edu.tsinghua.lumaqq.qq.ISender#removeAllQQListener()
*/
public void removeAllQQListener() {
qqListeners.clear();
setListenerChanged(true);
}
// 检查监听器是否已经改变,如果是则更新监听器
protected synchronized void checkListenerChange() {
if(isListenerChanged()) {
qqListenersBackup.clear();
Iterator iter = qqListeners.iterator();
while(iter.hasNext())
qqListenersBackup.add(iter.next());
setListenerChanged(false);
}
}
// 设置listener changed标志
protected synchronized void setListenerChanged(boolean b) {
listenerChanged = b;
}
// 得到listener changed标志
protected synchronized boolean isListenerChanged() {
return listenerChanged;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -