package net.spy.memcached.transcoders;
import java.util.Date;
import net.spy.memcached.CachedData;
/**
* Transcoder that provides compatibility with Greg Whalin's memcached client.
*/
public class WhalinTranscoder extends BaseSerializingTranscoder
implements Transcoder<Object> {
static final int SPECIAL_BYTE = 1;
static final int SPECIAL_BOOLEAN = 8192;
static final int SPECIAL_INT = 4;
static final int SPECIAL_LONG = 16384;
static final int SPECIAL_CHARACTER = 16;
static final int SPECIAL_STRING = 32;
static final int SPECIAL_STRINGBUFFER = 64;
static final int SPECIAL_FLOAT = 128;
static final int SPECIAL_SHORT = 256;
static final int SPECIAL_DOUBLE = 512;
static final int SPECIAL_DATE = 1024;
static final int SPECIAL_STRINGBUILDER = 2048;
static final int SPECIAL_BYTEARRAY = 4096;
static final int COMPRESSED = 2;
static final int SERIALIZED = 8;
private final TranscoderUtils tu=new TranscoderUtils(false);
public WhalinTranscoder() {
super(CachedData.MAX_SIZE);
}
/* (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());
}
if((d.getFlags() & SERIALIZED) != 0) {
rv=deserialize(data);
} else {
int f=d.getFlags() & ~COMPRESSED;
switch(f) {
case SPECIAL_BOOLEAN:
rv=Boolean.valueOf(this.decodeBoolean(data));
break;
case SPECIAL_INT:
rv=new Integer(tu.decodeInt(data));
break;
case SPECIAL_SHORT:
rv=new Short((short)tu.decodeInt(data));
break;
case SPECIAL_LONG:
rv=new Long(tu.decodeLong(data));
break;
case SPECIAL_DATE:
rv=new Date(tu.decodeLong(data));
break;
case SPECIAL_BYTE:
rv=new Byte(tu.decodeByte(data));
break;
case SPECIAL_FLOAT:
rv=new Float(Float.intBitsToFloat(tu.decodeInt(data)));
break;
case SPECIAL_DOUBLE:
rv=new Double(Double.longBitsToDouble(tu.decodeLong(data)));
break;
case SPECIAL_BYTEARRAY:
rv=data;
break;
case SPECIAL_STRING:
rv = decodeString(data);
break;
case SPECIAL_STRINGBUFFER:
rv=new StringBuffer(decodeString(data));
break;
case SPECIAL_STRINGBUILDER:
rv=new StringBuilder(decodeString(data));
break;
case SPECIAL_CHARACTER:
rv = decodeCharacter(data);
break;
default:
getLogger().warn("Cannot handle data with flags %x", f);
}
}
return rv;
}
public CachedData encode(Object o) {
byte[] b=null;
int flags=0;
if(o instanceof String) {
b=encodeString((String)o);
flags |= SPECIAL_STRING;
} else if(o instanceof StringBuffer) {
flags |= SPECIAL_STRINGBUFFER;
b=encodeString(String.valueOf(o));
} else if(o instanceof StringBuilder) {
flags |= SPECIAL_STRINGBUILDER;
b=encodeString(String.valueOf(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 Short) {
b=tu.encodeInt((Short)o);
flags |= SPECIAL_SHORT;
} else if(o instanceof Boolean) {
b=this.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.floatToIntBits((Float)o));
flags |= SPECIAL_FLOAT;
} else if(o instanceof Double) {
b=tu.encodeLong(Double.doubleToLongBits((Double)o));
flags |= SPECIAL_DOUBLE;
} else if(o instanceof byte[]) {
b=(byte[])o;
flags |= SPECIAL_BYTEARRAY;
} else if (o instanceof Character) {
b = tu.encodeInt((Character) o);
flags |= SPECIAL_CHARACTER;
} else {
b=serialize(o);
flags |= SERIALIZED;
}
assert b != null;
if(b.length > compressionThreshold) {
byte[] compressed=compress(b);
if(compressed.length < b.length) {
getLogger().debug("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, getMaxSize());
}
protected Character decodeCharacter(byte[] b){
return Character.valueOf((char)tu.decodeInt(b));
}
public byte[] encodeBoolean(boolean b){
byte[] rv = new byte[1];
rv[0] = (byte) (b ? 1 : 0);
return rv;
}
public boolean decodeBoolean(byte[] in) {
assert in.length == 1 : "Wrong length for a boolean";
return in[0] == 1;
}
}