package io.craft.atom.protocol.rpc;
import io.craft.atom.protocol.ProtocolException;
import io.craft.atom.protocol.rpc.model.RpcBody;
import io.craft.atom.protocol.rpc.model.RpcMethod;
import io.craft.atom.protocol.rpc.spi.Serialization;
import io.craft.atom.util.Assert;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.lang.ref.SoftReference;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.esotericsoftware.kryo.serializers.CompatibleFieldSerializer;
/**
* The implementor using <a href="https://github.com/EsotericSoftware/kryo">kryo</a>.
* <p>
* Not thread safe.
*
* @author mindwind
* @version 1.0, Jul 23, 2014
*/
public class KryoSerialization implements Serialization<RpcBody> {
// singleton
private static final KryoSerialization INSTNACE = new KryoSerialization();
public static KryoSerialization getInstance() { return INSTNACE; }
private KryoSerialization() {}
// thread local cache
private static final ThreadLocal<SoftReference<Kryo>> CACHE = new ThreadLocal<SoftReference<Kryo>>() {
@Override
protected SoftReference<Kryo> initialValue() {
Kryo kryo = newKryo();
return new SoftReference<Kryo>(kryo);
}
};
private static Kryo newKryo() {
Kryo kryo = new Kryo();
kryo.register(RpcBody.class);
kryo.register(RpcMethod.class);
kryo.setDefaultSerializer(CompatibleFieldSerializer.class);
return kryo;
}
@Override
public byte type() {
return 1;
}
@Override
public byte[] serialize(RpcBody rb) {
try {
Assert.notNull(rb);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Output output = new Output(baos);
kryo().writeObject(output, rb);
output.close();
return baos.toByteArray();
} catch (Exception e) {
throw new ProtocolException(e);
}
}
private Kryo kryo() {
Kryo kryo = CACHE.get().get();
if (kryo == null) {
kryo = newKryo();
CACHE.set(new SoftReference<Kryo>(kryo));
}
return kryo;
}
@Override
public RpcBody deserialize(byte[] bytes) {
return deserialize(bytes, 0);
}
@Override
public RpcBody deserialize(byte[] bytes, int off) {
try {
Assert.notNull(bytes);
ByteArrayInputStream bais = new ByteArrayInputStream(bytes, off, bytes.length - off);
Input input = new Input(bais);
RpcBody rb = kryo().readObject(input, RpcBody.class);
input.close();
return rb;
} catch (Exception e) {
throw new ProtocolException(e);
}
}
}