Network layer objectstreams
For the basic network layer messagestream we use the standard
{@link java.io.ObjectInputStream and {@link java.io.ObjectOutputStream. This provides us with the
ability to send and receive normal java objects.
This however needs every object to be serializable, what, with for instance
the Observable class, turned out the be a bit of a problem.
Connections
For the connection between the server and the clients both sides have a daemon who handles this. The {@link quest.client.net.ClientDaemon} and the {@link quest.server.net.ServerDaemon} maintain a permanent connection with an input and output connection on top of that.
The server- and clientdaemon both run there own messagelistener.
Clientside it listenes constantly for messages of the server and destributes them to the appropriate service.
Serverside it checks every connection with a client whether data is available.
If data is available the message is received and distributed to the
appropriate service.
This way the network layer offers a flexible messagestream which every service
can use for communication.
Processes
Now that the basic communication is setup, additional services can be added.
These services are called processes, and are defined in {@link quest.global.net.Proces}. Every service, like a chatsystem or a gamesystem, must register
itself as a proces both server- and clientside. This way it registers the
messagetype it uses for communication between server and clients and the
server- and clientlisteners it offers for the handling of the messages.
The server- and clientdaemon now know that when they receive a message of
the registerd type, they should call the oppropriate listener for it.
Every service can be build on top of the network layer by simply construct a
proces object, with a message type which extends {@link quest.global.net.Message} and a listener which implements {@link quest.global.net.MessageServerListener} or {@link quest.global.net.MessageClientListener}.
This proces is then registered at the server- and clientdaemon and the
service is ready.
When a proces is registered it can be registerred as USER_BASED or GLOBAL_BASED. In short this means that when it's USER_BASED every client needs to be
registerred seperately to be allowed to communicate with that service and when it's GLOBAL_BASED that is not needed, so that all users who can communicate with the main service can also communicate with the subservices. This last possibility is mainly used for subservices like the three added services which help the chatserver perform his tasks.
Listeners
So every proces needs to offer a listener for the message it uses for the
communication. The interface for these listeners are defined om the above
mentioned listeners.
This listener is then supposed to handle that messages it receives from the
daemons. When it is finished with handling and has constructed the reply
messages it hands these to the daemons, together with a list of usernames
to which the messages should be sent and the daemons take care of the
communication.
This way the network layer is completely transparent for the services and
every imaginable service is able to run on top of the network layer
as long as it follows the guidelines.
Authentication
When the user first connects it must follow the authentication guidelines described in {@link quest.server.login}. This way the serverdaemon receives an indication that the user is authenticated and is now allowed to communicate with
the services running on top of the network layer. Until the login procedure
is finished the client isn't allowed access to the services.
Because the serverdaemon knows nothing about the services, except how to call them the services know a little about eachother for the added security.
This way the services can inform the serverdaemon when the client needs to talk to another service.
- The loginmanager informs the serverdaemon, when the authentication was
succesfull, that the client is now allowed to communicate with the chatserver.
This is done on a user-based level.
- The chatserver informs the serverdaemon that all clients who are allowed to
communicate with the chatserver, can also communicate with the channelserver, rankingserver and searchserver. This is done because these are servers which
help the chatserver in performing his task, so it's up to the chatserver to
register these processes and the give the client the ability to communicate
with them.
This is done on a global-based level.
- The chatserver informs the serverdaemon, when a game is started, that the clients who participate in the game, are now allowed to communicate with the gameserver.
- The chatserver informs the serverdaemon, when a game is finished, that the clients who participated in the game, should now be denied access to the gameserver.
- The loginmanager informs the serverdaemon, when a client logged out, that the client should now be denied access to all services.
This way access to the services is strictly controlled for added security.
Databases
Both the server- and client- daemon maintain small tables of the processes
registerd at their side.
The serverdaemon also maintains a table of online users, including
the messagestream setup with them and the services they are allowed to
communicate with.
The loginmanager uses a connection with the quest database on a SQL server
through the {@link quest.server.util.MSQLCommunicator}.
In this SQL database all user information like username, password, number of
played games and ranking are stored.
Logging
All services are allowed to write to the logfile. This way they can inform the
administrators of the program about there status and errors.
All that needs to be done is to get an instance of the {@link quest.server.log.LogManager} and with this the service can write entries to the logfile.
The logmanager makes sure that every logentry is in a standard format including
the date and time of the entry, for easy reading.
Frameworks
- SingletonPattern -> Used everywhere
- ObserverPattern -> Listeners
- Chain of Command -> Services handles own messages