package games.strategy.net.nio;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* A packet of data to be written over the network.
*
* <p>
* Packets do not correspond to ip packets. A packet is just the data for one serialized object.
* </p>
*
* <p>
* The packet is written over the network as 32 bits indicating the size in bytes, then the data itself.
* </p>
*/
public class SocketWriteData {
private static final Logger s_logger = Logger.getLogger(SocketWriteData.class.getName());
private static final AtomicInteger s_counter = new AtomicInteger();
private final ByteBuffer m_size;
private final ByteBuffer m_content;
private final int m_number = s_counter.incrementAndGet();
// how many times we called write before we finished writing ourselves
private int m_writeCalls = 0;
public SocketWriteData(final byte[] data, int count) {
m_content = ByteBuffer.allocate(count);
m_content.put(data, 0, count);
m_size = ByteBuffer.allocate(4);
if (count < 0 || count > SocketReadData.MAX_MESSAGE_SIZE) {
throw new IllegalStateException("Invalid message size:" + count);
}
count = count ^ SocketReadData.MAGIC;
m_size.putInt(count);
m_size.flip();
m_content.flip();
}
public int size() {
return m_size.capacity() + m_content.capacity();
}
public int getWriteCalls() {
return m_writeCalls;
}
/**
* @return true if the write has written the entire message.
*/
public boolean write(final SocketChannel channel) throws IOException {
m_writeCalls++;
if (m_size.hasRemaining()) {
final int count = channel.write(m_size);
if (count == -1) {
throw new IOException("triplea: end of stream detected");
}
if (s_logger.isLoggable(Level.FINEST)) {
s_logger.finest("wrote size_buffer bytes:" + count);
}
// we could not write everything
if (m_size.hasRemaining()) {
return false;
}
}
final int count = channel.write(m_content);
if (count == -1) {
throw new IOException("triplea: end of stream detected");
}
if (s_logger.isLoggable(Level.FINEST)) {
s_logger.finest("wrote content bytes:" + count);
}
return !m_content.hasRemaining();
}
@Override
public String toString() {
return "<id:" + m_number + " size:" + m_content.capacity() + ">";
}
}