package org.radargun;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.nio.ByteBuffer;
/**
* Helper class holding serialization logic.
*
* @author Mircea Markus <Mircea.Markus@jboss.com>
*/
public final class SerializationHelper {
private static final int MIN_REMAINING = 32;
private SerializationHelper() {}
/**
* Write serialized representation of given object to the buffer on the current position.
* If the object does not fit to buffer's capacity, a new buffer is allocated, old buffer
* is copied into the new buffer and then the object is written into the new buffer.
*
* Note than the original buffer can be modified even if the object does not fit there.
*
* @param serializable
* @param buffer Buffer with appended serialized representation of the object.
* @return
* @throws IOException
*/
public static ByteBuffer serializeObject(Serializable serializable, ByteBuffer buffer) throws IOException {
try (ByteBufferOutputStream out = new ByteBufferOutputStream(buffer); ObjectOutputStream oos = new ObjectOutputStream(out)) {
oos.writeObject(serializable);
return out.getBuffer();
}
}
/**
* Write length of serialized representation of given object and the serialized representation
* to the buffer on the current position. The length is represented as 4 byte integer in current byte order.
* If the object does not fit to buffer's capacity, a new buffer is allocated, old buffer
* is copied into the new buffer and then the object is written into the new buffer.
*
* Note than the original buffer can be modified even if the object does not fit there.
*
* @param serializable
* @param buffer Buffer with appended serialized representation of the object.
* @return
* @throws IOException
*/
public static ByteBuffer serializeObjectWithLength(Serializable serializable, ByteBuffer buffer) throws IOException {
if (buffer.remaining() < MIN_REMAINING) {
buffer = grow(buffer, MIN_REMAINING);
}
int sizePosition = buffer.position();
buffer.position(sizePosition + 4);
try (ByteBufferOutputStream out = new ByteBufferOutputStream(buffer); ObjectOutputStream oos = new ObjectOutputStream(out)) {
oos.writeObject(serializable);
buffer = out.getBuffer();
buffer.putInt(sizePosition, buffer.position() - sizePosition - 4);
return buffer;
}
}
/**
* Append long to the end of the buffer, possibly reallocating it.
*
* @param value
* @param buffer
* @return
*/
public static ByteBuffer appendLong(long value, ByteBuffer buffer) {
if (buffer.remaining() < 8) buffer = grow(buffer, MIN_REMAINING);
buffer.putLong(value);
return buffer;
}
/**
* Deserialize object from given byte array, starting at startPos and using length bytes.
*
* @param serializedData
* @param startPos
* @param length
* @return
* @throws IOException
*/
public static Object deserialize(byte[] serializedData, int startPos, int length) throws IOException {
try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(serializedData, startPos, length))) {
return ois.readObject();
} catch (ClassNotFoundException e) {
throw new IllegalStateException("Unmarshalling exception", e);
}
}
private static ByteBuffer grow(ByteBuffer buffer, int minCapacityIncrease) {
ByteBuffer tmp = ByteBuffer.allocate(Math.max(buffer.capacity() << 1, buffer.capacity() + minCapacityIncrease));
buffer.flip();
tmp.put(buffer);
return tmp;
}
private static class ByteBufferOutputStream extends OutputStream {
private ByteBuffer buffer;
private ByteBufferOutputStream(ByteBuffer buffer) {
this.buffer = buffer;
}
private void grow(int minCapacityIncrease) {
buffer = SerializationHelper.grow(buffer, minCapacityIncrease);
}
@Override
public void write(int b) throws IOException {
if (!buffer.hasRemaining()) {
grow(1);
}
buffer.put((byte) b);
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
if (buffer.remaining() < len) {
grow(len - buffer.remaining());
}
buffer.put(b, off, len);
}
public ByteBuffer getBuffer() {
return buffer;
}
}
}