package net.spy.memcached.transcoders;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.UnsupportedEncodingException;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import org.apache.commons.lang.CharEncoding;
import net.spy.SpyObject;
import net.spy.util.CloseUtil;
/**
* Base class for any transcoders that may want to work with serialized or
* compressed data.
*/
public abstract class BaseSerializingTranscoder extends SpyObject {
/**
* Default compression threshold value.
*/
public static final int DEFAULT_COMPRESSION_THRESHOLD = 16384;
protected int compressionThreshold=DEFAULT_COMPRESSION_THRESHOLD;
protected String charset = CharEncoding.UTF_8;
/**
* Set the compression threshold to the given number of bytes. This
* transcoder will attempt to compress any data being stored that's larger
* than this.
*
* @param to the number of bytes
*/
public void setCompressionThreshold(int to) {
compressionThreshold=to;
}
/**
* Set the character set for string value transcoding (defaults to UTF-8).
*/
public void setCharset(String to) {
// Validate the character set.
try {
new String(new byte[97], to);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
charset=to;
}
/**
* Get the bytes representing the given serialized object.
*/
protected byte[] serialize(Object o) {
if(o == null) {
throw new NullPointerException("Can't serialize null");
}
byte[] rv=null;
try {
ByteArrayOutputStream bos=new ByteArrayOutputStream();
ObjectOutputStream os=new ObjectOutputStream(bos);
os.writeObject(o);
os.close();
bos.close();
rv=bos.toByteArray();
} catch(IOException e) {
throw new IllegalArgumentException("Non-serializable object", e);
}
return rv;
}
/**
* Get the object represented by the given serialized bytes.
*/
protected Object deserialize(byte[] in) {
Object rv=null;
try {
if(in != null) {
ByteArrayInputStream bis=new ByteArrayInputStream(in);
ObjectInputStream is=new ObjectInputStream(bis);
rv=is.readObject();
is.close();
bis.close();
}
} catch(IOException e) {
getLogger().warn("Caught IOException decoding %d bytes of data",
in.length, e);
} catch (ClassNotFoundException e) {
getLogger().warn("Caught CNFE decoding %d bytes of data",
in.length, e);
}
return rv;
}
/**
* Compress the given array of bytes.
*/
protected byte[] compress(byte[] in) {
if(in == null) {
throw new NullPointerException("Can't compress null");
}
ByteArrayOutputStream bos=new ByteArrayOutputStream();
GZIPOutputStream gz=null;
try {
gz = new GZIPOutputStream(bos);
gz.write(in);
} catch (IOException e) {
throw new RuntimeException("IO exception compressing data", e);
} finally {
CloseUtil.close(gz);
CloseUtil.close(bos);
}
byte[] rv=bos.toByteArray();
getLogger().debug("Compressed %d bytes to %d", in.length, rv.length);
return rv;
}
/**
* Decompress the given array of bytes.
*
* @return null if the bytes cannot be decompressed
*/
protected byte[] decompress(byte[] in) {
ByteArrayOutputStream bos=null;
if(in != null) {
ByteArrayInputStream bis=new ByteArrayInputStream(in);
bos=new ByteArrayOutputStream();
GZIPInputStream gis;
try {
gis = new GZIPInputStream(bis);
byte[] buf=new byte[8192];
int r=-1;
while((r=gis.read(buf)) > 0) {
bos.write(buf, 0, r);
}
} catch (IOException e) {
getLogger().warn("Failed to decompress data", e);
bos = null;
}
}
return bos == null ? null : bos.toByteArray();
}
/**
* Decode the string with the current character set.
*/
protected String decodeString(byte[] data) {
String rv=null;
try {
if(data != null) {
rv=new String(data, charset);
}
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
return rv;
}
/**
* Encode a string into the current character set.
*/
protected byte[] encodeString(String in) {
byte[] rv=null;
try {
rv=in.getBytes(charset);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
return rv;
}
}