Joe,

In fact, no it does not work properly with multiple instances, and
this is a problem I discovered shortly after originally posting this.
The solution I devised was to make the Proxy abstract and simply
create concrete sub-classes for each Presenter I want to proxy
(anonymous sub-classes do not work!). This is a little tedious, but
the abstraction I wrote makes it pretty simple to implement. Below is
the updated code. Note that I also changed the ViewProxy to use a
LayoutPanel instead of a SimplePanel so that proxied views that
implement RequiresLayout are supported.

/**
 * PresenterProxy wraps a Presenter implementation and acts as a
gateway to that
 * Presenter. The wrapped Presenter is created on-demand the first
time any
 * method is called, or optionally it can be created eagerly at the
time the
 * PresenterProxy is created.
 *
 * Instantiation of the wrapped Presenter occurs behind a
GWT.runAsync() call so
 * that complex wrapped Presenters may be split out into code
fragments during
 * module compilation.
 *
 * In order to achieve this "delayed" instantiation, the
PresenterProxy must be
 * given a Provider<T extends Presenter> instance to provide the
actual
 * implementation at the appropriate time.
 *
 * Additionally, a ViewProxy is utilized that consists of a
LayoutPanel to
 * minimize the impact on the UI. The ViewProxy can be inserted into
the DOM
 * immediately without waiting for the wrapped Presenter to become
available.
 *
 * Any calls made to the wrapped Presenter before the instance becomes
available
 * are queued in a buffer and later replayed when the instance becomes
 * available. Once available, all calls are executed immediately on
the wrapped
 * instance.
 *
 * @author jcarlson
 *
 * @param <T>
 */
public abstract class PresenterProxy<T extends Presenter> implements
        Presenter {

    private static class ProxyView implements View {

        LayoutPanel proxy = new LayoutPanel();

        ProxyView() {
        }

        @Override
        public Widget asWidget() {
            return this.proxy;
        }

        protected void setView(View view) {
            this.proxy.clear();
            this.proxy.add(view.asWidget());
        }

    }

    private boolean asyncCalled;
    private boolean bound;

    private HandlerManager bus;
    private T impl;
    private Queue<Command> queue;
    private ProxyView view;

    public PresenterProxy(HandlerManager bus) {
        this(bus, false);
    }

    public PresenterProxy(HandlerManager bus, boolean eager) {
        this.bus = bus;
        this.queue = new LinkedList<Command>();
        this.view = new ProxyView();
        if (eager) {
            ensurePresenter();
        }
    }

    @Override
    public final void bind() {
        this.bound = true;
        queue(new Command() {

            @Override
            public void execute() {
                PresenterProxy.this.impl.bind();
            }

        });
    }

    @Override
    public final View getView() {
        return this.view;
    }

    @Override
    public final void handleHistory(final HistoryItem item) {
        queue(new Command() {

            @Override
            public void execute() {
                PresenterProxy.this.impl.handleHistory(item);
            }

        });
    }

    @Override
    public final boolean isBound() {
        return this.bound;
    }

    @Override
    public final void release() {
        queue(new Command() {

            @Override
            public void execute() {
                PresenterProxy.this.impl.release();
            }
        });
        this.bound = false;
    }

    protected final void onAsyncFailure(Throwable reason) {
        PresenterProxy.this.bus
                .fireEvent(new ApplicationExceptionEvent(reason));
    }

    protected final void onAsyncSuccess(T impl) {
        // set impl instance
        this.impl = impl;

        // fill-in proxy view
        this.view.setView(PresenterProxy.this.impl.getView());

        // execute any queued commands
        while (ResizingPresenterProxy.this.queue.peek() != null) {
            Command cmd = PresenterProxy.this.queue.poll();
            cmd.execute();
        }

    }

    /**
     * The key method that subclasses must override.
     * This allows each GWT.runAsync() call to be in its own
     * concrete class, thus allowing the compiler to produce
     * multiple exclusive fragments.
     */
    protected abstract void runAsync();

    void ensurePresenter() {
        if (!this.asyncCalled) {
            this.asyncCalled = true;
            runAsync();
        }
    }

    void queue(Command command) {
        ensurePresenter();
        if (this.impl != null) {
            command.execute();
        } else {
            this.queue.offer(command);
        }
    }

}



And an implementation of the proxy:



public class MyPresenterProxy extends
        PresenterProxy<ProfilePresenter> {

    private Provider<ProfilePresenter> provider;

    @Inject
    public MyPresenterProxy(HandlerManager bus,
            Provider<ProfilePresenter> provider) {
        super(bus);
        this.provider = provider;
    }

    @Override
    protected void runAsync() {
        GWT.runAsync(new RunAsyncCallback() {

            @Override
            public void onFailure(Throwable reason) {
                onAsyncFailure(reason);
            }

            @Override
            public void onSuccess() {
                MyPresenter presenter = MyPresenterProxy.this.provider
                        .get();
                onAsyncSuccess(presenter);
            }
        });
    }

}

On Feb 8, 3:31 am, Joe Cheng <j...@joecheng.com> wrote:
> Jarrod, are you using this ProxyPresenter more than once within the same
> application (with different presenter type parameters), and found that it
> introduced the split points as expected? I originally tried something like
> this but found that it would only ever introduce a single split point, no
> matter how many times I used it.
>
> I was able to solve the problem using deferred binding and was about to
> write a blog post about it, but if your code actually works as desired then
> I need to go back and figure out what I was doing wrong.
>
>
>
> On Mon, Jan 25, 2010 at 8:16 PM, jarrod <jarrod.carl...@gmail.com> wrote:
> > While building an application for my company, I needed a way to make
> > large sections of the application sit behind a split point. After
> > organizing my application into "modules" of related functionality, I
> > came up with slick, easy way to make those "modules" split out
> > automatically: by using a proxy presenter.
>
> > My application uses gin and a hand-made MVP framework based loosely
> > off of gwt-presenter. Some adaptation may be necessary to fit your
> > particular frameworks, but here goes:
>
> > public class ProxyPresenter<T extends Presenter> implements Presenter
> > {
>
> >    private static class ProxyView implements View {
>
> >        SimplePanel proxy = new SimplePanel();
>
> >        ProxyView() {
>
> >        }
>
> >       �...@override
> >        public Widget asWidget() {
> >            return this.proxy;
> >        }
>
> >        protected void setView(View view) {
> >            this.proxy.setWidget(view.asWidget());
> >        }
>
> >    }
>
> >    private boolean asyncCalled;
> >    private boolean bound;
>
> >    private HandlerManager bus;
> >    private T impl;
> >    private Provider<T> provider;
> >    private Queue<Command> queue;
> >    private ProxyView view;
>
> >    public ProxyPresenter(HandlerManager bus, Provider<T> provider) {
> >        this(bus, provider, false);
> >    }
>
> >    public ProxyPresenter(HandlerManager bus, Provider<T> provider,
> >            boolean eager) {
> >        this.bus = bus;
> >        this.provider = provider;
> >        this.queue = new LinkedList<Command>();
> >        this.view = new ProxyView();
> >        if (eager) {
> >            ensurePresenter();
> >        }
> >    }
>
> >   �...@override
> >    public void bind() {
> >        this.bound = true;
> >        queue(new Command() {
>
> >           �...@override
> >            public void execute() {
> >                ProxyPresenter.this.impl.bind();
> >            }
>
> >        });
> >    }
>
> >   �...@override
> >    public View getView() {
> >        return this.view;
> >    }
>
> >   �...@override
> >    public void handleHistory(final HistoryItem item) {
> >        queue(new Command() {
>
> >           �...@override
> >            public void execute() {
> >                ProxyPresenter.this.impl.handleHistory(item);
> >            }
>
> >        });
> >    }
>
> >   �...@override
> >    public boolean isBound() {
> >        return this.bound;
> >    }
>
> >   �...@override
> >    public void release() {
> >        queue(new Command() {
>
> >           �...@override
> >            public void execute() {
> >                ProxyPresenter.this.impl.release();
> >            }
> >        });
> >        this.bound = false;
> >    }
>
> >    protected void ensurePresenter() {
> >        if (!this.asyncCalled) {
> >            this.asyncCalled = true;
> >            GWT.runAsync(new RunAsyncCallback() {
>
> >               �...@override
> >                public void onFailure(Throwable reason) {
> >                    ProxyPresenter.this.bus
> >                            .fireEvent(new ApplicationExceptionEvent
> > (reason));
> >                }
>
> >               �...@override
> >                public void onSuccess() {
>
> >                    // get impl instance
> >                    ProxyPresenter.this.impl =
> > ProxyPresenter.this.provider
> >                            .get();
>
> >                    // fill-in proxy view
> >                    ProxyPresenter.this.view.setView
> > (ProxyPresenter.this.impl
> >                            .getView());
>
> >                    // execute any queued commands
> >                    while (ProxyPresenter.this.queue.peek() != null) {
> >                        Command cmd = ProxyPresenter.this.queue.poll
> > ();
> >                        cmd.execute();
> >                    }
>
> >                }
> >            });
> >        }
> >    }
>
> >    protected void queue(Command command) {
> >        ensurePresenter();
> >        if (this.impl != null) {
> >            command.execute();
> >        } else {
> >            this.queue.offer(command);
> >        }
> >    }
>
> >    T getPresenter() {
> >        return this.impl;
> >    }
>
> > }
>
> > Then, in my gin module, instead of using an explicit bind, I use a
> > @Provides method, like so:
>
> >   �...@provides
> >    Presenter getRealPresenter(HandlerManager bus,
> >            Provider<RealPresenter> provider) {
> >        return new ProxyPresenter<RealPresenter>(bus, provider);
> >    }
>
> > The rest is automagic!
>
> > --
> > You received this message because you are subscribed to the Google Groups
> > "Google Web Toolkit" group.
> > To post to this group, send email to google-web-tool...@googlegroups.com.
> > To unsubscribe from this group, send email to
> > google-web-toolkit+unsubscr...@googlegroups.com<google-web-toolkit%2Bunsubs 
> > cr...@googlegroups.com>
> > .
> > For more options, visit this group at
> >http://groups.google.com/group/google-web-toolkit?hl=en.

-- 
You received this message because you are subscribed to the Google Groups 
"Google Web Toolkit" group.
To post to this group, send email to google-web-tool...@googlegroups.com.
To unsubscribe from this group, send email to 
google-web-toolkit+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/google-web-toolkit?hl=en.

Reply via email to