1
0
Fork 0
mirror of https://github.com/vanitasvitae/Smack.git synced 2025-12-14 06:51:08 +01:00

Add MucBookmarkAutojoinManager

Also add MucConfigFormManager and improve the MUC API (SMACK-648). Bump
to jxmpp 0.5.0-alpha3.

Improve and extend PrivateDataManager and BookmarkManager.
This commit is contained in:
Florian Schmaus 2015-04-21 19:05:22 +02:00
parent 265e5c69d5
commit f274581c27
15 changed files with 690 additions and 102 deletions

View file

@ -0,0 +1,116 @@
/**
*
* Copyright 2015 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;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.jivesoftware.smack.SmackException.NoResponseException;
import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.muc.MultiUserChatException.MucConfigurationNotSupported;
import org.jivesoftware.smackx.xdata.Form;
import org.jivesoftware.smackx.xdata.FormField;
import org.jxmpp.jid.Jid;
import org.jxmpp.jid.util.JidUtil;
/**
* Multi-User Chat configuration form manager is used to fill out and submit a {@link Form} used to
* configure rooms.
* <p>
* Room configuration needs either be done right after the room is created and still locked. Or at
* any later point (see <a href="http://xmpp.org/extensions/xep-0045.html#roomconfig">XEP-45 § 10.2
* Subsequent Room Configuration</a>). When done with the configuration, call
* {@link #submitConfigurationForm()}.
* </p>
* <p>
* The manager may not provide all possible configuration options. If you want direct access to the
* configuraiton form, use {@link MultiUserChat#getConfigurationForm()} and
* {@link MultiUserChat#sendConfigurationForm(Form)}.
* </p>
*/
public class MucConfigFormManager {
public static final String MUC_ROOMCONFIG_ROOMOWNERS = "muc#roomconfig_roomowners";
private final MultiUserChat multiUserChat;
private final Form answerForm;
private final List<Jid> owners;
/**
* Create a new MUC config form manager.
* <p>
* Note that the answerForm needs to be filled out with the defaults.
* </p>
*
* @param multiUserChat the MUC for this configuration form.
* @throws InterruptedException
* @throws NotConnectedException
* @throws XMPPErrorException
* @throws NoResponseException
*/
MucConfigFormManager(MultiUserChat multiUserChat) throws NoResponseException,
XMPPErrorException, NotConnectedException, InterruptedException {
this.multiUserChat = multiUserChat;
// Set the answer form
Form configForm = multiUserChat.getConfigurationForm();
this.answerForm = configForm.createAnswerForm();
// Add the default answers to the form to submit
for (FormField field : configForm.getFields()) {
if (field.getType() == FormField.Type.hidden
|| StringUtils.isNullOrEmpty(field.getVariable())) {
continue;
}
answerForm.setDefaultAnswer(field.getVariable());
}
// Set the local variables according to the fields found in the answer form
if (answerForm.hasField(MUC_ROOMCONFIG_ROOMOWNERS)) {
// Set 'owners' to the currently configured owners
List<String> ownerStrings = answerForm.getField(MUC_ROOMCONFIG_ROOMOWNERS).getValues();
owners = new ArrayList<>(ownerStrings.size());
JidUtil.jidsFrom(ownerStrings, owners, null);
}
else {
// roomowners not supported, this should barely be the case
owners = null;
}
}
public boolean supportsRoomOwners() {
return owners != null;
}
public MucConfigFormManager setRoomOwners(Collection<? extends Jid> newOwners) throws MucConfigurationNotSupported {
if (!supportsRoomOwners()) {
throw new MucConfigurationNotSupported(MUC_ROOMCONFIG_ROOMOWNERS);
}
owners.clear();
owners.addAll(newOwners);
return this;
}
public void submitConfigurationForm() throws NoResponseException, XMPPErrorException, NotConnectedException,
InterruptedException {
if (owners != null) {
answerForm.setAnswer(MUC_ROOMCONFIG_ROOMOWNERS, JidUtil.toStringList(owners));
}
multiUserChat.sendConfigurationForm(answerForm);
}
}

View file

@ -57,6 +57,9 @@ import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
import org.jivesoftware.smackx.iqregister.packet.Registration;
import org.jivesoftware.smackx.muc.MultiUserChatException.MucAlreadyJoinedException;
import org.jivesoftware.smackx.muc.MultiUserChatException.MucNotJoinedException;
import org.jivesoftware.smackx.muc.MultiUserChatException.MissingMucCreationAcknowledgeException;
import org.jivesoftware.smackx.muc.packet.Destroy;
import org.jivesoftware.smackx.muc.packet.MUCAdmin;
import org.jivesoftware.smackx.muc.packet.MUCInitialPresence;
@ -354,25 +357,30 @@ public class MultiUserChat {
* the room. {@link #sendConfigurationForm(Form)}
*
* @param nickname the nickname to use.
* @return a handle to the MUC create configuration form API.
* @throws XMPPErrorException if the room couldn't be created for some reason (e.g. 405 error if
* the user is not allowed to create the room)
* @throws NoResponseException if there was no response from the server.
* @throws SmackException If the creation failed because of a missing acknowledge from the
* server, e.g. because the room already existed.
* @throws InterruptedException
* @throws NotConnectedException
* @throws MucAlreadyJoinedException
* @throws MissingMucCreationAcknowledgeException
*/
public synchronized void create(Resourcepart nickname) throws NoResponseException, XMPPErrorException, SmackException, InterruptedException {
public synchronized MucCreateConfigFormHandle create(Resourcepart nickname) throws NoResponseException,
XMPPErrorException, InterruptedException, MucAlreadyJoinedException,
NotConnectedException, MissingMucCreationAcknowledgeException {
if (joined) {
throw new IllegalStateException("Creation failed - User already joined the room.");
throw new MucAlreadyJoinedException();
}
if (createOrJoin(nickname)) {
MucCreateConfigFormHandle mucCreateConfigFormHandle = createOrJoin(nickname);
if (mucCreateConfigFormHandle != null) {
// We successfully created a new room
return;
return mucCreateConfigFormHandle;
}
// We need to leave the room since it seems that the room already existed
leave();
throw new SmackException("Creation failed - Missing acknowledge of room creation.");
throw new MissingMucCreationAcknowledgeException();
}
/**
@ -380,15 +388,16 @@ public class MultiUserChat {
* discussion history and using the connections default reply timeout.
*
* @param nickname
* @return true if the room creation was acknowledged by the service, false otherwise.
* @return A {@link MucCreateConfigFormHandle} if the room was created, or {code null} if the room was joined.
* @throws NoResponseException
* @throws XMPPErrorException
* @throws SmackException
* @throws InterruptedException
* @throws NotConnectedException
* @throws MucAlreadyJoinedException
* @see #createOrJoin(Resourcepart, String, DiscussionHistory, long)
*/
public synchronized boolean createOrJoin(Resourcepart nickname) throws NoResponseException, XMPPErrorException,
SmackException, InterruptedException {
public synchronized MucCreateConfigFormHandle createOrJoin(Resourcepart nickname) throws NoResponseException, XMPPErrorException,
InterruptedException, MucAlreadyJoinedException, NotConnectedException {
return createOrJoin(nickname, null, null, connection.getPacketReplyTimeout());
}
@ -402,16 +411,18 @@ public class MultiUserChat {
* @param password the password to use.
* @param history the amount of discussion history to receive while joining a room.
* @param timeout the amount of time to wait for a reply from the MUC service(in milliseconds).
* @return true if the room creation was acknowledged by the service, false otherwise.
* @return A {@link MucCreateConfigFormHandle} if the room was created, or {code null} if the room was joined.
* @throws XMPPErrorException if the room couldn't be created for some reason (e.g. 405 error if
* the user is not allowed to create the room)
* @throws NoResponseException if there was no response from the server.
* @throws InterruptedException
* @throws MucAlreadyJoinedException if the MUC is already joined
* @throws NotConnectedException
*/
public synchronized boolean createOrJoin(Resourcepart nickname, String password, DiscussionHistory history, long timeout)
throws NoResponseException, XMPPErrorException, SmackException, InterruptedException {
public synchronized MucCreateConfigFormHandle createOrJoin(Resourcepart nickname, String password, DiscussionHistory history, long timeout)
throws NoResponseException, XMPPErrorException, InterruptedException, MucAlreadyJoinedException, NotConnectedException {
if (joined) {
throw new IllegalStateException("Creation failed - User already joined the room.");
throw new MucAlreadyJoinedException();
}
Presence presence = enter(nickname, password, history, timeout);
@ -420,9 +431,78 @@ public class MultiUserChat {
MUCUser mucUser = MUCUser.from(presence);
if (mucUser != null && mucUser.getStatus().contains(Status.ROOM_CREATED_201)) {
// Room was created and the user has joined the room
return true;
return new MucCreateConfigFormHandle();
}
return null;
}
/**
* A handle used to configure a newly created room. As long as the room is not configured it will be locked, which
* means that no one is able to join. The room will become unlocked as soon it got configured. In order to create an
* instant room, use {@link #makeInstant()}.
* <p>
* For advanced configuration options, use {@link MultiUserChat#getConfigurationForm()}, get the answer form with
* {@link Form#createAnswerForm()}, fill it out and send it back to the room with
* {@link MultiUserChat#sendConfigurationForm(Form)}.
* </p>
*/
public class MucCreateConfigFormHandle {
/**
* Create an instant room. The default configuration will be accepted and the room will become unlocked, i.e.
* other users are able to join.
*
* @throws NoResponseException
* @throws XMPPErrorException
* @throws NotConnectedException
* @throws InterruptedException
* @see <a href="http://www.xmpp.org/extensions/xep-0045.html#createroom-instant">XEP-45 § 10.1.2 Creating an
* Instant Room</a>
*/
public void makeInstant() throws NoResponseException, XMPPErrorException, NotConnectedException,
InterruptedException {
sendConfigurationForm(new Form(DataForm.Type.submit));
}
/**
* Alias for {@link MultiUserChat#getConfigFormManager()}.
*
* @return a MUC configuration form manager for this room.
* @throws NoResponseException
* @throws XMPPErrorException
* @throws NotConnectedException
* @throws InterruptedException
* @see MultiUserChat#getConfigFormManager()
*/
public MucConfigFormManager getConfigFormManager() throws NoResponseException,
XMPPErrorException, NotConnectedException, InterruptedException {
return MultiUserChat.this.getConfigFormManager();
}
}
/**
* Create or join a MUC if it is necessary, i.e. if not the MUC is not already joined.
*
* @param nickname the required nickname to use.
* @param password the optional password required to join
* @return A {@link MucCreateConfigFormHandle} if the room was created, or {code null} if the room was joined.
* @throws NoResponseException
* @throws XMPPErrorException
* @throws NotConnectedException
* @throws InterruptedException
*/
public MucCreateConfigFormHandle createOrJoinIfNecessary(Resourcepart nickname, String password) throws NoResponseException,
XMPPErrorException, NotConnectedException, InterruptedException {
if (isJoined()) {
return null;
}
try {
return createOrJoin(nickname, password, null, connection.getPacketReplyTimeout());
}
catch (MucAlreadyJoinedException e) {
return null;
}
return false;
}
/**
@ -466,10 +546,11 @@ public class MultiUserChat {
* 404 error can occur if the room does not exist or is locked; or a
* 407 error can occur if user is not on the member list; or a
* 409 error can occur if someone is already in the group chat with the same nickname.
* @throws SmackException if there was no response from the server.
* @throws InterruptedException
* @throws NotConnectedException
* @throws NoResponseException if there was no response from the server.
*/
public void join(Resourcepart nickname, String password) throws XMPPErrorException, SmackException, InterruptedException {
public void join(Resourcepart nickname, String password) throws XMPPErrorException, InterruptedException, NoResponseException, NotConnectedException {
join(nickname, password, null, connection.getPacketReplyTimeout());
}
@ -547,6 +628,25 @@ public class MultiUserChat {
userHasLeft();
}
/**
* Get a {@link MucConfigFormManager} to configure this room.
* <p>
* Only room owners are able to configure a room.
* </p>
*
* @return a MUC configuration form manager for this room.
* @throws NoResponseException
* @throws XMPPErrorException
* @throws NotConnectedException
* @throws InterruptedException
* @see <a href="http://xmpp.org/extensions/xep-0045.html#roomconfig">XEP-45 § 10.2 Subsequent Room Configuration</a>
* @since 4.2
*/
public MucConfigFormManager getConfigFormManager() throws NoResponseException,
XMPPErrorException, NotConnectedException, InterruptedException {
return new MucConfigFormManager(this);
}
/**
* Returns the room's configuration form that the room's owner can use or <tt>null</tt> if
* no configuration is possible. The configuration form allows to set the room's language,
@ -570,14 +670,13 @@ public class MultiUserChat {
/**
* Sends the completed configuration form to the server. The room will be configured
* with the new settings defined in the form. If the form is empty then the server
* will create an instant room (will use default configuration).
* with the new settings defined in the form.
*
* @param form the form with the new settings.
* @throws XMPPErrorException if an error occurs setting the new rooms' configuration.
* @throws NoResponseException if there was no response from the server.
* @throws NotConnectedException
* @throws InterruptedException
* @throws InterruptedException
*/
public void sendConfigurationForm(Form form) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
MUCOwner iq = new MUCOwner();
@ -868,13 +967,14 @@ public class MultiUserChat {
* @throws NoResponseException if there was no response from the server.
* @throws NotConnectedException
* @throws InterruptedException
* @throws MucNotJoinedException
*/
public void changeNickname(Resourcepart nickname) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
public void changeNickname(Resourcepart nickname) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException, MucNotJoinedException {
StringUtils.requireNotNullOrEmpty(nickname, "Nickname must not be null or blank.");
// Check that we already have joined the room before attempting to change the
// nickname.
if (!joined) {
throw new IllegalStateException("Must be logged into the room to change nickname.");
throw new MucNotJoinedException(this);
}
final FullJid jid = JidCreate.fullFrom(room, nickname);
// We change the nickname by sending a presence packet where the "to"
@ -905,14 +1005,14 @@ public class MultiUserChat {
* @param mode the mode type for the presence update.
* @throws NotConnectedException
* @throws InterruptedException
* @throws MucNotJoinedException
*/
public void changeAvailabilityStatus(String status, Presence.Mode mode) throws NotConnectedException, InterruptedException {
public void changeAvailabilityStatus(String status, Presence.Mode mode) throws NotConnectedException, InterruptedException, MucNotJoinedException {
StringUtils.requireNotNullOrEmpty(nickname, "Nickname must not be null or blank.");
// Check that we already have joined the room before attempting to change the
// availability status.
if (!joined) {
throw new IllegalStateException(
"Must be logged into the room to change the " + "availability status.");
throw new MucNotJoinedException(this);
}
// We change the availability status by sending a presence packet to the room with the
// new presence status and mode
@ -1689,11 +1789,11 @@ public class MultiUserChat {
*
* @return the next message if one is immediately available and
* <tt>null</tt> otherwise.
* @throws MUCNotJoinedException
* @throws MucNotJoinedException
*/
public Message pollMessage() throws MUCNotJoinedException {
public Message pollMessage() throws MucNotJoinedException {
if (messageCollector == null) {
throw new MUCNotJoinedException(this);
throw new MucNotJoinedException(this);
}
return messageCollector.pollResult();
}
@ -1703,12 +1803,12 @@ public class MultiUserChat {
* (not return) until a message is available.
*
* @return the next message.
* @throws MUCNotJoinedException
* @throws MucNotJoinedException
* @throws InterruptedException
*/
public Message nextMessage() throws MUCNotJoinedException, InterruptedException {
public Message nextMessage() throws MucNotJoinedException, InterruptedException {
if (messageCollector == null) {
throw new MUCNotJoinedException(this);
throw new MucNotJoinedException(this);
}
return messageCollector.nextResult();
}
@ -1721,12 +1821,12 @@ public class MultiUserChat {
* @param timeout the maximum amount of time to wait for the next message.
* @return the next message, or <tt>null</tt> if the timeout elapses without a
* message becoming available.
* @throws MUCNotJoinedException
* @throws MucNotJoinedException
* @throws InterruptedException
*/
public Message nextMessage(long timeout) throws MUCNotJoinedException, InterruptedException {
public Message nextMessage(long timeout) throws MucNotJoinedException, InterruptedException {
if (messageCollector == null) {
throw new MUCNotJoinedException(this);
throw new MucNotJoinedException(this);
}
return messageCollector.nextResult(timeout);
}

View file

@ -0,0 +1,86 @@
/**
*
* Copyright © 2014-2015 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;
import org.jivesoftware.smack.SmackException;
public abstract class MultiUserChatException extends SmackException {
protected MultiUserChatException() {
}
protected MultiUserChatException(String message) {
super(message);
}
/**
*
*/
private static final long serialVersionUID = 1L;
// This could eventually become an unchecked exception. But be aware that it's required in the
// control flow of MultiUserChat.createOrJoinIfNecessary
public static class MucAlreadyJoinedException extends MultiUserChatException {
/**
*
*/
private static final long serialVersionUID = 1L;
}
/**
* Thrown if the requested operation required the MUC to be joined by the
* client, while the client is currently joined.
*
*/
public static class MucNotJoinedException extends MultiUserChatException {
/**
*
*/
private static final long serialVersionUID = 1L;
public MucNotJoinedException(MultiUserChat multiUserChat) {
super("Client not currently joined " + multiUserChat.getRoom());
}
}
public static class MissingMucCreationAcknowledgeException extends MultiUserChatException {
/**
*
*/
private static final long serialVersionUID = 1L;
}
/**
* Thrown if the MUC room does not support the requested configuration option.
*/
public static class MucConfigurationNotSupported extends MultiUserChatException {
/**
*
*/
private static final long serialVersionUID = 1L;
public MucConfigurationNotSupported(String configString) {
super("The MUC configuration '" + configString + "' is not supported by the MUC service");
}
}
}

View file

@ -0,0 +1,145 @@
/**
*
* Copyright © 2015 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.bookmarkautojoin;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jivesoftware.smack.AbstractConnectionListener;
import org.jivesoftware.smack.ConnectionCreationListener;
import org.jivesoftware.smack.Manager;
import org.jivesoftware.smack.SmackException.NoResponseException;
import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPConnectionRegistry;
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
import org.jivesoftware.smackx.bookmarks.BookmarkManager;
import org.jivesoftware.smackx.bookmarks.BookmarkedConference;
import org.jivesoftware.smackx.muc.MultiUserChat;
import org.jivesoftware.smackx.muc.MultiUserChat.MucCreateConfigFormHandle;
import org.jivesoftware.smackx.muc.MultiUserChatManager;
import org.jxmpp.jid.parts.Resourcepart;
/**
* Autojoin bookmarked Multi-User Chat conferences.
*
* @see <a href="http://xmpp.org/extensions/xep-0048.html">XEP-48: Bookmarks</a>
*
*/
public final class MucBookmarkAutojoinManager extends Manager {
private static final Logger LOGGER = Logger.getLogger(MucBookmarkAutojoinManager.class.getName());
private static final Map<XMPPConnection, MucBookmarkAutojoinManager> INSTANCES = new WeakHashMap<>();
private static boolean autojoinEnabledDefault = false;
static {
XMPPConnectionRegistry.addConnectionCreationListener(new ConnectionCreationListener() {
@Override
public void connectionCreated(XMPPConnection connection) {
getInstanceFor(connection);
}
});
}
public static void setAutojoinPerDefault(boolean autojoin) {
autojoinEnabledDefault = autojoin;
}
public static synchronized MucBookmarkAutojoinManager getInstanceFor(XMPPConnection connection) {
MucBookmarkAutojoinManager mbam = INSTANCES.get(connection);
if (mbam == null) {
mbam = new MucBookmarkAutojoinManager(connection);
INSTANCES.put(connection, mbam);
}
return mbam;
}
private final MultiUserChatManager multiUserChatManager;
private final BookmarkManager bookmarkManager;
private boolean autojoinEnabled = autojoinEnabledDefault;
private MucBookmarkAutojoinManager(XMPPConnection connection) {
super(connection);
multiUserChatManager = MultiUserChatManager.getInstanceFor(connection);
bookmarkManager = BookmarkManager.getBookmarkManager(connection);
connection.addConnectionListener(new AbstractConnectionListener() {
@Override
public void authenticated(XMPPConnection connection, boolean resumed) {
if (!autojoinEnabled) {
return;
}
// TODO handle resumed case?
autojoinBookmarkedConferences();
}
});
}
public void setAutojoinEnabled(boolean autojoin) {
autojoinEnabled = autojoin;
}
public void autojoinBookmarkedConferences() {
List<BookmarkedConference> bookmarkedConferences;
try {
bookmarkedConferences = bookmarkManager.getBookmarkedConferences();
}
catch (NotConnectedException | InterruptedException e) {
LOGGER.log(Level.FINER, "Could not get MUC bookmarks", e);
return;
}
catch (NoResponseException | XMPPErrorException e) {
LOGGER.log(Level.WARNING, "Could not get MUC bookmarks", e);
return;
}
final XMPPConnection connection = connection();
Resourcepart defaultNick = connection.getUser().getResourcepart();
for (BookmarkedConference bookmarkedConference : bookmarkedConferences) {
if (!bookmarkedConference.isAutoJoin()) {
continue;
}
Resourcepart nick = bookmarkedConference.getNickname();
if (nick == null) {
nick = defaultNick;
}
String password = bookmarkedConference.getPassword();
MultiUserChat muc = multiUserChatManager.getMultiUserChat(bookmarkedConference.getJid());
try {
MucCreateConfigFormHandle handle = muc.createOrJoinIfNecessary(nick, password);
if (handle != null) {
handle.makeInstant();
}
}
catch (NotConnectedException | InterruptedException e) {
LOGGER.log(Level.FINER, "Could not autojoin bookmarked MUC", e);
// abort here
break;
}
catch (NoResponseException | XMPPErrorException e) {
// Do no abort, just log,
LOGGER.log(Level.WARNING, "Could not autojoin bookmarked MUC", e);
}
}
}
}

View file

@ -1,6 +1,6 @@
/**
*
* Copyright © 2014 Florian Schmaus
* Copyright 2015 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -14,23 +14,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.muc;
import org.jivesoftware.smack.SmackException;
/**
* Thrown if the requested operation required the MUC to be joined by the
* client, while the client is currently joined.
*
* Manager to autojoin bookmarked Multi-User Chat conferences.
*/
public class MUCNotJoinedException extends SmackException {
/**
*
*/
private static final long serialVersionUID = -5204934585663465576L;
public MUCNotJoinedException(MultiUserChat multiUserChat) {
super("Client not currently joined " + multiUserChat.getRoom());
}
}
package org.jivesoftware.smackx.muc.bookmarkautojoin;