aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorhristoterezov <hristo@jitsi.org>2014-05-29 15:13:20 +0300
committerhristoterezov <hristo@jitsi.org>2014-05-29 15:13:20 +0300
commit2a12abaefeb6601d1f2b4170fcdc4e810422f1a7 (patch)
treefd3810f7509ca15b55f46ba9f2e591445d985fa7 /src
parent1c9691a3b44113fb0fe596518c45c0b1ba52c291 (diff)
downloadjitsi-2a12abaefeb6601d1f2b4170fcdc4e810422f1a7.zip
jitsi-2a12abaefeb6601d1f2b4170fcdc4e810422f1a7.tar.gz
jitsi-2a12abaefeb6601d1f2b4170fcdc4e810422f1a7.tar.bz2
Removing Smack ChatManager, Chat and ChatStateManager objects from our code and implements manual sending of messages and handles the responses.
Diffstat (limited to 'src')
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicInstantMessagingJabberImpl.java301
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/OperationSetTypingNotificationsJabberImpl.java145
2 files changed, 179 insertions, 267 deletions
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicInstantMessagingJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicInstantMessagingJabberImpl.java
index a6c06e6..588e917 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicInstantMessagingJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicInstantMessagingJabberImpl.java
@@ -33,6 +33,7 @@ import org.jivesoftware.smackx.packet.*;
* @author Matthieu Helleringer
* @author Alain Knaebel
* @author Emil Ivov
+ * @author Hristo Terezov
*/
public class OperationSetBasicInstantMessagingJabberImpl
extends AbstractOperationSetBasicInstantMessaging
@@ -56,10 +57,15 @@ public class OperationSetBasicInstantMessagingJabberImpl
* target a specific resource (rather than sending a message to all logged
* instances of a user).
*/
- private Map<String, TargetAddress> jids
- = new Hashtable<String, TargetAddress>();
+ private Map<String, StoredThreadID> jids
+ = new Hashtable<String, StoredThreadID>();
/**
+ * The most recent full JID used for the contact address.
+ */
+ private Map<String, String> recentJIDForAddress
+ = new Hashtable<String, String>();
+ /**
* The smackMessageListener instance listens for incoming messages.
* Keep a reference of it so if anything goes wrong we don't add
* two different instances.
@@ -70,19 +76,28 @@ public class OperationSetBasicInstantMessagingJabberImpl
* Contains the complete jid of a specific user and the time that it was
* last used so that we could remove it after a certain point.
*/
- public static class TargetAddress
+ public static class StoredThreadID
{
- /** The last complete JID (including resource) that we got a msg from*/
- String jid;
-
/** The time that we last sent or received a message from this jid */
long lastUpdatedTime;
/** The last chat used, this way we will reuse the thread-id */
- Chat chat;
+ String threadID;
}
/**
+ * A prefix helps to make sure that thread 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 thread ID.
+ */
+ private static long id = 0;
+
+ /**
* The number of milliseconds that we preserve threads with no traffic
* before considering them dead.
*/
@@ -266,11 +281,7 @@ public class OperationSetBasicInstantMessagingJabberImpl
return true;
else if(contentType.equals(HTML_MIME_TYPE))
{
- String toJID = null;
-
- TargetAddress ta = getJidForAddress(contact.getAddress());
- if(ta != null)
- toJID = ta.jid;
+ String toJID = recentJIDForAddress.get(contact.getAddress());
if (toJID == null)
toJID = contact.getAddress();
@@ -284,73 +295,24 @@ public class OperationSetBasicInstantMessagingJabberImpl
}
/**
- * Returns a reference to an open chat with the specified
- * <tt>jid</tt> if one exists or creates a new one otherwise.
- *
- * @param toAddress the address without the resource, we used to put
- * a reference in jids table.
- * @param jid the Jabber ID that we'd like to obtain a chat instance for.
- *
- * @return a reference to an open chat with the specified
- * <tt>jid</tt> if one exists or creates a new one otherwise.
- */
- public Chat obtainChatInstance(String toAddress,
- String jid)
- {
- XMPPConnection jabberConnection
- = jabberProvider.getConnection();
-
- TargetAddress ta = getJidForAddress(toAddress);
-
- if (ta != null
- && ta.chat != null
- && ta.jid.equals(jid)
- && ta.chat.getParticipant().equals(jid))
- {
- return ta.chat;
- }
-
- org.jivesoftware.smack.MessageListener msgListener
- = new org.jivesoftware.smack.MessageListener()
- {
- public void processMessage(
- Chat chat,
- org.jivesoftware.smack.packet.Message message)
- {
- //we are not fully supporting chat based messaging
- //right now and only use a hack to make it look that
- //way. as a result we don't listen on the chat
- //itself and the only thing we do here is an update
- //of the active thread timestamp.
- }
- };
-
- //we don't have a thread for this chat, so let's create one.
- Chat chat = jabberConnection.getChatManager()
- .createChat(jid, msgListener);
-
- return chat;
- }
-
- /**
* Remove from our <tt>jids</tt> map all entries that have not seen any
* activity (i.e. neither outgoing nor incoming messags) for more than
* JID_INACTIVITY_TIMEOUT. Note that this method is not synchronous and that
- * it is only meant for use by the {@link #getJidForAddress(String)} and
+ * it is only meant for use by the {@link #getThreadIDForAddress(String)} and
* {@link #putJidForAddress(String, String, Chat)}
*/
private void purgeOldJids()
{
long currentTime = System.currentTimeMillis();
- Iterator<Map.Entry<String, TargetAddress>> entries
+ Iterator<Map.Entry<String, StoredThreadID>> entries
= jids.entrySet().iterator();
while( entries.hasNext() )
{
- Map.Entry<String, TargetAddress> entry = entries.next();
- TargetAddress target = entry.getValue();
+ Map.Entry<String, StoredThreadID> entry = entries.next();
+ StoredThreadID target = entry.getValue();
if (currentTime - target.lastUpdatedTime
> JID_INACTIVITY_TIMEOUT)
@@ -371,19 +333,19 @@ public class OperationSetBasicInstantMessagingJabberImpl
* contacted us from or <tt>null</tt> if we don't have a jid for the
* specified <tt>address</tt> yet.
*/
- TargetAddress getJidForAddress(String address)
+ String getThreadIDForAddress(String jid)
{
synchronized(jids)
{
purgeOldJids();
- TargetAddress ta = jids.get(address);
+ StoredThreadID ta = jids.get(jid);
if (ta == null)
return null;
ta.lastUpdatedTime = System.currentTimeMillis();
- return ta;
+ return ta.threadID;
}
}
@@ -398,23 +360,24 @@ public class OperationSetBasicInstantMessagingJabberImpl
* @param jid the jid (i.e. address/resource) that the contact with the
* specified <tt>address</tt> last contacted us from.
*/
- private void putJidForAddress(String address, String jid, Chat chat)
+ private void putJidForAddress(String jid, String threadID)
{
synchronized(jids)
{
purgeOldJids();
- TargetAddress ta = jids.get(address);
+ StoredThreadID ta = jids.get(jid);
if (ta == null)
{
- ta = new TargetAddress();
- jids.put(address, ta);
+ ta = new StoredThreadID();
+ jids.put(jid, ta);
}
- ta.jid = jid;
+ recentJIDForAddress.put(StringUtils.parseBareAddress(jid), jid);
+
ta.lastUpdatedTime = System.currentTimeMillis();
- ta.chat = chat;
+ ta.threadID = threadID;
}
}
@@ -441,115 +404,100 @@ public class OperationSetBasicInstantMessagingJabberImpl
"The specified contact is not a Jabber contact."
+ to);
- try
- {
- assertConnected();
-
- org.jivesoftware.smack.packet.Message msg =
- new org.jivesoftware.smack.packet.Message();
+ assertConnected();
- String toJID = null;
-
- boolean sendToBaseResource = false;
- if (toResource != null)
- {
- if(toResource.equals(ContactResource.BASE_RESOURCE))
- {
- toJID = to.getAddress();
- sendToBaseResource = true;
- }
- else
- toJID =
- ((ContactResourceJabberImpl) toResource).getFullJid();
- }
+ org.jivesoftware.smack.packet.Message msg =
+ new org.jivesoftware.smack.packet.Message();
- if (toJID == null)
- {
- TargetAddress ta = getJidForAddress(to.getAddress());
- if(ta != null)
- toJID = ta.jid;
- }
+ String toJID = null;
- if (toJID == null)
+ if (toResource != null)
+ {
+ if(toResource.equals(ContactResource.BASE_RESOURCE))
{
- sendToBaseResource = true;
toJID = to.getAddress();
}
+ else
+ toJID =
+ ((ContactResourceJabberImpl) toResource).getFullJid();
+ }
- Chat chat = obtainChatInstance(to.getAddress(), toJID);
+ if (toJID == null)
+ {
+ toJID = to.getAddress();
+ }
- msg.setPacketID(message.getMessageUID());
- msg.setTo(toJID);
+ msg.setPacketID(message.getMessageUID());
+ msg.setTo(toJID);
- for (PacketExtension ext : extensions)
- {
- msg.addExtension(ext);
- }
+ for (PacketExtension ext : extensions)
+ {
+ msg.addExtension(ext);
+ }
- if (logger.isTraceEnabled())
- logger.trace("Will send a message to:" + toJID
- + " chat.jid=" + chat.getParticipant()
- + " chat.tid=" + chat.getThreadID());
+ if (logger.isTraceEnabled())
+ logger.trace("Will send a message to:" + toJID
+ + " chat.jid=" + toJID);
- MessageDeliveredEvent msgDeliveryPendingEvt
- = new MessageDeliveredEvent(message, to, toResource);
+ MessageDeliveredEvent msgDeliveryPendingEvt
+ = new MessageDeliveredEvent(message, to, toResource);
- msgDeliveryPendingEvt
- = messageDeliveryPendingTransform(msgDeliveryPendingEvt);
+ msgDeliveryPendingEvt
+ = messageDeliveryPendingTransform(msgDeliveryPendingEvt);
- if (msgDeliveryPendingEvt == null)
- return null;
+ if (msgDeliveryPendingEvt == null)
+ return null;
- String content = msgDeliveryPendingEvt
- .getSourceMessage().getContent();
+ String content = msgDeliveryPendingEvt
+ .getSourceMessage().getContent();
- if(message.getContentType().equals(HTML_MIME_TYPE))
- {
- msg.setBody(Html2Text.extractText(content));
+ if(message.getContentType().equals(HTML_MIME_TYPE))
+ {
+ msg.setBody(Html2Text.extractText(content));
- // Check if the other user supports XHTML messages
- // make sure we use our discovery manager as it caches calls
- if(jabberProvider.isFeatureListSupported(
- chat.getParticipant(),
- HTML_NAMESPACE))
- {
- // Add the XHTML text to the message
- XHTMLManager.addBody(msg,
- OPEN_BODY_TAG + content + CLOSE_BODY_TAG);
- }
- }
- else
+ // Check if the other user supports XHTML messages
+ // make sure we use our discovery manager as it caches calls
+ if(jabberProvider.isFeatureListSupported(
+ toJID,
+ HTML_NAMESPACE))
{
- // this is plain text so keep it as it is.
- msg.setBody(content);
+ // Add the XHTML text to the message
+ XHTMLManager.addBody(msg,
+ OPEN_BODY_TAG + content + CLOSE_BODY_TAG);
}
+ }
+ else
+ {
+ // this is plain text so keep it as it is.
+ msg.setBody(content);
+ }
- //msg.addExtension(new Version());
+ //msg.addExtension(new Version());
- if(msgDeliveryPendingEvt.isMessageEncrypted())
- {
- msg.addExtension(new CarbonPacketExtension.PrivateExtension());
- }
+ if(msgDeliveryPendingEvt.isMessageEncrypted())
+ {
+ msg.addExtension(new CarbonPacketExtension.PrivateExtension());
+ }
- MessageEventManager.
- addNotificationsRequests(msg, true, false, false, true);
+ MessageEventManager.
+ addNotificationsRequests(msg, true, false, false, true);
- chat.sendMessage(msg);
+ String threadID = getThreadIDForAddress(toJID);
+ if(threadID == null)
+ threadID = nextThreadID();
- putJidForAddress(to.getAddress(), toJID, chat);
+ msg.setThread(threadID);
- MessageDeliveredEvent msgDeliveredEvt
- = new MessageDeliveredEvent(message, to, toResource);
+ jabberProvider.getConnection().sendPacket(msg);
- // msgDeliveredEvt = messageDeliveredTransform(msgDeliveredEvt);
+ putJidForAddress(toJID, threadID);
- return msgDeliveredEvt;
- }
- catch (XMPPException ex)
- {
- logger.error("message not sent", ex);
- return null;
- }
+ MessageDeliveredEvent msgDeliveredEvt
+ = new MessageDeliveredEvent(message, to, toResource);
+
+ // msgDeliveredEvt = messageDeliveredTransform(msgDeliveredEvt);
+
+ return msgDeliveredEvt;
}
/**
@@ -1009,27 +957,7 @@ public class OperationSetBasicInstantMessagingJabberImpl
fireMessageEvent(ev);
return;
}
- //cache the jid (resource included) of the contact that's sending us
- //a message so that all following messages would go to the resource
- //that they contacted us from.
- String address = userBareID;
- if(isPrivateMessaging)
- {
- address = JabberActivator.getResources().getI18NString(
- "service.gui.FROM",
- new String[]{
- StringUtils.parseResource(msg.getFrom()),
- userBareID} );
- }
-
- Chat chat =
- jabberProvider.getConnection().getChatManager()
- .getThreadChat(msg.getThread());
- putJidForAddress(address, userFullId, chat);
-
- if (logger.isTraceEnabled())
- logger.trace("just mapped: " + userBareID
- + " to " + msg.getFrom());
+ putJidForAddress(userFullId, msg.getThread());
// In the second condition we filter all group chat messages,
// because they are managed by the multi user chat operation set.
@@ -1247,6 +1175,11 @@ public class OperationSetBasicInstantMessagingJabberImpl
return message.toString();
}
+ public String getRecentJIDForAddress(String address)
+ {
+ return recentJIDForAddress.get(address);
+ }
+
/**
* Receives incoming MailNotification Packets
*/
@@ -1358,4 +1291,16 @@ public class OperationSetBasicInstantMessagingJabberImpl
{
this.packetFilters.add(filter);
}
+
+ /**
+ * Returns the next unique thread id. Each thread id made up of a short
+ * alphanumeric prefix along with a unique numeric value.
+ *
+ * @return the next thread id.
+ */
+ private static synchronized String nextThreadID() {
+ return prefix + Long.toString(id++);
+ }
+
+
}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetTypingNotificationsJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetTypingNotificationsJabberImpl.java
index 79f0b29..2e43512 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetTypingNotificationsJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetTypingNotificationsJabberImpl.java
@@ -14,8 +14,12 @@ import net.java.sip.communicator.service.protocol.jabberconstants.*;
import net.java.sip.communicator.util.*;
import org.jivesoftware.smack.*;
-import org.jivesoftware.smack.util.StringUtils;
+import org.jivesoftware.smack.filter.*;
+import org.jivesoftware.smack.packet.*;
+import org.jivesoftware.smack.packet.Message;
+import org.jivesoftware.smack.util.*;
import org.jivesoftware.smackx.*;
+import org.jivesoftware.smackx.packet.*;
/**
* Maps SIP Communicator typing notifications to those going and coming from
@@ -23,6 +27,7 @@ import org.jivesoftware.smackx.*;
*
* @author Damian Minkov
* @author Emil Ivov
+ * @author Hristo Terezov
*/
public class OperationSetTypingNotificationsJabberImpl
extends AbstractOperationSetTypingNotifications<ProtocolProviderServiceJabberImpl>
@@ -62,12 +67,6 @@ public class OperationSetTypingNotificationsJabberImpl
private SmackChatStateListener smackChatStateListener = null;
/**
- * The listener instance that we use in order to track for new chats so that
- * we could stick a SmackChatStateListener to them.
- */
- private SmackChatManagerListener smackChatManagerListener = null;
-
- /**
* @param provider a ref to the <tt>ProtocolProviderServiceImpl</tt>
* that created us and that we'll use for retrieving the underlying aim
* connection.
@@ -148,15 +147,12 @@ public class OperationSetTypingNotificationsJabberImpl
|| parentProvider.getConnection() == null)
return;
- String toJID = null;
+ String toJID = opSetBasicIM.getRecentJIDForAddress(contact.getAddress());
// find the currently contacted jid to send typing info to him
// or if we do not have a jid and we have already sent message to the
// bare jid we will also send typing info there
- OperationSetBasicInstantMessagingJabberImpl.TargetAddress ta
- = opSetBasicIM.getJidForAddress(contact.getAddress());
- if (ta != null)
- toJID = ta.jid;
+
// if we haven't sent a message yet, do not send typing notifications
if(toJID == null)
@@ -166,13 +162,6 @@ public class OperationSetTypingNotificationsJabberImpl
logger.trace("Sending XEP-0085 chat state=" + state
+ " to " + toJID);
- Chat chat;
-
- if(ta != null && ta.chat != null)
- chat = ta.chat;
- else
- chat = parentProvider.getConnection()
- .getChatManager().createChat(toJID, null);
ChatState chatState = null;
@@ -193,18 +182,29 @@ public class OperationSetTypingNotificationsJabberImpl
chatState = ChatState.gone;
}
- try
- {
- ChatStateManager.getInstance(parentProvider.getConnection())
- .setCurrentState(chatState, chat);
- }
- catch(XMPPException exc)
- {
- //we don't want to bother the user with network exceptions
- //so let's simply log it.
- logger.warn("Failed to send state [" + state + "] to ["
- + contact.getAddress() + "].", exc);
- }
+ setCurrentState(chatState, toJID);
+ }
+
+ /**
+ * Creates and sends a packet for the new chat state.
+ * @param chatState the new chat state.
+ * @param jid the JID of the receiver.
+ */
+ private void setCurrentState(ChatState chatState, String jid)
+ {
+ String threadID = opSetBasicIM.getThreadIDForAddress(jid);
+ if(threadID == null)
+ return;
+
+ Message message = new Message();
+ ChatStateExtension extension = new ChatStateExtension(chatState);
+ message.addExtension(extension);
+
+ message.setTo(jid);
+ message.setType(Message.Type.chat);
+ message.setThread(threadID);
+ message.setFrom(parentProvider.getConnection().getUser());
+ parentProvider.getConnection().sendPacket(message);
}
/**
@@ -271,30 +271,27 @@ public class OperationSetTypingNotificationsJabberImpl
messageEventManager.addMessageEventNotificationListener(
new IncomingMessageEventsListener());
- //according to the smack api documentation we need to do this
- //every time we connect in order to reinitialize the chat state
- //manager (@see http://tinyurl.com/6j9uqs )
- ChatStateManager.getInstance(parentProvider.getConnection());
+ if(smackChatStateListener == null)
+ smackChatStateListener = new SmackChatStateListener();
+
+ parentProvider.getConnection().addPacketListener(
+ smackChatStateListener, new PacketTypeFilter(Message.class));
+
- if(smackChatManagerListener == null)
- smackChatManagerListener = new SmackChatManagerListener();
- parentProvider.getConnection().getChatManager()
- .addChatListener(smackChatManagerListener);
}
else if(evt.getNewState() == RegistrationState.UNREGISTERED
|| evt.getNewState() == RegistrationState.AUTHENTICATION_FAILED
|| evt.getNewState() == RegistrationState.CONNECTION_FAILED)
{
- if(parentProvider.getConnection() != null
- && parentProvider.getConnection().getChatManager() != null)
+ if(parentProvider.getConnection() != null)
{
- parentProvider.getConnection().getChatManager()
- .removeChatListener(smackChatManagerListener);
+ parentProvider.getConnection()
+ .removePacketListener(smackChatStateListener);
}
- smackChatManagerListener = null;
+ smackChatStateListener = null;
if(messageEventManager != null)
{
@@ -306,32 +303,6 @@ public class OperationSetTypingNotificationsJabberImpl
}
/**
- * The class that we use when listening for new chats so that we could start
- * tracking them for chat events.
- */
- private class SmackChatManagerListener implements ChatManagerListener
- {
- /**
- * Simply adds a chat state listener to every newly created chat
- * so that we could track it for chat state events.
- *
- * @param chat the chat that we need to add a state listener to.
- * @param isLocal indicates whether the chat has been initiated by us
- */
- public void chatCreated(Chat chat, boolean isLocal)
- {
- if (logger.isTraceEnabled())
- logger.trace("Created a chat with "
- + chat.getParticipant() + " local="+isLocal);
-
- if(smackChatStateListener == null)
- smackChatStateListener = new SmackChatStateListener();
-
- chat.addMessageListener(smackChatStateListener);
- };
- }
-
- /**
* Listens for incoming request for typing info
*/
private class JabberMessageEventRequestListener
@@ -419,7 +390,7 @@ public class OperationSetTypingNotificationsJabberImpl
* to XEP-0085.
*/
private class SmackChatStateListener
- implements ChatStateListener
+ implements PacketListener
{
/**
* Called by smack when the state of a chat changes.
@@ -428,15 +399,16 @@ public class OperationSetTypingNotificationsJabberImpl
* @param state the new state of the chat.
* @param message the message containing the new chat state
*/
- public void stateChanged(Chat chat,
- ChatState state,
+ public void stateChanged(ChatState state,
org.jivesoftware.smack.packet.Message message)
{
+ String fromJID = message.getFrom();
if (logger.isTraceEnabled())
- logger.trace(chat.getParticipant() + " entered the "
+ logger.trace(fromJID + " entered the "
+ state.name()+ " state.");
- String fromID = StringUtils.parseBareAddress(chat.getParticipant());
+
+ String fromID = StringUtils.parseBareAddress(fromJID);
List<ChatRoom> chatRooms = parentProvider.getOperationSet(
OperationSetMultiUserChat.class).getCurrentlyJoinedChatRooms();
@@ -465,8 +437,7 @@ public class OperationSetTypingNotificationsJabberImpl
{
//create the volatile contact
sourceContact = opSetPersPresence.createVolatileContact(
- (isPrivateMessagingAddress? message.getFrom() :
- chat.getParticipant()), isPrivateMessagingAddress);
+ message.getFrom(), isPrivateMessagingAddress);
}
}
@@ -496,19 +467,15 @@ public class OperationSetTypingNotificationsJabberImpl
logger.warn("Unknown typing state!");
}
- /**
- * Called when a new message is received. We ignore this one since
- * we handle message reception on a lower level.
- *
- * @param chat the chat that the message belongs to
- * @param msg the message that we need to process.
- */
- public void processMessage(Chat chat,
- org.jivesoftware.smack.packet.Message msg)
+ @Override
+ public void processPacket(Packet packet)
{
- if (logger.isTraceEnabled())
- logger.trace("ignoring a process message");
-
+ Message msg = (Message) packet;
+ ChatStateExtension ext = (ChatStateExtension) msg.getExtension(
+ "http://jabber.org/protocol/chatstates");
+ if(ext == null)
+ return;
+ stateChanged(ChatState.valueOf(ext.getElementName()), msg);
}
}
}