package jrummikub.control.network; import javax.swing.SwingUtilities; import jrummikub.util.Event; import jrummikub.util.IEvent; import jrummikub.util.LoginData; import org.jivesoftware.smack.Connection; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.packet.XMPPError; import org.jivesoftware.smack.packet.XMPPError.Type; import org.jivesoftware.smackx.muc.MultiUserChat; class ConnectionControl { private final LoginData loginData; private volatile Connection connection; private volatile MultiUserChat muc; private Event connectedEvent = new Event(); private Event connectionFailedEvent = new Event(); ConnectionControl(LoginData loginData) { this.loginData = loginData; } void connect() { new Thread(new ConnectRunner()).start(); } void disconnect() { connectedEvent = new Event(); connectionFailedEvent = new Event(); new Thread(new DisconnectRunner()).start(); } IEvent getConnectedEvent() { return connectedEvent; } IEvent getConnectionFailedEvent() { return connectionFailedEvent; } private static void emitLater(final Event event) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { event.emit(); } }); } private class ConnectRunner implements Runnable { @Override public void run() { synchronized (ConnectionControl.this) { connection = new XMPPConnection(loginData.getServerName()); try { connection.connect(); connection.login(loginData.getUserName(), loginData.getPassword(), "JRummikub"); muc = new MultiUserChat(connection, loginData.getChannelName()); String nickname = loginData.getUserName(); // Loop until a unused nickname is found while (true) { try { muc.join(nickname); break; // Join was successful, break the loop } catch (XMPPException e) { XMPPError error = e.getXMPPError(); if (error.getType() == Type.CANCEL && error.getCode() == 409) { // There was a conflict, try again with another // nickname nickname += "_"; continue; } else { // An unknown error has occurred, cancel connect throw e; } } } emitLater(connectedEvent); } catch (XMPPException e) { connection.disconnect(); connection = null; // TODO Auto-generated catch block e.printStackTrace(); emitLater(connectionFailedEvent); } } } } private class DisconnectRunner implements Runnable { @Override public void run() { synchronized (ConnectionControl.this) { if (connection != null) { connection.disconnect(); connection = null; } } } } }