package csc4509;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
public class Message {
private ByteBuffer bufferHeader = ByteBuffer.allocate(8);
private ByteBuffer bufferPayload = null;
private int messType = 1;
private int messSize = 0;
byte[] message;
private SocketChannel sc;
private ReadMessageStatus readState = ReadMessageStatus.ReadUnstarted;
public Message (int type) {
this.messType = type;
}
public Message (int type, int size) {
this.messType = type;
this.messSize = size;
}
public void write (SocketChannel sc) {
try {
ByteBuffer bufferPayload = ByteBuffer.allocate(messSize);
/* Rewind buffer */
bufferHeader.rewind();
bufferPayload.rewind();
/* Remplissage des buffers */
bufferHeader.putInt(messType);
bufferHeader.putInt(messSize);
bufferPayload.put(message);
/* Flip buffers */
bufferHeader.flip();
bufferPayload.flip();
/* Envoie */
sc.write(bufferHeader);
sc.write(bufferPayload);
/* Exceptions */
} catch (SocketException se) {
se.printStackTrace();
return;
} catch (UnknownHostException ue) {
ue.printStackTrace();
return;
} catch (IOException ie) {
ie.printStackTrace();
return;
}
}
public void readFullMessage() {
while (this.readMessage(this.getSc()) != ReadMessageStatus.ReadDataCompleted);
}
public ReadMessageStatus readMessage (SocketChannel sc) {
try {
switch (readState) {
case ReadUnstarted:
bufferHeader.rewind();
int res = sc.read(bufferHeader);
if (res == 0) {
return ReadMessageStatus.ReadUnstarted;
}
else if (res == -1) {
return ReadMessageStatus.ChannelClosed;
}
readState = ReadMessageStatus.ReadHeaderStarted;
return readState;
case ReadHeaderStarted:
/* Read from socket channel */
if (sc.read(bufferHeader) == -1) {
return ReadMessageStatus.ChannelClosed;
}
if (bufferHeader.position() == bufferHeader.capacity()) {
readState = ReadMessageStatus.ReadHeaderCompleted;
return readState;
}
else {
return ReadMessageStatus.ReadHeaderStarted;
}
case ReadHeaderCompleted:
bufferHeader.flip();
messType = bufferHeader.getInt();
messSize = bufferHeader.getInt();
bufferPayload = ByteBuffer.allocate(messSize);
if (sc.read(bufferPayload) == -1) {
return ReadMessageStatus.ChannelClosed;
}
if (buffEnded(bufferPayload)) { /* Read is finished */
readState = ReadMessageStatus.ReadDataCompleted;
}
else { /* There is still something to read */
readState = ReadMessageStatus.ReadDataStarted;
}
return readState;
case ReadDataStarted:
if (sc.read(bufferPayload) == -1) {
return ReadMessageStatus.ChannelClosed;
}
if (buffEnded(bufferPayload)) { /* Nothing to read */
readState = ReadMessageStatus.ReadDataCompleted;
return readState;
}
else {
return ReadMessageStatus.ReadDataStarted;
}
case ReadDataCompleted:
readState = ReadMessageStatus.ReadUnstarted;
return null;
case ChannelClosed:
readState = ReadMessageStatus.ReadUnstarted;
return null;
default:
return null;
}
/* Exceptions */
} catch (SocketException se) {
//se.printStackTrace();
return ReadMessageStatus.ChannelClosed;
} catch (UnknownHostException ue) {
//ue.printStackTrace();
return ReadMessageStatus.ChannelClosed;
} catch (IOException ie) {
//ie.printStackTrace();
return ReadMessageStatus.ChannelClosed;
}
}
private boolean buffEnded(ByteBuffer bf) {
if (bufferPayload.position() == bufferPayload.capacity()) {
bufferPayload.flip();
/* Read values from buffer */
message = new byte[messSize];
bufferPayload.get(message, 0, messSize);
/* Buffer reading is ended */
return true;
}
else {
/* There is still data to read */
return false;
}
}
public void printMessage() {
System.out.println(new String(message));
}
public String toString() {
return "Type:" + messType + "; Taille :" + messSize + "; Recu : " + new String(message);
}
public void printDebug(String msg) {
System.out.println(msg + "Type:" + messType + "; Taille :" + messSize + "; Recu : " + new String(message));
}
public void setType(int type) {
this.messType = type;
}
public int getType() {
return messType;
}
public int getContentSize() {
return messSize;
}
public byte[] getMessage() {
return message;
}
/* public int setMessage(byte[] pattern) {
this.messSize = pattern.length;
this.message = new byte[pattern.length];
this.message = pattern;
return 1;
} */
public int setMessage(int type, Serializable data) throws IOException {
ByteArrayOutputStream bo = new ByteArrayOutputStream();
ObjectOutputStream oo = new ObjectOutputStream(bo);
oo.writeObject(data);
oo.close();
bo.close();
this.messSize = bo.size();
this.message = new byte[bo.size()];
this.message = bo.toByteArray();
return 1;
}
public Object getData() throws IOException {
Object res = null;
ByteArrayInputStream bi = new ByteArrayInputStream(message);
ObjectInputStream oi = new ObjectInputStream(bi);
try {
res = oi.readObject();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
oi.close();
bi.close();
return res;
}
public String getString() {
String s = null;
try {
s = (String) getData();
} catch (IOException e) {
e.printStackTrace();
}
return s;
}
public void setSc(SocketChannel sc) {
this.sc = sc;
}
public SocketChannel getSc() {
return sc;
}
public SocketAddress getHost() {
return sc.socket().getRemoteSocketAddress();
}
public int getPort() {
return sc.socket().getPort();
}
public int getLocalPort() {
return sc.socket().getLocalPort();
}
}