Slide 1

Slide 1 text

GWT + mvp4g Anthony Kotenko, iPark ventures™ 2011 © web-development using

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

goo.gl/DKYzc Slides — there [ PDF, ~2MB ]

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

Schedule

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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!

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

1. Briefly 'bout GWT

Slide 13

Slide 13 text

GWT code.google.com/webtoolkit/ Google Web Toolkit /ˈɡwɪt/

Slide 14

Slide 14 text

GWT /ˈɡwɪt/

Slide 15

Slide 15 text

/ˈɡwɪt/

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

A box of useful tools

Slide 19

Slide 19 text

A box of useful tools The most complete for web-developer

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

widgets cross-browserly! optimization http://2.bp.blogspot.com/_VzXmgKXrn6Y/TKB2a3eZTBI/AAAAAAAAAaQ/mn7NmabwO8U/s1600/browsers%5Btsksoft.blogspot.com%5D.jpg

Slide 23

Slide 23 text

widgets cross-browserly! on-the-fly development optimization http://lh4.ggpht.com/_a0imbbK4r5U/Sxwd1oVpXiI/AAAAAAAAAjc/gsRkQUn9kZI/gwt-dev-mode.png

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

widgets cross-browserly! on-the-fly development optimization OOP benefits debug http://www.ibm.com/developerworks/library/j-ajax4/eclipse-debug.jpg

Slide 26

Slide 26 text

widgets cross-browserly! on-the-fly development optimization OOP benefits debug RPC API/DB

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

widgets cross-browserly! simple i18n on-the-fly development optimization OOP benefits Code Splitting debug RPC

Slide 29

Slide 29 text

widgets cross-browserly! simple i18n on-the-fly development optimization OOP benefits Code Splitting debug RPC

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

No content

Slide 34

Slide 34 text

History

Slide 35

Slide 35 text

Version 1.0 was released in 2006

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

Version 2.1 MVP-conception RequestFactory / Editors

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

Quake 2 in browser quake2-gwt-port.appspot.com

Slide 42

Slide 42 text

Trendy Youth Modern

Slide 43

Slide 43 text

GWT is actively developing project, however it already contains everything you need /ˈɡwɪt/

Slide 44

Slide 44 text

No content

Slide 45

Slide 45 text

2. GWT Conceptions

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

Any GWT-project starts from entry point EntryPoint

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

JavaScript Logo is from marakana.com

Slide 50

Slide 50 text

JSNI JavaScript Native Interface

Slide 51

Slide 51 text

JSNI public native static void () /*-{ . . . @.::( /L;/L;...)(); . . . }-*/;

Slide 52

Slide 52 text

JSNI public native static void getJson(int requestId, String url, StockWatcher handler) /*-{ var callback = "callback" + requestId; var script = document.createElement("script"); script.setAttribute("src", url+callback); script.setAttribute("type", "text/javascript"); window[callback] = function(jsonObj) { [email protected] .client.StockWatcher::handleJsonResponse( Lcom/google/gwt/core/client/JavaScriptObject;)(jsonObj); window[callback + "done"] = true; } setTimeout(function() { if (!window[callback + "done"]) { [email protected] .client.StockWatcher::handleJsonResponse( Lcom/google/gwt/core/client/JavaScriptObject;)(null); } document.body.removeChild(script); delete window[callback]; delete window[callback + "done"]; }, 1000); document.body.appendChild(script); }-*/;

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

No content

Slide 57

Slide 57 text

Development Mode ♥

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

Development Mode http://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 ♥

Slide 60

Slide 60 text

Development Mode http://lc:8080/ui/?gwt.codesvr=lc:9997#!job/start http://lh4.ggpht.com/_a0imbbK4r5U/Sxwd1oVpXiI/AAAAAAAAAjc/gsRkQUn9kZI/gwt-dev-mode.png

Slide 61

Slide 61 text

Development Mode http://lc:8080/ui/?gwt.codesvr=lc:9997#!job/start http://lh4.ggpht.com/_a0imbbK4r5U/Sxwd1oVpXiI/AAAAAAAAAjc/gsRkQUn9kZI/gwt-dev-mode.png

Slide 62

Slide 62 text

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!

Slide 63

Slide 63 text

No content

Slide 64

Slide 64 text

Code Splitting when the neccessary code was loaded

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

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!

Slide 69

Slide 69 text

No content

Slide 70

Slide 70 text

.gwt.xml

Slide 71

Slide 71 text

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

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

.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

Slide 74

Slide 74 text

.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

Slide 75

Slide 75 text

.gwt.xml ⁕ Components ⁕ Browsers ⁕ Locales ⁕ Debug

Slide 76

Slide 76 text

.gwt.xml ⁕ Components ⁕ Browsers ⁕ Locales ⁕ Debug

Slide 77

Slide 77 text

.gwt.xml ⁕ Components ⁕ Browsers ⁕ Locales ⁕ Debug

Slide 78

Slide 78 text

.gwt.xml ⁕ Components ⁕ Browsers ⁕ Locales ⁕ Debug [Debug.gwt.xml]

Slide 79

Slide 79 text

.gwt.xml ⁕ Components ⁕ Browsers ⁕ Locales ⁕ Debug [Debug.gwt.xml]

Slide 80

Slide 80 text

.gwt.xml ⁕ Components ⁕ Browsers ⁕ Locales ⁕ Debug [Debug.gwt.xml]

Slide 81

Slide 81 text

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

Slide 82

Slide 82 text

No content

Slide 83

Slide 83 text

M V P R

Slide 84

Slide 84 text

Model View Controller

Slide 85

Slide 85 text

Model View Controller API/DB

Slide 86

Slide 86 text

Model View Controller calls

Slide 87

Slide 87 text

Model View Presenter

Slide 88

Slide 88 text

Model View Presenter events update

Slide 89

Slide 89 text

Model View Presenter Reverse

Slide 90

Slide 90 text

Model View Presenter Reverse

Slide 91

Slide 91 text

Presenter Event Bus

Slide 92

Slide 92 text

Presenter Event Bus Pre er

Slide 93

Slide 93 text

P EB P P P P P P

Slide 94

Slide 94 text

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

Slide 95

Slide 95 text

geekswithblogs.net/kobush/archive/2006/01/09/65305.aspx Difference between MVC and MVP

Slide 96

Slide 96 text

geekswithblogs.net/kobush/archive/2006/01/09/65305.aspx The article about MVC/MVP difference

Slide 97

Slide 97 text

tv.jetbrains.net/videocontent/gwt-event-bus-basics The video with the example of EventBus in work

Slide 98

Slide 98 text

tv.jetbrains.net/videocontent/gwt-event-bus-basics The video with the example of EventBus in work

Slide 99

Slide 99 text

EventBus is the central communication channel

Slide 100

Slide 100 text

No content

Slide 101

Slide 101 text

Deferred Binding

Slide 102

Slide 102 text

Deferred Binding In response to the lack of Reflection

Slide 103

Slide 103 text

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

Slide 104

Slide 104 text

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

Slide 105

Slide 105 text

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

Slide 106

Slide 106 text

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

Slide 107

Slide 107 text

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

Slide 108

Slide 108 text

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

Slide 109

Slide 109 text

Deferred Binding

Slide 110

Slide 110 text

Deferred Binding private static final PopupImpl impl = GWT.create(PopupImpl.class);

Slide 111

Slide 111 text

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

Slide 112

Slide 112 text

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

Slide 113

Slide 113 text

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

Slide 114

Slide 114 text

No content

Slide 115

Slide 115 text

★ Attention ★ Attention!

Slide 116

Slide 116 text

Dependency Injection

Slide 117

Slide 117 text

Dependency Injection Using GWT INjection / Guice frameworks

Slide 118

Slide 118 text

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

Slide 119

Slide 119 text

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

Slide 120

Slide 120 text

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

Slide 121

Slide 121 text

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

Slide 122

Slide 122 text

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

Slide 123

Slide 123 text

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

Slide 124

Slide 124 text

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

Slide 125

Slide 125 text

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!

Slide 126

Slide 126 text

No content

Slide 127

Slide 127 text

Remote Service

Slide 128

Slide 128 text

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

Slide 129

Slide 129 text

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

Slide 130

Slide 130 text

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

Slide 131

Slide 131 text

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

Slide 132

Slide 132 text

developerlife.com/tutorials/?p=125 Tutorial on creating Remote Services

Slide 133

Slide 133 text

Remote Services is server-side API built using Java interfaces

Slide 134

Slide 134 text

No content

Slide 135

Slide 135 text

JUnit

Slide 136

Slide 136 text

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

Slide 137

Slide 137 text

GWT-code is easy to test because of JUnit support

Slide 138

Slide 138 text

No content

Slide 139

Slide 139 text

Deficiencies and observations Anyway, you need good skills in JavaScript

Slide 140

Slide 140 text

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

Slide 141

Slide 141 text

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

Slide 142

Slide 142 text

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

Slide 143

Slide 143 text

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

Slide 144

Slide 144 text

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

Slide 145

Slide 145 text

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)

Slide 146

Slide 146 text

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

Slide 147

Slide 147 text

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

Slide 148

Slide 148 text

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

Slide 149

Slide 149 text

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

Slide 150

Slide 150 text

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

Slide 151

Slide 151 text

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

Slide 152

Slide 152 text

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

Slide 153

Slide 153 text

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

Slide 154

Slide 154 text

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

Slide 155

Slide 155 text

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

Slide 156

Slide 156 text

www.linux.org.ru/forum/talks/4497412 Here GWT drawbacks are discussed

Slide 157

Slide 157 text

Every reasoned weakness in GWT have a rational solution.

Slide 158

Slide 158 text

galak-sandbox.blogspot.com/2010/10/gwt.html Summary on GWT-code optimization

Slide 159

Slide 159 text

And I would ask for a beer now!

Slide 160

Slide 160 text

No content

Slide 161

Slide 161 text

3. mvp4g

Slide 162

Slide 162 text

No content

Slide 163

Slide 163 text

code.google.com/p/mvp4g/ mvp4g framework web-page

Slide 164

Slide 164 text

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

Slide 165

Slide 165 text

mvp4g framework helps to

Slide 166

Slide 166 text

work with (R)MVP mvp4g framework helps to

Slide 167

Slide 167 text

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

Slide 168

Slide 168 text

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

Slide 169

Slide 169 text

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

Slide 170

Slide 170 text

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

Slide 171

Slide 171 text

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

Slide 172

Slide 172 text

mvp4gshowcase.appspot.com mvp4g framework showcase

Slide 173

Slide 173 text

mvp4gshowcase.appspot.com mvp4g framework showcase

Slide 174

Slide 174 text

code.google.com/p/mvp4g/wiki/Mvp4g_vs_GWTP Comparison of code written with mvp4g or native GWT

Slide 175

Slide 175 text

code.google.com/p/mvp4g/wiki/Mvp4g_vs_GWTP Comparison of code written with mvp4g or native GWT

Slide 176

Slide 176 text

Pierre-Laurent Coirier [email protected]

Slide 177

Slide 177 text

Pierre-Laurent Coirier [email protected] (meet him at Google I/O '11)

Slide 178

Slide 178 text

The code you write using mvp4g framework is much simpler than GWT-code without its usage. It is achieved by Pierre correct use of annotations. Code is written by human. It is better to help him sometimes. Code is written by human. It is better to help him sometimes.

Slide 179

Slide 179 text

No content

Slide 180

Slide 180 text

Annotations

Slide 181

Slide 181 text

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

Slide 182

Slide 182 text

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

Slide 183

Slide 183 text

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

Slide 184

Slide 184 text

No content

Slide 185

Slide 185 text

RMVP

Slide 186

Slide 186 text

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

Slide 187

Slide 187 text

RMVP presenter @Presenter(view=OneView.class) public class OnePresenter extends BasePresenter { @Inject private ServiceAsync service; }

Slide 188

Slide 188 text

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

Slide 189

Slide 189 text

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

Slide 190

Slide 190 text

No content

Slide 191

Slide 191 text

EventBus

Slide 192

Slide 192 text

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

Slide 193

Slide 193 text

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

Slide 194

Slide 194 text

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

Slide 195

Slide 195 text

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

Slide 196

Slide 196 text

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

Slide 197

Slide 197 text

EventBus filters and stuff @Filters(filterClasses={FilterOne.class, FilterTwo.class}) @Debug(logger=CustomLogger.class) @Events(startView = StartView.class) public interface OneEventBus extends EventBus { . . . } class FilterOne implements EventFilter { @Override public boolean filterEvent(...) { return ...; } }

Slide 198

Slide 198 text

No content

Slide 199

Slide 199 text

History

Slide 200

Slide 200 text

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

Slide 201

Slide 201 text

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

Slide 202

Slide 202 text

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

Slide 203

Slide 203 text

@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 { @Inject private TokenGenerator tokens; public void convertFromToken(...) { if ("foo".equals(event)) eventBus.fooEvent( Integer.parseInt(params[0]), Filter.parse(params[1])); } public String fooEvent(...) { return tokens.fooEvent(id, filter); } } /foo?26;all History parameters

Slide 204

Slide 204 text

History hashbang @Events(...) public interface OneEventBus ... { @Event(...) public void fooEvent(int id, Filter filter); } @History public class OneHC implements HistoryConverter { ... public boolean isCrawable() { return true; } } /#!foo?26;all

Slide 205

Slide 205 text

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

Slide 206

Slide 206 text

No content

Slide 207

Slide 207 text

Multi- modularity

Slide 208

Slide 208 text

Multi- modularity annotations @AfterLoadChildModule @BeforeLoadChildModule @ChildModule @ChildModules @DisplayChildModuleView @HistoryName @LoadChildModuleErrors

Slide 209

Slide 209 text

Multi- modularity URLs company/list company/add company/edit?123 user/list user/add user/edit?39 object/action[?parameters] REST

Slide 210

Slide 210 text

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

Slide 211

Slide 211 text

@Events(..., module=UserModule.class) public interface UserEventBus extends EventBus { @Event(..., handlers=UserListPresenter.class, historyName="list") public void usersList(); . . . } @Events(...) @ChildModules( @ChildModule(moduleClass=UserModule.class) @ChildModule(moduleClass=CompanyModule.class) ) public interface ParentEventBus extends EventBus{ @Event(modulesToLoad=UserModule.class) public void usersList(); @Event(modulesToLoad=CompanyModule.class) public void companiesList(); } Multi- modularity event buses

Slide 212

Slide 212 text

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

Slide 213

Slide 213 text

History, event buses and modules are the skeleton of your site navigation system History, event buses and modules are the skeleton of your site navigation system You can load modules asynchronously! So user will not get the kilobytes he needs not, if he will not visit specified sections of your site. You can load modules asynchronously! So user will not get the kilobytes he needs not, if he will not visit specified sections of your site.

Slide 214

Slide 214 text

No content

Slide 215

Slide 215 text

PlaceService

Slide 216

Slide 216 text

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

Slide 217

Slide 217 text

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

Slide 218

Slide 218 text

No content

Slide 219

Slide 219 text

Remarks

Slide 220

Slide 220 text

Remarks There is no layouting-system yet

Slide 221

Slide 221 text

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

Slide 222

Slide 222 text

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

Slide 223

Slide 223 text

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

Slide 224

Slide 224 text

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

Slide 225

Slide 225 text

mvp4g — is what Zoidberg has prescribed!

Slide 226

Slide 226 text

No content

Slide 227

Slide 227 text

4. UI components

Slide 228

Slide 228 text

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

Slide 229

Slide 229 text

No content

Slide 230

Slide 230 text

No content

Slide 231

Slide 231 text

code.google.com/webtoolkit/doc/latest/RefWidgetGallery.html GWT components library

Slide 232

Slide 232 text

UiBinder: .ui.xml Name Babylen Family name Tatarsky Submit

Slide 233

Slide 233 text

UiBinder: .java public class SettingsForm extends Composite { interface SFormBinder extends UiBinder {} 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) { ... } }

Slide 234

Slide 234 text

HTMLPanel
Some div
  • Item 1
  • Item 2
  • Item 3

Some span

Slide 235

Slide 235 text

Manual make-up vs. Cross-browser support .gwt-Button { font-size: 150%; } .b-popup { position: absolute; } Attention!

Slide 236

Slide 236 text

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.

Slide 237

Slide 237 text

No content

Slide 238

Slide 238 text

Custom components

Slide 239

Slide 239 text

Custom components Do not inherit, but delegate

Slide 240

Slide 240 text

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

Slide 241

Slide 241 text

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

Slide 242

Slide 242 text

Customization vs. Cross-browser support Attention!

Slide 243

Slide 243 text

So it is better either to keep your site design as simple as possible... ...either to allocate a significant amount of time for UI designers and programmers to work through your own component library. ...either to allocate a significant amount of time for UI designers and programmers to work through your own component library.

Slide 244

Slide 244 text

No content

Slide 245

Slide 245 text

The lack of UI Designer was a drawback for someone

Slide 246

Slide 246 text

The lack of UI Designer was a drawback for someone

Slide 247

Slide 247 text

No content

Slide 248

Slide 248 text

5. Layouting

Slide 249

Slide 249 text

Reasons?

Slide 250

Slide 250 text

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

Slide 251

Slide 251 text

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

Slide 252

Slide 252 text

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.

Slide 253

Slide 253 text

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

Slide 254

Slide 254 text

No content

Slide 255

Slide 255 text

Layouts LIST ITEM EDIT B B B C A A C A C D

Slide 256

Slide 256 text

public class LayoutList implements Layout { } LayoutList.ui.xml: Layouts LIST ITEM EDIT public enum Place { A, B, C, D}; public interface Layout { public LayoutId id(); public HasWidgets place(Place place); Map places(); } public class LayoutItem implements Layout { } LayoutItem.ui.xml: public class LayoutEdit implements Layout { } LayoutEdit.ui.xml:

Slide 257

Slide 257 text

Layouts LIST ITEM EDIT B B B C A A C A C D

Slide 258

Slide 258 text

Base page BasePage.ui.xml: toolbar layout footer copy

Slide 259

Slide 259 text

No content

Slide 260

Slide 260 text

public enum Portal implements MakesLink { NEWS_LIST(LayoutId.LIST, , ), NEWS_EDIT(LayoutId.EDIT, , ), NEWS_VIEW(LayoutId.ITEM, , ), NEWS_DELETE(LayoutId.ITEM, , ) USER_LIST(LayoutId.LIST, , ), USER_EDIT(LayoutId.EDIT, , ), USER_VIEW(LayoutId.ITEM, , ), USER_DELETE(LayoutId.ITEM, , ), . . . @Override public String makeLink() { . . . } } Page / Portal

Slide 261

Slide 261 text

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

Slide 262

Slide 262 text

public enum Portal implements MakesLink { . . . public class PortalUrl implements MakesLink { PortalUrl(Portal portal[, ]) { ... } 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));

Slide 263

Slide 263 text

public abstract class LayoutBuilder { 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 places); } Layout builder

Slide 264

Slide 264 text

public class UserHistoryConverter implements HistoryConverter { 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

Slide 265

Slide 265 text

public class UserLayoutBuilder implements LayoutBuilder { public void layout(Portal page, State state, Map 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

Slide 266

Slide 266 text

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 ]

Slide 267

Slide 267 text

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

Slide 268

Slide 268 text

No content

Slide 269

Slide 269 text

Layouting helps us to build and to live!

Slide 270

Slide 270 text

github.com/shamansir/gwt-mvp4g-layouting-demo I've wanted to make a demo for you, but had no time ;(

Slide 271

Slide 271 text

github.com/shamansir/gwt-mvp4g-layouting-demo I've wanted to make a demo for you, but had no time ;( Follow

Slide 272

Slide 272 text

github.com/shamansir/gwt-mvp4g-layouting-demo I've wanted to make a demo for you, but had no time ;(

Slide 273

Slide 273 text

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

Slide 274

Slide 274 text

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

Slide 275

Slide 275 text

No content

Slide 276

Slide 276 text

6. Non-Java API

Slide 277

Slide 277 text

code.google.com/p/google-web-toolkit-doc-1-5/wiki/GettingStartedJSON Accidentally, here is the main point

Slide 278

Slide 278 text

Possibility — exists

Slide 279

Slide 279 text

RequestBuilder

Slide 280

Slide 280 text

General context

Slide 281

Slide 281 text

Call chains

Slide 282

Slide 282 text

Insering JS-object into HTML-markup (you can parse them using JSNI)

Slide 283

Slide 283 text

Advantage : Independence from serialization

Slide 284

Slide 284 text

Disadvantage : Unconventional approach with all the consequences

Slide 285

Slide 285 text

shamansir-ru.tumblr.com/post/1728720550/deferred-api-gwt-rpc And here is the source code

Slide 286

Slide 286 text

No content

Slide 287

Slide 287 text

7. i18n

Slide 288

Slide 288 text

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

Slide 289

Slide 289 text

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

Slide 290

Slide 290 text

Messages / Constants

Slide 291

Slide 291 text

Messages / Constants Message

Slide 292

Slide 292 text

ErrorsConstants_ru.properties ERR_101 = Ошибка авторизации ERR_102 = Неизвестная ошибка ERR_103 = Ресурс не найден errors = ERR_101, ERR_102, ERR_103 public interface ErrorsConstants extends ConstantsWithLookup { Map errors(); } Messages / Constants

Slide 293

Slide 293 text

Mae'n hawdd iawn i gyfieithu prosiectau GWT... Mae'n hawdd iawn i gyfieithu prosiectau GWT... ...if you'll teach your translators to manage .properties-files or give them PoEdit or Pootle ...if you'll teach your translators to manage .properties-files or give them PoEdit or Pootle

Slide 294

Slide 294 text

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

Slide 295

Slide 295 text

No content

Slide 296

Slide 296 text

8. Conclusion

Slide 297

Slide 297 text

experika.com We applied those techniques for Experika

Slide 298

Slide 298 text

experika.com Welcome to Experika

Slide 299

Slide 299 text

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

Slide 300

Slide 300 text

profiles.google.com/shaman.sir Anthony Kotenko

Slide 301

Slide 301 text

Thank you. Made with LibreOffice 3.3.1 Impress

Slide 302

Slide 302 text

More questions?

Slide 303

Slide 303 text

GWT FTW!

Slide 304

Slide 304 text

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