From 90d6377fdb0a56770dfa2354520ffe4934990162 Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Fri, 11 Feb 2011 12:49:00 +0500 Subject: [PATCH 01/33] Fix empty SASL's element. --- source/org/jivesoftware/smack/sasl/SASLMechanism.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/source/org/jivesoftware/smack/sasl/SASLMechanism.java b/source/org/jivesoftware/smack/sasl/SASLMechanism.java index 8a5767740..cebd1bd12 100644 --- a/source/org/jivesoftware/smack/sasl/SASLMechanism.java +++ b/source/org/jivesoftware/smack/sasl/SASLMechanism.java @@ -263,9 +263,6 @@ public String toXML() { if (authenticationText != null) { stanza.append(authenticationText); } - else { - stanza.append("="); - } stanza.append(""); return stanza.toString(); } From 71a651785165ae8d46567f3c0e29304257b07ce3 Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Mon, 28 Feb 2011 16:24:00 +0500 Subject: [PATCH 02/33] DataForm in FileTransferNegotiator must contains field with TYPE_LIST_SINGLE. --- .../smackx/filetransfer/FileTransferNegotiator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/org/jivesoftware/smackx/filetransfer/FileTransferNegotiator.java b/source/org/jivesoftware/smackx/filetransfer/FileTransferNegotiator.java index cd74c1ff7..06ec67316 100644 --- a/source/org/jivesoftware/smackx/filetransfer/FileTransferNegotiator.java +++ b/source/org/jivesoftware/smackx/filetransfer/FileTransferNegotiator.java @@ -473,7 +473,7 @@ else if (isByteStream) { private DataForm createDefaultInitiationForm() { DataForm form = new DataForm(Form.TYPE_FORM); FormField field = new FormField(STREAM_DATA_FIELD_NAME); - field.setType(FormField.TYPE_LIST_MULTI); + field.setType(FormField.TYPE_LIST_SINGLE); if (!IBB_ONLY) { field.addOption(new FormField.Option(Socks5BytestreamManager.NAMESPACE)); } From 0c06a1b16599a0d08e94143529d540935e568f89 Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Wed, 2 Mar 2011 17:10:09 +0500 Subject: [PATCH 03/33] Set file size and name for outgoing file transfer from InputStream. --- .../jivesoftware/smackx/filetransfer/OutgoingFileTransfer.java | 1 + 1 file changed, 1 insertion(+) diff --git a/source/org/jivesoftware/smackx/filetransfer/OutgoingFileTransfer.java b/source/org/jivesoftware/smackx/filetransfer/OutgoingFileTransfer.java index 88822fd86..e0271d646 100644 --- a/source/org/jivesoftware/smackx/filetransfer/OutgoingFileTransfer.java +++ b/source/org/jivesoftware/smackx/filetransfer/OutgoingFileTransfer.java @@ -276,6 +276,7 @@ public synchronized void sendStream(final InputStream in, final String fileName, transferThread = new Thread(new Runnable() { public void run() { + setFileInfo(fileName, fileSize); //Create packet filter try { outputStream = negotiateStream(fileName, fileSize, description); From 03237f7a9f30f4f2332a8573682d9caabbd3d539 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Tue, 29 Mar 2011 12:03:57 +0200 Subject: [PATCH 04/33] Revert "initialize ServiceDiscovery on demand" as it causes problems on disconnect(). Features check the state of the connection with: // remove feature from service discovery ServiceDiscoveryManager serviceDiscoveryManager = ServiceDiscoveryManager.getInstanceFor(this.connection); // check if service discovery is not already disposed by connection shutdown if (serviceDiscoveryManager != null) { serviceDiscoveryManager.removeFeature(NAMESPACE); } This reverts commit 7ad98dc7f729781b442156561f5ebc2894569d1b. --- .../smackx/ServiceDiscoveryManager.java | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/source/org/jivesoftware/smackx/ServiceDiscoveryManager.java b/source/org/jivesoftware/smackx/ServiceDiscoveryManager.java index cb25ec65d..94c768459 100644 --- a/source/org/jivesoftware/smackx/ServiceDiscoveryManager.java +++ b/source/org/jivesoftware/smackx/ServiceDiscoveryManager.java @@ -68,7 +68,7 @@ public class ServiceDiscoveryManager { private EntityCapsManager capsManager; private static Map instances = - new HashMap(); + new ConcurrentHashMap(); private Connection connection; private final List features = new ArrayList(); @@ -81,7 +81,7 @@ public class ServiceDiscoveryManager { // Add service discovery for normal XMPP c2s connections XMPPConnection.addConnectionCreationListener(new ConnectionCreationListener() { public void connectionCreated(Connection connection) { - getInstanceFor(connection); + new ServiceDiscoveryManager(connection); } }); } @@ -114,13 +114,7 @@ public ServiceDiscoveryManager(Connection connection) { * @return the ServiceDiscoveryManager associated with a given connection. */ public static ServiceDiscoveryManager getInstanceFor(Connection connection) { - synchronized (instances) { - ServiceDiscoveryManager serviceDiscoveryManager = instances.get(connection); - if (serviceDiscoveryManager != null) { - return serviceDiscoveryManager; - } - return new ServiceDiscoveryManager(connection); - } + return instances.get(connection); } /** @@ -240,9 +234,7 @@ private void init() { connection.addConnectionListener(new ConnectionListener() { public void connectionClosed() { // Unregister this instance since the connection has been closed - synchronized (instances) { - instances.remove(connection); - } + instances.remove(connection); } public void connectionClosedOnError(Exception e) { From a480d982f17862c94b7ba8f430100427fc7ddf03 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Thu, 14 Apr 2011 15:25:03 +0200 Subject: [PATCH 05/33] fixing SMACK-329 http://issues.igniterealtime.org/browse/SMACK-329 --- source/org/jivesoftware/smackx/XHTMLText.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/org/jivesoftware/smackx/XHTMLText.java b/source/org/jivesoftware/smackx/XHTMLText.java index 63b8218d5..201e5308a 100644 --- a/source/org/jivesoftware/smackx/XHTMLText.java +++ b/source/org/jivesoftware/smackx/XHTMLText.java @@ -131,7 +131,7 @@ private String closeBodyTag() { * */ public void appendBrTag() { - text.append("
"); + text.append("
"); } /** From f4d8f796f8f560f9562dfe8f7c711c5b2ab09496 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sun, 17 Apr 2011 11:47:22 +0200 Subject: [PATCH 06/33] Do disco by component name --- source/org/jivesoftware/smackx/OfflineMessageManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/org/jivesoftware/smackx/OfflineMessageManager.java b/source/org/jivesoftware/smackx/OfflineMessageManager.java index efc928021..ea1c3ca80 100644 --- a/source/org/jivesoftware/smackx/OfflineMessageManager.java +++ b/source/org/jivesoftware/smackx/OfflineMessageManager.java @@ -77,7 +77,7 @@ public OfflineMessageManager(Connection connection) { * @throws XMPPException If the user is not allowed to make this request. */ public boolean supportsFlexibleRetrieval() throws XMPPException { - DiscoverInfo info = ServiceDiscoveryManager.getInstanceFor(connection).discoverInfo(null); + DiscoverInfo info = ServiceDiscoveryManager.getInstanceFor(connection).discoverInfo(connection.getServiceName()); return info.containsFeature(namespace); } From 6a37d9e1dcf6f14f20de8699364e21c31ecea2d6 Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Thu, 21 Apr 2011 20:42:51 +0600 Subject: [PATCH 07/33] Fix using compression --- source/org/jivesoftware/smack/XMPPConnection.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/source/org/jivesoftware/smack/XMPPConnection.java b/source/org/jivesoftware/smack/XMPPConnection.java index 361ca0aff..75f78f836 100644 --- a/source/org/jivesoftware/smack/XMPPConnection.java +++ b/source/org/jivesoftware/smack/XMPPConnection.java @@ -578,9 +578,7 @@ private void connectUsingConfiguration(ConnectionConfiguration config) throws XM */ private void initConnection() throws XMPPException { boolean isFirstInitialization = packetReader == null || packetWriter == null; - if (!isFirstInitialization) { - usingCompression = false; - } + usingCompression = false; // Set the reader and writer instance variables initReaderAndWriter(); From cb68c8e01b705ee36538ca87bb9776f076188529 Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Thu, 21 Apr 2011 20:43:59 +0600 Subject: [PATCH 08/33] Remove chat manager on disconnect --- source/org/jivesoftware/smack/Connection.java | 2 +- source/org/jivesoftware/smack/XMPPConnection.java | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/source/org/jivesoftware/smack/Connection.java b/source/org/jivesoftware/smack/Connection.java index a90282da9..7cf6b81ea 100644 --- a/source/org/jivesoftware/smack/Connection.java +++ b/source/org/jivesoftware/smack/Connection.java @@ -159,7 +159,7 @@ public abstract class Connection { /** * The ChatManager keeps track of references to all current chats. */ - private ChatManager chatManager = null; + protected ChatManager chatManager = null; /** * The SmackDebugger allows to log and debug XML traffic. diff --git a/source/org/jivesoftware/smack/XMPPConnection.java b/source/org/jivesoftware/smack/XMPPConnection.java index 75f78f836..365e9a792 100644 --- a/source/org/jivesoftware/smack/XMPPConnection.java +++ b/source/org/jivesoftware/smack/XMPPConnection.java @@ -474,6 +474,7 @@ public void disconnect(Presence unavailablePresence) { roster.cleanup(); roster = null; } + chatManager = null; wasAuthenticated = false; @@ -666,6 +667,7 @@ else if (!wasAuthenticated) { socket = null; } this.setWasAuthenticated(authenticated); + chatManager = null; authenticated = false; connected = false; From e3a7f3d2b623d9d4b13226adefbdcbb9608c232d Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Thu, 21 Apr 2011 20:48:02 +0600 Subject: [PATCH 09/33] Fix NullPointerException in disconnect --- source/org/jivesoftware/smack/XMPPConnection.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/org/jivesoftware/smack/XMPPConnection.java b/source/org/jivesoftware/smack/XMPPConnection.java index 365e9a792..de1cb4cde 100644 --- a/source/org/jivesoftware/smack/XMPPConnection.java +++ b/source/org/jivesoftware/smack/XMPPConnection.java @@ -464,6 +464,8 @@ protected void shutdown(Presence unavailablePresence) { public void disconnect(Presence unavailablePresence) { // If not connected, ignore this request. + PacketReader packetReader = this.packetReader; + PacketWrite packetWriter = this.packetWriter; if (packetReader == null || packetWriter == null) { return; } @@ -479,9 +481,9 @@ public void disconnect(Presence unavailablePresence) { wasAuthenticated = false; packetWriter.cleanup(); - packetWriter = null; + this.packetWriter = null; packetReader.cleanup(); - packetReader = null; + this.packetReader = null; } public void sendPacket(Packet packet) { From 131b8129b6a1b2c668daec0153e1acf751be0e29 Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Thu, 21 Apr 2011 21:37:09 +0600 Subject: [PATCH 10/33] Fix syntax error in last commit --- source/org/jivesoftware/smack/XMPPConnection.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/org/jivesoftware/smack/XMPPConnection.java b/source/org/jivesoftware/smack/XMPPConnection.java index de1cb4cde..c5501ecfc 100644 --- a/source/org/jivesoftware/smack/XMPPConnection.java +++ b/source/org/jivesoftware/smack/XMPPConnection.java @@ -465,7 +465,7 @@ protected void shutdown(Presence unavailablePresence) { public void disconnect(Presence unavailablePresence) { // If not connected, ignore this request. PacketReader packetReader = this.packetReader; - PacketWrite packetWriter = this.packetWriter; + PacketWriter packetWriter = this.packetWriter; if (packetReader == null || packetWriter == null) { return; } From 084a1813eb273491ecc9200af4255c66bf3ca1e0 Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Thu, 21 Apr 2011 21:51:05 +0600 Subject: [PATCH 11/33] Catch IllegalStateException in FileTransfer --- .../smackx/filetransfer/OutgoingFileTransfer.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source/org/jivesoftware/smackx/filetransfer/OutgoingFileTransfer.java b/source/org/jivesoftware/smackx/filetransfer/OutgoingFileTransfer.java index e0271d646..0bc1d770c 100644 --- a/source/org/jivesoftware/smackx/filetransfer/OutgoingFileTransfer.java +++ b/source/org/jivesoftware/smackx/filetransfer/OutgoingFileTransfer.java @@ -283,6 +283,9 @@ public void run() { } catch (XMPPException e) { handleXMPPException(e); return; + } catch (IllegalStateException e) { + setStatus(FileTransfer.Status.error); + setException(e); } if (outputStream == null) { return; @@ -296,6 +299,9 @@ public void run() { } catch (XMPPException e) { setStatus(FileTransfer.Status.error); setException(e); + } catch (IllegalStateException e) { + setStatus(FileTransfer.Status.error); + setException(e); } finally { try { if (in != null) { From 44cf74205c9b3c8d8d2ae361e24e31f2e5bc3902 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Tue, 26 Apr 2011 20:22:49 +0200 Subject: [PATCH 12/33] fix npe in xhtmlExtensionProvider --- .../jivesoftware/smackx/provider/XHTMLExtensionProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/org/jivesoftware/smackx/provider/XHTMLExtensionProvider.java b/source/org/jivesoftware/smackx/provider/XHTMLExtensionProvider.java index 4aebf52b0..50f437f15 100644 --- a/source/org/jivesoftware/smackx/provider/XHTMLExtensionProvider.java +++ b/source/org/jivesoftware/smackx/provider/XHTMLExtensionProvider.java @@ -81,7 +81,7 @@ else if (parser.getName().equals(xhtmlExtension.getElementName()) else { // This is a check for tags that are both a start and end tag like
// So that they aren't doubled - if(!lastTag.equals(parser.getText())) { + if(lastTag == null || !lastTag.equals(parser.getText())) { buffer.append(parser.getText()); } } From 6c51b12bbab70b8c9221ed2edf428a4f952d4045 Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Wed, 27 Apr 2011 19:37:00 +0600 Subject: [PATCH 13/33] Pubsub's affiliations fixed. --- build/resources/META-INF/smack.providers | 4 +-- .../smackx/pubsub/Affiliation.java | 16 ++++++------ .../smackx/pubsub/AffiliationsExtension.java | 26 +++++++++++++++++-- .../pubsub/provider/AffiliationProvider.java | 2 +- .../pubsub/provider/AffiliationsProvider.java | 2 +- 5 files changed, 36 insertions(+), 14 deletions(-) diff --git a/build/resources/META-INF/smack.providers b/build/resources/META-INF/smack.providers index 9f0f4f15a..ee4eec1d1 100644 --- a/build/resources/META-INF/smack.providers +++ b/build/resources/META-INF/smack.providers @@ -536,13 +536,13 @@ affiliations - http://jabber.org/protocol/pubsub + http://jabber.org/protocol/pubsub#owner org.jivesoftware.smackx.pubsub.provider.AffiliationsProvider affiliation - http://jabber.org/protocol/pubsub + http://jabber.org/protocol/pubsub#owner org.jivesoftware.smackx.pubsub.provider.AffiliationProvider diff --git a/source/org/jivesoftware/smackx/pubsub/Affiliation.java b/source/org/jivesoftware/smackx/pubsub/Affiliation.java index d0fc7dcf4..670714361 100644 --- a/source/org/jivesoftware/smackx/pubsub/Affiliation.java +++ b/source/org/jivesoftware/smackx/pubsub/Affiliation.java @@ -28,7 +28,7 @@ */ public class Affiliation implements PacketExtension { - protected String node; + protected String jid; protected Type type; public enum Type @@ -39,18 +39,18 @@ public enum Type /** * Constructs an affiliation. * - * @param nodeId The node the user is affiliated with. + * @param jid The JID with affiliation. * @param affiliation The type of affiliation. */ - public Affiliation(String nodeId, Type affiliation) + public Affiliation(String jid, Type affiliation) { - node = nodeId; + this.jid = jid; type = affiliation; } - public String getNodeId() + public String getJid() { - return node; + return jid; } public Type getType() @@ -60,7 +60,7 @@ public Type getType() public String getElementName() { - return "subscription"; + return "affiliation"; } public String getNamespace() @@ -72,7 +72,7 @@ public String toXML() { StringBuilder builder = new StringBuilder("<"); builder.append(getElementName()); - appendAttribute(builder, "node", node); + appendAttribute(builder, "jid", jid); appendAttribute(builder, "affiliation", type.toString()); builder.append("/>"); diff --git a/source/org/jivesoftware/smackx/pubsub/AffiliationsExtension.java b/source/org/jivesoftware/smackx/pubsub/AffiliationsExtension.java index aa82dcbab..563147eeb 100644 --- a/source/org/jivesoftware/smackx/pubsub/AffiliationsExtension.java +++ b/source/org/jivesoftware/smackx/pubsub/AffiliationsExtension.java @@ -31,10 +31,26 @@ public AffiliationsExtension() super(PubSubElementType.AFFILIATIONS); } - public AffiliationsExtension(List subList) + public AffiliationsExtension(List affiliationList) { super(PubSubElementType.AFFILIATIONS); - items = subList; + + if (affiliationList != null) + items = affiliationList; + } + + /** + * Affiliations for the specified node. + * + * @param nodeId + * @param subList + */ + public AffiliationsExtension(String nodeId, List affiliationList) + { + super(PubSubElementType.AFFILIATIONS, nodeId); + + if (affiliationList != null) + items = affiliationList; } public List getAffiliations() @@ -53,6 +69,12 @@ public String toXML() { StringBuilder builder = new StringBuilder("<"); builder.append(getElementName()); + if (getNode() != null) + { + builder.append(" node='"); + builder.append(getNode()); + builder.append("'"); + } builder.append(">"); for (Affiliation item : items) diff --git a/source/org/jivesoftware/smackx/pubsub/provider/AffiliationProvider.java b/source/org/jivesoftware/smackx/pubsub/provider/AffiliationProvider.java index 4e27c5075..bd0f74fef 100644 --- a/source/org/jivesoftware/smackx/pubsub/provider/AffiliationProvider.java +++ b/source/org/jivesoftware/smackx/pubsub/provider/AffiliationProvider.java @@ -31,7 +31,7 @@ public class AffiliationProvider extends EmbeddedExtensionProvider @Override protected PacketExtension createReturnExtension(String currentElement, String currentNamespace, Map attributeMap, List content) { - return new Affiliation(attributeMap.get("node"), Affiliation.Type.valueOf(attributeMap.get("affiliation"))); + return new Affiliation(attributeMap.get("jid"), Affiliation.Type.valueOf(attributeMap.get("affiliation"))); } } diff --git a/source/org/jivesoftware/smackx/pubsub/provider/AffiliationsProvider.java b/source/org/jivesoftware/smackx/pubsub/provider/AffiliationsProvider.java index 9bfeb8110..ee7af0520 100644 --- a/source/org/jivesoftware/smackx/pubsub/provider/AffiliationsProvider.java +++ b/source/org/jivesoftware/smackx/pubsub/provider/AffiliationsProvider.java @@ -32,7 +32,7 @@ @Override protected PacketExtension createReturnExtension(String currentElement, String currentNamespace, Map attributeMap, List content) { - return new AffiliationsExtension((List)content); + return new AffiliationsExtension(attributeMap.get("node"), (List)content); } } From 870299d0c030d31657c426be92990724836dc846 Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Wed, 27 Apr 2011 19:42:32 +0600 Subject: [PATCH 14/33] Incorrect caps calculation fix ("http://jabber.org/protocol/caps" was missed). --- .../jivesoftware/smackx/EntityCapsManager.java | 17 ++++++++--------- .../smackx/ServiceDiscoveryManager.java | 6 +++--- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/source/org/jivesoftware/smackx/EntityCapsManager.java b/source/org/jivesoftware/smackx/EntityCapsManager.java index b27dfd6a6..cff3dcb04 100644 --- a/source/org/jivesoftware/smackx/EntityCapsManager.java +++ b/source/org/jivesoftware/smackx/EntityCapsManager.java @@ -30,7 +30,9 @@ import org.jivesoftware.smackx.packet.DiscoverInfo; import org.jivesoftware.smackx.packet.CapsExtension; import org.jivesoftware.smackx.packet.DataForm; +import org.jivesoftware.smackx.packet.DiscoverInfo.Feature; +import java.util.ArrayList; import java.util.Comparator; import java.util.Iterator; import java.util.List; @@ -248,7 +250,7 @@ private static String formFieldValuesToCaps(Iterator i) { void calculateEntityCapsVersion(DiscoverInfo discoverInfo, String identityType, - String identityName, List features, + String identityName, DataForm extendedInfo) { String s = ""; @@ -257,15 +259,12 @@ void calculateEntityCapsVersion(DiscoverInfo discoverInfo, s += "client/" + identityType + "//" + identityName + "<"; // Add features - synchronized (features) { - SortedSet fs = new TreeSet(); - for (String f : features) { - fs.add(f); - } + SortedSet features = new TreeSet(); + for (Iterator it = discoverInfo.getFeatures(); it.hasNext();) + features.add(it.next().getVar()); - for (String f : fs) { - s += f + "<"; - } + for (String f : features) { + s += f + "<"; } if (extendedInfo != null) { diff --git a/source/org/jivesoftware/smackx/ServiceDiscoveryManager.java b/source/org/jivesoftware/smackx/ServiceDiscoveryManager.java index 94c768459..ecab4c51f 100644 --- a/source/org/jivesoftware/smackx/ServiceDiscoveryManager.java +++ b/source/org/jivesoftware/smackx/ServiceDiscoveryManager.java @@ -322,9 +322,9 @@ public void processPacket(Packet packet) { // Add the client's identity and features if "node" is // null or our entity caps version. if (discoverInfo.getNode() == null || - (capsManager == null? true : + capsManager == null || (capsManager.getNode() + "#" + - getEntityCapsVersion()).equals(discoverInfo.getNode()))) { + getEntityCapsVersion()).equals(discoverInfo.getNode())) { addDiscoverInfoTo(response); } else { @@ -748,7 +748,7 @@ private void renewEntityCapsVersion() { if (connection instanceof XMPPConnection) { if (capsManager != null) { capsManager.calculateEntityCapsVersion(getOwnDiscoverInfo(), - identityType, identityName, features, extendedInfo); + identityType, identityName, extendedInfo); //capsManager.notifyCapsVerListeners(); } } From 4ff597358f9d5ab5b0dcec14e251fb0013ff3286 Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Thu, 5 May 2011 17:51:41 +0600 Subject: [PATCH 15/33] Fix affiliation provider and packet extension to retrieve all affiliations. --- build/resources/META-INF/smack.providers | 12 +++++++++++ .../smackx/pubsub/Affiliation.java | 21 +++++++++++++++++++ .../pubsub/provider/AffiliationProvider.java | 2 +- 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/build/resources/META-INF/smack.providers b/build/resources/META-INF/smack.providers index ee4eec1d1..738e18070 100644 --- a/build/resources/META-INF/smack.providers +++ b/build/resources/META-INF/smack.providers @@ -534,6 +534,12 @@ org.jivesoftware.smackx.pubsub.provider.SubscriptionProvider + + affiliations + http://jabber.org/protocol/pubsub + org.jivesoftware.smackx.pubsub.provider.AffiliationsProvider + + affiliations http://jabber.org/protocol/pubsub#owner @@ -546,6 +552,12 @@ org.jivesoftware.smackx.pubsub.provider.AffiliationProvider + + affiliation + http://jabber.org/protocol/pubsub + org.jivesoftware.smackx.pubsub.provider.AffiliationProvider + + options http://jabber.org/protocol/pubsub diff --git a/source/org/jivesoftware/smackx/pubsub/Affiliation.java b/source/org/jivesoftware/smackx/pubsub/Affiliation.java index 670714361..d55534d51 100644 --- a/source/org/jivesoftware/smackx/pubsub/Affiliation.java +++ b/source/org/jivesoftware/smackx/pubsub/Affiliation.java @@ -29,6 +29,7 @@ public class Affiliation implements PacketExtension { protected String jid; + protected String node; protected Type type; public enum Type @@ -43,8 +44,21 @@ public enum Type * @param affiliation The type of affiliation. */ public Affiliation(String jid, Type affiliation) + { + this(jid, null, affiliation); + } + + /** + * Constructs an affiliation. + * + * @param jid The JID with affiliation. + * @param node The node with affiliation. + * @param affiliation The type of affiliation. + */ + public Affiliation(String jid, String node, Type affiliation) { this.jid = jid; + this.node = node; type = affiliation; } @@ -53,6 +67,11 @@ public String getJid() return jid; } + public String getNode() + { + return node; + } + public Type getType() { return type; @@ -72,6 +91,8 @@ public String toXML() { StringBuilder builder = new StringBuilder("<"); builder.append(getElementName()); + if (node != null) + appendAttribute(builder, "node", node); appendAttribute(builder, "jid", jid); appendAttribute(builder, "affiliation", type.toString()); diff --git a/source/org/jivesoftware/smackx/pubsub/provider/AffiliationProvider.java b/source/org/jivesoftware/smackx/pubsub/provider/AffiliationProvider.java index bd0f74fef..892eec6bf 100644 --- a/source/org/jivesoftware/smackx/pubsub/provider/AffiliationProvider.java +++ b/source/org/jivesoftware/smackx/pubsub/provider/AffiliationProvider.java @@ -31,7 +31,7 @@ public class AffiliationProvider extends EmbeddedExtensionProvider @Override protected PacketExtension createReturnExtension(String currentElement, String currentNamespace, Map attributeMap, List content) { - return new Affiliation(attributeMap.get("jid"), Affiliation.Type.valueOf(attributeMap.get("affiliation"))); + return new Affiliation(attributeMap.get("jid"), attributeMap.get("node"), Affiliation.Type.valueOf(attributeMap.get("affiliation"))); } } From b73cf20a668c0d01c2c9933e95ac443ab2c01034 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sun, 8 May 2011 21:13:19 +0200 Subject: [PATCH 16/33] merge with 3.2.0 --- .../jivesoftware/smack/AccountManager.java | 29 +++---- .../org/jivesoftware/smack/ChatManager.java | 37 +++++++-- source/org/jivesoftware/smack/Connection.java | 22 +++--- .../jivesoftware/smack/PacketCollector.java | 78 +++++++++++++++---- .../smack/ReconnectionManager.java | 22 ++++-- source/org/jivesoftware/smack/Roster.java | 12 +-- .../smack/SASLAuthentication.java | 10 +-- .../smack/SmackConfiguration.java | 2 +- .../jivesoftware/smack/XMPPConnection.java | 50 +++--------- .../smack/packet/PrivacyItem.java | 2 +- .../smack/packet/Registration.java | 11 ++- .../smack/util/PacketParserUtils.java | 22 +++--- .../jivesoftware/smack/util/StringUtils.java | 44 +++++++++++ .../smackx/MessageEventManager.java | 4 +- .../smackx/ServiceDiscoveryManager.java | 7 +- .../smackx/debugger/EnhancedDebugger.java | 22 +++++- .../org/jivesoftware/smackx/muc/RoomInfo.java | 20 +++-- .../jivesoftware/smackx/packet/DelayInfo.java | 6 +- .../smackx/packet/StreamInitiation.java | 4 +- .../provider/DelayInformationProvider.java | 3 +- .../provider/StreamInitiationProvider.java | 5 +- .../smackx/pubsub/ConfigureForm.java | 4 +- .../org/jivesoftware/smackx/pubsub/Item.java | 37 +++++++-- .../smackx/pubsub/PayloadItem.java | 44 +++++++++++ .../smackx/pubsub/PubSubElementType.java | 5 +- .../smackx/pubsub/PubSubManager.java | 4 +- .../smackx/pubsub/provider/ItemProvider.java | 7 +- .../smackx/workgroup/packet/QueueDetails.java | 25 +++--- .../workgroup/packet/QueueOverview.java | 10 ++- 29 files changed, 366 insertions(+), 182 deletions(-) diff --git a/source/org/jivesoftware/smack/AccountManager.java b/source/org/jivesoftware/smack/AccountManager.java index 840139b55..4d9faa591 100644 --- a/source/org/jivesoftware/smack/AccountManager.java +++ b/source/org/jivesoftware/smack/AccountManager.java @@ -131,10 +131,9 @@ public Collection getAccountAttributes() { if (info == null) { getRegistrationInfo(); } - List attributes = info.getRequiredFields(); - if (attributes.size()>0) { - HashSet set = new HashSet(attributes); - return Collections.unmodifiableSet(set); + Map attributes = info.getAttributes(); + if (attributes != null) { + return Collections.unmodifiableSet(attributes.keySet()); } } catch (XMPPException xe) { @@ -226,12 +225,10 @@ public void createAccount(String username, String password, Map } Registration reg = new Registration(); reg.setType(IQ.Type.SET); - reg.setTo(connection.getServiceName()); - for(String s : attributes.keySet()){ - reg.addAttribute(s, attributes.get(s)); - } - reg.setUsername(username); - reg.setPassword(password); + reg.setTo(connection.getServiceName()); + attributes.put("username",username); + attributes.put("password",password); + reg.setAttributes(attributes); PacketFilter filter = new AndFilter(new PacketIDFilter(reg.getPacketID()), new PacketTypeFilter(IQ.class)); PacketCollector collector = connection.createPacketCollector(filter); @@ -259,8 +256,10 @@ public void changePassword(String newPassword) throws XMPPException { Registration reg = new Registration(); reg.setType(IQ.Type.SET); reg.setTo(connection.getServiceName()); - reg.setUsername(StringUtils.parseName(connection.getUser())); - reg.setPassword(newPassword); + Map map = new HashMap(); + map.put("username",StringUtils.parseName(connection.getUser())); + map.put("password",newPassword); + reg.setAttributes(map); PacketFilter filter = new AndFilter(new PacketIDFilter(reg.getPacketID()), new PacketTypeFilter(IQ.class)); PacketCollector collector = connection.createPacketCollector(filter); @@ -291,8 +290,10 @@ public void deleteAccount() throws XMPPException { Registration reg = new Registration(); reg.setType(IQ.Type.SET); reg.setTo(connection.getServiceName()); - // To delete an account, we set remove to true - reg.setRemove(true); + Map attributes = new HashMap(); + // To delete an account, we add a single attribute, "remove", that is blank. + attributes.put("remove", ""); + reg.setAttributes(attributes); PacketFilter filter = new AndFilter(new PacketIDFilter(reg.getPacketID()), new PacketTypeFilter(IQ.class)); PacketCollector collector = connection.createPacketCollector(filter); diff --git a/source/org/jivesoftware/smack/ChatManager.java b/source/org/jivesoftware/smack/ChatManager.java index a893f4b4e..22dc3f9d5 100644 --- a/source/org/jivesoftware/smack/ChatManager.java +++ b/source/org/jivesoftware/smack/ChatManager.java @@ -20,6 +20,13 @@ package org.jivesoftware.smack; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.Set; +import java.util.WeakHashMap; +import java.util.concurrent.CopyOnWriteArraySet; + import org.jivesoftware.smack.filter.AndFilter; import org.jivesoftware.smack.filter.FromContainsFilter; import org.jivesoftware.smack.filter.PacketFilter; @@ -65,14 +72,20 @@ private static synchronized String nextID() { /** * Maps thread ID to chat. */ - private Map threadChats = new ReferenceMap(ReferenceMap.HARD, - ReferenceMap.WEAK); + private Map threadChats = Collections.synchronizedMap(new ReferenceMap(ReferenceMap.HARD, + ReferenceMap.WEAK)); /** * Maps jids to chats */ - private Map jidChats = new ReferenceMap(ReferenceMap.HARD, - ReferenceMap.WEAK); + private Map jidChats = Collections.synchronizedMap(new ReferenceMap(ReferenceMap.HARD, + ReferenceMap.WEAK)); + + /** + * Maps base jids to chats + */ + private Map baseJidChats = Collections.synchronizedMap(new ReferenceMap(ReferenceMap.HARD, + ReferenceMap.WEAK)); private Set chatManagerListeners = new CopyOnWriteArraySet(); @@ -161,6 +174,7 @@ private Chat createChat(String userJID, String threadID, boolean createdLocally) Chat chat = new Chat(this, userJID, threadID); threadChats.put(threadID, chat); jidChats.put(userJID, chat); + baseJidChats.put(StringUtils.parseBareAddress(userJID), chat); for(ChatManagerListener listener : chatManagerListeners) { listener.chatCreated(chat, createdLocally); @@ -179,8 +193,21 @@ private Chat createChat(Message message) { return createChat(userJID, threadID, false); } + /** + * Try to get a matching chat for the given user JID. Try the full + * JID map first, the try to match on the base JID if no match is + * found. + * + * @param userJID + * @return + */ private Chat getUserChat(String userJID) { - return jidChats.get(userJID); + Chat match = jidChats.get(userJID); + + if (match == null) { + match = baseJidChats.get(StringUtils.parseBareAddress(userJID)); + } + return match; } public Chat getThreadChat(String thread) { diff --git a/source/org/jivesoftware/smack/Connection.java b/source/org/jivesoftware/smack/Connection.java index a90282da9..0ce01e54d 100644 --- a/source/org/jivesoftware/smack/Connection.java +++ b/source/org/jivesoftware/smack/Connection.java @@ -332,9 +332,13 @@ protected boolean isReconnectionAllowed() { /** * Logs in to the server using the strongest authentication mode supported by - * the server, then sets presence to available. If more than five seconds - * (default timeout) elapses in each step of the authentication process without - * a response from the server, or if an error occurs, a XMPPException will be thrown.

+ * the server, then sets presence to available. If the server supports SASL authentication + * then the user will be authenticated using SASL if not Non-SASL authentication will + * be tried. If more than five seconds (default timeout) elapses in each step of the + * authentication process without a response from the server, or if an error occurs, a + * XMPPException will be thrown.

+ * + * Before logging in (i.e. authenticate) to the server the connection must be connected. * * It is possible to log in without sending an initial available presence by using * {@link ConnectionConfiguration#setSendPresence(boolean)}. If this connection is @@ -355,15 +359,13 @@ public void login(String username, String password) throws XMPPException { /** * Logs in to the server using the strongest authentication mode supported by - * the server. If the server supports SASL authentication then the user will be - * authenticated using SASL if not Non-SASL authentication will be tried. If more than - * five seconds (default timeout) elapses in each step of the authentication process - * without a response from the server, or if an error occurs, a XMPPException will be - * thrown.

+ * the server, then sets presence to available. If the server supports SASL authentication + * then the user will be authenticated using SASL if not Non-SASL authentication will + * be tried. If more than five seconds (default timeout) elapses in each step of the + * authentication process without a response from the server, or if an error occurs, a + * XMPPException will be thrown.

* * Before logging in (i.e. authenticate) to the server the connection must be connected. - * For compatibility and easiness of use the connection will automatically connect to the - * server if not already connected.

* * It is possible to log in without sending an initial available presence by using * {@link ConnectionConfiguration#setSendPresence(boolean)}. If this connection is diff --git a/source/org/jivesoftware/smack/PacketCollector.java b/source/org/jivesoftware/smack/PacketCollector.java index b4940af33..08c7caf6a 100644 --- a/source/org/jivesoftware/smack/PacketCollector.java +++ b/source/org/jivesoftware/smack/PacketCollector.java @@ -23,6 +23,7 @@ import org.jivesoftware.smack.filter.PacketFilter; import org.jivesoftware.smack.packet.Packet; +import java.util.LinkedList; import java.util.concurrent.TimeUnit; import java.util.concurrent.LinkedBlockingQueue; @@ -49,7 +50,7 @@ public class PacketCollector { private static final int MAX_PACKETS = 65536; private PacketFilter packetFilter; - private LinkedBlockingQueue resultQueue; + private LinkedList resultQueue; private Connection conection; private boolean cancelled = false; @@ -63,7 +64,7 @@ public class PacketCollector { protected PacketCollector(Connection conection, PacketFilter packetFilter) { this.conection = conection; this.packetFilter = packetFilter; - this.resultQueue = new LinkedBlockingQueue(MAX_PACKETS); + this.resultQueue = new LinkedList(); } /** @@ -74,8 +75,8 @@ protected PacketCollector(Connection conection, PacketFilter packetFilter) { public void cancel() { // If the packet collector has already been cancelled, do nothing. if (!cancelled) { - conection.removePacketCollector(this); cancelled = true; + conection.removePacketCollector(this); } } @@ -97,8 +98,13 @@ public PacketFilter getPacketFilter() { * @return the next packet result, or null if there are no more * results. */ - public Packet pollResult() { - return resultQueue.poll(); + public synchronized Packet pollResult() { + if (resultQueue.isEmpty()) { + return null; + } + else { + return resultQueue.removeLast(); + } } /** @@ -107,12 +113,17 @@ public Packet pollResult() { * * @return the next available packet. */ - public Packet nextResult() { - while (true) { + public synchronized Packet nextResult() { + // Wait indefinitely until there is a result to return. + while (resultQueue.isEmpty()) { try { - return resultQueue.take(); - } catch (InterruptedException e) { /* ignore */ } + wait(); + } + catch (InterruptedException ie) { + // Ignore. + } } + return resultQueue.removeLast(); } /** @@ -123,14 +134,40 @@ public Packet nextResult() { * @param timeout the amount of time to wait for the next packet (in milleseconds). * @return the next available packet. */ - public Packet nextResult(long timeout) { - long endTime = System.currentTimeMillis() + timeout; - do { + public synchronized Packet nextResult(long timeout) { + // Wait up to the specified amount of time for a result. + if (resultQueue.isEmpty()) { + long waitTime = timeout; + long start = System.currentTimeMillis(); try { - return resultQueue.poll(timeout, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { /* ignore */ } - } while (System.currentTimeMillis() < endTime); - return null; + // Keep waiting until the specified amount of time has elapsed, or + // a packet is available to return. + while (resultQueue.isEmpty()) { + if (waitTime <= 0) { + break; + } + wait(waitTime); + long now = System.currentTimeMillis(); + waitTime -= (now - start); + start = now; + } + } + catch (InterruptedException ie) { + // Ignore. + } + // Still haven't found a result, so return null. + if (resultQueue.isEmpty()) { + return null; + } + // Return the packet that was found. + else { + return resultQueue.removeLast(); + } + } + // There's already a packet waiting, so return it. + else { + return resultQueue.removeLast(); + } } /** @@ -144,7 +181,14 @@ protected synchronized void processPacket(Packet packet) { return; } if (packetFilter == null || packetFilter.accept(packet)) { - while (!resultQueue.offer(packet)) { resultQueue.poll(); } + // If the max number of packets has been reached, remove the oldest one. + if (resultQueue.size() == MAX_PACKETS) { + resultQueue.removeLast(); + } + // Add the new packet. + resultQueue.addFirst(packet); + // Notify waiting threads a result is available. + notifyAll(); } } } diff --git a/source/org/jivesoftware/smack/ReconnectionManager.java b/source/org/jivesoftware/smack/ReconnectionManager.java index b0119b8b2..514c8235e 100644 --- a/source/org/jivesoftware/smack/ReconnectionManager.java +++ b/source/org/jivesoftware/smack/ReconnectionManager.java @@ -1,7 +1,7 @@ package org.jivesoftware.smack; import org.jivesoftware.smack.packet.StreamError; - +import java.util.Random; /** * Handles the automatic reconnection process. Every time a connection is dropped without * the application explictly closing it, the manager automatically tries to reconnect to @@ -20,7 +20,9 @@ public class ReconnectionManager implements ConnectionListener { // Holds the connection to the server private Connection connection; - + private Thread reconnectionThread; + private int randomBase = new Random().nextInt(11) + 5; // between 5 and 15 seconds + // Holds the state of the reconnection boolean done = false; @@ -61,12 +63,15 @@ private boolean isReconnectionAllowed() { *

  • Finally it will try indefinitely every 5 minutes. * */ - protected void reconnect() { + synchronized protected void reconnect() { if (this.isReconnectionAllowed()) { // Since there is no thread running, creates a new one to attempt // the reconnection. - Thread reconnectionThread = new Thread() { - + // avoid to run duplicated reconnectionThread -- fd: 16/09/2010 + if (reconnectionThread!=null && reconnectionThread.isAlive()) return; + + reconnectionThread = new Thread() { + /** * Holds the current number of reconnection attempts */ @@ -78,13 +83,14 @@ protected void reconnect() { * @return the number of seconds until the next reconnection attempt. */ private int timeDelay() { + attempts++; if (attempts > 13) { - return 60 * 5; // 5 minutes + return randomBase*6*5; // between 2.5 and 7.5 minutes (~5 minutes) } if (attempts > 7) { - return 60; // 1 minute + return randomBase*6; // between 30 and 90 seconds (~1 minutes) } - return 10; // 10 seconds + return randomBase; // 10 seconds } /** diff --git a/source/org/jivesoftware/smack/Roster.java b/source/org/jivesoftware/smack/Roster.java index 914e08625..66a78b27d 100644 --- a/source/org/jivesoftware/smack/Roster.java +++ b/source/org/jivesoftware/smack/Roster.java @@ -479,7 +479,7 @@ else if (response.getType() == IQ.Type.ERROR) { * @return the number of entries in the roster. */ public int getEntryCount() { - return getEntries().size(); + return getEntries().size(); } /** @@ -532,7 +532,7 @@ public RosterEntry getEntry(String user) { if (user == null) { return null; } - return entries.get(user.toLowerCase()); + return entries.get(user.toLowerCase()); } /** @@ -555,7 +555,7 @@ public boolean contains(String user) { * @return the roster group with the specified name. */ public RosterGroup getGroup(String name) { - return groups.get(name); + return groups.get(name); } /** @@ -564,7 +564,7 @@ public RosterGroup getGroup(String name) { * @return the number of groups in the roster. */ public int getGroupCount() { - return groups.size(); + return groups.size(); } /** @@ -573,7 +573,7 @@ public int getGroupCount() { * @return an iterator for all roster groups. */ public Collection getGroups() { - return Collections.unmodifiableCollection(groups.values()); + return Collections.unmodifiableCollection(groups.values()); } /** @@ -1030,7 +1030,7 @@ public void processPacket(Packet packet) { rosterInitialized = true; Roster.this.notifyAll(); } - + // Fire event for roster listeners. fireRosterChangedEvent(addedEntries, updatedEntries, deletedEntries); } diff --git a/source/org/jivesoftware/smack/SASLAuthentication.java b/source/org/jivesoftware/smack/SASLAuthentication.java index c7fb7252e..807186e7c 100644 --- a/source/org/jivesoftware/smack/SASLAuthentication.java +++ b/source/org/jivesoftware/smack/SASLAuthentication.java @@ -238,10 +238,9 @@ public String authenticate(String username, String resource, CallbackHandler cbh // Wait until SASL negotiation finishes synchronized (this) { - long endTime = System.currentTimeMillis(); - while (!saslNegotiated && !saslFailed && (System.currentTimeMillis() < endTime)) { + if (!saslNegotiated && !saslFailed) { try { - wait(Math.abs(System.currentTimeMillis() - endTime)); + wait(30000); } catch (InterruptedException e) { // Ignore @@ -424,10 +423,9 @@ public String authenticateAnonymously() throws XMPPException { private String bindResourceAndEstablishSession(String resource) throws XMPPException { // Wait until server sends response containing the element synchronized (this) { - long endTime = System.currentTimeMillis() + 30000; - while (!resourceBinded && (System.currentTimeMillis() < endTime)) { + if (!resourceBinded) { try { - wait(Math.abs(System.currentTimeMillis() - endTime)); + wait(30000); } catch (InterruptedException e) { // Ignore diff --git a/source/org/jivesoftware/smack/SmackConfiguration.java b/source/org/jivesoftware/smack/SmackConfiguration.java index 86dc7f397..0e09d23f8 100644 --- a/source/org/jivesoftware/smack/SmackConfiguration.java +++ b/source/org/jivesoftware/smack/SmackConfiguration.java @@ -44,7 +44,7 @@ */ public final class SmackConfiguration { - private static final String SMACK_VERSION = "3.1.0"; + private static final String SMACK_VERSION = "3.2.0"; private static int packetReplyTimeout = 5000; private static int keepAliveInterval = 30000; diff --git a/source/org/jivesoftware/smack/XMPPConnection.java b/source/org/jivesoftware/smack/XMPPConnection.java index 361ca0aff..195b8ea3d 100644 --- a/source/org/jivesoftware/smack/XMPPConnection.java +++ b/source/org/jivesoftware/smack/XMPPConnection.java @@ -184,34 +184,7 @@ public String getUser() { return user; } - /** - * Logs in to the server using the strongest authentication mode supported by - * the server. If the server supports SASL authentication then the user will be - * authenticated using SASL if not Non-SASL authentication will be tried. If more than - * five seconds (default timeout) elapses in each step of the authentication process - * without a response from the server, or if an error occurs, a XMPPException will be - * thrown.

    - * - * Before logging in (i.e. authenticate) to the server the connection must be connected. - * For compatibility and easiness of use the connection will automatically connect to the - * server if not already connected.

    - * - * It is possible to log in without sending an initial available presence by using - * {@link ConnectionConfiguration#setSendPresence(boolean)}. If this connection is - * not interested in loading its roster upon login then use - * {@link ConnectionConfiguration#setRosterLoadedAtLogin(boolean)}. - * Finally, if you want to not pass a password and instead use a more advanced mechanism - * while using SASL then you may be interested in using - * {@link ConnectionConfiguration#setCallbackHandler(javax.security.auth.callback.CallbackHandler)}. - * For more advanced login settings see {@link ConnectionConfiguration}. - * - * @param username the username. - * @param password the password or null if using a CallbackHandler. - * @param resource the resource. - * @throws XMPPException if an error occurs. - * @throws IllegalStateException if not connected to the server, or already logged in - * to the server. - */ + @Override public synchronized void login(String username, String password, String resource) throws XMPPException { if (!isConnected()) { throw new IllegalStateException("Not connected to server."); @@ -291,16 +264,7 @@ public synchronized void login(String username, String password, String resource } } - /** - * Logs in to the server anonymously. Very few servers are configured to support anonymous - * authentication, so it's fairly likely logging in anonymously will fail. If anonymous login - * does succeed, your XMPP address will likely be in the form "server/123ABC" (where "123ABC" - * is a random value generated by the server). - * - * @throws XMPPException if an error occurs or anonymous logins are not supported by the server. - * @throws IllegalStateException if not connected to the server, or already logged in - * to the server. - */ + @Override public synchronized void loginAnonymously() throws XMPPException { if (!isConnected()) { throw new IllegalStateException("Not connected to server."); @@ -357,6 +321,10 @@ public Roster getRoster() { return roster; } } + + if (!config.isRosterLoadedAtLogin()) { + roster.reload(); + } // If this is the first time the user has asked for the roster after calling // login, we want to wait for the server to send back the user's roster. This // behavior shields API users from having to worry about the fact that roster @@ -414,7 +382,7 @@ public boolean isAnonymous() { */ protected void shutdown(Presence unavailablePresence) { // Set presence to offline. - if(packetWriter!=null){ + if (packetWriter!=null){ packetWriter.sendPacket(unavailablePresence); } @@ -422,10 +390,10 @@ protected void shutdown(Presence unavailablePresence) { authenticated = false; connected = false; - if(packetReader!=null){ + if (packetReader!=null){ packetReader.shutdown(); } - if(packetWriter!=null){ + if (packetWriter!=null){ packetWriter.shutdown(); } // Wait 150 ms for processes to clean-up, then shutdown. diff --git a/source/org/jivesoftware/smack/packet/PrivacyItem.java b/source/org/jivesoftware/smack/packet/PrivacyItem.java index 57767082e..78cb8db17 100644 --- a/source/org/jivesoftware/smack/packet/PrivacyItem.java +++ b/source/org/jivesoftware/smack/packet/PrivacyItem.java @@ -169,7 +169,7 @@ public int getOrder() { * * @param order indicates the order in the list. */ - private void setOrder(int order) { + public void setOrder(int order) { this.order = order; } diff --git a/source/org/jivesoftware/smack/packet/Registration.java b/source/org/jivesoftware/smack/packet/Registration.java index 30685867e..df22e27ed 100644 --- a/source/org/jivesoftware/smack/packet/Registration.java +++ b/source/org/jivesoftware/smack/packet/Registration.java @@ -84,9 +84,14 @@ public void setInstructions(String instructions) { public Map getAttributes() { return attributes; } - - public void addRequiredField(String field){ - requiredFields.add(field); + + /** + * Sets the account attributes. The map must only contain String key/value pairs. + * + * @param attributes the account attributes. + */ + public void setAttributes(Map attributes) { + this.attributes = attributes; } public List getRequiredFields(){ diff --git a/source/org/jivesoftware/smack/util/PacketParserUtils.java b/source/org/jivesoftware/smack/util/PacketParserUtils.java index 4452bd491..5f85b1e9e 100644 --- a/source/org/jivesoftware/smack/util/PacketParserUtils.java +++ b/source/org/jivesoftware/smack/util/PacketParserUtils.java @@ -432,6 +432,7 @@ else if (eventType == XmlPullParser.END_TAG) { private static Registration parseRegistration(XmlPullParser parser) throws Exception { Registration registration = new Registration(); + Map fields = null; boolean done = false; while (!done) { int eventType = parser.next(); @@ -441,21 +442,19 @@ private static Registration parseRegistration(XmlPullParser parser) throws Excep if (parser.getNamespace().equals("jabber:iq:register")) { String name = parser.getName(); String value = ""; - + if (fields == null) { + fields = new HashMap(); + } + if (parser.next() == XmlPullParser.TEXT) { value = parser.getText(); - if(name.equals("instructions")){ - registration.setInstructions(value); - } - else{ - registration.addAttribute(name, value); - } } - else if(name.equals("registered")){ - registration.setRegistered(true); + // Ignore instructions, but anything else should be added to the map. + if (!name.equals("instructions")) { + fields.put(name, value); } - else{ - registration.addRequiredField(name); + else { + registration.setInstructions(value); } } // Otherwise, it must be a packet extension. @@ -473,6 +472,7 @@ else if (eventType == XmlPullParser.END_TAG) { } } } + registration.setAttributes(fields); return registration; } diff --git a/source/org/jivesoftware/smack/util/StringUtils.java b/source/org/jivesoftware/smack/util/StringUtils.java index 628f4b57e..2c0bc3eec 100644 --- a/source/org/jivesoftware/smack/util/StringUtils.java +++ b/source/org/jivesoftware/smack/util/StringUtils.java @@ -23,19 +23,63 @@ import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; import java.util.Random; +import java.util.TimeZone; /** * A collection of utility methods for String objects. */ public class StringUtils { + /** + * Date format as defined in XEP-0082 - XMPP Date and Time Profiles. The time zone is set to + * UTC. + *

    + * Date formats are not synchronized. Since multiple threads access the format concurrently, it + * must be synchronized externally or you can use the convenience methods + * {@link #parseXEP0082Date(String)} and {@link #formatXEP0082Date(Date)}. + */ + public static final DateFormat XEP_0082_UTC_FORMAT = new SimpleDateFormat( + "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); + static { + XEP_0082_UTC_FORMAT.setTimeZone(TimeZone.getTimeZone("UTC")); + } + private static final char[] QUOTE_ENCODE = """.toCharArray(); private static final char[] APOS_ENCODE = "'".toCharArray(); private static final char[] AMP_ENCODE = "&".toCharArray(); private static final char[] LT_ENCODE = "<".toCharArray(); private static final char[] GT_ENCODE = ">".toCharArray(); + /** + * Parses the given date string in the XEP-0082 - XMPP Date and Time Profiles format. + * + * @param dateString the date string to parse + * @return the parsed Date + * @throws ParseException if the specified string cannot be parsed + */ + public static Date parseXEP0082Date(String dateString) throws ParseException { + synchronized (XEP_0082_UTC_FORMAT) { + return XEP_0082_UTC_FORMAT.parse(dateString); + } + } + + /** + * Formats a Date into a XEP-0082 - XMPP Date and Time Profiles string. + * + * @param date the time value to be formatted into a time string + * @return the formatted time string in XEP-0082 format + */ + public static String formatXEP0082Date(Date date) { + synchronized (XEP_0082_UTC_FORMAT) { + return XEP_0082_UTC_FORMAT.format(date); + } + } + /** * Returns the name portion of a XMPP address. For example, for the * address "matt@jivesoftware.com/Smack", "matt" would be returned. If no diff --git a/source/org/jivesoftware/smackx/MessageEventManager.java b/source/org/jivesoftware/smackx/MessageEventManager.java index edbb3676e..f8f553aac 100644 --- a/source/org/jivesoftware/smackx/MessageEventManager.java +++ b/source/org/jivesoftware/smackx/MessageEventManager.java @@ -54,7 +54,7 @@ public class MessageEventManager { /** * Creates a new message event manager. * - * @param con a Connection. + * @param con a Connection to a XMPP server. */ public MessageEventManager(Connection con) { this.con = con; @@ -307,4 +307,4 @@ protected void finalize() throws Throwable { destroy(); super.finalize(); } -} +} \ No newline at end of file diff --git a/source/org/jivesoftware/smackx/ServiceDiscoveryManager.java b/source/org/jivesoftware/smackx/ServiceDiscoveryManager.java index 94c768459..ec0844b9b 100644 --- a/source/org/jivesoftware/smackx/ServiceDiscoveryManager.java +++ b/source/org/jivesoftware/smackx/ServiceDiscoveryManager.java @@ -108,10 +108,10 @@ public ServiceDiscoveryManager(Connection connection) { } /** - * Returns the ServiceDiscoveryManager instance associated with a given connection. + * Returns the ServiceDiscoveryManager instance associated with a given Connection. * * @param connection the connection used to look for the proper ServiceDiscoveryManager. - * @return the ServiceDiscoveryManager associated with a given connection. + * @return the ServiceDiscoveryManager associated with a given Connection. */ public static ServiceDiscoveryManager getInstanceFor(Connection connection) { return instances.get(connection); @@ -596,7 +596,6 @@ public DiscoverInfo discoverInfo(String entityID, String node) throws XMPPExcept if (result.getType() == IQ.Type.ERROR) { throw new XMPPException(result.getError()); } - return (DiscoverInfo) result; } @@ -795,4 +794,4 @@ public void capsVerUpdated(String ver) { m.capsManager.spam(); } }*/ -} +} \ No newline at end of file diff --git a/source/org/jivesoftware/smackx/debugger/EnhancedDebugger.java b/source/org/jivesoftware/smackx/debugger/EnhancedDebugger.java index 8f490229a..1c7d8a55f 100644 --- a/source/org/jivesoftware/smackx/debugger/EnhancedDebugger.java +++ b/source/org/jivesoftware/smackx/debugger/EnhancedDebugger.java @@ -316,7 +316,27 @@ public void actionPerformed(ActionEvent e) { menu.add(menuItem1); // Add listener to the text area so the popup menu can come up. messageTextArea.addMouseListener(new PopupListener(menu)); - allPane.setBottomComponent(new JScrollPane(messageTextArea)); + JPanel sublayout = new JPanel(new BorderLayout()); + sublayout.add(new JScrollPane(messageTextArea), BorderLayout.CENTER); + + JButton clearb = new JButton("Clear All Packets"); + + clearb.addActionListener(new AbstractAction() { + private static final long serialVersionUID = -8576045822764763613L; + + @Override + public void actionPerformed(ActionEvent e) { + for(int i=0; i< messagesTable.getRowCount();i++) + { + messagesTable.removeRow(i); + } + + } + }); + + sublayout.add(clearb, BorderLayout.NORTH); + allPane.setBottomComponent(sublayout); + allPane.setDividerLocation(150); tabbedPane.add("All Packets", allPane); diff --git a/source/org/jivesoftware/smackx/muc/RoomInfo.java b/source/org/jivesoftware/smackx/muc/RoomInfo.java index 1e2c655b7..7a632cfa0 100644 --- a/source/org/jivesoftware/smackx/muc/RoomInfo.java +++ b/source/org/jivesoftware/smackx/muc/RoomInfo.java @@ -21,6 +21,7 @@ package org.jivesoftware.smackx.muc; import org.jivesoftware.smackx.Form; +import org.jivesoftware.smackx.FormField; import org.jivesoftware.smackx.packet.DiscoverInfo; import java.util.Iterator; @@ -88,17 +89,14 @@ public class RoomInfo { // Get the information based on the discovered extended information Form form = Form.getFormFrom(info); if (form != null) { - this.description = - form.getField("muc#roominfo_description").getValues().next(); - Iterator values = form.getField("muc#roominfo_subject").getValues(); - if (values.hasNext()) { - this.subject = values.next(); - } - else { - this.subject = ""; - } - this.occupantsCount = - Integer.parseInt(form.getField("muc#roominfo_occupants").getValues() + FormField descField = form.getField("muc#roominfo_description"); + this.description = descField == null ? "" : descField.getValues().next(); + + FormField subjField = form.getField("muc#roominfo_subject"); + this.subject = subjField == null ? "" : subjField.getValues().next(); + + FormField occCountField = form.getField("muc#roominfo_occupants"); + this.occupantsCount = occCountField == null ? -1 : Integer.parseInt(occCountField.getValues() .next()); } } diff --git a/source/org/jivesoftware/smackx/packet/DelayInfo.java b/source/org/jivesoftware/smackx/packet/DelayInfo.java index 15ce5aa0f..f40497140 100644 --- a/source/org/jivesoftware/smackx/packet/DelayInfo.java +++ b/source/org/jivesoftware/smackx/packet/DelayInfo.java @@ -15,7 +15,7 @@ import java.util.Date; -import org.jivesoftware.smack.packet.Packet; +import org.jivesoftware.smack.util.StringUtils; /** * A decorator for the {@link DelayInformation} class to transparently support @@ -89,9 +89,7 @@ public String toXML() { buf.append("<").append(getElementName()).append(" xmlns=\"").append(getNamespace()).append( "\""); buf.append(" stamp=\""); - synchronized (Packet.XEP_0082_UTC_FORMAT) { - buf.append(Packet.XEP_0082_UTC_FORMAT.format(getStamp())); - } + buf.append(StringUtils.formatXEP0082Date(getStamp())); buf.append("\""); if (getFrom() != null && getFrom().length() > 0) { buf.append(" from=\"").append(getFrom()).append("\""); diff --git a/source/org/jivesoftware/smackx/packet/StreamInitiation.java b/source/org/jivesoftware/smackx/packet/StreamInitiation.java index 1aa09f528..1659f1999 100644 --- a/source/org/jivesoftware/smackx/packet/StreamInitiation.java +++ b/source/org/jivesoftware/smackx/packet/StreamInitiation.java @@ -347,9 +347,7 @@ public String toXML() { } if (getDate() != null) { - synchronized (XEP_0082_UTC_FORMAT) { - buffer.append("date=\"").append(XEP_0082_UTC_FORMAT.format(date)).append("\" "); - } + buffer.append("date=\"").append(StringUtils.formatXEP0082Date(date)).append("\" "); } if (getHash() != null) { diff --git a/source/org/jivesoftware/smackx/provider/DelayInformationProvider.java b/source/org/jivesoftware/smackx/provider/DelayInformationProvider.java index b319ff0bb..5dc0ee77b 100644 --- a/source/org/jivesoftware/smackx/provider/DelayInformationProvider.java +++ b/source/org/jivesoftware/smackx/provider/DelayInformationProvider.java @@ -37,6 +37,7 @@ import org.jivesoftware.smack.packet.Packet; import org.jivesoftware.smack.packet.PacketExtension; import org.jivesoftware.smack.provider.PacketExtensionProvider; +import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smackx.packet.DelayInformation; import org.xmlpull.v1.XmlPullParser; @@ -73,7 +74,7 @@ public class DelayInformationProvider implements PacketExtensionProvider { private static Map formats = new HashMap(); static { formats.put("^\\d+T\\d+:\\d+:\\d+$", DelayInformation.XEP_0091_UTC_FORMAT); - formats.put("^\\d+-\\d+-\\d+T\\d+:\\d+:\\d+\\.\\d+Z$", Packet.XEP_0082_UTC_FORMAT); + formats.put("^\\d+-\\d+-\\d+T\\d+:\\d+:\\d+\\.\\d+Z$", StringUtils.XEP_0082_UTC_FORMAT); formats.put("^\\d+-\\d+-\\d+T\\d+:\\d+:\\d+Z$", XEP_0082_UTC_FORMAT_WITHOUT_MILLIS); } diff --git a/source/org/jivesoftware/smackx/provider/StreamInitiationProvider.java b/source/org/jivesoftware/smackx/provider/StreamInitiationProvider.java index 51b4d4181..eb0c66cf3 100644 --- a/source/org/jivesoftware/smackx/provider/StreamInitiationProvider.java +++ b/source/org/jivesoftware/smackx/provider/StreamInitiationProvider.java @@ -25,6 +25,7 @@ import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smack.packet.Packet; import org.jivesoftware.smack.provider.IQProvider; +import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smackx.packet.DataForm; import org.jivesoftware.smackx.packet.StreamInitiation; import org.jivesoftware.smackx.packet.StreamInitiation.File; @@ -97,9 +98,7 @@ public IQ parseIQ(final XmlPullParser parser) throws Exception { Date fileDate = new Date(); if (date != null) { try { - synchronized (Packet.XEP_0082_UTC_FORMAT) { - fileDate = Packet.XEP_0082_UTC_FORMAT.parse(date); - } + fileDate = StringUtils.parseXEP0082Date(date); } catch (ParseException e) { // couldn't parse date, use current date-time } diff --git a/source/org/jivesoftware/smackx/pubsub/ConfigureForm.java b/source/org/jivesoftware/smackx/pubsub/ConfigureForm.java index 2962c9bee..7f1005e87 100644 --- a/source/org/jivesoftware/smackx/pubsub/ConfigureForm.java +++ b/source/org/jivesoftware/smackx/pubsub/ConfigureForm.java @@ -161,7 +161,9 @@ public ChildrenAssociationPolicy getChildrenAssociationPolicy() public void setChildrenAssociationPolicy(ChildrenAssociationPolicy policy) { addField(ConfigureNodeFields.children_association_policy, FormField.TYPE_LIST_SINGLE); - setAnswer(ConfigureNodeFields.children_association_policy.getFieldName(), policy.toString()); + List values = new ArrayList(1); + values.add(policy.toString()); + setAnswer(ConfigureNodeFields.children_association_policy.getFieldName(), values); } /** diff --git a/source/org/jivesoftware/smackx/pubsub/Item.java b/source/org/jivesoftware/smackx/pubsub/Item.java index 9d627abfe..2ce0baac5 100644 --- a/source/org/jivesoftware/smackx/pubsub/Item.java +++ b/source/org/jivesoftware/smackx/pubsub/Item.java @@ -13,7 +13,7 @@ */ package org.jivesoftware.smackx.pubsub; -import org.jivesoftware.smack.packet.PacketExtension; +import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smackx.pubsub.provider.ItemProvider; /** @@ -39,7 +39,7 @@ * * @author Robin Collier */ -public class Item implements PacketExtension +public class Item extends NodeExtension { private String id; @@ -52,6 +52,7 @@ public class Item implements PacketExtension */ public Item() { + super(PubSubElementType.ITEM); } /** @@ -63,8 +64,27 @@ public Item() */ public Item(String itemId) { + // The element type is actually irrelevant since we override getNamespace() to return null + super(PubSubElementType.ITEM); id = itemId; } + + /** + * Create an Item with an id and a node id. + *

    + * Note: This is not valid for publishing an item to a node, only receiving from + * one as part of {@link Message}. If used to create an Item to publish + * (via {@link LeafNode#publish(Item)}, the server may return an + * error for an invalid packet. + * + * @param itemId The id of the item. + * @param nodeId The id of the node which the item was published to. + */ + public Item(String itemId, String nodeId) + { + super(PubSubElementType.ITEM_EVENT, nodeId); + id = itemId; + } /** * Get the item id. Unique to the node it is associated with. @@ -76,16 +96,13 @@ public String getId() return id; } - public String getElementName() - { - return "item"; - } - + @Override public String getNamespace() { return null; } + @Override public String toXML() { StringBuilder builder = new StringBuilder(""); return builder.toString(); diff --git a/source/org/jivesoftware/smackx/pubsub/PayloadItem.java b/source/org/jivesoftware/smackx/pubsub/PayloadItem.java index e147e6102..52e53f1f3 100644 --- a/source/org/jivesoftware/smackx/pubsub/PayloadItem.java +++ b/source/org/jivesoftware/smackx/pubsub/PayloadItem.java @@ -16,6 +16,8 @@ import org.jivesoftware.smack.packet.PacketExtension; import org.jivesoftware.smackx.pubsub.provider.ItemProvider; +import com.sun.corba.se.impl.protocol.giopmsgheaders.Message; + /** * This class represents an item that has been, or will be published to a * pubsub node. An Item has several properties that are dependent @@ -43,6 +45,20 @@ public class PayloadItem extends Item { private E payload; + /** + * Create an Item with no id and a payload The id will be set by the server. + * + * @param payloadExt A {@link PacketExtension} which represents the payload data. + */ + public PayloadItem(E payloadExt) + { + super(); + + if (payloadExt == null) + throw new IllegalArgumentException("payload cannot be 'null'"); + payload = payloadExt; + } + /** * Create an Item with an id and payload. * @@ -58,6 +74,28 @@ public PayloadItem(String itemId, E payloadExt) payload = payloadExt; } + /** + * Create an Item with an id, node id and payload. + * + *

    + * Note: This is not valid for publishing an item to a node, only receiving from + * one as part of {@link Message}. If used to create an Item to publish + * (via {@link LeafNode#publish(Item)}, the server may return an + * error for an invalid packet. + * + * @param itemId The id of this item. + * @param nodeId The id of the node the item was published to. + * @param payloadExt A {@link PacketExtension} which represents the payload data. + */ + public PayloadItem(String itemId, String nodeId, E payloadExt) + { + super(itemId, nodeId); + + if (payloadExt == null) + throw new IllegalArgumentException("payload cannot be 'null'"); + payload = payloadExt; + } + /** * Get the payload associated with this Item. Customising the payload * parsing from the server can be accomplished as described in {@link ItemProvider}. @@ -69,6 +107,7 @@ public E getPayload() return payload; } + @Override public String toXML() { StringBuilder builder = new StringBuilder(""); builder.append(payload.toXML()); builder.append(""); diff --git a/source/org/jivesoftware/smackx/pubsub/PubSubElementType.java b/source/org/jivesoftware/smackx/pubsub/PubSubElementType.java index 78fa9c193..a887ca2ba 100644 --- a/source/org/jivesoftware/smackx/pubsub/PubSubElementType.java +++ b/source/org/jivesoftware/smackx/pubsub/PubSubElementType.java @@ -32,6 +32,9 @@ public enum PubSubElementType OPTIONS("options", PubSubNamespace.BASIC), DEFAULT("default", PubSubNamespace.OWNER), ITEMS("items", PubSubNamespace.BASIC), + ITEMS_EVENT("items", PubSubNamespace.EVENT), + ITEM("item", PubSubNamespace.BASIC), + ITEM_EVENT("item", PubSubNamespace.EVENT), PUBLISH("publish", PubSubNamespace.BASIC), PUBLISH_OPTIONS("publish-options", PubSubNamespace.BASIC), PURGE_OWNER("purge", PubSubNamespace.OWNER), @@ -41,7 +44,7 @@ public enum PubSubElementType SUBSCRIBE("subscribe", PubSubNamespace.BASIC), SUBSCRIPTION("subscription", PubSubNamespace.BASIC), SUBSCRIPTIONS("subscriptions", PubSubNamespace.BASIC), - UNSUBSCRIBE("unsubscribe", PubSubNamespace.BASIC); + UNSUBSCRIBE("unsubscribe", PubSubNamespace.BASIC); private String eName; private PubSubNamespace nSpace; diff --git a/source/org/jivesoftware/smackx/pubsub/PubSubManager.java b/source/org/jivesoftware/smackx/pubsub/PubSubManager.java index 4e67b315e..e3eeae4b4 100644 --- a/source/org/jivesoftware/smackx/pubsub/PubSubManager.java +++ b/source/org/jivesoftware/smackx/pubsub/PubSubManager.java @@ -48,13 +48,15 @@ final public class PubSubManager private Map nodeMap = new ConcurrentHashMap(); /** - * Create a pubsub manager associated to the specified connection. + * Create a pubsub manager associated to the specified connection. Defaults the service + * name to pubsub * * @param connection The XMPP connection */ public PubSubManager(Connection connection) { con = connection; + to = "pubsub." + connection.getServiceName(); } /** diff --git a/source/org/jivesoftware/smackx/pubsub/provider/ItemProvider.java b/source/org/jivesoftware/smackx/pubsub/provider/ItemProvider.java index f8b59427e..aabd4cb2f 100644 --- a/source/org/jivesoftware/smackx/pubsub/provider/ItemProvider.java +++ b/source/org/jivesoftware/smackx/pubsub/provider/ItemProvider.java @@ -35,13 +35,14 @@ public class ItemProvider implements PacketExtensionProvider public PacketExtension parseExtension(XmlPullParser parser) throws Exception { String id = parser.getAttributeValue(null, "id"); + String node = parser.getAttributeValue(null, "node"); String elem = parser.getName(); int tag = parser.next(); if (tag == XmlPullParser.END_TAG) { - return new Item(id); + return new Item(id, node); } else { @@ -63,11 +64,11 @@ else if (!((tag == XmlPullParser.START_TAG) && parser.isEmptyElementTag())) if (!done) tag = parser.next(); } - return new PayloadItem(id, new SimplePayload(payloadElemName, payloadNS, payloadText.toString())); + return new PayloadItem(id, node, new SimplePayload(payloadElemName, payloadNS, payloadText.toString())); } else { - return new PayloadItem(id, PacketParserUtils.parsePacketExtension(payloadElemName, payloadNS, parser)); + return new PayloadItem(id, node, PacketParserUtils.parsePacketExtension(payloadElemName, payloadNS, parser)); } } } diff --git a/source/org/jivesoftware/smackx/workgroup/packet/QueueDetails.java b/source/org/jivesoftware/smackx/workgroup/packet/QueueDetails.java index f51c81fdb..ef11a789d 100644 --- a/source/org/jivesoftware/smackx/workgroup/packet/QueueDetails.java +++ b/source/org/jivesoftware/smackx/workgroup/packet/QueueDetails.java @@ -46,8 +46,9 @@ public class QueueDetails implements PacketExtension { */ public static final String NAMESPACE = "http://jabber.org/protocol/workgroup"; - private static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("yyyyMMdd'T'HH:mm:ss"); + private static final String DATE_FORMAT = "yyyyMMdd'T'HH:mm:ss"; + private SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT); /** * The list of users in the queue. */ @@ -124,7 +125,7 @@ public String toXML() { if (timestamp != null) { buf.append(""); - buf.append(DATE_FORMATTER.format(timestamp)); + buf.append(dateFormat.format(timestamp)); buf.append(""); } @@ -139,8 +140,10 @@ public String toXML() { * Provider class for QueueDetails packet extensions. */ public static class Provider implements PacketExtensionProvider { - + public PacketExtension parseExtension(XmlPullParser parser) throws Exception { + + SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT); QueueDetails queueDetails = new QueueDetails(); int eventType = parser.getEventType(); @@ -163,7 +166,7 @@ public PacketExtension parseExtension(XmlPullParser parser) throws Exception { eventType = parser.next(); while ((eventType != XmlPullParser.END_TAG) || (! "user".equals(parser.getName()))) - { + { if ("position".equals(parser.getName())) { position = Integer.parseInt(parser.nextText()); } @@ -171,23 +174,19 @@ else if ("time".equals(parser.getName())) { time = Integer.parseInt(parser.nextText()); } else if ("join-time".equals(parser.getName())) { - joinTime = DATE_FORMATTER.parse(parser.nextText()); + joinTime = dateFormat.parse(parser.nextText()); } else if( parser.getName().equals( "waitTime" ) ) { - Date wait = DATE_FORMATTER.parse( parser.nextText() ); - System.out.println( wait ); + Date wait = dateFormat.parse(parser.nextText()); + System.out.println( wait ); } - - - + eventType = parser.next(); if (eventType != XmlPullParser.END_TAG) { // throw exception } - } - - + } queueDetails.addUser(new QueueUser(uid, position, time, joinTime)); diff --git a/source/org/jivesoftware/smackx/workgroup/packet/QueueOverview.java b/source/org/jivesoftware/smackx/workgroup/packet/QueueOverview.java index ef44e9e01..a559579b4 100644 --- a/source/org/jivesoftware/smackx/workgroup/packet/QueueOverview.java +++ b/source/org/jivesoftware/smackx/workgroup/packet/QueueOverview.java @@ -39,7 +39,8 @@ public class QueueOverview implements PacketExtension { */ public static String NAMESPACE = "http://jabber.org/protocol/workgroup"; - private static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("yyyyMMdd'T'HH:mm:ss"); + private static final String DATE_FORMAT = "yyyyMMdd'T'HH:mm:ss"; + private SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT); private int averageWaitTime; private Date oldestEntry; @@ -101,7 +102,7 @@ public String toXML () { buf.append("").append(userCount).append(""); } if (oldestEntry != null) { - buf.append("").append(DATE_FORMATTER.format(oldestEntry)).append(""); + buf.append("").append(dateFormat.format(oldestEntry)).append(""); } if (averageWaitTime != -1) { buf.append(""); @@ -118,7 +119,8 @@ public static class Provider implements PacketExtensionProvider { public PacketExtension parseExtension (XmlPullParser parser) throws Exception { int eventType = parser.getEventType(); - QueueOverview queueOverview = new QueueOverview(); + QueueOverview queueOverview = new QueueOverview(); + SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT); if (eventType != XmlPullParser.START_TAG) { // throw exception @@ -135,7 +137,7 @@ else if ("time".equals(parser.getName())) { queueOverview.setAverageWaitTime(Integer.parseInt(parser.nextText())); } else if ("oldest".equals(parser.getName())) { - queueOverview.setOldestEntry((DATE_FORMATTER.parse(parser.nextText()))); + queueOverview.setOldestEntry((dateFormat.parse(parser.nextText()))); } else if ("status".equals(parser.getName())) { queueOverview.setStatus(WorkgroupQueue.Status.fromString(parser.nextText())); From 781031c6bfd154a0031ae6d6561419a1ecc484dc Mon Sep 17 00:00:00 2001 From: "holger.bergunde" Date: Mon, 23 May 2011 14:11:35 +0000 Subject: [PATCH 17/33] SMACK-338 this should use IBB as fallback protocol if available git-svn-id: http://svn.igniterealtime.org/svn/repos/smack/branches/smack_3_2_0@12409 b35dd754-fafc-0310-a699-88a17e54d16e --- .../smackx/filetransfer/FileTransferNegotiator.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/org/jivesoftware/smackx/filetransfer/FileTransferNegotiator.java b/source/org/jivesoftware/smackx/filetransfer/FileTransferNegotiator.java index 06ec67316..2d65cc7e4 100644 --- a/source/org/jivesoftware/smackx/filetransfer/FileTransferNegotiator.java +++ b/source/org/jivesoftware/smackx/filetransfer/FileTransferNegotiator.java @@ -324,7 +324,8 @@ else if (variable.equals(InBandBytestreamManager.NAMESPACE)) { throw new XMPPException(error.getMessage(), error); } - if (isByteStream && isIBB && field.getType().equals(FormField.TYPE_LIST_MULTI)) { + //if (isByteStream && isIBB && field.getType().equals(FormField.TYPE_LIST_MULTI)) { + if (isByteStream && isIBB) { return new FaultTolerantNegotiator(connection, byteStreamTransferManager, inbandTransferManager); From a282398167a77cd63a362d3e2cc2dc5286a30a83 Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Mon, 6 Jun 2011 12:23:51 +0600 Subject: [PATCH 18/33] Catch and log exceptions in Smack Listener Processor. --- source/org/jivesoftware/smack/PacketReader.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/source/org/jivesoftware/smack/PacketReader.java b/source/org/jivesoftware/smack/PacketReader.java index bc8d02e37..2dc3b27b7 100644 --- a/source/org/jivesoftware/smack/PacketReader.java +++ b/source/org/jivesoftware/smack/PacketReader.java @@ -460,7 +460,11 @@ public ListenerNotification(Packet packet) { public void run() { for (ListenerWrapper listenerWrapper : connection.recvListeners.values()) { - listenerWrapper.notifyListener(packet); + try { + listenerWrapper.notifyListener(packet); + } catch (RuntimeException e) { + e.printStackTrace(); + } } } } From 38cc176319a386e0d287561465c3ca80aa6b5ba7 Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Mon, 6 Jun 2011 12:40:36 +0600 Subject: [PATCH 19/33] Pubsub element can be inside the message stanza. --- build/resources/META-INF/smack.providers | 6 ++ .../smackx/pubsub/PubSubElement.java | 58 +++++++++++++++++++ .../provider/PubSubElementProvider.java | 33 +++++++++++ 3 files changed, 97 insertions(+) create mode 100644 source/org/jivesoftware/smackx/pubsub/PubSubElement.java create mode 100644 source/org/jivesoftware/smackx/pubsub/provider/PubSubElementProvider.java diff --git a/build/resources/META-INF/smack.providers b/build/resources/META-INF/smack.providers index 738e18070..b49129d9b 100644 --- a/build/resources/META-INF/smack.providers +++ b/build/resources/META-INF/smack.providers @@ -504,6 +504,12 @@ org.jivesoftware.smackx.pubsub.provider.PubSubProvider + + pubsub + http://jabber.org/protocol/pubsub + org.jivesoftware.smackx.pubsub.provider.PubSubElementProvider + + create http://jabber.org/protocol/pubsub diff --git a/source/org/jivesoftware/smackx/pubsub/PubSubElement.java b/source/org/jivesoftware/smackx/pubsub/PubSubElement.java new file mode 100644 index 000000000..55c38a777 --- /dev/null +++ b/source/org/jivesoftware/smackx/pubsub/PubSubElement.java @@ -0,0 +1,58 @@ +package org.jivesoftware.smackx.pubsub; + +import java.util.Collections; +import java.util.List; + +import org.jivesoftware.smack.packet.PacketExtension; +import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace; + +/** + * Represents the packet extension used in messages. + * The embedded event information, which is specific to the event type, + * can be retrieved by the {@link #getExtension()} method. + */ +public class PubSubElement implements EmbeddedPacketExtension +{ + private List extensions = Collections.emptyList(); + + public PubSubElement(List extensionList) + { + extensions = extensionList; + } + + public List getExtensions() + { + return extensions; + } + + public NodeExtension getExtension() + { + return (NodeExtension) extensions.get(0); + } + + public String getElementName() + { + return "pubsub"; + } + + public String getNamespace() + { + return PubSubNamespace.BASIC.getXmlns(); + } + + public String toXML() + { + StringBuilder builder = new StringBuilder(); + builder.append("<"); + builder.append(getElementName()); + builder.append(" xmlns='"); + builder.append(getNamespace()); + builder.append("'>"); + for (PacketExtension extension : extensions) + builder.append(extension.toXML()); + builder.append(""); + return builder.toString(); + } +} diff --git a/source/org/jivesoftware/smackx/pubsub/provider/PubSubElementProvider.java b/source/org/jivesoftware/smackx/pubsub/provider/PubSubElementProvider.java new file mode 100644 index 000000000..864936c3b --- /dev/null +++ b/source/org/jivesoftware/smackx/pubsub/provider/PubSubElementProvider.java @@ -0,0 +1,33 @@ +/** + * 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. + */ +package org.jivesoftware.smackx.pubsub.provider; + +import java.util.List; +import java.util.Map; + +import org.jivesoftware.smack.packet.PacketExtension; +import org.jivesoftware.smackx.provider.EmbeddedExtensionProvider; +import org.jivesoftware.smackx.pubsub.PubSubElement; + +/** + * Parses the pubsub element out of the message stanza from the server. + */ +public class PubSubElementProvider extends EmbeddedExtensionProvider +{ + @Override + protected PacketExtension createReturnExtension(String currentElement, String currentNamespace, Map attMap, List content) + { + return new PubSubElement((List)content); + } +} From c2b1a2f9610290f3318ae7906a4895ac40dfe517 Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Mon, 6 Jun 2011 12:43:58 +0600 Subject: [PATCH 20/33] Fix NullPointerException in initConnection. --- source/org/jivesoftware/smack/XMPPConnection.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/source/org/jivesoftware/smack/XMPPConnection.java b/source/org/jivesoftware/smack/XMPPConnection.java index c5501ecfc..8e1f919a5 100644 --- a/source/org/jivesoftware/smack/XMPPConnection.java +++ b/source/org/jivesoftware/smack/XMPPConnection.java @@ -580,6 +580,8 @@ private void connectUsingConfiguration(ConnectionConfiguration config) throws XM * @throws XMPPException if establishing a connection to the server fails. */ private void initConnection() throws XMPPException { + PacketReader packetReader = this.packetReader; + PacketWriter packetWriter = this.packetWriter; boolean isFirstInitialization = packetReader == null || packetWriter == null; usingCompression = false; @@ -588,8 +590,8 @@ private void initConnection() throws XMPPException { try { if (isFirstInitialization) { - packetWriter = new PacketWriter(this); - packetReader = new PacketReader(this); + this.packetWriter = packetWriter = new PacketWriter(this); + this.packetReader = packetReader = new PacketReader(this); // If debugging is enabled, we should start the thread that will listen for // all packets and then log them. @@ -638,14 +640,14 @@ else if (!wasAuthenticated) { packetWriter.shutdown(); } catch (Throwable ignore) { /* ignore */ } - packetWriter = null; + this.packetWriter = null; } if (packetReader != null) { try { packetReader.shutdown(); } catch (Throwable ignore) { /* ignore */ } - packetReader = null; + this.packetReader = null; } if (reader != null) { try { From b430676dc7f39794c50b2991059a8a8148e37ae5 Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Mon, 6 Jun 2011 12:56:59 +0600 Subject: [PATCH 21/33] Creating a thread and never starting it will cause a memory leak. --- .../smackx/commands/AdHocCommandManager.java | 81 +++++++++---------- 1 file changed, 40 insertions(+), 41 deletions(-) diff --git a/source/org/jivesoftware/smackx/commands/AdHocCommandManager.java b/source/org/jivesoftware/smackx/commands/AdHocCommandManager.java index c85db1da0..7496bf66f 100755 --- a/source/org/jivesoftware/smackx/commands/AdHocCommandManager.java +++ b/source/org/jivesoftware/smackx/commands/AdHocCommandManager.java @@ -333,46 +333,7 @@ public void processPacket(Packet packet) { PacketFilter filter = new PacketTypeFilter(AdHocCommandData.class); connection.addPacketListener(listener, filter); - // Create a thread to reap sessions. But, we'll only start it later when commands are - // actually registered. - sessionsSweeper = new Thread(new Runnable() { - public void run() { - while (true) { - for (String sessionId : executingCommands.keySet()) { - LocalCommand command = executingCommands.get(sessionId); - // Since the command could be removed in the meanwhile - // of getting the key and getting the value - by a - // processed packet. We must check if it still in the - // map. - if (command != null) { - long creationStamp = command.getCreationDate(); - // Check if the Session data has expired (default is - // 10 minutes) - // To remove it from the session list it waits for - // the double of the of time out time. This is to - // let - // the requester know why his execution request is - // not accepted. If the session is removed just - // after the time out, then whe the user request to - // continue the execution he will recieved an - // invalid session error and not a time out error. - if (System.currentTimeMillis() - creationStamp > SESSION_TIMEOUT * 1000 * 2) { - // Remove the expired session - executingCommands.remove(sessionId); - } - } - } - try { - Thread.sleep(1000); - } - catch (InterruptedException ie) { - // Ignore. - } - } - } - - }); - sessionsSweeper.setDaemon(true); + sessionsSweeper = null; } /** @@ -476,7 +437,45 @@ private void processAdHocCommand(AdHocCommandData requestData) { response.setStatus(Status.executing); executingCommands.put(sessionId, command); // See if the session reaping thread is started. If not, start it. - if (!sessionsSweeper.isAlive()) { + if (sessionsSweeper == null) { + sessionsSweeper = new Thread(new Runnable() { + public void run() { + while (true) { + for (String sessionId : executingCommands.keySet()) { + LocalCommand command = executingCommands.get(sessionId); + // Since the command could be removed in the meanwhile + // of getting the key and getting the value - by a + // processed packet. We must check if it still in the + // map. + if (command != null) { + long creationStamp = command.getCreationDate(); + // Check if the Session data has expired (default is + // 10 minutes) + // To remove it from the session list it waits for + // the double of the of time out time. This is to + // let + // the requester know why his execution request is + // not accepted. If the session is removed just + // after the time out, then whe the user request to + // continue the execution he will recieved an + // invalid session error and not a time out error. + if (System.currentTimeMillis() - creationStamp > SESSION_TIMEOUT * 1000 * 2) { + // Remove the expired session + executingCommands.remove(sessionId); + } + } + } + try { + Thread.sleep(1000); + } + catch (InterruptedException ie) { + // Ignore. + } + } + } + + }); + sessionsSweeper.setDaemon(true); sessionsSweeper.start(); } } From 44d445d84db9e36738f0158952a79026caa29931 Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Mon, 6 Jun 2011 13:00:09 +0600 Subject: [PATCH 22/33] Unregister connections on connectionClosedOnError. --- .../org/jivesoftware/smack/PrivacyListManager.java | 13 ++++++++----- .../smackx/ServiceDiscoveryManager.java | 13 ++++++++----- .../bytestreams/ibb/InBandBytestreamManager.java | 12 +++++++++++- .../bytestreams/socks5/Socks5BytestreamManager.java | 12 +++++++++++- 4 files changed, 38 insertions(+), 12 deletions(-) diff --git a/source/org/jivesoftware/smack/PrivacyListManager.java b/source/org/jivesoftware/smack/PrivacyListManager.java index eb1d231d2..c15f69cfc 100644 --- a/source/org/jivesoftware/smack/PrivacyListManager.java +++ b/source/org/jivesoftware/smack/PrivacyListManager.java @@ -95,18 +95,21 @@ public void connectionClosed() { } public void connectionClosedOnError(Exception e) { - // ignore + // Unregister this instance since the connection has been closed + instances.remove(connection); } - public void reconnectionFailed(Exception e) { - // ignore + public void reconnectionSuccessful() { + // Register this instance since the connection has been + // reestablished + instances.put(connection, PrivacyListManager.this); } - public void reconnectingIn(int seconds) { + public void reconnectionFailed(Exception e) { // ignore } - public void reconnectionSuccessful() { + public void reconnectingIn(int seconds) { // ignore } }); diff --git a/source/org/jivesoftware/smackx/ServiceDiscoveryManager.java b/source/org/jivesoftware/smackx/ServiceDiscoveryManager.java index ecab4c51f..9694da46a 100644 --- a/source/org/jivesoftware/smackx/ServiceDiscoveryManager.java +++ b/source/org/jivesoftware/smackx/ServiceDiscoveryManager.java @@ -238,18 +238,21 @@ public void connectionClosed() { } public void connectionClosedOnError(Exception e) { - // ignore + // Unregister this instance since the connection has been closed + instances.remove(connection); } - public void reconnectionFailed(Exception e) { - // ignore + public void reconnectionSuccessful() { + // Register this instance since the connection has been + // reestablished + instances.put(connection, ServiceDiscoveryManager.this); } - public void reconnectingIn(int seconds) { + public void reconnectionFailed(Exception e) { // ignore } - public void reconnectionSuccessful() { + public void reconnectingIn(int seconds) { // ignore } }); diff --git a/source/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamManager.java b/source/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamManager.java index 6c4e1b57a..b72a04840 100644 --- a/source/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamManager.java +++ b/source/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamManager.java @@ -95,7 +95,7 @@ public enum StanzaType { */ static { Connection.addConnectionCreationListener(new ConnectionCreationListener() { - public void connectionCreated(Connection connection) { + public void connectionCreated(final Connection connection) { final InBandBytestreamManager manager; manager = InBandBytestreamManager.getByteStreamManager(connection); @@ -106,6 +106,16 @@ public void connectionClosed() { manager.disableService(); } + public void connectionClosedOnError(Exception e) { + manager.disableService(); + } + + public void reconnectionSuccessful() { + // Register this instance since the connection has been + // reestablished + managers.put(connection, manager); + } + }); } diff --git a/source/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamManager.java b/source/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamManager.java index 5d4b50958..de9ab385d 100644 --- a/source/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamManager.java +++ b/source/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamManager.java @@ -89,7 +89,7 @@ public final class Socks5BytestreamManager implements BytestreamManager { static { Connection.addConnectionCreationListener(new ConnectionCreationListener() { - public void connectionCreated(Connection connection) { + public void connectionCreated(final Connection connection) { final Socks5BytestreamManager manager; manager = Socks5BytestreamManager.getBytestreamManager(connection); @@ -100,6 +100,16 @@ public void connectionClosed() { manager.disableService(); } + public void connectionClosedOnError(Exception e) { + manager.disableService(); + } + + public void reconnectionSuccessful() { + // Register this instance since the connection has been + // reestablished + managers.put(connection, manager); + } + }); } From fd2d5120a29832bccb8b4906a8f2833d5187433d Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Mon, 6 Jun 2011 13:31:17 +0600 Subject: [PATCH 23/33] Use weak references to connections from managers. --- .../smack/PrivacyListManager.java | 28 ++++++++++++---- .../smackx/ServiceDiscoveryManager.java | 29 ++++++++++++----- .../ibb/InBandBytestreamManager.java | 23 +++++++++---- .../socks5/Socks5BytestreamManager.java | 32 ++++++++++++------- .../smackx/commands/AdHocCommandManager.java | 30 ++++++++++++----- 5 files changed, 102 insertions(+), 40 deletions(-) mode change 100755 => 100644 source/org/jivesoftware/smackx/commands/AdHocCommandManager.java diff --git a/source/org/jivesoftware/smack/PrivacyListManager.java b/source/org/jivesoftware/smack/PrivacyListManager.java index c15f69cfc..a0e50768d 100644 --- a/source/org/jivesoftware/smack/PrivacyListManager.java +++ b/source/org/jivesoftware/smack/PrivacyListManager.java @@ -25,6 +25,7 @@ import org.jivesoftware.smack.packet.Privacy; import org.jivesoftware.smack.packet.PrivacyItem; +import java.lang.ref.WeakReference; import java.util.*; /** @@ -43,7 +44,8 @@ public class PrivacyListManager { // Keep the list of instances of this class. - private static Map instances = new Hashtable(); + private static Map> instances = + new WeakHashMap>(); private Connection connection; private final List listeners = new ArrayList(); @@ -85,24 +87,32 @@ private String getUser() { */ private void init() { // Register the new instance and associate it with the connection - instances.put(connection, this); + synchronized (PrivacyListManager.class) { + instances.put(connection, new WeakReference(this)); + } // Add a listener to the connection that removes the registered instance when // the connection is closed connection.addConnectionListener(new ConnectionListener() { public void connectionClosed() { // Unregister this instance since the connection has been closed - instances.remove(connection); + synchronized (PrivacyListManager.class) { + instances.remove(connection); + } } public void connectionClosedOnError(Exception e) { // Unregister this instance since the connection has been closed - instances.remove(connection); + synchronized (PrivacyListManager.class) { + instances.remove(connection); + } } public void reconnectionSuccessful() { // Register this instance since the connection has been // reestablished - instances.put(connection, PrivacyListManager.this); + synchronized (PrivacyListManager.class) { + instances.put(connection, new WeakReference(PrivacyListManager.this)); + } } public void reconnectionFailed(Exception e) { @@ -163,8 +173,12 @@ public String getChildElementXML() { * @param connection the connection used to look for the proper PrivacyListManager. * @return the PrivacyListManager associated with a given Connection. */ - public static PrivacyListManager getInstanceFor(Connection connection) { - return instances.get(connection); + public synchronized static PrivacyListManager getInstanceFor(Connection connection) { + WeakReference reference = instances.get(connection); + if (reference == null) + return null; + else + return reference.get(); } /** diff --git a/source/org/jivesoftware/smackx/ServiceDiscoveryManager.java b/source/org/jivesoftware/smackx/ServiceDiscoveryManager.java index 9694da46a..9c38f1a6e 100644 --- a/source/org/jivesoftware/smackx/ServiceDiscoveryManager.java +++ b/source/org/jivesoftware/smackx/ServiceDiscoveryManager.java @@ -35,6 +35,7 @@ import org.jivesoftware.smackx.packet.DataForm; import java.util.*; +import java.lang.ref.WeakReference; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.concurrent.ConcurrentHashMap; @@ -67,8 +68,8 @@ public class ServiceDiscoveryManager { private EntityCapsManager capsManager; - private static Map instances = - new ConcurrentHashMap(); + private static Map> instances = + new WeakHashMap>(); private Connection connection; private final List features = new ArrayList(); @@ -113,8 +114,12 @@ public ServiceDiscoveryManager(Connection connection) { * @param connection the connection used to look for the proper ServiceDiscoveryManager. * @return the ServiceDiscoveryManager associated with a given connection. */ - public static ServiceDiscoveryManager getInstanceFor(Connection connection) { - return instances.get(connection); + public synchronized static ServiceDiscoveryManager getInstanceFor(Connection connection) { + WeakReference reference = instances.get(connection); + if (reference == null) + return null; + else + return reference.get(); } /** @@ -228,24 +233,32 @@ public DiscoverInfo getOwnDiscoverInfo() { */ private void init() { // Register the new instance and associate it with the connection - instances.put(connection, this); + synchronized (ServiceDiscoveryManager.class) { + instances.put(connection, new WeakReference(this)); + } // Add a listener to the connection that removes the registered instance when // the connection is closed connection.addConnectionListener(new ConnectionListener() { public void connectionClosed() { // Unregister this instance since the connection has been closed - instances.remove(connection); + synchronized (ServiceDiscoveryManager.class) { + instances.remove(connection); + } } public void connectionClosedOnError(Exception e) { // Unregister this instance since the connection has been closed - instances.remove(connection); + synchronized (ServiceDiscoveryManager.class) { + instances.remove(connection); + } } public void reconnectionSuccessful() { // Register this instance since the connection has been // reestablished - instances.put(connection, ServiceDiscoveryManager.this); + synchronized (ServiceDiscoveryManager.class) { + instances.put(connection, new WeakReference(ServiceDiscoveryManager.this)); + } } public void reconnectionFailed(Exception e) { diff --git a/source/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamManager.java b/source/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamManager.java index b72a04840..e3cfdd0ed 100644 --- a/source/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamManager.java +++ b/source/org/jivesoftware/smackx/bytestreams/ibb/InBandBytestreamManager.java @@ -13,12 +13,13 @@ */ package org.jivesoftware.smackx.bytestreams.ibb; +import java.lang.ref.WeakReference; import java.util.Collections; -import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Random; +import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; import org.jivesoftware.smack.AbstractConnectionListener; @@ -113,7 +114,9 @@ public void connectionClosedOnError(Exception e) { public void reconnectionSuccessful() { // Register this instance since the connection has been // reestablished - managers.put(connection, manager); + synchronized (InBandBytestreamManager.class) { + managers.put(connection, new WeakReference(manager)); + } } }); @@ -139,7 +142,8 @@ public void reconnectionSuccessful() { private final static Random randomGenerator = new Random(); /* stores one InBandBytestreamManager for each XMPP connection */ - private final static Map managers = new HashMap(); + private final static Map> managers = + new WeakHashMap>(); /* XMPP connection */ private final Connection connection; @@ -193,10 +197,15 @@ public void reconnectionSuccessful() { public static synchronized InBandBytestreamManager getByteStreamManager(Connection connection) { if (connection == null) return null; - InBandBytestreamManager manager = managers.get(connection); + WeakReference reference = managers.get(connection); + InBandBytestreamManager manager; + if (reference == null) + manager = null; + else + manager = reference.get(); if (manager == null) { manager = new InBandBytestreamManager(connection); - managers.put(connection, manager); + managers.put(connection, new WeakReference(manager)); } return manager; } @@ -535,7 +544,9 @@ protected List getIgnoredBytestreamRequests() { private void disableService() { // remove manager from static managers map - managers.remove(connection); + synchronized (InBandBytestreamManager.class) { + managers.remove(connection); + } // remove all listeners registered by this manager this.connection.removePacketListener(this.initiationListener); diff --git a/source/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamManager.java b/source/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamManager.java index de9ab385d..66c4c5612 100644 --- a/source/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamManager.java +++ b/source/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamManager.java @@ -14,15 +14,16 @@ package org.jivesoftware.smackx.bytestreams.socks5; import java.io.IOException; +import java.lang.ref.WeakReference; import java.net.Socket; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Random; +import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeoutException; @@ -107,7 +108,9 @@ public void connectionClosedOnError(Exception e) { public void reconnectionSuccessful() { // Register this instance since the connection has been // reestablished - managers.put(connection, manager); + synchronized (Socks5BytestreamManager.class) { + managers.put(connection, new WeakReference(manager)); + } } }); @@ -128,7 +131,8 @@ public void reconnectionSuccessful() { private final static Random randomGenerator = new Random(); /* stores one Socks5BytestreamManager for each XMPP connection */ - private final static Map managers = new HashMap(); + private final static Map> managers = + new WeakHashMap>(); /* XMPP connection */ private final Connection connection; @@ -183,10 +187,15 @@ public static synchronized Socks5BytestreamManager getBytestreamManager(Connecti if (connection == null) { return null; } - Socks5BytestreamManager manager = managers.get(connection); + WeakReference reference = managers.get(connection); + Socks5BytestreamManager manager; + if (reference == null) + manager = null; + else + manager = reference.get(); if (manager == null) { manager = new Socks5BytestreamManager(connection); - managers.put(connection, manager); + managers.put(connection, new WeakReference(manager)); manager.activate(); } return manager; @@ -300,12 +309,13 @@ public synchronized void disableService() { this.proxyBlacklist.clear(); this.ignoredBytestreamRequests.clear(); - // remove manager from static managers map - managers.remove(this.connection); - - // shutdown local SOCKS5 proxy if there are no more managers for other connections - if (managers.size() == 0) { - Socks5Proxy.getSocks5Proxy().stop(); + synchronized (Socks5BytestreamManager.class) { + // remove manager from static managers map + managers.remove(this.connection); + // shutdown local SOCKS5 proxy if there are no more managers for other connections + if (managers.size() == 0) { + Socks5Proxy.getSocks5Proxy().stop(); + } } // remove feature from service discovery diff --git a/source/org/jivesoftware/smackx/commands/AdHocCommandManager.java b/source/org/jivesoftware/smackx/commands/AdHocCommandManager.java old mode 100755 new mode 100644 index 7496bf66f..f611cb3d2 --- a/source/org/jivesoftware/smackx/commands/AdHocCommandManager.java +++ b/source/org/jivesoftware/smackx/commands/AdHocCommandManager.java @@ -37,10 +37,12 @@ import org.jivesoftware.smackx.packet.DiscoverInfo.Identity; import org.jivesoftware.smackx.packet.DiscoverItems; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; /** @@ -68,8 +70,8 @@ public class AdHocCommandManager { * Map a Connection with it AdHocCommandManager. This map have a key-value * pair for every active connection. */ - private static Map instances = - new ConcurrentHashMap(); + private static Map> instances = + new WeakHashMap>(); /** * Register the listener for all the connection creations. When a new @@ -91,8 +93,12 @@ public void connectionCreated(Connection connection) { * @param connection the XMPP connection. * @return the AdHocCommandManager associated with the connection. */ - public static AdHocCommandManager getAddHocCommandsManager(Connection connection) { - return instances.get(connection); + public synchronized static AdHocCommandManager getAddHocCommandsManager(Connection connection) { + WeakReference reference = instances.get(connection); + if (reference == null) + return null; + else + return reference.get(); } /** @@ -253,25 +259,33 @@ public RemoteCommand getRemoteCommand(String jid, String node) { */ private void init() { // Register the new instance and associate it with the connection - instances.put(connection, this); + synchronized (AdHocCommandManager.this) { + instances.put(connection, new WeakReference(this)); + } // Add a listener to the connection that removes the registered instance // when the connection is closed connection.addConnectionListener(new ConnectionListener() { public void connectionClosed() { // Unregister this instance since the connection has been closed - instances.remove(connection); + synchronized (AdHocCommandManager.this) { + instances.remove(connection); + } } public void connectionClosedOnError(Exception e) { // Unregister this instance since the connection has been closed - instances.remove(connection); + synchronized (AdHocCommandManager.this) { + instances.remove(connection); + } } public void reconnectionSuccessful() { // Register this instance since the connection has been // reestablished - instances.put(connection, AdHocCommandManager.this); + synchronized (AdHocCommandManager.this) { + instances.put(connection, new WeakReference(AdHocCommandManager.this)); + } } public void reconnectingIn(int seconds) { From f1e889aae273d96b3e8cfa3bb9366aed834adfcf Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Mon, 6 Jun 2011 13:32:50 +0600 Subject: [PATCH 24/33] Allow to add connection listener before connection was established. --- source/org/jivesoftware/smack/Connection.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/source/org/jivesoftware/smack/Connection.java b/source/org/jivesoftware/smack/Connection.java index 7cf6b81ea..80a834f1d 100644 --- a/source/org/jivesoftware/smack/Connection.java +++ b/source/org/jivesoftware/smack/Connection.java @@ -529,6 +529,7 @@ protected static Collection getConnectionCreationLis * * @param connectionListener a connection listener. */ + @Deprecated public void addConnectionListener(ConnectionListener connectionListener) { if (!isConnected()) { throw new IllegalStateException("Not connected to server."); @@ -541,6 +542,21 @@ public void addConnectionListener(ConnectionListener connectionListener) { } } + /** + * Adds a connection listener to this connection that will be notified when + * the connection closes or fails. + * + * @param connectionListener a connection listener. + */ + public void forceAddConnectionListener(ConnectionListener connectionListener) { + if (connectionListener == null) { + return; + } + if (!connectionListeners.contains(connectionListener)) { + connectionListeners.add(connectionListener); + } + } + /** * Removes a connection listener from this connection. * From 31c700d2b465e7d1d89082cd55f713da08309075 Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Mon, 6 Jun 2011 13:36:08 +0600 Subject: [PATCH 25/33] Don't register connection creation listener from roster. --- source/org/jivesoftware/smack/Roster.java | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/source/org/jivesoftware/smack/Roster.java b/source/org/jivesoftware/smack/Roster.java index 914e08625..689ad5567 100644 --- a/source/org/jivesoftware/smack/Roster.java +++ b/source/org/jivesoftware/smack/Roster.java @@ -139,20 +139,7 @@ public void connectionClosedOnError(Exception e) { }; - // if not connected add listener after successful login - if(!this.connection.isConnected()) { - Connection.addConnectionCreationListener(new ConnectionCreationListener() { - - public void connectionCreated(Connection connection) { - if(connection.equals(Roster.this.connection)) { - Roster.this.connection.addConnectionListener(connectionListener); - } - - } - }); - } else { - connection.addConnectionListener(connectionListener); - } + connection.forceAddConnectionListener(connectionListener); } /** From 6d812b4af9cc2cafc4d6e0d9e2c1b6b9dd802e3c Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Mon, 6 Jun 2011 13:37:05 +0600 Subject: [PATCH 26/33] Cache key store. --- .../smack/ServerTrustManager.java | 117 +++++++++++++++--- 1 file changed, 97 insertions(+), 20 deletions(-) diff --git a/source/org/jivesoftware/smack/ServerTrustManager.java b/source/org/jivesoftware/smack/ServerTrustManager.java index a54d0fcf9..cabcd2ca0 100644 --- a/source/org/jivesoftware/smack/ServerTrustManager.java +++ b/source/org/jivesoftware/smack/ServerTrustManager.java @@ -29,6 +29,7 @@ import java.security.cert.CertificateParsingException; import java.security.cert.X509Certificate; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -51,32 +52,45 @@ class ServerTrustManager implements X509TrustManager { */ private String server; private KeyStore trustStore; + + private static Map stores = new HashMap(); public ServerTrustManager(String server, ConnectionConfiguration configuration) { this.configuration = configuration; this.server = server; InputStream in = null; - try { - trustStore = KeyStore.getInstance(configuration.getTruststoreType()); - in = new FileInputStream(configuration.getTruststorePath()); - trustStore.load(in, configuration.getTruststorePassword().toCharArray()); - } - catch (Exception e) { - e.printStackTrace(); - // Disable root CA checking - configuration.setVerifyRootCAEnabled(false); - } - finally { - if (in != null) { - try { - in.close(); - } - catch (IOException ioe) { - // Ignore. - } - } - } + synchronized (stores) { + KeyStoreOptions options = new KeyStoreOptions(configuration.getTruststoreType(), + configuration.getTruststorePath(), configuration.getTruststorePassword()); + if (stores.containsKey(options)) { + trustStore = stores.get(options); + } else { + try { + trustStore = KeyStore.getInstance(options.getType()); + in = new FileInputStream(options.getPath()); + trustStore.load(in, options.getPassword().toCharArray()); + } + catch (Exception e) { + trustStore = null; + e.printStackTrace(); + } + finally { + if (in != null) { + try { + in.close(); + } + catch (IOException ioe) { + // Ignore. + } + } + } + stores.put(options, trustStore); + } + if (trustStore == null) + // Disable root CA checking + configuration.setVerifyRootCAEnabled(false); + } } public X509Certificate[] getAcceptedIssuers() { @@ -256,4 +270,67 @@ private static List getSubjectAlternativeNames(X509Certificate certifica return identities; } + private static class KeyStoreOptions { + private final String type; + private final String path; + private final String password; + + public KeyStoreOptions(String type, String path, String password) { + super(); + this.type = type; + this.path = path; + this.password = password; + } + + public String getType() { + return type; + } + + public String getPath() { + return path; + } + + public String getPassword() { + return password; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + + ((password == null) ? 0 : password.hashCode()); + result = prime * result + ((path == null) ? 0 : path.hashCode()); + result = prime * result + ((type == null) ? 0 : type.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + KeyStoreOptions other = (KeyStoreOptions) obj; + if (password == null) { + if (other.password != null) + return false; + } else if (!password.equals(other.password)) + return false; + if (path == null) { + if (other.path != null) + return false; + } else if (!path.equals(other.path)) + return false; + if (type == null) { + if (other.type != null) + return false; + } else if (!type.equals(other.type)) + return false; + return true; + } + } + } From f579c5c8c84d9773e0734a1a717bde60fd5a95ab Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Mon, 6 Jun 2011 17:59:47 +0600 Subject: [PATCH 27/33] Subscription element can be inside http://jabber.org/protocol/pubsub#event namespace. --- build/resources/META-INF/smack.providers | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/build/resources/META-INF/smack.providers b/build/resources/META-INF/smack.providers index b49129d9b..e7a68eb24 100644 --- a/build/resources/META-INF/smack.providers +++ b/build/resources/META-INF/smack.providers @@ -540,6 +540,12 @@ org.jivesoftware.smackx.pubsub.provider.SubscriptionProvider + + subscription + http://jabber.org/protocol/pubsub#event + org.jivesoftware.smackx.pubsub.provider.SubscriptionProvider + + affiliations http://jabber.org/protocol/pubsub From bceed8aff5fdc9a518d7f111ef37a9a68a042907 Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Mon, 6 Jun 2011 21:24:25 +0600 Subject: [PATCH 28/33] Some extra changes from smack 3.2.0. --- build/build.xml | 14 +- build/resources/releasedocs/changelog.html | 60 +++- documentation/messaging.html | 34 ++ .../smackx/jingle/nat/STUNResolver.java | 23 +- .../smack/ChatConnectionTest.java | 291 ++++++++++++++++++ .../smack/ThreadedDummyConnection.java | 77 +++++ .../smack/filters/FromMatchesFilterTest.java | 92 ++++++ .../smack/packet/MessageTest.java | 3 + .../smack/util/PacketParserUtilsTest.java | 3 +- .../FileTransferNegotiatorTest.java | 41 +++ .../jivesoftware/smackx/muc/RoomInfoTest.java | 50 +++ .../smackx/pubsub/ConfigureFormTest.java | 16 + .../smackx/pubsub/ItemValidationTest.java | 107 +++++++ .../smackx/packet/XHTMLExtensionTest.java | 255 +++++++-------- 14 files changed, 916 insertions(+), 150 deletions(-) create mode 100644 test-unit/org/jivesoftware/smack/ChatConnectionTest.java create mode 100644 test-unit/org/jivesoftware/smack/ThreadedDummyConnection.java create mode 100644 test-unit/org/jivesoftware/smack/filters/FromMatchesFilterTest.java create mode 100644 test-unit/org/jivesoftware/smackx/filetransfer/FileTransferNegotiatorTest.java create mode 100644 test-unit/org/jivesoftware/smackx/muc/RoomInfoTest.java create mode 100644 test-unit/org/jivesoftware/smackx/pubsub/ConfigureFormTest.java create mode 100644 test-unit/org/jivesoftware/smackx/pubsub/ItemValidationTest.java diff --git a/build/build.xml b/build/build.xml index 804190014..0f35dc027 100644 --- a/build/build.xml +++ b/build/build.xml @@ -26,7 +26,7 @@ - + @@ -98,8 +98,8 @@ destdir="${compile.dir}" includeAntRuntime="no" debug="on" - source="1.5" - target="1.5" + source="1.6" + target="1.6" > @@ -113,8 +113,8 @@ destdir="${compile.dir}/jingle/extension" includeAntRuntime="no" debug="on" - source="1.5" - target="1.5" + source="1.6" + target="1.6" > @@ -141,8 +141,8 @@ destdir="${compile.test.dir}" includeAntRuntime="no" debug="on" - source="1.5" - target="1.5" + source="1.6" + target="1.6" > diff --git a/build/resources/releasedocs/changelog.html b/build/resources/releasedocs/changelog.html index c169cec75..13e9500a8 100644 --- a/build/resources/releasedocs/changelog.html +++ b/build/resources/releasedocs/changelog.html @@ -140,7 +140,65 @@

    Smack Changelog

    + +

    3.2.0 -- May 3, 2011

    +

    New Feature

    +
      +
    • [SMACK-272] - Add support for pubsub (XEP-0060)
    • +
    • [SMACK-296] - Add support for XEP-0224: Attention
    • +
    • [SMACK-319] - Add common interfaces for SOCKS5 Bytestreams and In-Band Bytestreams
    • +
    +

    Improvement

    +
      +
    • [SMACK-137] - File Transfer Settings
    • +
    • [SMACK-156] - Add the ability to register for roster events before logging in
    • +
    • [SMACK-261] - Minor Jingle cleanup to better support Jingle in Spark
    • +
    • [SMACK-277] - Update XMLUnit to the latest version
    • +
    • [SMACK-282] - Support SASL-related error conditions.
    • +
    • [SMACK-283] - Investigate why Jingle is connecting to stun.xten.net
    • +
    • [SMACK-285] - Add support for Nicks
    • +
    • [SMACK-289] - There is no way of retrieving items from a pubsub node when the user has multiple subscriptions.
    • +
    • [SMACK-294] - Handle empty roster groups and no goups in the same way
    • +
    • [SMACK-295] - Fire reconnectionSuccessful event when session is established
    • +
    • [SMACK-297] - add configuration for local Socks5 proxy
    • +
    • [SMACK-298] - Respond to all incoming Socks5 bytestream requests
    • +
    • [SMACK-299] - Improve accepting of Socks5 bytestream requests
    • +
    • [SMACK-300] - improve local Socks5 proxy implemetation
    • +
    • [SMACK-301] - support for bytestream packets to query Socks5 proxy for network address
    • +
    • [SMACK-302] - Improve establishing of Socks5 bytestreams
    • +
    • [SMACK-303] - integrate of the extracted Socks5 bytestream API in file transfer API
    • +
    • [SMACK-304] - Extend the IQ API to create empty IQ results and IQ error response packets
    • +
    • [SMACK-307] - Improve Message Parser Robustness and Message Body I18N
    • +
    • [SMACK-309] - Fully implement XEP-0047 In-Band Bytestreams
    • +
    • [SMACK-310] - Add Support for Localized Message Subjects
    • +
    + +

    Bug

    +
      +
    • [SMACK-163] - Fix NPE in RoomInfo when subject has not value
    • +
    • [SMACK-207] - Parsing of messages may disconnect Smack/Spark
    • +
    • [SMACK-225] - Improper handeling of DNS SRV records
    • +
    • [SMACK-232] - Better handling of Roster error
    • +
    • [SMACK-243] - Packet with wrong date format makes Smack to disconnect
    • +
    • [SMACK-264] - fix for NPE in SASLMechanism.java
    • +
    • [SMACK-269] - Smack 3.1.0 creates a new chat for every incoming message
    • +
    • [SMACK-271] - Deadlock in XMPPConnection while login and parsing stream features
    • +
    • [SMACK-275] - Patch: Fix for broken SASL DIGEST-MD5 implementation
    • +
    • [SMACK-280] - The authentification should use the Connection#sendPacket method and work transparent with packets and packet listeners.
    • +
    • [SMACK-288] - The parsing of the result for a LeafNode.getItems() call is incorrect. It creates a DefaultPacketExtension instead of an Item for every other item in the result.
    • +
    • [SMACK-290] - Deadlock while getting Roster before it's initialized
    • +
    • [SMACK-291] - RosterGroup modifications should depend on roster push
    • +
    • [SMACK-293] - Support optional roster subscription attribute
    • +
    • [SMACK-305] - RosterEntry#getGroups causing a roster reload
    • +
    • [SMACK-308] - Multiple errors in pubsub GetItemsRequest
    • +
    • [SMACK-312] - Only fire RosterListener#entriesUpdated for RosterEntries that changed
    • +
    • [SMACK-327] - getFeatures() method on DiscoverInfo is improperly set to be package protected instead of public
    • +
    • [SMACK-328] - Number format exception while parsing dates.
    • +
    • [SMACK-332] - Smack 3.2.0b2 shows wrong version in Smack Dubugger Window
    • +
    • [SMACK-334] - Error in form for FileTransferNegotiator
    • +
    +

    3.1.0 -- November 20, 2008

    New Features

    @@ -333,4 +391,4 @@

    2.2.0 -- March 9, 2006

    - \ No newline at end of file + diff --git a/documentation/messaging.html b/documentation/messaging.html index 35af39c74..457c8d6a7 100644 --- a/documentation/messaging.html +++ b/documentation/messaging.html @@ -82,6 +82,40 @@ } + +

    + Incoming Chat +

    + +When chats are prompted by another user, the setup is slightly different since +you are receiving a chat message first. Instead of explicitly creating a chat to send +messages, you need to register to handle newly created Chat instances when the ChatManager +creates them. +
    +
    +The ChatManager will already find a matching chat (by thread id) and if none exists, then it +will create a new one that does match. To get this new chat, you have to register to be +notified when it happens. You can register a message listener to receive all future messages as +part of this handler.

    + +

    // Assume we've created a Connection name "connection".
    +ChatManager chatmanager = connection.getChatManager().addChatListener(
    +    new ChatManagerListener() {
    +        @Override
    +        public void chatCreated(Chat chat, boolean createdLocally)
    +        {
    +            if (!createdLocally)
    +                chat.addMessageListener(new MyNewMessageListener());;
    +        }
    +    });
    +
    +
    +In addition to thread based chat messages, there are some clients that +do not send a thread id as part of the chat. To handle this scenario, +Smack will attempt match the incoming messages to the best fit existing +chat, based on the JID. It will attempt to find a chat with the same full +JID, failing that, it will try the base JID. If no existing chat to the +user can found, then a new one is created.




    diff --git a/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/STUNResolver.java b/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/STUNResolver.java index a3d2c24b7..496dc7578 100644 --- a/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/STUNResolver.java +++ b/jingle/extension/source/org/jivesoftware/smackx/jingle/nat/STUNResolver.java @@ -52,11 +52,6 @@ public class STUNResolver extends TransportResolver { // The filename where the STUN servers are stored. public final static String STUNSERVERS_FILENAME = "META-INF/stun-config.xml"; - // Fallback values when we don't have any STUN server to use... - private final static String FALLBACKHOSTNAME = "stun.xten.net"; - - private final static int FALLBACKHOSTPORT = 3478; - // Current STUN server we are using protected STUNService currentServer; @@ -189,10 +184,10 @@ public ArrayList loadSTUNServers(java.io.InputStream stunConfigStream) { } catch (XmlPullParserException e) { - e.printStackTrace(); + LOGGER.error(e.getMessage(), e); } catch (IOException e) { - e.printStackTrace(); + LOGGER.error(e.getMessage(), e); } currentServer = bestSTUNServer(serversList); @@ -247,13 +242,7 @@ public ArrayList loadSTUNServers() { } } catch (Exception e) { - e.printStackTrace(); - } - - // If the list of candidates is empty, add at least one default server - if (serversList.isEmpty()) { - currentServer = new STUNService(FALLBACKHOSTNAME, FALLBACKHOSTPORT); - serversList.add(currentServer); + LOGGER.error(e.getMessage(), e); } return serversList; @@ -370,14 +359,14 @@ public void run() { } } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e.getMessage(), e); } } } } } catch (SocketException e) { - e.printStackTrace(); + LOGGER.error(e.getMessage(), e); } finally { setInitialized(); @@ -524,7 +513,7 @@ public boolean checkBinding() { } } catch (Exception e) { - e.printStackTrace(); + LOGGER.error(e.getMessage(), e); } return result; diff --git a/test-unit/org/jivesoftware/smack/ChatConnectionTest.java b/test-unit/org/jivesoftware/smack/ChatConnectionTest.java new file mode 100644 index 000000000..93a808e8c --- /dev/null +++ b/test-unit/org/jivesoftware/smack/ChatConnectionTest.java @@ -0,0 +1,291 @@ +/** + * $RCSfile$ + * $Revision: 11640 $ + * $Date: 2010-02-18 08:38:57 -0500 (Thu, 18 Feb 2010) $ + * + * Copyright 2010 Jive Software. + * + * 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. + */ + +package org.jivesoftware.smack; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import org.jivesoftware.smack.packet.Message; +import org.jivesoftware.smack.packet.Packet; +import org.jivesoftware.smack.packet.PacketExtension; +import org.junit.After; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +/** + * Tests that verifies the correct behavior of the {@see Roster} implementation. + * + * @see Roster + * @see Roster Management + * @author Guenther Niess + */ +public class ChatConnectionTest +{ + + private DummyConnection connection; + + @Before + public void setUp() throws Exception + { + // Uncomment this to enable debug output + // Connection.DEBUG_ENABLED = true; + + connection = new DummyConnection(); + connection.connect(); + connection.login("me", "secret"); + } + + @After + public void tearDown() throws Exception + { + if (connection != null) + connection.disconnect(); + } + + /** + * Confirm that a new chat is created when a chat message is received but + * there is no thread id for a user with only a base jid. + */ + @Test + public void chatCreatedWithIncomingChatNoThreadBaseJid() + { + TestChatManagerListener listener = new TestChatManagerListener(); + connection.getChatManager().addChatListener(listener); + + Packet incomingChat = createChatPacket(null, false); + processServerMessage(incomingChat); + + Chat newChat = listener.getNewChat(); + assertNotNull(newChat); + } + + /** + * Confirm that a new chat is created when a chat message is received but + * there is no thread id for a user with a full jid. + */ + @Test + public void chatCreatedWhenIncomingChatNoThreadFullJid() + { + TestChatManagerListener listener = new TestChatManagerListener(); + connection.getChatManager().addChatListener(listener); + + Packet incomingChat = createChatPacket(null, true); + processServerMessage(incomingChat); + + Chat newChat = listener.getNewChat(); + assertNotNull(newChat); + } + + /** + * Confirm that an existing chat created with a base jid is matched to an + * incoming chat message that has no thread id and the user is a full jid. + */ + @Test + public void chatFoundWhenNoThreadFullJid() + { + TestChatManagerListener listener = new TestChatManagerListener(); + connection.getChatManager().addChatListener(listener); + Chat outgoing = connection.getChatManager().createChat("you@testserver", null); + + Packet incomingChat = createChatPacket(null, true); + processServerMessage(incomingChat); + + Chat newChat = listener.getNewChat(); + assertNotNull(newChat); + assertTrue(newChat == outgoing); + } + + /** + * Confirm that an existing chat created with a base jid is matched to an + * incoming chat message that has no thread id and the user is a base jid. + */ + @Test + public void chatFoundWhenNoThreadBaseJid() + { + TestChatManagerListener listener = new TestChatManagerListener(); + connection.getChatManager().addChatListener(listener); + Chat outgoing = connection.getChatManager().createChat("you@testserver", null); + + Packet incomingChat = createChatPacket(null, false); + processServerMessage(incomingChat); + + Chat newChat = listener.getNewChat(); + assertNotNull(newChat); + assertTrue(newChat == outgoing); + } + + /** + * Confirm that an existing chat created with a base jid is matched to an + * incoming chat message that has the same id and the user is a full jid. + */ + @Test + public void chatFoundWithSameThreadFullJid() + { + TestChatManagerListener listener = new TestChatManagerListener(); + connection.getChatManager().addChatListener(listener); + Chat outgoing = connection.getChatManager().createChat("you@testserver", null); + + Packet incomingChat = createChatPacket(outgoing.getThreadID(), true); + processServerMessage(incomingChat); + + Chat newChat = listener.getNewChat(); + assertNotNull(newChat); + assertTrue(newChat == outgoing); + } + + /** + * Confirm that an existing chat created with a base jid is matched to an + * incoming chat message that has the same id and the user is a base jid. + */ + @Test + public void chatFoundWithSameThreadBaseJid() + { + TestChatManagerListener listener = new TestChatManagerListener(); + connection.getChatManager().addChatListener(listener); + Chat outgoing = connection.getChatManager().createChat("you@testserver", null); + + Packet incomingChat = createChatPacket(outgoing.getThreadID(), false); + processServerMessage(incomingChat); + + Chat newChat = listener.getNewChat(); + assertNotNull(newChat); + assertTrue(newChat == outgoing); + } + + /** + * Confirm that an existing chat created with a base jid is not matched to + * an incoming chat message that has a different id and the same user as a + * base jid. + */ + @Ignore + @Test + public void chatNotFoundWithDiffThreadBaseJid() + { + TestChatManagerListener listener = new TestChatManagerListener(); + connection.getChatManager().addChatListener(listener); + Chat outgoing = connection.getChatManager().createChat("you@testserver", null); + + Packet incomingChat = createChatPacket(outgoing.getThreadID() + "ff", false); + processServerMessage(incomingChat); + + Chat newChat = listener.getNewChat(); + assertNotNull(newChat); + assertFalse(newChat == outgoing); + } + + /** + * Confirm that an existing chat created with a base jid is not matched to + * an incoming chat message that has a different id and the same base jid. + */ + @Ignore + @Test + public void chatNotFoundWithDiffThreadFullJid() + { + TestChatManagerListener listener = new TestChatManagerListener(); + connection.getChatManager().addChatListener(listener); + Chat outgoing = connection.getChatManager().createChat("you@testserver", null); + + Packet incomingChat = createChatPacket(outgoing.getThreadID() + "ff", true); + processServerMessage(incomingChat); + + Chat newChat = listener.getNewChat(); + assertNotNull(newChat); + assertFalse(newChat == outgoing); + } + + private Packet createChatPacket(final String threadId, final boolean isFullJid) + { + Message chatMsg = new Message("me@testserver", Message.Type.chat); + chatMsg.setBody("the body message"); + chatMsg.setFrom("you@testserver" + (isFullJid ? "/resource" : "")); + + if (threadId != null) + chatMsg.addExtension(new PacketExtension() + { + @Override + public String toXML() + { + return "" + threadId + ""; + } + + @Override + public String getNamespace() + { + return null; + } + + @Override + public String getElementName() + { + return "thread"; + } + }); + return chatMsg; + } + + private void processServerMessage(Packet incomingChat) + { + TestChatServer chatServer = new TestChatServer(incomingChat); + chatServer.start(); + try + { + chatServer.join(); + } catch (InterruptedException e) + { + fail(); + } + } + + class TestChatManagerListener implements ChatManagerListener + { + private Chat newChat; + + @Override + public void chatCreated(Chat chat, boolean createdLocally) + { + newChat = chat; + } + + public Chat getNewChat() + { + return newChat; + } + } + + private class TestChatServer extends Thread + { + private Packet chatPacket; + + TestChatServer(Packet chatMsg) + { + chatPacket = chatMsg; + } + + @Override + public void run() + { + connection.processPacket(chatPacket); + } + } +} diff --git a/test-unit/org/jivesoftware/smack/ThreadedDummyConnection.java b/test-unit/org/jivesoftware/smack/ThreadedDummyConnection.java new file mode 100644 index 000000000..8631b0371 --- /dev/null +++ b/test-unit/org/jivesoftware/smack/ThreadedDummyConnection.java @@ -0,0 +1,77 @@ +package org.jivesoftware.smack; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; + +import org.jivesoftware.smack.packet.IQ; +import org.jivesoftware.smack.packet.Message; +import org.jivesoftware.smack.packet.Packet; +import org.jivesoftware.smack.packet.IQ.Type; + +public class ThreadedDummyConnection extends DummyConnection +{ + private BlockingQueue replyQ = new ArrayBlockingQueue(1); + private BlockingQueue messageQ = new LinkedBlockingQueue(5); + + @Override + public void sendPacket(Packet packet) + { + super.sendPacket(packet); + + if ((packet instanceof IQ) && !replyQ.isEmpty()) + { + // Set reply packet to match one being sent. We haven't started the + // other thread yet so this is still safe. + IQ replyPacket = replyQ.peek(); + replyPacket.setPacketID(packet.getPacketID()); + replyPacket.setFrom(packet.getTo()); + replyPacket.setTo(packet.getFrom()); + replyPacket.setType(Type.RESULT); + + new ProcessQueue(replyQ).start(); + } + } + + public void addMessage(Message msgToProcess) + { + messageQ.add(msgToProcess); + } + + public void addIQReply(IQ reply) + { + replyQ.add(reply); + } + + public void processMessages() + { + if (!messageQ.isEmpty()) + new ProcessQueue(messageQ).start(); + else + System.out.println("No messages to process"); + } + + class ProcessQueue extends Thread + { + private BlockingQueue processQ; + + ProcessQueue(BlockingQueue queue) + { + processQ = queue; + } + + @Override + public void run() + { + try + { + processPacket(processQ.take()); + } + catch (InterruptedException e) + { + e.printStackTrace(); + } + } + }; + +} diff --git a/test-unit/org/jivesoftware/smack/filters/FromMatchesFilterTest.java b/test-unit/org/jivesoftware/smack/filters/FromMatchesFilterTest.java new file mode 100644 index 000000000..6bb1106b5 --- /dev/null +++ b/test-unit/org/jivesoftware/smack/filters/FromMatchesFilterTest.java @@ -0,0 +1,92 @@ +package org.jivesoftware.smack.filters; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; + +import org.jivesoftware.smack.filter.FromMatchesFilter; +import org.jivesoftware.smack.packet.Packet; +import org.junit.Test; + +public class FromMatchesFilterTest { + private static final String BASE_JID1 = "ss@muc.myserver.com"; + private static final String FULL_JID1_R1 = BASE_JID1 + "/resource"; + private static final String FULL_JID1_R2 = BASE_JID1 + "/resource2"; + private static final String BASE_JID2 = "sss@muc.myserver.com"; + private static final String FULL_JID2 = BASE_JID2 + "/resource"; + + private static final String SERVICE_JID1 = "muc.myserver.com"; + private static final String SERVICE_JID2 = "pubsub.myserver.com"; + + @Test + public void compareMatchingFullJid() + { + FromMatchesFilter filter = new FromMatchesFilter(FULL_JID1_R1); + Packet packet = new Packet() { + @Override + public String toXML() { return null; } + }; + + packet.setFrom(FULL_JID1_R1); + assertTrue(filter.accept(packet)); + + packet.setFrom(BASE_JID1); + assertFalse(filter.accept(packet)); + + packet.setFrom(FULL_JID1_R2); + assertFalse(filter.accept(packet)); + + packet.setFrom(BASE_JID2); + assertFalse(filter.accept(packet)); + + packet.setFrom(FULL_JID2); + assertFalse(filter.accept(packet)); + } + + @Test + public void compareMatchingBaseJid() + { + FromMatchesFilter filter = new FromMatchesFilter(BASE_JID1); + Packet packet = new Packet() { + @Override + public String toXML() { return null; } + }; + + packet.setFrom(BASE_JID1); + assertTrue(filter.accept(packet)); + + packet.setFrom(FULL_JID1_R1); + assertTrue(filter.accept(packet)); + + packet.setFrom(FULL_JID1_R2); + assertTrue(filter.accept(packet)); + + packet.setFrom(BASE_JID2); + assertFalse(filter.accept(packet)); + + packet.setFrom(FULL_JID2); + assertFalse(filter.accept(packet)); + } + + @Test + public void compareMatchingServiceJid() + { + FromMatchesFilter filter = new FromMatchesFilter(SERVICE_JID1); + Packet packet = new Packet() { + @Override + public String toXML() { return null; } + }; + + packet.setFrom(SERVICE_JID1); + assertTrue(filter.accept(packet)); + + packet.setFrom(SERVICE_JID2); + assertFalse(filter.accept(packet)); + + packet.setFrom(BASE_JID1); + assertFalse(filter.accept(packet)); + + packet.setFrom(FULL_JID1_R1); + assertFalse(filter.accept(packet)); + + } +} diff --git a/test-unit/org/jivesoftware/smack/packet/MessageTest.java b/test-unit/org/jivesoftware/smack/packet/MessageTest.java index fd79aad0d..526698bb1 100644 --- a/test-unit/org/jivesoftware/smack/packet/MessageTest.java +++ b/test-unit/org/jivesoftware/smack/packet/MessageTest.java @@ -8,6 +8,8 @@ package org.jivesoftware.smack.packet; import static org.custommonkey.xmlunit.XMLAssert.*; + +import org.junit.Ignore; import org.junit.Test; import org.xml.sax.SAXException; @@ -105,6 +107,7 @@ public void oneMessageBodyTest() throws IOException, SAXException, ParserConfigu assertXMLEqual(control, message.toXML()); } + @Ignore @Test public void multipleMessageBodiesTest() throws IOException, SAXException, ParserConfigurationException { final String messageBody1 = "This is a test of the emergency broadcast system, 1."; diff --git a/test-unit/org/jivesoftware/smack/util/PacketParserUtilsTest.java b/test-unit/org/jivesoftware/smack/util/PacketParserUtilsTest.java index dfd945b77..430360aed 100644 --- a/test-unit/org/jivesoftware/smack/util/PacketParserUtilsTest.java +++ b/test-unit/org/jivesoftware/smack/util/PacketParserUtilsTest.java @@ -20,6 +20,7 @@ import org.custommonkey.xmlunit.Diff; import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Packet; +import org.junit.Ignore; import org.junit.Test; import org.xmlpull.mxp1.MXParser; import org.xmlpull.v1.XmlPullParser; @@ -720,6 +721,7 @@ public void invalidXMLInMessageBody() throws Exception { } + @Ignore @Test public void multipleMessageBodiesParsingTest() throws Exception { String control = XMLBuilder.create("message") @@ -739,7 +741,6 @@ public void multipleMessageBodiesParsingTest() throws Exception { .a("xml:lang", "sp") .t("This is a test of the emergency broadcast system, 3.") .asString(outputProperties); - Packet message = PacketParserUtils.parseMessage(getParser(control)); assertXMLEqual(control, message.toXML()); diff --git a/test-unit/org/jivesoftware/smackx/filetransfer/FileTransferNegotiatorTest.java b/test-unit/org/jivesoftware/smackx/filetransfer/FileTransferNegotiatorTest.java new file mode 100644 index 000000000..9a6e6cd63 --- /dev/null +++ b/test-unit/org/jivesoftware/smackx/filetransfer/FileTransferNegotiatorTest.java @@ -0,0 +1,41 @@ +package org.jivesoftware.smackx.filetransfer; + +import static org.junit.Assert.*; + +import org.jivesoftware.smack.DummyConnection; +import org.jivesoftware.smack.XMPPException; +import org.jivesoftware.smack.packet.Packet; +import org.jivesoftware.smackx.ServiceDiscoveryManager; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class FileTransferNegotiatorTest { + private DummyConnection connection; + + @Before + public void setUp() throws Exception { + // Uncomment this to enable debug output + //Connection.DEBUG_ENABLED = true; + + connection = new DummyConnection(); + connection.connect(); + connection.login("me", "secret"); + new ServiceDiscoveryManager(connection); + } + + @After + public void tearDown() throws Exception { + if (connection != null) + connection.disconnect(); + } + + @Test + public void verifyForm() throws Exception + { + FileTransferNegotiator fileNeg = FileTransferNegotiator.getInstanceFor(connection); + fileNeg.negotiateOutgoingTransfer("me", "streamid", "file", 1024, null, 10); + Packet packet = connection.getSentPacket(); + assertTrue(packet.toXML().indexOf("\"stream-method\" type=\"list-single\"") != -1); + } +} diff --git a/test-unit/org/jivesoftware/smackx/muc/RoomInfoTest.java b/test-unit/org/jivesoftware/smackx/muc/RoomInfoTest.java new file mode 100644 index 000000000..09e2b6d37 --- /dev/null +++ b/test-unit/org/jivesoftware/smackx/muc/RoomInfoTest.java @@ -0,0 +1,50 @@ +package org.jivesoftware.smackx.muc; + +import org.jivesoftware.smackx.FormField; +import org.jivesoftware.smackx.muc.RoomInfo; +import org.jivesoftware.smackx.packet.DataForm; +import org.jivesoftware.smackx.packet.DiscoverInfo; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertEquals; +import org.junit.Test; + +public class RoomInfoTest +{ + @Test + public void validateRoomWithEmptyForm() + { + DataForm dataForm = new DataForm("result"); + + DiscoverInfo discoInfo = new DiscoverInfo(); + discoInfo.addExtension(dataForm); + RoomInfo roomInfo = new RoomInfo(discoInfo); + assertTrue(roomInfo.getDescription().isEmpty()); + assertTrue(roomInfo.getSubject().isEmpty()); + assertEquals(-1, roomInfo.getOccupantsCount()); + } + + @Test + public void validateRoomWithForm() + { + DataForm dataForm = new DataForm("result"); + + FormField desc = new FormField("muc#roominfo_description"); + desc.addValue("The place for all good witches!"); + dataForm.addField(desc); + + FormField subject = new FormField("muc#roominfo_subject"); + subject.addValue("Spells"); + dataForm.addField(subject); + + FormField occupants = new FormField("muc#roominfo_occupants"); + occupants.addValue("3"); + dataForm.addField(occupants); + + DiscoverInfo discoInfo = new DiscoverInfo(); + discoInfo.addExtension(dataForm); + RoomInfo roomInfo = new RoomInfo(discoInfo); + assertEquals("The place for all good witches!", roomInfo.getDescription()); + assertEquals("Spells", roomInfo.getSubject()); + assertEquals(3, roomInfo.getOccupantsCount()); + } +} diff --git a/test-unit/org/jivesoftware/smackx/pubsub/ConfigureFormTest.java b/test-unit/org/jivesoftware/smackx/pubsub/ConfigureFormTest.java new file mode 100644 index 000000000..291d16019 --- /dev/null +++ b/test-unit/org/jivesoftware/smackx/pubsub/ConfigureFormTest.java @@ -0,0 +1,16 @@ +package org.jivesoftware.smackx.pubsub; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class ConfigureFormTest +{ + @Test + public void checkChildrenAssocPolicy() + { + ConfigureForm form = new ConfigureForm(FormType.submit); + form.setChildrenAssociationPolicy(ChildrenAssociationPolicy.owners); + assertEquals(ChildrenAssociationPolicy.owners, form.getChildrenAssociationPolicy()); + } +} diff --git a/test-unit/org/jivesoftware/smackx/pubsub/ItemValidationTest.java b/test-unit/org/jivesoftware/smackx/pubsub/ItemValidationTest.java new file mode 100644 index 000000000..a314b4628 --- /dev/null +++ b/test-unit/org/jivesoftware/smackx/pubsub/ItemValidationTest.java @@ -0,0 +1,107 @@ +package org.jivesoftware.smackx.pubsub; + +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import java.io.Reader; +import java.io.StringReader; + +import org.jivesoftware.smack.ThreadedDummyConnection; +import org.jivesoftware.smackx.pubsub.provider.ItemsProvider; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.xmlpull.mxp1.MXParser; +import org.xmlpull.v1.XmlPullParser; + +public class ItemValidationTest +{ + private ThreadedDummyConnection connection; + + @Before + public void setUp() throws Exception + { + // Uncomment this to enable debug output + // Connection.DEBUG_ENABLED = true; + + connection = new ThreadedDummyConnection(); + connection.connect(); + connection.login("me", "secret"); + } + + @After + public void tearDown() throws Exception + { + if (connection != null) + connection.disconnect(); + } + + @Test + public void verifyBasicItem() throws Exception + { + Item simpleItem = new Item(); + String simpleCtrl = ""; + assertXMLEqual(simpleCtrl, simpleItem.toXML()); + + Item idItem = new Item("uniqueid"); + String idCtrl = ""; + assertXMLEqual(idCtrl, idItem.toXML()); + + Item itemWithNodeId = new Item("testId", "testNode"); + String nodeIdCtrl = ""; + assertXMLEqual(nodeIdCtrl, itemWithNodeId.toXML()); + } + + @Test + public void verifyPayloadItem() throws Exception + { + SimplePayload payload = new SimplePayload(null, null, "This is the payload"); + + PayloadItem simpleItem = new PayloadItem(payload); + String simpleCtrl = "" + payload.toXML() + ""; + assertXMLEqual(simpleCtrl, simpleItem.toXML()); + + PayloadItem idItem = new PayloadItem("uniqueid", payload); + String idCtrl = "" + payload.toXML() + ""; + assertXMLEqual(idCtrl, idItem.toXML()); + + PayloadItem itemWithNodeId = new PayloadItem("testId", "testNode", payload); + String nodeIdCtrl = "" + payload.toXML() + ""; + assertXMLEqual(nodeIdCtrl, itemWithNodeId.toXML()); + } + +// @Test +// public void parseBasicItemWithoutNode() throws Exception +// { +// XmlPullParser parser = new MXParser(); +// Reader reader = new StringReader( +// "" + +// "" + +// "" + +// ""); +// parser.setInput(reader); +// ItemsProvider itemsProvider = new ItemsProvider(); +// ItemsExtension ext = (ItemsExtension) itemsProvider.parseExtension(parser); +// Item basicItem = (Item) ext.getItems().get(0); +// +// assertEquals("testid1", basicItem.getId()); +// assertNull(basicItem.getNode()); +// } + +// @Test +// public void parseBasicItemNode() throws Exception +// { +// BlockingQueue itemQ = new ArrayBlockingQueue(1); +// +// setupListener(itemQ); +// Message itemMsg = getMessage(""); +// connection.addMessage(itemMsg); +// +// Item basicItem = itemQ.poll(2, TimeUnit.SECONDS); +// +// assertNotNull(basicItem); +// assertEquals("testid1", basicItem.getId()); +// assertEquals("testNode", basicItem.getNode()); +// } +} diff --git a/test/org/jivesoftware/smackx/packet/XHTMLExtensionTest.java b/test/org/jivesoftware/smackx/packet/XHTMLExtensionTest.java index 9fb993126..e27238503 100644 --- a/test/org/jivesoftware/smackx/packet/XHTMLExtensionTest.java +++ b/test/org/jivesoftware/smackx/packet/XHTMLExtensionTest.java @@ -52,11 +52,16 @@ package org.jivesoftware.smackx.packet; -import java.util.*; - -import org.jivesoftware.smack.*; -import org.jivesoftware.smack.filter.*; -import org.jivesoftware.smack.packet.*; +import java.util.Iterator; + +import org.jivesoftware.smack.Chat; +import org.jivesoftware.smack.PacketCollector; +import org.jivesoftware.smack.PacketListener; +import org.jivesoftware.smack.filter.PacketExtensionFilter; +import org.jivesoftware.smack.filter.PacketFilter; +import org.jivesoftware.smack.filter.ThreadFilter; +import org.jivesoftware.smack.packet.Message; +import org.jivesoftware.smack.packet.Packet; import org.jivesoftware.smack.test.SmackTestCase; /** @@ -70,7 +75,7 @@ public class XHTMLExtensionTest extends SmackTestCase { private int bodiesReceived; public XHTMLExtensionTest(String name) { - super(name); + super(name); } /** @@ -79,27 +84,27 @@ public XHTMLExtensionTest(String name) { * 1. User_1 will send a message with formatted text (XHTML) to user_2 */ public void testSendSimpleXHTMLMessage() { - // User1 creates a chat with user2 - Chat chat1 = getConnection(0).getChatManager().createChat(getBareJID(1), null); - - // User1 creates a message to send to user2 - Message msg = new Message(); - msg.setSubject("Any subject you want"); - msg.setBody("Hey John, this is my new green!!!!"); - // Create a XHTMLExtension Package and add it to the message - XHTMLExtension xhtmlExtension = new XHTMLExtension(); - xhtmlExtension.addBody( - "

    Hey John, this is my new green!!!!

    "); - msg.addExtension(xhtmlExtension); - - // User1 sends the message that contains the XHTML to user2 - try { - chat1.sendMessage(msg); - Thread.sleep(200); - } - catch (Exception e) { - fail("An error occured sending the message with XHTML"); - } + // User1 creates a chat with user2 + Chat chat1 = getConnection(0).getChatManager().createChat(getBareJID(1), null); + + // User1 creates a message to send to user2 + Message msg = new Message(); + msg.setSubject("Any subject you want"); + msg.setBody("Hey John, this is my new green!!!!"); + // Create a XHTMLExtension Package and add it to the message + XHTMLExtension xhtmlExtension = new XHTMLExtension(); + xhtmlExtension.addBody( + "

    Hey John, this is my new green!!!!

    "); + msg.addExtension(xhtmlExtension); + + // User1 sends the message that contains the XHTML to user2 + try { + chat1.sendMessage(msg); + Thread.sleep(200); + } + catch (Exception e) { + fail("An error occured sending the message with XHTML"); + } } /** @@ -111,48 +116,48 @@ public void testSendSimpleXHTMLMessage() { * something is wrong */ public void testSendSimpleXHTMLMessageAndDisplayReceivedXHTMLMessage() { - // Create a chat for each connection - Chat chat1 = getConnection(0).getChatManager().createChat(getBareJID(1), null); - final PacketCollector chat2 = getConnection(1).createPacketCollector( - new ThreadFilter(chat1.getThreadID())); - - // User1 creates a message to send to user2 - Message msg = new Message(); - msg.setSubject("Any subject you want"); - msg.setBody("Hey John, this is my new green!!!!"); - // Create a XHTMLExtension Package and add it to the message - XHTMLExtension xhtmlExtension = new XHTMLExtension(); - xhtmlExtension.addBody( - "

    Hey John, this is my new green!!!!

    "); - msg.addExtension(xhtmlExtension); - - // User1 sends the message that contains the XHTML to user2 - try { - chat1.sendMessage(msg); - } - catch (Exception e) { - fail("An error occured sending the message with XHTML"); - } - Packet packet = chat2.nextResult(2000); - Message message = (Message) packet; - assertNotNull("Body is null", message.getBody()); - try { - xhtmlExtension = - (XHTMLExtension) message.getExtension( - "html", - "http://jabber.org/protocol/xhtml-im"); - assertNotNull( - "Message without extension \"http://jabber.org/protocol/xhtml-im\"", - xhtmlExtension); - assertTrue("Message without XHTML bodies", xhtmlExtension.getBodiesCount() > 0); - for (Iterator it = xhtmlExtension.getBodies(); it.hasNext();) { - String body = (String) it.next(); - System.out.println(body); - } - } - catch (ClassCastException e) { - fail("ClassCastException - Most probable cause is that smack providers is misconfigured"); - } + // Create a chat for each connection + Chat chat1 = getConnection(0).getChatManager().createChat(getBareJID(1), null); + final PacketCollector chat2 = getConnection(1).createPacketCollector( + new ThreadFilter(chat1.getThreadID())); + + // User1 creates a message to send to user2 + Message msg = new Message(); + msg.setSubject("Any subject you want"); + msg.setBody("Hey John, this is my new green!!!!"); + // Create a XHTMLExtension Package and add it to the message + XHTMLExtension xhtmlExtension = new XHTMLExtension(); + xhtmlExtension.addBody( + "

    Hey John, this is my new green!!!!

    "); + msg.addExtension(xhtmlExtension); + + // User1 sends the message that contains the XHTML to user2 + try { + chat1.sendMessage(msg); + } + catch (Exception e) { + fail("An error occured sending the message with XHTML"); + } + Packet packet = chat2.nextResult(2000); + Message message = (Message) packet; + assertNotNull("Body is null", message.getBody()); + try { + xhtmlExtension = + (XHTMLExtension) message.getExtension( + "html", + "http://jabber.org/protocol/xhtml-im"); + assertNotNull( + "Message without extension \"http://jabber.org/protocol/xhtml-im\"", + xhtmlExtension); + assertTrue("Message without XHTML bodies", xhtmlExtension.getBodiesCount() > 0); + for (Iterator it = xhtmlExtension.getBodies(); it.hasNext();) { + String body = (String) it.next(); + System.out.println(body); + } + } + catch (ClassCastException e) { + fail("ClassCastException - Most probable cause is that smack providers is misconfigured"); + } } /** @@ -164,22 +169,23 @@ public void testSendSimpleXHTMLMessageAndDisplayReceivedXHTMLMessage() { * something is wrong */ public void testSendComplexXHTMLMessageAndDisplayReceivedXHTMLMessage() { - // Create a chat for each connection - Chat chat1 = getConnection(0).getChatManager().createChat(getBareJID(1), null); - final PacketCollector chat2 = getConnection(1).createPacketCollector( - new ThreadFilter(chat1.getThreadID())); - - // Create a Listener that listens for Messages with the extension - //"http://jabber.org/protocol/xhtml-im" - // This listener will listen on the conn2 and answer an ACK if everything is ok - PacketFilter packetFilter = - new PacketExtensionFilter("html", "http://jabber.org/protocol/xhtml-im"); - PacketListener packetListener = new PacketListener() { - public void processPacket(Packet packet) { - - } - }; - getConnection(1).addPacketListener(packetListener, packetFilter); + // Create a chat for each connection + Chat chat1 = getConnection(0).getChatManager().createChat(getBareJID(1), null); + final PacketCollector chat2 = getConnection(1).createPacketCollector( + new ThreadFilter(chat1.getThreadID())); + + // Create a Listener that listens for Messages with the extension + //"http://jabber.org/protocol/xhtml-im" + // This listener will listen on the conn2 and answer an ACK if everything is ok + PacketFilter packetFilter = + new PacketExtensionFilter("html", "http://jabber.org/protocol/xhtml-im"); + PacketListener packetListener = new PacketListener() { + @Override + public void processPacket(Packet packet) { + + } + }; + getConnection(1).addPacketListener(packetListener, packetFilter); // User1 creates a message to send to user2 Message msg = new Message(); @@ -189,52 +195,53 @@ public void processPacket(Packet packet) { // Create an XHTMLExtension and add it to the message XHTMLExtension xhtmlExtension = new XHTMLExtension(); xhtmlExtension.addBody( - "

    impresionante!

    Como Emerson dijo una vez:

    Una consistencia ridícula es el espantajo de mentes pequeñas.

    "); + "

    impresionante!

    Como Emerson dijo una vez:

    Una consistencia ridicula es el espantajo de mentes pequenas.

    "); xhtmlExtension.addBody( "

    awesome!

    As Emerson once said:

    A foolish consistency is the hobgoblin of little minds.

    "); msg.addExtension(xhtmlExtension); - // User1 sends the message that contains the XHTML to user2 - try { - bodiesSent = xhtmlExtension.getBodiesCount(); - bodiesReceived = 0; - chat1.sendMessage(msg); - } - catch (Exception e) { - fail("An error occured sending the message with XHTML"); - } - Packet packet = chat2.nextResult(2000); - int received = 0; - Message message = (Message) packet; - assertNotNull("Body is null", message.getBody()); - try { - xhtmlExtension = - (XHTMLExtension) message.getExtension( - "html", - "http://jabber.org/protocol/xhtml-im"); - assertNotNull( - "Message without extension \"http://jabber.org/protocol/xhtml-im\"", - xhtmlExtension); - assertTrue("Message without XHTML bodies", xhtmlExtension.getBodiesCount() > 0); - for (Iterator it = xhtmlExtension.getBodies(); it.hasNext();) { - received++; - System.out.println((String) it.next()); - } - bodiesReceived = received; - } - catch (ClassCastException e) { - fail("ClassCastException - Most probable cause is that smack providers is " + - "misconfigured"); - } - // Wait half second so that the complete test can run - assertEquals( - "Number of sent and received XHTMP bodies does not match", - bodiesSent, - bodiesReceived); + // User1 sends the message that contains the XHTML to user2 + try { + bodiesSent = xhtmlExtension.getBodiesCount(); + bodiesReceived = 0; + chat1.sendMessage(msg); + } + catch (Exception e) { + fail("An error occured sending the message with XHTML"); + } + Packet packet = chat2.nextResult(2000); + int received = 0; + Message message = (Message) packet; + assertNotNull("Body is null", message.getBody()); + try { + xhtmlExtension = + (XHTMLExtension) message.getExtension( + "html", + "http://jabber.org/protocol/xhtml-im"); + assertNotNull( + "Message without extension \"http://jabber.org/protocol/xhtml-im\"", + xhtmlExtension); + assertTrue("Message without XHTML bodies", xhtmlExtension.getBodiesCount() > 0); + for (Iterator it = xhtmlExtension.getBodies(); it.hasNext();) { + received++; + System.out.println((String) it.next()); + } + bodiesReceived = received; + } + catch (ClassCastException e) { + fail("ClassCastException - Most probable cause is that smack providers is " + + "misconfigured"); + } + // Wait half second so that the complete test can run + assertEquals( + "Number of sent and received XHTMP bodies does not match", + bodiesSent, + bodiesReceived); } + @Override protected int getMaxConnections() { - return 2; + return 2; } } From e6f69362e8545b14444bf70ff1b786a3bc693d11 Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Tue, 7 Jun 2011 17:16:38 +0600 Subject: [PATCH 29/33] Remove unused import. --- source/org/jivesoftware/smackx/pubsub/PayloadItem.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/source/org/jivesoftware/smackx/pubsub/PayloadItem.java b/source/org/jivesoftware/smackx/pubsub/PayloadItem.java index 52e53f1f3..defdb212d 100644 --- a/source/org/jivesoftware/smackx/pubsub/PayloadItem.java +++ b/source/org/jivesoftware/smackx/pubsub/PayloadItem.java @@ -16,8 +16,6 @@ import org.jivesoftware.smack.packet.PacketExtension; import org.jivesoftware.smackx.pubsub.provider.ItemProvider; -import com.sun.corba.se.impl.protocol.giopmsgheaders.Message; - /** * This class represents an item that has been, or will be published to a * pubsub node. An Item has several properties that are dependent From ccdd40871adae56b2950dd9e633d85e94f3c82ae Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Thu, 30 Jun 2011 12:29:35 +0600 Subject: [PATCH 30/33] Possibility to remove empty group. --- source/org/jivesoftware/smack/Roster.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/source/org/jivesoftware/smack/Roster.java b/source/org/jivesoftware/smack/Roster.java index 9e7a18460..ecc81110a 100644 --- a/source/org/jivesoftware/smack/Roster.java +++ b/source/org/jivesoftware/smack/Roster.java @@ -244,6 +244,23 @@ public RosterGroup createGroup(String name) { groups.put(name, group); return group; } + + /** + * Removes empty group. + * + * @param name the name of the group. + * @throws IllegalStateException if group doesn't exists or is not empty. + */ + public void removeEmptyGroup(String name) { + RosterGroup group = groups.get(name); + if (group == null) { + throw new IllegalArgumentException("Group with name " + name + " doesn't exists."); + } + if (group.getEntryCount() != 0) { + throw new IllegalArgumentException("Group " + name + " is not empty."); + } + groups.remove(name); + } /** * Creates a new roster entry and presence subscription. The server will asynchronously From 10b3b22da854af056ba94f0740863fd9a22244ad Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Thu, 30 Jun 2011 13:02:14 +0600 Subject: [PATCH 31/33] Don't create roster if it is not loaded at login. --- .../jivesoftware/smack/XMPPConnection.java | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/source/org/jivesoftware/smack/XMPPConnection.java b/source/org/jivesoftware/smack/XMPPConnection.java index bb609be1d..bccf73685 100644 --- a/source/org/jivesoftware/smack/XMPPConnection.java +++ b/source/org/jivesoftware/smack/XMPPConnection.java @@ -234,16 +234,16 @@ public synchronized void login(String username, String password, String resource authenticated = true; anonymous = false; - // Create the roster if it is not a reconnection or roster already created by getRoster() - if (this.roster == null) { - if(rosterStorage==null){ - this.roster = new Roster(this); + if (config.isRosterLoadedAtLogin()) { + // Create the roster if it is not a reconnection or roster already + // created by getRoster() + if (this.roster == null) { + if (rosterStorage == null) { + this.roster = new Roster(this); + } else { + this.roster = new Roster(this, rosterStorage); + } } - else{ - this.roster = new Roster(this,rosterStorage); - } - } - if (config.isRosterLoadedAtLogin()) { this.roster.reload(); } @@ -323,6 +323,9 @@ public Roster getRoster() { } if (!config.isRosterLoadedAtLogin()) { + if (roster == null) { + roster = new Roster(this); + } roster.reload(); } // If this is the first time the user has asked for the roster after calling From 47dcb8d659869b4871f4377cba46bf82709eeb36 Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Mon, 4 Jun 2012 13:53:06 +0600 Subject: [PATCH 32/33] Don't use semaphore while waiting for PacketReader to be started. See related bug in Java: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6801020 --- source/org/jivesoftware/smack/PacketReader.java | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/source/org/jivesoftware/smack/PacketReader.java b/source/org/jivesoftware/smack/PacketReader.java index 2dc3b27b7..856770f87 100644 --- a/source/org/jivesoftware/smack/PacketReader.java +++ b/source/org/jivesoftware/smack/PacketReader.java @@ -51,7 +51,6 @@ class PacketReader { private boolean done; private String connectionID = null; - private Semaphore connectionSemaphore; protected PacketReader(final XMPPConnection connection) { this.connection = connection; @@ -97,21 +96,17 @@ public Thread newThread(Runnable runnable) { * @throws XMPPException if the server fails to send an opening stream back * for more than five seconds. */ - public void startup() throws XMPPException { - connectionSemaphore = new Semaphore(1); - + synchronized public void startup() throws XMPPException { readerThread.start(); // Wait for stream tag before returing. We'll wait a couple of seconds before // giving up and throwing an error. try { - connectionSemaphore.acquire(); - // A waiting thread may be woken up before the wait time or a notify // (although this is a rare thing). Therefore, we continue waiting // until either a connectionID has been set (and hence a notify was // made) or the total wait time has elapsed. int waitTime = SmackConfiguration.getPacketReplyTimeout(); - connectionSemaphore.tryAcquire(3 * waitTime, TimeUnit.MILLISECONDS); + wait(3 * waitTime); } catch (InterruptedException ie) { // Ignore. @@ -344,8 +339,8 @@ else if (eventType == XmlPullParser.END_TAG) { * 3) TLS negotiation was successful * */ - private void releaseConnectionIDLock() { - connectionSemaphore.release(); + synchronized private void releaseConnectionIDLock() { + notify(); } /** From a7210a3b2465d13b5f84499f68ecfab4369c1e48 Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Mon, 4 Jun 2012 13:54:10 +0600 Subject: [PATCH 33/33] Path and password for trust store can be null. --- source/org/jivesoftware/smack/ServerTrustManager.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/source/org/jivesoftware/smack/ServerTrustManager.java b/source/org/jivesoftware/smack/ServerTrustManager.java index cabcd2ca0..b72fe003b 100644 --- a/source/org/jivesoftware/smack/ServerTrustManager.java +++ b/source/org/jivesoftware/smack/ServerTrustManager.java @@ -21,6 +21,8 @@ package org.jivesoftware.smack; import javax.net.ssl.X509TrustManager; + +import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.InputStream; import java.io.IOException; @@ -68,8 +70,12 @@ public ServerTrustManager(String server, ConnectionConfiguration configuration) } else { try { trustStore = KeyStore.getInstance(options.getType()); - in = new FileInputStream(options.getPath()); - trustStore.load(in, options.getPassword().toCharArray()); + if (options.getPath() != null) + in = new BufferedInputStream(new FileInputStream(options.getPath())); + char [] chars = null; + if (options.getPassword() != null) + chars = options.getPassword().toCharArray(); + trustStore.load(in, chars); } catch (Exception e) { trustStore = null;