Class NioServer

java.lang.Object
  extended by NioServer

public class NioServer
extends java.lang.Object

A robust class for establishing simultaneous TCP and UDP servers and manipulating their listening ports. The NioServer.Events and property change events make it an appropriate tool in a threaded, GUI application. It is almost identical in design to the UdpServer and TcpServer classes that should have accompanied this class when you downloaded it.

To start a server, create a new NioServer and call start():

 NioServer server = new NioServer();
 server.start();

You'll want to bind to a port or two:

 server.addTcpBinding( new InetSocketAddress( 80 ) );
 server.addUdpBinding( new InetSocketAddress( 80 ) );

Of course it won't be much help unless you register as a listener so you'll know when data has come in:

 server.addNioServerListener( new NioServer.Adapter(){
     public void tcpDataReceived( NioServer.Event evt ){
         ByteBuffer buff = evt.getBuffer();
         ...
     }   // end data received

     public void udpDataReceived( NioServer.Event evt ){
         ByteBuffer buff = evt.getBuffer();
         ...
     }   // end data received
 });

The server runs on one thread, and all events are fired on that thread. Consider offloading heavy processing to another thread. Be aware that you can register multiple listeners to respond to incoming data so be mindful of more than one listener being around to makes calls on the data.

The public methods are all synchronized on this, and great care has been taken to avoid deadlocks and race conditions. That being said, there may still be bugs (please contact the author if you find any), and you certainly still have the power to introduce these problems yourself.

It's often handy to have your own class extend this one rather than making an instance field to hold a NioServer where you'd have to pass along all the setPort(...) methods and so forth.

The supporting NioServer.Event, NioServer.Listener, and NioServer.Adapter classes are static inner classes in this file so that you have only one file to copy to your project. You're welcome.

Since the TcpServer.java, UdpServer.java, and NioServer.java are so similar, and since lots of copying and pasting was going on among them, you may find some comments that refer to TCP instead of UDP or vice versa. Please feel free to let me know, so I can correct that.

This code is released into the Public Domain. Since this is Public Domain, you don't need to worry about licensing, and you can simply copy this NioServer.java file to your own package and use it as you like. Enjoy. Please consider leaving the following statement here in this code:

This NioServer class was copied to this project from its source as found at iHarder.net.

Author:
Robert Harder, rharder@users.sourceforge.net
See Also:
NioServer, NioServer.Adapter, NioServer.Event, NioServer.Listener

Nested Class Summary
static class NioServer.Adapter
          A helper class that implements all methods of the NioServer.Listener interface with empty methods.
static class NioServer.Event
          An event representing activity by a NioServer.
static interface NioServer.Listener
          An interface for listening to events from a NioServer.
static class NioServer.State
          One of four possible states for the server to be in:
 
Field Summary
static java.lang.String INPUT_BUFFER_SIZE_PROP
          Refers to the size of the input buffer.
static java.lang.String LAST_EXCEPTION_PROP
          Refers to the last exception encountered internally on the server thread.
static java.lang.String OUTPUT_BUFFER_SIZE_PROP
          Refers to the size of the output buffer.
static java.lang.String SINGLE_TCP_PORT_PROP
          Refers to the convenience methods for listening on a single port.
static java.lang.String SINGLE_UDP_PORT_PROP
          Refers to the convenience methods for listening on a single port.
static java.lang.String STATE_PROP
          Refers to the state of the server (STARTING, STARTED, STOPPING, STOPPED).
static java.lang.String TCP_BINDINGS_PROP
          Refers to the TCP bindings for the server.
static java.lang.String UDP_BINDINGS_PROP
          Refers to the UDP bindings for the server.
 
Constructor Summary
NioServer()
          Constructs a new NioServer, listening to nothing, and not started.
NioServer(java.util.concurrent.ThreadFactory factory)
          Constructs a new NioServer, listening to nothing, and not started.
 
Method Summary
 void addNioServerListener(NioServer.Listener l)
          Adds a NioServer.Listener.
 void addPropertyChangeListener(java.beans.PropertyChangeListener listener)
          Add a property listener.
 void addPropertyChangeListener(java.lang.String property, java.beans.PropertyChangeListener listener)
          Add a property listener for the named property.
 NioServer addTcpBinding(java.net.SocketAddress addr)
          Adds a TCP binding to the server.
 NioServer addUdpBinding(java.net.SocketAddress addr)
          Adds a UDP binding to the server.
 NioServer addUdpBinding(java.net.SocketAddress addr, java.lang.String group)
          Experimental Hack - Adds a UDP binding to the server and joins the given multicast group (if group is not null and is a valid multicast group).
 NioServer clearTcpBindings()
          Clears all TCP bindings.
 NioServer clearUdpBindings()
          Clears all UDP bindings.
 void closeAfterWriting(java.nio.channels.SelectionKey key)
          Convenience method for telling the server to close the connection after the last byte of the output buffer has been written.
protected  void fireConnectionClosed(java.nio.channels.SelectionKey key)
          Fire when a connection is closed remotely.
protected  void fireExceptionNotification(java.lang.Throwable t)
          Fires a property change event with the new exception.
protected  void fireNewConnection(java.nio.channels.SelectionKey key, java.nio.ByteBuffer outBuff)
          Fire when a new connection is established.
 void fireProperties()
          Fires property chagne events for all current values setting the old value to null and new value to the current.
protected  void firePropertyChange(java.lang.String prop, java.lang.Object oldVal, java.lang.Object newVal)
          Fire a property change event on the current thread.
protected  void fireTcpDataReceived(java.nio.channels.SelectionKey key, java.nio.ByteBuffer inBuff, java.nio.ByteBuffer outBuff)
          Fire when data is received.
protected  void fireTcpReadyToWrite(java.nio.channels.SelectionKey key, java.nio.ByteBuffer outBuff)
          Fire when data is received.
protected  void fireUdpDataReceived(java.nio.channels.SelectionKey key, java.nio.ByteBuffer inBuff, java.nio.ByteBuffer outBuff, java.net.SocketAddress remote)
          Fire when data is received.
 int getInputBufferSize()
          Returns the size of the ByteBuffer used to read from the connections.
 java.lang.Throwable getLastException()
          Returns the last exception (Throwable, actually) that the server encountered.
static java.util.logging.Level getLoggingLevel()
          Static method returning the logging level using Java's java.util.logging package.
 int getOutputBufferSize()
          Returns the size of the ByteBuffer used to write to the connections.
 int getSingleTcpPort()
          Returns the port for the single TCP binding in effect, or -1 (minus one) if there are no or multiple TCP bindings or some other error.
 int getSingleUdpPort()
          Returns the port for the single UDP binding in effect, or -1 (minus one) if there are no or multiple UDP bindings or some other error.
 NioServer.State getState()
          Returns the current state of the server, one of STARTING, STARTED, STOPPING, or STOPPED.
 java.util.Set<java.net.SocketAddress> getTcpBindings()
          Returns a set of socket addresses that the server is (or will be when started) bound to/listening on.
 java.util.Map<java.net.SocketAddress,java.lang.String> getUdpBindings()
          Returns a map of socket addresses and multicast groups that the server is (or will be when started) bound to/listening on.
 void removeNioServerListener(NioServer.Listener l)
          Removes a NioServer.Listener.
 void removePropertyChangeListener(java.beans.PropertyChangeListener listener)
          Remove a property listener.
 void removePropertyChangeListener(java.lang.String property, java.beans.PropertyChangeListener listener)
          Remove a property listener for the named property.
 NioServer removeTcpBinding(java.net.SocketAddress addr)
          Removes a TCP binding.
 NioServer removeUdpBinding(java.net.SocketAddress addr)
          Removes a UDP binding.
 void reset()
          Resets the server, if it is running, otherwise does nothing.
protected  void runServer()
          This method starts up and listens indefinitely for network connections.
 void setInputBufferSize(int size)
          Sets the size of the ByteBuffer used to read from the connections.
static void setLoggingLevel(java.util.logging.Level level)
          Static method to set the logging level using Java's java.util.logging package.
 void setNotifyOnWritable(java.nio.channels.SelectionKey key, boolean notify)
          Sets whether or not events will fire when a channel is ready to be written to.
 void setOutputBufferSize(int size)
          Sets the size of the ByteBuffer used to write from the connections.
 NioServer setSingleTcpPort(int port)
          Convenience method for clearing all bindings and setting up listening for TCP on the given port.
 NioServer setSingleUdpPort(int port)
          Convenience method for clearing all bindings and setting up listening for UDP on the given port.
 NioServer setSingleUdpPort(int port, java.lang.String group)
          Convenience method for clearing all bindings and setting up listening for UDP on the given port and joining the provided multicast group.
protected  void setState(NioServer.State state)
          Sets the state and fires an event.
 NioServer setTcpBindings(java.util.Set<java.net.SocketAddress> newSet)
          Sets the TCP bindings that the server should use.
 NioServer setUdpBindings(java.util.Map<java.net.SocketAddress,java.lang.String> newMap)
          Sets the UDP bindings that the server should use.
 void start()
          Attempts to start the server listening and returns immediately.
 void stop()
          Attempts to stop the server, if the server is in the STARTED state, and returns immediately.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

INPUT_BUFFER_SIZE_PROP

public static final java.lang.String INPUT_BUFFER_SIZE_PROP
Refers to the size of the input buffer.

See Also:
setInputBufferSize(int), getInputBufferSize(), Constant Field Values

OUTPUT_BUFFER_SIZE_PROP

public static final java.lang.String OUTPUT_BUFFER_SIZE_PROP
Refers to the size of the output buffer.

See Also:
setOutputBufferSize(int), getOutputBufferSize(), Constant Field Values

STATE_PROP

public static final java.lang.String STATE_PROP
Refers to the state of the server (STARTING, STARTED, STOPPING, STOPPED).

See Also:
getState(), Constant Field Values

LAST_EXCEPTION_PROP

public static final java.lang.String LAST_EXCEPTION_PROP
Refers to the last exception encountered internally on the server thread.

See Also:
getLastException(), Constant Field Values

TCP_BINDINGS_PROP

public static final java.lang.String TCP_BINDINGS_PROP
Refers to the TCP bindings for the server.

See Also:
addTcpBinding(java.net.SocketAddress), getTcpBindings(), clearTcpBindings(), setSingleTcpPort(int), getSingleTcpPort(), Constant Field Values

UDP_BINDINGS_PROP

public static final java.lang.String UDP_BINDINGS_PROP
Refers to the UDP bindings for the server.

See Also:
addUdpBinding(java.net.SocketAddress), getUdpBindings(), clearUdpBindings(), setSingleUdpPort(int), getSingleUdpPort(), Constant Field Values

SINGLE_TCP_PORT_PROP

public static final java.lang.String SINGLE_TCP_PORT_PROP
Refers to the convenience methods for listening on a single port.

See Also:
addTcpBinding(java.net.SocketAddress), getTcpBindings(), clearTcpBindings(), setSingleTcpPort(int), getSingleTcpPort(), Constant Field Values

SINGLE_UDP_PORT_PROP

public static final java.lang.String SINGLE_UDP_PORT_PROP
Refers to the convenience methods for listening on a single port.

See Also:
addUdpBinding(java.net.SocketAddress), getUdpBindings(), clearUdpBindings(), setSingleUdpPort(int), getSingleUdpPort(), Constant Field Values
Constructor Detail

NioServer

public NioServer()
Constructs a new NioServer, listening to nothing, and not started.


NioServer

public NioServer(java.util.concurrent.ThreadFactory factory)
Constructs a new NioServer, listening to nothing, and not started. The provided ThreadFactory will be used when starting and running the server.

Parameters:
factory - the ThreadFactory to use when starting the server
Method Detail

start

public void start()
Attempts to start the server listening and returns immediately. Listen for start events to know if the server was successfully started.

See Also:
NioServer.Listener

stop

public void stop()
Attempts to stop the server, if the server is in the STARTED state, and returns immediately. Be sure to listen for stop events to know if the server was successfully stopped.

See Also:
NioServer.Listener

getState

public NioServer.State getState()
Returns the current state of the server, one of STARTING, STARTED, STOPPING, or STOPPED.

Returns:
state of the server

setState

protected void setState(NioServer.State state)
Sets the state and fires an event. This method does not change what the server is doing, only what is reflected by the currentState variable.

Parameters:
state - the new state of the server

reset

public void reset()
Resets the server, if it is running, otherwise does nothing. This is accomplished by registering as a listener, stopping the server, detecting the stop, unregistering, and starting the server again. It's a useful design pattern, and you may want to look at the source code for this method to check it out.


runServer

protected void runServer()
This method starts up and listens indefinitely for network connections. On entering this method, the state is assumed to be STARTING. Upon exiting this method, the state will be STOPPING.


setNotifyOnWritable

public void setNotifyOnWritable(java.nio.channels.SelectionKey key,
                                boolean notify)
Sets whether or not events will fire when a channel is ready to be written to. After a NioServer.Listener.tcpReadyToWrite(NioServer.Event) returns with no data in the output buffer, this will be turned off until you either A) turn it on yourself, or B) provide data in an output buffer from another event.

Parameters:
key - The accKey representing the connection in question
notify - Whether or not to notify
Throws:
java.lang.NullPointerException - if accKey is null

closeAfterWriting

public void closeAfterWriting(java.nio.channels.SelectionKey key)
Convenience method for telling the server to close the connection after the last byte of the output buffer has been written.

Parameters:
key - the SelectionKey for the corresponding connection

getInputBufferSize

public int getInputBufferSize()
Returns the size of the ByteBuffer used to read from the connections. This refers to the buffer that will be passed along with NioServer.Event objects as data is received and so forth.

Returns:
The size of the ByteBuffer

setInputBufferSize

public void setInputBufferSize(int size)
Sets the size of the ByteBuffer used to read from the connections. This refers to the buffer that will be passed along with NioServer.Event objects as data is received and so forth.

Parameters:
size - The size of the ByteBuffer
Throws:
java.lang.IllegalArgumentException - if size is not positive

getOutputBufferSize

public int getOutputBufferSize()
Returns the size of the ByteBuffer used to write to the connections. This refers to the buffer that will be passed along with NioServer.Event objects.

Returns:
The size of the ByteBuffer

setOutputBufferSize

public void setOutputBufferSize(int size)
Sets the size of the ByteBuffer used to write from the connections. This refers to the buffer that will be passed along with NioServer.Event objects.

Parameters:
size - The size of the ByteBuffer
Throws:
java.lang.IllegalArgumentException - if size is not positive

addTcpBinding

public NioServer addTcpBinding(java.net.SocketAddress addr)
Adds a TCP binding to the server. Effectively this is how you set which ports and on which interfaces you want the server to listen. In the simplest case, you might do the following to listen generically on port 80: addTcpBinding( new InetAddress(80) );. The server can listen on multiple ports at once.

Parameters:
addr - The address on which to listen
Returns:
"this" to aid in chaining commands

removeTcpBinding

public NioServer removeTcpBinding(java.net.SocketAddress addr)
Removes a TCP binding. Effectively stops the server from listening to this or that port.

Parameters:
addr - The address to stop listening to
Returns:
"this" to aid in chaining commands

getTcpBindings

public java.util.Set<java.net.SocketAddress> getTcpBindings()
Returns a set of socket addresses that the server is (or will be when started) bound to/listening on. This set is not backed by the actual data structures. Changes to this returned set have no effect on the server.

Returns:
set of tcp listening points

setTcpBindings

public NioServer setTcpBindings(java.util.Set<java.net.SocketAddress> newSet)

Sets the TCP bindings that the server should use. The expression setTcpBindings( getTcpBindings() ) should result in no change to the server.

Parameters:
newSet -
Returns:
"this" to aid in chaining commands

clearTcpBindings

public NioServer clearTcpBindings()
Clears all TCP bindings.

Returns:
"this" to aid in chaining commands

addUdpBinding

public NioServer addUdpBinding(java.net.SocketAddress addr)
Adds a UDP binding to the server. Effectively this is how you set which ports and on which interfaces you want the server to listen. In the simplest case, you might do the following to listen generically on port 6997: addUdpBinding( new InetAddress(6997) );. The server can listen on multiple ports at once.

Parameters:
addr - The address on which to listen
Returns:
"this" to aid in chaining commands

addUdpBinding

public NioServer addUdpBinding(java.net.SocketAddress addr,
                               java.lang.String group)

Experimental Hack - Adds a UDP binding to the server and joins the given multicast group (if group is not null and is a valid multicast group). In the simplest case, you might do the following to listen on port 16000 and multicast group 239.0.0.1: addUdpBinding( new InetAddress(16000), "239.0.0.1" );. The server can listen on multiple ports at once.

As of Java 6, the java.nio "New IO" packages don't support multicast groups ("annoyed grunt"), however I found a clever hack at this gentleman's website (http://www.mernst.org/blog/archives/12-01-2006_12-31-2006.html) that makes multicast work -- for now.

Parameters:
addr - The address on which to listen
group - The multicast group to join
Returns:
"this" to aid in chaining commands

removeUdpBinding

public NioServer removeUdpBinding(java.net.SocketAddress addr)
Removes a UDP binding. Effectively stops the server from listening to this or that port.

Parameters:
addr - The address to stop listening to
Returns:
"this" to aid in chaining commands

getUdpBindings

public java.util.Map<java.net.SocketAddress,java.lang.String> getUdpBindings()
Returns a map of socket addresses and multicast groups that the server is (or will be when started) bound to/listening on. This set is not backed by the actual data structures. Changes to this returned set have no effect on the server. The map's value portion will be null if not multicast group is joined for that port or it may have a String which would be the requested multicast group.

Returns:
map of udp listening points

setUdpBindings

public NioServer setUdpBindings(java.util.Map<java.net.SocketAddress,java.lang.String> newMap)

Sets the UDP bindings that the server should use. The expression setTcpBindings( getTcpBindings() ) should result in no change to the server.

The map consists of socket addresses (probably InetSocketAddress) and multicast addresses (the String value).

Parameters:
newMap -
Returns:
"this" to aid in chaining commands

clearUdpBindings

public NioServer clearUdpBindings()
Clears all UDP bindings.

Returns:
"this" to aid in chaining commands

setSingleTcpPort

public NioServer setSingleTcpPort(int port)
Convenience method for clearing all bindings and setting up listening for TCP on the given port.

Parameters:
port - the port to listen to
Returns:
this to aid in chaining
Throws:
java.lang.IllegalArgumentException - if port is out of range

setSingleUdpPort

public NioServer setSingleUdpPort(int port)
Convenience method for clearing all bindings and setting up listening for UDP on the given port.

Parameters:
port - the port to listen to
Returns:
this to aid in chaining
Throws:
java.lang.IllegalArgumentException - if port is out of range

setSingleUdpPort

public NioServer setSingleUdpPort(int port,
                                  java.lang.String group)
Convenience method for clearing all bindings and setting up listening for UDP on the given port and joining the provided multicast group.

Parameters:
port - the port to listen to
Returns:
this to aid in chaining
Throws:
java.lang.IllegalArgumentException - if port is out of range

getSingleTcpPort

public int getSingleTcpPort()
Returns the port for the single TCP binding in effect, or -1 (minus one) if there are no or multiple TCP bindings or some other error.

Returns:
TCP listening port or -1

getSingleUdpPort

public int getSingleUdpPort()
Returns the port for the single UDP binding in effect, or -1 (minus one) if there are no or multiple UDP bindings or some other error.

Returns:
UDP listening port or -1

addNioServerListener

public void addNioServerListener(NioServer.Listener l)
Adds a NioServer.Listener.

Parameters:
l - the listener

removeNioServerListener

public void removeNioServerListener(NioServer.Listener l)
Removes a NioServer.Listener.

Parameters:
l - the listener

fireTcpDataReceived

protected void fireTcpDataReceived(java.nio.channels.SelectionKey key,
                                   java.nio.ByteBuffer inBuff,
                                   java.nio.ByteBuffer outBuff)
Fire when data is received.

Parameters:
key - the SelectionKey associated with the data
outBuff - the outBuff containing the new (and possibly leftoverR) data

fireTcpReadyToWrite

protected void fireTcpReadyToWrite(java.nio.channels.SelectionKey key,
                                   java.nio.ByteBuffer outBuff)
Fire when data is received.

Parameters:
key - the SelectionKey associated with the data
outBuff - the outBuff containing the new (and possibly leftoverR) data

fireUdpDataReceived

protected void fireUdpDataReceived(java.nio.channels.SelectionKey key,
                                   java.nio.ByteBuffer inBuff,
                                   java.nio.ByteBuffer outBuff,
                                   java.net.SocketAddress remote)
Fire when data is received.

Parameters:
key - the SelectionKey associated with the data
inBuff - the input buffer containing the data
remote - the source address of the datagram or null if not available
outBuff - the output buffer for writing data

fireConnectionClosed

protected void fireConnectionClosed(java.nio.channels.SelectionKey key)
Fire when a connection is closed remotely.

Parameters:
key - The accKey for the closed connection.

fireNewConnection

protected void fireNewConnection(java.nio.channels.SelectionKey key,
                                 java.nio.ByteBuffer outBuff)
Fire when a new connection is established.

Parameters:
key - the SelectionKey associated with the connection

fireProperties

public void fireProperties()
Fires property chagne events for all current values setting the old value to null and new value to the current.


firePropertyChange

protected void firePropertyChange(java.lang.String prop,
                                  java.lang.Object oldVal,
                                  java.lang.Object newVal)
Fire a property change event on the current thread.

Parameters:
prop - name of property
oldVal - old value
newVal - new value

addPropertyChangeListener

public void addPropertyChangeListener(java.beans.PropertyChangeListener listener)
Add a property listener.

Parameters:
listener - the listener

addPropertyChangeListener

public void addPropertyChangeListener(java.lang.String property,
                                      java.beans.PropertyChangeListener listener)
Add a property listener for the named property.

Parameters:
property - the property name
listener - the listener

removePropertyChangeListener

public void removePropertyChangeListener(java.beans.PropertyChangeListener listener)
Remove a property listener.

Parameters:
listener - the listener

removePropertyChangeListener

public void removePropertyChangeListener(java.lang.String property,
                                         java.beans.PropertyChangeListener listener)
Remove a property listener for the named property.

Parameters:
property - the property name
listener - the listener

getLastException

public java.lang.Throwable getLastException()
Returns the last exception (Throwable, actually) that the server encountered.

Returns:
last exception

fireExceptionNotification

protected void fireExceptionNotification(java.lang.Throwable t)
Fires a property change event with the new exception.

Parameters:
t -

setLoggingLevel

public static void setLoggingLevel(java.util.logging.Level level)
Static method to set the logging level using Java's java.util.logging package. Example: NioServer.setLoggingLevel(Level.OFF);.

Parameters:
level - the new logging level

getLoggingLevel

public static java.util.logging.Level getLoggingLevel()
Static method returning the logging level using Java's java.util.logging package.

Returns:
the logging level