// Copyright (c) 2006 Dustin Sallings <dustin@spy.net>
package net.spy.memcached.transcoders;
import java.util.Date;
import net.spy.memcached.CachedData;
/**
* Transcoder that serializes and compresses objects.
*/
public class SerializingTranscoder extends BaseSerializingTranscoder
implements Transcoder<Object> {
// General flags
static final int SERIALIZED=1;
static final int COMPRESSED=2;
// Special flags for specially handled types.
private static final int SPECIAL_MASK=0xff00;
static final int SPECIAL_BOOLEAN=(1<<8);
static final int SPECIAL_INT=(2<<8);
static final int SPECIAL_LONG=(3<<8);
static final int SPECIAL_DATE=(4<<8);
static final int SPECIAL_BYTE=(5<<8);
static final int SPECIAL_FLOAT=(6<<8);
static final int SPECIAL_DOUBLE=(7<<8);
static final int SPECIAL_BYTEARRAY=(8<<8);
private final TranscoderUtils tu=new TranscoderUtils(true);
/* (non-Javadoc)
* @see net.spy.memcached.Transcoder#decode(net.spy.memcached.CachedData)
*/
public Object decode(CachedData d) {
byte[] data=d.getData();
Object rv=null;
if((d.getFlags() & COMPRESSED) != 0) {
data=decompress(d.getData());
}
int flags=d.getFlags() & SPECIAL_MASK;
if((d.getFlags() & SERIALIZED) != 0 && data != null) {
rv=deserialize(data);
} else if(flags != 0 && data != null) {
switch(flags) {
case SPECIAL_BOOLEAN:
rv=Boolean.valueOf(tu.decodeBoolean(data));
break;
case SPECIAL_INT:
rv=Integer.valueOf(tu.decodeInt(data));
break;
case SPECIAL_LONG:
rv=Long.valueOf(tu.decodeLong(data));
break;
case SPECIAL_DATE:
rv=new Date(tu.decodeLong(data));
break;
case SPECIAL_BYTE:
rv=Byte.valueOf(tu.decodeByte(data));
break;
case SPECIAL_FLOAT:
rv=Float.valueOf(Float.intBitsToFloat(tu.decodeInt(data)));
break;
case SPECIAL_DOUBLE:
rv=Double.valueOf(Double.longBitsToDouble(tu.decodeLong(data)));
break;
case SPECIAL_BYTEARRAY:
rv=data;
break;
default:
getLogger().warn("Undecodeable with flags %x", flags);
}
} else {
rv=decodeString(data);
}
return rv;
}
/* (non-Javadoc)
* @see net.spy.memcached.Transcoder#encode(java.lang.Object)
*/
public CachedData encode(Object o) {
byte[] b=null;
int flags=0;
if(o instanceof String) {
b=encodeString((String)o);
} else if(o instanceof Long) {
b=tu.encodeLong((Long)o);
flags |= SPECIAL_LONG;
} else if(o instanceof Integer) {
b=tu.encodeInt((Integer)o);
flags |= SPECIAL_INT;
} else if(o instanceof Boolean) {
b=tu.encodeBoolean((Boolean)o);
flags |= SPECIAL_BOOLEAN;
} else if(o instanceof Date) {
b=tu.encodeLong(((Date)o).getTime());
flags |= SPECIAL_DATE;
} else if(o instanceof Byte) {
b=tu.encodeByte((Byte)o);
flags |= SPECIAL_BYTE;
} else if(o instanceof Float) {
b=tu.encodeInt(Float.floatToRawIntBits((Float)o));
flags |= SPECIAL_FLOAT;
} else if(o instanceof Double) {
b=tu.encodeLong(Double.doubleToRawLongBits((Double)o));
flags |= SPECIAL_DOUBLE;
} else if(o instanceof byte[]) {
b=(byte[])o;
flags |= SPECIAL_BYTEARRAY;
} else {
b=serialize(o);
flags |= SERIALIZED;
}
assert b != null;
if(b.length > compressionThreshold) {
byte[] compressed=compress(b);
if(compressed.length < b.length) {
getLogger().info("Compressed %s from %d to %d",
o.getClass().getName(), b.length, compressed.length);
b=compressed;
flags |= COMPRESSED;
} else {
getLogger().info(
"Compression increased the size of %s from %d to %d",
o.getClass().getName(), b.length, compressed.length);
}
}
return new CachedData(flags, b);
}
}