package com.github.pfichtner.jrunalyser.ui.dock; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.concurrent.Callable; import java.util.concurrent.Executors; import java.util.concurrent.FutureTask; import com.google.common.base.Supplier; public final class Suppliers { private Suppliers() { super(); } private static class BackgroundInvocationHandler<T> implements InvocationHandler { private final FutureTask<T> futureTask; private T real; public BackgroundInvocationHandler(final Supplier<T> supplier) { this.futureTask = new FutureTask<T>(new Callable<T>() { public T call() { return supplier.get(); } }); Executors.newSingleThreadExecutor().execute(this.futureTask); } public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { try { // assign for performance reasons, no synchronization needed: // multiple assignment of this.real won't hurt if (this.real == null) { // this call will block if the object was not already // created this.real = this.futureTask.get(); } return method.invoke(this.real, args); } catch (final InvocationTargetException ite) { throw ite.getCause(); } } } /** * Creates a Proxy that calls the passed Supplier to retrieve the delegate. * All calls to the Proxy will block until the passed Supplier has created * the delegate-object. * * @param <T> * type of Proxy * @param delegateSupplier * the Supplier to provides the delegate-object * @param iface * interfaces to implement * @return Proxy of type <code>ifaces</code> that retrieves the * delegate-object in background */ public static <T> T background(final Supplier<T> delegateSupplier, final Class<T> iface) { return iface.cast(Proxy.newProxyInstance(delegateSupplier.getClass() .getClassLoader(), new Class[] { iface }, new BackgroundInvocationHandler<T>(delegateSupplier))); } }