package org.commcare.util.externalizable;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Hashtable;
import org.javarosa.core.util.PrefixTree;
import org.javarosa.core.util.externalizable.ExtUtil;
import org.javarosa.core.util.externalizable.ExtWrapTagged;
import org.javarosa.core.util.externalizable.PrototypeFactory;
/**
* @author ctsims
*
*/
public class ImprovedPrototypeFactory extends PrototypeFactory {
PrefixTree classNames;
Hashtable<Integer, Class> prototypes = new Hashtable<Integer, Class>();
MessageDigest digest;
public ImprovedPrototypeFactory (PrefixTree classNames) {
super(classNames);
this.classNames = classNames;
try {
digest = java.security.MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/*
* (non-Javadoc)
* @see org.javarosa.core.util.externalizable.PrototypeFactory#addClass(java.lang.Class)
*/
@Override
public void addClass (Class c) {
if (!initialized) {
lazyInit();
}
//this is used as a bulk operation, so we custom implement it, the android hash is way faster
//than the j2me compatible one.
byte[] hash = getClassHashInternal(c);
if (compareHash(hash, ExtWrapTagged.WRAPPER_TAG)) {
throw new Error("Hash collision! " + c.getName() + " and reserved wrapper tag");
}
Class d = getClass(hash);
if (d != null && d != c) {
int one = getHash(hash);
int two = getHash(getClassHash(d));
throw new Error("Hash collision! " + one + c.getName() + ExtUtil.printBytes(hash) +" and " + d.getName() + ExtUtil.printBytes(getClassHash(d)));
}
prototypes.put(getHash(hash), c);
}
public byte[] getClassHashInternal (Class type) {
byte[] hash = new byte[CLASS_HASH_SIZE];
byte[] md5 = digest.digest(type.getName().getBytes());
for (int i = 0; i < hash.length; i++)
hash[i] = md5[i];
byte[] badHash = new byte[] {0,4,78,97};
if(PrototypeFactory.compareHash(badHash, hash)) {
System.out.println("BAD CLASS: " + type.getName());
}
return hash;
}
private Integer getHash(byte[] hash) {
return Integer.valueOf((hash[3] << 0) + (hash[2] << 8) + (hash[1] << 16) + (hash[0] << 24));
}
/*
* (non-Javadoc)
* @see org.javarosa.core.util.externalizable.PrototypeFactory#getClass(byte[])
*/
@Override
public Class getClass (byte[] hash) {
if (!initialized) {
lazyInit();
}
return prototypes.get(getHash(hash));
}
}