package net.gnehzr.tnoodle.utils; import static net.gnehzr.tnoodle.utils.GwtSafeUtils.azzert; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; public class LazyInstantiator<H> { // package.FileHandler("www/") private static final Pattern INSTANTIATION_PATTERN = Pattern.compile("(\\S+)\\s*\\((.*)\\)"); // TODO - this pattern doesn't actually match all valid strings private static final Pattern ARGUMENT_PATTERN = Pattern.compile("((\"[^,]*\")|(true)|(false)|(-?\\d+)),?\\s*"); private String className; private String definition; private Class<H> parentClass; private ClassLoader classLoader; public LazyInstantiator(String definition, Class<H> classy, ClassLoader classLoader) throws BadLazyClassDescriptionException { if(classLoader == null) { classLoader = getClass().getClassLoader(); } this.classLoader = classLoader; Matcher m = INSTANTIATION_PATTERN.matcher(definition); if(!m.matches()) { throw new BadLazyClassDescriptionException(definition); } this.definition = definition; this.parentClass = classy; ArrayList<Class<?>> argTypes = new ArrayList<Class<?>>(); ArrayList<Object> args = new ArrayList<Object>(); // group 0 is the whole string // group 1 is the name of the class we're lazily instantiating // group 2 is the constructor arguments this.className = m.group(1); String arguments = m.group(2); m = ARGUMENT_PATTERN.matcher(arguments); int start = 0; while(m.find(start)) { start = m.end(); String strExpr = m.group(2); String trueExpr = m.group(3); String falseExpr = m.group(4); String intExpr = m.group(5); if(strExpr != null) { argTypes.add(String.class); azzert(strExpr.startsWith("\"") && strExpr.endsWith("\"")); // TODO - handle escape character (decode string!) String str = strExpr.substring(1, strExpr.length()-1); args.add(str); } else if(trueExpr != null) { argTypes.add(boolean.class); args.add(true); } else if(falseExpr != null) { argTypes.add(boolean.class); args.add(false); } else if(intExpr != null) { argTypes.add(int.class); args.add(Integer.parseInt(intExpr)); } else { azzert(false); } } if(start != arguments.length()) { throw new BadLazyClassDescriptionException(definition); } this.argTypes = argTypes.toArray(new Class<?>[0]); this.args = args.toArray(); } private Constructor<? extends H> constructor; private Class<?>[] argTypes; private Object[] args; private Class<? extends H> thisClass; public H newInstance() throws LazyInstantiatorException { try { if(constructor == null) { thisClass = classLoader.loadClass(className).asSubclass(this.parentClass); constructor = thisClass.getConstructor(this.argTypes); } return constructor.newInstance(args); } catch(ClassNotFoundException e) { throw new LazyInstantiatorException(e); } catch(NoSuchMethodException e) { throw new LazyInstantiatorException(e); } catch(InstantiationException e) { throw new LazyInstantiatorException(e); } catch(IllegalArgumentException e) { throw new LazyInstantiatorException(e); } catch(IllegalAccessException e) { throw new LazyInstantiatorException(e); } catch(InvocationTargetException e) { throw new LazyInstantiatorException(e); } } private H cachedInstance = null; public synchronized H cachedInstance() throws LazyInstantiatorException { if(cachedInstance == null) { cachedInstance = newInstance(); } return cachedInstance; } @Override public String toString() { return super.toString() + " " + this.definition; } }