net.kano.joscar.net
Class ClientConn

java.lang.Object
  extended byClientConn
Direct Known Subclasses:
ClientFlapConn

public class ClientConn
extends java.lang.Object

A somewhat simple, asynchronous interface to a TCP-based outgoing or "client" connection. Provides a concept of connection state as well as a stream handler that processes the socket's data streams, once connected, in its own thread.

One shortcoming of this class is that it does not by default support a proxy of any kind. That is, there are no connection states relating to connecting to a proxy. However, one can use a custom javax.net.SocketFactory that connects to the proxy and then returns that Socket, or even something more complicated (like returning a custom subclass of Socket in the socket factory for some sort of proxy with extrastream metadata).

As stated above, this class provides a notion of the current state of a connection. The following is a list of all possible state transitions and each transition's meaning. Note that when the state changes, all listeners are notified of the old state, the new state, and a "reason" object whose type varies (though it is most commonly a java.lang.Exception or a java.lang.Error). The type and meaning of this reason object for each state transition is given below.

STATE_NOT_CONNECTED -> STATE_INITING -> STATE_FAILED
Creating the connection thread failed
Reason object: the java.lang.Throwable that caused the failure
STATE_NOT_CONNECTED -> STATE_INITING -> STATE_RESOLVING -> STATE_FAILED
Looking up the specified hostname failed (maybe the host does not exist)
Reason object: a java.net.UnknownHostException
STATE_NOT_CONNECTED -> STATE_INITING -> [STATE_RESOLVING (optional)] -> STATE_CONNECTING -> STATE_FAILED
Making a TCP connection to the given server on the given port failed
Reason object: a java.net.IOException
STATE_NOT_CONNECTED -> STATE_INITING -> [STATE_RESOLVING (optional)] -> STATE_CONNECTING -> STATE_CONNECTED -> STATE_NOT_CONNECTED
This is the normal, healthy progression of the connection state
Reason object:
If disconnect() was called
The reason object will be REASON_ON_PURPOSE
If a connection/socket error occurred that closed the connection
The reason object will be the java.lang.IOException that caused the connection to close
If the connection was closed in another way (that is, if the stream handler returned normally)
The reason object will be REASON_CONN_CLOSED
Just to make things more confusing, if you call disconnect during a connection, the state will revert to STATE_NOT_CONNECTED no matter what state it's currently in.

Note that this class has various means of setting both a hostname and an IP address to use for connecting. More importantly, note that connect will fail if both of these are set and if neither of these is set. So what does this mean? Yes, it means only one of these values can be non-null when connect is called.

You may wonder why I bothered to allow one to set both a hostname and an InetAddress. I did this because often one wants to resolve a hostname in the same thread as one is connecting on, as resolving and connecting normally happen in succession when making a connection.

Note that as far as this author is aware, every method in this class is completely thread-safe. One should also note that connection listeners' listener methods are called with a lock on the ClientConn and that the stream handler's handleStream method is not.
Also note that ClientConns are created with no stream handler, no connection listeners, and a default socket factory (null). A typical usage of ClientConn, then, might be as follows:
ClientConn conn = new ClientConn("joust.kano.net", 80);
conn.addConnListener(myConnectionListener);
conn.setStreamHandler(myStreamHandler);
conn.setSocketFactory(new SomeSortOfProxySocketFactoryYouMade());

conn.connect();
System.out.println("Connecting...");
 
Note that the italicized portion of the above code sets a custom socket factory. This step is by no means required, but is useful for creating connections through a proxy. See setSocketFactory for details. Also note that the code prints a "Connecting..." message after calling connect. If you don't understand that this class is completely asynchronous by now, I don't think you ever will.


Nested Class Summary
static class ClientConn.State
          Represents a single connection state.
 
Field Summary
static ClientConn.State REASON_CONN_CLOSED
          A reason indicating that the reason for a state change to NOT_CONNECTED was that the socket was closed for some reason.
static ClientConn.State REASON_ON_PURPOSE
          A reason indicating that the reason for a state change to NOT_CONNECTED was that disconnect was called.
static ClientConn.State STATE_CONNECTED
          A state indicating that a TCP connection has succeeded and is currently open.
static ClientConn.State STATE_CONNECTING
          A state indicating that a TCP connection attempt is being made to the given server on the given port.
static ClientConn.State STATE_FAILED
          A state indicating that some stage of the connection failed.
static ClientConn.State STATE_INITING
          A state indicating that this FLAP client is preparing to connect.
static ClientConn.State STATE_NOT_CONNECTED
          A state indicating that this FLAP client is not connected to a server.
static ClientConn.State STATE_RESOLVING
          A state indicating that the given hostname is being resolved to an IP address before connecting.
 
Constructor Summary
ClientConn()
          Creates a ClientConn with no hostname/IP or port.
ClientConn(java.net.InetAddress ip, int port)
          Creates a ClientConn for the given IP address and port number.
ClientConn(java.lang.String host, int port)
          Creates a ClientConn for the given hostname and port number.
 
Method Summary
 void addConnListener(ClientConnListener l)
          Adds a connection listener to this connection.
 void connect()
          Attempts to connect using the values of host or IP address and TCP port which were, presumably, set before this method was called.
 void disconnect()
          If not already disconnected, this disconnects the TCP socket associated with this connection and sets the connection state to STATE_NOT_CONNECTED.
 java.lang.String getHost()
          Returns the hostname associated with this connection.
 java.net.InetAddress getIpAddress()
          Returns the IP address associated with this connection.
 int getPort()
          Returns the TCP port associated with this connection.
 java.net.Socket getSocket()
          Returns the socket on which this connection resides, or null if this connection has no underlying socket yet.
 javax.net.SocketFactory getSocketFactory()
          Sets this FLAP connection's socket factory.
 ClientConn.State getState()
          Returns the current connection state.
 ClientConnStreamHandler getStreamHandler()
          Returns this connection's "stream handler."
protected  void processError(java.lang.Throwable t)
          Closes this connection and sets the state to STATE_NOT_CONNECTED, with the given exception or error as the state change's reason object.
 void removeConnListener(ClientConnListener l)
          Removes a connection listener from this connection.
 void setHost(java.lang.String host)
          Sets the hostname associated with this connection.
 void setIpAddress(java.net.InetAddress ip)
          Sets the IP address associated with this connection.
 void setPort(int port)
          Sets the TCP port associated with this connection.
 void setSocketFactory(javax.net.SocketFactory socketFactory)
          Sets the socket factory this FLAP connection should use to create an outgoing socket.
 void setStreamHandler(ClientConnStreamHandler streamHandler)
          Sets the "stream handler" for this connection to the given handler.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

STATE_NOT_CONNECTED

public static final ClientConn.State STATE_NOT_CONNECTED
A state indicating that this FLAP client is not connected to a server.


STATE_INITING

public static final ClientConn.State STATE_INITING
A state indicating that this FLAP client is preparing to connect. This state normally does not last for more than a few milliseconds.


STATE_RESOLVING

public static final ClientConn.State STATE_RESOLVING
A state indicating that the given hostname is being resolved to an IP address before connecting.


STATE_CONNECTING

public static final ClientConn.State STATE_CONNECTING
A state indicating that a TCP connection attempt is being made to the given server on the given port.


STATE_CONNECTED

public static final ClientConn.State STATE_CONNECTED
A state indicating that a TCP connection has succeeded and is currently open.


STATE_FAILED

public static final ClientConn.State STATE_FAILED
A state indicating that some stage of the connection failed. See ClientFlapConn documentation for details on state transitions and meanings.


REASON_ON_PURPOSE

public static final ClientConn.State REASON_ON_PURPOSE
A reason indicating that the reason for a state change to NOT_CONNECTED was that disconnect was called.


REASON_CONN_CLOSED

public static final ClientConn.State REASON_CONN_CLOSED
A reason indicating that the reason for a state change to NOT_CONNECTED was that the socket was closed for some reason. This normally means some sort of network failure.

Constructor Detail

ClientConn

public ClientConn()
Creates a ClientConn with no hostname/IP or port. (You can use setHost(java.lang.String), setIpAddress(java.net.InetAddress), and setPort(int) to set them later.)


ClientConn

public ClientConn(java.lang.String host,
                  int port)
Creates a ClientConn for the given hostname and port number. The given hostname and port will be be used to connect to when connect is called.

Parameters:
host - the hostname to connect to when connect is called
port - the port to connect to when connect is called

ClientConn

public ClientConn(java.net.InetAddress ip,
                  int port)
Creates a ClientConn for the given IP address and port number. The given IP address and port will be be used to connect to when connect is called.

Parameters:
ip - the hostname to connect to when connect is called
port - the port to connect to when connect is called
Method Detail

addConnListener

public final void addConnListener(ClientConnListener l)
Adds a connection listener to this connection.

Parameters:
l - the listener to add

removeConnListener

public final void removeConnListener(ClientConnListener l)
Removes a connection listener from this connection.

Parameters:
l - the listener to remove

getSocket

public final java.net.Socket getSocket()
Returns the socket on which this connection resides, or null if this connection has no underlying socket yet.

Returns:
this connection's socket

getHost

public final java.lang.String getHost()
Returns the hostname associated with this connection.

Returns:
the hostname associated with this connection

setHost

public final void setHost(java.lang.String host)
Sets the hostname associated with this connection.

Parameters:
host - the hostname to associate with this connection

getIpAddress

public final java.net.InetAddress getIpAddress()
Returns the IP address associated with this connection.

Returns:
the IP address associated with this connection

setIpAddress

public final void setIpAddress(java.net.InetAddress ip)
Sets the IP address associated with this connection.

Parameters:
ip - the IP address associated with this connection

getPort

public final int getPort()
Returns the TCP port associated with this connection.

Returns:
the TCP port associated with this connection

setPort

public final void setPort(int port)
Sets the TCP port associated with this connection.

Parameters:
port - the TCP port associated with this connection

getState

public final ClientConn.State getState()
Returns the current connection state. This will be one of STATE_NOT_CONNECTED, STATE_INITING, STATE_RESOLVING, STATE_CONNECTING, STATE_CONNECTED, or STATE_FAILED; see each value's individual documentation for details.

Returns:
the current state of this connection

connect

public final void connect()
                   throws java.lang.IllegalStateException
Attempts to connect using the values of host or IP address and TCP port which were, presumably, set before this method was called. Upon successful connection, a Socket will be passed to this ClientConn's stream handler.

Note that this method can only be called when the connection is in either of the states STATE_NOT_CONNECTED and STATE_FAILED; otherwise one must call disconnect() before calling this method.

Throws:
java.lang.IllegalStateException - if a connection attempt is already being made; if both IP and hostname are both set; if neither IP or hostname is set; if port is not set

processError

protected final void processError(java.lang.Throwable t)
Closes this connection and sets the state to STATE_NOT_CONNECTED, with the given exception or error as the state change's reason object. Note that calling this method will have no effect if the connection state is already STATE_NOT_CONNECTED or STATE_FAILED.

Parameters:
t - an exception or error that caused the connection to close

disconnect

public final void disconnect()
If not already disconnected, this disconnects the TCP socket associated with this connection and sets the connection state to STATE_NOT_CONNECTED. Note that if the connection state is already STATE_NOT_CONNECTED or STATE_FAILED no state change will take place.


setSocketFactory

public final void setSocketFactory(javax.net.SocketFactory socketFactory)
Sets the socket factory this FLAP connection should use to create an outgoing socket. If socketFactory is null, as is the default value, new Socket(..) is used in place of a using a socket factory.

Parameters:
socketFactory - a socket factory to use in creating the outgoing OSCAR connection, or null to not use a factory

getSocketFactory

public final javax.net.SocketFactory getSocketFactory()
Sets this FLAP connection's socket factory. This factory will be used to create the outgoing socket to the OSCAR server. Note that if this is null (the default value) then new Socket(..) is used in place of using a socket factory to create a socket.

Returns:
the socket factory associated with this FLAP connection

setStreamHandler

public final void setStreamHandler(ClientConnStreamHandler streamHandler)
Sets the "stream handler" for this connection to the given handler. The stream handler is passed a Socket created by this ClientConn as soon as it has been successfully created.

Note that streamHandler can be null if you really want it to be; a value of null simply means the connection will be made and immediately dropped.

Also note that the stream handler's value will be read after the socket has been created, so it would be feasible (though not recommended) to postpone setting a stream handler until the connection's state has been changed to STATE_CONNECTED.

Also note that, as one should expect, new ClientConns are initialized with no stream handler (a value of null).

Parameters:
streamHandler - a "stream handler" for this connection
See Also:
ClientConnStreamHandler

getStreamHandler

public final ClientConnStreamHandler getStreamHandler()
Returns this connection's "stream handler." See above for details on what this value means. Note that the returned value may be null.

Returns:
this connection's stream handler