1
0
Fork 0
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:
Gaston Dombiak 2006-09-14 19:21:38 +00:00 committed by gato
parent 3af86fd462
commit 29073a307a

View file

@ -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;
}
}
} }