/*
This file is part of Fantom.
Fantom is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fantom is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fantom. If not, see <http://www.gnu.org/licenses/>.
*/
package cz.matfyz.aai.fantom.message;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Properties;
import cz.matfyz.aai.fantom.game.Graph;
import cz.matfyz.aai.fantom.server.Client;
import cz.matfyz.aai.fantom.server.ClientException;
import cz.matfyz.aai.fantom.server.ServerException;
import cz.matfyz.aai.fantom.utils.Parser;
public class MessagingClientBase {
/**
* The name of the character set used for communication between the server and
* the clients.
*/
public static final String PROTOCOL_CHARSET = "UTF-8";
/**
* The input stream for reading messages from the client.
*/
private InputStream input;
private BufferedReader inputReader;
/**
* The output stream for sending messages to the client.
*/
private OutputStream output;
private OutputStreamWriter outputWriter;
/**
* The output stream used for logging messages sent between the
* client and the server.
*/
private OutputStream messageLogStream;
private OutputStreamWriter messageLogWriter;
private Client client;
public void closeStreams() throws IOException {
if(input != null)
input.close();
if(output != null)
output.close();
if(messageLogStream != null)
messageLogStream.close();
}
/**
* Sends a message to the client.
*
* @param message the message to be sent to the client.
* @throws ServerException if there is a problem when sending the message to the client.
*/
public void sendMessage(Message message) throws ServerException {
if(message == null)
throw new IllegalArgumentException("message must not be null");
Properties[] messageData = message.serialize();
try {
sendMessage(messageData);
}
catch(ClientException e) {
if(client != null)
e.setClient(client);
throw e;
}
}
/**
* Internal version of the send message method
* @param message the message sent to the client.
* @throws ServerException if there is a problem sending the message.
*/
public void sendMessage(Properties[] message) throws ServerException {
if(message == null)
throw new IllegalArgumentException("message must not be null");
try {
for(int i = 0; i < message.length; i++) {
String msgLine = Parser.encodeProperties(message[i]);
outputWriter.write(msgLine);
outputWriter.write("\r\n");
if(messageLogWriter != null) {
messageLogWriter.write("> ");
messageLogWriter.write(msgLine);
messageLogWriter.write("\n");
}
}
outputWriter.write("\r\n");
outputWriter.flush();
if(messageLogWriter != null) {
messageLogWriter.write("\n");
messageLogWriter.flush();
}
}
catch(IOException e) {
throw new ClientException("Sending the message to the client failed", client);
}
}
/**
* Receives and parses a message from the client.
*
* @param graph the graph, on which the game is played (used to decode the message).
* @return the parsed message from the client.
* @throws ServerException if something goes wrong while processing the message.
*/
public Message receiveMessage(Graph graph) throws ServerException {
Properties[] messageData = receiveMessageRaw();
return Message.loadMessage(messageData, client, graph);
}
/**
* Receives raw message data from the client.
*
* @return the raw message data read from the client.
* @throws ServerException if something goes wrong while reading the data.
*/
public Properties[] receiveMessageRaw() throws ServerException {
ArrayList<Properties> messageData = new ArrayList<Properties>();
try {
String line = inputReader.readLine();
while(line != null && !line.isEmpty()) {
if(messageLogWriter != null) {
messageLogWriter.write("< ");
messageLogWriter.write(line);
messageLogWriter.write("\n");
}
Properties record = Parser.parseLine(line);
messageData.add(record);
line = inputReader.readLine();
}
if(messageLogWriter != null) {
messageLogWriter.write("\n");
messageLogWriter.flush();
}
return messageData.toArray(new Properties[messageData.size()]);
}
catch(IOException e) {
throw new ClientException("Reading data from the client failed", e, client);
}
}
public void setStreams(InputStream input, OutputStream output, OutputStream messageLog) throws IOException {
if(inputReader != null)
throw new IllegalStateException("The input stream was already assigned");
if(outputWriter != null)
throw new IllegalStateException("The output stream was already assigned");
this.input = input;
inputReader = new BufferedReader(new InputStreamReader(input, PROTOCOL_CHARSET));
this.output = output;
outputWriter = new OutputStreamWriter(output, PROTOCOL_CHARSET);
if(messageLog != null) {
this.messageLogStream = messageLog;
messageLogWriter = new OutputStreamWriter(messageLogStream, PROTOCOL_CHARSET);
}
}
}