GWT Extreme!


Published on

In this session, see Google Web Toolkit used in exotic and creative ways to solve interesting engineering problems, from authoring OpenSocial apps that run as both Web gadgets and native Android applications, to developing Adobe AIR applications using GWT, compiling CSS selectors to Javascript at compile time, running multithreaded code with GWT and Gears workers, or exporting GWT libraries for JavaScript users. Learn the secrets of writing "faster than possible" GWT code, how to use Generators and Linkers in harmony, and make seamless procedure calls from GWT code to other environments like Flash, Gears, or Android.

Published in: Technology
1 Comment
No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

GWT Extreme!

  1. 2. GWT Extreme! Performance and Flexibility <ul><li>Ray Cromwell, CTO, Timefire, Inc </li></ul><ul><li>05/29/2008 </li></ul>
  2. 3. BUDD: Why did he call it GWT Extreme? BILL: I guess he thought it sounded kinda cool.
  3. 4. Extreme Performance and Flexibility <ul><ul><li>“ Faster (and Smaller) than Possible” code </li></ul></ul><ul><ul><ul><li>Parsing and Evaluating CSS Selector Queries </li></ul></ul></ul><ul><ul><ul><li>High Performance Graphics </li></ul></ul></ul><ul><ul><li>Bridging GWT with other execution environments </li></ul></ul><ul><ul><ul><li>Remote procedure calls to Android, Flash, and Gears </li></ul></ul></ul><ul><ul><li>Writing Flash and Gears Workers in Java </li></ul></ul><ul><ul><ul><li>Tricks to compile subsets of your source as separate packages </li></ul></ul></ul><ul><ul><li>Q&A if time permits </li></ul></ul>
  4. 5. GWT Bloated and Slow? Think Again <ul><ul><li>Faster </li></ul></ul><ul><ul><ul><li>Generate Java code on the fly at compile time </li></ul></ul></ul><ul><ul><ul><li>Compiler inlines small Java and Javascript methods </li></ul></ul></ul><ul><ul><ul><li>Devirtualizes most other method calls </li></ul></ul></ul><ul><ul><ul><li>And tons more, too many to list…. </li></ul></ul></ul><ul><ul><li>Smaller </li></ul></ul><ul><ul><ul><li>Prunes and eliminates anything not used </li></ul></ul></ul><ul><ul><ul><li>Aggressively obfuscates code </li></ul></ul></ul><ul><ul><ul><ul><li>Obfuscated identifiers chosen to maximize DEFLATE compression </li></ul></ul></ul></ul><ul><ul><ul><li>Replace runtime operations with compile time </li></ul></ul></ul>“ Faster and Smaller than Possible” Code
  5. 6. GwtQuery (aka GQuery) <ul><ul><li>JQuery-like API in GWT </li></ul></ul><ul><ul><li>Uses GWT 1.5 language features for succinct code </li></ul></ul><ul><ul><li>Run-time CSS3 Selector parsing and evaluation </li></ul></ul><ul><ul><li>Compile-time CSS3 Selector parsing </li></ul></ul><ul><ul><li>Leverages modern browser features when available: </li></ul></ul><ul><ul><ul><li>XPath ( document.evaluate ) </li></ul></ul></ul><ul><ul><ul><li>W3C CSS Selector API ( document.querySelectorAll ) </li></ul></ul></ul><ul><ul><ul><li>getElementsByClassName() </li></ul></ul></ul>
  6. 7. GwtQuery Example Runtime Evaluation <ul><li>Find all “menus”, make first element text “Hello” </li></ul>import gwtquery.client.GwtQuery; import static gwtquery.client.GwtQuery.$; public class GwtQueryModule implements EntryPoint { public void onModuleLoad() { $( “ > li:first-child” ).html(“hello”); } }
  7. 8. GwtQuery Example What does the $(selector) function translate into? <ul><li>On Safari 3.1 </li></ul><ul><li>document.querySelectorAll(selector) </li></ul><ul><li>On Firefox, Opera, older Safari </li></ul><ul><li>Lots of Regexp parsing to compute xpathExpression </li></ul><ul><li>document.evaluate(xpathExpression) </li></ul><ul><li>On IE < 8 and others, a bunch of Regexp and DOM calls </li></ul><ul><li>Note: Each browser gets separately compiled JS </li></ul>
  8. 9. Digression: Generators <ul><li>Feature of Deferred Binding Mechanism </li></ul><ul><li>GWT.create(RequestedType.class) </li></ul><ul><li>Replace requested type with generated implementation </li></ul><ul><li>Turns into new GeneratedType() </li></ul>
  9. 10. GwtQuery Example Compile-time parsing <ul><li>Selectors usually literal strings, known at compile time </li></ul><ul><li>Why parse and translate these at runtime?! </li></ul><ul><li>Perform parsing and translation to XPath or JS-DOM navigation calls at compile-time </li></ul>public MySelectors extends Selectors { @Selector ( “ > li:first-child” ) GQuery allFirstMenuItems (); } MySelectors selector = GWT.create ( MySelectors.class ); selector. allFirstMenuItems ().html(“hello”);
  10. 11. GwtQuery Example Compile-time parsing <ul><li>GWT.create(MySelectors.class) triggers Generator </li></ul><ul><li>Different Generator for each browser (DOM, XPath, etc) </li></ul><ul><li>Generator creates implementation of MySelectors interface </li></ul><ul><li>For each method with a @Selector annotation </li></ul><ul><li>Parses CSS Selector, emits implementation of method </li></ul><ul><li>Compiler inlines method, elides everything else </li></ul>
  11. 12. GwtQuery Example Compile Time Parsing: Bottom Line ul > li:first-child becomes document.evaluate(“ul/li[position() = 1]”)
  12. 13. GwtQuery Example How big is the output? <ul><li>jQuery 1.2.3 </li></ul><ul><li>~3400 lines of Javascript </li></ul><ul><li>98kb unprocessed source </li></ul><ul><li>15kb obfuscated and gzipped </li></ul><ul><li>GwtQuery </li></ul><ul><li>~3400 lines of Java </li></ul><ul><li>116kb on disk </li></ul><ul><li>How big is it compiled? </li></ul><ul><li>15kb or larger? </li></ul><ul><li>How about 7kb, a 50% reduction? </li></ul><ul><li>3kb sounds about right! </li></ul><ul><li>712 bytes is the answer! </li></ul><ul><li>Smaller than single packet, HTTP headers </li></ul>
  13. 14. Caveats and Objections <ul><li>Trivial example </li></ul><ul><li>More reasonable example would exercise larger part of API </li></ul><ul><li>and reduce amount of pruned code </li></ul><ul><li>Example shows how aggressive GWT optimizer is </li></ul><ul><li>past GWT critics have used Hello World examples to demonstrate purported “bloat” </li></ul>
  14. 15. Demo: Progressively Enhancing <UL> into PowerPoint-like slide transitions Sample Code < div class =&quot; slide transition-fade&quot;> Slide 1 < ul class=&quot;transition-fade&quot;> < li > Point One </li> < li > Point Two </li> < li > Point Three </li> </ul> </div> < div class =&quot; slide transition-fade&quot;> Slide 2 < ul class=&quot;transition-appear&quot;> < li > Slide 2 Point One </li> < li > Slide 2 Point Two </li> < li > Slide 3 Point Three </li> </ul> </div>
  15. 16. GwtQuery code Sample Code for Selectors needed interface Slide extends Selectors { // find all LI elements rooted at ctx @Selector ( &quot;li&quot; ) NodeList<Element> slideBulletsCtx ( Node ctx ); // Find all DIV elements with class 'slide' @Selector ( &quot;div.slide&quot; ) NodeList<Element> allSlides (); }
  16. 17. GwtQuery code Sample Code for Event Handling final Slide s = GWT.create ( Slide.class ) ; $(Document.get().getBody()).click(new Function() { int curSlide = 0; int curBullet = 0; GQuery slides = $(s. allSlides() ); GQuery bullets = $(s. slideBulletsCtx( slides.get(curSlide) ) ); public boolean f(Event e) { if (curBullet < bullets.size()) bullets.eq(curBullet++).as(Effects).fadeIn(); else bullets.css(&quot;opacity&quot;,&quot;0&quot;); slides.eq(curSlide).css(&quot;display&quot;, &quot;none&quot;); curSlide++; if(curSlide == slides.size()) curSlide = 0; curBullet = 0; bullets = $(s.slideBulletsCtx(slides.get(curSlide))); slides.eq(curSlide).css(&quot;display&quot;,&quot;block&quot;) .as(Effects).fadeIn(); return true; } });
  17. 18. Sample of Generated Output for Selector “.slide li” W3C Selector API version public class SlideNativeImpl extends SelectorEngine implements MySelectors { public final NodeList<Element> slideBullets() { return querySelectorAll ( &quot;.slide li&quot; ); } }
  18. 19. Sample of Generated Output for Selector “.slide li” XPath Version public class SlideXPathImpl extends SelectorEngine implements Slide { public final NodeList<Element> slideBullets() { return xpathEvaluate ( &quot;./descendant::*[contains(concat(' ', @class, ' '), ' slide ')]/descendant::li&quot; ); } }
  19. 20. GWT Query <ul><li>Alpha Released Today </li></ul><ul><li>Available at </li></ul><ul><li>Help Contribute to Core and Plugins! </li></ul>
  20. 21. High Performance Graphics
  21. 22. Extreme Graphics Performance <ul><li>Immediate Mode vs Retained Mode </li></ul><ul><ul><li>Canvas vs SVG/VML </li></ul></ul><ul><li>JS VMs top out at between 1000-10000 method calls on Canvas </li></ul><ul><li>Can we cache/reuse work? </li></ul><ul><li>Take a page from OpenGL’s Playbook: Display Lists </li></ul>
  22. 23. Extreme Graphics Performance: Display Lists <ul><li>Record a sequence of draw calls </li></ul><ul><li>Replay sequence like a macro </li></ul><ul><li>Framework/driver can perform optimizations </li></ul><ul><ul><li>Collapse sequence of scale/rotate/translate operations into setTransform call </li></ul></ul><ul><ul><li>Cull/Clip some operations if possible </li></ul></ul><ul><ul><li>Cache result as bitmap where possible </li></ul></ul><ul><li>DEMO! </li></ul>
  23. 24. Extreme Graphics Performance and Flexibility: Chronoscope Chart Library Chronoscope Chart Library <ul><li>20,000 lines of code </li></ul><ul><ul><li>500kb of source </li></ul></ul><ul><ul><li>compiles to 58kb compressed </li></ul></ul><ul><li>30,000+ points at interactive rates </li></ul><ul><li>Javascript, Flash, Applet, Servlet, and Android </li></ul><ul><li>Multi-grained API </li></ul><ul><ul><li>Full control with Java+GWT </li></ul></ul><ul><ul><li>Higher level with Javascript API </li></ul></ul><ul><ul><li>Or with no coding at all via Microformats and CSS </li></ul></ul><ul><li>DEMO! </li></ul>
  24. 25. Some insights from porting to GWT 1.5 <ul><li>Method inlining yields up to 100% perf gains </li></ul><ul><li>Ability to inline JSNI provided huge gains for IE/Flash version </li></ul><ul><li>Slight increase in size </li></ul><ul><li>Abstractions don’t hurt much </li></ul><ul><li>Beware usage of long, costs of non-double types </li></ul><ul><li>Static initializers can be harmful </li></ul>
  25. 26. Chronoscope and Mobile Code with GWT <ul><li>Platform neutral code </li></ul><ul><li>Only 4 classes needed to run in other environments or on the “cloud” </li></ul><ul><ul><li>Flash, Android, Applet, Servlet </li></ul></ul><ul><li>GWT methods automatically exported to Javascript via GWT-Exporter library </li></ul>
  26. 27. Integrating GWT with other Environments
  27. 28. Integrating GWT with other environments <ul><li>GWT already integrates with Servlets </li></ul><ul><li>JSNI is used to integrate with Browser/JS </li></ul><ul><li>Extend RPC model to arbitrary containers </li></ul><ul><ul><li>Android </li></ul></ul><ul><ul><li>Flash </li></ul></ul><ul><ul><li>Gears Workers </li></ul></ul>
  28. 29. Example: Syndroid Gadgets can span many Platforms Android iGoogle OSX Google Desktop Yahoo And many Flash widget startups
  29. 30. Example: Syndroid <ul><li>Synthesis of Android and GWT </li></ul><ul><li>Write Gadgets to a restricted API </li></ul><ul><li>Compile to Javascript or Dalvik or (later) Actionscript </li></ul><ul><li>Deploy on Android, iGoogle, OSX, Yahoo, et al </li></ul><ul><li>Prototype DEMO! </li></ul>
  30. 31. Example: Android Native Interface What if Android browser had a window.locationService object? public class LocationServiceClient implements LocationService { public native String getLocation() /*-{ return $wnd. locationService . getLocation() ; }-*/; }
  31. 32. Generators + Linkers = Awesomeness <ul><li>Define RPC interface (sync or async) </li></ul><ul><li>Use Generator to generate client stub </li></ul><ul><ul><li>Params may or may not need to be serialized </li></ul></ul><ul><li>Also generate “server” to handle request </li></ul><ul><li>“ Server” handling code may need bootstrapping </li></ul><ul><li>Linker used to generate bootstrap code </li></ul><ul><li>If needed, use Linker to package/compile </li></ul>
  32. 33. Android Native Interface AndroidNativeInterface LocationService String getLocation(); extends LocationServiceClient String getLocation() { return $wnd.locationService.getLocation(); } implements Emitted by Generator LocationServiceImpl String getLocation() { return native code... } impl Written by Developer Android Bootstrap Bind LocationServiceImpl to window.locationService Provided by Linker
  33. 34. Example: Android Native Interface Synchronous RPC public interface AndroidNativeInterface {} @ANIBinding ( &quot;locationService&quot; ) @ImplementedBy ( &quot;LocationServiceImpl&quot; ) public interface LocationService extends AndroidNativeInterface { String getLocation (); }
  34. 35. Example: Android Native Interface Implement Android side (not legal GWT code!) public class LocationServiceImpl implements LocationService { public String getLocation () { try { Location currentLocation = ((LocationManager) context.getSystemService(Context.LOCATION_SERVICE)) .getCurrentLocation(&quot;gps&quot;); return &quot;Lat: &quot;+currentLocation.getLatitude()+ &quot;, Long: &quot;+currentLocation.getLongitude() ; } catch (Throwable e) { return &quot;ExceptionInNativeAndroid:&quot;+e.getClass().getName()+&quot;: &quot;+e.getMessage(); } } }
  35. 36. Example: Android Native Interface To use LocationService service = GWT.create ( LocationService.class ); Window.alert(“Your location is: “+ service.getLocation() );
  36. 37. Example: Linker Generated BootstrapActivity LocationServiceImpl gets exposed as window.locationService public class BootstrapActivity extends Activity { @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(getBootstrapView()); } public WebView getBootstrapView() { WebView wv=new WebView(this); wv.getSettings().setJavaScriptEnabled(true); wv.getSettings().setUseDesktopUserAgent(true); wv.getSettings().setLoadsImagesAutomatically(true); wv.addJavascriptInterface(new ContactsServiceImpl(this), &quot;contactsService&quot;); wv.addJavascriptInterface(new LocationServiceImpl (this), &quot;locationService&quot; ); wv.loadUrl(&quot;file:///android_asset/index.html&quot;); return wv; } } @ImplementedBy @ANIBinding
  37. 38. Example: Linker Generated Manifest Needed by Android <manifest xmlns:android=&quot; &quot; package=&quot;syndroid.demo.SyndroidDemo&quot;><uses-permission android:name=&quot;android.permission.ACCESS_LOCATION&quot;/><uses-permission android:name=&quot;android.permission.ACCESS_GPS&quot;/><uses-permission android:name=&quot;android.permission.ACCESS_ASSISTED_GPS&quot;/> <application> <activity android:name=&quot;BootstrapActivity&quot; android:label=&quot;SyndroidDemo&quot;> <intent-filter> <action android:name=&quot;android.intent.action.MAIN&quot;/> <category android:name=&quot;android.intent.category.LAUNCHER&quot;/> </intent-filter> </activity> </application></manifest>
  38. 39. Example: Linker Generated Build Script Used to compile and package APK file mkdir resmkdir classes $ANDROID_HOME/tools/aapt compile -m -J src -M AndroidManifest.xml -I $ANDROID_HOME/android.jar find src -name '*.java' -print >src.list javac -cp $ANDROID_HOME/android.jar @src.list -d classes $ANDROID_HOME/tools/dx -JXmx384M --dex --output=classes.dex -- locals=full --positions=lines classes/ $ANDROID_HOME/tools/aapt package -f -c -M AndroidManifest.xml -A assets -I $ANDROID_HOME/android.jar SyndroidDemo.apk zip SyndroidDemo.apk classes.dex
  39. 40. Client Stub Generator <ul><li>Use @ ImplementedBy annotation to find Android implementing class </li></ul><ul><li>Copy this class as resource (for Linker step) </li></ul><ul><li>Generate new Client stub </li></ul><ul><ul><li>Generate JSNI native method on Client Stub </li></ul></ul><ul><ul><li>JSNI method invokes Javascript object named by @ANIBinding annotation </li></ul></ul>
  40. 41. Generator to Linker Communication <ul><li>Generators work on types, can’t see build artifacts (compiler output) </li></ul><ul><li>Linkers work out build artifacts, can’t explore the type system </li></ul><ul><li>Some Linkers need type information </li></ul><ul><ul><li>e.g. Bootstrap scripts, manifests </li></ul></ul><ul><li>Communicate with linker by emitting a build artifact (e.g. text file) </li></ul><ul><li>Linker can scan for this special file and read contents </li></ul><ul><li>In our case, we write out mapping of @ANIBinding to @ImplementedBy </li></ul>
  41. 42. Using Linker Generate Bootstrap/Package for APT <ul><li>Read info from Generator (ANIBindings/ImplementedBy) </li></ul><ul><li>Copy implementation classes to build dir </li></ul><ul><li>Copy public resources to assets dir </li></ul><ul><li>Generate Android Manifest.xml </li></ul><ul><li>Generate Android Bootstrap Activity </li></ul><ul><ul><li>Set WebView as view </li></ul></ul><ul><ul><li>Enable Javascript </li></ul></ul><ul><ul><li>For each ANIBinding, bind instance of implementing class to Javascript </li></ul></ul><ul><li>Run Android Tools </li></ul><ul><ul><li>javac </li></ul></ul><ul><ul><li>dx </li></ul></ul><ul><ul><li>aapt to create final .apt </li></ul></ul>
  42. 43. Future Directions <ul><li>Use Special GWT bootstrap script to detect Android browsers </li></ul><ul><li>Offer user choice of “over the air” provision of Android-specific app </li></ul><ul><li>See for detailed architecture </li></ul>
  43. 44. Compiling GWT to Flash
  44. 45. Reusing the same Design Pattern for Flash <ul><li>Define ActionScriptNativeInterface </li></ul><ul><li>Place all “Flash” java code in .flash package </li></ul><ul><ul><li>Use generator to copy it to output as a resource </li></ul></ul><ul><li>Use Generator to create JSNI stubs to invoke Flash methods </li></ul><ul><li>But how do we turn Java code into SWF for the server side? </li></ul>
  45. 46. ActionScript Native Interface ActionScriptNativeInterface DrawService void drawLine(x,y); extends DrawServiceClient void drawLine(int x, int y) { $wnd.flashPlugin.drawLine(x, y); } implements Emitted by Generator package foo.flash; native void drawLine(int x, int y) /*-{ ... actionscript code to draw line ... }-*/; impl Written by Developer Flash Bootstrap generate main() Export drawLine(x,y) via ExternalInterface Provided by Linker
  46. 47. Compiling Java to ActionScript with GWT <ul><li>IDEA: Invoke GWT compiler recursively </li></ul><ul><li>Use Linker to create new GWT Project </li></ul><ul><li>Copy “flash” Java code to source path </li></ul><ul><li>Emit Module.gwt.xml file </li></ul><ul><li>Generate entrypoint </li></ul><ul><ul><li>For each ActionScriptNativeInterface add ExternalInterface </li></ul></ul><ul><li>Invoke GWT Compiler to produce SWF? </li></ul><ul><li>Emit SWF as output artifact </li></ul>
  47. 48. Packaging GWT output as SWF? <ul><li>GWT Compiler produces JS </li></ul><ul><li>Avoid GWT APIs which call DOM JSNI methods </li></ul><ul><ul><li>JRE generally safe </li></ul></ul><ul><li>Use Linker to </li></ul><ul><ul><li>add custom bootstrap script to invoke EntryPoint </li></ul></ul><ul><ul><li>invoke Flex3 SDK in non-strict mode </li></ul></ul><ul><ul><li>Emit resulting SWF as output artifact </li></ul></ul><ul><li>Generator+Linker+Generator+Linker Pattern </li></ul>
  48. 49. Writing Gears Workers in GWT <ul><li>Reuse same pattern as Flash </li></ul><ul><ul><li>e.g. place Gears-translatable Java in ‘.gears’ package </li></ul></ul><ul><li>Use Async RPC interfaces </li></ul><ul><li>JSON to marshal simple object types to Gears and back </li></ul><ul><li>Use SSO-like Linker </li></ul>
  49. 50. Q&A? <ul><li>GwtQuery available at </li></ul><ul><ul><li> </li></ul></ul><ul><li>Chronoscope available </li></ul><ul><ul><li> </li></ul></ul><ul><li>For in-depth articles/code, see blog at: </li></ul><ul><ul><li> </li></ul></ul><ul><li>Upcoming articles on Syndroid, and ActionScriptNativeInterface </li></ul>