Commits

Chris Thunes  committed 9cf696a

More refactoring of the connection process. Pull more of the
responsibility into ClientFactory.

  • Participants
  • Parent commits e1768f8

Comments (0)

Files changed (6)

File brewtab-irc/src/main/java/com/brewtab/irc/client/Client.java

 import com.brewtab.irc.User;
 
 public interface Client {
-    public void setUsername(String username);
 
     public String getUsername();
 
-    public void setHostname(String hostname);
-
     public String getHostname();
 
-    public void setRealName(String realName);
-
     public String getRealName();
 
     public void setNick(String nick);
 
     public String getNick();
 
-    public void setPassword(String password);
-
-    public String getPassword();
-
-    /**
-     * Connect to a server.
-     * 
-     * @param uri a URI specifying an irc: or ircs: scheme
-     */
-    public void connect(String uri);
-
     /**
      * Quit and disconnect from the server
      * 

File brewtab-irc/src/main/java/com/brewtab/irc/client/ClientFactory.java

 
 import com.brewtab.irc.impl.ClientFactoryImpl;
 
-public class ClientFactory {
-    public static Client newClient() {
-        return ClientFactoryImpl.newClient();
+public abstract class ClientFactory {
+    public static final int DEFAULT_PORT = 6667;
+    public static final int DEFAULT_SSL_PORT = 6697;
+
+    public static final String DEFAULT_USERNAME = "irc-client";
+    public static final String DEFAULT_HOSTNAME = "localhost";
+    public static final String DEFAULT_REALNAME = "Brewtab IRC Client";
+
+    public abstract void setUsername(String username);
+
+    public abstract void setHostname(String hostname);
+
+    public abstract void setRealName(String realName);
+
+    public abstract void setNick(String nick);
+
+    public abstract Client connect(String uri);
+
+    public abstract Client connect(String uri, String password);
+
+    public static ClientFactory newInstance() {
+        return ClientFactoryImpl.newInstance();
     }
 }

File brewtab-irc/src/main/java/com/brewtab/irc/impl/ClientFactoryImpl.java

 package com.brewtab.irc.impl;
 
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import com.brewtab.irc.ConnectionException;
 import com.brewtab.irc.client.Client;
+import com.brewtab.irc.client.ClientFactory;
+
+public class ClientFactoryImpl extends ClientFactory {
+    private String username = DEFAULT_USERNAME;
+    private String hostname = DEFAULT_HOSTNAME;
+    private String realName = DEFAULT_REALNAME;
+    private String nick = null;
+
+    public static ClientFactory newInstance() {
+        return new ClientFactoryImpl();
+    }
+
+    @Override
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+
+    @Override
+    public void setHostname(String hostname) {
+        this.hostname = hostname;
+    }
+
+
+    @Override
+    public void setRealName(String realName) {
+        this.realName = realName;
+    }
+
+
+    @Override
+    public void setNick(String nick) {
+        this.nick = nick;
+    }
+
+    private URI parseConnectURISpec(String uriSpec) {
+        final URI uri;
+
+        try {
+            uri = new URI(uriSpec);
+        } catch (URISyntaxException e) {
+            throw new RuntimeException(e);
+        }
+
+        String scheme = uri.getScheme();
+
+        if (scheme == null || !(scheme.equals("irc") || scheme.equals("ircs"))) {
+            throw new ConnectionException("URI scheme must be one of irc or ircs");
+        }
+
+        return uri;
+    }
+
+    @Override
+    public Client connect(String uriSpec) {
+        return connect(uriSpec, null);
+    }
+
+    @Override
+    public Client connect(String uriSpec, String password) {
+        URI uri = parseConnectURISpec(uriSpec);
+        boolean useSSL = uri.getScheme().equals("ircs");
+
+        String host = uri.getHost();
+        int port = uri.getPort();
+
+        if (port == -1) {
+            port = useSSL ? DEFAULT_SSL_PORT : DEFAULT_PORT;
+        }
+
+        // Use the user info from the URI if present
+        String nick = this.nick;
+        if (uri.getUserInfo() != null) {
+            nick = uri.getUserInfo();
+        }
+
+        if (nick == null) {
+            throw new ConnectionException("Nick must be provided to connect");
+        }
+
+        ClientImpl client = new ClientImpl();
+        SocketAddress socketAddress = new InetSocketAddress(host, port);
+
+        client.connect(socketAddress, useSSL);
+        client.registerConnection(nick, username, hostname, realName, password);
 
-public class ClientFactoryImpl {
-    public static Client newClient() {
-        return new ClientImpl();
+        return client;
     }
 }

File brewtab-irc/src/main/java/com/brewtab/irc/impl/ClientImpl.java

 package com.brewtab.irc.impl;
 
-import java.net.InetSocketAddress;
-import java.net.URI;
-import java.net.URISyntaxException;
+import java.net.SocketAddress;
 import java.security.KeyManagementException;
 import java.security.NoSuchAlgorithmException;
 import java.security.cert.CertificateException;
 import javax.net.ssl.SSLEngine;
 import javax.net.ssl.TrustManager;
 import javax.net.ssl.X509TrustManager;
-
 import org.jboss.netty.bootstrap.ClientBootstrap;
 import org.jboss.netty.channel.ChannelFactory;
 import org.jboss.netty.channel.ChannelFuture;
 import com.brewtab.irc.NotConnectedException;
 import com.brewtab.irc.User;
 import com.brewtab.irc.client.Channel;
-import com.brewtab.irc.client.Client;
 import com.brewtab.irc.client.NickNameInUseException;
 import com.brewtab.irc.messages.Message;
 import com.brewtab.irc.messages.MessageListener;
 class ClientImpl implements Client {
     private static final Logger log = LoggerFactory.getLogger(ClientImpl.class);
 
-    public static final int DEFAULT_PORT = 6667;
-    public static final int DEFAULT_SSL_PORT = 6697;
-
     /* Default SSL context, initialized lazily */
     private static SSLContext defaultSSLContext = null;
 
     /* Netty objects */
     private ClientBootstrap bootstrap;
 
-    /* Cached copy of the server's name */
-    private String servername;
-
     /* Connection information */
-    private String password;
     private String nick;
     private String username;
     private String hostname;
 
     private boolean connected;
 
-    private boolean usingSSL;
-
     /**
      * Construct a new IRCClient connected to the given address
      * 
      * @param address The address to connect to
      */
-    public ClientImpl() {
+    ClientImpl() {
         this.connection = new ConnectionImpl();
 
-        this.password = null;
         this.nick = null;
         this.username = null;
         this.hostname = null;
         this.realName = null;
 
         this.connected = false;
-        this.usingSSL = false;
 
         this.connection.addMessageListener(
             MessageFilters.message(MessageType.PING, (String) null),
             });
     }
 
+    void setSSLContext(SSLContext sslContext) {
+        this.sslContext = sslContext;
+    }
+
+    SSLContext getSSLContext() {
+        if (sslContext == null) {
+            sslContext = getDefaultSSLContext();
+        }
+
+        return sslContext;
+    }
+
     private static TrustManager createNonValidatingTrustManager() {
         return new X509TrustManager() {
             @Override
         return defaultSSLContext;
     }
 
-    public void setSSLContext(SSLContext sslContext) {
-        this.sslContext = sslContext;
-    }
-
-    public SSLContext getSSLContext() {
-        if (sslContext == null) {
-            sslContext = getDefaultSSLContext();
-        }
-
-        return sslContext;
-    }
-
     private SslHandler getClientSSLHandler() {
         SSLContext context = getSSLContext();
         SSLEngine engine = context.createSSLEngine();
         return new SslHandler(engine);
     }
 
-    private URI parseConnectURISpec(String uriSpec) {
-        final URI uri;
-
-        try {
-            uri = new URI(uriSpec);
-        } catch (URISyntaxException e) {
-            throw new RuntimeException(e);
-        }
-
-        if (uri.getScheme().toLowerCase().equals("irc")) {
-            usingSSL = false;
-        } else if (uri.getScheme().toLowerCase().equals("ircs")) {
-            usingSSL = true;
-        } else {
-            throw new ConnectionException("protocol must be one of irc or ircs");
-        }
-
-        int port = uri.getPort();
-
-        if (port == -1) {
-            if (usingSSL) {
-                port = DEFAULT_SSL_PORT;
-            } else {
-                port = DEFAULT_PORT;
-            }
-        }
-
-        try {
-            return new URI(uri.getScheme(), null, uri.getHost(), port, null, null, null);
-        } catch (URISyntaxException e) {
-            throw new RuntimeException("unexpected exception", e);
-        }
-    }
-
     private void doSSLHandshake(SslHandler sslHandler) {
         log.debug("performing SSL handshake");
         ChannelFuture handshakeFuture = sslHandler.handshake();
     }
 
     /**
-     * Connect with a password and with the given information
+     * Connect to the remote server and perform the SSL handshake if SSL is being used.
      */
-    @Override
-    public void connect(String uriSpec) {
-        URI uri = parseConnectURISpec(uriSpec);
-
+    void connect(SocketAddress socketAddress, boolean useSSL) {
         ChannelFactory channelFactory = new NioClientSocketChannelFactory(
             Executors.newCachedThreadPool(),
             Executors.newCachedThreadPool());
         ChannelPipeline clientPipeline = NettyChannelPipeline.newPipeline(connection);
         SslHandler sslHandler = null;
 
-        if (usingSSL) {
+        if (useSSL) {
             sslHandler = getClientSSLHandler();
             clientPipeline.addFirst("ssl", sslHandler);
         }
         bootstrap.setPipeline(clientPipeline);
 
         /* Perform connection */
-        ChannelFuture future = bootstrap.connect(new InetSocketAddress(uri.getHost(), uri.getPort()));
+        ChannelFuture future = bootstrap.connect(socketAddress);
 
         log.debug("connecting");
 
         if (future.isSuccess()) {
             log.debug("connected successfully");
 
-            if (usingSSL) {
+            if (useSSL) {
                 doSSLHandshake(sslHandler);
             }
 
             connected = true;
-            registerConnection();
         } else {
             log.debug("connection failed");
             throw new ConnectionException(future.getCause());
         }
     }
 
-    private void registerConnection() {
+    void registerConnection(String nick, String username, String hostname, String realName, String password) {
         log.debug("registering connection");
 
-        Message nickMessage = new Message(MessageType.NICK, this.nick);
-        Message userMessage = new Message(MessageType.USER,
-            this.username, this.hostname, this.servername, this.realName);
+        Message nickMessage = new Message(MessageType.NICK, nick);
+        Message userMessage = new Message(MessageType.USER, username, hostname, hostname, realName);
 
-        if (this.password != null) {
+        if (password != null) {
             /* Send a PASS message first */
-            connection.send(new Message(MessageType.PASS, this.password));
+            connection.send(new Message(MessageType.PASS, password));
         }
 
         Message response;
             log.debug("connection registered");
             break;
         }
+
+        this.nick = nick;
+        this.username = username;
+        this.hostname = hostname;
+        this.realName = realName;
     }
 
     /**
      * @return the new IRCChannel object or null if the channel could not be
      *         joined
      */
+    @Override
     public Channel join(String channelName) {
         if (!connected) {
             throw new NotConnectedException();
     }
 
     @Override
-    public String getPassword() {
-        return password;
-    }
-
-    @Override
-    public void setPassword(String password) {
-        if (connected) {
-            throw new IllegalStateException("can't set password, already connected");
-        }
-
-        this.password = password;
-    }
-
-    @Override
     public String getNick() {
         return nick;
     }
                 throw new RuntimeException("request interrupted");
             }
         }
-
-        this.nick = nick;
     }
 
     @Override
     }
 
     @Override
-    public void setUsername(String username) {
-        if (connected) {
-            throw new IllegalStateException("can't set username, already connected");
-        }
-
-        this.username = username;
-    }
-
-    @Override
     public String getHostname() {
         return hostname;
     }
 
     @Override
-    public void setHostname(String hostname) {
-        if (connected) {
-            throw new IllegalStateException("can't set hostname, already connected");
-        }
-
-        this.hostname = hostname;
-    }
-
-    @Override
     public String getRealName() {
         return realName;
     }
 
     @Override
-    public void setRealName(String realName) {
-        if (connected) {
-            throw new IllegalStateException("can't set real name, already connected");
-        }
-
-        this.realName = realName;
-    }
-
-    @Override
     public Connection getConnection() {
         return connection;
     }

File brewtab-irc/src/main/java/com/brewtab/irc/util/Log4jAppender.java

             }
         }
 
-        client = ClientFactory.newClient();
-        client.setNick(nick);
-        client.setUsername("log4j");
-        client.setHostname(localhost);
-        client.setRealName("Brewtab IRC log4j appender");
-        client.connect(url);
+        ClientFactory clientFactory = ClientFactory.newInstance();
+        clientFactory.setNick(nick);
+        clientFactory.setUsername("log4j");
+        clientFactory.setHostname(localhost);
+        clientFactory.setRealName("Brewtab IRC log4j appender");
+
+        client = clientFactory.connect(url);
     }
 
     private void init() {

File brewtab-ircbot/src/main/java/com/brewtab/ircbot/Bot.java

     private static final Logger log = LoggerFactory.getLogger(Bot.class);
 
     public static void main(String[] args) throws Exception {
-        /* Create IRC client */
-        Client client = ClientFactory.newClient();
+        /* Create and connect IRC client */
+        Client client = ClientFactory.newInstance().connect("irc://testbot@irc.brewtab.com");
 
         /* Create logger */
         Class.forName("org.h2.Driver");
         /* Listener for ++ and -- */
         PlusPlus plusPlus = new PlusPlus(properties);
 
-        /* Will block until connection process is complete */
-        client.setNick("testbot");
-        client.setUsername("bot");
-        client.setHostname("kitimat");
-        client.setRealName("Mr. Bot");
-
-        /* Connect to the server */
-        client.connect("irc://irc.brewtab.com");
-
-        /*
-         * Join a channel. Channels can also be directly instantiated and
-         * separately joined
-         */
+        /* Join a channel */
         Channel c = client.join("#bot");
 
         StringBuilder sb = new StringBuilder();