From 7d976539265b99b89cdab95a3db72625a708bc38 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sat, 27 Jun 2015 15:04:26 +0200 Subject: [PATCH 1/8] Smack 4.1.3-SNAPSHOT --- version.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.gradle b/version.gradle index 123c48fe5..617ae8444 100644 --- a/version.gradle +++ b/version.gradle @@ -1,7 +1,7 @@ allprojects { ext { - shortVersion = '4.1.2' - isSnapshot = false + shortVersion = '4.1.3' + isSnapshot = true jxmppVersion = '0.4.2-beta1' smackMinAndroidSdk = 8 } From a9741a8b1099579736b6ce130aa43c2a44312a7b Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Mon, 29 Jun 2015 17:07:42 +0200 Subject: [PATCH 2/8] Use weak map for 'managers' in Socks5BytestreamManager Fixes memory leak and SMACK-678. --- .../smackx/bytestreams/socks5/Socks5BytestreamManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamManager.java index 04bd3d9fe..4ef7b167d 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamManager.java @@ -20,11 +20,11 @@ import java.io.IOException; import java.net.Socket; import java.util.ArrayList; 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 java.util.concurrent.TimeoutException; @@ -110,7 +110,7 @@ public final class Socks5BytestreamManager extends Manager implements Bytestream 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<>(); /* * assigns a user to a listener that is informed if a bytestream request for this user is From e6a403fb1c869e9c6a1b5edf3d5b99d3cff2cb98 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Thu, 2 Jul 2015 09:16:21 +0200 Subject: [PATCH 3/8] Re-escape XML text in parseContentDepth() SMACK-680. --- .../org/jivesoftware/smack/util/PacketParserUtils.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/smack-core/src/main/java/org/jivesoftware/smack/util/PacketParserUtils.java b/smack-core/src/main/java/org/jivesoftware/smack/util/PacketParserUtils.java index ac5ea11b8..0dc960583 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/util/PacketParserUtils.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/util/PacketParserUtils.java @@ -481,7 +481,7 @@ public class PacketParserUtils { } break; case XmlPullParser.TEXT: - xml.append(parser.getText()); + xml.escape(parser.getText()); break; } event = parser.next(); @@ -497,7 +497,12 @@ public class PacketParserUtils { // Only append the text if the parser is not on on an empty element' start tag. Empty elements are reported // twice, so in order to prevent duplication we only add their text when we are on their end tag. if (!(event == XmlPullParser.START_TAG && parser.isEmptyElementTag())) { - sb.append(parser.getText()); + CharSequence text = parser.getText(); + if (event == XmlPullParser.TEXT) { + // TODO the toString() can be removed in Smack 4.2. + text = StringUtils.escapeForXML(text.toString()); + } + sb.append(text); } if (event == XmlPullParser.END_TAG && parser.getDepth() <= depth) { break outerloop; From 3bb06b8429246a46a6c310819bb13130a41fbe82 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Fri, 3 Jul 2015 14:24:13 +0200 Subject: [PATCH 4/8] Wait in Roster's presence listener until Roster is loaded Fixes SMACK-681. --- .../main/java/org/jivesoftware/smack/roster/Roster.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java b/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java index 496fcae4e..ce481c952 100644 --- a/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java +++ b/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java @@ -1180,6 +1180,13 @@ public class Roster extends Manager { @Override public void processPacket(Stanza packet) throws NotConnectedException { + // Try to ensure that the roster is loaded when processing presence stanzas. While the + // presence listener is synchronous, the roster result listener is not, which means that + // the presence listener may be invoked with a not yet loaded roster. + boolean loaded = waitUntilLoaded(); + if (loaded) { + LOGGER.warning("Roster not loaded while processing presence stanza"); + } final XMPPConnection connection = connection(); Presence presence = (Presence) packet; String from = presence.getFrom(); From 0555297a6e52cda5d393509916f8c3281d085de8 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Fri, 3 Jul 2015 14:42:45 +0200 Subject: [PATCH 5/8] Fix Roster.waitUntilLoaded and make it interruptable waitTime and start need to be initialized outside of the while body. --- .../org/jivesoftware/smack/roster/Roster.java | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java b/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java index ce481c952..81d15b3cd 100644 --- a/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java +++ b/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java @@ -303,9 +303,10 @@ public class Roster extends Manager { * * @throws NotLoggedInException * @throws NotConnectedException + * @throws InterruptedException * @since 4.1 */ - public void reloadAndWait() throws NotLoggedInException, NotConnectedException { + public void reloadAndWait() throws NotLoggedInException, NotConnectedException, InterruptedException { reload(); waitUntilLoaded(); } @@ -329,25 +330,18 @@ public class Roster extends Manager { return true; } - protected boolean waitUntilLoaded() { - final XMPPConnection connection = connection(); + protected boolean waitUntilLoaded() throws InterruptedException { + long waitTime = connection().getPacketReplyTimeout(); + long start = System.currentTimeMillis(); while (!loaded) { - long waitTime = connection.getPacketReplyTimeout(); - long start = System.currentTimeMillis(); if (waitTime <= 0) { break; } - try { - synchronized (this) { - if (!loaded) { - wait(waitTime); - } + synchronized (this) { + if (!loaded) { + wait(waitTime); } } - catch (InterruptedException e) { - LOGGER.log(Level.FINE, "interrupted", e); - break; - } long now = System.currentTimeMillis(); waitTime -= now - start; start = now; @@ -1183,7 +1177,14 @@ public class Roster extends Manager { // Try to ensure that the roster is loaded when processing presence stanzas. While the // presence listener is synchronous, the roster result listener is not, which means that // the presence listener may be invoked with a not yet loaded roster. - boolean loaded = waitUntilLoaded(); + boolean loaded; + try { + loaded = waitUntilLoaded(); + } + catch (InterruptedException e) { + LOGGER.log(Level.INFO, "Presence listener was interrupted", e); + loaded = Roster.this.loaded; + } if (loaded) { LOGGER.warning("Roster not loaded while processing presence stanza"); } From 36d99ecab3ac21bbed29383e683c487118eb1512 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Fri, 10 Jul 2015 23:08:35 +0200 Subject: [PATCH 6/8] Fix ChatManager API documentation --- documentation/messaging.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/documentation/messaging.md b/documentation/messaging.md index 3ee5a4b0c..3aa595dae 100644 --- a/documentation/messaging.md +++ b/documentation/messaging.md @@ -17,7 +17,7 @@ and then send them a text message: ``` // Assume we've created an XMPPConnection name "connection"._ -ChatManager chatmanager = connection.getChatManager(); +ChatManager chatmanager = ChatManager.getInstanceFor(connection); Chat newChat = chatmanager.createChat("jsmith@jivesoftware.com", new MessageListener() { public void processMessage(Chat chat, Message message) { System.out.println("Received message: " + message); @@ -72,8 +72,9 @@ when it happens. You can register a message listener to receive all future messages as part of this handler. ``` -_// Assume we've created an XMPPConnection name "connection"._ -ChatManager chatmanager = connection.getChatManager().addChatListener( +// Assume we've created an XMPPConnection name "connection"._ +ChatManager chatManager = ChatManager.getInstanceFor(connection); +chatManager.addChatListener( new ChatManagerListener() { @Override public void chatCreated(Chat chat, boolean createdLocally) From ae944d35462623f006acaa6cca386a9f158fd172 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Fri, 3 Jul 2015 17:35:20 +0200 Subject: [PATCH 7/8] Only wait in Roster's presence listener if loading otherwhise skip waitUntilLoaded(). This introduces RosterState. SMACK-681 --- .../org/jivesoftware/smack/roster/Roster.java | 42 ++++++++++++------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java b/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java index 81d15b3cd..dfaa3ea55 100644 --- a/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java +++ b/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java @@ -145,9 +145,16 @@ public class Roster extends Manager { */ private final Object rosterListenersAndEntriesLock = new Object(); - // The roster is marked as initialized when at least a single roster packet - // has been received and processed. - private boolean loaded = false; + private enum RosterState { + uninitialized, + loading, + loaded, + } + + /** + * The current state of the roster. + */ + private RosterState rosterState = RosterState.uninitialized; private final PresencePacketListener presencePacketListener = new PresencePacketListener(); @@ -290,9 +297,11 @@ public class Roster extends Manager { if (rosterStore != null && isRosterVersioningSupported()) { packet.setVersion(rosterStore.getRosterVersion()); } + rosterState = RosterState.loading; connection.sendIqWithResponseCallback(packet, new RosterResultListener(), new ExceptionCallback() { @Override public void processException(Exception exception) { + rosterState = RosterState.uninitialized; LOGGER.log(Level.SEVERE, "Exception reloading roster" , exception); } }); @@ -333,12 +342,12 @@ public class Roster extends Manager { protected boolean waitUntilLoaded() throws InterruptedException { long waitTime = connection().getPacketReplyTimeout(); long start = System.currentTimeMillis(); - while (!loaded) { + while (!isLoaded()) { if (waitTime <= 0) { break; } synchronized (this) { - if (!loaded) { + if (!isLoaded()) { wait(waitTime); } } @@ -356,7 +365,7 @@ public class Roster extends Manager { * @since 4.1 */ public boolean isLoaded() { - return loaded; + return rosterState == RosterState.loaded; } /** @@ -963,7 +972,7 @@ public class Roster extends Manager { } } } - loaded = false; + rosterState = RosterState.uninitialized; } /** @@ -1177,15 +1186,16 @@ public class Roster extends Manager { // Try to ensure that the roster is loaded when processing presence stanzas. While the // presence listener is synchronous, the roster result listener is not, which means that // the presence listener may be invoked with a not yet loaded roster. - boolean loaded; - try { - loaded = waitUntilLoaded(); + if (rosterState == RosterState.loading) { + try { + waitUntilLoaded(); + } + catch (InterruptedException e) { + LOGGER.log(Level.INFO, "Presence listener was interrupted", e); + + } } - catch (InterruptedException e) { - LOGGER.log(Level.INFO, "Presence listener was interrupted", e); - loaded = Roster.this.loaded; - } - if (loaded) { + if (!isLoaded()) { LOGGER.warning("Roster not loaded while processing presence stanza"); } final XMPPConnection connection = connection(); @@ -1350,7 +1360,7 @@ public class Roster extends Manager { } } - loaded = true; + rosterState = RosterState.loaded; synchronized (Roster.this) { Roster.this.notifyAll(); } From f8d513e37c546ec78719a4c4bd380c7fd842f5bb Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Wed, 15 Jul 2015 09:02:46 +0200 Subject: [PATCH 8/8] Smack 4.1.3 --- resources/releasedocs/changelog.html | 13 +++++++++++++ version.gradle | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/resources/releasedocs/changelog.html b/resources/releasedocs/changelog.html index 7a805d5f5..184c15f70 100644 --- a/resources/releasedocs/changelog.html +++ b/resources/releasedocs/changelog.html @@ -141,6 +141,19 @@ hr {
+

4.1.3 -- 2015-07-15

+ +

Bug +

+
    +
  • [SMACK-679] - Memory leak in Socks5BytestreamManager. Should use weak map for 'managers' +
  • +
  • [SMACK-680] - XHTML bodies are un-escaped after parsing +
  • +
  • [SMACK-681] - Roster presence callbacks may not be invoked right after login +
  • +
+

4.1.2 -- 2015-06-27

Bug diff --git a/version.gradle b/version.gradle index 617ae8444..9ac4f3d96 100644 --- a/version.gradle +++ b/version.gradle @@ -1,7 +1,7 @@ allprojects { ext { shortVersion = '4.1.3' - isSnapshot = true + isSnapshot = false jxmppVersion = '0.4.2-beta1' smackMinAndroidSdk = 8 }