Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

59
Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc

Transcript of Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Page 1: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Deferred Binding:The Magic of GWT

Ray Cromwell CTO, Timepedia, Inc

Page 2: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

“Any sufficiently advanced technology is indistinguishable from magic.” -

Arthur C. Clarke

Page 3: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Deferred Binding

• What is it?• Why it’s needed.• How does GWT use it?• The Nitty Gritty of How it Works• How to create your own Deferred

Binding• Discussion

Page 4: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

What is it? Let’s start with Static Binding

• Connection c = new MySQLConnection()– c tied to specific implementation, happens at

compile time– No ability to defer choice until runtime, user

stuck with MySQL connection

• Want: Connection c = load(userDriver);– Where userDriver selectable at runtime

Page 5: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Fix: Dynamic Binding

• Java has Dynamic Binding– Dynamic Class Loading– Dynamic Method Invocation (Reflection)

• Used by many Java applications– Runtime loadable drivers (JDBC, JAXP, etc)– Dependency Injection/Method Interceptors– Persistence Frameworks (Hiberbate/JPA)– Java Service Provider Interfaces (SPIs)

Page 6: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Another Solution: Deferred Binding• “Compile Time Dynamic Binding”• Still allows ‘userDriver’ selection to

be made at runtime• Conceptually similar

– GWT “dynamically loads” classes at compile time

• Similar capabilities in terms of reflection and method interception

Page 7: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Deferred Binding differs in Actualization• GWT determines set of possible bindings for

each instantiation• For each permutation, generates Javascript with

specific bindings ‘baked in’• Deferred Bindings can be ‘intercepted’

– Can delegate to a Generator, generates code on-the-fly– Provides full featured reflection API called TypeOracle

• Bootstrap selection script loads Javascript ‘executable’ containing correct set of bindings for given situation

Page 8: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Another way to look at it

• Imagine a database app which loads a JDBC driver via Class.forName()

• What if javac discovered all your JDBC drivers and– Compiled a separate executable for

each driver (MyOracleApp, MySybaseApp, etc)

– Used a startup script to pick the right version depending on your preferences

Page 9: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

To Summarize

• Static Binding– Foo f = new Foo();

• Dynamic Binding– Class c = Class.forName(fooImplName);– Foo f = (Foo)c.newInstance();

• Deferred Binding– Foo f = (Foo)GWT.create(Foo.class);

Page 10: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Why it’s needed

• Smaller code• Better optimizations• Fewer network roundtrips• Metaprogramming• GWT Mantra: Why do at runtime

what you can do at compile time?

Page 11: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Smaller Code

• Browser and Locale differences– One set of functionality, many different

implementations

• Why force Firefox user to download inactive Opera implementation?

• Why force Chinese user to download English?

• Dynamic loading would add unneeded extra roundtrips and startup time

Page 12: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Better Optimization

• Dynamic Binding makes optimization more difficult– Compiler can’t analyze code it can’t see

• GWT sees all source code at compile time

• It optimizes each permutation as if dynamic bindings are statically bound

Page 13: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Example

• Animal a = (Animal)GWT.create(Animal.class)

• Bindings exist for Cat and Dog as implementations of Animal

• a.speak()– GWT can inline Cat.speak() and Dog.speak()– Can also remove dead code not touched by

Dog when running Cat permutation– Javac can’t.

Page 14: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Real World Example

DOM.setInnerText(element, “text”);

Delegates to implementation returned by GWT.create(DOMImpl.class)

Page 15: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Real World Example (cont)

In DOMImplIE6.javapublic native void setInnerText(Element

elem, String text) /*-{ if (!text) text = ''; elem.innerText = text; }-*/;

Page 16: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Real World Example (cont)In DOMImpl (for Safari) public native void setInnerText(Element elem, String text)

/*-{ // Remove all children first. while (elem.firstChild) { elem.removeChild(elem.firstChild); } // Add a new text node. if (text != null) { elem.appendChild($doc.createTextNode(text)); } }-*/;

Page 17: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Resulting Javascript on IE

DOM.setInnerText(element, “test”);

Compiles to

element.innerText = “test”;

Page 18: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

On Safari, the result is

$setInnerText(element, ‘Test’);function $setInnerText(elem, text) { while (elem.firstChild) { elem.removeChild(elem.firstChild); } if (text != null) {

elem.appendChild($doc.createTextNode(text)); }}

Page 19: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Fewer roundtrips

• Typical Web applications include external resources– External JS scripts– Cascading Style Sheets– Images– Locale resource translations

• Deferred Binding allows resources to be ‘baked’ into crunched-down, streamlined versions

• Reduce network trips, increase startup speed

Page 20: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Metaprogramming

• Extend Java language with annotations or by interface convention

• Intercept class creation and substitute on-the-fly implementations

• Example: Javascript Interop– Create Interface (e.g. GMap2)– Map interface to JS library (e.g. Google Maps)– Have GWT compiler generate glue code

automatically

Page 21: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Super Cool Example: Image Bundlesinterface MyIcons extends ImageBundle { Image mySubmitBtn(); Image myLoadBtn(); Image myCancelBtn();}MyIcons mIcons =

(MyIcons)GWT.create(MyIcons.class)

Page 22: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Super Cool Example: Explained

• ImageBundle is tied to a Generator• Generator looks for gif/jpg/png icons of the

same name as each method• Concatenates all icons into single mosaic

image• Browser loads only 1 icon file• Generates MyIcons implementation class,

which returns icon clipped to region of interest

Page 23: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Summary: What’s the Mantra?

• Why do at runtime what you can do at compile time?

Page 24: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

How does GWT use it?

• ImageBundles• RPC

– Generates custom serialization/service invocation impl for your Remote Interfaces

• Browser ‘detection’– Swaps in different DOM, event, and UI class

implementations based on browser• Localization

– Generates implementations of ResourceBundle-like classes per locale

Page 25: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

The Nitty Gritty Details

• Module File Declarations– Defining and Extending Properties– Replace-With and Generate-With

• Permutation Generation• Selection Script

Page 26: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Module Files and Deferred Binding• Properties

– Define an enumerated set of values for a given name

• Rules– Declare how to rebind a given type

• Replace-With or Generate-With

• Conditions– When should this rule be executed?

Page 27: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Properties

• Start with a declaration of the initial enumeration

<define-property name=“gender” values=“male,female”/>

• Set a default value statically<set-property name=“gender” value=“male”/>

Page 28: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Properties (cont)

• A property can be set at runtime via Javascript provider

<property-provider name=“gender"><![CDATA[ return isFemale(document.cookie) ? “female” :

“male”;]]></property-provider>

Page 29: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Properties (cont)

• Modules can inherit your property – And extend its enumerated set of

values<extend-property name=“gender”

values=“neuter”/>

Page 30: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Rules: Replace-With

• Instruct compiler to replace one type with another

• Can limit with Conditions– “Replace all Dogs with Cats when

property Cats rule the world is true” <replace-with class=“org.cats.Cat”> <when-type-is class=“org.dogs.Dog”/> </replace-with>

Page 31: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Rules: Generate-With

• Like Replace-With, only replacement class is generated on-the-fly

• Handled by your Generator subclass – Has full reflection access to all known

classes <generate-with

class=“org.cats.rebind.CatGenerator”> <when-type-is class=“org.cats.VirtualCat”/> </generate-with>

Page 32: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Conditions

• <when-type-is class=“…”/>– Triggers when class attribute matches

• <when-type-assignable class=“…”/>• <when-property-is name=“…” value=“…”/>

– Triggers when property matches value

• Boolean logic supported– Condition OR Condition (<any>)– Condition AND Condition (<all>)– NOT Condition (<none>)

Page 33: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Permutation Generation

• Each property defines a dimension in n-dimensional space

• GWT will compile a version of your application for each position in this space

• Thus, the rebind conditions in the module are evaluated for each possible permutation

Page 34: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

A Picture of Permutations

Firefox

Opera

Safari

IE6

English French Chinese

FF_EN

OP_EN

SF_EN

IE_EN

FF_FR

OP_FR

SF_FR

IE_FR

FF_ZH

OP_ZH

SF_ZH

IE_ZH

Page 35: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Permutations

• Of course, with more than 2 properties, we get more dimensions

• That’s a lot of versions, BUT– Sometimes two or more permutations map to

the same compiled code– Trades cheap server disk space for reduced

bandwidth usage, server pressure, and faster user experience

– Your users will thank you for a small, fast app

Page 36: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Selection Script

• Small amount of bootstrap code• Determines property values and maps

them onto a compiled version of app• Allows Perfect Caching

– Users never download big script more than once (Expires: For-eve-ah!)

– When app changes, small Selection Script changes and loads differently named version

• (Selection Script expires Real Soon Now)

Page 37: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Create your own Deferred Binding

• Example 1: Debug vs Production – Pick between two implementations, one

when deploying as debug build, another when deploying to production

• Example 2: Bean Introspector with Generators– Create Interface Introspector which can

return list of JavaBean methods of a class

Page 38: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Example 1: Debug vs Production

• Create Logger interface– DebugLogger produces detailed errors– ProductionLogger no-op

• interface Logger { void log(String msg); }

• Usage: Logger log = (Logger)GWT.create(Logger.class)

Page 39: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Example 1 (cont)

• Step 2: Define new property in Logger.gwt.xml– <define-property name=“logger”

values=“debug,production”>

• Set default value– <set-property name=“logger”

value=“production”/>

Page 40: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Example 1: (cont)

Map property values to implementations<replace-with class=“DebugLogger”> <when-type-is class=“Logger”/> <when-property-is name=“logger” value=“debug”/></replace-with>– Repeat for ProductionLogger

Page 41: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Example 1: (cont) Implement Classesclass DebugLogger implements

Logger { public void log(String msg) { Window.alert(msg); }}

Page 42: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Example 1: (cont)

• Choose version in host page via– <gwt:property name=“logger”

value=“…”/>– Or ?logger=value in URL

• For extra credit– Return separate versions for Firefox,

IE, etc• E.g. Use Firebug console on Firefox

Page 43: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Example 2: Introspector

• Create tagging interface Introspector

interface Introspector {}• To use, derive interface with

annotations• Each method in derived interface

contains annotation declaring the class to be introspected

Page 44: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Example 2

interface MySpector extends Introspector {

/** * @gwt.introspect org.company.Foo */ String[] getFoo();}

Page 45: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Example 2: Usage

MySpector ms = (MySpector)GWT.create(MySpector.class);

// return list of bean properties of FooString beanProperties[] =

ms.getFoo();

Page 46: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Example 2: Generators to the Rescue• In Introspector.gwt.xml

<generate-with class=“MyGenerator”> <when-type-assignable class=“Introspector”/></generate-with>

• Note, Generators should not be in the .client package, by convention place them in a .rebind package

Page 47: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Example 2: Implement a Generator• Place in .rebind package• Extend com.google.gwt.core.ext.Generator• Override public String generate(TreeLogger logger,

GeneratorContext ctx, String requestedClass)• Call ctx.tryCreate(logger, package, className) to

create PrintWriter• Use PrintWriter for outputing new Java source• Inspect type information with TypeOracle from ctx• Return fully-qualified name of generated class

Page 48: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Example 2: Skeletonpublic class MyGenerator extends Generator {public String generate(TreeLogger l, GeneratorContext ctx,

String requestedClass) { PrintWriter pw = context.tryCreate( l, “test”, “TestImpl”); pw.println(“package test;”); pw.println(“public class TestImpl implements MySpector {“); pw.println(“public String[] getFoo() { return String[0]; }”); println(“}”); return “test.MySpectorImpl”; }}

Page 49: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Example 2: Skeleton, Problems

• Impl class always called “TestImpl”• Package fixed as “test”• getFoo() is stubbed

Page 50: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

TypeOracle vs Java Reflection

GWT Reflection Java Reflection

TypeOracle.findType Class.forName

JClassType Class

JMethod Method

JParameter Parameter

JField Field

Page 51: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Example 2: Computing destination class/package TypeOracle oracle = ctx.getTypeOracle(); JClassType ctype = oracle.findType(requestedClass); String package = ctype.getPackage().getName(); String genClass = ctype.getSimpleSourceName() +

“Impl”; PrintWriter pw = context.tryCreate( l, package, genClass); pw.println(“package ”+package); pw.println(“public class “+genClass+” implements MySpector

{“); pw.println(“public String[] getFoo() { return String[0]; }”); println(“}”); return package+genClass;

Page 52: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Example 2: Implement getFoo()

TypeOracle oracle = ctx.getTypeOracle(); JClassType ctype = oracle.findType(requestedClass); String package = ctype.getPackage().getName(); String genClass = ctype.getSimpleSourceName() + “Impl”; PrintWriter pw = context.tryCreate( l, package, genClass); pw.println(“package ”+package); pw.println(“public class “+genClass+” implements

MySpector {“); genMethods(oracle, ctype, pw); println(“}”); return package+genClass;

Page 53: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Example 2: Loop over all methods

public void genMethods(TypeOracle oracle, JClassType ctype, PrintWriter pw) {

for(JMethod method : ctype.getMethods()) { String md[][] = method.getMetaData(“gwt.introspect”); if(md != null && md.length > 0) { String classToIntrospect = md[0][0]; genMethod(method, oracle, classToIntrospect,

pw); } }}

Page 54: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Example 2: Generate Method

public void genMethod(JMethod m, TypeOracle oracle, String target,

PrintWriter pw) { JClassType targetType = oracle.findType(target); ArrayList<String> beanProps = new ArrayList<String>(); for(JMethod targetMethod : targetType) if(isBeanMethod(targetMethod)) beanProps.add(t.getName()); pw.println(“public String[] “+m.getName()+”() {”; writeProps(beanProps, pw); pw.println(“}”);}

Page 55: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Example 2: Detecting a bean methodpublic boolean isBeanMethod(JMethod m) { String name = m.getName(); JParameter params[] = m.getParameters(); return name.startsWith(“get”) &&

Character.isUpperCase(name.charAt(3)) && params.length > 0;}

Page 56: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Example 2: Writing out array

void writeProps(ArrayList<String> props, PrintWriter pw) { pw.println(“return new String[] {“); for(String prop : props) { pw.print(“\””+prop.substring(3)+”\”, “); } pw.println(“};”);}

Page 57: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

In Summary, Deferred Binding…

• Provides code generation and dynamic binding at compile time

• Allows the GWT compiler to perform an impressive number of optimizations not otherwise possible

• Can dramatically reduce network roundtrips• Permits Perfect Caching

• It’s simply the Magic of Google Web Toolkit

Page 59: Deferred Binding: The Magic of GWT Ray Cromwell CTO, Timepedia, Inc.

Discussion

Any questions?