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); /* (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(tu.decodeBoolean(data)); break; case SPECIAL_INT: rv=Integer.valueOf(tu.decodeInt(data)); break; case SPECIAL_SHORT: rv=Short.valueOf((short)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; 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; 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=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.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 { 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); } }