mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-11-27 00:32:07 +01:00
Added reconnection support. SMACK-172
git-svn-id: http://svn.igniterealtime.org/svn/repos/smack/trunk@5368 b35dd754-fafc-0310-a699-88a17e54d16e
This commit is contained in:
parent
3af86fd462
commit
29073a307a
1 changed files with 247 additions and 124 deletions
|
@ -51,13 +51,25 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||||
* <pre>
|
* <pre>
|
||||||
* // Create a connection to the jivesoftware.com XMPP server.
|
* // Create a connection to the jivesoftware.com XMPP server.
|
||||||
* XMPPConnection con = new XMPPConnection("jivesoftware.com");
|
* XMPPConnection con = new XMPPConnection("jivesoftware.com");
|
||||||
|
* // Connect to the server
|
||||||
|
* con.connect();
|
||||||
* // Most servers require you to login before performing other tasks.
|
* // Most servers require you to login before performing other tasks.
|
||||||
* con.login("jsmith", "mypass");
|
* con.login("jsmith", "mypass");
|
||||||
* // Start a new conversation with John Doe and send him a message.
|
* // Start a new conversation with John Doe and send him a message.
|
||||||
* Chat chat = con.createChat("jdoe@jabber.org");
|
* Chat chat = con.createChat("jdoe@jabber.org");
|
||||||
* chat.sendMessage("Hey, how's it going?");
|
* chat.sendMessage("Hey, how's it going?");
|
||||||
|
* // Disconnect from the server
|
||||||
|
* con.disconnect();
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
|
* XMPPConnections can be reused between connections. This means that an XMPPConnection
|
||||||
|
* may be connected, disconnected and then connected again. Listeners of the XMPPConnection
|
||||||
|
* will remain accross connections.<p>
|
||||||
|
*
|
||||||
|
* If a connected XMPPConnection gets disconnected abruptly then it will try to reconnect
|
||||||
|
* again. To stop the reconnection process just use {@link #disconnect()}. Once stopped
|
||||||
|
* you can use {@link #connect()} to manually connect to the server.
|
||||||
|
*
|
||||||
* @author Matt Tucker
|
* @author Matt Tucker
|
||||||
*/
|
*/
|
||||||
public class XMPPConnection {
|
public class XMPPConnection {
|
||||||
|
@ -113,7 +125,15 @@ public class XMPPConnection {
|
||||||
String connectionID;
|
String connectionID;
|
||||||
private String user = null;
|
private String user = null;
|
||||||
private boolean connected = false;
|
private boolean connected = false;
|
||||||
|
/**
|
||||||
|
* Flag that indicates if the user is currently authenticated with the server.
|
||||||
|
*/
|
||||||
private boolean authenticated = false;
|
private boolean authenticated = false;
|
||||||
|
/**
|
||||||
|
* Flag that indicates if the user was authenticated with the server when the connection
|
||||||
|
* to the server was closed (abruptly or not).
|
||||||
|
*/
|
||||||
|
private boolean wasAuthenticated = false;
|
||||||
private boolean anonymous = false;
|
private boolean anonymous = false;
|
||||||
private boolean usingTLS = false;
|
private boolean usingTLS = false;
|
||||||
|
|
||||||
|
@ -122,7 +142,7 @@ public class XMPPConnection {
|
||||||
|
|
||||||
Roster roster = null;
|
Roster roster = null;
|
||||||
private AccountManager accountManager = null;
|
private AccountManager accountManager = null;
|
||||||
private SASLAuthentication saslAuthentication = new SASLAuthentication(this);
|
protected SASLAuthentication saslAuthentication = new SASLAuthentication(this);
|
||||||
|
|
||||||
Writer writer;
|
Writer writer;
|
||||||
Reader reader;
|
Reader reader;
|
||||||
|
@ -147,22 +167,20 @@ public class XMPPConnection {
|
||||||
* Holds the initial configuration used while creating the connection.
|
* Holds the initial configuration used while creating the connection.
|
||||||
*/
|
*/
|
||||||
private ConnectionConfiguration configuration;
|
private ConnectionConfiguration configuration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new connection to the specified XMPP server. A DNS SRV lookup will be
|
* Creates a new connection to the specified XMPP server. A DNS SRV lookup will be
|
||||||
* performed to try to determine the IP address and port corresponding to the
|
* performed to try to determine the IP address and port corresponding to the
|
||||||
* serviceName; if that lookup fails, it's assumed that server resides at serviceName
|
* serviceName; if that lookup fails, it's assumed that server resides at serviceName
|
||||||
* with the default port of 5222. This is the preferred constructor for connecting
|
* with the default port of 5222. This is the preferred constructor for connecting
|
||||||
* to an XMPP server.
|
* to an XMPP server.<p>
|
||||||
|
*
|
||||||
|
* Note that XMPPConnection constructors do not establish the connection to the server,
|
||||||
|
* to make it effective use the connect method. {@link #connect()}.
|
||||||
*
|
*
|
||||||
* @param serviceName the name of the XMPP server to connect to; e.g. <tt>jivesoftware.com</tt>.
|
* @param serviceName the name of the XMPP server to connect to; e.g. <tt>jivesoftware.com</tt>.
|
||||||
* @throws XMPPException if an error occurs while trying to establish the connection.
|
|
||||||
* Two possible errors can occur which will be wrapped by an XMPPException --
|
|
||||||
* UnknownHostException (XMPP error code 504), and IOException (XMPP error code
|
|
||||||
* 502). The error codes and wrapped exceptions can be used to present more
|
|
||||||
* appropiate error messages to end-users.
|
|
||||||
*/
|
*/
|
||||||
public XMPPConnection(String serviceName) throws XMPPException {
|
public XMPPConnection(String serviceName) {
|
||||||
// Perform DNS lookup to get host and port to use
|
// Perform DNS lookup to get host and port to use
|
||||||
DNSUtil.HostAddress address = DNSUtil.resolveXMPPDomain(serviceName);
|
DNSUtil.HostAddress address = DNSUtil.resolveXMPPDomain(serviceName);
|
||||||
// Create the configuration for this new connection
|
// Create the configuration for this new connection
|
||||||
|
@ -172,53 +190,46 @@ public class XMPPConnection {
|
||||||
config.setCompressionEnabled(false);
|
config.setCompressionEnabled(false);
|
||||||
config.setSASLAuthenticationEnabled(true);
|
config.setSASLAuthenticationEnabled(true);
|
||||||
config.setDebuggerEnabled(DEBUG_ENABLED);
|
config.setDebuggerEnabled(DEBUG_ENABLED);
|
||||||
// Set the new connection configuration
|
init(config, null);
|
||||||
connectUsingConfiguration(config, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new connection to the XMPP server at the specifiec host and port.
|
* Creates a new connection to the XMPP server at the specifiec host and port.<p>
|
||||||
|
*
|
||||||
|
* Note that XMPPConnection constructors do not establish the connection to the server,
|
||||||
|
* to make it effective use the connect method. {@link #connect()}.
|
||||||
*
|
*
|
||||||
* @param host the name of the XMPP server to connect to; e.g. <tt>jivesoftware.com</tt>.
|
* @param host the name of the XMPP server to connect to; e.g. <tt>jivesoftware.com</tt>.
|
||||||
* @param port the port on the server that should be used; e.g. <tt>5222</tt>.
|
* @param port the port on the server that should be used; e.g. <tt>5222</tt>.
|
||||||
* @throws XMPPException if an error occurs while trying to establish the connection.
|
|
||||||
* Two possible errors can occur which will be wrapped by an XMPPException --
|
|
||||||
* UnknownHostException (XMPP error code 504), and IOException (XMPP error code
|
|
||||||
* 502). The error codes and wrapped exceptions can be used to present more
|
|
||||||
* appropiate error messages to end-users.
|
|
||||||
*/
|
*/
|
||||||
public XMPPConnection(String host, int port) throws XMPPException {
|
public XMPPConnection(String host, int port) {
|
||||||
// Create the configuration for this new connection
|
// Create the configuration for this new connection
|
||||||
ConnectionConfiguration config = new ConnectionConfiguration(host, port);
|
ConnectionConfiguration config = new ConnectionConfiguration(host, port);
|
||||||
config.setTLSEnabled(true);
|
config.setTLSEnabled(true);
|
||||||
config.setCompressionEnabled(false);
|
config.setCompressionEnabled(false);
|
||||||
config.setSASLAuthenticationEnabled(true);
|
config.setSASLAuthenticationEnabled(true);
|
||||||
config.setDebuggerEnabled(DEBUG_ENABLED);
|
config.setDebuggerEnabled(DEBUG_ENABLED);
|
||||||
// Set the new connection configuration
|
init(config, null);
|
||||||
connectUsingConfiguration(config, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new connection to the specified XMPP server on the given host and port.
|
* Creates a new connection to the specified XMPP server on the given host and port.<p>
|
||||||
|
*
|
||||||
|
* Note that XMPPConnection constructors do not establish the connection to the server,
|
||||||
|
* to make it effective use the connect method. {@link #connect()}.
|
||||||
*
|
*
|
||||||
* @param host the host name, or null for the loopback address.
|
* @param host the host name, or null for the loopback address.
|
||||||
* @param port the port on the server that should be used; e.g. <tt>5222</tt>.
|
* @param port the port on the server that should be used; e.g. <tt>5222</tt>.
|
||||||
* @param serviceName the name of the XMPP server to connect to; e.g. <tt>jivesoftware.com</tt>.
|
* @param serviceName the name of the XMPP server to connect to; e.g. <tt>jivesoftware.com</tt>.
|
||||||
* @throws XMPPException if an error occurs while trying to establish the connection.
|
|
||||||
* Two possible errors can occur which will be wrapped by an XMPPException --
|
|
||||||
* UnknownHostException (XMPP error code 504), and IOException (XMPP error code
|
|
||||||
* 502). The error codes and wrapped exceptions can be used to present more
|
|
||||||
* appropiate error messages to end-users.
|
|
||||||
*/
|
*/
|
||||||
public XMPPConnection(String host, int port, String serviceName) throws XMPPException {
|
public XMPPConnection(String host, int port, String serviceName) {
|
||||||
// Create the configuration for this new connection
|
// Create the configuration for this new connection
|
||||||
ConnectionConfiguration config = new ConnectionConfiguration(host, port, serviceName);
|
ConnectionConfiguration config = new ConnectionConfiguration(host, port, serviceName);
|
||||||
config.setTLSEnabled(true);
|
config.setTLSEnabled(true);
|
||||||
config.setCompressionEnabled(false);
|
config.setCompressionEnabled(false);
|
||||||
config.setSASLAuthenticationEnabled(true);
|
config.setSASLAuthenticationEnabled(true);
|
||||||
config.setDebuggerEnabled(DEBUG_ENABLED);
|
config.setDebuggerEnabled(DEBUG_ENABLED);
|
||||||
// Set the new connection configuration
|
init(config, null);
|
||||||
connectUsingConfiguration(config, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -227,53 +238,44 @@ public class XMPPConnection {
|
||||||
*
|
*
|
||||||
* A custom SocketFactory allows fine-grained control of the actual connection to the
|
* A custom SocketFactory allows fine-grained control of the actual connection to the
|
||||||
* XMPP server. A typical use for a custom SocketFactory is when connecting through a
|
* XMPP server. A typical use for a custom SocketFactory is when connecting through a
|
||||||
* SOCKS proxy.
|
* SOCKS proxy.<p>
|
||||||
|
*
|
||||||
|
* Note that XMPPConnection constructors do not establish the connection to the server,
|
||||||
|
* to make it effective use the connect method. {@link #connect()}.
|
||||||
*
|
*
|
||||||
* @param host the host name, or null for the loopback address.
|
* @param host the host name, or null for the loopback address.
|
||||||
* @param port the port on the server that should be used; e.g. <tt>5222</tt>.
|
* @param port the port on the server that should be used; e.g. <tt>5222</tt>.
|
||||||
* @param serviceName the name of the XMPP server to connect to; e.g. <tt>jivesoftware.com</tt>.
|
* @param serviceName the name of the XMPP server to connect to; e.g. <tt>jivesoftware.com</tt>.
|
||||||
* @param socketFactory a SocketFactory that will be used to create the socket to the XMPP
|
* @param socketFactory a SocketFactory that will be used to create the socket to the XMPP
|
||||||
* server.
|
* server.
|
||||||
* @throws XMPPException if an error occurs while trying to establish the connection.
|
|
||||||
* Two possible errors can occur which will be wrapped by an XMPPException --
|
|
||||||
* UnknownHostException (XMPP error code 504), and IOException (XMPP error code
|
|
||||||
* 502). The error codes and wrapped exceptions can be used to present more
|
|
||||||
* appropiate error messages to end-users.
|
|
||||||
*/
|
*/
|
||||||
public XMPPConnection(String host, int port, String serviceName, SocketFactory socketFactory)
|
public XMPPConnection(String host, int port, String serviceName, SocketFactory socketFactory) {
|
||||||
throws XMPPException
|
|
||||||
{
|
|
||||||
// Create the configuration for this new connection
|
// Create the configuration for this new connection
|
||||||
ConnectionConfiguration config = new ConnectionConfiguration(host, port, serviceName);
|
ConnectionConfiguration config = new ConnectionConfiguration(host, port, serviceName);
|
||||||
config.setTLSEnabled(true);
|
config.setTLSEnabled(true);
|
||||||
config.setCompressionEnabled(false);
|
config.setCompressionEnabled(false);
|
||||||
config.setSASLAuthenticationEnabled(true);
|
config.setSASLAuthenticationEnabled(true);
|
||||||
config.setDebuggerEnabled(DEBUG_ENABLED);
|
config.setDebuggerEnabled(DEBUG_ENABLED);
|
||||||
// Set the new connection configuration
|
init(config, socketFactory);
|
||||||
connectUsingConfiguration(config, socketFactory);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public XMPPConnection(ConnectionConfiguration config) throws XMPPException {
|
public XMPPConnection(ConnectionConfiguration config) {
|
||||||
// Set the new connection configuration
|
init(config, null);
|
||||||
connectUsingConfiguration(config, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public XMPPConnection(ConnectionConfiguration config, SocketFactory socketFactory)
|
public XMPPConnection(ConnectionConfiguration config, SocketFactory socketFactory) {
|
||||||
throws XMPPException {
|
init(config, socketFactory);
|
||||||
// Set the new connection configuration
|
|
||||||
connectUsingConfiguration(config, socketFactory);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void connectUsingConfiguration(ConnectionConfiguration config,
|
private void connectUsingConfiguration(ConnectionConfiguration config) throws XMPPException {
|
||||||
SocketFactory socketFactory) throws XMPPException {
|
|
||||||
this.host = config.getHost();
|
this.host = config.getHost();
|
||||||
this.port = config.getPort();
|
this.port = config.getPort();
|
||||||
try {
|
try {
|
||||||
if (socketFactory == null) {
|
if (config.getSocketFactory() == null) {
|
||||||
this.socket = new Socket(host, port);
|
this.socket = new Socket(host, port);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.socket = socketFactory.createSocket(host, port);
|
this.socket = config.getSocketFactory().createSocket(host, port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (UnknownHostException uhe) {
|
catch (UnknownHostException uhe) {
|
||||||
|
@ -289,15 +291,7 @@ public class XMPPConnection {
|
||||||
XMPPError.Condition.remote_server_error, errorMessage), ioe);
|
XMPPError.Condition.remote_server_error, errorMessage), ioe);
|
||||||
}
|
}
|
||||||
this.serviceName = config.getServiceName();
|
this.serviceName = config.getServiceName();
|
||||||
try {
|
initConnection();
|
||||||
// Keep a copy to be sure that once the configuration has been passed to the
|
|
||||||
// constructor it cannot be modified
|
|
||||||
this.configuration = (ConnectionConfiguration) config.clone();
|
|
||||||
}
|
|
||||||
catch (CloneNotSupportedException e) {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
init();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -403,7 +397,11 @@ public class XMPPConnection {
|
||||||
* presence may optionally be sent. If <tt>sendPresence</tt>
|
* presence may optionally be sent. If <tt>sendPresence</tt>
|
||||||
* is false, a presence packet must be sent manually later. If more than five seconds
|
* is false, a presence packet must be sent manually later. If more than five seconds
|
||||||
* (default timeout) elapses in each step of the authentication process without a
|
* (default timeout) elapses in each step of the authentication process without a
|
||||||
* response from the server, or if an error occurs, a XMPPException will be thrown.
|
* response from the server, or if an error occurs, a XMPPException will be thrown.<p>
|
||||||
|
*
|
||||||
|
* Before logging in (i.e. authenticate) to the server the connection must be connected.
|
||||||
|
* For compatibility and easiness of use the connection will automatically connect to the
|
||||||
|
* server if not already connected.
|
||||||
*
|
*
|
||||||
* @param username the username.
|
* @param username the username.
|
||||||
* @param password the password.
|
* @param password the password.
|
||||||
|
@ -456,19 +454,24 @@ public class XMPPConnection {
|
||||||
useCompression();
|
useCompression();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the roster.
|
// Create the roster if it is not a reconnection.
|
||||||
this.roster = new Roster(this);
|
if (this.roster == null) {
|
||||||
|
this.roster = new Roster(this);
|
||||||
|
}
|
||||||
roster.reload();
|
roster.reload();
|
||||||
|
|
||||||
// Set presence to online.
|
// Set presence to online.
|
||||||
if (sendPresence) {
|
if (sendPresence) {
|
||||||
packetWriter.sendPacket(new Presence(Presence.Type.available));
|
packetWriter.sendPacket(new Presence(Presence.Type.available));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Indicate that we're now authenticated.
|
// Indicate that we're now authenticated.
|
||||||
authenticated = true;
|
authenticated = true;
|
||||||
anonymous = false;
|
anonymous = false;
|
||||||
|
|
||||||
|
// Stores the autentication for future reconnection
|
||||||
|
this.getConfiguration().setUsernameAndPassword(username, password);
|
||||||
|
|
||||||
// If debugging is enabled, change the the debug window title to include the
|
// If debugging is enabled, change the the debug window title to include the
|
||||||
// name we are now logged-in as.
|
// name we are now logged-in as.
|
||||||
// If DEBUG_ENABLED was set to true AFTER the connection was created the debugger
|
// If DEBUG_ENABLED was set to true AFTER the connection was created the debugger
|
||||||
|
@ -642,9 +645,12 @@ public class XMPPConnection {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes the connection by setting presence to unavailable then closing the stream to
|
* Closes the connection by setting presence to unavailable then closing the stream to
|
||||||
* the XMPP server. Once a connection has been closed, it cannot be re-opened.
|
* the XMPP server. The shutdown logic will be used during a planned disconnection or when
|
||||||
|
* dealing with an unexpected disconnection. Unlike {@link #disconnect()} the connection's
|
||||||
|
* {@link PacketReader}, {@link PacketWriter} and {@link Roster} will not be removed thus
|
||||||
|
* connection's state is kept.
|
||||||
*/
|
*/
|
||||||
public void close() {
|
protected void shutdown() {
|
||||||
// Set presence to offline.
|
// Set presence to offline.
|
||||||
packetWriter.sendPacket(new Presence(Presence.Type.unavailable));
|
packetWriter.sendPacket(new Presence(Presence.Type.unavailable));
|
||||||
packetReader.shutdown();
|
packetReader.shutdown();
|
||||||
|
@ -675,8 +681,32 @@ public class XMPPConnection {
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
// Ignore.
|
// Ignore.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.setWasAuthenticated(authenticated);
|
||||||
authenticated = false;
|
authenticated = false;
|
||||||
connected = false;
|
connected = false;
|
||||||
|
|
||||||
|
saslAuthentication.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes the connection by setting presence to unavailable then closing the stream to
|
||||||
|
* the XMPP server. The XMPPConnection can still be used for connecting to the server
|
||||||
|
* again.
|
||||||
|
*
|
||||||
|
* The difference between disconnect and shutdown is that disconnect makes a complete reset
|
||||||
|
* of the connection state whereas shutdown only cleans the connection and keeps alive
|
||||||
|
* packet reader listeners, previous login and roster presences.
|
||||||
|
*/
|
||||||
|
public void disconnect() {
|
||||||
|
this.shutdown();
|
||||||
|
|
||||||
|
this.roster = null;
|
||||||
|
|
||||||
|
this.wasAuthenticated = false;
|
||||||
|
|
||||||
|
packetWriter = null;
|
||||||
|
packetReader = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -834,29 +864,53 @@ public class XMPPConnection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the connection configuration. This method is only executed
|
||||||
|
* when the XMPPConnection is created.
|
||||||
|
*/
|
||||||
|
private void init(ConnectionConfiguration config, SocketFactory socketFactory) {
|
||||||
|
try {
|
||||||
|
// Keep a copy to be sure that once the configuration has been passed to the
|
||||||
|
// constructor it cannot be modified
|
||||||
|
this.configuration = (ConnectionConfiguration) config.clone();
|
||||||
|
this.configuration.setSocketFactory(socketFactory);
|
||||||
|
}
|
||||||
|
catch (CloneNotSupportedException e) {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the connection by creating a packet reader and writer and opening a
|
* Initializes the connection by creating a packet reader and writer and opening a
|
||||||
* XMPP stream to the server.
|
* XMPP stream to the server.
|
||||||
*
|
*
|
||||||
* @throws XMPPException if establishing a connection to the server fails.
|
* @throws XMPPException if establishing a connection to the server fails.
|
||||||
*/
|
*/
|
||||||
private void init() throws XMPPException {
|
private void initConnection() throws XMPPException {
|
||||||
// Set the reader and writer instance variables
|
// Set the reader and writer instance variables
|
||||||
initReaderAndWriter();
|
initReaderAndWriter();
|
||||||
|
|
||||||
try
|
try {
|
||||||
{
|
boolean isFirstInitialization = packetReader == null || packetWriter == null;
|
||||||
packetWriter = new PacketWriter(this);
|
|
||||||
packetReader = new PacketReader(this);
|
|
||||||
|
|
||||||
// If debugging is enabled, we should start the thread that will listen for
|
if (isFirstInitialization) {
|
||||||
// all packets and then log them.
|
packetWriter = new PacketWriter(this);
|
||||||
if (configuration.isDebuggerEnabled()) {
|
packetReader = new PacketReader(this);
|
||||||
packetReader.addPacketListener(debugger.getReaderListener(), null);
|
|
||||||
if (debugger.getWriterListener() != null) {
|
// If debugging is enabled, we should start the thread that will listen for
|
||||||
packetWriter.addPacketListener(debugger.getWriterListener(), null);
|
// all packets and then log them.
|
||||||
|
if (configuration.isDebuggerEnabled()) {
|
||||||
|
packetReader.addPacketListener(debugger.getReaderListener(), null);
|
||||||
|
if (debugger.getWriterListener() != null) {
|
||||||
|
packetWriter.addPacketListener(debugger.getWriterListener(), null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
packetWriter.init();
|
||||||
|
packetReader.init();
|
||||||
|
}
|
||||||
|
|
||||||
// Start the packet writer. This will open a XMPP stream to the server
|
// Start the packet writer. This will open a XMPP stream to the server
|
||||||
packetWriter.startup();
|
packetWriter.startup();
|
||||||
// Start the packet reader. The startup() method will block until we
|
// Start the packet reader. The startup() method will block until we
|
||||||
|
@ -869,99 +923,123 @@ public class XMPPConnection {
|
||||||
// Start keep alive process (after TLS was negotiated - if available)
|
// Start keep alive process (after TLS was negotiated - if available)
|
||||||
packetWriter.startKeepAliveProcess();
|
packetWriter.startKeepAliveProcess();
|
||||||
|
|
||||||
// Notify that a new connection has been established
|
|
||||||
connectionEstablished(this);
|
|
||||||
|
|
||||||
// Add a listener for all message packets so that we can deliver errant
|
if (isFirstInitialization) {
|
||||||
// messages to the best Chat instance available.
|
// Notify that a new connection has been established
|
||||||
addPacketListener(new PacketListener() {
|
connectionEstablished(this);
|
||||||
public void processPacket(Packet packet) {
|
|
||||||
Message message = (Message)packet;
|
// Add a listener for all message packets so that we can deliver errant
|
||||||
// Ignore any messages with a thread ID, as they will likely
|
// messages to the best Chat instance available.
|
||||||
// already be associated with a Chat. This will miss messages
|
addPacketListener(new PacketListener() {
|
||||||
// with new thread ID values, but we can only assume that a
|
public void processPacket(Packet packet) {
|
||||||
// listener is registered to deal with this case.
|
Message message = (Message) packet;
|
||||||
if (message.getThread() == null &&
|
// Ignore any messages with a thread ID, as they will likely
|
||||||
message.getType() != Message.Type.GROUP_CHAT &&
|
// already be associated with a Chat. This will miss messages
|
||||||
message.getType() != Message.Type.HEADLINE) {
|
// with new thread ID values, but we can only assume that a
|
||||||
WeakReference<Chat> chatRef =
|
// listener is registered to deal with this case.
|
||||||
chats.get(StringUtils.parseBareAddress(message.getFrom()));
|
if (message.getThread() == null &&
|
||||||
if (chatRef != null) {
|
message.getType() != Message.Type.GROUP_CHAT &&
|
||||||
// Do some extra clean-up if the reference was cleared.
|
message.getType() != Message.Type.HEADLINE) {
|
||||||
Chat chat = chatRef.get();
|
WeakReference<Chat> chatRef =
|
||||||
if (chat == null) {
|
chats.get(StringUtils.parseBareAddress(message.getFrom()));
|
||||||
chats.remove(message.getFrom());
|
if (chatRef != null) {
|
||||||
}
|
// Do some extra clean-up if the reference was cleared.
|
||||||
else {
|
Chat chat = chatRef.get();
|
||||||
chat.deliver(message);
|
if (chat == null) {
|
||||||
|
chats.remove(message.getFrom());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
chat.deliver(message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}, new PacketTypeFilter(Message.class));
|
||||||
}, new PacketTypeFilter(Message.class));
|
}
|
||||||
|
else {
|
||||||
|
packetReader.notifyReconnection();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (XMPPException ex) {
|
catch (XMPPException ex) {
|
||||||
// An exception occurred in setting up the connection. Make sure we shut down the
|
// An exception occurred in setting up the connection. Make sure we shut down the
|
||||||
// readers and writers and close the socket.
|
// readers and writers and close the socket.
|
||||||
|
|
||||||
if (packetWriter != null) {
|
if (packetWriter != null) {
|
||||||
try { packetWriter.shutdown(); } catch (Throwable ignore) { /* ignore */ }
|
try {
|
||||||
|
packetWriter.shutdown();
|
||||||
|
}
|
||||||
|
catch (Throwable ignore) { /* ignore */ }
|
||||||
packetWriter = null;
|
packetWriter = null;
|
||||||
}
|
}
|
||||||
if (packetReader != null) {
|
if (packetReader != null) {
|
||||||
try { packetReader.shutdown(); } catch (Throwable ignore) { /* ignore */ }
|
try {
|
||||||
|
packetReader.shutdown();
|
||||||
|
}
|
||||||
|
catch (Throwable ignore) { /* ignore */ }
|
||||||
packetReader = null;
|
packetReader = null;
|
||||||
}
|
}
|
||||||
if (reader != null) {
|
if (reader != null) {
|
||||||
try { reader.close(); } catch (Throwable ignore) { /* ignore */ }
|
try {
|
||||||
|
reader.close();
|
||||||
|
}
|
||||||
|
catch (Throwable ignore) { /* ignore */ }
|
||||||
reader = null;
|
reader = null;
|
||||||
}
|
}
|
||||||
if (writer != null) {
|
if (writer != null) {
|
||||||
try { writer.close(); } catch (Throwable ignore) { /* ignore */}
|
try {
|
||||||
|
writer.close();
|
||||||
|
}
|
||||||
|
catch (Throwable ignore) { /* ignore */}
|
||||||
writer = null;
|
writer = null;
|
||||||
}
|
}
|
||||||
if (socket != null) {
|
if (socket != null) {
|
||||||
try { socket.close(); } catch (Exception e) { /* ignore */ }
|
try {
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
|
catch (Exception e) { /* ignore */ }
|
||||||
socket = null;
|
socket = null;
|
||||||
}
|
}
|
||||||
|
this.setWasAuthenticated(authenticated);
|
||||||
authenticated = false;
|
authenticated = false;
|
||||||
connected = false;
|
connected = false;
|
||||||
|
|
||||||
throw ex; // Everything stoppped. Now throw the exception.
|
throw ex; // Everything stoppped. Now throw the exception.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initReaderAndWriter() throws XMPPException {
|
private void initReaderAndWriter() throws XMPPException {
|
||||||
try {
|
try {
|
||||||
if (!usingCompression) {
|
if (!usingCompression) {
|
||||||
reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
|
reader =
|
||||||
writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"));
|
new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
|
||||||
|
writer = new BufferedWriter(
|
||||||
|
new OutputStreamWriter(socket.getOutputStream(), "UTF-8"));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
try {
|
try {
|
||||||
Class<?> zoClass = Class.forName("com.jcraft.jzlib.ZOutputStream");
|
Class<?> zoClass = Class.forName("com.jcraft.jzlib.ZOutputStream");
|
||||||
//ZOutputStream out = new ZOutputStream(socket.getOutputStream(), JZlib.Z_BEST_COMPRESSION);
|
|
||||||
Constructor<?> constructor =
|
Constructor<?> constructor =
|
||||||
zoClass.getConstructor(OutputStream.class, Integer.TYPE);
|
zoClass.getConstructor(OutputStream.class, Integer.TYPE);
|
||||||
Object out = constructor.newInstance(socket.getOutputStream(), 9);
|
Object out = constructor.newInstance(socket.getOutputStream(), 9);
|
||||||
//out.setFlushMode(JZlib.Z_PARTIAL_FLUSH);
|
|
||||||
Method method = zoClass.getMethod("setFlushMode", Integer.TYPE);
|
Method method = zoClass.getMethod("setFlushMode", Integer.TYPE);
|
||||||
method.invoke(out, 1);
|
method.invoke(out, 1);
|
||||||
writer = new BufferedWriter(new OutputStreamWriter((OutputStream) out, "UTF-8"));
|
writer =
|
||||||
|
new BufferedWriter(new OutputStreamWriter((OutputStream) out, "UTF-8"));
|
||||||
|
|
||||||
Class<?> ziClass = Class.forName("com.jcraft.jzlib.ZInputStream");
|
Class<?> ziClass = Class.forName("com.jcraft.jzlib.ZInputStream");
|
||||||
//ZInputStream in = new ZInputStream(socket.getInputStream());
|
|
||||||
constructor = ziClass.getConstructor(InputStream.class);
|
constructor = ziClass.getConstructor(InputStream.class);
|
||||||
Object in = constructor.newInstance(socket.getInputStream());
|
Object in = constructor.newInstance(socket.getInputStream());
|
||||||
//in.setFlushMode(JZlib.Z_PARTIAL_FLUSH);
|
|
||||||
method = ziClass.getMethod("setFlushMode", Integer.TYPE);
|
method = ziClass.getMethod("setFlushMode", Integer.TYPE);
|
||||||
method.invoke(in, 1);
|
method.invoke(in, 1);
|
||||||
reader = new BufferedReader(new InputStreamReader((InputStream) in, "UTF-8"));
|
reader = new BufferedReader(new InputStreamReader((InputStream) in, "UTF-8"));
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
|
reader = new BufferedReader(
|
||||||
writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"));
|
new InputStreamReader(socket.getInputStream(), "UTF-8"));
|
||||||
|
writer = new BufferedWriter(
|
||||||
|
new OutputStreamWriter(socket.getOutputStream(), "UTF-8"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1002,7 +1080,8 @@ public class XMPPConnection {
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
try {
|
try {
|
||||||
debuggerClass = Class.forName("org.jivesoftware.smack.debugger.LiteDebugger");
|
debuggerClass =
|
||||||
|
Class.forName("org.jivesoftware.smack.debugger.LiteDebugger");
|
||||||
}
|
}
|
||||||
catch (Exception ex2) {
|
catch (Exception ex2) {
|
||||||
ex2.printStackTrace();
|
ex2.printStackTrace();
|
||||||
|
@ -1012,8 +1091,8 @@ public class XMPPConnection {
|
||||||
// Create a new debugger instance. If an exception occurs then disable the debugging
|
// Create a new debugger instance. If an exception occurs then disable the debugging
|
||||||
// option
|
// option
|
||||||
try {
|
try {
|
||||||
Constructor<?> constructor =
|
Constructor<?> constructor = debuggerClass
|
||||||
debuggerClass.getConstructor(XMPPConnection.class, Writer.class, Reader.class);
|
.getConstructor(XMPPConnection.class, Writer.class, Reader.class);
|
||||||
debugger = (SmackDebugger) constructor.newInstance(this, writer, reader);
|
debugger = (SmackDebugger) constructor.newInstance(this, writer, reader);
|
||||||
reader = debugger.getReader();
|
reader = debugger.getReader();
|
||||||
writer = debugger.getWriter();
|
writer = debugger.getWriter();
|
||||||
|
@ -1071,11 +1150,11 @@ public class XMPPConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the configuration used while connecting to the server.
|
* Returns the configuration used to connect to the server.
|
||||||
*
|
*
|
||||||
* @return the configuration used while connecting to the server.
|
* @return the configuration used to connect to the server.
|
||||||
*/
|
*/
|
||||||
ConnectionConfiguration getConfiguration() {
|
protected ConnectionConfiguration getConfiguration() {
|
||||||
return configuration;
|
return configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1244,4 +1323,48 @@ public class XMPPConnection {
|
||||||
this.notify();
|
this.notify();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Establishes a connection to the XMPP server and performs an automatic login
|
||||||
|
* only if the previous connection state was logged (authenticated). It basically
|
||||||
|
* creates and maintains a socket connection to the server.<p>
|
||||||
|
*
|
||||||
|
* Listeners will be preserved from a previous connection if the reconnection
|
||||||
|
* occurs after an abrupt termination.
|
||||||
|
*
|
||||||
|
* @throws XMPPException if an error occurs while trying to establish the connection.
|
||||||
|
* Two possible errors can occur which will be wrapped by an XMPPException --
|
||||||
|
* UnknownHostException (XMPP error code 504), and IOException (XMPP error code
|
||||||
|
* 502). The error codes and wrapped exceptions can be used to present more
|
||||||
|
* appropiate error messages to end-users.
|
||||||
|
*/
|
||||||
|
public void connect() throws XMPPException {
|
||||||
|
// Stablishes the connection, readers and writers
|
||||||
|
connectUsingConfiguration(configuration);
|
||||||
|
// Automatically makes the login if the user was previouslly connected successfully
|
||||||
|
// to the server and the connection was terminated abruptly
|
||||||
|
if (connected && wasAuthenticated) {
|
||||||
|
// Make the login
|
||||||
|
try {
|
||||||
|
if (isAnonymous()) {
|
||||||
|
// Make the anonymous login
|
||||||
|
loginAnonymously();
|
||||||
|
} else {
|
||||||
|
login(getConfiguration().getUsername(), getConfiguration().getPassword());
|
||||||
|
}
|
||||||
|
} catch (XMPPException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets if the connection has already logged in the server.
|
||||||
|
*
|
||||||
|
* @param wasAuthenticated
|
||||||
|
*/
|
||||||
|
private void setWasAuthenticated(boolean wasAuthenticated) {
|
||||||
|
if (!this.wasAuthenticated) {
|
||||||
|
this.wasAuthenticated = wasAuthenticated;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue