cz.cuni.pogamut.server
Class UTServerConnection

java.lang.Object
  extended by cz.cuni.pogamut.server.UTServerConnection
All Implemented Interfaces:
MediatorClientInterface, FlagListener, java.lang.Runnable, java.util.EventListener

public class UTServerConnection
extends java.lang.Object
implements java.lang.Runnable, MediatorClientInterface, FlagListener

This class is used by UTServer for managing the server. It contains thread that is continuously processing the requests that can be made through UTServer class. It also alters the information in UTServer (protected ones). Remember ... on this.requests / this.messagesFromGB is synchronized the this.requestOrMessageLatch ... on that we're waiting if no request of message is in queue ... IF YOU ADD ANYTHING TO this.requests || this.messagesFromGB always do it in SYNC with respective object (this.requests || this.messagesFromGB) and in the same SYNC do this.requestOrMessageLatch.countDown() Note that if you in thread finds out that communication died out, just throw new UTServerConnectionReinitialize("reason") exception, the try-catch block in the run() will catch it and process it accordinaly.


Field Summary
private static int AFTER_SAME_MAP_WAIT_MILLIS
           
private  java.util.concurrent.BlockingQueue<java.lang.String> commandsToGB
          Commands that should be delivered to gamebots, are taken by Mediator's CLIENT->PARSER thread.
private static int COMMUNICATION_FLAG_LISTENER
           
private  boolean communicationShouldBeRunning
          Here we store information whether the communication should be OK.
private  Flag<UTServerRequest> currentRequestFlag
          Request the thread is currently processing.
private  java.net.URI currentUri
           
private  GameBotConnection gameBotConnection
           
private  java.util.logging.Logger gbRawDataLog
          Logger for GameBotConnection for raw data (not parsed).
private static long INFINITE_WAIT
           
private  long lastPingSentMillis
           
private  long lastReconnectTriedMillis
           
private  java.util.logging.Logger log
          Log of the server, logging the requests and it's results.
private  int mapChangeReconnectAttempt
          How many times we have tried to connect to GB before connect to the same map again.
private  boolean mapChanging
          Flag that tells us whether the map is changing.
private static int MAX_MAP_RECONNECT_ATTEMPTS
           
private  Mediator mediator
           
protected  java.util.Set<RcvMsgListener> messageListeners
           
private static UTServerRequest messagePoll
           
protected  java.util.concurrent.BlockingQueue<MessageObject> messagesFromGB
          Messages from GameBots...
private static long NO_WAIT
           
private static UTServerRequest nothing
           
private  UTServerConnectionInterface owner
          Owner of the UTServerConnection, who spawned it.
private  Parser parser
           
private  boolean pingSent
           
private  boolean pongReceived
           
private  java.lang.String previousMap
          Previous map on the server, this information is needed, to check whether the server has changed the map or not.
private static UTServerRequest requestAutoReconnect
           
private  java.util.concurrent.CountDownLatch requestOrMessageLatch
           
private  java.lang.Object requestOrMessageLatchAccess
           
private static UTServerRequest requestPingPong
           
private  java.util.concurrent.BlockingQueue<UTServerRequest> requests
          Queue with requests to the server.
private  boolean shouldRun
          Config flag ... when dropped, the thread will die and the object will be no longer usable!
private  java.lang.Thread thread
          Here we store the instance of the Thread.
private  Flag<java.lang.Boolean> threadAlive
          Flag which tells us wether threadIsAlive, it is changed to TRUE when the thread is started and to FALSE as the last command of the thread.
private static int threadCounter
          Serves for numbering the threads of all ServerControls, just for naming of the threads.
private static UTServerRequest waitingBounded
           
private static UTServerRequest waitingInfinite
           
 
Constructor Summary
UTServerConnection(UTServerConnectionInterface owner)
           
 
Method Summary
 void addRcvMsgListener(RcvMsgListener listener)
          Add listener that will be notified when a new message from Server Control will arrive.
private  void clearServerInfo()
          Clears informations in this.owner (like navpoints, items, available maps, etc.)
 void closeClient()
          Close the connection (if any exists).
private  void communicationDied()
          Called everytime ... communicationShouldBeRunning and it isn't
private  long computeMaxWaiting()
          This should return millis how long (max) we should wait for GB message / request to arrive before checking the PING/PONG and AUTO-RECONNECT
 void connect()
          Can be called when the server state is TERMINATED or NONE, start up the thread.
private  void connectToGB()
          Connects to the GameBot, URI is taken from this.owner.getServerURI() Doesn't do anything if communication is alive.
 void disconnect()
           
private  void doAutomaticReconnect()
          Called only IFF communication is down...
private  void doPingPong()
           
 void flagChanged(java.lang.Object changedValue, int listenerParam)
          When registering the flag you may additionally specify listener parameter, if you do so - your listener will be called with that parameter.
private  MessageObject getBlockingMessageFromGB()
          Called ONLY from server connection thread!
 UTServerRequest getCurrentRequest()
          Returns the request the object is currently processing, may be null!
 java.net.URI getCurrentURI()
           
 java.lang.Thread getThread()
          Get thread of the instance, if not isThreadAlive() then it returns null.
 Flag<java.lang.Boolean> getThreadAliveFlag()
          Returns the flag that tells you whether the thread is alive, you may register listener on it.
 boolean changeMap(java.lang.String mapName)
          Will send command to change the map IFF it's not the one that is currently running.
 boolean changeMapAndWait(java.lang.String mapName)
          Will send command to change the map IFF it's not the one that is currently running.
protected  void interruptThread()
           
private  boolean isCommunicationAlive()
           
 boolean isThreadAlive()
          Returns state of the thread.
private  void loadAvailableMaps(boolean forced)
          Called only from connectToGB(), to get list of available maps on server.
private  java.util.List<UTMap> loadAvailableMapsInner()
          Sends GETITEMS to GB and waits for items, returns list of them.
private  void loadInfoInner(java.lang.String command, MessageType begin, MessageType info, MessageType end, java.util.Collection result)
          Sends @command to GB and waits for message of type @begin, then filling result array with messages of type @info until message of type @end comes.
private  void loadInventory(boolean forced)
          Called only from processRequest(), it will load inventory, which is map 'Human readable string' -> Item with filled property.
private  void loadItems(boolean forced)
          Called only from processRequest(), it will load navpoints IFF not previously loaded... it will store it to the this.owner.items It will also raise the latch in owner ... ... this.owner.itemsLoadedLatch
private  java.util.List<Item> loadItemsInner()
          Sends GETITEMS to GB and waits for items, returns list of them.
private  void loadNavPoints(boolean forced)
          Called only from processRequest(), it will load navpoints IFF not previously loaded... it will store it to the this.owner.navPoints It will also raise the latch in owner ... ... this.owner.navPointsLoadedLatch
private  java.util.List<NavPoint> loadNavPointsInner()
          Sends GETNAVS to GB and waits for navpoints, returns list of them.
private  void loadPlayers()
          Called from processRequest() , don't call from anywhere else (out of sync).
private  java.util.Set<Player> loadPlayersInner()
          Sends GETPLRS to GB and waits for players, returns list of them.
private  void logException(java.lang.Exception e)
           
 void mapFinishedMessageCame()
           
private  void preprocessGBMessage(MessageObject msg)
          Every message from GB goes through HERE ... doing some miscellaneous work.
private  void processGBMessage()
          Process one message from the GB queue ... currently it's just removing it from the queue (all of them).
private  void processRequest()
          Process one request from the requests queue ... currently it's just removing it from the queue.
private  void processRequestOrMessage()
          Processing one MESSAGE and one REQUEST if there is any...
 java.lang.String receiveMessageFromClient()
          Get one message from client which is needed to deliver to the GameBots.
private  void reinitialize(boolean reconnect)
          Must be called only from withing the run() Reinitilize the communication ... e.g. will close it, clean the queues (commands, messages, requests).
private  void reinitInnerVariables()
           
 void removeRcvMsgListener(RcvMsgListener listener)
          Remove listener that listens for messages from server control.
 boolean request(UTServerRequest request)
          This method is synchronized!
 void run()
          Is called internaly from runThread() ... this class shouldn't be run via Thread.run(object).
private  java.lang.Thread runThread()
          Called from constructor to start the thread.
 void sendCommandToGB(java.lang.String message)
           
 void sendMessageToClient(MessageObject msg)
          Sends message object to the client.
private  void setCurrentRequest(UTServerRequest request)
           
private  void setServerState(UTServerState serverState)
           
private  void stopCommunication()
          Will stop communication if working.
protected  void terminate()
           
private  void threadIteration()
          "Body" of the thread ... here we're processing the requests to the connection.
private  MessageObject waitForResponse(MessageType type)
          Wait until message of type @type arrives, then return it.
 void wakeUpWaiting()
          Wakes up the thread is waiting for request / message.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

requestPingPong

private static final UTServerRequest requestPingPong

requestAutoReconnect

private static final UTServerRequest requestAutoReconnect

messagePoll

private static final UTServerRequest messagePoll

waitingInfinite

private static final UTServerRequest waitingInfinite

waitingBounded

private static final UTServerRequest waitingBounded

nothing

private static final UTServerRequest nothing

INFINITE_WAIT

private static final long INFINITE_WAIT
See Also:
Constant Field Values

NO_WAIT

private static final long NO_WAIT
See Also:
Constant Field Values

COMMUNICATION_FLAG_LISTENER

private static final int COMMUNICATION_FLAG_LISTENER
See Also:
Constant Field Values

MAX_MAP_RECONNECT_ATTEMPTS

private static final int MAX_MAP_RECONNECT_ATTEMPTS
See Also:
Constant Field Values

AFTER_SAME_MAP_WAIT_MILLIS

private static final int AFTER_SAME_MAP_WAIT_MILLIS
See Also:
Constant Field Values

owner

private UTServerConnectionInterface owner
Owner of the UTServerConnection, who spawned it.


threadCounter

private static int threadCounter
Serves for numbering the threads of all ServerControls, just for naming of the threads.


threadAlive

private Flag<java.lang.Boolean> threadAlive
Flag which tells us wether threadIsAlive, it is changed to TRUE when the thread is started and to FALSE as the last command of the thread.


thread

private java.lang.Thread thread
Here we store the instance of the Thread.


gbRawDataLog

private java.util.logging.Logger gbRawDataLog
Logger for GameBotConnection for raw data (not parsed). Log is not clear when new connection / reconnection is done, only put the info of new connection.


log

private java.util.logging.Logger log
Log of the server, logging the requests and it's results. Log is not cleared when connecting / reconnecting, only a message is put there that tells us that reconnection / connection has been made.


shouldRun

private boolean shouldRun
Config flag ... when dropped, the thread will die and the object will be no longer usable! Do the request(new UTServerRequestTermination()).


mapChanging

private boolean mapChanging
Flag that tells us whether the map is changing.


mapChangeReconnectAttempt

private int mapChangeReconnectAttempt
How many times we have tried to connect to GB before connect to the same map again.


previousMap

private java.lang.String previousMap
Previous map on the server, this information is needed, to check whether the server has changed the map or not.


currentRequestFlag

private Flag<UTServerRequest> currentRequestFlag
Request the thread is currently processing.


requestOrMessageLatchAccess

private java.lang.Object requestOrMessageLatchAccess

requestOrMessageLatch

private java.util.concurrent.CountDownLatch requestOrMessageLatch

currentUri

private java.net.URI currentUri

messageListeners

protected java.util.Set<RcvMsgListener> messageListeners

requests

private java.util.concurrent.BlockingQueue<UTServerRequest> requests
Queue with requests to the server.


commandsToGB

private java.util.concurrent.BlockingQueue<java.lang.String> commandsToGB
Commands that should be delivered to gamebots, are taken by Mediator's CLIENT->PARSER thread.


messagesFromGB

protected java.util.concurrent.BlockingQueue<MessageObject> messagesFromGB
Messages from GameBots...


gameBotConnection

private GameBotConnection gameBotConnection

parser

private Parser parser

mediator

private Mediator mediator

communicationShouldBeRunning

private boolean communicationShouldBeRunning
Here we store information whether the communication should be OK.


pingSent

private boolean pingSent

lastPingSentMillis

private long lastPingSentMillis

pongReceived

private boolean pongReceived

lastReconnectTriedMillis

private long lastReconnectTriedMillis
Constructor Detail

UTServerConnection

public UTServerConnection(UTServerConnectionInterface owner)
Method Detail

addRcvMsgListener

public void addRcvMsgListener(RcvMsgListener listener)
Add listener that will be notified when a new message from Server Control will arrive. Beware, that the thread that calls the listeners is the very same thread that recieves the messages from Parser, so you cant recieve more messages, unless you return control.


removeRcvMsgListener

public void removeRcvMsgListener(RcvMsgListener listener)
Remove listener that listens for messages from server control.


setCurrentRequest

private void setCurrentRequest(UTServerRequest request)

request

public boolean request(UTServerRequest request)
This method is synchronized! This is only way how to add request to the queue of requests, USE ONLY THIS EVEN INSIDE THE CLASS!

Parameters:
request -
Returns:
success

getCurrentRequest

public UTServerRequest getCurrentRequest()
Returns the request the object is currently processing, may be null!


getThreadAliveFlag

public Flag<java.lang.Boolean> getThreadAliveFlag()
Returns the flag that tells you whether the thread is alive, you may register listener on it.

Returns:

isThreadAlive

public boolean isThreadAlive()
Returns state of the thread. (Anybody may check whether thread is running.)

Returns:
threadAlive flag

runThread

private java.lang.Thread runThread()
Called from constructor to start the thread.


getThread

public java.lang.Thread getThread()
Get thread of the instance, if not isThreadAlive() then it returns null.


run

public void run()
Is called internaly from runThread() ... this class shouldn't be run via Thread.run(object). We assume that each object, can be run in ONLY ONE thread. 1) therefore as the first action, test wether threadIsAlive - if so, exit 2) do all the work in try/catch block and catch all the exceptions, otherwise you won't be able to do the 3) 3) as the last action (almost), drops the flag threadAlive Here also lies the while-cycle that takes care of requests (change uri, checking communication, reconnecting and such)

Specified by:
run in interface java.lang.Runnable

logException

private void logException(java.lang.Exception e)

setServerState

private void setServerState(UTServerState serverState)

communicationDied

private void communicationDied()
Called everytime ... communicationShouldBeRunning and it isn't


reinitInnerVariables

private void reinitInnerVariables()

clearServerInfo

private void clearServerInfo()
Clears informations in this.owner (like navpoints, items, available maps, etc.) Called ONLY FROM communicationDied() !


getCurrentURI

public java.net.URI getCurrentURI()

stopCommunication

private void stopCommunication()
Will stop communication if working.


reinitialize

private void reinitialize(boolean reconnect)
Must be called only from withing the run() Reinitilize the communication ... e.g. will close it, clean the queues (commands, messages, requests). BUT IT WON'T CONNECT! ... instead of that, it will add request for reconnection.


receiveMessageFromClient

public java.lang.String receiveMessageFromClient()
                                          throws CantReadException
Get one message from client which is needed to deliver to the GameBots. USED BY INTERFACE, DONT USE May block.

Specified by:
receiveMessageFromClient in interface MediatorClientInterface
Throws:
CantReadException
java.io.IOException

sendMessageToClient

public void sendMessageToClient(MessageObject msg)
                         throws CantWriteException
Sends message object to the client. USED BY INTERFACE, DONT USE

Specified by:
sendMessageToClient in interface MediatorClientInterface
Parameters:
msg -
Throws:
java.io.IOException
CantWriteException

closeClient

public void closeClient()
                 throws CantCloseConnectionException
Description copied from interface: MediatorClientInterface
Close the connection (if any exists).

Specified by:
closeClient in interface MediatorClientInterface
Throws:
CantCloseConnectionException

isCommunicationAlive

private boolean isCommunicationAlive()

sendCommandToGB

public void sendCommandToGB(java.lang.String message)

getBlockingMessageFromGB

private MessageObject getBlockingMessageFromGB()
                                        throws CantReadException
Called ONLY from server connection thread!

Returns:
message from GB
Throws:
CantReadException

waitForResponse

private MessageObject waitForResponse(MessageType type)
                               throws CantReadException
Wait until message of type @type arrives, then return it.

Throws:
CantReadException

threadIteration

private void threadIteration()
                      throws java.lang.Exception
"Body" of the thread ... here we're processing the requests to the connection.

Throws:
java.lang.Exception

processRequestOrMessage

private void processRequestOrMessage()
                              throws java.net.UnknownHostException,
                                     ConnectException,
                                     CantReadException,
                                     UTServerConnectionTerminationRequested,
                                     UTServerConnectionReinitialization
Processing one MESSAGE and one REQUEST if there is any... Using: processGBMessage() processRequest()

Throws:
CantReadException
ConnectException
java.net.UnknownHostException
UTServerConnectionTerminationRequested
UTServerConnectionReinitialization

preprocessGBMessage

private void preprocessGBMessage(MessageObject msg)
Every message from GB goes through HERE ... doing some miscellaneous work. Like ... catching PONG / new bot appeared and such... This is called directly from MediatorClientInterface, therefore it's executed by Mediator.

Parameters:
msg -

computeMaxWaiting

private long computeMaxWaiting()
This should return millis how long (max) we should wait for GB message / request to arrive before checking the PING/PONG and AUTO-RECONNECT

Returns:
INFINITE_WAIT if infinite, NO_WAIT if no need wait, or positive number (millis)

doPingPong

private void doPingPong()
                 throws java.lang.Exception
Throws:
java.lang.Exception

doAutomaticReconnect

private void doAutomaticReconnect()
                           throws java.net.UnknownHostException,
                                  ConnectException,
                                  CantReadException,
                                  UTServerConnectionReinitialization
Called only IFF communication is down...

Throws:
ConnectException
java.net.UnknownHostException
CantReadException
UTServerConnectionReinitialization

connectToGB

private void connectToGB()
                  throws java.net.UnknownHostException,
                         ConnectException,
                         CantReadException,
                         UTServerConnectionReinitialization
Connects to the GameBot, URI is taken from this.owner.getServerURI() Doesn't do anything if communication is alive.

Throws:
java.net.UnknownHostException
ConnectException
CantReadException
UTServerConnectionReinitialization

processGBMessage

private void processGBMessage()
Process one message from the GB queue ... currently it's just removing it from the queue (all of them). (DOESN'T BLOCK)


processRequest

private void processRequest()
                     throws UTServerConnectionTerminationRequested,
                            java.net.UnknownHostException,
                            ConnectException,
                            CantReadException,
                            UTServerConnectionReinitialization
Process one request from the requests queue ... currently it's just removing it from the queue. (DOESN'T NOT BLOCK) When executing this method, you may be sure, that no one will poke the communication in any way!

Throws:
CantReadException
ConnectException
java.net.UnknownHostException
UTServerConnectionReinitialization
UTServerConnectionException
UTServerConnectionTerminationRequested

terminate

protected void terminate()

connect

public void connect()
Can be called when the server state is TERMINATED or NONE, start up the thread.


disconnect

public void disconnect()

loadInfoInner

private void loadInfoInner(java.lang.String command,
                           MessageType begin,
                           MessageType info,
                           MessageType end,
                           java.util.Collection result)
                    throws CantReadException
Sends @command to GB and waits for message of type @begin, then filling result array with messages of type @info until message of type @end comes. Messages are added to collection @result

Throws:
CantReadException

loadPlayersInner

private java.util.Set<Player> loadPlayersInner()
                                        throws CantReadException
Sends GETPLRS to GB and waits for players, returns list of them.

Parameters:
forced - whether to load even if list exists
Returns:
list of players currently on the server
Throws:
CantReadException

loadNavPointsInner

private java.util.List<NavPoint> loadNavPointsInner()
                                             throws CantReadException
Sends GETNAVS to GB and waits for navpoints, returns list of them.

Returns:
list of navpoints in map
Throws:
CantReadException

loadItemsInner

private java.util.List<Item> loadItemsInner()
                                     throws CantReadException
Sends GETITEMS to GB and waits for items, returns list of them.

Returns:
list of items in map
Throws:
CantReadException

loadAvailableMapsInner

private java.util.List<UTMap> loadAvailableMapsInner()
                                              throws CantReadException
Sends GETITEMS to GB and waits for items, returns list of them.

Returns:
list of items in map
Throws:
CantReadException

loadPlayers

private void loadPlayers()
                  throws CantReadException
Called from processRequest() , don't call from anywhere else (out of sync). It will ask GB to send players list again.

Throws:
CantReadException

loadNavPoints

private void loadNavPoints(boolean forced)
                    throws CantReadException
Called only from processRequest(), it will load navpoints IFF not previously loaded... it will store it to the this.owner.navPoints It will also raise the latch in owner ... ... this.owner.navPointsLoadedLatch

Throws:
CantReadException

loadItems

private void loadItems(boolean forced)
                throws CantReadException
Called only from processRequest(), it will load navpoints IFF not previously loaded... it will store it to the this.owner.items It will also raise the latch in owner ... ... this.owner.itemsLoadedLatch

Throws:
CantReadException

loadAvailableMaps

private void loadAvailableMaps(boolean forced)
                        throws CantReadException
Called only from connectToGB(), to get list of available maps on server.

Throws:
CantReadException

loadInventory

private void loadInventory(boolean forced)
                    throws CantReadException
Called only from processRequest(), it will load inventory, which is map 'Human readable string' -> Item with filled property. Loads IFF not previously loaded... it will store it to the this.owner.inventory

Throws:
CantReadException

flagChanged

public void flagChanged(java.lang.Object changedValue,
                        int listenerParam)
Description copied from interface: FlagListener
When registering the flag you may additionally specify listener parameter, if you do so - your listener will be called with that parameter. Note that we purposefully denying OOP paradigm here. 'listenerParam' will allow you to implement this interface only once for more flags at the cost of switch(listenerParam){} ... but imagine that you have 4 objects which all register 4 different flag listeners (it would be a bit messy, wouldn't it).

Specified by:
flagChanged in interface FlagListener

wakeUpWaiting

public void wakeUpWaiting()
Wakes up the thread is waiting for request / message.


changeMap

public boolean changeMap(java.lang.String mapName)
Will send command to change the map IFF it's not the one that is currently running. After that it will take care not to connect to the server with the same map again.

Parameters:
mapName -

changeMapAndWait

public boolean changeMapAndWait(java.lang.String mapName)
Will send command to change the map IFF it's not the one that is currently running. After that it will take care not to connect to the server with the same map again. Block until connection to server with specified map name is made or until it fails to change the map.

Parameters:
mapName -

mapFinishedMessageCame

public void mapFinishedMessageCame()
                            throws UTServerConnectionReinitialization
Throws:
UTServerConnectionReinitialization

interruptThread

protected void interruptThread()