edu.nps.moves.disutil
Class NioServer

java.lang.Object
  extended by edu.nps.moves.disutil.NioServer
Direct Known Subclasses:
PduNioMulticastReceiver

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 nioServerTcpDataReceived( NioServer.Event evt ){
         ByteBuffer buff = evt.getBuffer();
         ...
     }   // end data received

     public void nioServerUdpDataReceived( 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.

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

Nested Class Summary
 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 BUFFER_SIZE_PROP
          The buffer size property.
static java.lang.String LAST_EXCEPTION_PROP
           
static java.lang.String SINGLE_TCP_PORT_PROP
           
static java.lang.String SINGLE_UDP_PORT_PROP
           
static java.lang.String STATE_PROP
           
static java.lang.String TCP_BINDINGS_PROP
           
static java.lang.String UDP_BINDINGS_PROP
           
 
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.
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)
          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 buffer)
          Fire when data is received.
protected  void fireUdpDataReceived(java.nio.channels.SelectionKey key, java.nio.ByteBuffer buffer, java.net.SocketAddress remote)
          Fire when data is received.
 int getBufferSize()
          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 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 STOPPED, STARTING, or STARTED.
 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 TCP packets.
 void setBufferSize(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.
 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

BUFFER_SIZE_PROP

public static final java.lang.String BUFFER_SIZE_PROP
The buffer size property.

See Also:
Constant Field Values

STATE_PROP

public static final java.lang.String STATE_PROP
See Also:
Constant Field Values

LAST_EXCEPTION_PROP

public static final java.lang.String LAST_EXCEPTION_PROP
See Also:
Constant Field Values

TCP_BINDINGS_PROP

public static final java.lang.String TCP_BINDINGS_PROP
See Also:
Constant Field Values

UDP_BINDINGS_PROP

public static final java.lang.String UDP_BINDINGS_PROP
See Also:
Constant Field Values

SINGLE_TCP_PORT_PROP

public static final java.lang.String SINGLE_TCP_PORT_PROP
See Also:
Constant Field Values

SINGLE_UDP_PORT_PROP

public static final java.lang.String SINGLE_UDP_PORT_PROP
See Also:
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 STOPPED, STARTING, or STARTED.

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 TCP packets. On entering this method, the state is assumed to be STARTING. Upon exiting this method, the state will be STOPPING.


getBufferSize

public int getBufferSize()
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

setBufferSize

public void setBufferSize(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

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

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

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
group -
Returns:
this to aid in chaining

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 buffer)
Fire when data is received.

Parameters:
key - the SelectionKey associated with the data
buffer - the buffer containing the new (and possibly leftover) data

fireUdpDataReceived

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

Parameters:
key - the SelectionKey associated with the data
buffer - the buffer containing the data
remote - the source address of the datagram or null if not available

fireConnectionClosed

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

Parameters:
key - The key for the closed connection.

fireNewConnection

protected void fireNewConnection(java.nio.channels.SelectionKey key)
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