Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Architecting your GWT applications with GWT-Platform - Lesson 02


Published on

Write GXT3 application using GWTP

  • Be the first to comment

Architecting your GWT applications with GWT-Platform - Lesson 02

  1. 1. Architecting your GWT application with GWT- PlatformJuan Manuel Rojas R. Lima, Perú 26/10/2012
  2. 2. Architecting your GWT applicationGoogle found that a Model-view-presenter(MVP) architecture works best whendeveloping GWT apps View Presenter FrameworksMvp4ggwt-dispatchgwt-platform
  3. 3. GWT-PlatformIts an open source MVP framework, thatsupports many nice features of GWT, includingcode splitting and history management, with asimple annotation-based API.
  4. 4. A highly productive app stack UI (MVP) gwt-platform (GWTP) RPC GWT RequestFactory PostgreSQL JPA 2.0 - PostgreSQL
  5. 5. Google Plugin for EclipseUpdate sitesEclipse 4.2 (Juno)
  6. 6. GWTP Eclipse PluginTo install the GWTP Eclipse Plugin, fromEclipse go to Help > Install New SoftwareClick on Add...Name: GWTPLocation:
  7. 7. Clean example code1. Delete theme lines from Module.gwt.xml2. Delete files from Entry point client package GreetingService package com.example.client; GreetingServiceAsync server package, import; import; GreetingServiceImpl shared packaged public class FirstProject implements EntryPoint { FieldVerifier src/test/java public void onModuleLoad() { GwtTestFirstProject Window.alert("empty project"); } src/test/resources } FirstProjectJUnit.gwt.xml3. Clean Css file and html table code src/main/webapp4. Delete servlet definition from web.xml src/main/webapp/WEB-INF
  8. 8. Dependency injection (DI)Separate behavior from dependency resolution.Injects the dependent element (object or valueetc) to the destination automatically.Reduction of boilerplate code in the applicationobjects since all work to initialize or set updependencies is handled by a providercomponent.
  9. 9. Dependency injection for GWTgoogle-ginGIN is built on top of Guice and uses (a subsetof) Guices binding language. <!-- google-gin --> <dependency> <groupId></groupId> <artifactId>gin</artifactId> <version>2.0.0</version> <exclusions> <exclusion> <groupId></groupId> <artifactId>gwt-servlet</artifactId> </exclusion> </exclusions> </dependency>
  10. 10. Dependency injection for Java 5google-guiceThink of Guices @Inject as the new new.Guice embraces Javas type safe nature usinggenerics and annotations. <!-- google guice --> <dependency> <groupId></groupId> <artifactId>guice</artifactId> <version>3.0</version> </dependency>
  11. 11. Dependency injection GIN Constructor injection Field injectionpublic class ClientPlaceManager { public class ColaboradorPresenter { @Inject @Inject Messages messages; public ClientPlaceManager(final EventBus eventBus, final TokenFormatter tokenFormatter) { public ColaboradorPresenter() { //eventBus and tokenFormatter are not null //messages is null } }} protected void onBind() { //messages is not null } }
  12. 12. Dependency injection GIN (Continuation) @Provides Methods When you need create and initialize an object. public class ClientModule extends AbstractPresenterModule { @Provides @Singleton public AppRequestFactory createRequestFactory(EventBus eventBus, MyDefaultRequestTransport requestTransport) { AppRequestFactory factory = GWT.create(AppRequestFactory.class); factory.initialize(eventBus, requestTransport); return factory; } } public class ColaboradorPresenter { private final AppRequestFactory factory;How to inject @Inject public ColaboradorPresenter(Provider<AppRequestFactory> provider){ factory = provider.get(); } }
  13. 13. Setting GWTP and GXT3 <properties>Add to your Module.gwt.xml ... <gwtp.version>0.7</gwtp.version> ...<inherits name=com.sencha.gxt.ui.GXT/> </properties><inherits name=com.gwtplatform.mvp.Mvp/> <!-- MVP component --> <dependency>Add to your POM.xml <groupId>com.gwtplatform</groupId> <artifactId>gwtp-mvp-client</artifactId> <version>${gwtp.version}</version> <scope>provided</scope> <!-- sencha gxt3 --> </dependency> <dependency> <!-- Annotation component --> <groupId>com.sencha.gxt</groupId> <dependency> <artifactId>gxt</artifactId> <groupId>com.gwtplatform</groupId> <version>3.0.1</version> <artifactId>gwtp-processors</artifactId> </dependency> <version>${gwtp.version}</version> <scope>provided</scope> </dependency>
  14. 14. Setting GWTP Create the directories com.example.clientimport static java.lang.annotation.ElementType.FIELD;import static java.lang.annotation.ElementType.PARAMETER; |--presenterimport static java.lang.annotation.ElementType.METHOD;import static java.lang.annotation.RetentionPolicy.RUNTIME; |--view |--place@BindingAnnotation@Target({ FIELD, PARAMETER, METHOD }) public class NameTokens {@Retention(RUNTIME)public @interface DefaultPlace { }} import; public class ClientPlaceManager extends PlaceManagerImpl { private final PlaceRequest defaultPlaceRequest; @Inject public ClientPlaceManager(final EventBus eventBus, final TokenFormatter tokenFormatter, @DefaultPlace final String defaultPlaceNameToken) { super(eventBus, tokenFormatter); this.defaultPlaceRequest = new PlaceRequest(defaultPlaceNameToken); } public void revealDefaultPlace() { revealPlace(defaultPlaceRequest, false); }
  15. 15. Setting GIN for GWTPInheriting the GIN module<inherits name=""/>Create a gin package in the client sidepublic class ClientModule extends AbstractPresenterModule { Define objects @Override available for protected void configure() { injection install(new DefaultModule(ClientPlaceManager.class)); }}import; Getters methods@GinModules(ClientModule.class)public interface ClientGinjector extends Ginjector { for get objects EventBus getEventBus(); PlaceManager getPlaceManager();}If GIN cant find a binding for a class, it falls back to calling GWT.create() on thatclass.
  16. 16. Setting GIN for GWTP(Continuation)Configure your EntryPointpublic class FirstProject implements EntryPoint { private final ClientGinjector ginjector = GWT.create(ClientGinjector.class); public void onModuleLoad() { // This is required for Gwt-Platform proxys generator DelayedBindRegistry.bind(ginjector); ginjector.getPlaceManager().revealCurrentPlace(); }} Add the next properties to your Module.gwt.xml <module> ... <define-configuration-property name=gin.ginjector is-multi-valued=false /> <set-configuration-property name=gin.ginjector value=com.example.client.gin.ClientGinjector /> </module>
  17. 17. GWT-Platform and GXT3Structure your viewsA place represent a url of a program
  18. 18. GWT-Platform and GXT3(Continuation)TokensMost presenters have a token so the user can navigate.When there is not token the default presenter is shown.You can navigate from one presenter to another by:● Typing another url PlaceRequest request = new PlaceRequest("inicio");● Using a Hyperlink Widget placeManager.revealPlace(request);● Using a PlaceRequest
  19. 19. GWT-Platform and GXT3(Continuation)Nested PresentersYour header, footer and menu are in onepresenter the "parent presenter".
  20. 20. GWT-Platform and GXT3(Continuation)Presenter WidgetIs for reusable graphical and logical code.
  21. 21. GWT-Platform and GXT3(Continuation)Popup PresentersIs a presenter widgetthat is shown insidea popup dialog. For create Popup Presenters with GXT Window you need the following classes
  22. 22. GWT-Platform and GXT3(Continuation)All presenters are composed of three files if you will useUIBinderAll presenters have a inner interface that view implements.
  23. 23. GWT-Platform and GXT3(Continuation)Presenter lifecycle
  24. 24. GWT-Platform and GXT3(Continuation)Presenter lifecycle1. Presenters are Singleton so it is instantiated once.2. prepareFromRequest(): Is where you can get url parameters.3. onBind(): Is called when the presenter is instantiated.4. onReveal(): Is called whenever the Presenter was not visible on screen and becomes visible.5. onHide(): Is called whenever the Presenter was visible on screen and is being hidden.6. onReset(): Is called whenever the user navigates to a page that shows the presenter, whether it was visible or not.
  25. 25. Create Presenterusing GWTP Eclipse Plugin
  26. 26. First PresenterLayoutPresenterOptions ● Use UiBinder ● RevealRootContentEvent ● Is Not a PlaceOrderingMove to view packageLayoutView.javaLayoutView.ui.xml
  27. 27. First Presenter LayoutPresenter(Continuation)Deprecated shared.EventBusGWTP Eclipse Plugin use EventBus from event.sharednext this package was deprecated and change to web.bindery.event.shared.* Is important to do the next in every presenter you createwith GWTP Eclipse PluginDeleteimport byimport;
  28. 28. First Presenter LayoutPresenter(Continuation)Add the next field to LayoutPresenter import; //for nested presenters @ContentSlot public static final Type<RevealContentHandler<?>> SLOT_content = new Type<RevealContentHandler<?>>();Modify LayoutView.ui.xml<!DOCTYPE ui:UiBinder SYSTEM ""><ui:UiBinder xmlns:gxt= "urn:import:com.sencha.gxt.widget.core.client" xmlns:container= "urn:import:com.sencha.gxt.widget.core.client.container" > <container:Viewport> <!--for nested presenter --> <gxt:ContentPanel ui:field="contentPanel" borders="false"headerVisible= "false" bodyBorder= "false" /> </container:Viewport></ui:UiBinder>
  29. 29. First Presenter LayoutPresenter (Continuation) Setting Vertical Layout (LayoutView.ui.xml)<ui:UiBinder> ...<ui:with type="com.sencha.gxt.widget.core.client.container.VerticalLayoutContainer.VerticalLayoutData"field="minVerticalLayoutData" > <ui:attributes width="1" height="-1" /> </ui:with> <ui:with type="com.sencha.gxt.widget.core.client.container.VerticalLayoutContainer.VerticalLayoutData"field="maxVerticalLayoutData" > <ui:attributes width="1" height="1" /> </ui:with> <container:Viewport> ... </container:Viewport></ui:UiBinder>
  30. 30. First Presenter LayoutPresenter (Continuation) Using Vertical Layout (LayoutView.ui.xml)<ui:UiBinder> ... <container:Viewport> <container:VerticalLayoutContainer> <container:child layoutData="{minVerticalLayoutData}"> <g:HTMLPanel> <div> <div>First Project</div> </div> </g:HTMLPanel> </container:child> <container:child layoutData="{maxVerticalLayoutData}"> <!--for nested presenter --> <gxt:ContentPanel ui:field="contentPanel" borders="false" headerVisible="false"bodyBorder="false" /> </container:child> </container:VerticalLayoutContainer> </container:Viewport></ui:UiBinder>
  31. 31. First Presenter LayoutPresenter(Continuation)Add the next field to LayoutView@UiField ContentPanel contentPanel;//for nested presenterAdd the next method to LayoutView @Override public void setInSlot(Object slot, Widget content) { if(slot == LayoutPresenter.SLOT_content){ contentPanel.clear(); if(content != null){ contentPanel.add(content); contentPanel.forceLayout(); } return; } super.setInSlot(slot, content); }
  32. 32. Default PresenterWelcomePresenterOptions ● Use UiBinder ● RevealContentEvent ● Content Slot (from parent presenter) ● Is a Place ● CodeSplit (recommended) ● Token: #welcome ● DefaultPlace
  33. 33. Default Presenter WelcomePresenter(Continuation)Modify WelcomeView.ui.xml<!DOCTYPE ui:UiBinder SYSTEM ""><ui:UiBinder xmlns:gxt= "urn:import:com.sencha.gxt.widget.core.client" xmlns:container= "urn:import:com.sencha.gxt.widget.core.client.container"> <gxt:ContentPanel headingText= "Welcome" > <container:CenterLayoutContainer> <g:HTMLPanel><h2> Welcome User </h2></g:HTMLPanel> </container:CenterLayoutContainer> </gxt:ContentPanel></ui:UiBinder>
  34. 34. reset.cssDownload reset.cssput this css in your HTML header<head>...<link type="text/css" rel="stylesheet" href="reset.css">...</head>In your Module.css file*{ font-family: arial, helvetica, tahoma, sans-serif;}
  35. 35. mvn gwt:run
  36. 36. Styling our applicationGWT provides ClientBundle for styling in anoptimised way. client.resources |- add.png |- delete.png |- cancel.png |- edit.png |- save.png |- exit.png |- bg.gif
  37. 37. Styling our application(Continuation)public interface Resources extends ClientBundle { @Source("add.png") ImageResource add(); @Source("delete.png") client.resources ImageResource delete(); |- @Source("cancel.png") ImageResource cancel(); @Source("edit.png") ImageResource edit(); @Source("save.png") ImageResource save(); @Source("exit.png") ImageResource exit();}
  38. 38. Styling our application(Continuation)public interface CommonsCss extends CssResource { @ClassName("layout-header") String layout_header(); client.resources |- @ClassName("layout-title") |- Commons.css String layout_title(); String logout(); @ClassName("underline") String underline(); @ClassName("button") String button(); String exit();}
  39. 39. Styling our application(Continuation)Add to your ClientBundlepublic interface Resources extends ClientBundle { ... @Source("bg.gif") ImageResource bg(); @Source("Commons.css") CommonsCss commonsCss();}
  40. 40. Styling our application(Continuation)Modify LayoutView.ui.xml<ui:UiBinder> <ui:with type="com.example.client.resources.Resources" field="resources" /> ... <container:child layoutData="{minVerticalLayoutData}"> <g:HTMLPanel styleName="{resources.commonsCss.layout_header}"> <div class="{resources.commonsCss.layout_title}"> First Project </div> <div class="{resources.commonsCss.logout}"> <span class="{resources.commonsCss.underline}"> <a class="{resources.commonsCss.button}" href="/logout" > <span class="{resources.commonsCss.exit}">Logout</span> </a> </span> </div> </g:HTMLPanel> </container:child> ...</ui:UiBinder>
  41. 41. Styling our application(Continuation)Modify LayoutView.javapublic class LayoutView extends ViewImpl implements LayoutPresenter .MyView { ... @Inject public LayoutView(final Binder binder , final Resources resources ) { resources.commonsCss ().ensureInjected ();//load css widget = binder.createAndBindUi (this); }}
  42. 42. mvn gwt:run Thanks
  43. 43. References