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 <jarrod.carl
...@gmail.com> 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 <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