+
3.4.1 -- Feb 9, 2014
+
+
Bug
+
+- [SMACK-540] - Memory leak in MultiUserChat
+
+
+
3.4.0 -- Feb 2, 2014
Bug Fixes
diff --git a/experimental/source/org/jivesoftware/smackx/carbons/CarbonManager.java b/experimental/source/org/jivesoftware/smackx/carbons/CarbonManager.java
index 9217860ce..dc2159925 100644
--- a/experimental/source/org/jivesoftware/smackx/carbons/CarbonManager.java
+++ b/experimental/source/org/jivesoftware/smackx/carbons/CarbonManager.java
@@ -16,6 +16,7 @@
package org.jivesoftware.smackx.carbons;
+import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.Map;
import java.util.WeakHashMap;
@@ -51,18 +52,18 @@ public class CarbonManager {
static {
Connection.addConnectionCreationListener(new ConnectionCreationListener() {
public void connectionCreated(Connection connection) {
- new CarbonManager(connection);
+ getInstanceFor(connection);
}
});
}
- private Connection connection;
+ private WeakReference
weakRefConnection;
private volatile boolean enabled_state = false;
private CarbonManager(Connection connection) {
ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection);
sdm.addFeature(Carbon.NAMESPACE);
- this.connection = connection;
+ weakRefConnection = new WeakReference(connection);
instances.put(connection, this);
}
@@ -73,7 +74,7 @@ public class CarbonManager {
*
* @return a CarbonManager instance
*/
- public static CarbonManager getInstanceFor(Connection connection) {
+ public static synchronized CarbonManager getInstanceFor(Connection connection) {
CarbonManager carbonManager = instances.get(connection);
if (carbonManager == null) {
@@ -99,6 +100,7 @@ public class CarbonManager {
* @return true if supported
*/
public boolean isSupportedByServer() {
+ Connection connection = weakRefConnection.get();
try {
DiscoverInfo result = ServiceDiscoveryManager
.getInstanceFor(connection).discoverInfo(connection.getServiceName());
@@ -118,6 +120,7 @@ public class CarbonManager {
* @param new_state whether carbons should be enabled or disabled
*/
public void sendCarbonsEnabled(final boolean new_state) {
+ final Connection connection = weakRefConnection.get();
IQ setIQ = carbonsEnabledIQ(new_state);
connection.addPacketListener(new PacketListener() {
@@ -148,6 +151,7 @@ public class CarbonManager {
if (enabled_state == new_state)
return true;
+ Connection connection = weakRefConnection.get();
IQ setIQ = carbonsEnabledIQ(new_state);
PacketCollector collector =
diff --git a/source/org/jivesoftware/smack/keepalive/KeepAliveManager.java b/source/org/jivesoftware/smack/keepalive/KeepAliveManager.java
index 254a0419b..3560bc1c3 100644
--- a/source/org/jivesoftware/smack/keepalive/KeepAliveManager.java
+++ b/source/org/jivesoftware/smack/keepalive/KeepAliveManager.java
@@ -16,12 +16,12 @@
package org.jivesoftware.smack.keepalive;
+import java.lang.ref.WeakReference;
import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
+import java.util.WeakHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
@@ -52,7 +52,7 @@ import org.jivesoftware.smack.ping.packet.Ping;
* @author Florian Schmaus
*/
public class KeepAliveManager {
- private static Map instances = new HashMap();
+ private static Map instances = Collections.synchronizedMap(new WeakHashMap());
private static volatile ScheduledExecutorService periodicPingExecutorService;
static {
@@ -65,7 +65,7 @@ public class KeepAliveManager {
}
}
- private Connection connection;
+ private WeakReference weakRefConnection;
private long pingInterval = SmackConfiguration.getKeepAliveInterval();
private Set pingFailedListeners = Collections.synchronizedSet(new HashSet());
private volatile ScheduledFuture> periodicPingTask;
@@ -120,40 +120,21 @@ public class KeepAliveManager {
}
private KeepAliveManager(Connection connection) {
- this.connection = connection;
- init();
- handleConnect();
- }
+ weakRefConnection = new WeakReference(connection);
- /*
- * Call after every connection to add the packet listener.
- */
- private void handleConnect() {
- // Listen for all incoming packets and reset the scheduled ping whenever
- // one arrives.
- connection.addPacketListener(new PacketListener() {
-
- @Override
- public void processPacket(Packet packet) {
- // reschedule the ping based on this last server contact
- lastSuccessfulContact = System.currentTimeMillis();
- schedulePingServerTask();
- }
- }, null);
- }
-
- private void init() {
connection.addConnectionListener(new ConnectionListener() {
@Override
public void connectionClosed() {
stopPingServerTask();
+ Connection connection = weakRefConnection.get();
handleDisconnect(connection);
}
@Override
public void connectionClosedOnError(Exception arg0) {
stopPingServerTask();
+ Connection connection = weakRefConnection.get();
handleDisconnect(connection);
}
@@ -174,6 +155,25 @@ public class KeepAliveManager {
instances.put(connection, this);
schedulePingServerTask();
+ handleConnect();
+ }
+
+ /*
+ * Call after every connection to add the packet listener.
+ */
+ private void handleConnect() {
+ Connection connection = weakRefConnection.get();
+ // Listen for all incoming packets and reset the scheduled ping whenever
+ // one arrives.
+ connection.addPacketListener(new PacketListener() {
+
+ @Override
+ public void processPacket(Packet packet) {
+ // reschedule the ping based on this last server contact
+ lastSuccessfulContact = System.currentTimeMillis();
+ schedulePingServerTask();
+ }
+ }, null);
}
/**
@@ -276,6 +276,7 @@ public class KeepAliveManager {
public void run() {
Ping ping = new Ping();
PacketFilter responseFilter = new PacketIDFilter(ping.getPacketID());
+ Connection connection = weakRefConnection.get();
final PacketCollector response = pingFailedListeners.isEmpty() ? null : connection.createPacketCollector(responseFilter);
connection.sendPacket(ping);
diff --git a/source/org/jivesoftware/smackx/MessageEventManager.java b/source/org/jivesoftware/smackx/MessageEventManager.java
index 900914b3d..7ad7adfeb 100644
--- a/source/org/jivesoftware/smackx/MessageEventManager.java
+++ b/source/org/jivesoftware/smackx/MessageEventManager.java
@@ -20,7 +20,6 @@
package org.jivesoftware.smackx;
-import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
diff --git a/source/org/jivesoftware/smackx/muc/MultiUserChat.java b/source/org/jivesoftware/smackx/muc/MultiUserChat.java
index db8a80f73..85d1aa8e1 100644
--- a/source/org/jivesoftware/smackx/muc/MultiUserChat.java
+++ b/source/org/jivesoftware/smackx/muc/MultiUserChat.java
@@ -27,6 +27,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
@@ -116,12 +117,16 @@ public class MultiUserChat {
// Chat protocol. This information will be used when another client tries to
// discover whether this client supports MUC or not.
ServiceDiscoveryManager.getInstanceFor(connection).addFeature(discoNamespace);
+
// Set the NodeInformationProvider that will provide information about the
// joined rooms whenever a disco request is received
+ final WeakReference weakRefConnection = new WeakReference(connection);
ServiceDiscoveryManager.getInstanceFor(connection).setNodeInformationProvider(
discoNode,
new NodeInformationProvider() {
public List getNodeItems() {
+ Connection connection = weakRefConnection.get();
+ if (connection == null) return new LinkedList();
List answer = new ArrayList();
Iterator rooms=MultiUserChat.getJoinedRooms(connection);
while (rooms.hasNext()) {
diff --git a/source/org/jivesoftware/smackx/ping/PingManager.java b/source/org/jivesoftware/smackx/ping/PingManager.java
index 068206698..4c34f9223 100644
--- a/source/org/jivesoftware/smackx/ping/PingManager.java
+++ b/source/org/jivesoftware/smackx/ping/PingManager.java
@@ -16,6 +16,7 @@
package org.jivesoftware.smackx.ping;
+import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.Map;
import java.util.WeakHashMap;
@@ -65,7 +66,7 @@ public class PingManager {
});
}
- private Connection connection;
+ private WeakReference weakRefConnection;
/**
* Retrieves a {@link PingManager} for the specified {@link Connection}, creating one if it doesn't already
@@ -84,8 +85,8 @@ public class PingManager {
return pingManager;
}
- private PingManager(Connection con) {
- this.connection = con;
+ private PingManager(Connection connection) {
+ weakRefConnection = new WeakReference(connection);
ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection);
// The ServiceDiscoveryManager was not pre-initialized
@@ -101,6 +102,7 @@ public class PingManager {
* Sends a Pong for every Ping
*/
public void processPacket(Packet packet) {
+ Connection connection = weakRefConnection.get();
IQ pong = IQ.createResultIQ((Ping) packet);
connection.sendPacket(pong);
}
@@ -121,7 +123,7 @@ public class PingManager {
*/
public boolean ping(String jid, long pingTimeout) {
Ping ping = new Ping(jid);
-
+ Connection connection = weakRefConnection.get();
try {
SyncPacketSend.getReply(connection, ping);
}
@@ -151,6 +153,7 @@ public class PingManager {
* @throws XMPPException An XMPP related error occurred during the request
*/
public boolean isPingSupported(String jid) throws XMPPException {
+ Connection connection = weakRefConnection.get();
DiscoverInfo result = ServiceDiscoveryManager.getInstanceFor(connection).discoverInfo(jid);
return result.containsFeature(Ping.NAMESPACE);
}
@@ -165,6 +168,7 @@ public class PingManager {
* @return true if a reply was received from the server, false otherwise.
*/
public boolean pingMyServer() {
+ Connection connection = weakRefConnection.get();
return ping(connection.getServiceName());
}
}
diff --git a/source/org/jivesoftware/smackx/receipts/DeliveryReceiptManager.java b/source/org/jivesoftware/smackx/receipts/DeliveryReceiptManager.java
index 0b4a6aae6..e628b20e5 100644
--- a/source/org/jivesoftware/smackx/receipts/DeliveryReceiptManager.java
+++ b/source/org/jivesoftware/smackx/receipts/DeliveryReceiptManager.java
@@ -16,6 +16,7 @@
package org.jivesoftware.smackx.receipts;
+import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
@@ -52,7 +53,7 @@ public class DeliveryReceiptManager implements PacketListener {
});
}
- private Connection connection;
+ private WeakReference weakRefConnection;
private boolean auto_receipts_enabled = false;
private Set receiptReceivedListeners = Collections
.synchronizedSet(new HashSet());
@@ -60,7 +61,7 @@ public class DeliveryReceiptManager implements PacketListener {
private DeliveryReceiptManager(Connection connection) {
ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection);
sdm.addFeature(DeliveryReceipt.NAMESPACE);
- this.connection = connection;
+ weakRefConnection = new WeakReference(connection);
instances.put(connection, this);
// register listener for delivery receipts and requests
@@ -91,6 +92,7 @@ public class DeliveryReceiptManager implements PacketListener {
* @return true if supported
*/
public boolean isSupported(String jid) {
+ Connection connection = weakRefConnection.get();
try {
DiscoverInfo result =
ServiceDiscoveryManager.getInstanceFor(connection).discoverInfo(jid);
@@ -119,6 +121,7 @@ public class DeliveryReceiptManager implements PacketListener {
DeliveryReceiptRequest drr = (DeliveryReceiptRequest)packet.getExtension(
DeliveryReceiptRequest.ELEMENT, DeliveryReceipt.NAMESPACE);
if (drr != null) {
+ Connection connection = weakRefConnection.get();
Message ack = new Message(packet.getFrom(), Message.Type.normal);
ack.addExtension(new DeliveryReceipt(packet.getPacketID()));
connection.sendPacket(ack);