OK, great, I went through a similar approach previously. The new approach
I'm using is similar but you can remove the boilerplate in the proxy
implementation, as the deferred binding mechanism will fill it all in. In
fact since you're using Gin it will literally look like this:
public abstract class MyAsyncShim extends AsyncShim<MyPresenter> { }
I'll reply to this thread when I have something written up. I would also
like to adapt your idea of using a command queue, right now I'm doing
something similar but not guaranteeing the methods will be executed in the
order they were invoked.
On Tue, Feb 9, 2010 at 8:42 AM, jarrod <[email protected]> wrote:
> 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 <[email protected]> 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 <[email protected]>
> 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
> [email protected].
> > > To unsubscribe from this group, send email to
> > > [email protected]<google-web-toolkit%[email protected]><google-web-toolkit%2Bunsubs
> [email protected]>
> > > .
> > > 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 [email protected].
> To unsubscribe from this group, send email to
> [email protected]<google-web-toolkit%[email protected]>
> .
> 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 [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/google-web-toolkit?hl=en.