Upgrade to Pro — share decks privately, control downloads, hide ads and more …

GWT + mvp4g

GWT + mvp4g

GWT + mvp4g Lecture from ADDConf '2011

Ulric Wilfred

November 21, 2011
Tweet

More Decks by Ulric Wilfred

Other Decks in Programming

Transcript

  1. Anthony Kotenko 6 years in Java EE development 6 years

    in UI development Sex: male http://shamansir.madfire.net http://zokotuhaFly.habrahabr.ru http://twitter.com/shaman_sir http://profiles.google.com/shaman.sir
  2. 1. Introduction. A brief history and examples of GWT usage

    2. A brief introduction to concepts: - MVP / Reverse MVP - EventBus - Dependency Injection 3. Description of mvp4g framework - differences in RMVP implementation from GWT - difference in implementation of EventBus - multimoduleness - HistoryConverter conception - advantages / disadvantages
  3. 6. Working with non-Java Server-Side-API (versus RPC-services) - making call

    chains - callback vs. GwtEvent - advantages / disadvantages 4. Components in GWT - UiBinder, standard components - custom widgets development 7. i18n in GWT 5. Our layouting system development 8. Conclusion. Links to the examples
  4. Your questions may (and must be) asked during the lecture:

    to let reporter know about you having question regarding the theme or not, just raise your hand (any of them). Like so: Discussion is important I have a question!
  5. Used in these projects: Google Wave wave.google.com Google Checkout checkout.google.com

    Google Moderator google.com/moderator Whirled whirled.com Lombardi Blueprint blueprint.lombardi.com ContactOffice beta.contactoffice.com
  6. Used in these projects: GoGrid gogrid.com Curriki curriki.org OpenKM openkm.com

    Kdice kdice.com SeeMap seemap.ru Одноклассники odnoklassniki.ru
  7. widgets cross-browserly! simple i18n on-the-fly development optimization OOP benefits debug

    RPC http://test.ical.ly/wp-content/uploads/2010/04/i18n.png
  8. Version 1.0 was released in 2006 Version 1.6 Google Eclipse

    Plugin Project structure matches Web Application specification
  9. • Java → JavaScript, JSNI • Development Mode • Code

    Splitting • <Module>.gwt.xml • MVC, MVP, RMVP, EventBus • Deferred Binding • Dependency Injection • Remote Service • JUnit • Disadvantages and remarks
  10. JSNI public native static void <functionName>(<parameters>) /*-{ . . .

    @<path.to.the.package>.<ClassName>::<methodName>( /L<param-type>;/L<param-type>;...)(<arguments>); . . . }-*/;
  11. JSNI public native static void getJson(int requestId, String url, StockWatcher

    handler) /*-{ var callback = "callback" + requestId; var script = document.createElement("script"); script.setAttribute("src", url+callback); script.setAttribute("type", "text/javascript"); window[callback] = function(jsonObj) { [email protected] .client.StockWatcher::handleJsonResponse( Lcom/google/gwt/core/client/JavaScriptObject;)(jsonObj); window[callback + "done"] = true; } setTimeout(function() { if (!window[callback + "done"]) { [email protected] .client.StockWatcher::handleJsonResponse( Lcom/google/gwt/core/client/JavaScriptObject;)(null); } document.body.removeChild(script); delete window[callback]; delete window[callback + "done"]; }, 1000); document.body.appendChild(script); }-*/;
  12. JSNI You can wrap native JavaScript widgets with JSNI. For

    example, Google Maps or any WYSIWYG-editor
  13. JSNI WYSIWYG-widget, written in Closure and integrated with the help

    of JSNI Google Maps widget, integrated with the help of JSNI Flash-object using JavaScript-callbacks, which are called through JSNI
  14. Development Mode helps in debugging your project: when you change

    your Java-code just press Ctrl+F5 in your browser — and your changes will come into force! Mrrwah!
  15. Code Splitting Spell isoid createAsync(final MClient client) { GWT.runAsync(...) public

    void onFailure(Throwable err) { . . . } public void onSuccess() { if (instance == null) { . . . instance = new Module(); . . . client.onSuccess(instance); } }); } when the neccessary code was loaded
  16. Code Splitting Spell isSp createAsync(final MClient client) { GWT.runAsync(new RunAsyncCallback()

    { public void onFailure(Throwable err) { . . . } public void onSuccess() { if (instance == null) { . . . instance = new Module(); . . . client.onSuccess(instance); } }); } when the neccessary code was loaded
  17. Code Splitting public static void createAsync(final MClient client) { GWT.runAsync(new

    RunAsyncCallback() { public void onFailure(Throwable err) { client.onUnavailable(); } public void onSuccess() { if (instance == null) { instance = new Module(); } client.onSuccess(instance); } }); } when the neccessary code was loaded
  18. Code Splitting lets you specify separate parts of your project

    to load: so you can split your project in large modules — and your users will feel themselves happy! Brrlyawrr!
  19. <Module>.gwt.xml ⁕ Components a list of code components you use

    ⁕ Browsers a list of browsers to be a target of project compilation
  20. <Module>.gwt.xml ⁕ Components a list of code components you use

    ⁕ Browsers a list of browsers to be a target of project compilation ⁕ Locales a list of locales supported in your project
  21. <Module>.gwt.xml ⁕ Components a list of code components you use

    ⁕ Browsers a list of browsers to be a target of project compilation ⁕ Locales a list of locales supported in your project ⁕ Debug turning debug information output on/off
  22. <Module>.gwt.xml ⁕ Components <inherits name="com.google.gwt.user.User"/> ⁕ Browsers <set-property name="user.agent" value="ie6,gecko1_8,safari"

    /> ⁕ Locales <extend-property name="locale" values="fr_CA,de" /> <set-property-fallback name="locale" value="fr_CA" /> ⁕ Debug
  23. <Module>.gwt.xml ⁕ Components <inherits name="com.google.gwt.user.User"/> ⁕ Browsers <set-property name="user.agent" value="ie6,gecko1_8,safari"

    /> ⁕ Locales <extend-property name="locale" values="fr_CA,de" /> <set-property-fallback name="locale" value="fr_CA" /> ⁕ Debug [<Module>Debug.gwt.xml]
  24. <Module>.gwt.xml ⁕ Components <inherits name="com.google.gwt.user.User"/> ⁕ Browsers <set-property name="user.agent" value="ie6,gecko1_8,safari"

    /> ⁕ Locales <extend-property name="locale" values="fr_CA,de" /> <set-property-fallback name="locale" value="fr_CA" /> ⁕ Debug [<Module>Debug.gwt.xml] <inherits name="com.example.MainModule" /> <set-property name="log_level" value="DEBUG" />
  25. <Module>.gwt.xml ⁕ Components <inherits name="com.google.gwt.user.User" /> ⁕ Browsers <set-property name="user.agent"

    value="ie6,gecko1_8,safari" /> ⁕ Locales <extend-property name="locale" values="fr_CA,de" /> <set-property-fallback name="locale" value="fr_CA" /> ⁕ Debug [<Module>Debug.gwt.xml] <inherits name="com.example.MainModule" /> <set-property name="log_level" value="DEBUG" />
  26. .gwt.xml file — is almost the same thing as web.xml

    file for web application: here lies all of the project configuration
  27. Hmmm... To be honest, seems I did not understand the

    difference between all those mah-fah-am-wee-pee...
  28. Deferred Binding Dynamic implementation of any interface (and just in

    case if it is actually required) In response to the lack of Reflection
  29. Deferred Binding GWT.create(....class) spell Dynamic implementation of any interface (and

    just in case if it is actually required) In response to the lack of Reflection
  30. Deferred Binding GWT.create(....class) spell Dynamic implementation of any interface (and

    just in case if it is actually required) CompileTime-binding In response to the lack of Reflection
  31. Deferred Binding GWT.create(....class) spell Dynamic implementation of any interface (and

    just in case if is actually required) CompileTime-binding In response to the lack of Reflection
  32. Deferred Binding PopupImpl: public void setVisible(boolean visible) { // ...

    common code for all implementations of PopupPanel ... // If the PopupImpl creates an iframe shim, it's also // necessary to hide it as well. impl.setVisible(getElement(), visible); }
  33. Deferred Binding PopupImpl: public void setVisible(boolean visible) { // ...

    common code for all implementations of PopupPanel ... // If the PopupImpl creates an iframe shim, it's also // necessary to hide it as well. impl.setVisible(getElement(), visible); } PopupImplIE6: public native void setVisible(Element popup, boolean visible) /*-{ if (popup.__frame) { popup.__frame.style.visibility = visible ? 'visible' : 'hidden'; } }-*/;
  34. Deferred Binding <replace-with class="com.google.gwt...PopupImplIE6"> <when-type-is class="com.google.gwt...PopupImpl" /> <any> <when-property-is name="user.agent"

    value="ie6" /> <when-property-is name="user.agent" value="ie6_1" /> </any> </replace-with> private static final PopupImpl impl = GWT.create(PopupImpl.class);
  35. Deferred Binding is a tool to create cross-browser and translingual

    implementations. Namely for techniques that will differ between contexts of project usage.
  36. Dependency Injection Binding instances to interfaces at one point (thus

    we achieve separation of behavior from implementing solution) Using GWT INjection / Guice frameworks
  37. Dependency Injection Lets you forget about XML-settings and factories Binding

    instances to interfaces at one point (thus we achieve separation of behavior from implementing solution) Using GWT INjection / Guice frameworks
  38. Dependency Injection Lets you forget about XML-settings and factories Binding

    instances to interfaces at one point (thus we achieve separation of behavior from implementing solution) Runtime-binding Using GWT INjection / Guice frameworks
  39. Dependency Injection Lets you forget about XML-settings and factories Binding

    instances to interfaces at one point (thus we achieve separation of behavior from implementing solution) Runtime-binding Using GWT INjection / Guice frameworks
  40. Dependency Injection class MyModule extends AbstractGinModule { @Override protected void

    configure() { bind(Something.class).toProvider(SomethingProvider.class); bind(Any.class).in(Singleton.class); bind(Foo.class).to(SomeFooImpl.class); } } class Bar { @Inject private Any any; private final Something something; private final Foo foo; @Inject public Bar(Something something, Foo foo) { } }
  41. Dependency Injection lets you easily manage your logical implementations. Even

    when your project is running. For example, you can switch database drivers or service implementations. These are the things you've done using application-context.xml in Spring, but much better. Annotations are wonderrrful!
  42. Remote Service public interface StringReverserService extends RemoteService { public String

    reverseString(String stringToReverse); } public interface StringReverserServiceAsync { void reverseString(String stringToReverse, AsyncCallback async); }
  43. Remote Service public interface StringReverserService extends RemoteService { public String

    reverseString(String stringToReverse); } public interface StringReverserServiceAsync { void reverseString(String stringToReverse, AsyncCallback async); } public class StringReverserServiceImpl extends RemoteServiceServlet implements StringReverserService { . . . }
  44. Remote Service public interface StringReverserService extends RemoteService { public String

    reverseString(String stringToReverse); } public interface StringReverserServiceAsync { void reverseString(String stringToReverse, AsyncCallback async); } public class StringReverserServiceImpl extends RemoteServiceServlet implements StringReverserService { . . . } StringReverserServiceAsync reverserService = (StringReverserServiceAsync) GWT.create(StringReverserService.class);
  45. JUnit public class StockWatcherTest extends GWTTestCase { public String getModuleName()

    { return "com.google.gwt.sample.stockwatcher.StockWatcher"; } . . . }
  46. Deficiencies and observations Anyway, you need good skills in JavaScript

    Especially when using external JS-libraries «Manual» makeup (HTMLPanel) becomes not sustainable and has no cross-browser compatibility
  47. Deficiencies and observations Anyway, you need good skills in JavaScript

    Especially when using external JS-libraries «Manual» makeup (HTMLPanel) becomes not sustainable and has no cross-browser compatibility GWT is for web-applications, but not pretentious portals
  48. Deficiencies and observations Anyway, you need good skills in JavaScript

    Especially when using external JS-libraries «Manual» makeup (HTMLPanel) becomes not sustainable and has no cross-browser compatibility GWT is for web-applications, but not pretentious portals You can write your own (or extend existing) components, but then thinking about cross-browser compatibility is your concern
  49. Deficiencies and observations Anyway, you need good skills in JavaScript

    Especially when using external JS-libraries «Manual» makeup (HTMLPanel) becomes not sustainable and has no cross-browser compatibility GWT is for web-applications, but not pretentious portals You can write your own (or extend existing) components, but then thinking about cross-browser compatibility is your concern And you'll need to make a detailed lecture about GWT components system for your makeup men, by the way
  50. Deficiencies and observations Anyway, you need good skills in JavaScript

    Especially when using external JS-libraries «Manual» makeup (HTMLPanel) becomes not sustainable and has no cross-browser compatibility GWT is for web-applications, but not pretentious portals You can write your own (or extend existing) components, but then thinking about cross-browser compatibility is your concern And you'll need to make a detailed lecture about GWT components system for your makeup men, by the way No guidance at non-Java Server-Side (Python & GAE, for example)
  51. Deficiencies and observations Anyway, you need good skills in JavaScript

    Especially when using external JS-libraries «Manual» makeup (HTMLPanel) becomes not sustainable and has no cross-browser compatibility GWT is for web-applications, but not pretentious portals You can write your own (or extend existing) components, but then thinking about cross-browser compatibility is your concern And you'll need to make a detailed lecture about GWT components system for your makeup men, by the way No guidance at non-Java Server-Side (Python & GAE, for example) Well, let's buid it on top of RequestBuilder
  52. Deficiencies and observations Anyway, you need good skills in JavaScript

    Especially when using external JS-libraries One JS-error crashes the whole application «Manual» makeup (HTMLPanel) becomes not sustainable and has no cross-browser compatibility GWT is for web-applications, but not pretentious portals You can write your own (or extend existing) components, but then thinking about cross-browser compatibility is your concern And you'll need to make a detailed lecture about GWT components system for your makeup men, by the way No guidance at non-Java Server-Side (Python & GAE, for example) Well, let's buid it on top of RequestBuilder
  53. Deficiencies and observations Anyway, you need good skills in JavaScript

    Especially when using external JS-libraries One JS-error crashes the whole application However, we have GWT.setUncaughtExceptionHandler «Manual» makeup (HTMLPanel) becomes not sustainable and has no cross-browser compatibility GWT is for web-applications, but not pretentious portals You can write your own (or extend existing) components, but then thinking about cross-browser compatibility is your concern And you'll need to make a detailed lecture about GWT components system for your makeup men, by the way No guidance at non-Java Server-Side (Python & GAE, for example) Well, let's buid it on top of RequestBuilder
  54. Deficiencies and observations Anyway, you need good skills in JavaScript

    Especially when using external JS-libraries One JS-error crashes the whole application However, we have GWT.setUncaughtExceptionHandler «Manual» makeup (HTMLPanel) becomes not sustainable and has no cross-browser compatibility GWT is for web-applications, but not pretentious portals You can write your own (or extend existing) components, but then thinking about cross-browser compatibility is your concern And you'll need to make a detailed lecture about GWT components system for your makeup men, by the way No guidance at non-Java Server-Side (Python & GAE, for example) Well, let's buid it on top of RequestBuilder JavaScript-errors provide little information
  55. Deficiencies and observations Anyway, you need good skills in JavaScript

    Especially when using external JS-libraries One JS-error crashes the whole application However, we have GWT.setUncaughtExceptionHandler «Manual» makeup (HTMLPanel) becomes not sustainable and has no cross-browser compatibility GWT is for web-applications, but not pretentious portals You can write your own (or extend existing) components, but then thinking about cross-browser compatibility is your concern And you'll need to make a detailed lecture about GWT components system for your makeup men, by the way No guidance at non-Java Server-Side (Python & GAE, for example) Well, let's buid it on top of RequestBuilder JavaScript-errors provide little information Although, they are for sure much easier to understand when debug info is on
  56. Deficiencies and observations Anyway, you need good skills in JavaScript

    Especially when using external JS-libraries One JS-error crashes the whole application However, we have GWT.setUncaughtExceptionHandler «Manual» makeup (HTMLPanel) becomes not sustainable and has no cross-browser compatibility GWT is for web-applications, but not pretentious portals You can write your own (or extend existing) components, but then thinking about cross-browser compatibility is your concern And you'll need to make a detailed lecture about GWT components system for your makeup men, by the way Development Mode works slower than real code: so you may encounter problems in events succession No guidance at non-Java Server-Side (Python & GAE, for example) Well, let's buid it on top of RequestBuilder JavaScript-errors provide little information Although, they are for sure much easier to understand when debug info is on
  57. Deficiencies and observations Anyway, you need good skills in JavaScript

    Especially when using external JS-libraries One JS-error crashes the whole application However, we have GWT.setUncaughtExceptionHandler «Manual» makeup (HTMLPanel) becomes not sustainable and has no cross-browser compatibility GWT is for web-applications, but not pretentious portals You can write your own (or extend existing) components, but then thinking about cross-browser compatibility is your concern And you'll need to make a detailed lecture about GWT components system for your makeup men, by the way Development Mode works slower than real code: so you may encounter problems in events succession Нey, you say you've never debugged code using alerts?! No guidance at non-Java Server-Side (Python & GAE, for example) Well, let's buid it on top of RequestBuilder JavaScript-errors provide little information Although, they are for sure much easier to understand when debug info is on
  58. Deficiencies and observations Anyway, you need good skills in JavaScript

    Especially when using external JS-libraries One JS-error crashes the whole application However, we have GWT.setUncaughtExceptionHandler «Manual» makeup (HTMLPanel) becomes not sustainable and has no cross-browser compatibility GWT is for web-applications, but not pretentious portals You can write your own (or extend existing) components, but then thinking about cross-browser compatibility is your concern And you'll need to make a detailed lecture about GWT components system for your makeup men, by the way Development Mode works slower than real code: so you may encounter problems in events succession Нey, you say you've never debugged code using alerts?! No guidance at non-Java Server-Side (Python & GAE, for example) Well, let's buid it on top of RequestBuilder JavaScript-errors provide little information Although, they are for sure much easier to understand when debug info is on Regular expressions are just a wrapper for JavaScript RegExp
  59. Deficiencies and observations Anyway, you need good skills in JavaScript

    One JS-error crashes the whole application «Manual» makeup (HTMLPanel) becomes not sustainable and has no cross-browser compatibility Development Mode works slower than real code: so you may encounter problems in events succession No guidance at non-Java Server-Side (Python & GAE, for example) JavaScript-errors provide little information Regular expressions are just a wrapper for JavaScript RegExp
  60. Deficiencies and observations Anyway, you need good skills in JavaScript

    Especially when using external JS-libraries One JS-error crashes the whole application However, we have GWT.setUncaughtExceptionHandler «Manual» makeup (HTMLPanel) becomes not sustainable and has no cross-browser compatibility GWT is for web-applications, but not pretentious portals You can write your own (or extend existing) components, but then thinking about cross-browser compatibility is your concern And you'll need to make a detailed lecture about GWT components system for your makeup men, by the way Development Mode works slower than real code: so you may encounter problems in events succession Нey, you say you've never debugged code using alerts?! No guidance at non-Java Server-Side (Python & GAE, for example) Well, let's buid it on top of RequestBuilder JavaScript-errors provide little information Although, they are for sure much easier to understand when debug info is on Regular expressions are just a wrapper for JavaScript RegExp
  61. • What helps? • Annotation system • RMVP realization •

    EventBus realization • URL, HistoryConverters, #! • Multimodularity • PlaceService • Remarks
  62. work with (R)MVP organize multi-modular applications design and develop events

    buses work with history (incl. hashbangs #!) mvp4g framework helps to
  63. work with (R)MVP organize multi-modular applications design and develop events

    buses work with history (incl. hashbangs #!) ... also constantly being improved mvp4g framework helps to
  64. work with (R)MVP organize multi-modular applications design and develop events

    buses work with history (incl. hashbangs #!) ... also constantly being improved mvp4g framework helps to
  65. The code you write using mvp4g framework is much simpler

    than GWT-code without its usage. It is achieved by Pierre correct use of annotations. Code is written by human. It is better to help him sometimes. Code is written by human. It is better to help him sometimes.
  66. RMVP annotations @Debug @Event @EventHandler @Events @Filters @Forward @History @InitHistory

    @InjectService @NotFoundHistory @PlaceService @Presenter @Service @Start
  67. RMVP view @Presenter(view=OneView.class) public class OnePresenter extends BasePresenter<IOneView, OneEventBus> {

    @Inject private ServiceAsync service; } class OneView extends Composite implements IOneView { . . . }
  68. RMVP reverse @Presenter(view=OneView.class) public class OnePresenter extends BasePresenter<IOneView, OneEventBus> {

    @Inject private ServiceAsync service; } class OneView extends Composite implements IOneView, ReverseViewInterface<OnePresenter> { . . . }
  69. EventBus annotations @Debug @Event @EventHandler @Events @Filters @Forward @History @InitHistory

    @InjectService @NotFoundHistory @PlaceService @Presenter @Service @Start
  70. EventBus events @Events(startView = StartView.class) public interface OneEventBus extends EventBus

    { @Event public void fooEvent(...); @Event public void barEvent(...); }
  71. EventBus handlers @Events(startView = StartView.class) public interface OneEventBus extends EventBus

    { @Event(handlers={FooPresenter.class, AcmePresenter.class}) public void fooEvent(...); @Event(handlers=BarPresenter.class) public void barEvent(...); } FooPresenter::onFooEvent(...) {...} FooPresenter::onFooEvent(...) {...} BarPresenter::onBarEvent(...) {...}
  72. EventBus activation @Events(startView = StartView.class) public interface OneEventBus extends EventBus

    { @Event(handlers={FooPresenter.class, AcmePresenter.class}, activate={FooPresenter.class, AcmePresener.class}, deactivate={BarPresenter.class}) public void fooEvent(...); @Event(handlers=BarPresenter.class, activate={BarPresenter.class}, deactivate={FooPresenter.class, AcmePresener.class}) public void barEvent(...); }
  73. EventBus broadcast @Events(startView = StartView.class) public interface OneEventBus extends EventBus

    { @Event(broadcastTo=IBroadcast.class, calledMethod="boo") public void broadcastEvent(...); } public class Foo implements IBroadcast { public void boo(...) {...}; }
  74. EventBus filters and stuff @Filters(filterClasses={FilterOne.class, FilterTwo.class}) @Debug(logger=CustomLogger.class) @Events(startView = StartView.class)

    public interface OneEventBus extends EventBus { . . . } class FilterOne implements EventFilter<OneEventBus> { @Override public boolean filterEvent(...) { return ...; } }
  75. History annotations @Debug @Event @EventHandler @Events @Filters @Forward @History @InitHistory

    @InjectService @NotFoundHistory @PlaceService @Presenter @Service @Start
  76. History handling @Events(..., historyOnStart = true) public interface OneEventBus extends

    EventBus { @Start @InitHistory public void start(); @Event(handlers=..., navigationEvent=true, historyName="foo", historyConverter=OneHC.class) public void fooEvent(...); @NotFoundHistory public void show404(); }
  77. @Events(..., historyOnStart = true) public interface OneEventBus extends EventBus {

    @Start @InitHistory public void start(); @Event(handlers=..., navigationEvent=true, historyName="foo", historyConverter=OneHC.class) public void fooEvent(...); @NotFoundHistory public void show404(); } /start /foo History passing
  78. @Events(...) public interface OneEventBus ... { @Event(..., navigationEvent=true, historyName="foo", historyConverter=OneHC.class)

    public void fooEvent(int id, Filter filter); } @History public class OneHC implements HistoryConverter<OneEventBus> { @Inject private TokenGenerator tokens; public void convertFromToken(...) { if ("foo".equals(event)) eventBus.fooEvent( Integer.parseInt(params[0]), Filter.parse(params[1])); } public String fooEvent(...) { return tokens.fooEvent(id, filter); } } /foo?26;all History parameters
  79. History hashbang @Events(...) public interface OneEventBus ... { @Event(...) public

    void fooEvent(int id, Filter filter); } @History public class OneHC implements HistoryConverter<OneEventBus> { ... public boolean isCrawable() { return true; } } /#!foo?26;all
  80. History and event buses are the skeleton of your site

    navigation system History and event buses are the skeleton of your site navigation system
  81. Multi- modularity modules public interface CompanyModule extends Mvp4gModule {} @Events(...,

    module=CompanyModule.class) public interface CompanyEventBus extends EventBus {...} public interface UserModule extends Mvp4gModule {} @Events(..., module=UserModule.class) public interface UserEventBus extends EventBus {...}
  82. @Events(..., module=UserModule.class) public interface UserEventBus extends EventBus { @Event(..., handlers=UserListPresenter.class,

    historyName="list") public void usersList(); . . . } @Events(...) @ChildModules( @ChildModule(moduleClass=UserModule.class) @ChildModule(moduleClass=CompanyModule.class) ) public interface ParentEventBus extends EventBus{ @Event(modulesToLoad=UserModule.class) public void usersList(); @Event(modulesToLoad=CompanyModule.class) public void companiesList(); } Multi- modularity event buses
  83. History, event buses and modules are the skeleton of your

    site navigation system History, event buses and modules are the skeleton of your site navigation system You can load modules asynchronously! So user will not get the kilobytes he needs not, if he will not visit specified sections of your site. You can load modules asynchronously! So user will not get the kilobytes he needs not, if he will not visit specified sections of your site.
  84. PlaceService annotations @Debug @Event @EventHandler @Events @Filters @Forward @History @InitHistory

    @InjectService @NotFoundHistory @PlaceService @Presenter @Service @Start
  85. PlaceService overriding @PlaceService(CustomPlaceService.class) @Events(...) public interface MainEventBus extends EventBusWithLookup {

    . . . } public class CustomPlaceService extends PlaceService { protected void convertToken(String token) { ... } protected String[] parseToken(String token) { ... } public String tokenize(String eventName, String param) { ... } . . . }
  86. Remarks There is no layouting-system yet Multimodularity is aimed at

    object → action principle GIN/Guice are supported
  87. Remarks There is no layouting-system yet Multimodularity is aimed at

    object → action principle When using custom GwtEvents, you should keep an eye on presenters activation. Callbacks — easier. GIN/Guice are supported
  88. Remarks There is no layouting-system yet Multimodularity is aimed at

    object → action principle When using custom GwtEvents, you should keep an eye on presenters activation. Callbacks — easier. There are LazyView & LazyPresenter GIN/Guice are supported
  89. Button PushButton RadioButton CheckBox DatePicker ToggleButton TextBox PasswordTextBox TextArea Hyperlink

    / Anchor ListBox CellList MenuBar Tree, CellTree SuggestBox RichTextArea FlexTable, Grid, CellTable CellBrowser TabBar DialogBox PopupPanel StackPanel, StackLayoutPanel HorizontalPanel VerticalPanel FlowPanel VerticalSplitPanel HorizontalSplitPanel SplitLayoutPanel DockPanel, DockLayoutPanel TabPanel, TabLayoutPanel DisclosurePanel
  90. UiBinder: .ui.xml <ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui"> <g:VerticalPanel styleName="my-css-style"> <g:HorizontalPanel> <g:Label>Name</g:Label> <g:TextBox

    ui:field="nameBox">Babylen</g:TextBox> </g:HorizontalPanel> <g:HorizontalPanel> <g:Label>Family name</g:Label> <g:TextBox ui:field="fnameBox">Tatarsky</g:TextBox> </g:HorizontalPanel> <g:ListBox ui:field="namesLst" visibleItemCount="1" /> <g:Button ui:field="submit">Submit</g:Button> </g:VerticalPanel> </ui:UiBinder>
  91. UiBinder: .java public class SettingsForm extends Composite { interface SFormBinder

    extends UiBinder<Widget, SettingsForm> {} private static FormBinder uiBinder = GWT.create(SFormBinder.class); @UiField TextBox nameBox; @UiField TextBox fnameBox; @UiField ListBox namesLst; public HelloWorld(String... names) { initWidget(uiBinder.createAndBindUi(this)); for (String name : names) { namesLst.addItem(name); } } @UiHandler("submit") public onSubmit(ClickEvent e) { ... } }
  92. HTMLPanel <g:HTMLPanel> <div>Some div</div> <div> <ul> <li>Item 1</li> <li>Item 2</li>

    <li>Item 3</li> </ul> </div> <p> <span>Some span</span> </p> </g:HTMLPanel>
  93. In GWT, there is an entire vast library of components

    and an armory of layouts. Though, the fact of developing a site with its own unique style is fraught with cross-browser compatibility problems.
  94. Custom components Do not inherit, but delegate @UiConstructor public MyCustomWidget(String

    defaultText) { . . . } public void setMaxLength(int maxLength) { ... }
  95. Custom components Do not inherit, but delegate @UiConstructor public MyCustomWidget(String

    defaultText) { initWidget(uiBinder.createAndBindUi(this)); } public void setMaxLength(int maxLength) { ... }
  96. So it is better either to keep your site design

    as simple as possible... ...either to allocate a significant amount of time for UI designers and programmers to work through your own component library. ...either to allocate a significant amount of time for UI designers and programmers to work through your own component library.
  97. Reasons? If your site is built with logical blocks which

    are visually placed in different order, depending on context.
  98. Reasons? If your site is built with logical blocks which

    are visually placed in different order, depending on context. For example, portlets or custom widgets
  99. Reasons? If your site is built with logical blocks which

    are visually placed in different order, depending on context. For example, portlets or custom widgets Means, when it is a flexible site.
  100. Reasons? If your site is built with logical blocks which

    are visually placed in different order, depending on context. For example, portlets or custom widgets Means, when it is a flexible site. These mechanics are not yet implemented in mvp4g
  101. public class LayoutList implements Layout { } LayoutList.ui.xml: <FlowPanel ui:field="a"/>

    <FlowPanel ui:field="b"/> <FlowPanel ui:field="c"/> Layouts LIST ITEM EDIT public enum Place { A, B, C, D}; public interface Layout { public LayoutId id(); public HasWidgets place(Place place); Map<Place, HasWidgets> places(); } public class LayoutItem implements Layout { } LayoutItem.ui.xml: <FlowPanel ui:field="a"/> <FlowPanel ui:field="b"/> <FlowPanel ui:field="c"/> public class LayoutEdit implements Layout { } LayoutEdit.ui.xml: <FlowPanel ui:field="a"/> <FlowPanel ui:field="b"/> <FlowPanel ui:field="c"/> <FlowPanel ui:field="d"/>
  102. public enum Portal implements MakesLink { NEWS_LIST(LayoutId.LIST, <event-spec>, <options>), NEWS_EDIT(LayoutId.EDIT,

    <event-spec>, <options>), NEWS_VIEW(LayoutId.ITEM, <event-spec>, <options>), NEWS_DELETE(LayoutId.ITEM, <event-spec>, <options>) USER_LIST(LayoutId.LIST, <event-spec>, <options>), USER_EDIT(LayoutId.EDIT, <event-spec>, <options>), USER_VIEW(LayoutId.ITEM, <event-spec>, <options>), USER_DELETE(LayoutId.ITEM, <event-spec>, <options>), . . . @Override public String makeLink() { . . . } } Page / Portal
  103. public enum Portal implements MakesLink { . . . public

    class PortalUrl implements MakesLink { PortalUrl(Portal portal[, <params>]) { ... } public PortalUrl addParam(...) { ... } public PortalUrl fromEvent(String module, String event, String params) { ... } @Override public String makeLink() { ... } } } Link
  104. public enum Portal implements MakesLink { . . . public

    class PortalUrl implements MakesLink { PortalUrl(Portal portal[, <params>]) { ... } public PortalUrl addParam(...) { ... } public PortalUrl fromEvent(String module, String event, String params) { ... } @Override public String makeLink() { ... } } } Link History.newItem(Portal.USER_LIST.makeLink()); History.newItem(new PortalUrl(Portal.USER_EDIT, uid).makeLink()); History.newItem(userTokenGenerator.edit(uid));
  105. public abstract class LayoutBuilder<E extends ChildEventBus> { public CanBuildLayout prepareFor(final

    Portal page) { return new CanBuildLayout { public Layout build(State state) { layout(page, state, LayoutFactory.get(page.layout).places()); } } } public abstract void layout(Portal page, State state, Map<Place, HasWidgets> places); } Layout builder
  106. public class UserHistoryConverter implements HistoryConverter<UserEventBus> { public void convertFromToken(String evt,

    String param) { // можно использовать tokenGenerator PortalUrl curUrl = PortalUrl.fromToken("user",evt,param); Portal portal = curUrl.portal; eventBus.newPage(portal, layoutBuilder.prepareFor(portal)); eventBus.dispatch(curUrl); } } Switching layouts
  107. public class UserLayoutBuilder implements LayoutBuilder<UserEventBus> { public void layout(Portal page,

    State state, Map<Place, HasWidgets> places) switch (page) { case USER_ITEM: { eventBus.projectItem(places.get(Place.A)); eventBus.projectCalendar(places.get(Place.B)); eventBus.projectPreview(places.get(Place.C)); } break; case USER_LIST: switch (state) { ... } break; case USER_EDIT: ... break; } } } Builder implementation
  108. public interface ChildEventBus { @Event(forwardToParent=true) public void newPage(Portal page, CanBuildLayout

    builder); @Event(forwardToParent=true) public void project(Widget what, HasWidgets where); @Event(forwardToParent=true) public void updateState(State state) } Event buses [ forwarded to BaseEventBus ]
  109. public interface UserEventBus extends ChildEventBus { // navigation @Event(navigationEvent=true, ...)

    public void list(); @Event(navigationEvent=true, handlers=UserShowPresenter.class, historyConverter=UserHistoryConverter.class) public void show(String uid); @Event(navigationEvent=true, ...) public void edit(String uid); . . . // projection @Event(handlers=UserShowPresenter.class,calledMethod="prjItem") public void projectItem(HasWidgets where); @Event(handlers=UserShowPresenter.class,calledMethod="prjPrvw") public void projectPreview(HasWidgets where); @Event(handlers=CalendarPresenter.class,calledMethod="project") public void projectCalendar(HasWidgets where) } Event buses
  110. Messages / Constants public interface LoginMessages extends Messages { public

    String enterName(); public String emailExists(String email); public String emailInvalid(String email); public String loginFailed(String username); public String youFailedNTimes(@PluralCount int times); } public interface MenuConstants extends Constants { public String login(); public String logout(); public String contacts(); public String settings(); }
  111. LoginMessages_ru.properties enterName = Введите имя emailExists = E-mail {0} зарегистрирован

    в системе emailInvalid = Некорректный e-mail {0} loginFailed = Не удалось зайти пользователем {0} youFailedNTimes = Кол-во неудачных попыток: {0,number} youFailedNTimes[one] = {0,number} неудачная попытка youFailedNTimes[few] = {0,number} неудачных попыток MenuConstants_ru.properties login= Войти logout = Выйти contacts = Контакты settings = Настройки Messages / Constants
  112. <e:MyTextBox ui:field="box" defaultText="{messages.enterText}" LoginMessages messages = GWT.create(LoginMessages.class); MenuConstants constants =

    GWT.create(MenuConstants.class); <ui:with type="....LoginMessages" field="messages" /> Messages / Constants
  113. ErrorsConstants_ru.properties ERR_101 = Ошибка авторизации ERR_102 = Неизвестная ошибка ERR_103

    = Ресурс не найден errors = ERR_101, ERR_102, ERR_103 public interface ErrorsConstants extends ConstantsWithLookup { Map<String, String> errors(); } Messages / Constants
  114. Mae'n hawdd iawn i gyfieithu prosiectau GWT... Mae'n hawdd iawn

    i gyfieithu prosiectau GWT... ...if you'll teach your translators to manage .properties-files or give them PoEdit or Pootle ...if you'll teach your translators to manage .properties-files or give them PoEdit or Pootle
  115. Thanks to Vitaly Gashock, for intoducing mvp4g to me and

    partnership Mikhail Kashkin, for mentoring http://www.vurt.ru http://twitter.com/vgashock Alexey Kakunin, for 道 and 先生 http://www.emdev.ru
  116. Philip J. Fry, Dr. Zoidber, Nibbler and Hypnotoad are all

    the Futurama series characters and all created by Matt Groening Homer Simpson is the character of The Simpsons series and also created by Matt Groening All the phrases they tell in this presentation have no relation nor for these characters, nor for series noticed above, nor for their creator