ecologylab.services.distributed.client
Class NIOClient

java.lang.Object
  extended by ecologylab.generic.Debug
      extended by ecologylab.services.distributed.impl.NIOCore
          extended by ecologylab.services.distributed.impl.NIONetworking
              extended by ecologylab.services.distributed.client.NIOClient
All Implemented Interfaces:
StartAndStoppable, ClientConstants, NetworkingConstants, java.lang.Runnable
Direct Known Subclasses:
NIOAuthClient

public class NIOClient
extends NIONetworking
implements java.lang.Runnable, ClientConstants

Services Client using NIO; a major difference with the NIO version is state tracking. Since the sending methods do not wait for the server to return. This object will listen for incoming messages from the server, and will send any messages that it recieves on its end. Since the underlying implementation is TCP/IP, messages sent should be sent in order, and the responses should match that order. Another major difference between this and the non-NIO version of ServicesClient is that it is StartAndStoppable.

Author:
Zachary O. Toups (toupsz@cs.tamu.edu)

Field Summary
protected  java.util.HashMap<java.lang.String,java.lang.String> headerMap
          Stores the key-value pairings from a parsed HTTP-like header on an incoming message.
protected  java.lang.StringBuilder incomingMessageBuffer
          Stores incoming character data until it can be parsed into an XML message and turned into a Java object.
protected  boolean isSending
           
protected  java.nio.CharBuffer outgoingChars
           
protected  java.lang.StringBuilder outgoingMessageBuffer
          Stores outgoing character data for ResponseMessages.
protected  java.lang.StringBuilder outgoingMessageHeaderBuffer
          Stores outgoing header character data.
protected  PreppedRequestPool pRequestPool
           
protected  int reconnectAttempts
          The number of times a call to reconnect() should attempt to contact the server before giving up and calling stop().
protected  java.lang.StringBuilder requestBuffer
           
protected  java.util.Queue<PreppedRequest> requestsQueue
           
protected  MessageWithMetadataPool<ResponseMessage> responsePool
           
protected  long selectInterval
          selectInterval is passed to select() when it is called in the run loop.
protected  java.lang.String serverAddress
           
protected  int startReadIndex
           
protected  java.nio.channels.SocketChannel thisSocket
           
protected  java.util.Map<java.lang.Long,PreppedRequest> unfulfilledRequests
          A map that stores all the requests that have not yet gotten responses.
protected  int waitBetweenReconnectAttempts
          The number of milliseconds to wait between reconnect attempts.
 
Fields inherited from class ecologylab.services.distributed.impl.NIONetworking
byteBufferPool, connectionCount, objectRegistry, shuttingDown, translationSpace
 
Fields inherited from class ecologylab.services.distributed.impl.NIOCore
portNumber, selector
 
Fields inherited from interface ecologylab.services.distributed.common.ClientConstants
RECONNECT_ATTEMPTS, WAIT_BEWTEEN_RECONNECT_ATTEMPTS
 
Fields inherited from interface ecologylab.services.distributed.common.NetworkingConstants
CHARACTER_ENCODING, CONTENT_LENGTH_STRING, CONTENT_LENGTH_STRING_LENGTH, DECODER, ENCODER, HTTP_HEADER_LINE_DELIMITER, HTTP_HEADER_TERMINATOR, MAX_HTTP_HEADER_LENGTH, MAX_PACKET_SIZE_BYTES, MAX_PACKET_SIZE_CHARACTERS, UNIQUE_IDENTIFIER_STRING
 
Constructor Summary
NIOClient(java.lang.String serverAddress, int portNumber, TranslationSpace messageSpace, Scope<?> objectRegistry)
           
 
Method Summary
 void acceptFinished(java.nio.channels.SelectionKey key)
          Queues a request to change key's interest operations back to READ.
protected  void acceptKey(java.nio.channels.SelectionKey key)
          This method does nothing, as NIOClients do not accept incoming connections.
protected  void acceptReady(java.nio.channels.SelectionKey key)
           
protected  void addUnfulfilledRequest(PreppedRequest req)
          Hook method to allow subclasses to deal with unfulfilled requests in their own way.
protected  void checkAndDropIdleKeys()
          Check for timeout on all allocated keys; deallocate those that are hanging around, but no longer in use.
protected  void clearSessionId()
           
 boolean connect()
          If this client is not already connected, connects to the specified serverAddress on the specified portNumber, then calls start() to begin listening for server responses and processing them, then sends handshake data and establishes the session id.
 boolean connected()
           
protected  void connectReady(java.nio.channels.SelectionKey key)
           
protected  boolean createConnection()
          Side effect of calling start().
protected  PreppedRequest dequeueRequest()
          Returns the next request in the request queue and removes it from that queue.
 void disconnect()
           
 void disconnect(boolean waitForResponses)
           
protected  void enqueueRequestForSending(PreppedRequest request)
           
 long generateUid()
          Increments the internal tracker of the next UID, and returns the current one.
 java.lang.String getServer()
           
 long getUidNoIncrement()
          Returns the most recently used UID.
protected  void invalidateKey(java.nio.channels.SelectionKey key, boolean permanent)
           
 boolean isServerRunning()
          Check to see if the server is running.
 PreppedRequest nonBlockingSendMessage(RequestMessage request)
          Sends request, but does not wait for the response.
protected  void nullOut()
           
protected  int parseHeader(int startChar, java.lang.StringBuilder allIncomingChars)
          Parses the header of an incoming set of characters (i.e.
protected  PreppedRequest prepareAndEnqueueRequestForSending(RequestMessage request)
          Sets the UID for request (if necessary), enqueues it then registers write interest for the NIOClient's selection key and calls wakeup() on the selector.
protected  void processReadData(java.lang.Object readSessionId, java.nio.channels.SelectionKey sk, java.nio.ByteBuffer bytes, int bytesRead)
          This method is called whenever bytes have been read from a socket.
protected  void processResponse(ResponseMessage responseMessageToProcess)
          Process a ResponseMessage received from the server in response to a previously-sent RequestMessage.
protected  void readFinished(java.nio.channels.SelectionKey key)
           
protected  void reconnect()
          Attempts to reconnect this client if it has been disconnected.
protected  void removeBadConnections(java.nio.channels.SelectionKey key)
           
protected  int requestsRemaining()
          Returns the number of requests remaining in the requests queue.
 ResponseMessage sendMessage(RequestMessage request)
          Blocking send.
 ResponseMessage sendMessage(RequestMessage request, int timeOutMillis)
          Blocking send with timeout.
 void setReconnectAttempts(int reconnectAttempts)
           
 void setServer(java.lang.String serverAddress)
           
 void setWaitBetweenReconnectAttempts(int waitBetweenReconnectAttempts)
           
protected  boolean shutdownOK()
           
 void start()
           
 void stop()
           
protected  MessageWithMetadata<ResponseMessage> translateXMLStringToResponse(java.lang.String messageString, int incomingUid)
          Use the ServicesClient and its NameSpace to do the translation.
protected  void unableToRestorePreviousConnection(java.lang.String oldId, java.lang.String newId)
          Hook method to allow subclasses to deal with a failed restore after disconnect.
 void waitForConnect()
          Try and connect to the server.
protected  void writeKey(java.nio.channels.SelectionKey key)
          Writes the bytes from pendingWrites that belong to key.
 
Methods inherited from class ecologylab.services.distributed.impl.NIONetworking
acquireByteBufferFromPool, connectionTerminated, enqueueBytesForWriting, readReady, terminationAction, writeReady
 
Methods inherited from class ecologylab.services.distributed.impl.NIOCore
close, connectFinished, getPortNumber, invalidateKey, queueForAccept, queueForConnect, queueForRead, queueForWrite, run, setPendingInvalidate, writeFinished
 
Methods inherited from class ecologylab.generic.Debug
classSimpleName, closeLoggingFile, debug, debug, debug, debug, debugA, debugA, debugA, debugI, debugI, debugI, error, error, getClassName, getClassName, getInteractive, getPackageName, getPackageName, getPackageName, initialize, level, level, level, logToFile, print, print, println, println, println, println, println, println, printlnA, printlnA, printlnA, printlnI, printlnI, printlnI, printlnI, setLoggingFile, show, show, superString, toggleInteractive, toString, toString, warning, warning, weird, weird
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
 
Methods inherited from interface java.lang.Runnable
run
 

Field Detail

serverAddress

protected java.lang.String serverAddress

outgoingChars

protected final java.nio.CharBuffer outgoingChars

requestBuffer

protected final java.lang.StringBuilder requestBuffer

incomingMessageBuffer

protected final java.lang.StringBuilder incomingMessageBuffer
Stores incoming character data until it can be parsed into an XML message and turned into a Java object.


outgoingMessageBuffer

protected final java.lang.StringBuilder outgoingMessageBuffer
Stores outgoing character data for ResponseMessages.


outgoingMessageHeaderBuffer

protected final java.lang.StringBuilder outgoingMessageHeaderBuffer
Stores outgoing header character data.


requestsQueue

protected final java.util.Queue<PreppedRequest> requestsQueue

unfulfilledRequests

protected final java.util.Map<java.lang.Long,PreppedRequest> unfulfilledRequests
A map that stores all the requests that have not yet gotten responses. Maps UID to RequestMessage.


reconnectAttempts

protected int reconnectAttempts
The number of times a call to reconnect() should attempt to contact the server before giving up and calling stop().


waitBetweenReconnectAttempts

protected int waitBetweenReconnectAttempts
The number of milliseconds to wait between reconnect attempts.


selectInterval

protected long selectInterval
selectInterval is passed to select() when it is called in the run loop. It is set to 0 indicating that the loop should block until the selector picks up something interesting. However, if this class is subclassed, it is possible to modify this value so that the select() will only block for the number of ms supplied by this field. Thus, it is possible (by also subclassing the sendData() method) to have this send data on an interval, and then select.


isSending

protected boolean isSending

startReadIndex

protected int startReadIndex

headerMap

protected final java.util.HashMap<java.lang.String,java.lang.String> headerMap
Stores the key-value pairings from a parsed HTTP-like header on an incoming message.


thisSocket

protected java.nio.channels.SocketChannel thisSocket

pRequestPool

protected final PreppedRequestPool pRequestPool

responsePool

protected final MessageWithMetadataPool<ResponseMessage> responsePool
Constructor Detail

NIOClient

public NIOClient(java.lang.String serverAddress,
                 int portNumber,
                 TranslationSpace messageSpace,
                 Scope<?> objectRegistry)
          throws java.io.IOException
Throws:
java.io.IOException
Method Detail

connect

public boolean connect()
If this client is not already connected, connects to the specified serverAddress on the specified portNumber, then calls start() to begin listening for server responses and processing them, then sends handshake data and establishes the session id.

See Also:
ServicesClientBase.connect()

prepareAndEnqueueRequestForSending

protected PreppedRequest prepareAndEnqueueRequestForSending(RequestMessage request)
                                                     throws XMLTranslationException
Sets the UID for request (if necessary), enqueues it then registers write interest for the NIOClient's selection key and calls wakeup() on the selector.

Parameters:
request -
Throws:
XMLTranslationException

enqueueRequestForSending

protected void enqueueRequestForSending(PreppedRequest request)

disconnect

public void disconnect(boolean waitForResponses)

shutdownOK

protected boolean shutdownOK()
Returns:

nullOut

protected void nullOut()

connected

public boolean connected()

createConnection

protected boolean createConnection()
Side effect of calling start().


unableToRestorePreviousConnection

protected void unableToRestorePreviousConnection(java.lang.String oldId,
                                                 java.lang.String newId)
Hook method to allow subclasses to deal with a failed restore after disconnect. This should be a rare occurance, but some sublcasses may need to deal with this case specifically.

Parameters:
oldId - - the previous session id.
newId - - the new session id given by the server after reconnect.

nonBlockingSendMessage

public PreppedRequest nonBlockingSendMessage(RequestMessage request)
                                      throws java.io.IOException
Sends request, but does not wait for the response. The response gets processed later in a non-stateful way by the run method.

Parameters:
request - the request to send to the server.
Returns:
the UID of request.
Throws:
java.io.IOException

sendMessage

public ResponseMessage sendMessage(RequestMessage request)
Blocking send. Sends the request and waits infinitely for the response, which it returns.

See Also:
ServicesClientBase.sendMessage(ecologylab.services.messages.RequestMessage)

sendMessage

public ResponseMessage sendMessage(RequestMessage request,
                                   int timeOutMillis)
Blocking send with timeout. Sends the request and waits timeOutMillis milliseconds for the response, which it returns. sendMessage(RequestMessage, int) will return null if no message was recieved in time.

Parameters:
request -
timeOutMillis -
Returns:

start

public void start()
Specified by:
start in interface StartAndStoppable
Overrides:
start in class NIOCore

stop

public void stop()
Specified by:
stop in interface StartAndStoppable
Overrides:
stop in class NIOCore

dequeueRequest

protected PreppedRequest dequeueRequest()
Returns the next request in the request queue and removes it from that queue. Sublcasses that override the queue functionality will need to override this method.

Returns:
the next request in the request queue.

requestsRemaining

protected int requestsRemaining()
Returns the number of requests remaining in the requests queue. Subclasses that override the queue functionality will need to change this method accordingly.

Returns:
the size of the request queue.

reconnect

protected void reconnect()
Attempts to reconnect this client if it has been disconnected. After reconnecting, re-queues all requests still in the unfulfilledRequests map. If the attempt to reconnect fails, reconnect() will attempt a number of times equal to reconnectAttempts, waiting waitBetweenReconnectAttempts milliseconds between attempts. If all such attempts fail, calls stop() on this to shut down the client. The client will then need to be re-started manually.


addUnfulfilledRequest

protected void addUnfulfilledRequest(PreppedRequest req)
Hook method to allow subclasses to deal with unfulfilled requests in their own way. Adds req to the unfulfilled requests map.

Parameters:
req -

disconnect

public void disconnect()

setReconnectAttempts

public void setReconnectAttempts(int reconnectAttempts)
Parameters:
reconnectAttempts - the reconnectAttempts to set

setWaitBetweenReconnectAttempts

public void setWaitBetweenReconnectAttempts(int waitBetweenReconnectAttempts)
Parameters:
waitBetweenReconnectAttempts - the waitBetweenReconnectAttempts to set

clearSessionId

protected void clearSessionId()

acceptKey

protected void acceptKey(java.nio.channels.SelectionKey key)
This method does nothing, as NIOClients do not accept incoming connections.

Specified by:
acceptKey in class NIONetworking
See Also:
NIONetworking.acceptKey(java.nio.channels.SelectionKey)

checkAndDropIdleKeys

protected void checkAndDropIdleKeys()
Description copied from class: NIOCore
Check for timeout on all allocated keys; deallocate those that are hanging around, but no longer in use.

Specified by:
checkAndDropIdleKeys in class NIOCore
See Also:
NIOCore.checkAndDropIdleKeys()

invalidateKey

protected void invalidateKey(java.nio.channels.SelectionKey key,
                             boolean permanent)
Specified by:
invalidateKey in class NIOCore
See Also:
NIOCore.invalidateKey(java.nio.channels.SelectionKey, boolean)

processReadData

protected void processReadData(java.lang.Object readSessionId,
                               java.nio.channels.SelectionKey sk,
                               java.nio.ByteBuffer bytes,
                               int bytesRead)
                        throws BadClientException
Description copied from class: NIONetworking
This method is called whenever bytes have been read from a socket. There is no guaranty that the bytes will be a valid or complete message, nor is there a guaranty about what said bytes encode. Implementations should be prepared to handle incomplete messages, multiple messages, or malformed messages in this method.

Specified by:
processReadData in class NIONetworking
Parameters:
readSessionId - the id being use for this session.
bytes - the bytes read from the SocketChannel.
bytesRead - the number of bytes in the bytes array.
Throws:
BadClientException - if the client from which the bytes were read has transmitted something inappropriate, such as data too large for a buffer or a possibly malicious message.
See Also:
ecologylab.services.distributed.impl.NIONetworking#processReadData(java.lang.Object, java.nio.channels.SocketChannel, byte[], int)

removeBadConnections

protected void removeBadConnections(java.nio.channels.SelectionKey key)
Specified by:
removeBadConnections in class NIOCore
See Also:
NIOCore.removeBadConnections(java.nio.channels.SelectionKey)

generateUid

public long generateUid()
Increments the internal tracker of the next UID, and returns the current one.

Returns:
the current uidIndex.

translateXMLStringToResponse

protected MessageWithMetadata<ResponseMessage> translateXMLStringToResponse(java.lang.String messageString,
                                                                            int incomingUid)
                                                                     throws XMLTranslationException
Use the ServicesClient and its NameSpace to do the translation. Can be overridden to provide special functionalities

Parameters:
messageString -
Returns:
Throws:
XMLTranslationException

processResponse

protected void processResponse(ResponseMessage responseMessageToProcess)
Process a ResponseMessage received from the server in response to a previously-sent RequestMessage.

Parameters:
responseMessageToProcess -

getServer

public java.lang.String getServer()

setServer

public void setServer(java.lang.String serverAddress)

getUidNoIncrement

public long getUidNoIncrement()
Returns the most recently used UID.

Returns:
the current uidIndex.

isServerRunning

public boolean isServerRunning()
Check to see if the server is running.

Returns:
true if the server is running, false otherwise.

waitForConnect

public void waitForConnect()
Try and connect to the server. If we fail, wait CONNECTION_RETRY_SLEEP_INTERVAL and try again. Repeat ad nauseum.


parseHeader

protected int parseHeader(int startChar,
                          java.lang.StringBuilder allIncomingChars)
Parses the header of an incoming set of characters (i.e. a message from a client to a server), loading all of the HTTP-like headers into the given headerMap. If headerMap is null, this method will throw a null pointer exception.

Parameters:
allIncomingChars - - the characters read from an incoming stream.
headerMap - - the map into which all of the parsed headers will be placed.
Returns:
the length of the parsed header, or -1 if it was not yet found.

writeKey

protected void writeKey(java.nio.channels.SelectionKey key)
                 throws java.io.IOException
Description copied from class: NIONetworking
Writes the bytes from pendingWrites that belong to key.

Overrides:
writeKey in class NIONetworking
Throws:
java.io.IOException
See Also:
NIONetworking.writeKey(java.nio.channels.SelectionKey)

acceptReady

protected void acceptReady(java.nio.channels.SelectionKey key)
Specified by:
acceptReady in class NIOCore
See Also:
NIOCore.acceptReady(java.nio.channels.SelectionKey)

connectReady

protected void connectReady(java.nio.channels.SelectionKey key)
Specified by:
connectReady in class NIOCore
See Also:
NIOCore.connectReady(java.nio.channels.SelectionKey)

readFinished

protected void readFinished(java.nio.channels.SelectionKey key)
Specified by:
readFinished in class NIOCore
See Also:
NIOCore.readFinished(java.nio.channels.SelectionKey)

acceptFinished

public void acceptFinished(java.nio.channels.SelectionKey key)
Description copied from class: NIOCore
Queues a request to change key's interest operations back to READ. This method is automatically called after acceptReady(SelectionKey) in the main operating loop.

Specified by:
acceptFinished in class NIOCore
See Also:
NIOCore.acceptFinished(java.nio.channels.SelectionKey)