diff --git a/smack-core/src/main/java/org/jivesoftware/smack/util/CleaningWeakReferenceMap.java b/smack-core/src/main/java/org/jivesoftware/smack/util/CleaningWeakReferenceMap.java new file mode 100644 index 000000000..fb16de964 --- /dev/null +++ b/smack-core/src/main/java/org/jivesoftware/smack/util/CleaningWeakReferenceMap.java @@ -0,0 +1,94 @@ +/** + * + * Copyright the original author or authors + * + * 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.util; + +import java.lang.ref.WeakReference; +import java.util.HashMap; +import java.util.Iterator; + +/** + * Extends a {@link HashMap} with {@link WeakReference} values, so that + * weak references which have been cleared are periodically removed from + * the map. The cleaning occurs as part of {@link #put}, after a specific + * number ({@link #cleanInterval}) of calls to {@link #put}. + * + * @param The key type. + * @param The value type. + * + * @author Boris Grozev + */ +public class CleaningWeakReferenceMap + extends HashMap> { + private static final long serialVersionUID = 0L; + + /** + * The number of calls to {@link #put} after which to clean this map + * (i.e. remove cleared {@link WeakReference}s from it). + */ + private final int cleanInterval; + + /** + * The number of times {@link #put} has been called on this instance + * since the last time it was {@link #clean}ed. + */ + private int numberOfInsertsSinceLastClean = 0; + + /** + * Initializes a new {@link CleaningWeakReferenceMap} instance with the + * default clean interval. + */ + public CleaningWeakReferenceMap() { + this(50); + } + + /** + * Initializes a new {@link CleaningWeakReferenceMap} instance with a given + * clean interval. + * @param cleanInterval the number of calls to {@link #put} after which the + * map will clean itself. + */ + public CleaningWeakReferenceMap(int cleanInterval) { + this.cleanInterval = cleanInterval; + } + + @Override + public WeakReference put(K key, WeakReference value) { + WeakReference ret = super.put(key, value); + + if (numberOfInsertsSinceLastClean++ > cleanInterval) { + numberOfInsertsSinceLastClean = 0; + clean(); + } + + return ret; + } + + /** + * Removes all cleared entries from this map (i.e. entries whose value + * is a cleared {@link WeakReference}). + */ + private void clean() { + Iterator>> iter = entrySet().iterator(); + while (iter.hasNext()) { + Entry> e = iter.next(); + if (e != null && e.getValue() != null + && e.getValue().get() == null) { + iter.remove(); + } + } + } +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java index cdf1adc50..598fe68e4 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java @@ -764,6 +764,11 @@ public class MultiUserChat { // throw. userHasLeft(); + final EntityFullJid myRoomJid = this.myRoomJid; + if (myRoomJid == null) { + return; + } + // We leave a room by sending a presence packet where the "to" // field is in the form "roomName@service/nickname" Presence leavePresence = new Presence(Presence.Type.unavailable); diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatManager.java index a627ada6a..8c5a98ccd 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatManager.java @@ -19,7 +19,6 @@ package org.jivesoftware.smackx.muc; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -46,6 +45,7 @@ import org.jivesoftware.smack.filter.StanzaTypeFilter; import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smack.util.Async; +import org.jivesoftware.smack.util.CleaningWeakReferenceMap; import org.jivesoftware.smackx.disco.AbstractNodeInformationProvider; import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; @@ -144,7 +144,7 @@ public final class MultiUserChatManager extends Manager { * those instances to get garbage collected. Note that MultiUserChat instances can not get garbage collected while * the user is joined, because then the MUC will have PacketListeners added to the XMPPConnection. */ - private final Map> multiUserChats = new HashMap<>(); + private final Map> multiUserChats = new CleaningWeakReferenceMap<>(); private boolean autoJoinOnReconnect;