web-development using

GWT + mvp4g
Anthony Kotenko, iPark ventures™ 2011 ©

This presentation was specially prepared for Application Developer Days 2011
Saint-Petersburg, Russia

Slides — there

goo.gl/4GgnS
[ PDF, ~2MB ]

Anthony Kotenko
6 years in Java EE development 6 years in UI development Sex: male

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

Schedule

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

4. Components in GWT - UiBinder, standard components - custom widgets development 5. Our layouting system development 6. Working with non-Java Server-Side-API (versus RPC-services) - making call chains - callback vs. GwtEvent - advantages / disadvantages 7. i18n in GWT 8. Conclusion. Links to the examples

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:

I have a question!

Discussion is important

1. Briefly 'bout GWT

GWT

Google Web Toolkit

/ˈɡwɪt/
code.google.com/webtoolkit/

GWT
/ˈɡwɪt/

/ˈɡwɪt/

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

Used in these projects:
GoGrid gogrid.com Curriki curriki.org OpenKM openkm.com Kdice kdice.com SeeMap seemap.ru Одноклассники odnoklassniki.ru

A box of useful tools

The most complete A box of useful tools

for web-developer

widgets

http://old.ongwt.com/public/WindowsLiveWriter_GWTMosaicnicewidgetlibrary_D777_image_2.png

widgets

optimization

http://radar.oreilly.com/200912081729.jpg

widgets

optimization

cross-browserly!

http://2.bp.blogspot.com/_VzXmgKXrn6Y/TKB2a3eZTBI/AAAAAAAAAaQ/mn7NmabwO8U/s1600/browsers%5Btsksoft.blogspot.com%5D.jpg

widgets

optimization

cross-browserly! on-the-fly development

http://lh4.ggpht.com/_a0imbbK4r5U/Sxwd1oVpXiI/AAAAAAAAAjc/gsRkQUn9kZI/gwt-dev-mode.png

widgets

optimization

cross-browserly! on-the-fly development
OOP benefits

widgets

optimization

cross-browserly! on-the-fly development
OOP benefits

debug

http://www.ibm.com/developerworks/library/j-ajax4/eclipse-debug.jpg

widgets

optimization

cross-browserly! on-the-fly development
OOP benefits

debug

RPC

API/DB

widgets

optimization

cross-browserly! on-the-fly development
OOP benefits

debug

RPC

simple i18n
http://test.ical.ly/wp-content/uploads/2010/04/i18n.png

widgets

optimization

cross-browserly! on-the-fly development
OOP benefits

debug

RPC

simple i18n

Code Splitting

widgets

optimization

cross-browserly! on-the-fly development
OOP benefits

debug

RPC

simple i18n

Code Splitting

http://www.safetylca.org/images/toolbox.jpg

http://blog.ericlamb.net/wp-content/uploads/2009/08/toolbox.jpg http://www.safetylca.org/images/toolbox.jpg

GWT is a box of useful tools

/ˈɡwɪt/

History

Version 1.0 was released in 2006

Version 1.0 was released in 2006
Version 1.6 Google Eclipse Plugin Project structure matches Web Application specification

Version 2.0
- Development Mode - Code Splitting - Declarative UI - Client Bundle

Version 2.1 MVP-conception RequestFactory / Editors

Version 2.1 MVP-conception RequestFactory / Editors Version 2.2 UI Designer HTML5 Canvas support only Java 1.6 was left

quake2-gwt-port.appspot.com

Quake 2 in browser

https://y2mzuw.blu.livefilestore.com/y1m9Pc7Xi6qtMdKU_hGCv7VZrEKiIZTYqDIC5laL9A0LxracK6AN8EAet90MRtWlBJISphNp_Y8QCxpb0p9v1y lTCdwATCweUs9496DC14_ijBjhnpj2oRWme9B1SC2C0t9HJ1wX8RTsVQAhyDYCsqfeg/quake-html5-04-02-2010.jpg

quake2-gwt-port.appspot.com

Quake 2 in browser

Trendy Youth Modern

GWT is actively developing project, however it already contains everything you need

/ˈɡwɪt/

2. GWT Conceptions

almaer.com/blog/rotating-java-and-javascript-on-the-server

EntryPoint
Any GWT-project starts from entry point

Java → JavaScript, JSNI ● Development Mode ● Code Splitting ● <Module>.gwt.xml ● MVC, MVP, RMVP, EventBus ● Deferred Binding ● Dependency Injection ● Remote Service ● JUnit ● Disadvantages and remarks

JavaScript Logo is from marakana.com

JavaScript Native Interface

JSNI

public native static void <functionName>(<parameters>) /*-{ . . . @<path.to.the.package>.<ClassName>::<methodName>( /L<param-type>;/L<param-type>;...)(<arguments>); . . . }-*/;

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) { handler.@com.google.gwt.sample.stockwatcher .client.StockWatcher::handleJsonResponse( Lcom/google/gwt/core/client/JavaScriptObject;)(jsonObj); window[callback + "done"] = true; } setTimeout(function() { if (!window[callback + "done"]) { handler.@com.google.gwt.sample.stockwatcher .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); }-*/;

JSNI

You can wrap native JavaScript widgets with JSNI. For example, Google Maps or any WYSIWYG-editor

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

JSNI

You can use JSNI to make third-party components written in JavaScript become GWT-widgets

Development Mode

Development Mode
http://lc:8080/ui/?gwt.codesvr=lc:9997#!job/start

Development Mode
http://lc:8080/ui/?gwt.codesvr=lc:9997#!job/start the plugin for your lovely IDE the plugin for your lovely browser
(but not for Opera)

Development Mode
http://lc:8080/ui/?gwt.codesvr=lc:9997#!job/start

http://lh4.ggpht.com/_a0imbbK4r5U/Sxwd1oVpXiI/AAAAAAAAAjc/gsRkQUn9kZI/gwt-dev-mode.png

Development Mode
http://lc:8080/ui/?gwt.codesvr=lc:9997#!job/start

http://lh4.ggpht.com/_a0imbbK4r5U/Sxwd1oVpXiI/AAAAAAAAAjc/gsRkQUn9kZI/gwt-dev-mode.png

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!

Code Splitting

when the neccessary code was loaded

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

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

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

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!

<Module>.gwt.xml

<Module>.gwt.xml
⁕ Components a list of code components you use

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

<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

<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

<Module>.gwt.xml
⁕ Components <inherits name="com.google.gwt.user.User"/> ⁕ Browsers

⁕ Locales

⁕ Debug

<Module>.gwt.xml
⁕ Components <inherits name="com.google.gwt.user.User"/> ⁕ Browsers <set-property name="user.agent" value="ie6,gecko1_8,safari" /> ⁕ Locales

⁕ Debug

<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>.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]

<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" />

<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" />

.gwt.xml file — is almost the same thing as web.xml file for web application: here lies all of the project configuration

R M V P

Model View Controller

Model View Controller
API/DB

Model View Controller
calls

Model View Presenter

Model View Presenter
events

update

Reverse Model View Presenter

Reverse Model View Presenter

Presenter
Event Bus

er

Presenter Pre
Event Bus

P

P
EB

P P P P P

Hmmm... To be honest, seems I did not understand the difference between all those mah-fah-am-wee-pee...

Difference between MVC and MVP

geekswithblogs.net/kobush/archive/2006/01/09/65305.aspx

The article about MVC/MVP difference

geekswithblogs.net/kobush/archive/2006/01/09/65305.aspx

The video with the example of EventBus in work

tv.jetbrains.net/videocontent/gwt-event-bus-basics

The video with the example of EventBus in work

tv.jetbrains.net/videocontent/gwt-event-bus-basics

EventBus is the central communication channel

Deferred Binding

Deferred Binding
In response to the lack of Reflection

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

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

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

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

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);

}

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'; } }-*/;

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>

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);

Slides on Deferred Binding

www.docstoc.com/docs/53396874/Deferred-Binding-The-Magic-of-GWT

Slides on Deferred Binding

www.docstoc.com/docs/53396874/Deferred-Binding-The-Magic-of-GWT

Deferred Binding is a tool to create cross-browser and translingual implementations. Namely for techniques that will differ between contexts of project usage.

★ Attention ★

Attention!

Dependency Injection

Dependency Injection
Using GWT INjection / Guice frameworks

Dependency Injection
Using GWT INjection / Guice frameworks Binding instances to interfaces at one point (thus we achieve separation of behavior from implementing solution)

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

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

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

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) { }

}

Dependency Injection
@GinModules(MyModule.class) interface class MyGinjector extends Ginjector { public Something getSomething(); public Foo getFoo(); }

Guice wiki-pages

code.google.com/p/google-guice/wiki/Motivation?tm=6

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!

Remote Service

Remote Service
public interface StringReverserService extends RemoteService { public String reverseString(String stringToReverse); }

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

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 { . . . }

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);

Tutorial on creating Remote Services

developerlife.com/tutorials/?p=125

Remote Services is server-side API built using Java interfaces

JUnit

JUnit
public class StockWatcherTest extends GWTTestCase { public String getModuleName() { return "com.google.gwt.sample.stockwatcher.StockWatcher"; } . . . }

JUnit
public class StockWatcherTest extends GWTTestCase { . . . FooPresenter.IFooView fooView = Mockito.mock(FooPresenter.IFooView.class); ... = new FooPresenter(..., fooView); Mockito.verify(fooView).someViewMethod(...);

}

GWT-code is easy to test because of JUnit support

Deficiencies and observations
Anyway, you need good skills in JavaScript

Deficiencies and observations
Anyway, you need good skills in JavaScript Especially when using external JS-libraries

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

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

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

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

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)

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

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 One JS-error crashes the whole application

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 One JS-error crashes the whole application However, we have GWT.setUncaughtExceptionHandler

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 One JS-error crashes the whole application However, we have GWT.setUncaughtExceptionHandler JavaScript-errors provide little information

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 One JS-error crashes the whole application However, we have GWT.setUncaughtExceptionHandler JavaScript-errors provide little information Although, they are for sure much easier to understand when debug info is on

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 One JS-error crashes the whole application However, we have GWT.setUncaughtExceptionHandler JavaScript-errors provide little information Although, they are for sure much easier to understand when debug info is on Development Mode works slower than real code: so you may encounter problems in events succession

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 One JS-error crashes the whole application However, we have GWT.setUncaughtExceptionHandler JavaScript-errors provide little information Although, they are for sure much easier to understand when debug info is on 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?!

Deficiencies and observations
Regular expressions are just a wrapper for JavaScript RegExp
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 One JS-error crashes the whole application However, we have GWT.setUncaughtExceptionHandler JavaScript-errors provide little information Although, they are for sure much easier to understand when debug info is on 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?!

Deficiencies and observations
Regular expressions are just a wrapper for JavaScript RegExp
Anyway, you need good skills in JavaScript «Manual» makeup (HTMLPanel) becomes not sustainable and has no cross-browser compatibility

No guidance at non-Java Server-Side (Python & GAE, for example)

One JS-error crashes the whole application JavaScript-errors provide little information

Development Mode works slower than real code: so you may encounter problems in events succession

Deficiencies and observations
Regular expressions are just a wrapper for JavaScript RegExp
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 One JS-error crashes the whole application However, we have GWT.setUncaughtExceptionHandler JavaScript-errors provide little information Although, they are for sure much easier to understand when debug info is on 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?!

Here GWT drawbacks are discussed

www.linux.org.ru/forum/talks/4497412

Every reasoned weakness in GWT have a rational solution.

Summary on GWT-code optimization

galak-sandbox.blogspot.com/2010/10/gwt.html

And I would ask for a beer now!

3. mvp4g

mvp4g framework web-page

code.google.com/p/mvp4g/

● ● ● ● ● ● ● ●

What helps? Annotation system RMVP realization EventBus realization URL, HistoryConverters, #! Multimodularity PlaceService Remarks

mvp4g framework helps to

mvp4g framework helps to
work with (R)MVP

mvp4g framework helps to
work with (R)MVP organize multi-modular applications

mvp4g framework helps to
work with (R)MVP organize multi-modular applications design and develop events buses

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

mvp4g framework helps to
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
work with (R)MVP organize multi-modular applications design and develop events buses work with history (incl. hashbangs #!)

... also constantly being improved

mvp4g framework showcase

mvp4gshowcase.appspot.com

mvp4g framework showcase

mvp4gshowcase.appspot.com

Comparison of code written with mvp4g or native GWT

code.google.com/p/mvp4g/wiki/Mvp4g_vs_GWTP

Comparison of code written with mvp4g or native GWT

code.google.com/p/mvp4g/wiki/Mvp4g_vs_GWTP

Pierre-Laurent Coirier plcoirier@gmail.com

Pierre-Laurent Coirier plcoirier@gmail.com
(meet him at Google I/O '11)

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. Code is written by human. It is better to help him sometimes. It is better to help him sometimes.

Annotations

Annotations

@Debug @Event @EventHandler @Events @Filters @Forward @History @InitHistory @InjectService @NotFoundHistory @PlaceService @Presenter @Service @Start

There is Annotation Processor Factory (annotation validator that applies just when you edit the source code)

Annotations

Annotations — the power of mvp4g! Annotations — the power of mvp4g!

RMVP

RMVP
annotations

@Debug @Event @EventHandler @Events @Filters @Forward @History @InitHistory @InjectService @NotFoundHistory @PlaceService @Presenter @Service @Start

@Presenter(view=OneView.class) public class OnePresenter extends BasePresenter<IOneView, OneEventBus> {

RMVP
presenter

@Inject private ServiceAsync service; }

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

RMVP
view

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

RMVP
reverse

EventBus

EventBus
annotations

@Debug @Event @EventHandler @Events @Filters @Forward @History @InitHistory @InjectService @NotFoundHistory @PlaceService @Presenter @Service @Start

@Events(startView = StartView.class) public interface OneEventBus extends EventBus {

EventBus
events
}

@Event public void fooEvent(...); @Event public void barEvent(...);

@Events(startView = StartView.class) public interface OneEventBus extends EventBus {

EventBus
handlers
}

@Event(handlers={FooPresenter.class, AcmePresenter.class}) public void fooEvent(...); @Event(handlers=BarPresenter.class) public void barEvent(...);

FooPresenter::onFooEvent(...) {...} FooPresenter::onFooEvent(...) {...} BarPresenter::onBarEvent(...) {...}

@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(...); }

EventBus
activation

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(...) {...}; }

@Filters(filterClasses={FilterOne.class, FilterTwo.class}) @Debug(logger=CustomLogger.class) @Events(startView = StartView.class) public interface OneEventBus extends EventBus { . . . }

EventBus
filters and stuff
class FilterOne implements EventFilter<OneEventBus> { @Override public boolean filterEvent(...) { return ...; } }

History

History
annotations

@Debug @Event @EventHandler @Events @Filters @Forward @History @InitHistory @InjectService @NotFoundHistory @PlaceService @Presenter @Service @Start

@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(); }

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(); }

History
passing
/foo

/start

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

/foo?26;all

History

parameters

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); }

}

@Events(...) public interface OneEventBus ... {

/#!foo?26;all
}

@Event(...) public void fooEvent(int id, Filter filter);

History
hashbang

@History public class OneHC implements HistoryConverter<OneEventBus> { ... public boolean isCrawable() { return true; } }

History and event buses are the skeleton History and event buses are the skeleton of your site navigation system of your site navigation system

Multimodularity

Multimodularity
annotations

@AfterLoadChildModule @BeforeLoadChildModule @ChildModule @ChildModules @DisplayChildModuleView @HistoryName @LoadChildModuleErrors

REST

Multimodularity
URLs

object/action[?parameters] company/list company/add company/edit?123 user/list user/add user/edit?39

public interface UserModule extends Mvp4gModule {} public interface CompanyModule extends Mvp4gModule {}

Multimodularity
modules
@Events(..., module=CompanyModule.class) public interface CompanyEventBus extends EventBus {...} @Events(..., module=UserModule.class) public interface UserEventBus extends EventBus {...}

@Events(...) @ChildModules( @ChildModule(moduleClass=UserModule.class) @ChildModule(moduleClass=CompanyModule.class) ) public interface ParentEventBus extends EventBus{ @Event(modulesToLoad=UserModule.class) public void usersList();

Multimodularity
}

@Event(modulesToLoad=CompanyModule.class) public void companiesList();

event buses

@Events(..., module=UserModule.class) public interface UserEventBus extends EventBus { @Event(..., handlers=UserListPresenter.class, historyName="list") public void usersList(); . . .

}

Multimodularity
asynchronous loading

@Events(...) @ChildModules( @ChildModule(moduleClass= UserModule.class, runAsync=true) @ChildModule(moduleClass= CompanyModule.class, runAsync=true)) public interface ParentEventBus extends EventBus { . . . }

History, event buses and modules are the skeleton History, event buses and modules are the skeleton of your site navigation system of your site navigation system

You can load modules asynchronously! You can load modules asynchronously! So user will not get the kilobytes So user will not get the kilobytes he needs not, if he will not visit he needs not, if he will not visit specified sections of your site. specified sections of your site.

PlaceService

PlaceService
annotations

@Debug @Event @EventHandler @Events @Filters @Forward @History @InitHistory @InjectService @NotFoundHistory @PlaceService @Presenter @Service @Start

@PlaceService(CustomPlaceService.class) @Events(...) public interface MainEventBus extends EventBusWithLookup { . . . }

PlaceService
overriding
public class CustomPlaceService extends PlaceService { protected void convertToken(String token) { ... } protected String[] parseToken(String token) { ... } public String tokenize(String eventName, String param) { ... } . . . }

Remarks

There is no layouting-system yet

Remarks

There is no layouting-system yet Multimodularity is aimed at object → action principle

Remarks

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

Remarks

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

Remarks
When using custom GwtEvents, you should keep an eye on presenters activation. Callbacks — easier.

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

Remarks
When using custom GwtEvents, you should keep an eye on presenters activation. Callbacks — easier. There are LazyView & LazyPresenter

mvp4g — is what Zoidberg has prescribed!

4. UI components

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

GWT components library

code.google.com/webtoolkit/doc/latest/RefWidgetGallery.html

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>

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) { ... } }

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>

Attention!
.b-popup { position: absolute; }

Manual make-up vs. Cross-browser support

.gwt-Button { font-size: 150%; }

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.

Custom components

Custom components
Do not inherit, but delegate

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

Custom components
Do not inherit, but delegate
@UiConstructor public MyCustomWidget(String defaultText) { initWidget(uiBinder.createAndBindUi(this)); } public void setMaxLength(int maxLength) { ... }

Attention!

Customization vs. Cross-browser support

So it is better either to keep your site design as simple as possible...

...either to allocate ...either to allocate a significant amount of time a significant amount of time for UI designers and programmers for UI designers and programmers to work through your own to work through your own component library. component library.

The lack of UI Designer was a drawback for someone

The lack of UI Designer was a drawback for someone

5. Layouting

Reasons?

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

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

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.

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

Layouts
LIST
B C A C B

ITEM

EDIT
B A D C

A

Layouts
LIST
public class LayoutList implements Layout { } LayoutList.ui.xml: <FlowPanel ui:field="a"/> <FlowPanel ui:field="b"/> <FlowPanel ui:field="c"/>

public interface Layout { public LayoutId id(); public HasWidgets place(Place place); Map<Place, HasWidgets> places(); }

ITEM

EDIT
public class LayoutEdit implements Layout { } LayoutEdit.ui.xml: <FlowPanel ui:field="a"/> <FlowPanel ui:field="b"/> <FlowPanel ui:field="c"/> <FlowPanel ui:field="d"/>

public class LayoutItem implements Layout { } LayoutItem.ui.xml: <FlowPanel ui:field="a"/> <FlowPanel ui:field="b"/> <FlowPanel ui:field="c"/>

public enum Place { A, B, C, D};

Layouts
LIST
B C A C B

ITEM

EDIT
B A D C

A

Base page
toolbar layout

footer

copy

BasePage.ui.xml: <FlowPanel ui:field="toolbar"/> <FlowPanel ui:field="layout"/> <FlowPanel ui:field="footer"/> <FlowPanel ui:field="copy"/>

Page / Portal
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() { . . . } }

Link
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
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() { ... } } }
History.newItem(Portal.USER_LIST.makeLink()); History.newItem(new PortalUrl(Portal.USER_EDIT, uid).makeLink()); History.newItem(userTokenGenerator.edit(uid));

Layout builder
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); }

Switching layouts
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); } }

Builder implementation
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; } } }

Event buses
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) }

[ forwarded to BaseEventBus ]

Event buses
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) }

Layouting helps us to build and to live!

I've wanted to make a demo for you, but had no time ;(

github.com/shamansir/gwt-mvp4g-layouting-demo

I've wanted to make a demo for you, but had no time ;(

Follow

github.com/shamansir/gwt-mvp4g-layouting-demo

I've wanted to make a demo for you, but had no time ;(

github.com/shamansir/gwt-mvp4g-layouting-demo

Фото gwt-mvp4g-layouting-demo.appspot.com

QRCode gwt-mvp4g-layouting-demo.appspot.com

6. Non-Java API

Accidentally, here is the main point

code.google.com/p/google-web-toolkit-doc-1-5/wiki/GettingStartedJSON

Possibility — exists

RequestBuilder

General context

Call chains

Insering JS-object into HTML-markup

(you can parse them using JSNI)

Advantage : Independence from serialization

Disadvantage : Unconventional approach with all the consequences

And here is the source code

shamansir-ru.tumblr.com/post/1728720550/deferred-api-gwt-rpc

7. i18n

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(); }

Messages / Constants
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

LoginMessages messages = GWT.create(LoginMessages.class); MenuConstants constants = GWT.create(MenuConstants.class);

<ui:with type="....LoginMessages" field="messages" /> <e:MyTextBox ui:field="box" defaultText="{messages.enterText}"

Messages / Constants

<ui:UiBinder

... xmlns:txt="ui:with:...MyMessages" />

<txt:msg key="messageKey">Message</txt:msg>

Messages / Constants
public interface ErrorsConstants extends ConstantsWithLookup { Map<String, String> errors(); }

ErrorsConstants_ru.properties ERR_101 = Ошибка авторизации ERR_102 = Неизвестная ошибка ERR_103 = Ресурс не найден errors = ERR_101, ERR_102, ERR_103

Mae'n hawdd iawn ii Mae'n hawdd iawn gyfieithu prosiectau GWT... gyfieithu prosiectau GWT...

...if you'll teach your ...if you'll teach your translators to manage translators to manage .properties-files or give .properties-files or give them PoEdit or Pootle them PoEdit or Pootle

Позволяют использовать локализованные ресурсы

ResourceBundles

8. Conclusion

We applied those techniques for Experika

experika.com

Welcome to Experika

experika.com

Thanks to
Vitaly Gashock, for intoducing mvp4g to me and partnership http://twitter.com/vgashock Mikhail Kashkin, for mentoring http://www.vurt.ru Alexey Kakunin, for 道 and 先生 http://www.emdev.ru

Anthony Kotenko

profiles.google.com/shaman.sir

Thank you.

Made with LibreOffice 3.3.1 Impress

More questions?

GWT FTW!

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

Master your semester with Scribd & The New York Times

Special offer for students: Only $4.99/month.

Master your semester with Scribd & The New York Times

Cancel anytime.