package org.sugarj.driver.caching; import java.lang.ref.WeakReference; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.strategoxt.lang.Context; import org.sugarj.util.Pair; /** * Manages instances of org.strategoxt.lang.Context to enable * reuse and exclusive access. * * @author seba */ public class StrategoContextCache { /** * Class represents the actual type of the context, * first List denotes currently used contexts, * second List denotes currently unused contexts. */ private final Map<Class<?>, Pair<? extends List<Context>, ? extends List<WeakReference<Context>>>> cache = new HashMap<Class<?>, Pair<? extends List<Context>,? extends List<WeakReference<Context>>>>(); private final Map<Context, Class<?>> ctxToInit = new HashMap<Context, Class<?>>(); /** * Retrieves a free context from the cache or generates a new one. * * @param purpose * @return a context of the given actual type. */ public synchronized Context acquireContext(Class<?> initType) { Pair<? extends List<Context>,? extends List<WeakReference<Context>>> p = cache.get(initType); if (p == null) { p = Pair.create(new ArrayList<Context>(), new ArrayList<WeakReference<Context>>()); cache.put(initType, p); } Context fresh = null; while (fresh == null && !p.b.isEmpty()) fresh = p.b.remove(0).get(); if (fresh == null) try { fresh = (Context) initType.getMethod("init").invoke(initType); } catch (IllegalAccessException e) { throw new IllegalArgumentException("Illegal actual type " + initType, e); } catch (IllegalArgumentException e) { throw new IllegalArgumentException("Illegal actual type " + initType, e); } catch (InvocationTargetException e) { throw new IllegalArgumentException("Illegal actual type " + initType, e); } catch (NoSuchMethodException e) { throw new IllegalArgumentException("Illegal actual type " + initType, e); } catch (SecurityException e) { throw new IllegalArgumentException("Illegal actual type " + initType, e); } p.a.add(fresh); ctxToInit.put(fresh, initType); return fresh; } /** * Releases a previously acquired context. */ public synchronized void releaseContext(Context ctx) { Class<?> initType = ctxToInit.remove(ctx); Pair<? extends List<Context>,? extends List<WeakReference<Context>>> p = cache.get(initType); if (p == null || !p.a.contains(ctx)) throw new IllegalArgumentException("unknown context from initializer " + initType); p.a.remove(ctx); p.b.add(new WeakReference<Context>(ctx)); } }