2006-11-22 23:55:37 +01:00
|
|
|
/**
|
2006-11-23 02:51:00 +01:00
|
|
|
* $RCSfile$
|
|
|
|
* $Revision: 2407 $
|
|
|
|
* $Date: 2004-11-02 15:37:00 -0800 (Tue, 02 Nov 2004) $
|
2006-11-22 23:55:37 +01:00
|
|
|
*
|
2007-02-12 01:59:05 +01:00
|
|
|
* Copyright 2003-2007 Jive Software.
|
2006-11-23 02:51:00 +01:00
|
|
|
*
|
|
|
|
* All rights reserved. Licensed 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.
|
2006-11-22 23:55:37 +01:00
|
|
|
*/
|
2006-11-23 02:51:00 +01:00
|
|
|
|
2006-11-22 23:55:37 +01:00
|
|
|
package org.jivesoftware.smack;
|
|
|
|
|
2006-12-05 08:46:29 +01:00
|
|
|
import org.jivesoftware.smack.filter.AndFilter;
|
|
|
|
import org.jivesoftware.smack.filter.FromContainsFilter;
|
|
|
|
import org.jivesoftware.smack.filter.PacketFilter;
|
|
|
|
import org.jivesoftware.smack.filter.ThreadFilter;
|
2006-11-22 23:55:37 +01:00
|
|
|
import org.jivesoftware.smack.packet.Message;
|
|
|
|
import org.jivesoftware.smack.packet.Packet;
|
2006-12-05 08:46:29 +01:00
|
|
|
import org.jivesoftware.smack.util.StringUtils;
|
|
|
|
import org.jivesoftware.smack.util.collections.ReferenceMap;
|
2006-11-22 23:55:37 +01:00
|
|
|
|
|
|
|
import java.util.*;
|
|
|
|
import java.util.concurrent.CopyOnWriteArraySet;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The chat manager keeps track of references to all current chats. It will not hold any references
|
|
|
|
* in memory on its own so it is neccesary to keep a reference to the chat object itself. To be
|
2006-11-23 02:51:00 +01:00
|
|
|
* made aware of new chats, register a listener by calling {@link #addChatListener(ChatManagerListener)}.
|
2006-11-22 23:55:37 +01:00
|
|
|
*
|
|
|
|
* @author Alexander Wenckus
|
|
|
|
*/
|
|
|
|
public class ChatManager {
|
2006-11-23 22:10:59 +01:00
|
|
|
|
2006-11-22 23:55:37 +01:00
|
|
|
/**
|
|
|
|
* Returns the next unique id. Each id made up of a short alphanumeric
|
|
|
|
* prefix along with a unique numeric value.
|
|
|
|
*
|
|
|
|
* @return the next id.
|
|
|
|
*/
|
|
|
|
private static synchronized String nextID() {
|
|
|
|
return prefix + Long.toString(id++);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A prefix helps to make sure that ID's are unique across mutliple instances.
|
|
|
|
*/
|
|
|
|
private static String prefix = StringUtils.randomString(5);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Keeps track of the current increment, which is appended to the prefix to
|
|
|
|
* forum a unique ID.
|
|
|
|
*/
|
|
|
|
private static long id = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Maps thread ID to chat.
|
|
|
|
*/
|
|
|
|
private Map<String, Chat> threadChats = new ReferenceMap<String, Chat>(ReferenceMap.HARD,
|
|
|
|
ReferenceMap.WEAK);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Maps jids to chats
|
|
|
|
*/
|
|
|
|
private Map<String, Chat> jidChats = new ReferenceMap<String, Chat>(ReferenceMap.HARD,
|
|
|
|
ReferenceMap.WEAK);
|
|
|
|
|
2006-11-23 22:10:59 +01:00
|
|
|
private Set<ChatManagerListener> chatManagerListeners
|
|
|
|
= new CopyOnWriteArraySet<ChatManagerListener>();
|
|
|
|
|
|
|
|
private Map<PacketInterceptor, PacketFilter> interceptors
|
|
|
|
= new WeakHashMap<PacketInterceptor, PacketFilter>();
|
2006-11-22 23:55:37 +01:00
|
|
|
|
|
|
|
private XMPPConnection connection;
|
|
|
|
|
|
|
|
ChatManager(XMPPConnection connection) {
|
|
|
|
this.connection = connection;
|
|
|
|
|
2006-11-23 02:51:00 +01:00
|
|
|
PacketFilter filter = new PacketFilter() {
|
|
|
|
public boolean accept(Packet packet) {
|
|
|
|
if (!(packet instanceof Message)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
Message.Type messageType = ((Message) packet).getType();
|
|
|
|
return messageType != Message.Type.groupchat &&
|
|
|
|
messageType != Message.Type.headline;
|
|
|
|
}
|
|
|
|
};
|
2006-11-22 23:55:37 +01:00
|
|
|
// Add a listener for all message packets so that we can deliver errant
|
|
|
|
// messages to the best Chat instance available.
|
|
|
|
connection.addPacketListener(new PacketListener() {
|
|
|
|
public void processPacket(Packet packet) {
|
|
|
|
Message message = (Message) packet;
|
|
|
|
Chat chat;
|
|
|
|
if (message.getThread() == null) {
|
|
|
|
chat = getUserChat(StringUtils.parseBareAddress(message.getFrom()));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
chat = getThreadChat(message.getThread());
|
2006-12-05 19:07:35 +01:00
|
|
|
if (chat == null) {
|
|
|
|
// Try to locate the chat based on the sender of the message
|
|
|
|
chat = getUserChat(StringUtils.parseBareAddress(message.getFrom()));
|
|
|
|
}
|
2006-11-22 23:55:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if(chat == null) {
|
|
|
|
chat = createChat(message);
|
|
|
|
}
|
|
|
|
deliverMessage(chat, message);
|
|
|
|
}
|
|
|
|
}, filter);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates a new chat and returns it.
|
|
|
|
*
|
|
|
|
* @param userJID the user this chat is with.
|
|
|
|
* @param listener the listener which will listen for new messages from this chat.
|
|
|
|
* @return the created chat.
|
|
|
|
*/
|
2006-11-23 22:10:59 +01:00
|
|
|
public Chat createChat(String userJID, MessageListener listener) {
|
2006-11-28 19:46:40 +01:00
|
|
|
String threadID;
|
|
|
|
do {
|
|
|
|
threadID = nextID();
|
|
|
|
} while (threadChats.get(threadID) != null);
|
2006-11-22 23:55:37 +01:00
|
|
|
|
2006-11-28 19:46:40 +01:00
|
|
|
return createChat(userJID, threadID, listener);
|
|
|
|
}
|
2006-11-22 23:55:37 +01:00
|
|
|
|
2006-11-28 19:46:40 +01:00
|
|
|
/**
|
|
|
|
* Creates a new chat using the specified thread ID, then returns it.
|
|
|
|
*
|
|
|
|
* @param userJID the jid of the user this chat is with
|
|
|
|
* @param thread the thread of the created chat.
|
|
|
|
* @param listener the listener to add to the chat
|
|
|
|
* @return the created chat.
|
|
|
|
*/
|
|
|
|
public Chat createChat(String userJID, String thread, MessageListener listener) {
|
|
|
|
Chat chat = threadChats.get(thread);
|
|
|
|
if(chat != null) {
|
|
|
|
throw new IllegalArgumentException("ThreadID is already used");
|
|
|
|
}
|
|
|
|
chat = createChat(userJID, thread, true);
|
|
|
|
chat.addMessageListener(listener);
|
2006-11-22 23:55:37 +01:00
|
|
|
return chat;
|
|
|
|
}
|
|
|
|
|
|
|
|
private Chat createChat(String userJID, String threadID, boolean createdLocally) {
|
|
|
|
Chat chat = new Chat(this, userJID, threadID);
|
|
|
|
threadChats.put(threadID, chat);
|
|
|
|
jidChats.put(userJID, chat);
|
|
|
|
|
2006-11-23 02:51:00 +01:00
|
|
|
for(ChatManagerListener listener : chatManagerListeners) {
|
2006-11-22 23:55:37 +01:00
|
|
|
listener.chatCreated(chat, createdLocally);
|
|
|
|
}
|
|
|
|
|
|
|
|
return chat;
|
|
|
|
}
|
|
|
|
|
|
|
|
private Chat createChat(Message message) {
|
|
|
|
String threadID = message.getThread();
|
|
|
|
String userJID = message.getFrom();
|
|
|
|
|
|
|
|
return createChat(userJID, threadID, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
private Chat getUserChat(String userJID) {
|
|
|
|
return jidChats.get(userJID);
|
|
|
|
}
|
|
|
|
|
2007-01-17 20:36:45 +01:00
|
|
|
public Chat getThreadChat(String thread) {
|
2006-11-22 23:55:37 +01:00
|
|
|
return threadChats.get(thread);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Register a new listener with the ChatManager to recieve events related to chats.
|
|
|
|
*
|
|
|
|
* @param listener the listener.
|
|
|
|
*/
|
2006-11-23 02:51:00 +01:00
|
|
|
public void addChatListener(ChatManagerListener listener) {
|
|
|
|
chatManagerListeners.add(listener);
|
2006-11-22 23:55:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Removes a listener, it will no longer be notified of new events related to chats.
|
|
|
|
*
|
|
|
|
* @param listener the listener that is being removed
|
|
|
|
*/
|
2006-11-23 02:51:00 +01:00
|
|
|
public void removeChatListener(ChatManagerListener listener) {
|
|
|
|
chatManagerListeners.remove(listener);
|
2006-11-22 23:55:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns an unmodifiable collection of all chat listeners currently registered with this
|
|
|
|
* manager.
|
|
|
|
*
|
|
|
|
* @return an unmodifiable collection of all chat listeners currently registered with this
|
|
|
|
* manager.
|
|
|
|
*/
|
2006-11-23 02:51:00 +01:00
|
|
|
public Collection<ChatManagerListener> getChatListeners() {
|
|
|
|
return Collections.unmodifiableCollection(chatManagerListeners);
|
2006-11-22 23:55:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private void deliverMessage(Chat chat, Message message) {
|
|
|
|
// Here we will run any interceptors
|
|
|
|
chat.deliver(message);
|
|
|
|
}
|
|
|
|
|
|
|
|
void sendMessage(Chat chat, Message message) {
|
2006-11-23 22:10:59 +01:00
|
|
|
for(Map.Entry<PacketInterceptor, PacketFilter> interceptor : interceptors.entrySet()) {
|
|
|
|
PacketFilter filter = interceptor.getValue();
|
|
|
|
if(filter != null && filter.accept(message)) {
|
|
|
|
interceptor.getKey().interceptPacket(message);
|
|
|
|
}
|
|
|
|
}
|
2006-12-05 08:46:29 +01:00
|
|
|
// Ensure that messages being sent have a proper FROM value
|
|
|
|
if (message.getFrom() == null) {
|
|
|
|
message.setFrom(connection.getUser());
|
|
|
|
}
|
2006-11-22 23:55:37 +01:00
|
|
|
connection.sendPacket(message);
|
|
|
|
}
|
|
|
|
|
|
|
|
PacketCollector createPacketCollector(Chat chat) {
|
|
|
|
return connection.createPacketCollector(new AndFilter(new ThreadFilter(chat.getThreadID()),
|
|
|
|
new FromContainsFilter(chat.getParticipant())));
|
|
|
|
}
|
|
|
|
|
2006-11-23 22:10:59 +01:00
|
|
|
/**
|
|
|
|
* Adds an interceptor which intercepts any messages sent through chats.
|
|
|
|
*
|
|
|
|
* @param packetInterceptor the interceptor.
|
|
|
|
*/
|
|
|
|
public void addOutgoingMessageInterceptor(PacketInterceptor packetInterceptor) {
|
|
|
|
addOutgoingMessageInterceptor(packetInterceptor, null);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void addOutgoingMessageInterceptor(PacketInterceptor packetInterceptor, PacketFilter filter) {
|
|
|
|
if (packetInterceptor != null) {
|
|
|
|
interceptors.put(packetInterceptor, filter);
|
|
|
|
}
|
|
|
|
}
|
2006-11-22 23:55:37 +01:00
|
|
|
}
|