diff options
author | hristoterezov <hristo@jitsi.org> | 2014-05-29 15:13:20 +0300 |
---|---|---|
committer | hristoterezov <hristo@jitsi.org> | 2014-05-29 15:13:20 +0300 |
commit | 2a12abaefeb6601d1f2b4170fcdc4e810422f1a7 (patch) | |
tree | fd3810f7509ca15b55f46ba9f2e591445d985fa7 /src | |
parent | 1c9691a3b44113fb0fe596518c45c0b1ba52c291 (diff) | |
download | jitsi-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')
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); } } } |