mirror of
https://github.com/vanitasvitae/Smack.git
synced 2024-10-31 17:25:58 +01:00
Option to automatically rejoin MUC rooms after reconnection
Fixes SMACK-572.
This commit is contained in:
parent
6cf3ad32f9
commit
5bb0c8c223
2 changed files with 124 additions and 0 deletions
|
@ -0,0 +1,29 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright 2016 Florian Schmaus
|
||||||
|
*
|
||||||
|
* 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.muc;
|
||||||
|
|
||||||
|
public interface AutoJoinFailedCallback {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoked if the automatic rejoin rooms on reconnect failed.
|
||||||
|
*
|
||||||
|
* @param muc the MultiUserChat which failed first.
|
||||||
|
* @param e the exception causing the failure.
|
||||||
|
*/
|
||||||
|
void autoJoinFailed(MultiUserChat muc, Exception e);
|
||||||
|
|
||||||
|
}
|
|
@ -26,8 +26,10 @@ import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
import java.util.concurrent.CopyOnWriteArraySet;
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.AbstractConnectionListener;
|
||||||
import org.jivesoftware.smack.ConnectionCreationListener;
|
import org.jivesoftware.smack.ConnectionCreationListener;
|
||||||
import org.jivesoftware.smack.Manager;
|
import org.jivesoftware.smack.Manager;
|
||||||
import org.jivesoftware.smack.StanzaListener;
|
import org.jivesoftware.smack.StanzaListener;
|
||||||
|
@ -44,6 +46,7 @@ import org.jivesoftware.smack.filter.NotFilter;
|
||||||
import org.jivesoftware.smack.filter.StanzaTypeFilter;
|
import org.jivesoftware.smack.filter.StanzaTypeFilter;
|
||||||
import org.jivesoftware.smack.packet.Message;
|
import org.jivesoftware.smack.packet.Message;
|
||||||
import org.jivesoftware.smack.packet.Stanza;
|
import org.jivesoftware.smack.packet.Stanza;
|
||||||
|
import org.jivesoftware.smack.util.Async;
|
||||||
import org.jivesoftware.smackx.disco.AbstractNodeInformationProvider;
|
import org.jivesoftware.smackx.disco.AbstractNodeInformationProvider;
|
||||||
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
|
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
|
||||||
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
|
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
|
||||||
|
@ -55,8 +58,24 @@ import org.jxmpp.jid.EntityBareJid;
|
||||||
import org.jxmpp.jid.EntityFullJid;
|
import org.jxmpp.jid.EntityFullJid;
|
||||||
import org.jxmpp.jid.DomainBareJid;
|
import org.jxmpp.jid.DomainBareJid;
|
||||||
import org.jxmpp.jid.Jid;
|
import org.jxmpp.jid.Jid;
|
||||||
|
import org.jxmpp.jid.parts.Resourcepart;
|
||||||
import org.jxmpp.jid.EntityJid;
|
import org.jxmpp.jid.EntityJid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A manager for Multi-User Chat rooms.
|
||||||
|
* <p>
|
||||||
|
* Use {@link #getMultiUserChat(EntityBareJid)} to retrieve an object representing a Multi-User Chat room.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* <b>Automatic rejoin:</b> The manager supports automatic rejoin of MultiUserChat rooms once the connection got
|
||||||
|
* re-established. This mechanism is disabled by default. To enable it, use {@link #setAutoJoinOnReconnect(boolean)}.
|
||||||
|
* You can set a {@link AutoJoinFailedCallback} via {@link #setAutoJoinFailedCallback(AutoJoinFailedCallback)} to get
|
||||||
|
* notified if this mechanism failed for some reason. Note that as soon as rejoining for a single room failed, no
|
||||||
|
* further attempts will be made for the other rooms.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @see <a href="http://xmpp.org/extensions/xep-0045.html">XEP-0045: Multi-User Chat</a>
|
||||||
|
*/
|
||||||
public final class MultiUserChatManager extends Manager {
|
public final class MultiUserChatManager extends Manager {
|
||||||
private final static String DISCO_NODE = MUCInitialPresence.NAMESPACE + "#rooms";
|
private final static String DISCO_NODE = MUCInitialPresence.NAMESPACE + "#rooms";
|
||||||
|
|
||||||
|
@ -122,6 +141,10 @@ public final class MultiUserChatManager extends Manager {
|
||||||
*/
|
*/
|
||||||
private final Map<EntityBareJid, WeakReference<MultiUserChat>> multiUserChats = new HashMap<>();
|
private final Map<EntityBareJid, WeakReference<MultiUserChat>> multiUserChats = new HashMap<>();
|
||||||
|
|
||||||
|
private boolean autoJoinOnReconnect;
|
||||||
|
|
||||||
|
private AutoJoinFailedCallback autoJoinFailedCallback;
|
||||||
|
|
||||||
private MultiUserChatManager(XMPPConnection connection) {
|
private MultiUserChatManager(XMPPConnection connection) {
|
||||||
super(connection);
|
super(connection);
|
||||||
// Listens for all messages that include a MUCUser extension and fire the invitation
|
// Listens for all messages that include a MUCUser extension and fire the invitation
|
||||||
|
@ -152,6 +175,55 @@ public final class MultiUserChatManager extends Manager {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
connection.addAsyncStanzaListener(invitationPacketListener, INVITATION_FILTER);
|
connection.addAsyncStanzaListener(invitationPacketListener, INVITATION_FILTER);
|
||||||
|
|
||||||
|
connection.addConnectionListener(new AbstractConnectionListener() {
|
||||||
|
@Override
|
||||||
|
public void authenticated(XMPPConnection connection, boolean resumed) {
|
||||||
|
if (resumed) return;
|
||||||
|
if (!autoJoinOnReconnect) return;
|
||||||
|
|
||||||
|
final Set<EntityBareJid> mucs = getJoinedRooms();
|
||||||
|
if (mucs.isEmpty()) return;
|
||||||
|
|
||||||
|
Async.go(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
final AutoJoinFailedCallback failedCallback = autoJoinFailedCallback;
|
||||||
|
for (EntityBareJid mucJid : mucs) {
|
||||||
|
MultiUserChat muc = getMultiUserChat(mucJid);
|
||||||
|
|
||||||
|
if (!muc.isJoined()) return;
|
||||||
|
|
||||||
|
Resourcepart nickname = muc.getNickname();
|
||||||
|
if (nickname == null) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
muc.leave();
|
||||||
|
} catch (NotConnectedException | InterruptedException e) {
|
||||||
|
if (failedCallback != null) {
|
||||||
|
failedCallback.autoJoinFailed(muc, e);
|
||||||
|
} else {
|
||||||
|
LOGGER.log(Level.WARNING, "Could not leave room", e);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
muc.join(nickname);
|
||||||
|
} catch (NotAMucServiceException | NoResponseException | XMPPErrorException
|
||||||
|
| NotConnectedException | InterruptedException e) {
|
||||||
|
if (failedCallback != null) {
|
||||||
|
failedCallback.autoJoinFailed(muc, e);
|
||||||
|
} else {
|
||||||
|
LOGGER.log(Level.WARNING, "Could not leave room", e);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -354,6 +426,29 @@ public final class MultiUserChatManager extends Manager {
|
||||||
invitationsListeners.remove(listener);
|
invitationsListeners.remove(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If automatic join on reconnect is enabled, then the manager will try to auto join MUC rooms after the connection
|
||||||
|
* got re-established.
|
||||||
|
*
|
||||||
|
* @param autoJoin <code>true</code> to enable, <code>false</code> to disable.
|
||||||
|
*/
|
||||||
|
public void setAutoJoinOnReconnect(boolean autoJoin) {
|
||||||
|
autoJoinOnReconnect = autoJoin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a callback invoked by this manager when automatic join on reconnect failed. If failedCallback is not
|
||||||
|
* <code>null</code>,then automatic rejoin get also enabled.
|
||||||
|
*
|
||||||
|
* @param failedCallback the callback.
|
||||||
|
*/
|
||||||
|
public void setAutoJoinFailedCallback(AutoJoinFailedCallback failedCallback) {
|
||||||
|
autoJoinFailedCallback = failedCallback;
|
||||||
|
if (failedCallback != null) {
|
||||||
|
setAutoJoinOnReconnect(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void addJoinedRoom(EntityBareJid room) {
|
void addJoinedRoom(EntityBareJid room) {
|
||||||
joinedRooms.add(room);
|
joinedRooms.add(room);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue