Web-Development Using GWT + mvp4g

Preview:

DESCRIPTION

Slides for the lecture at ADDConf (http://addconf.ru) 2011

Citation preview

GWT + mvp4g

Anthony Kotenko, iPark ventures™2011 ©

web-development using

This presentation was specially prepared forApplication Developer Days 2011

Saint-Petersburg, Russia

goo.gl/4GgnS

Slides — there

[ PDF, ~2MB ]

Anthony Kotenko6 years in Java EE development

6 years in UI development

Sex: male

Anthony Kotenko6 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

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

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!

1. Briefly 'bout GWT

GWT

code.google.com/webtoolkit/

GoogleWebToolkit

/ˈɡwɪt/

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

A box of useful toolsThe most complete

for web-developer

widgets

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

widgetsoptimization

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

widgets

cross-browserly!optimization

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

widgets

cross-browserly!

on-the-fly development

optimization

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

widgets

cross-browserly!

on-the-fly development

optimization

OOP benefits

widgets

cross-browserly!

on-the-fly development

optimization

OOP benefits debug

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

widgets

cross-browserly!

on-the-fly development

optimization

OOP benefits debug

RPCAPI/DB

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

widgets

cross-browserly!

simple i18n

on-the-fly development

optimization

OOP benefits

Code Splitting

debug

RPC

widgets

cross-browserly!

simple i18n

on-the-fly development

optimization

OOP benefits

Code Splitting

debug

RPC

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

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

GWT is a box of useful tools/ˈɡwɪt/

History

Version 1.0was released in 2006

Version 1.0was released in 2006

Version 1.6Google Eclipse Plugin

Project structure matchesWeb 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

Quake 2 in browser

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

quake2-gwt-port.appspot.com

Quake 2 in browserquake2-gwt-port.appspot.com

TrendyYouth

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

Any GWT-project starts from entry point

EntryPoint

● 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

JSNI

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 JSNIGoogle Maps widget,

integrated with the help of JSNI

Flash-objectusing JavaScript-callbacks,

which are called through JSNI

You can use JSNI tomake third-party components

written in JavaScriptbecome GWT-widgets

Development Mode

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

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

(but not for Opera)the plugin for your lovely browser

the plugin for your lovely IDE

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

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

Development Modehttp://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 Splittingpublic 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

MVP

R

ModelViewController

ModelViewController

API/DB

ModelViewController

calls

ModelViewPresenter

ModelViewPresenter

events

upda

te

ModelViewPresenter

Reverse

ModelViewPresenter

Reverse

PresenterEvent Bus

PresenterEvent Bus

PresenterPresenter

PEB

PP P P P P

Hmmm... To be honest, seems I did not understand the difference

between all those mah-fah-am-wee-pee...

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

Difference between MVC and MVP

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

The article about MVC/MVP difference

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

The video with the example of EventBus in work

EventBus is the central communication channel

Deferred Binding

Deferred Binding

In response to the lack of Reflection

Deferred Binding

Dynamic implementation of any interface (and just in case if it is actually required)

In response to the lack of Reflection

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

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

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

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

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

Slides on Deferred Binding

Deferred Binding is a tool to create cross-browserand translingual implementations.

Namely for techniques that will differ betweencontexts of project usage.

★ Attention ★Attention!

Dependency Injection

Dependency Injection

Using GWT INjection / Guice frameworks

Dependency Injection

Binding instances to interfaces at one point (thus we achieve separation of behaviorfrom implementing solution)

Using GWT INjection / Guice frameworks

Dependency Injection

Lets you forget about XML-settings andfactories

Binding instances to interfaces at one point(thus we achieve separation of behaviorfrom implementing solution)

Using GWT INjection / Guice frameworks

Dependency Injection

Lets you forget about XML-settings andfactories

Binding instances to interfaces at one point(thus we achieve separation of behaviorfrom implementing solution)

Runtime-binding

Using GWT INjection / Guice frameworks

Dependency Injection

Lets you forget about XML-settings andfactories

Binding instances to interfaces at one point (thus we achieve separation of behaviorfrom implementing solution)

Runtime-binding

Using GWT INjection / Guice frameworks

Dependency Injectionclass 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();

}

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

Guice wiki-pages

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

developerlife.com/tutorials/?p=125

Tutorial on creating Remote Services

Remote Services is server-side APIbuilt using Java interfaces

JUnit

JUnitpublic class StockWatcherTest extends GWTTestCase {

public String getModuleName() { return "com.google.gwt.sample.stockwatcher.StockWatcher"; } . . .

}

JUnitpublic class StockWatcherTest extends GWTTestCase {

. . .

FooPresenter.IFooView fooView = Mockito.mock(FooPresenter.IFooView.class); ... = new FooPresenter(..., fooView); Mockito.verify(fooView).someViewMethod(...);}

GWT-code is easy to testbecause of JUnit support

Deficiencies and observations

Anyway, you need good skills in JavaScript

Deficiencies and observations

Anyway, you need good skills in JavaScriptEspecially when using external JS-libraries

Deficiencies and observations

Anyway, you need good skills in JavaScriptEspecially 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 JavaScriptEspecially when using external JS-libraries

«Manual» makeup (HTMLPanel) becomes not sustainable and has no cross-browser compatibilityGWT is for web-applications, but not pretentious portals

Deficiencies and observations

Anyway, you need good skills in JavaScriptEspecially when using external JS-libraries

«Manual» makeup (HTMLPanel) becomes not sustainable and has no cross-browser compatibilityGWT is for web-applications, but not pretentious portalsYou 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 JavaScriptEspecially when using external JS-libraries

«Manual» makeup (HTMLPanel) becomes not sustainable and has no cross-browser compatibilityGWT is for web-applications, but not pretentious portalsYou can write your own (or extend existing) components, but then thinking about cross-browser compatibility is your concernAnd 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 JavaScriptEspecially when using external JS-libraries

«Manual» makeup (HTMLPanel) becomes not sustainable and has no cross-browser compatibilityGWT is for web-applications, but not pretentious portalsYou can write your own (or extend existing) components, but then thinking about cross-browser compatibility is your concernAnd 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 JavaScriptEspecially when using external JS-libraries

«Manual» makeup (HTMLPanel) becomes not sustainable and has no cross-browser compatibilityGWT is for web-applications, but not pretentious portalsYou can write your own (or extend existing) components, but then thinking about cross-browser compatibility is your concernAnd 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 JavaScriptEspecially when using external JS-libraries

One JS-error crashes the whole application

«Manual» makeup (HTMLPanel) becomes not sustainable and has no cross-browser compatibilityGWT is for web-applications, but not pretentious portalsYou can write your own (or extend existing) components, but then thinking about cross-browser compatibility is your concernAnd 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 JavaScriptEspecially when using external JS-libraries

One JS-error crashes the whole applicationHowever, we have GWT.setUncaughtExceptionHandler

«Manual» makeup (HTMLPanel) becomes not sustainable and has no cross-browser compatibilityGWT is for web-applications, but not pretentious portalsYou can write your own (or extend existing) components, but then thinking about cross-browser compatibility is your concernAnd 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 JavaScriptEspecially when using external JS-libraries

One JS-error crashes the whole applicationHowever, we have GWT.setUncaughtExceptionHandler

«Manual» makeup (HTMLPanel) becomes not sustainable and has no cross-browser compatibilityGWT is for web-applications, but not pretentious portalsYou can write your own (or extend existing) components, but then thinking about cross-browser compatibility is your concernAnd 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

Deficiencies and observations

Anyway, you need good skills in JavaScriptEspecially when using external JS-libraries

One JS-error crashes the whole applicationHowever, we have GWT.setUncaughtExceptionHandler

«Manual» makeup (HTMLPanel) becomes not sustainable and has no cross-browser compatibilityGWT is for web-applications, but not pretentious portalsYou can write your own (or extend existing) components, but then thinking about cross-browser compatibility is your concernAnd 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 informationAlthough, they are for sure much easier to understand when debug info is on

Deficiencies and observations

Anyway, you need good skills in JavaScriptEspecially when using external JS-libraries

One JS-error crashes the whole applicationHowever, we have GWT.setUncaughtExceptionHandler

«Manual» makeup (HTMLPanel) becomes not sustainable and has no cross-browser compatibilityGWT is for web-applications, but not pretentious portalsYou can write your own (or extend existing) components, but then thinking about cross-browser compatibility is your concernAnd 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 informationAlthough, they are for sure much easier to understand when debug info is on

Deficiencies and observations

Anyway, you need good skills in JavaScriptEspecially when using external JS-libraries

One JS-error crashes the whole applicationHowever, we have GWT.setUncaughtExceptionHandler

«Manual» makeup (HTMLPanel) becomes not sustainable and has no cross-browser compatibilityGWT is for web-applications, but not pretentious portalsYou can write your own (or extend existing) components, but then thinking about cross-browser compatibility is your concernAnd 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 informationAlthough, they are for sure much easier to understand when debug info is on

Deficiencies and observations

Anyway, you need good skills in JavaScriptEspecially when using external JS-libraries

One JS-error crashes the whole applicationHowever, we have GWT.setUncaughtExceptionHandler

«Manual» makeup (HTMLPanel) becomes not sustainable and has no cross-browser compatibilityGWT is for web-applications, but not pretentious portalsYou can write your own (or extend existing) components, but then thinking about cross-browser compatibility is your concernAnd 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 informationAlthough, they are for sure much easier to understand when debug info is on

Regu

lar

expr

essi

ons

a re

just

a w

rapp

e r f

or Ja

vaSc

r ipt

RegExp

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

Regu

lar

expr

essi

ons

a re

just

a w

rapp

e r f

or Ja

vaSc

r ipt

RegExp

Deficiencies and observations

Anyway, you need good skills in JavaScriptEspecially when using external JS-libraries

One JS-error crashes the whole applicationHowever, we have GWT.setUncaughtExceptionHandler

«Manual» makeup (HTMLPanel) becomes not sustainable and has no cross-browser compatibilityGWT is for web-applications, but not pretentious portalsYou can write your own (or extend existing) components, but then thinking about cross-browser compatibility is your concernAnd 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 informationAlthough, they are for sure much easier to understand when debug info is on

Regu

lar

expr

essi

ons

a re

just

a w

rapp

e r f

or Ja

vaSc

r ipt

RegExp

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

Here GWT drawbacks are discussed

Every reasoned weakness in GWT have a rational solution.

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

Summary on GWT-code optimization

And I would ask for a beer now!

3. mvp4g

code.google.com/p/mvp4g/

mvp4g framework web-page

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

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 helps to

mvp4gshowcase.appspot.com

mvp4g framework showcase

mvp4gshowcase.appspot.com

mvp4g framework showcase

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

Comparison of code written with mvp4g or native GWT

Pierre-Laurent Coirierplcoirier@gmail.com

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

The code you write using mvp4gframework is much simpler thanGWT-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.

Annotations

Annotations

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

Annotations

There is Annotation Processor Factory(annotation validator that applies

just when you edit the source code)

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

RMVP

RMVPannotations

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

RMVPpresenter

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

RMVPview

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

class OneView extends Composite implements IOneView { . . .}

RMVPreverse

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

class OneView extends Composite implements IOneView, ReverseViewInterface<OnePresenter> { . . .}

EventBus

EventBusannotations

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

EventBusevents

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

@Event public void fooEvent(...);

@Event public void barEvent(...);

}

EventBushandlers

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

EventBusactivation

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

}

EventBusbroadcast

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

EventBusfilters 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 ...; }

}

History

Historyannotations

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

Historyhandling

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

}

@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

Historypassing

@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

Historyparameters

Historyhashbang

@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

History and event buses are the skeletonof your site navigation system

History and event buses are the skeletonof your site navigation system

Multi-modularity

Multi-modularityannotations

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

Multi-modularityURLs

company/listcompany/addcompany/edit?123user/listuser/adduser/edit?39

object/action[?parameters]

REST

Multi-modularitymodules

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

@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-modularityevent buses

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

. . .

}

Multi-modularityasynchronousloading

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

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

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

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

PlaceService

PlaceServiceannotations

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

PlaceServiceoverriding

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

Remarks

Remarks

There is no layouting-system yet

Remarks

There is no layouting-system yet

Multimodularity is aimedat object → action principle

Remarks

There is no layouting-system yet

Multimodularity is aimedat object → action principle

GIN/Guice are supported

Remarks

There is no layouting-system yet

Multimodularity is aimedat object → action principle

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

GIN/Guice are supported

Remarks

There is no layouting-system yet

Multimodularity is aimedat 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

mvp4g — is what Zoidberg has prescribed!

4. UI components

ButtonPushButtonRadioButtonCheckBoxDatePickerToggleButtonTextBoxPasswordTextBoxTextAreaHyperlink / AnchorListBoxCellListMenuBarTree, CellTreeSuggestBoxRichTextAreaFlexTable, Grid, CellTableCellBrowserTabBarDialogBox

PopupPanelStackPanel, StackLayoutPanelHorizontalPanelVerticalPanelFlowPanelVerticalSplitPanelHorizontalSplitPanelSplitLayoutPanelDockPanel, DockLayoutPanelTabPanel, TabLayoutPanelDisclosurePanel

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

GWT components library

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: .javapublic 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>

Manual make-up vs. Cross-browser support

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

.b-popup { position: absolute; }

Attention!

In GWT, there is an entire vast library of components

and an armory of layouts.

Though, the fact of developing a site withits 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

@UiConstructorpublic MyCustomWidget(String defaultText) { . . .}

public void setMaxLength(int maxLength) { ... }

Custom components

Do not inherit, but delegate

@UiConstructorpublic MyCustomWidget(String defaultText) { initWidget(uiBinder.createAndBindUi(this));}

public void setMaxLength(int maxLength) { ... }

Customization vs. Cross-browser support

Attention!

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

...either to allocatea significant amount of time

for UI designers and programmers to work through your own

component library.

...either to allocatea significant amount of time

for UI designers and programmers to work through your own

component library.

The lack of UI Designerwas a drawback

for someone

The lack of UI Designerwas a drawback

for someone

5. Layouting

Reasons?

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

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

For example, portlets or custom widgets

Reasons?If your site is built with logical blockswhich 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 blockswhich 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 ITEM EDIT

B

B

B

CA

A

C

A

C

D

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

Layouts

LIST ITEM EDIT

B

B

B

CA

A

C

A

C

D

Base page

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

toolbar

layout

footercopy

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

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

}

}

Link

History.newItem(Portal.USER_LIST.makeLink());History.newItem(new PortalUrl(Portal.USER_EDIT, uid).makeLink());History.newItem(userTokenGenerator.edit(uid));

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

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

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

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 ]

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

Layouting helps us to build and to live!

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

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

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

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

6. Non-Java API

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

Accidentally, here is the main point

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

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

And here is the source code

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

LoginMessages_ru.propertiesenterName = Введите имяemailExists = E-mail {0} зарегистрирован в системеemailInvalid = Некорректный e-mail {0}loginFailed = Не удалось зайти пользователем {0}youFailedNTimes = Кол-во неудачных попыток: {0,number}youFailedNTimes[one] = {0,number} неудачная попыткаyouFailedNTimes[few] = {0,number} неудачных попыток

MenuConstants_ru.propertieslogin= Войтиlogout = Выйтиcontacts = Контактыsettings = Настройки

Messages / Constants

<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

Messages / Constants

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

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

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

errors = ERR_101, ERR_102, ERR_103

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

Messages / Constants

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

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

...if you'll teach yourtranslators to manage.properties-files or givethem PoEdit or Pootle

...if you'll teach yourtranslators to manage.properties-files or givethem PoEdit or Pootle

ResourceBundles

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

8. Conclusion

experika.com

We applied those techniques for Experika

experika.com

Welcome to Experika

Thanks toVitaly 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

profiles.google.com/shaman.sir

Anthony Kotenko

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 characterof The Simpsons series

and also created by Matt Groening

All the phrases they tellin this presentation have no relation

nor for these characters, nor for series noticed above,

nor for their creator