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

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

Embed Size (px)

Citation preview

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?