mirror of
https://github.com/vanitasvitae/Smack.git
synced 2025-09-10 17:49:38 +02:00
Move getRoster() to XMPPConnection
Also remove the Exceptions from the signature of getRoster(). Extend ConnectionListener with connected() and authenticated() callbacks, required by Roster to be notified so that the Roster can be loaded *after* login.
This commit is contained in:
parent
4b56446e40
commit
64e7b8a868
15 changed files with 193 additions and 260 deletions
|
@ -25,25 +25,38 @@ package org.jivesoftware.smack;
|
|||
* @author Henning Staib
|
||||
*/
|
||||
public class AbstractConnectionListener implements ConnectionListener {
|
||||
@Override
|
||||
public void connected(XMPPConnection connection) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void authenticated(XMPPConnection connection) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectionClosed() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectionClosedOnError(Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reconnectingIn(int seconds) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reconnectionFailed(Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reconnectionSuccessful() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,6 +28,18 @@ package org.jivesoftware.smack;
|
|||
*/
|
||||
public interface ConnectionListener {
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* @param connection
|
||||
*/
|
||||
public void connected(XMPPConnection connection);
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* @param connection
|
||||
*/
|
||||
public void authenticated(XMPPConnection connection);
|
||||
|
||||
/**
|
||||
* Notification that the connection was closed normally or that the reconnection
|
||||
* process has been aborted.
|
||||
|
|
|
@ -35,7 +35,7 @@ import java.util.logging.Logger;
|
|||
*
|
||||
* @author Francisco Vives
|
||||
*/
|
||||
public class ReconnectionManager implements ConnectionListener {
|
||||
public class ReconnectionManager extends AbstractConnectionListener {
|
||||
private static final Logger LOGGER = Logger.getLogger(ReconnectionManager.class.getName());
|
||||
|
||||
// Holds the connection to the server
|
||||
|
@ -187,10 +187,12 @@ public class ReconnectionManager implements ConnectionListener {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectionClosed() {
|
||||
done = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectionClosedOnError(Exception e) {
|
||||
done = false;
|
||||
if (e instanceof StreamErrorException) {
|
||||
|
@ -207,20 +209,4 @@ public class ReconnectionManager implements ConnectionListener {
|
|||
this.reconnect();
|
||||
}
|
||||
}
|
||||
|
||||
public void reconnectingIn(int seconds) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
public void reconnectionFailed(Exception e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
/**
|
||||
* The connection has successfull gotten connected.
|
||||
*/
|
||||
public void reconnectionSuccessful() {
|
||||
// ignore
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -29,6 +29,8 @@ import java.util.Map.Entry;
|
|||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.jivesoftware.smack.SmackException.NoResponseException;
|
||||
import org.jivesoftware.smack.SmackException.NotLoggedInException;
|
||||
|
@ -59,6 +61,7 @@ import org.jivesoftware.smack.util.StringUtils;
|
|||
*/
|
||||
public class Roster {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(Roster.class.getName());
|
||||
/**
|
||||
* The default subscription processing mode to use when a Roster is created. By default
|
||||
* all subscription requests are automatically accepted.
|
||||
|
@ -123,9 +126,9 @@ public class Roster {
|
|||
PacketFilter presenceFilter = new PacketTypeFilter(Presence.class);
|
||||
presencePacketListener = new PresencePacketListener();
|
||||
connection.addPacketListener(presencePacketListener, presenceFilter);
|
||||
|
||||
|
||||
// Listen for connection events
|
||||
final ConnectionListener connectionListener = new AbstractConnectionListener() {
|
||||
connection.addConnectionListener(new AbstractConnectionListener() {
|
||||
|
||||
public void connectionClosed() {
|
||||
// Changes the presence available contacts to unavailable
|
||||
|
@ -137,22 +140,34 @@ public class Roster {
|
|||
setOfflinePresences();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// if not connected add listener after successful login
|
||||
if(!this.connection.isConnected()) {
|
||||
XMPPConnection.addConnectionCreationListener(new ConnectionCreationListener() {
|
||||
|
||||
public void connectionCreated(XMPPConnection connection) {
|
||||
if(connection.equals(Roster.this.connection)) {
|
||||
Roster.this.connection.addConnectionListener(connectionListener);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
} else {
|
||||
connection.addConnectionListener(connectionListener);
|
||||
});
|
||||
// If the connection is already established, call reload
|
||||
if (connection.isAuthenticated()) {
|
||||
try {
|
||||
reload();
|
||||
}
|
||||
catch (NotLoggedInException e) {
|
||||
LOGGER.log(Level.SEVERE, "Could not reload Roster", e);
|
||||
}
|
||||
}
|
||||
connection.addConnectionListener(new AbstractConnectionListener() {
|
||||
public void authenticated(XMPPConnection connection) {
|
||||
// Anonymous users can't have a roster, but it iss possible that a Roster instance is
|
||||
// retrieved if getRoster() is called *before* connect(). So we have to check here
|
||||
// again if it's an anonymous connection.
|
||||
if (connection.isAnonymous())
|
||||
return;
|
||||
if (!connection.getConfiguration().isRosterLoadedAtLogin())
|
||||
return;
|
||||
try {
|
||||
Roster.this.reload();
|
||||
}
|
||||
catch (NotLoggedInException e) {
|
||||
LOGGER.log(Level.SEVERE, "Could not reload Roster", e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -189,11 +204,9 @@ public class Roster {
|
|||
* Reloads the entire roster from the server. This is an asynchronous operation,
|
||||
* which means the method will return immediately, and the roster will be
|
||||
* reloaded at a later point when the server responds to the reload request.
|
||||
*
|
||||
* @throws SmackException If not logged in.
|
||||
* @throws IllegalStateException if logged in anonymously
|
||||
* @throws NotLoggedInException If not logged in.
|
||||
*/
|
||||
public void reload() throws XMPPException, SmackException {
|
||||
public void reload() throws NotLoggedInException{
|
||||
if (!connection.isAuthenticated()) {
|
||||
throw new NotLoggedInException();
|
||||
}
|
||||
|
|
|
@ -224,6 +224,8 @@ public abstract class XMPPConnection {
|
|||
|
||||
private final ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(2);
|
||||
|
||||
private Roster roster;
|
||||
|
||||
/**
|
||||
* Create an executor to deliver incoming packets to listeners. We'll use a single thread with an unbounded queue.
|
||||
*/
|
||||
|
@ -482,11 +484,53 @@ public abstract class XMPPConnection {
|
|||
* {@link RosterListener}s will throw an IllegalStateException.
|
||||
*
|
||||
* @return the user's roster.
|
||||
* @throws XMPPException if an error occurs on the XMPP protocol level.
|
||||
* @throws SmackException if an error occurs somehwere else besides XMPP protocol level.
|
||||
* @throws IllegalStateException if the connection is anonymous
|
||||
*/
|
||||
public abstract Roster getRoster() throws XMPPException, SmackException;
|
||||
public Roster getRoster() {
|
||||
if (isAnonymous()) {
|
||||
throw new IllegalStateException("Anonymous users can't have a roster");
|
||||
}
|
||||
// synchronize against login()
|
||||
synchronized(this) {
|
||||
if (roster == null) {
|
||||
roster = new Roster(this);
|
||||
}
|
||||
if (!isAuthenticated()) {
|
||||
return roster;
|
||||
}
|
||||
}
|
||||
|
||||
// If this is the first time the user has asked for the roster after calling
|
||||
// login, we want to wait for the server to send back the user's roster. This
|
||||
// behavior shields API users from having to worry about the fact that roster
|
||||
// operations are asynchronous, although they'll still have to listen for
|
||||
// changes to the roster. Note: because of this waiting logic, internal
|
||||
// Smack code should be wary about calling the getRoster method, and may need to
|
||||
// access the roster object directly.
|
||||
// Also only check for rosterInitalized is isRosterLoadedAtLogin is set, otherwise the user
|
||||
// has to manually call Roster.reload() before he can expect a initialized roster.
|
||||
if (!roster.rosterInitialized && config.isRosterLoadedAtLogin()) {
|
||||
try {
|
||||
synchronized (roster) {
|
||||
long waitTime = SmackConfiguration.getDefaultPacketReplyTimeout();
|
||||
long start = System.currentTimeMillis();
|
||||
while (!roster.rosterInitialized) {
|
||||
if (waitTime <= 0) {
|
||||
break;
|
||||
}
|
||||
roster.wait(waitTime);
|
||||
long now = System.currentTimeMillis();
|
||||
waitTime -= now - start;
|
||||
start = now;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (InterruptedException ie) {
|
||||
// Ignore.
|
||||
}
|
||||
}
|
||||
return roster;
|
||||
}
|
||||
/**
|
||||
* Returns the SASLAuthentication manager that is responsible for authenticating with
|
||||
* the server.
|
||||
|
@ -944,6 +988,44 @@ public abstract class XMPPConnection {
|
|||
}
|
||||
}
|
||||
|
||||
void callConnectionConnectedListener() {
|
||||
for (ConnectionListener listener : getConnectionListeners()) {
|
||||
listener.connected(this);
|
||||
}
|
||||
}
|
||||
|
||||
void callConnectionAuthenticatedListener() {
|
||||
for (ConnectionListener listener : getConnectionListeners()) {
|
||||
listener.connected(this);
|
||||
}
|
||||
}
|
||||
|
||||
void callConnectionClosedListener() {
|
||||
for (ConnectionListener listener : getConnectionListeners()) {
|
||||
try {
|
||||
listener.connectionClosed();
|
||||
}
|
||||
catch (Exception e) {
|
||||
// Catch and print any exception so we can recover
|
||||
// from a faulty listener and finish the shutdown process
|
||||
LOGGER.log(Level.SEVERE, "Error in listener while closing connection", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void callConnectionClosedOnErrorListener(Exception e) {
|
||||
for (ConnectionListener listener : getConnectionListeners()) {
|
||||
try {
|
||||
listener.connectionClosedOnError(e);
|
||||
}
|
||||
catch (Exception e2) {
|
||||
// Catch and print any exception so we can recover
|
||||
// from a faulty listener
|
||||
LOGGER.log(Level.SEVERE, "Error in listener while closing connection", e2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A wrapper class to associate a packet filter with a listener.
|
||||
*/
|
||||
|
|
|
@ -109,6 +109,14 @@ public class ConsoleDebugger implements SmackDebugger {
|
|||
};
|
||||
|
||||
connListener = new ConnectionListener() {
|
||||
public void connected(XMPPConnection connection) {
|
||||
System.out.println(dateFormatter.format(new Date()) + " XMPPConnection connected ("
|
||||
+ connection.hashCode() + ")");
|
||||
}
|
||||
public void authenticated(XMPPConnection connection) {
|
||||
System.out.println(dateFormatter.format(new Date())
|
||||
+ " XMPPConnection authenticated (" + connection.hashCode() + ")");
|
||||
}
|
||||
public void connectionClosed() {
|
||||
System.out.println(
|
||||
dateFormatter.format(new Date()) + " XMPPConnection closed (" +
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue