package org.yajul.io;
import org.yajul.collections.CollectionUtil;
import org.yajul.comparators.ComparatorChain;
import org.yajul.comparators.ComparatorUtil;
import org.yajul.serialization.SerializableWrapper;
import org.yajul.serialization.SerializationHelper;
import java.io.*;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Serialization statistics helper.
* <br>User: Joshua Davis
* Date: Nov 23, 2007
* Time: 6:08:06 PM
*/
public class SerializationStats {
private final static Logger log = Logger.getLogger(SerializationStats.class.getName());
/**
* Returns the size of the object if it was serialize all by itself.
*
* @param object the serializable object
* @return the number of bytes
* @throws IOException if something goes wrong
*/
public static int sizeOf(Serializable object) throws IOException {
ByteCountingOutputStream counter = new ByteCountingOutputStream(
new NullOutputStream());
SerializationHelper.serialize(object, counter);
return counter.getByteCount();
}
/**
* Counts the number of objects of each class inside the serializable object, and also
* counts the number of bytes that the object would have in serialized form.
*
* @param obj the object
* @return the statistics.
*/
public static Stats getStats(Serializable obj) {
try {
ByteCountingOutputStream counter = new ByteCountingOutputStream(new NullOutputStream());
CountingObjectOutputStream oos = new CountingObjectOutputStream(counter);
oos.writeObject(obj);
return new Stats(counter.getByteCount(), oos);
} catch (IOException e) {
log.log(Level.WARNING, "Unable to compute size of " + obj.getClass().getSimpleName() + " due to : " + e);
return null;
}
}
/**
* The total size, and the number of instances of each class in an object.
*/
public static class Stats {
private int totalSize;
private CountingObjectOutputStream oos;
public Stats(int byteCount, CountingObjectOutputStream oos) {
this.totalSize = byteCount;
this.oos = oos;
}
public int getTotalSize() {
return totalSize;
}
public Collection<CountingObjectOutputStream.Counter> getCounters() {
return oos.getCounters();
}
public CountingObjectOutputStream.Counter getCounter(String name) {
return oos.getCounter(name);
}
}
public static final ComparatorChain COUNTER_COMPARATOR = new ComparatorChain(
new Comparator<CountingObjectOutputStream.Counter>() {
public int compare(CountingObjectOutputStream.Counter o1, CountingObjectOutputStream.Counter o2) {
return ComparatorUtil.compareIntegers(o1.getCount(), o2.getCount());
}
},
new Comparator<CountingObjectOutputStream.Counter>() {
public int compare(CountingObjectOutputStream.Counter o1, CountingObjectOutputStream.Counter o2) {
return ComparatorUtil.NULL_LOW_STRING_COMPARATOR.compare(o1.getName(), o2.getName());
}
}
);
public static List<CountingObjectOutputStream.Counter> sortCounters(SerializationStats.Stats stats) {
List<CountingObjectOutputStream.Counter> counters = CollectionUtil.newArrayList(stats.getCounters());
Collections.sort(counters, COUNTER_COMPARATOR);
return counters;
}
/**
* Automatically unwrap the object if it implements SerializableWrapper.
*
* @param obj The object, or a SerializableWrapper around an object.
* @return The wrapped object if the argument implements SerializableWrapper, or the argument
* object if it doesn't implement SerializableWrapper.
* @throws java.io.IOException if something goes wrong
* @throws ClassNotFoundException if something goes wrong
*/
public static Serializable autoUnwrap(Serializable obj) throws IOException, ClassNotFoundException {
if (obj instanceof SerializableWrapper) {
SerializableWrapper wrapper = (SerializableWrapper) obj;
return wrapper.unwrap();
} else
return obj;
}
}