Thursday, April 22, 2004

Java; POI Optimization - Speeding up the RecordFactory class.

This optimization needs two posts. This post presents a class that maps short values to a Constructor object. The RecordFactory class maps the short id value in the Excel file to a Java class. In the current version of POI, that relationship is kept, quite logically, in a Map object. However, using a Map object required that the short value be converted into a Short object quite frequently. This conversion is inefficient and, if some specially coding is done, unneeded. Note that the following class, shortToConstructorCache, is derivative of my earlier shortShortCache class.

/**
 * Cache a mapping from a short value to a Constructor object.
 * 
 * This class is designed to optimize the RecordFactory.createRecord()
 * method. It might be useful in other contexts, but I did not check.
 */
public class shortToConstructorCache {

    /**
     * The number of entries in the cache.
     */
    protected int       distinct;

    /**
     * The cached short values.
     */
    private short       table[];

    /**
     * The cached constructor methods
     */
    private Constructor values[];

    /**
     * RecordFactory uses a statically created array of
     * classes to initialize the cache and the entries
     * in the cache are never changed nor added to.  
     */
    public shortToConstructorCache(Class[] records) {
        super();
        
    	this.table = new short[records.length];
    	this.values = new Constructor[records.length];

        Constructor constructor;

        for (int i = 0; i < records.length; i++) {
            Class record = null;
            short sid = 0;

            record = records[i];
            try {
                sid = record.getField("sid").getShort(null);
                constructor = record.getConstructor(new Class[] {short.class, short.class, byte[].class});
            } catch (Exception illegalArgumentException) {
                illegalArgumentException.printStackTrace();
                throw new RecordFormatException("Unable to determine record types");
            }

            if (constructor == null) {
                throw new RecordFormatException("Unable to get constructor for sid [" + sid + "].");
            } else {
                this.table[this.distinct] = sid;
                this.values[this.distinct] = constructor;
                this.distinct++;
            }
        }
    }

    /** Gets the Constructor object related to a given
     * key.
     */
    public Constructor get(short key) {
        Constructor rv = null;
        
        	for (int i = 0; i < this.distinct; i++) {
        	    if (this.table[i] == key) {
        	        rv = this.values[i];
        	    }
        	}
        
        return rv;
    }
    
    /** Returns the number of entries in the cache. */
    public int size() {
        return this.distinct;
    }
    
    /** We're breaking encapsulation but some code in RecordFactory
     * wants the information and I want to change RecordFactory as
     * little as possible.
     */
    public short[] getTable() {
        return this.table;
    }

}
Post a Comment