package rocks.inspectit.shared.all.kryonet;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import rocks.inspectit.shared.all.serializer.IKryoProvider;
import rocks.inspectit.shared.all.serializer.ISerializerProvider;
/**
* Implementation of the {@link IExtendedSerialization} with some additional methods we need for
* (de-)serializing the object during the communication. The idea is not to (de-)serialize from/to
* buffer, but to use the streams which would give us opportunity to transfer objects of unlimited
* size.
*
* @author Ivan Senic
*
*/
@SuppressWarnings("all")
public class ExtendedSerializationImpl implements IExtendedSerialization {
/**
* Default initial number of created serializers.
*/
private static final int INIT_CREATED_SERIALIZERS = 2;
/**
* Queue for {@link IKryoProvider} that are available.
*/
private Queue<IKryoProvider> serializerQueue = new ConcurrentLinkedQueue<IKryoProvider>();
/**
* {@link ISerializerProvider} for create new instances.
*/
private ISerializerProvider<? extends IKryoProvider> serializerProvider;
/**
* One argument constructor. Same as calling
* {@link #ExtendedSerializationImpl(ISerializerProvider, int)} with init serializers value of
* {@value #INIT_CREATED_SERIALIZERS}.
*
* @param serializerProvider
* {@link ISerializerProvider} needed for creation of the {@link IKryoProvider}
* instances.
*/
public ExtendedSerializationImpl(ISerializerProvider<? extends IKryoProvider> serializerProvider) {
this(serializerProvider, INIT_CREATED_SERIALIZERS);
}
/**
* Default constructor.
*
* @param serializerProvider
* {@link ISerializerProvider} needed for creation of the {@link IKryoProvider}
* instances.
* @param initialSerializersCreated
* Amount of {@link IKryoProvider}s to be created immediately.
*/
public ExtendedSerializationImpl(ISerializerProvider<? extends IKryoProvider> serializerProvider, int initialSerializersCreated) {
this.serializerProvider = serializerProvider;
for (int i = 0; i < initialSerializersCreated; i++) {
serializerQueue.offer(createKryoProvider());
}
}
/**
* {@inheritDoc}
* <p>
* Not implemented. It's not used because we won't write to the buffer, but to the output
* stream. But it's defined in the Serialization interface, so we must implement it.
*/
@Override
public void write(Connection connection, ByteBuffer buffer, Object object) {
}
/**
* {@inheritDoc}
* <p>
* Not implemented. It's not used because we won't read from the buffer, but from the input
* stream. But it's defined in the Serialization interface, so we must implement it.
*/
@Override
public Object read(Connection connection, ByteBuffer buffer) {
return null;
}
/**
* {@inheritDoc}
*/
@Override
public void writeLength(ByteBuffer buffer, int length) {
buffer.putInt(length);
}
/**
* {@inheritDoc}
*/
@Override
public int readLength(ByteBuffer buffer) {
return buffer.getInt();
}
/**
* {@inheritDoc}
* <p>
* Returns 4 as the original Kryo serialization. This should represent number of bytes needed
* for storing the length of the bytes to send.
*/
@Override
public int getLengthLength() {
return 4;
}
/**
* {@inheritDoc}
*/
@Override
@SuppressWarnings("unchecked")
public void write(Connection connection, OutputStream outputStream, Object object) {
Output output = new Output(outputStream);
IKryoProvider kryoProvider = serializerQueue.poll();
// if nothing is available in queue don't wait, create new one
if (null == kryoProvider) {
kryoProvider = createKryoProvider();
}
try {
Kryo kryo = kryoProvider.getKryo();
kryo.getContext().put("connection", connection);
kryo.writeClassAndObject(output, object);
output.flush();
} finally {
serializerQueue.offer(kryoProvider);
}
}
/**
*
* {@inheritDoc}
*/
@Override
@SuppressWarnings("unchecked")
public Object read(Connection connection, InputStream inputStream) {
Input input = new Input(inputStream);
IKryoProvider kryoProvider = serializerQueue.poll();
// if nothing is available in queue don't wait, create new one
if (null == kryoProvider) {
kryoProvider = createKryoProvider();
}
try {
Kryo kryo = kryoProvider.getKryo();
kryo.getContext().put("connection", connection);
return kryo.readClassAndObject(input);
} finally {
serializerQueue.offer(kryoProvider);
}
}
/**
* Creates new {@link IKryoProvider}.
* <p>
* Sub-classes can override.
*
* @return Creates new {@link IKryoProvider}.
*/
protected IKryoProvider createKryoProvider() {
return serializerProvider.createSerializer();
}
}