Hi, all,

Like many other projects, our GWT app needed a general framework. We opted to create one, and since I haven't seen anything else that works exactly like ours, I thought I'd share what we've done, in the hopes that doing so might contribute something useful to the (already extensive) discussions on GWT MVP frameworks. We'd also love to hear any comments/criticisms/suggestions you may have...!

In a nutshell:
- The framework is component-based. (No hot-swapping of components, though---code must be recompiled in order to switch components in or out.)
- Almost all objects are created in an injected context using GIN.
- We extend the standard GWT Place, Activity and ActivityManager classes/interfaces (among others). - There are two kinds of components in the framework: those that provide activity/view/ui-region bindings for specific places, and those that provide other kinds of functionality. - Activities are a generified extension of GWT's Activity; Activity classes have generic parameters that associate them with a specific Place class, a View class, and a class that represents the component they're a part of.

I'm not sure there's less boilerplate than in other MVP approaches. At least, though, it seems like everything is together that goes together, and we've got a decent, though very basic, path for encapsulating functionality in components as we complete and extend our app. And we got rid of the infamous "if (place instanceof SomePlace)" chain in ActivityMapper!

Anyone who'd like to check it out can get it like this:
    $ git clone http://lais.mora.edu.mx/gitrepo/pescador.git/
$ cd webclient (note: other subdirectories of the repository have unrelated stuff that you'll probably want to ignore)

Following are a few code snippets.

Here's part of a simple activity:

   public class BodyStartPageActivityImpl
            extends WebClientActivityBase<BodyStartPageView, StartPagePlace, 
StartPagePAVComponent>
             implements BodyStartPageActivity {

        @Inject
        public BodyStartPageActivityImpl(
                @Assisted StartPagePlace place) {
            super(place);
        }

        @Override
        public void start(AcceptsOneWidget container, EventBus eventBus) {
            BodyStartPageView view = getView();
            view.setText("Body start page activity here...<br />Another beautious 
line of start page.");
            container.setWidget(view);
        }

        [...]
   }

As shown, the activity is created using GIN, so it can have almost anything injected via its constructor. It also gets access to the correct view and place instances.

Here's a bit of a component that sets up activity/view/ui-region bindings for a place:

   public class ContentPAVComponentImpl extends PlaceActivityViewComponentBase<
            ContentPAVComponent,
            ContentPlace>
            implements
            ContentPAVComponent {

        @Inject
        public ContentPAVComponentImpl(
                ContentPlaceProvider contentPlaceProvider,
                ActivitiesFactory<ContentPlace, HeadContentActivity>
                        headActivitiesFactory,
                ActivitiesFactory<ContentPlace, BodyContentActivity>
                        bodyActivitiesFactory,
                ActivitiesFactory<ContentPlace, BannerContentActivity>
                        bannerActivitiesFactory,
                ActivitiesFactory<ContentPlace, WestContentActivity>
                        westActivitiesFactory) {

            super(
                ContentPAVComponent.class,
                "contenido",
                contentPlaceProvider,
                ContentPlace.class);

            // set up regions and activities factories
            addRegionAndActivitiesFactory(Head.class, headActivitiesFactory);
            addRegionAndActivitiesFactory(Body.class, bodyActivitiesFactory);
            addRegionAndActivitiesFactory(Banner.class, 
bannerActivitiesFactory);
            addRegionAndActivitiesFactory(West.class, westActivitiesFactory);
        }

        public static class ContentGinModule extends AbstractGinModule {
            // GIN module for bindings specific to this component
            [...]
        }

        [...]
   }


The component has a place provider and (GIN-generated) activity factories injected, which are passed along to the superclass. In turn, the superclass and other parts of the framework take care of starting the appropriate activities and views in the appropriate ui regions when the app goes to a place of the specified class. GIN bindings specific to this component are set up in the component's own GIN module.

Finally, here's a bit of a ComponetSetup class, which ties everything together:

   public class ActiveComponentSetup extends ComponentSetup {

        /**
         * Activate all necessary {@link GinModule}s for DI in the components 
to use,
         * as well as for basic infrastructure and local GinModule.
         */
        @GinModules({
                ActiveComponentSetupGinModule.class,    // current setup 
module, included below
                
                WebClientGinModule.class,                       // required 
basic infrastructure
                StandardDispatchModule.class,                   // required 
basic infrastructure
                
                ContentGinModule.class,                                 // 
content component
                StartPageGinModule.class                                // 
start page component
        })
        public interface ActiveComponentSetupGinjector extends 
WebClientGinjector {}

        /**
         *<p>Sets specific bindings;
         *  Backreferences (from components back to {@link 
ActiveComponentSetup})
         *  are set, as necessary, as components are received.</p>
        *
         *<p>Also set the root region provider.</p>
        *
         *<p>Note: components that rely on automatic generation of 
internationalized
         *  {@link Messages} by Maven must also set up the appropriate 
configuration in the
         *  pom.xml.</p>
        */
        @Inject
        public ActiveComponentSetup(
                        
                        WindowLayout winLayout,                         // 
global window layout widget
                        ContentPAVComponent contentPAVBinding,  // general 
content component
                        StartPagePAVComponent startPagePAVBinding   // start 
page component
                        ) {
                
                super();

                // do this before registering components, so that PAVBinding 
components
                // can be checked against the regions available here
                setRootRegionsWidget(winLayout);
                
                // register components
                // TODO once multibindings and mapbindings are in Gin, look 
into using that
                addComponents(contentPAVBinding, startPagePAVBinding);
                
                setDefaultPlaceProvider(startPagePAVBinding);
        }

            [...]
   }


So, basically, we have our Ginjector which brings together all the required GIN modules. ComponentSetup's constructor gets via injection the components we'll activate, and sets the default place and the object that'll take care of global UI layout.

So at the entry point, all we have to do is this:

   public class WebClient implements EntryPoint {
        
        /**
         * This is the entry point method.
         */
        public void onModuleLoad() {
                WebClientGinjector ginjector =
                                GWT.create(ActiveComponentSetupGinjector.class);

                ginjector.getComponetSetup().start();
        }
   }

And that's that! Many thanks in advance for your comments, suggestions, scathing criticisms, etc.!

Take care,
Andrew

P.S. It's all GPL, so anyone is welcome to reuse this, too.

--
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-toolkit@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