📄 messagequeue.java
字号:
/*
* LumaQQ - Java QQ Client
*
* Copyright (C) 2004 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;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.ListIterator;
import edu.tsinghua.lumaqq.models.ClusterIdMatcher;
import edu.tsinghua.lumaqq.models.QQNumberMatcher;
import edu.tsinghua.lumaqq.qq.QQ;
import edu.tsinghua.lumaqq.qq.packets.BasicInPacket;
import edu.tsinghua.lumaqq.qq.packets.in.ReceiveIMPacket;
import edu.tsinghua.swt.models.ShutterModel;
import edu.tsinghua.swt.widgets.CoolButton;
/**
* 消息队列实现类
*
* * @author 马若劼
*/
public class MessageQueue {
// 总队列
private LinkedList queue;
// 系统消息队列
private LinkedList sysQueue;
// 延迟处理队列
private LinkedList postponeQueue;
// 用户消息队列映射哈希表
private Hashtable userQueueMap;
// 短消息队列
private LinkedList smsQueue;
// shutter model,需要有model才好判断哪个好友是哪个组的
private ShutterModel model;
// QQ号码匹配器
private QQNumberMatcher qqNumMatcher;
// 群内部ID匹配器
private ClusterIdMatcher clusterIdMatcher;
private static MessageQueue instance = new MessageQueue();
public static MessageQueue getInstance() {
return instance;
}
/**
* 私有构造函数,singleton模式
*/
private MessageQueue() {
queue = new LinkedList();
sysQueue = new LinkedList();
postponeQueue = new LinkedList();
userQueueMap = new Hashtable();
smsQueue = new LinkedList();
qqNumMatcher = new QQNumberMatcher();
clusterIdMatcher = new ClusterIdMatcher();
}
/**
* 情况所有数据
*/
public void clear() {
queue.clear();
sysQueue.clear();
postponeQueue.clear();
userQueueMap.clear();
}
/**
* 设置model
* @param model
*/
public void setModel(ShutterModel model) {
this.model = model;
}
/**
* 得到下一条某个好友发来的消息,但是不把它从队列中删除
* @param qqNum 好友QQ号
* @return 如果有消息则返回消息,否则返回null
*/
public BasicInPacket peekMessage(int qqNum) {
Integer qq = new Integer(qqNum);
if(userQueueMap.containsKey(qq)) {
LinkedList userQueue = (LinkedList)userQueueMap.get(qq);
if(userQueue.size() > 0)
return (BasicInPacket)userQueue.getFirst();
else
return null;
} else
return null;
}
/**
* 得到第一条短消息,但是不把它从队列中删除
*
* @return InPacket对象,如果队列为空,返回null
*/
public BasicInPacket peekSMS() {
if(smsQueue.size() > 0)
return (BasicInPacket)smsQueue.getFirst();
else
return null;
}
/**
* 添加一个短消息到队列末尾
*
* @param in
*/
public void putSMS(BasicInPacket in) {
if(in != null) {
smsQueue.addLast(in);
queue.addLast(in);
}
}
/**
* 得到队列中第一条短消息,并且把它从队列中删除
*
* @return InPacket,如果队列为空,返回null
*/
public BasicInPacket getSMS() {
if(smsQueue.size() > 0) {
BasicInPacket in = (BasicInPacket)smsQueue.removeFirst();
queue.remove(in);
return in;
} else
return null;
}
/**
* 得到下一条某组的消息,但是不把它从队列中删除
* @param g 组索引
* @return 如果有消息则返回消息,否则返回null
*/
public BasicInPacket peekGroupMessage(int g) {
int nextSender = nextGroupSender(g);
if(nextSender == -1)
return null;
else {
Integer key = new Integer(nextSender);
LinkedList userQueue = (LinkedList)userQueueMap.get(key);
return (BasicInPacket)userQueue.getFirst();
}
}
/**
* 得到下一条系统消息,但是不把他从队列中删除
* @return 如果有消息则返回消息,否则返回null
*/
public BasicInPacket peekSystemMessage() {
if(sysQueue.size() > 0)
return (BasicInPacket)sysQueue.getFirst();
else
return null;
}
/**
* 把一个普通消息包推入消息队列
* @param packet
* 消息包对象
* @param group
* CoolButton对象,之所以用这个,是因为索引是可能变化的
*/
public void putMessage(BasicInPacket packet, CoolButton group) {
putMessage(packet, group, true);
}
/**
* @param packet
* 消息包对象
* @param group
* CoolButton对象,之所以用这个,是因为索引是可能变化的
* @param global
* true表示添加这个消息到总队列中
*/
public void putMessage(BasicInPacket packet, CoolButton group, boolean global) {
ReceiveIMPacket im = (ReceiveIMPacket)packet;
// 得到QQ号,判断是否已经存在该用户的消息队列,如果这个是群消息,这个其实就是群的内部ID
Integer qq = null;
if(im.header.type == QQ.QQ_RECV_IM_TEMP_CLUSTER_IM)
qq = new Integer(im.clusterIM.clusterId);
else
qq = new Integer(im.header.sender);
LinkedList userQueue = null;
if(!userQueueMap.containsKey(qq)) {
userQueue = new LinkedList();
userQueueMap.put(qq, userQueue);
} else {
userQueue = (LinkedList)userQueueMap.get(qq);
}
// 消息推入用户队列组队列和总队列
userQueue.addLast(packet);
if(global)
queue.addLast(packet);
}
/**
* 把一个系统消息推入队列
* @param packet
*/
public void putSystemMessage(BasicInPacket packet) {
sysQueue.addLast(packet);
queue.addLast(packet);
}
/**
* 得到一条普通消息,并把他从队列中删除
* @param qqNum 发送消息的好友QQ号
* @return 如果有消息在返回消息,否则返回null
*/
public BasicInPacket getMessage(int qqNum) {
Integer qq = new Integer(qqNum);
return getMessage(qq);
}
/**
* 得到一条普通消息,并把他从队列中删除
* @param qq 发送消息的好友QQ号的Integer形式,如果是群,其实就是内部ID
* @return 如果有消息在返回消息,否则返回null
*/
public BasicInPacket getMessage(Integer qq) {
// 检查是否有这个队列,有则取第一个消息,如果取后队列为空,删除这个队列
if(userQueueMap.containsKey(qq)) {
LinkedList userQueue = (LinkedList)userQueueMap.get(qq);
if(userQueue.size() == 0) return null;
BasicInPacket p = (BasicInPacket)userQueue.removeFirst();
// 从总队列中删除
queue.remove(p);
// 如果用户消息队列为空,删除这个队列,为什么我不判断组队列为不为空并删除呢?
// 主要我是觉得组往往是少数,而好友多的可能有几百个,如果不删除队列的话
// 可能比较浪费内存
if(userQueue.size() == 0) {
userQueueMap.remove(qq);
}
return p;
} else
return null;
}
/**
* 把qq号指定的好友或者群的所有消息删除
* @param qq 可能是好友的QQ号,也可能是群的内部ID
*/
public void removeMessage(Integer qq) {
// 检查是否有这个队列
if(userQueueMap.containsKey(qq)) {
LinkedList userQueue = (LinkedList)userQueueMap.get(qq);
ListIterator iter = userQueue.listIterator();
while(iter.hasNext()) {
// 从总队列中删除
Object obj = iter.next();
queue.remove(obj);
}
// 从队列映射表中删除
userQueueMap.remove(qq);
}
}
/**
* 把qq号指定的好友或者群的所有消息删除
* @param qq 可能是好友的QQ号,也可能是群的内部ID
*/
public void removeMessage(int qq) {
removeMessage(new Integer(qq));
}
/**
* 得到一条普通消息,这条消息是该组内队列的第一条
* @param g 组索引
* @return 如果有则返回消息,否则返回null
*/
public BasicInPacket getGroupMessage(int g) {
int nextSender = nextGroupSender(g);
if(nextSender == -1)
return null;
else {
Integer key = new Integer(nextSender);
LinkedList userQueue = (LinkedList)userQueueMap.get(key);
return (BasicInPacket)userQueue.removeFirst();
}
}
/**
* 得到一条系统消息,并把他从队列删除
* @return 如果有消息,返回消息,否则返回null
*/
public BasicInPacket getSystemMessage() {
if(sysQueue.size() > 0) {
BasicInPacket p = (BasicInPacket)sysQueue.removeFirst();
queue.remove(p);
return p;
} else
return null;
}
/**
* 检查是否某个好友还有消息未读
* @param qqNum 好友QQ号
* @return true如果有消息未读
*/
public boolean hasMessage(int qqNum) {
Integer qq = new Integer(qqNum);
return hasMessage(qq);
}
/**
* 检查是否某个好友还有消息未读
* @param key 好友QQ号的Integer类
* @return true如果有消息未读
*/
public boolean hasMessage(Integer key) {
return userQueueMap.containsKey(key);
}
/**
* 检查某个组是否有消息未读
* @param g 组索引
* @return true如果有消息未读
*/
public boolean hasGroupMessage(int g) {
return nextGroupSender(g) != -1;
}
/**
* @return true如果还有任何消息未读
*/
public boolean hasNext() {
return queue.size() > 0;
}
/**
* @return true如果还有系统消息未读
*/
public boolean hasSystemMessage() {
return sysQueue.size() > 0;
}
/**
* @return true如果还有短消息
*/
public boolean hasSMS() {
return smsQueue.size() > 0;
}
/**
* @return 下一条消息的发送者的QQ号,如果是0,表示是系统消息,-1表示无消息
* 如果是群消息,返回的将是群的内部ID
*/
public int nextSender() {
if(queue.size() == 0) return -1;
BasicInPacket packet = (BasicInPacket)queue.getFirst();
if(packet instanceof ReceiveIMPacket) {
ReceiveIMPacket im = (ReceiveIMPacket)packet;
if(im.header.type == QQ.QQ_RECV_IM_SYS_MESSAGE)
return 0;
else if(im.header.type == QQ.QQ_RECV_IM_TEMP_CLUSTER_IM)
return im.clusterIM.clusterId;
else
return im.header.sender;
} else
return 0;
}
/**
* 返回下一个消息的来源,对于普通消息,返回QQ_IM_FROM_FRIEND,对于系统消息,返回QQ_IM_FROM_SYS
* 对于群消息,有两种情况,因为群消息包含了普通消息和通知消息,对于普通消息,我们返回
* QQ_IM_FROM_CLUSTER,对于通知消息,我们返回QQ_IM_FROM_SYS
* @return
*/
public int nextMessageSource() {
if(queue.size() == 0) return -1;
BasicInPacket packet = (BasicInPacket)queue.getFirst();
if(packet instanceof ReceiveIMPacket) {
ReceiveIMPacket im = (ReceiveIMPacket)packet;
if(im.header.type == QQ.QQ_RECV_IM_SYS_MESSAGE)
return QQ.QQ_IM_FROM_SYS;
else if(im.header.type == QQ.QQ_RECV_IM_FROM_FRIEND || im.header.type == QQ.QQ_RECV_IM_FROM_STRANGER)
return QQ.QQ_IM_FROM_USER;
else if(im.header.type == QQ.QQ_RECV_IM_CLUSTER_IM ||
im.header.type == QQ.QQ_RECV_IM_TEMP_CLUSTER_IM ||
im.header.type == QQ.QQ_RECV_IM_UNKNOWN_CLUSTER_IM)
return QQ.QQ_IM_FROM_CLUSTER;
else if(im.header.type == QQ.QQ_RECV_IM_SMS || im.header.type == QQ.QQ_RECV_IM_MOBILE_QQ)
return QQ.QQ_IM_FROM_SMS;
else
return QQ.QQ_IM_FROM_SYS;
} else
return QQ.QQ_IM_FROM_SYS;
}
/**
* 返回该组内下一条消息发送者的QQ号
* @param g 组索引
* @return QQ号,如果没有消息,返回-1
*/
public int nextGroupSender(int g) {
ListIterator iter = queue.listIterator();
while(iter.hasNext()) {
Object obj = iter.next();
if(obj instanceof ReceiveIMPacket) {
ReceiveIMPacket packet = (ReceiveIMPacket)obj;
if(packet.header.type == QQ.QQ_RECV_IM_SMS || packet.header.type == QQ.QQ_RECV_IM_MOBILE_QQ)
continue;
// 得到下一个包的发送者QQ号
int sender = packet.header.sender;
if(packet.header.type == QQ.QQ_RECV_IM_TEMP_CLUSTER_IM)
sender = packet.clusterIM.clusterId;
// 在g指定的组中查找是否有这个好友
qqNumMatcher.setQQ(sender, true);
int[] indices = model.findItemIndex(g, qqNumMatcher);
// 如果有,那么肯定这是下一个发送者,返回
if(indices != null && indices.length > 0)
return sender;
else {
// 如果没有,看看这个是不是群
clusterIdMatcher.setClusterId(sender);
indices = model.findItemIndex(g, clusterIdMatcher);
if(indices != null && indices.length > 0)
return sender;
}
}
}
return -1;
}
/**
* 一个消息在好友列表还没得到之前到达了,延迟处理这个消息
* @param packet 消息包
*/
public void postponeMessage(BasicInPacket packet) {
postponeQueue.addLast(packet);
}
/**
* 返回下一个延迟处理的消息
* @return 如果有则返回消息,没有返回null
*/
public BasicInPacket getPostponedMessage() {
if(postponeQueue.size() > 0)
return (BasicInPacket)postponeQueue.removeFirst();
else
return null;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -