Java Doc Server && ServerConnectionHandler

This commit is contained in:
Andrin Fassbind 2022-04-15 19:41:43 +02:00 committed by Leonardo Brandenberger
parent a94a4c81d8
commit 5c0e55870d
2 changed files with 103 additions and 3 deletions

View File

@ -10,7 +10,15 @@ import java.util.Map;
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
/**
* This Class represents a Server. The user can start the programm with the port number as a argument.
* If no argument has been set the {@link NetworkHandler#DEFAULT_PORT} is used as port number.
* After initialising the server:
* 1. Starts a Socketserver using the logic given in {@link NetworkHandler.NetworkServer#createServer()}
* 2. The server starts to listen for incoming connection using the Logic given in {@link NetworkHandler.NetworkServer#waitForConnection()}
* 3. New conections will be atached to a Connectionhandler: {@link ServerConnectionHandler} and placed in a Map containing all active connections {@link Server#connections}
*
*/
public class Server { public class Server {
// Server connection // Server connection
@ -61,6 +69,11 @@ public class Server {
} }
} }
/**
* The Constructor to create a new instance.
* @param serverPort to listen for incoming connections.
* @throws IOException thrown if an I/O error occurs when opening the socket.
*/
public Server(int serverPort) throws IOException { public Server(int serverPort) throws IOException {
// Open server connection // Open server connection
System.out.println("Create server connection"); System.out.println("Create server connection");
@ -68,6 +81,10 @@ public class Server {
System.out.println("Listening on " + networkServer.getHostAddress() + ":" + networkServer.getHostPort()); System.out.println("Listening on " + networkServer.getHostAddress() + ":" + networkServer.getHostPort());
} }
/**
* With this methode the instance waits for incoming connections. If a client tries to connect to the server.
* The connection will be registered in the connection registry if successful.
*/
private void start() { private void start() {
ReentrantLock mutex = new ReentrantLock(); ReentrantLock mutex = new ReentrantLock();
Condition nameComplete = mutex.newCondition(); Condition nameComplete = mutex.newCondition();
@ -108,6 +125,9 @@ public class Server {
System.out.println("Server Stopped."); System.out.println("Server Stopped.");
} }
/**
* This method will stop the serversocket.
*/
public void terminate() { public void terminate() {
try { try {
System.out.println("Close server port."); System.out.println("Close server port.");

View File

@ -16,7 +16,31 @@ import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
/**
* This class represents the connection between the server and a client and offers the serverside logic.
* The ServerConnectionHandler receives data send from the client aswell as sends data to the client.
*
* The ServeConnectionHandler offers following functionality:
*
* Evaluating connection attempts from a client by:
* 1. Checks if Username is valid (Not used)
* 2. Saves Username in {@link ServerConnectionHandler#userName}
* 3. Saves the connection in the {@link ServerConnectionHandler#connectionRegistry}
*
* Processes disconnections from a client by:
* 1. Removing the connection from the {@link ServerConnectionHandler#connectionRegistry}
* 2. Terminates the socket by calling {@link NetworkHandler.NetworkConnection#close()}
*
* Processes Messages send from a client by:
* 1. Evaluating the reciever by differentiating between broadcast or unicast.
* 2. Sending the message accordingly.
*
* To use this class, start a new instance and start it in a thread.
* To constructor needs following parameter:
* 1. {@link ch.zhaw.pm2.multichat.protocol.NetworkHandler.NetworkConnection} representing the socket connection between server and client
* 2. {@link Map<String,ServerConnectionHandler>} registry to check for all active connections
* 3. {@link ReentrantLock @link Condition} to lock server thread to evaluate connection.
* */
public class ServerConnectionHandler extends ConnectionHandler implements Runnable{ public class ServerConnectionHandler extends ConnectionHandler implements Runnable{
private static final AtomicInteger connectionCounter = new AtomicInteger(0); private static final AtomicInteger connectionCounter = new AtomicInteger(0);
private final int connectionId = connectionCounter.incrementAndGet(); private final int connectionId = connectionCounter.incrementAndGet();
@ -29,11 +53,21 @@ public class ServerConnectionHandler extends ConnectionHandler implements Runnab
private String userName = "Anonymous-"+connectionId; private String userName = "Anonymous-"+connectionId;
private State state = NEW; private State state = NEW;
/**
* Called when runnable gets started in a thread.
*/
@Override @Override
public void run() { public void run() {
startReceiving(); startReceiving();
} }
/**
* Constructor to intitialize the connection
* @param connection representing the socket connection between server and clinet
* @param registry map containing all active connections between server and clients
* @param mutex to lock thread
* @param nameComplete condition to call threads
*/
public ServerConnectionHandler(NetworkHandler.NetworkConnection<String> connection, public ServerConnectionHandler(NetworkHandler.NetworkConnection<String> connection,
Map<String,ServerConnectionHandler> registry, ReentrantLock mutex, Condition nameComplete) { Map<String,ServerConnectionHandler> registry, ReentrantLock mutex, Condition nameComplete) {
super(); super();
@ -45,14 +79,26 @@ public class ServerConnectionHandler extends ConnectionHandler implements Runnab
this.nameComplete = nameComplete; this.nameComplete = nameComplete;
} }
/**
*
* @return the username of the connected client
*/
public String getUserName() { public String getUserName() {
return this.userName; return this.userName;
} }
/**
*
* @return state of the connection. Poosible states are see {@link ch.zhaw.pm2.multichat.protocol.ConnectionHandler.State}
*/
public State getState() { public State getState() {
return state; return state;
} }
/**
* This methods runs in a whileloop as long as the socket between server and client is available
* and the connection State is not ERROR.
*/
private void startReceiving() { private void startReceiving() {
System.out.println("Starting Connection Handler for new User"); System.out.println("Starting Connection Handler for new User");
try { try {
@ -83,6 +129,9 @@ public class ServerConnectionHandler extends ConnectionHandler implements Runnab
} }
/**
* This method will call {@link NetworkHandler.NetworkConnection#close()} to close the Socket.
*/
private void stopReceiving() { private void stopReceiving() {
System.out.println("Closing Connection Handler for " + userName); System.out.println("Closing Connection Handler for " + userName);
try { try {
@ -95,6 +144,17 @@ public class ServerConnectionHandler extends ConnectionHandler implements Runnab
System.out.println("Closed Connection Handler for " + userName); System.out.println("Closed Connection Handler for " + userName);
} }
/**
* This method gets called when socket recieves data. The method checks for the data type and reacts accordingly
* If data type:
* 1. Connect => checks if username is valid. if valid sends response to client with confirmation.
* If username not valid quits connection by changing status to ERROR.
* 2. Confirm => Server should not recieve this kind of message. STDOUT informs about it.
* 3. Disconnect => Disconnects connection by removing connection from registry and calling method to terminate socket.
* 4. Message => Checks if broadcast or unicast. Sends data accordingly
* 5. Error => STDERR message
* @param data recieved by the server
*/
private void processData(String data) { private void processData(String data) {
try { try {
Scanner scanner = new Scanner(data); Scanner scanner = new Scanner(data);
@ -125,6 +185,12 @@ public class ServerConnectionHandler extends ConnectionHandler implements Runnab
} }
} }
/**
* This method is called by method {@link ServerConnectionHandler#processData(String)}
* Checks if username is valid. if valid sends response to client with confirmation.
* @param sender of the payload
* @throws ChatProtocolException if username not valid
*/
private void caseConnect(String sender) throws ChatProtocolException { private void caseConnect(String sender) throws ChatProtocolException {
if (this.state != NEW) throw new ChatProtocolException("Illegal state for connect request: " + state); if (this.state != NEW) throw new ChatProtocolException("Illegal state for connect request: " + state);
if (sender.isBlank()) sender = this.userName; if (sender.isBlank()) sender = this.userName;
@ -141,7 +207,7 @@ public class ServerConnectionHandler extends ConnectionHandler implements Runnab
} }
mutex.lock(); mutex.lock();
try { try {
this.userName = sender.toString(); this.userName = sender;
nameComplete.signal(); nameComplete.signal();
} }
finally { finally {
@ -152,6 +218,11 @@ public class ServerConnectionHandler extends ConnectionHandler implements Runnab
this.state = CONNECTED; this.state = CONNECTED;
} }
/**
* This method is called by method {@link ServerConnectionHandler#processData(String)}
* Disconnects connection by removing connection from registry and calling method {@link ServerConnectionHandler#stopReceiving()} to terminate socket.
* @throws ChatProtocolException if state allready DISCONNECTED.
*/
private void caseDisconnect() throws ChatProtocolException { private void caseDisconnect() throws ChatProtocolException {
if (state == DISCONNECTED) if (state == DISCONNECTED)
throw new ChatProtocolException("Illegal state for disconnect request: " + state); throw new ChatProtocolException("Illegal state for disconnect request: " + state);
@ -163,6 +234,15 @@ public class ServerConnectionHandler extends ConnectionHandler implements Runnab
this.stopReceiving(); this.stopReceiving();
} }
/**
* This method is called by method {@link ServerConnectionHandler#processData(String)}
* Checks if broadcast or unicast. Sends data accordingly
* @param sender who sent data
* @param reciever to recieve data
* @param type of message
* @param payload data to transmit
* @throws ChatProtocolException if state not equal to CONNECT
*/
private void caseMessage(String sender, String reciever, String type, String payload) throws ChatProtocolException{ private void caseMessage(String sender, String reciever, String type, String payload) throws ChatProtocolException{
if (state != CONNECTED) throw new ChatProtocolException("Illegal state for message request: " + state); if (state != CONNECTED) throw new ChatProtocolException("Illegal state for message request: " + state);
if (USER_ALL.equals(reciever)) { if (USER_ALL.equals(reciever)) {