The GWT community is full of activity; so much so that it sometimes becomes difficult to keep track of! I thought it would be a good idea to try and gather some of this action in one place, so without further ado, here's what's going on in the GWT community!
Restlet 1.1.0 released: Using REST APIs with Servlets used to require wasted hours writing custom code. Fortunately, Restlet came along to take that pain away. Even more fortunately, Restlet integrates with GWT to make dealing with REST APIs a breeze. The team has recently announced their 1.1.0 release, might be worth a spin if you've exhausted yourself writing custom code and need some REST.
Hibernate4GWT (Gilead) 1.2 RC1: Hibernate is an extremely powerful ORM framework for the Java programming language. It has proven itself as an invaluable tool for those with tight data-to-domain mapping, and thanks to Hibernate4GWT, has become easily accessible to GWT application developers. Hibernate 1.2 RC1 (aka Gilead) is now available to download.
SmartGWT 1.0 released: SmartClient is a framework that allows you to not only utilize its widget library for your application UI, but also tie these widgets in with your server-side for data management. SmartGWT 1.0, combining both GWT and SmartClient, has been released thanks to the efforts of Sanjiv Jivan. Read more about it in Sanjiv's release announcement.
GWT Maven heaven: The gwt-maven project developed by Charlie Collins and fellow project members provides a way for developers using a Maven to easily integrate GWT into their build system. We also have Nicolas De loof who has been working on a GWT Maven plug-in in the Mojo project. We're happy to say that Charlie Collins and Nicolas De loof are now going to form GWT Maven heaven by integrating the functionality of both plugin together and hosting them on the Mojo project.
Jared Jacobs is the frontend lead at kaChing, a marketplace for investing talent. He had a chance to stop by and give us the lowdown on his team's successful port of their GWT application onto the Facebook platform. If you're looking to socialize your application on Facebook, read on for the steps to make it happen.
As you may know, social networks like Facebook, LinkedIn, and MySpace can be an excellent place to grow a new business. Most of the kaChing community first discovered us through friends using our Fantasy Stock Exchange Facebook app.
In this post, I'll help you get your GWT app running as a Facebook app. Believe it or not, it can be done in just two easy steps.
And you're done! Visit the Canvas Page URL that you chose, and you'll see your GWT app running in Facebook. The rest of this post will suggest a couple of ways to integrate more fully, to better leverage the Facebook platform.
If your GWT app is too wide for the containing Facebook iframe and you can't stomach a horizontal scrollbar, then you need to make your app slimmer - at least when it's running inside Facebook. Facebook's width limit (currently 760px) is a hard limit.
If your GWT app is too tall, it'll be clipped and you'll see a vertical scrollbar along the right side. To fix this, you can specify a large fixed canvas height for your app using the CanvasUtil feature of Facebook's JavaScript Client Library. You can read the docs for more detail, but in practice it boils down to adding the following snippet to the body of your app's main HTML page:
<script type="text/javascript" src="http://static.ak.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php"> </script> <div id='FB_HiddenContainer' style='display:none;position:absolute;left:-100px;top:-100px;width:0;height:0'> </div> <script type="text/javascript"> window.onload = function(){ FB_RequireFeatures(['CanvasUtil'], function(){ FB.XdComm.Server.init('some/path/to/xd_receiver.html'); FB.CanvasClient.setCanvasHeight('2000px'); }); }; </script>
You should customize the highlighted parts. Here's a description of what's going on in the snippet above:
FB.CanvasClient.setCanvasHeight('2000px', function(){FB.CanvasClient.startTimerToSizeToContent()});
For more info on the CanvasUtil feature, including how to make the containing Facebook window scroll to a desired location, see this demo iframe app.
If a Facebook user is logged into Facebook when accessing your Facebook app, the app URL will include the user's Facebook ID in the query string as the fb_sig_user or fb_sig_canvas_user parameter, depending on whether the user has authorized your application. (See Authorizing Applications for more on the various request parameters.) You can use this Facebook ID, in conjunction with your app's ID and secret key, to request information about the user from Facebook using any of Facebook's various APIs. As a GWT app author, you are likely to be using a Java server, so consider using one of these Java Facebook clients. We use this open-source Facebook Java API.
For a high-level overview of Facebook's various APIs and their relative merits, I'd recommend a recent blog post by Facebook Platform engineer Charlie Cheever.
I hope this article helps you get your snazzy, snappy GWT apps to larger audiences. If you can afford the time investment, be sure to utilize social network integration points that can spur viral growth, such as invitations, profile boxes, and activity streams.
One of the best resources for developers looking for tips on building applications or learning about a new technology is to hear from other developers who have already been through the experience and built world-class applications. That's why we're happy to share videos of a few developers who used the Google Web Toolkit to build rich, sophisticated Ajax applications that have wowed audiences, won prestigious awards and are pushing the boundaries of what we've come to expect from a web application.
Check them out in our new Who's Using GWT page. In these videos, the developers explain how they used GWT to build their apps, their opinions on GWT overall, and tips and learnings from working with GWT. These videos include the developers behind:
We'd love to hear from others in the community. If you would like to share your experience developing GWT applications with the rest of the community, let us know in the forum.
A lot of discussion occurs in the Google Web Toolkit contributors forum about development progress, feature requests, and the roadmap. We realize that many of you are very busy and would like to see a simple roadmap on the website, so we've updated "Making GWT Better" with our current plans.
As with any development work, its hard to exactly predict when things will land, so we've stayed away from specific dates and releases past the next one. You'll be happy to know that release 1.6 is well underway and on target for Q1 of 2009.
You can check for future updates in the Making GWT Better section of our website.
Anticipated Time Frame - Q1 2009
The following are features that are on our roadmap for releases post 1.6, but are in various states of development. As we reach the end of the 1.6 cycle, we'll update the roadmap with which features we are targeting for the next release.
For those of you interested in creating visualizations in your Google Web Toolkit applications, we're happy to announce the Google Visualization API Library for Google Web Toolkit (GWT). This adds another library of Java language bindings for JavaScript APIs provided by Google, collectively known as the suite of Google API Libraries for Google Web Toolkit.
We're also releasing a General Availability build of the Google Maps API Library for GWT. This build contains a few bug fixes that contributors have reported. Thank you for reporting those, and please continue to report them in the issue tracker.
You can read more about the new Visualization API in the announcement on the Google Code blog.
StudyBlue is an academic social networking application, built with GWT, that helps students study smarter, faster. StudyBlue has done a great job with their application styling and design, so much so that they are shooting for a Crunchie Award on Tech Crunch for Best Design 2008.
We're fortunate to have StudyBlue President Chris Klundt and Eric Wuebben, Creative Director for StudyBlue, share their experience styling their potentially award-winning application using GWT and well-planned CSS techniques. If you've ever wondered how you can turn your GWT project into the next most styling application on the block, read on below.
We've been approached by many programmers and designers alike that question how we got such a custom look using GWT. Our response is simple, "Use GWT to build the house, not to paint it." When you build a new house, you don't have your building contractor pick out the furniture, choose the color palette, or stencil the walls. Similarly, you shouldn't use GWT to inject all the "style" into your website. Instead, you rough it out with GWT and push the design to CSS.
Whether you're building a small widget to embed in an existing site, or you're building an entire web-application from scratch (that's us :-) ), we recommend the following three tenants to ensure maximum design efficiency and flexibility:
Sticking with our home construction analogy, you might go about building a home by first having an architect envision a space, then having his apprentice detail the blueprints, before finally having a contractor build the house. Similarly, you should assemble a good design team before diving into the construction of your site with GWT. Chances are, if you are a strong Java programmer (i.e. "the GWT Programmer"), you are not as strong at CSS design and image slicing. You need to know what team members you have at your disposal, and what their strengths are. Once you're set with a Designer and a CSS Stylist (they may be the same person), we recommend you follow this general workflow:
Let's elaborate a bit on points 2, 3 and 4.
Part of knowing your team means understanding what your Web Designer's preferences are when it comes to using Tables or DIVs. GWT offers widgets that encompass both Tables (HorizontalPanel, FlexTable, etc.) and DIVs (FlowPanel, HTML, etc.). There are benefits and drawbacks to using each of them. For example, Tables might be good for vertical/horizontal centering or adding stability to a grid. They are poor for dynamic positioning, hover states, "rounded corners", etc. Whatever the case, both the GWT Programmer and the Web Designer should have an agreed understanding on which layouts (Tables or DIVs) are to be used and when it's appropriate to make exceptions. We prefer to do use DIVs, using FlowPanel much more often than HorizontalPanel or VerticalPanel.
Creating a "blueprint" is important for three reasons. First, it helps eliminate guess work from the GWT Programmer. An HTML "blueprint" can quickly be tested on all browsers to prove that the style renders to the structure as expected. Secondly, "blueprints" are an easy way to communicate between GWT Programmer and Web Designer without both parties having to be in the same room at the same time. Plus it makes it easy to assign blame when things don't look right :-). Finally, creating the "blueprint" will help you realize what looks in the original artwork are impossible to recreate on the site (hopefully none).
Note: Using the WebDeveloper plugin (or Firebug's Inspect) for Mozilla Firefox is a great way to inspect your final layout as a GWT Programmer, to make sure you match the "blueprint". More on this later.
Finally, when you start creating the layout in GWT, remember to break down each piece into a Composite class. Not every Composite you create will be reusable. Sometimes you have to make your widgets so specific that they can't be reused. That's OK, it's a common occurrence in UI programming. However, many widgets you can design to be reusable. One obvious example is "buttons" on your website.
We can't stress this point enough: PUSH YOUR STYLING TO A CASCADING STYLE SHEET (CSS). Just about everything you can do style wise can be done with CSS, so keep it that way.
HTML randomText = new HTML("This is some random text in a DIV"); DOM.setElementProperty(randomText.getElement(), "color", "green"); DOM.setElementProperty(randomText.getElement(), "fontSize", "16px");
HTML randomText = new HTML("This is some random text in a DIV"); randomText.setStyleName("sb-TextWidgets-RandomText");
.sb-TextWidgets-RandomText{ color: green; font-size: 16px; }
So let's look at a more complex example, a navigation bar with "hover" and "selected" states. Below you'll notice we've created reusable code for our "hover" and "selected" state that can be used by any widget that we want to implement "hover" or "selected".
Hover Class:
public class Hover { private static MouseListenerAdapter mla; public static MouseListenerAdapter getHoverMla(){ if(mla == null){ mla = new MouseListenerAdapter(){ public void onMouseEnter(Widget hoverableWidget){ hoverableWidget.addStyleDependentName("hover"); } public void onMouseLeave(Widget hoverableWidget){ hoverableWidget.removeStyleDependentName("hover"); } }; } return mla; } . . . }
public class Selected { private List<HTML> itemList; private ClickListener cl; public Selected(){ itemList = new ArrayList<HTML>(); cl = new ClickListener(){ public void onClick(Widget selectedItem) { for(HTML item : itemList){ if(item.equals(selectedItem)){ item.addStyleDependentName("selected"); } else{ item.removeStyleDependentName("selected"); } } } }; } public ClickListener getSelectedCL(){ return cl; } public void addItem(HTML item){ itemList.add(item); item.addClickListener(cl); } public void removeItem(HTML item){ itemList.remove(item); item.removeClickListener(cl); } }
public class NavBar extends Composite{ public static String BLOG_HOME="http://blog.studyblue.com/"; private int ID=1; private Selected selector; public NavBar(){ super(); selector = new Selected(); FlowPanel holder = new FlowPanel(); holder.setStyleName("NavBar-Holder"); holder.add(link("Blog","")); holder.add(link("About Us","about")); holder.add(link("Jobs","about/jobs")); setWidget(holder); } private HTML link(String text, String location){ HTML ret = new HTML(text); ret.setStyleName("nav-item-"+ID); ret.addStyleName("nav-item"); selector.addItem(ret); ret.addMouseListener(Hover.getHoverMla()); ret.addClickListener(new ClickListener(){ public void onClick(Widget sender){ ///Open popup with blog page location } }); ID++; return ret; } }
.nav-item { background-image: url(images/nav.png); background-repeat: no-repeat; background-position: 0 0; display: block; height: 0px; padding: 30px 0 0 0; overflow: hidden; } .nav-item-1 { background-position: 0 0; width: 65px; } .nav-item-2 { background-position: -65px 0; width: 90px; } .nav-item-3 { background-position: -155px 0; width: 65px; } .nav-item-1-hover { background-position: 0 -30px; } .nav-item-2-hover { background-position: -65px -30px; } .nav-item-3-hover { background-position: -155px -30px; } .nav-item-1-selected { background-position: 0 -60px; } .nav-item-2-selected { background-position: -65px -60px; } .nav-item-3-selected { background-position: -155px -60px; }
So, let's break down what is going on here. The NavBar is a Composite which is holding a FlowPanel ("holder"). This FlowPanel is a DIV which is going to hold our 3 links: "blog", "about us", and "jobs". Each one of these links is an HTML widget (i.e. a DIV). Inside the method "link" we first are creating each HTML with the appropriate text, setting its style name with a unique integer, adding an additional style name. From there, we add the link to our "selector" as well as add a "hover" listener. Finally, we add a ClickListener which initiates an action (in this case taking the user to the blog).
Some things to note:
Without our CSS, the result would simply look like this:
Blog About Us Jobs
However, by adding a few style names, we are able to achieve a look like this:
We also streamlined our development by standardizing the use of stand-alone buttons on the site. That way, the GWT Programmer can create a button widget that can be reused depending on the size and color button needed. The widget uses DEPENDENT style names to produce small, medium, or large buttons colored with green, white, blue, or red that are preset in the style sheet and work for flexible content lengths.
It is really important to have a test environment for your Web Designer to mess with. As a GWT Programmer, you can't expect that your Web Designer will be able to run Hosted Mode. Also, until the GWT guys implement Out-of-Process Hosted Mode (OOPHM), you will definitely want to take a look at your product in all the major browsers before deploying to production. We run a Tomcat instance on a powerful box over at Amazon Web Services. Using SVN and Ant, we update all our code to the test machine, compile it, create a WAR and deploy it using one command. The key here is that this process takes over 6 minutes every time we want to deploy new code. Six minutes may not seem like that long, but when your Web Developer is waiting 6 minutes every time you need to make a small change to the layout, it gets annoying. So we implemented two ideas to help ease the pain.
First, if you take one thing away from this post, don't style using the GWT DOM class. Set your style names and let the CSS do the work. If we had put all the styles in the GWT code, it would take us 6 minutes to change the color of some trivial text, only to find out that we liked it better the old way (another 6 minutes).
Second, pull out your CSS files and images directory to some location outside your WAR. The idea here is that the Web Designer can manipulate the CSS and imagery without ever getting inside your WAR. This way, when its time to deploy new code, you don't overwrite the Web Designer's changes by replacing the CSS file and/or images on accident. This also helps with remote collaboration. The Web Designer gives the GWT Programmer the "blueprints", the GWT Programmer builds the app and deploys it to the test server, the Web Designer is free to make changes to the CSS and images while checking compatibility across all the browsers. Theoretically, you'd never have to be in the same room (although we don't prefer it that way).
Now get out there and build an awesome GWT house!
By Sumit Chandel, Google Web Toolkit Team
A couple weeks ago, I talked about On-demand widget creation in GWT, a technique you can use to improve the performance of your own GWT applications. What we detailed there was how to apply the technique and what benefits it yields, however we only briefly touched on when and where to apply the pattern.
Applying on-demand widget creation in your application requires a measured understanding of your GWT application's performance. Profiling your application is key to identifying performance hot spots that could be improved using the lazy load pattern or other performance tune-up techniques.
The two key data points to consider when profiling your application are slowdowns and memory usage. Here the term slowdown relates to how slow your application performs in terms of the JavaScript and DOM manipulations that are being processed to run the application. Obviously slowdowns are bad because they lead to sluggish user experiences and less users on your site. Memory usage is equally important as an application that leaks or consumes large amounts of memory is likely to slowdown or crash the user's browser, which also leads to users leaving your site, most likely preceded by profuse cursing.
In this post I wanted to share some tips you could use to profile your own GWT application to help plan your on-demand creation strategy or apply other performance improving code fixes.
One of the tools that I usually use to profile GWT applications is the FireBug plugin for Firefox. It has great support for profiling JavaScript performance, which you can use to help find hotspots in your code where certain widget creation calls are taking up too much time and would be better loaded on demand.
Don't try this out just yet! The GWT compiler takes care of optimizing and obfuscating the JavaScript generated from your GWT source, therefore if you tried to run the FireBug profiler over your application without first compiling your application with the -style PRETTY flag, you'll have a really hard time figuring out what you're profiling.
To re-compile your GWT application in PRETTY mode, simply tweak the MyApplication-compile script if you used the applicationCreator or change your GWT compile run configuration to pass the -style PRETTY mode flag to the compiler (e.g. for Linux -compile script shown below):
#!/bin/sh APPDIR=`dirname $0`; java -Xmx256M -cp "$APPDIR/src:$APPDIR/bin:$APPDIR/../../gwt-user.jar:$APPDIR/../../gwt-dev-linux.jar" com.google.gwt.dev.GWTCompiler -style PRETTY -out "$APPDIR/www" "$@" com.google.gwt.sample.mail.Mail;
Once you've compiled in PRETTY mode, you should be able to use FireBug's JavaScript performance profiler with ease to help identify spots where you would want to load your widgets on demand rather than all at once. You can look forward to something like the screenshot below:
Yet another way to profile your application is to do it manually by setting start / finish timestamps before and after the component you care about profiling, respectively. For example, let's say I wanted to determine the initial load time for the phone book application we developed as an example in the last blog post. I would first set a timestamp in my host HTML page, way up in the <head> of the document to make sure that the timestamp is recorded right when the first resource is picked up.
<title>Phonebook</title> <script language="javascript"> window.startTime = new Date().getTime(); </script> <iframe src="javascript:''" id="__gwt_historyFrame" style="border: 0pt none ; position: absolute; width: 0pt; height: 0pt;"></iframe>
Then I would add the finish timestamp right at the end of the onModuleLoad() method, which should allow me to get a good indication of how long it took to load the application from start to finish.
public void onModuleLoad() { ... displayLoadTime(); } private native void displayLoadTime() /*-{ $wnd.alert("Load time: " + (new Date().getTime() - $wnd.startTime)); }-*/;
A note about what's being measured here - there are some elements that are not included in this measuring technique that affect load time performance. For example, any external scripts that are required to load your application will not be factored into this measure by default; nor will any references to other external resources such as stylesheets. You can include these resources in your load time measurement by adding the corresponding tag in your module XML file so that they are loaded synchronously. Also, image fetches are not included in this load time measure (although you can use the ImageBundle to gather your images in a single download that you can time individually). What's more, any code that is executed in a DeferredCommand or an IncrementalCommand will not be picked up with this measuring technique.
Also, this measure captures the time it takes to execute code to load and display the widget, but not actually render it on the browser DOM with styles applied. Capturing that kind of measure would require far from trivial browser instrumentation.
That said, this measuring technique is still a good way to profile parts of your application and compare them to other implementations since you can accurately measure the time it takes to execute the code responsible for loading your widgets. You could set up the same load time measurement around any other widget creation method that you want to evaluate for on-demand loading. If you feel that setting up alerts to display the load time measurements is a little silly, you may want to take a look at Fred Sauer's gwt-log project, which allows you to log timestamps among other things while developing your GWT application.
Another note about manual timer measurements - there is a slight difference in timer resolution depending in which browser you're running the code above. However, the delta between browsers is usually less than 15ms, and not a humanly noticeable delay. Therefore this difference should be negligible as you collect data points to plan out your on-demand widget creation strategy.
Another thing to keep in mind is that aside from timer resolution differences, browsers do have different load times in general, so it's important to profile your application for each major browser you intend on supporting for your users.
Aside from the profiling techniques described above, there is always the old fashioned way of doing things - just trying it out and seeing how it feels. When something feels sluggish, chances are that it is and needs to be fixed. If you want to drill down to numbers, typically a delay greater than 0.8 seconds in load time is perceived by the user as a full second delay, and starts to qualify an application as sluggish.
Hopefully this post gave you some guidance on how to go about collecting data points about your application in order to plan strategies and fixes to improve performance. While some of the profiling techniques listed above should go a long way, the state of profiling tools around Ajax is still evolving and will take some time before becoming the rich environment developers may remember from days of old (desktop development).
A good place to get more tips about profiling and performance tune up techniques is on our very own GWT developer forum. We have tons of developers posting up there who have developed their own tricks to profile their GWT applications and improve performance, and they'd be happy to share their insights if you're looking for more ways to improve your own applications.
You may be happily coding away your GWT application, when you start to notice that as you keep enriching the application with new UI components, the load time starts to increase. If you're looking for ways to speed up your application, perhaps you should consider lazy loading in GWT application development - what we're coining "On-demand widget creation".
Lazy loading is a technique where a given object holds null references to other objects that later get instantiated only when they are needed. Actually, lazy loading is a concept that you may already be familiar with, but you may not know how it applies to GWT development. Hopefully this post helps you learn about how you can apply "on-demand widget creation" to speed up your own GWT applications.
Imagine your application looks something like a telephone directory listed alphabetically and split into three tabs (A-J, K-R, S-Z). Each tab contains a list of clickable names and phone numbers. Upon clicking an entry, you can access the contact address information as well as map it on an embedded Google Map located on the right side of the page, outside of the three tabs.
Initially, the code for the tab panel containing the list of names and phone numbers might look something like this:
String[] headings = new String[]{"A-J","K-R","S-Z"}; public void onModuleLoad() { VerticalPanel verticalPanel = new VerticalPanel(); initializeGMap(); TabPanel directory = new TabPanel(); FlexTable listingAJ = new FlexTable(); FlexTable listingKR = new FlexTable(); FlexTable listingSZ = new FlexTable(); loadListings(listingAJ, headings[0]); loadListings(listingKR, headings[1]); loadListings(listingSZ, headings[2]); directory.add(listingAJ, headings[0]); directory.add(listingKR, headings[1]); directory.add(listingSZ, headings[2]); verticalPanel.add(directory); verticalPanel.setSize("500px", "500px"); RootPanel.get().add(verticalPanel); } private void loadListings(FlexTable listings, String range) { int numRows = listings.getRowCount(); if("A-J".equals(range)) { listings.setWidget(numRows++, 0, new Listing("John Doe", "555-3092")); listings.setWidget(numRows++, 0, new Listing("Jane Doe", "555-2039")); } else if ("K-R".equals(range)) { listings.setWidget(numRows++, 0, new Listing("John Roe", "555-3123")); listings.setWidget(numRows++, 0, new Listing("John Koe", "555-9583")); listings.setWidget(numRows++, 0, new Listing("Jane Moe", "555-9503")); } else if("S-Z".equals(range)) { listings.setWidget(numRows++, 0, new Listing("Jane Zoe", "555-0945")); } }
This code seems good enough and it will work for what we expect out of our phone book. If you try it out in hosted mode, the phone book is quite responsive and usable. However, it's worthy to note that this example is over a limited population.
What if we wanted to do this for a much larger population - say that of New York City. We would be looking at roughly 8 million potential subscribers whose information we want to list. Assuming an even distribution between names across our three tab alphabetical division, this would mean showing 2.67 million entries in a single tab.
Ignoring the fact that this is an extreme example, you could imagine that trying to show that many entries on one tab is likely to freeze browsers and end your users' relationship with your application. However, the truth is that you don't even have to reach numbers in the 10^6 range for your users to start experiencing slowdowns, and our phone book application users will start feeling the pain even at a few hundred entries.
Let's suppose we were creating a phone book for a smaller population size, say that of Smalltown, Pennsylvania (population: 600). Here is when using "on-demand widget creation" can help - only render the widgets once you really need to see them.
Applying this as a first attempt to improving our phone book experience, we would end up with something like this:
public void onModuleLoad() { VerticalPanel verticalPanel = new VerticalPanel(); initializeGMap(); final TabPanel directory = new TabPanel(); FlexTable listingAJ = new FlexTable(); ListingPlaceHolder listingKR = new ListingPlaceHolder(); ListingPlaceHolder listingSZ = new ListingPlaceHolder(); directory.addTabListener(new TabListener() { public boolean onBeforeTabSelected(SourcesTabEvents sender, int tabIndex) { Widget listing = directory.getWidget(tabIndex); if(listing instanceof ListingPlaceHolder) { FlexTable listingToLoad = new FlexTable(); loadListings(listingToLoad, headings[tabIndex]); directory.remove(listing); directory.insert(listingToLoad, headings[tabIndex], tabIndex); } return true; } public void onTabSelected(SourcesTabEvents sender, int tabIndex) { } }); loadListings(listingAJ, headings[0]); directory.add(listingAJ, headings[0]); directory.add(listingKR, headings[1]); directory.add(listingSZ, headings[2]); verticalPanel.add(directory); verticalPanel.setSize("500px", "500px"); RootPanel.get().add(verticalPanel); }
As shown in the code above, you can see that we're not instantiating the second and third tab listings just yet, and instead setting the tab content to an empty ListingPlaceHolder type. Further down in the code, you can see that we've added a new TabListener to the directory that is checking for when a given tab is selected and whether the selected tab has been instantiated yet. If not, it loads the listings for the tab and adds them to the directory tab panel.
In the GWT incubator project, you can find the LazyPanel - a panel which allows you to easily load widgets on demand according to your lazy load strategy.
Using the LazyPanel is simple. All you need to do is add the widget that you want to lazily load in the lazy panel, and then call setVisible(true) on the lazy panel to actually have the widget load on demand. It's worth mentioning that the LazyPanel is mainly intended for use with widgets like the TabPanel and the StackPanel, and is not ideal in all cases.
Applying this to the phone book example, the recrafted code might look something like this:
public void onModuleLoad() { VerticalPanel verticalPanel = new VerticalPanel(); initializeGMap(); TabPanel directory = new TabPanel(); LazyListingPanel listingAJ = new LazyListingPanel(headings[0]); LazyListingPanel listingKR = new LazyListingPanel(headings[1]); LazyListingPanel listingSZ = new LazyListingPanel(headings[2]); listingAJ.setVisible(true); directory.add(listingAJ, headings[0]); directory.add(listingKR, headings[1]); directory.add(listingSZ, headings[2]); verticalPanel.add(directory); verticalPanel.setSize("500px", "500px"); RootPanel.get().add(verticalPanel); } public class LazyListingPanel extends LazyPanel { String range; public LazyListingPanel(String range) { this.range = range; } @Override public FlexTable createWidget() { FlexTable listings = new FlexTable(); loadListings(listings, range); return listings; } private void loadListings(FlexTable listings, String range) { ... } }
And there you have it.
As mentioned just above, the LazyPanel isn't always the ideal choice for implementing an on-demand widget creation design. For example, one thing we mentioned about our phone book application is that each listing is clickable, and once clicked bring up an address popup. You could imagine that manually implementing the lazy load pattern for the address popup widget probably makes more sense than create LazyPanel instances for each address popup attached to each phone book listing.
Lazily loading your widgets has the obvious benefit of improving the load time performance of your application. It also allows you to control your application's memory usage as your user interacts with it, which can also be critically important since applications that tend to consume a lot of memory can potentially crash in the user's browser.
However, it is possible to overdo lazy loading and actually have it affect your application performance negatively. In fact, sometimes you want to do just the opposite and eagerly load parts of your application to improve performance.
After going through the simple example of on-demand widget creation and talking about its benefits, it may seem counter-intuitive to now say that sometimes it's better to eagerly load a part of the application. But there do indeed exist cases where it's better to eagerly load parts of your application to create a better user experience.
Take for example our phone book application. Let's say we now wanted to add different types of directories to our phone book - businesses, people and government institutions. If we were to apply the lazy load pattern the same way as we did for the personal listings from A-Z, we would be tempted to do the same here and only load the business listings once they were actually clicked on and asked for. Same for the government institution listings.
The average user probably spends most of their time looking up personal and business listings. For example, let's say a user is looking up his lawyer's number. He might first check the personal listing for "John Doe", and supposing he doesn't find it, switch to the business listings to see if the number is there.
Supposing the business listings are loaded on demand, the user might have to wait a quick but noticeable few milliseconds before the listings actually show up - time that might not have been spent waiting if the listings were already loaded. On the other hand, having the business listings load up in advance might slow down the initial application load time, not to mention incur some memory usage in addition to everything else that's already loaded.
So, lazy loading is great but takes some planning. One of the decision points we just mentioned is how much memory the components you need to load will take up and how they affect initial load time of either your application or one of its larger components.
Aside from profiling your application to plan a lazy load strategy, it's generally useful to learn and apply profiling techniques during development so you can quickly identify hot spots and fix them. After making your final CSS tweaks, updated RPC calls and integrating a third party library and realizing that your application is now running ten times slower, it's important to locate and eliminate the slowdowns.
Because GWT application profiling is such an important topic, it seems appropriate to devote an entire blog post to just that topic, and then relating it back to lazy load strategy planning later. Stay tuned for next week where we'll show you different tools you can use to profile your GWT application and help iron out the wrinkles.
Recently I was giving an introductory talk on JavaScript Overlay Types in GWT. A question came up about what I meant by the following:
final native void foo(int x, int y) /*-{ ... }-*/;
can magically become
final static native void foo(MyJSO this_, int x, int y) /*-{ ... }-*/;
It was a great question, and merited explaining why Overlay Types have certain constraints on them and what goes on during the compile process. If you are brand new to Overlay Types, you'll want to look over the earlier blog post or docs first.
As the earlier post explained, in Overlay Types you can augment the Java type without disturbing the underlying JavaScript object. For example, you can have getters and setters in the Java class that don't exist on the underlying JavaScript object. At the same time, your Java class is providing this richer functionality without GWT having to modify the underlying JavaScript object instance or its prototype.
This is possible because by design we disallow polymorphic calls on instance methods. All methods must be 'final' and/or 'private'. Consequently, every method on an overlay type is statically resolvable by the compiler, so there is never a need for dynamic dispatch at runtime. We can either inline the method body or create a global function external to the object itself.
This all makes more sense if we look at a concrete example, so let's do that. Here we have a JavaScript snippet embedded in an HTML page. This snippet defines a native JavaScript object of type 'nativeCustomer' and creates a instance called 'fred'.
//JavaScript in an HTML page <script> function nativeCustomer () { this.FirstName = ""; this.LastName = ""; } var fred = new nativeCustomer(); fred.FirstName = "Fred"; fred.LastName = "Wilson"; </script>
Now we'll overlay that native JavaScript object with an Overlay Type in GWT.
// An overlay type in GWT, which must extend JavaScriptObject class Customer extends JavaScriptObject { // Overlay types always have protected, zero-arg constructors protected Customer() { } // Typically, methods on overlay types are JSNI public final native String getFirstName() /*-{ return this.FirstName; }-*/; public final native String getLastName() /*-{ return this.LastName; }-*/; public final String thankCustomer(String thanksType){ if (thanksType.equals("buying")){ return "Dear " + getFirstName() + ", thanks for buying our product"; } else { return "Dear " + getFirstName() + ", thanks for referring your friend"; } } }
For good measure, I'll add a JSNI method to get the native JavaScript object from the wild, returning the Customer overlay type above.
private native Customer getNativeCustomer() /*-{ return $wnd.fred; }-*/;
Now that we have our native JavaScript object, a way to access it, and an Overlay Type, we'll want to use it. Below I have some GWT code that simply gets the JavaScript object from the wild as an Overlay type, then calls some methods on it.
Customer customer = getNativeCustomer(); Window.alert(customer.getFirstName() + " " + customer.getLastName()); Window.alert(customer.getFullName());
In this blog post we're interested in what's happening underneath - what the compiled output looks like. You'll notice that the methods in our Overlay Type don't exist on the actual JavaScript object. Where do they go? As we said above, where possible we try to just get rid of them. Yep, gone. The compiler will actually inline the augmented method bodies, so that the above code looks like this:
var customer; customer = $wnd.fred; $wnd.alert(customer.FirstName + ' ' + customer.LastName); $wnd.alert(customer.FirstName + ' ' + customer.LastName);
You'll notice that we're accessing the underlying object's attributes (FirstName, LastName) directly. Pretty cool.
Sometimes it isn't possible to inline the augmented Java method, in which case a global function is created. Take the method thankCustomer() in the Customer class above. If we can't inline the method body, then we need to create a function somewhere. However, we don't want to add it to the underlying object or its prototype, so we create a global function that takes the underlying object as an argument. We get the same effect, but without the overhead of indirection.
So the 'thankCustomer' method above becomes
function $thankCustomer(this$static, thanksType){ if ($equals_0(thanksType, 'buying')) { return 'Dear ' + this$static.FirstName + ', thanks for buying our product'; } else { return 'Dear ' + this$static.FirstName + ', thanks for referring your friend'; } }
which means a Java source code line like
Window.alert(customer.thankCustomer("buying"));
in the end compiles to a call to global function $thankCustomer with the customer object passed as an argument.
$wnd.alert($thankCustomer(customer, 'buying'));
And that takes us full circle back to the code snippet at the beginning of this post. When we say that
final native void foo(int x, int y) /*-{ ... }-*/; can magically become final static native void foo(MyJSO this_, int x, int y) /*-{ ... }-*/;
We're showing that if foo can't be inlined, then it will become a global function with the object passed as an argument rather than a method on the object itself.
You may also now see why we don't allow attributes on an Overlay Type -- we'd have nowhere to store them in this model. However, as you've seen we can allow augmented Java methods through either inlining the method away, or creating a global function where the first argument is the object itself.
By Eric Ayers, Google Web Toolkit Team
We're pleased to announce the final release of the Gears 1.1, Gadgets 1.0, and Search 1.1 APIs, all part of the Google API Libraries for Google Web Toolkit project. We are also making available a second release candidate for the Maps API.
Download Now Online Documentation
Each library comes with:
Changes since last Release Candidate:
Gears 1.1 (1.1.1)
Gagets 1.0 (1.0.1)
Search 1.0 (1.0.1)
Maps 1.0 RC2 (1.0.1)
As described in our earlier article outlining ARIA support in GWT1.5, widgets now include basic support for W3C ARIA, an emerging set of Web standards that enable AJAX applications to work smoothly with screenreaders. But there is more to using an application than interacting with individual user interface widgets — overall usability is determined by the complete user experience.
We have improved the usability of Google Health for screenreader users by enhancing the built-in support available in GWT 1.5 via JavaScript. The resulting user experience enables users of screenreaders and self-voicing browsers to easily navigate the interface to obtain relevant auditory feedback — see the following sections for additional details.
Note that the accessibility support in Google Health requires support from both the browser as well as the adaptive technology in use. At present, we recommend Firefox 3.0 with screenreaders that support ARIA, alternatively, you can also use Fire Vox, the self-voicing extension to Firefox 3.0.
When signing in, first-time users should use this link ARIA-Enabled Google Health to turn on the accessibility enhancements. If you would like to use these enhancements whenever you sign in to Google Health, please perform these additional steps:
You can have one or more health profiles on Google Health, and once logged in, you can create and access health profiles from the main screen. Use the navigation keys (arrow keys) to navigate the interface. The left and right arrow keys move you through the major categories, whereas the up and down arrow keys move through the items in a given category. adaptive technology in use produces appropriate feedback as you move. In addition, the item under focus is visually highlighted and can be magnified by pressing the = key. Auditory feedback includes spoken output from the adaptive technology, augmented by short auditory icons that help orient the user within the application.
The bulk of the Google Health application consists of navigating among various categories, finding the relevant item within a category, and if needed, updating the contents of that item. As an example, when working with your health profile, you can:
This paradigm of navigating with the arrow keys, and pressing enter to edit the current item and using power keys for picking the desired action is applied consistently across all aspects of Google Health. Many categories in this application have a large number of items, e.g., the list of medications. In addition to the up and down arrow keys, these lists can be navigated by pressing capital letters to directly jump to the relevant section in the list of items. In addition, the application provides wizards for performing complex tasks, e.g., finding a doctor.
To conclude, here is a short summary of the generic key-bindings that are available throughout the application:
Following up on our earlier post, a release candidate of the Google Maps API Library for GWT is now available for download. This library provides a way to access the Google Maps API from a GWT project without having to write additional JavaScript code. The library gives you full control using the standard Maps components such as InfoWindows, Markers, MapTypes, and Geocoding. You can even use advanced features such as adding GWT widgets to the Map, creating custom overlays, custom map types, and other components.
In addition to maps, the Google API Libraries for GWT also provide libraries for Gears, Gadgets and the Google AJAX Search API. Please try out these release candidates and give us feedback, either through the issue tracker on code.google.com, or through the Google-Web-Toolkit or Google-Web-Toolkit-Contributors group.
By Emily Crutcher, Google Web Toolkit Team
A special thanks to the great group of engineers outside of Google who have contributed to the project including Ray Cromwell, Jason Essington, Daniel Florey, Fred Sauer.
As websites and applications become more interactive, users relying on assistive technology can find navigation difficult. Dynamic web applications are often written in ways that screen readers -- which interpret visual interfaces by speaking out loud or producing braille -- have difficulty interpreting. A developer building a tree widget, for example, might use a list element that has been altered to behave like a tree control. By default, a screen reader would present the control as a list, making the tree unusable for blind or visually impaired users. Screen readers also generally treat HTML span or div elements as regular static text elements, regardless of the presence of JavaScript event handlers for user interaction. You can easily imagine how this causes problems.
However, there's hope on the horizon in the form of WAI-ARIA, a specification for making web applications accessible via a standard set of DOM attributes. Currently a work-in-progress at the W3C, WAI-ARIA describes how to encode the purpose and function of a widget so browsers and screen readers can work together to properly identify widgets made up of DOM elements.
To make applications built with GWT more easily accessible, we've added accessibility support to the GWT library by baking ARIA roles and states into our widgets. With the accompanying ARIA support in Firefox and Opera (and soon, WebKit and Internet Explorer), applications built with the latest release of GWT will provide the information needed by screen readers such as JAWS, Window-Eyes, and FireVox. The ARIA support in the end-user tools is a bit of a moving target, but we've documented what works and what doesn't at present, so your application can evolve with the web.
If you've built your own widgets, you can make them accessible with the new Accessibility class, and to test out your newly-accessible widgets, you can watch for the ARIA attributes with a DOM inspector like Firebug. To check for the appropriate accessibility events, you can use a tool like Microsoft's Accessible Event Watcher -- or just install FireVox and listen to your application read aloud.
For more on ARIA and how to make sure your GWT application is easily accessible, you can read up on Accessibility in the GWT Developer's Guide.
We're happy — no, ecstatic — to announce that GWT 1.5 is now officially released and available for download.
Download GWT 1.5
GWT 1.5 delivers what we think are an impressive number of improvements, about four hundred issues if you're counting. We're also happy that one of those is issue 168, our most-requested feature, Support for Java 5.
Support for Java 5
We've blogged about several of the new features already. Now that it's official, let's recap and expand the list a bit...
@gwt.typeArgs
StringBuilder
TreeMap
LinkedHashMap
-ea
assert
just feel faster.
feels faster
Tree
MenuBar
TabPanel
Those are some highlights. The (new) GWT Developer's Guide has a more detailed explanation of GWT 1.5 changes, including notes about a few breaking changes you'll want to be aware of.
For further information or for help getting started with GWT, you may find the follow links helpful:
We really hope that you'll find that GWT 1.5 helps you build the most sophisticated web apps you can envision. And when you build the next big thing, please share your success stories in the GWT developer forum.
We're happy to say that the first Release Candidates for the Google API Libraries for Google Web Toolkit are now ready to be taken for a test drive.
The project is a collection of libraries that provide Java language bindings and API specific plumbing for some Google JavaScript APIs. The goal is to make it easy for developers to use these JavaScript APIs with GWT. Libraries available at this time include a new version of Gears, as well as new libraries for Gadgets and the Google AJAX Search API.
Gears 1.1 Library (Release Candidate) A new version of the Gears library is available. In addition to the earlier version's support for the Gears LocalServer, Database, and WorkerPool, 1.1 adds integrated support for offline applications and updated sample applications. The bindings have also been refactored to use GWT 1.5 JavaScript overlay types and a new package hierarchy.
Gadgets 1.0 Library (Release Candidate) The Gadgets library simplifies gadget development with GWT by automatically generating a Gadget specification from Java source and inserting a selection script in the specification much like a regular GWT project. After compiling your gadget with GWT, all files are in place to publish your gadget. This version currently supports the legacy Gadgets API based on the _IG_... namespace.
Google AJAX Search 1.0 Library (Release Candidate) The Google AJAX Search API lets you put Google Search in your web pages, including Web, Local, and Multimedia searches. This library allows you to access the API from Java code compiled with the GWT compiler without having to write additional JavaScript code.
If you've been following the early milestone builds, you may also be aware that a Google Maps API Library for GWT is in the works. Stay tuned for a release candidate for that library.
With this set of release candidates, each library is now distributed separately so that you can download only the specific library you are interested in.
We encourage you to try these release candidates out and give us feedback, either through the issue tracker on code.google.com, or through the Google-Web-Toolkit or Google-Web-Toolkit-Contributors group.
The second release candidate of GWT 1.5 is available for download now.
Thanks to everyone who started using GWT 1.5 RC1 and shared feedback. With your help, we're very near the end of the big GWT 1.5 development cycle.
If you haven't already, now would be a great time to start upgrading your project to take advantage of all the new features and great performance gains in GWT 1.5.
Enjoy!
Suppose you're happily using JSNI to call bits of handwritten JavaScript from within your GWT module. It works well, but JSNI only works at the level of individual methods. Some integration scenarios require you to more deeply intertwine JavaScript and Java objects — DOM and JSON programming are two good examples — and so what we really want is a way to interact directly with JavaScript objects from our Java source code. In other words, we want JavaScript objects that look like Java objects when we're coding.
GWT 1.5 introduces JavaScript overlay types to make it easy to integrate entire families of JavaScript objects into your GWT project. There are many benefits of this technique, including the ability to use your Java IDE's code completion and refactoring capabilities even as you're working with untyped JavaScript objects.
Overlay types are easiest to understand with examples. Suppose we want to access an array of JSON objects representing a set of "customer" entities. The JavaScript structure might look like this:
var jsonData = [ { "FirstName" : "Jimmy", "LastName" : "Webber" }, { "FirstName" : "Alan", "LastName" : "Dayal" }, { "FirstName" : "Keanu", "LastName" : "Spoon" }, { "FirstName" : "Emily", "LastName" : "Rudnick" } ];
To superimpose a Java type onto the above structure, you start by subclassing JavaScriptObject, a marker type that GWT uses to denote JavaScript objects. Let's go ahead and add some getters, too.
JavaScriptObject
// An overlay type class Customer extends JavaScriptObject { // Overlay types always have protected, zero-arg ctors protected Customer() { } // Typically, methods on overlay types are JSNI public final native String getFirstName() /*-{ return this.FirstName; }-*/; public final native String getLastName() /*-{ return this.LastName; }-*/; // Note, though, that methods aren't required to be JSNI public final String getFullName() { return getFirstName() + " " + getLastName(); } }
GWT will now understand that any instance of Customer is actually a true JavaScript object that comes from outside your GWT module. This has useful implications. For example, notice the this reference inside getFirstName() and getLastName(). That this is truly the identity of the JavaScript object, so you interact with it exactly as it exists in JavaScript. In this example, we can directly access the JSON fields we know exist, this.FirstName and this.LastName.
Customer
this
getFirstName()
getLastName()
this.FirstName
this.LastName
So, how do you actually get a JavaScript object on which to overlay a Java type? You can't construct it by writing new Customer() because the whole point is to overlay a Java type onto an already existing JavaScript object. Thus, we have to get such an object from the wild using JSNI:
new Customer()
class MyModuleEntryPoint implements EntryPoint { public void onModuleLoad() { Customer c = getFirstCustomer(); // Yay! Now I have a JS object that appears to be a Customer Window.alert("Hello, " + c.getFirstName()); } // Use JSNI to grab the JSON object we care about // The JSON object gets its Java type implicitly // based on the method's return type private native Customer getFirstCustomer() /*-{ // Get a reference to the first customer in the JSON array from earlier return $wnd.jsonData[0]; }-*/; }
Let's clarify what we've done here. We've taken a plain-old-JSON-object (POJSONO, anyone? no?) and created a normal-looking Java type that can be used to interact with it within your GWT code. You get code completion, refactoring, and compile-time checking as you would with any Java code. Yet, you have the flexibility of interacting with arbitrary JavaScript objects, which makes things like accessing JSON services via RequestBuilder a breeze.
A quick digression for compiler geeks. Another neat thing about overlay types is that you can augment the Java type without disturbing the underlying JavaScript object. In the example above, notice that we added the getFullName() method. It's purely Java code — it doesn't exist on the underlying JavaScript object — and yet the method is written in terms of the underlying JavaScript object. In other words, the Java view of the JavaScript object can be richer in functionality than the JavaScript view of the same object but without having to modify the underlying JS object, neither the instance nor its prototype.
getFullName()
prototype
(This is still part of the digression.) This cool wackiness of adding new methods to overlay types is possible because the rules for overlay types by design disallow polymorphic calls; all methods must be final and/or private. Consequently, every method on an overlay type is statically resolvable by the compiler, so there is never a need for dynamic dispatch at runtime. That's why we don't have to muck about with an object's function pointers; the compiler can generate a direct call to the method as if it were a global function, external to the object itself. It's easy to see that a direct function call is faster than an indirect one. Better still, since calls to methods on overlay types can be statically resolved, they are all candidates for automatic inlining, which is a Very Good Thing when you're fighting for performance in a scripting language. Below we'll revisit this to show you just how much this regimen pays off.
final
private
We glossed over something in the example above. The method getFirstCustomer() is pretty unrealistic. You're certainly going to want to be able to access the entire array of customers. Thus, we need an overlay type representing the JavaScript array itself. Fortunately, that's easy:
getFirstCustomer()
// w00t! Generics work just fine with overlay types class JsArray<E extends JavaScriptObject> extends JavaScriptObject { protected JsArray() { } public final native int length() /*-{ return this.length; }-*/; public final native E get(int i) /*-{ return this[i]; }-*/; }
Now we can write more interesting code:
class MyModuleEntryPoint implements EntryPoint { public void onModuleLoad() { JsArray<Customer> cs = getCustomers(); for (int i = 0, n = cs.length(); i < n; ++i) { Window.alert("Hello, " + cs.get(i).getFullName()); } } // Return the whole JSON array, as is private final native JsArray<Customer> getCustomers() /*-{ return $wnd.jsonData; }-*/; }
This is nice clean code, especially considering the flexibility of the plumbing it's built upon. As hinted at earlier, the compiler can do pretty fancy stuff to make this quite efficient. Take a look at the unobfuscated compiled output for the onModuleLoad() method:
onModuleLoad()
function $onModuleLoad(){ var cs, i, n; cs = $wnd.jsonData; for (i = 0, n = cs.length; i < n; ++i) { $wnd.alert('Hello, ' + (cs[i].FirstName + ' ' + cs[i].LastName)); } }
This is pretty darn optimized. Even the overhead of the getFullName() method went away. In fact, all of the Java method calls went away. When we say that "GWT gives you affordable abstractions," this is the kind of thing we're talking about. Not only does inlined code run significantly faster, we no longer had to include the function definitions themselves, thus shrinking the script a litte, too. (To be fair, though, inlining can also easily increase script size, so we're careful to strike a balance between size and speed.) It's pretty fun to look back at the original Java source above and try to reason about the sequence of optimizations the compiler had to perform to end up here.
Of course, we can't resist showing you the corresponding obfuscated code:
function B(){var a,b,c;a=$wnd.jsonData;for(b=0,c=a.length;b<c;++b){ $wnd.alert(l+(a[b].FirstName+m+a[b].LastName))}}
Notice in this version that the only bits that aren't obfuscated are the identifiers that originated in JavaScript, such as FirstName, LastName, jsonData, etc. That's why, although GWT strives to make it easy to do lots of JavaScript interop, we try hard to persuade people to write as much of their code as possible as pure Java source instead of mixing with JavaScript. Hopefully now when you hear us say that, you'll understand that we aren't bashing JavaScript — it's just that we can't optimize it as much, which makes us sad.
FirstName
LastName
jsonData
Overlay types are a key new feature in GWT 1.5. At its simplest, the technique makes direct interop with JavaScript libraries much easier. Hopefully after this post you could imagine how to almost directly port any JavaScript library into GWT as a set of Java types, thus allowing the use of a Java IDE for productive development and debugging without impacting size or speed due to any sort of GWT overhead. At the same time, overlay types serve as a powerful abstraction tool for delivering more elegant low-level APIs such as the the new GWT DOM package.
For more information...
RequestBuilder