Things have come a long way since traditional desktop client/server application development. Before the Web, this used to be one of the only ways for developers to get their applications out to the user. Developers struggled with user environments, OS interoperability and update issues, and a slew of other headaches that were just part of the status quo; that is, until the introduction of the World Wide Web.
Shortly after the emergence of the Web, client-server apps started shifting from the desktop to the browser in the form of Web apps. This presented a win for developers and users. Developers could now focus on a specific platform (the browser) rather than layers of OS abstractions, and users only needed to download one browser rather than a whole bunch of software packages to run their favorite applications.
On top of this, Web applications presented unparalleled user accessibility. Rather than install an application on each machine they wanted to use, users were able to access Web applications on any machine that had a browser installed.
This represented more than a trend; in fact, it was a revolution. More and more companies have moved applications from the desktop environment to the Web landscape, and the Web (and the desktop) is a better place for it.
However, despite everything gained by moving to the Web platform, something has been lost as well during the transition: application responsiveness and intuitive user interfaces. This trend has left users faced with a new model they haven’t been trained to understand.
Many users are unwilling to be retrained, having already spent much effort learning the desktop paradigm. A common complaint from users is that waiting for the page repaints between actions is extremely frustrating. In response to these problems, we’ve moved toward a new model once again: Web 2.0 development.
The drive behind this model is Ajax technology. In short, it consists of writing JavaScript that manipulates the Document Object Model (DOM) of the host page and uses XmlHttpRequests
and callback objects to send and receive data asynchronously. Ultimately, it’s recreating the desktop experience in the browser. This is one of the last steps in achieving a lossless transition from the desktop environment to the Web. Users can have the best of both worlds. But, things aren’t all sunshine and lollipops in the realm of developers.
Ajax development hurts, and is not recommended without a bottle of analgesics by your side. For one thing, manipulating the DOM is different in each browser, so you have to make sure your Ajax code is compatible with all browsers.
Another major concern is maintaining a JavaScript code base, particularly for large-scale applications. Consider a Web 2.0 CRM application, composed of over 50,000 lines of code (LOC) in JavaScript. Imagine a team of developers need to make a major change to the application’s calendar, so that rather than clicking on a time block to schedule meetings, the new requirement is to create an activity block and drag and drop it over the calendar.
Would the team members be confident enough to dig through their code base and start making changes? How much of that code base will become dead code by the time they’re done making those changes, and how will they find it? That is of course, if they ever do finish making those changes.
The fear of making these kind of changes to a large JavaScript code base stems from the fact Ajax development has poor tool support. And the nightmare doesn’t end there… another big problem is writing efficient JavaScript code for your Ajax application.
In the days where desktop applications were written using GUI libraries in languages like C/C++, this wasn’t as much of a concern since we could depend on the compiler to remove dead code, perform function inlining, optimize loops, and provide the many other benefits that come with strongly typed languages. JavaScript doesn’t provide this luxury. What’s coded is what’s run, with no intermediate steps to optimize what’s written.
However, there is hope in the form of the Google Web Toolkit (GWT). This tutorial will focus on creating Ajax applications using GWT by going through a sample application and explaining the various moving parts in GWT application development.
The Google Web Toolkit: Bringing software engineering to Ajax development
GWT allows developers to write Ajax applications using the Java programming language. The technology that enables this is the GWT compiler, which compiles Java code into equivalent browser-compliant JavaScript. GWT’s proposition is that rather than waiting for developer tools to come to Ajax, why not use the robust, mature, time-tested tools that already exist for strongly typed languages like Java? Besides the obvious advantage of leveraging existing tools and IDEs, the approach of using Java to write Ajax applications solves all the problems described above.
As previously discussed, browsers can make Ajax developers’ lives difficult because of their differing DOM implementations. With GWT, this is no longer an issue thanks to the GWT compiler. The GWT compiler translates Java code into equivalent browser-compliant JavaScript. Write the application once in Java, and let GWT take care of the rest to create an Ajax app that will” just work” regardless of the browser a user has chosen.
Another major issue that Ajax developers are facing, particularly in the enterprise domain, is the difficulty in managing a large JavaScript code base. Because GWT client code is now written in Java, developer teams are able to apply traditional software engineering principles to keep code cohesive and modular so they know exactly where to go when they need to make changes. On top of this, developers can use their favorite IDE tools to make code changes easier.
However, when lower level JavaScript functionality is needed, or external JavaScript files need to be included, developers easily include JavaScript code using GWT’s JavaScript Native Interface (JSNI). (See the GWT homepage for more info on JSNI.)
GWT also ships with a hosted mode browser, which allows developers to interact with their application without it having been translated into JavaScript. When running in hosted mode, the Java Virtual Machine (JVM) is actually executing their application code as compiled Java bytecode, using GWT plumbing to automate an embedded browser window.
The hosted mode browser displays the latest application code so you can see how your code changes affect application design. What’s more, because hosted mode uses a compiling class loader, hitting the Refresh button shows the latest code changes in the hosted mode browser window. By remaining in the traditional” code-test-debug” cycle, hosted mode is the most productive way to develop Web 2.0 applications quickly and effectively.
The core goal of Ajax is to provide better user experiences. GWT embraces this and makes better user experience central to GWT application development, employing many techniques to speed up app loading and response times.
For one, the GWT compiler obfuscates the Java code that gets translated to JavaScript so developers are left with the smallest script size possible. What’s more, GWT uses a bootstrap model that only requires the client browser to download the JavaScript required to run the GWT application on that specific browser.
This is possible because the GWT compiler generates unique combinations of GWT application code on a per browser basis. GWT also supports internationalization, and also generates combinations of a GWT application on a per locale basis (e.g. ” MyApp for Firefox in English”, ” MyApp for Firefox in French”, ” MyApp for Internet Explorer in English”, etc…).
This way, rather than have French-speaking Firefox users download a wad of JavaScript that includes irrelevant code that handles Internet Explorer specifics and the English locale, the user only need to download a concise, stripped down combination of the GWT application code that is catered to the Firefox browser and a French locale.
The bootstrap process also works in such a way that, unless the application code changes, the application may be cached forever by the browser. This means that once a user browses to a GWT application for a first time, subsequent visits will have close to instantaneous startup time. If the application changes, a simple redeploy of the GWT application files on the server allows GWT to make sure users get the latest version the next time they visit the site. We’ll talk more about this later.
Also, in addition to obfuscating JavaScript code, since the client code is written in a strongly typed language, the GWT compiler also applies optimization techniques that can’t be applied to scripting languages. This means that GWT client code isn’t just obfuscated, it’s also optimized: the GWT compiler performs dead code removal, function inlining, and other techniques to make sure the code is stripped down to the most efficient size possible.
The list of performance enhancing features goes on, like the ImageBundle component that sends an application’s image resources to the client in one request rather than have users wait for an HTTP request roundtrip for each image. GWT applications are engineered to be very fast, maximizing the value of Ajax apps: better user experiences.
Getting Started with the Google Web Toolkit
After hearing about Web 2.0, all that it promises and how GWT makes it easier, it’s time to get our feet wet with GWT application development. Let’s begin by building a quick sample application using GWT.
Before we start, you’ll need to meet a couple of prerequisites.
1) Install the Java SDK. Make sure you have a recent Java SDK installed (JDK 1.4 and up). If you don’t already have an SDK installed, you can download and install it from the Sun Developer Network.
Once you’ve installed the SDK, make sure to set your JAVA_HOME environment variable to the SDK install directory. On Linux or Mac OS X, use export JAVA_HOME=your_sdk_install_dir
. On Windows, use set JAVA_HOME=your_sdk_install_dir
.
2) Download and unzip the Google Web Toolkit package. You can download the Google Web Toolkit package for your operating system at the GWT download page.
Once you’ve downloaded the package, you can extract it by executing the following command in a terminal: tar xvzf gwt-linux-1.4.60.tar.gz
on Linux, or use tar xvzf gwt-mac-1.4.60.tar.gz
for Mac.
If you’re using the Windows platform you can extract the gwt-windows-1.4.60.zip package using an extractor facility like WinZip.
Let’s build a GWT application!
We’ll need an example to start building our GWT application. It seems like a good time to open a FruitMart Web application, where users can order fruits (apples, bananas, and oranges) all year round, no matter where they are in the world.
The FruitMart works in the following way: shoppers will have a fruit basket in which they can add any fruits they pick from the fruit stands. Once they’ve finished making their choices, they can submit they order and expect an express delivery of fruits to their door. For the purposes of this tutorial, we won’t cover user authentication and payment processing.
The FruitMart will have three fruit stands, one selling different types of apples, another selling different types of bananas and the last selling different types of oranges.
Every GWT application requires a set of project files that are used to compile, deploy and run the application in hosted mode. These are:
GWT ships with an applicationCreator utility that automatically creates the project files for new applications. You’ll find the applicationCreator utility in the directory where you unpacked your GWT distribution. To create the FruitMart project files, change to the directory where you unpacked GWT and run the following command in a terminal:
./applicationCreator-out some_directory/FruitMart com.google.fruitmart.client.FruitMart
You’ll should see output after running the command indicating that the directories and directories have been created.
You’ll notice that the applicationCreator created specific directories in addition to the FruitMart GWT project files. These directories were created in accordance with GWT’s recommended project structure. That is:
The GWT compiler expects to find client-side source files in the client sub-package by default. You can specify more directories containing client-side source files and sub-packages by adding source entries in the FruitMart.gwt.xml file, but in this case the client package will no longer be considered by default and you will need to add an explicit source entry to tell the GWT compiler that the client package also contains translatable source code. The same concept applies for directories containing public resources, where you would use the public tag to specify more directories containing public resources.
Before getting into module XML configuration, let’s take a deeper look at the GWT project files that the applicationCreator generated.
The application entry point class is where your application begins. Keep in mind that an Ajax application is typically a single application page whose DOM structure is changed as a result of user actions. For example, let’s say an application loads and displays a simple” Start” button widget and has a click listener attached. Once clicked, we might code the click listener to do something like trigger the application to clear the button from the page and bring up a panel widget that has some relevant information displayed in it. In GWT, the application page is represented by the RootPanel class, where widgets are added and removed from the RootPanel class.
The FruitMart.java file created by the applicationCreator includes some” Hello World” sample code demonstrating this. You can launch the application by running the FruitMart-shell hosted mode launch script generated by the applicationCreator. Try making some changes and see how it affects the application in hosted mode.
FruitMart.gwt.xml is the module XML file for the FruitMart application. This file resides in the project root path. The module XML file is where GWT compiler and hosted mode directives are declared. The most essential element in the Fruitmart.gwt.xml file is the entry point class entry, which tells the GWT compiler where to find the entry point class. Module XML supports a number of other entry types to specify other project specifics. We will be modifying the module XML file as we go along.
The application host HTML page is exactly what it sounds like. The FruitMart.html is the host HTML page, so unsurprisingly, it resides in the public subdirectory. This is also where the GWT application bootstrap process takes place. Now that we have a clearer understanding about each of the GWT project files, let’s start coding.
Creating the UI Layout
The first thing to do is to clear out the sample code generated by the applicationCreator
. Open the FruitMart.java file and clean it up so that it looks like the code in Sample 1:
We’ll also have to clean out the application host HTML page. Open the FruitMart.html
file and clear it so that it looks like the code found in Sample 2. Looking at the screenshot, what we need is one vertical panel containing two horizontal panels: the first would be the top panel displaying the FruitMart title, the second would be where the fruit mart stands and the user’s fruit basket are displayed. Let’s go ahead and create those panels as in Sample 3 and remember to update your import
statements as in Sample 4.
Keep in mind that the hosted mode launch script and the hosted mode browser are indispensable tools during GWT application development. Run the FruitMart-shell
launch script to see how the application looks so far. The hosted mode browser uses a compiling classloader, so pressing” Refresh” will pick up the latest code changes. Refresh early and often to see how the code changes affect the application in hosted mode.
Including external stylesheets (CSS)
The next step is to add the FruitMart label, and apply some styling. This brings us to the topic of including external CSS in our GWT application. To include an external CSS file, you’ll need to create it in the public folder of our GWT application. Create the fruitmart.css file in the directory: some_dir/FruitMart/src/com/google/fruitmart/public/fruitmart.css
Now let’s create some style rules for our top panel and FruitMarket label:
.fm-TopPanel { background-color: LightSkyBlue; } .fm-FruitMartLabel { font-family: arial, sans-serif; font-size: xx-large; font-weight: bold; font-stretch: extra-expanded; }
Now that we have our CSS rules defined, include the stylesheet in your application. Let’s go to the FruitMart.gwt.xml file and include fruitmart.css into the application.
<module> <!-- Inherit the core Web Toolkit stuff. --> <inherits name='com.google.gwt.user.User'/> <!-- Specify the app entry point class. --> <entry-point class='com.google.fruitmart.client.FruitMart'/> <stylesheet src="fruitmart.css" /> </module>
Notice that we don’t need to specify the whole path to fruitmart.css, because GWT expects to find any external resources in publicly accessible paths. In this case, we’ve used the default public path so the GWT compiler knows where to find the stylesheet.
Finally, let’s apply the new CSS style rules to our topPanel and fruitMartLabel widgets in FruitMart.java. Add the styles via the setStyleName methods just after creating the topPanel and fruitMartLabel widgets:
topPanel.setStyleName("fm-TopPanel"); ... fruitMartLabel.setStyleName("fm-FruitMartLabel");
The next two pieces to finishing up the FruitMart layout is to include the fruit stands and the fruit basket. From the screenshot, we can see we have a tab panel, where each tab represents a fruit stand. On the right hand side we see a vertical panel representing the fruit basket. Let’s create those panels now.
First, the fruit stands, and remember to include the import statement as in Sample 5. Now we’ll add tabs to the tab panel, and create and add the tab content. The next question is what content are we going to add to each of the tabs in the tab panel? We want to add another panel with the different fruits listed on it. So we want a set of widgets that each list the name of the fruit, a drop-down menu for users to select how many they’d like to pick, and a button to confirm that they want to pick the fruit.
It also seems like we want the same functionality for each of the fruits that our FruitMart application offers… there’s probably a reusability pattern we can apply here. Let’s come back to this part a bit later and move on to the fruit basket.
The fruit basket seems a lot more straightforward. Looking at the screenshot, we need to add a” Fruit Basket” panel and add an appropriate label to it. We also need to add a” Confirm” button that allows the user to confirm their order. Let’s create the top level fruit basket panel using the code from Sample 6.
Next, create labels for each item and item type in the basket. Next to each fruit basket item type, we display the name of the item type and the number of those fruits the user has picked. However, this presents a similar case for reusability as the one we saw for the fruit stands panel, because we want the same functionality for each item type.
This leads us to the topic of building custom widgets. In GWT, you can build custom widgets using the Composite pattern. Let’s start with the widgets that we want to create for each of the fruit items in the fruit basket. In GWT, when creating custom widgets our widget classes must extend the com.google.gwt.user.client.ui.Composite
abstract class.
Create a new source file called FruitBasketItemTypeWidget.java in the com.google.fruitmart.client package, and have it extend the com.google.gwt.user.client.ui.Composite abstract class.
package com.google.fruitmart.client; import com.google.gwt.user.client.ui.Composite; public class FruitBasketItemTypeWidget extends Composite { }
Now, define the FruitBasketItemTypeWidget
member variables and constructor. We’re looking to create a horizontal panel that contains two labels: one displaying the name of the fruit basket item type and the other displaying the quantity. In the constructor, we’ll set the panel and label size and spacing. We’ll also initialize the panel as the element that is being wrapped by this custom widget from Sample 7.
Everything in the code snippet above should be straightforward. The only part that might be a little unclear is the call to initWidget(fruitBasketItemTypePanel). This method sets the widget to be wrapped by the composite. It must be called exactly once per composite before the custom widget can be added to a panel or any Widget method calls can be made to it.
The last thing we need to do for the FruitBasketItemTypeWidget class is add setters to set the text for the fruitBasketItemTypeDisplayName and fruitBasketItemTypeQuantity labels:
public void setFruitBasketItemTypeDisplayName(String displayName) { fruitBasketItemTypeDisplayName.setText(displayName + " : "); } public void setFruitBasketItemTypeQuantity(String quantity) { fruitBasketItemTypeQuantity.setText(quantity); }
The last custom widget we need to create is the fruit basket item widget. The fruit basket item widget is just a panel with a label displaying the name of the item and an arbitrary number of fruit basket item type widgets. This should be a pretty simple task. The only tricky part is to include a method that allows us to add an arbitrary number of fruit basket item types to the widget. Create the FruitBasketItemWidget.java file in the com.google.fruitmart.client
package and build out the code according to the needs discussed so far. It should look like Sample 8:
Finally, we can move on to the custom widgets we need to create for the fruit stands panel. All we need to do is create fruit stand panels with a listing of each type of fruit item. Each fruit item type will be a widget that displays the name of the fruit item type, a drop-down box allowing users to select how many of fruits the user wants to pick, and a button to let the user confirm that they want to pick the fruit. For the purposes of this tutorial, we’ll assume that the user has a choice of one to five fruits each time they pick a type of fruit item.
Create the FruitItemTypeWidget class in the com.google.fruitmart.client package. Then proceed to build the composite widget. Following the same concepts about custom widget creation above, your code should look similar to Sample 9:
Next, create the fruit stand panel that will contain the fruit item type widgets. We also need a method that will allow us to add fruit item type widgets to the fruit stand panel. Again, this is a straightforward process. Create the FruitStandPanel
class in the com.google.fruitmart.client
package and finish up this last com, the last step to completing our application UI layout is adding our newly created composites to the entry point class. Re-open the FruitMart.java file.
Reviewing the code, we can see that we’ve already added the fruit stands tab panel and the fruit basket panel. The only thing left to do for the fruit stands tab panel is add the tabs, and add a new fruit item type widget for each tab as the tab content. Next we need to start adding each of the fruit basket item widgets.
Note that in creating each of the fruit basket item widgets, we will also need to create each of the fruit basket item type widgets. This would be an ideal situation for Factory classes to create these widgets: one factory to create the fruit basket item widgets, and another to create the fruit basket item type widgets. For this tutorial, however, we’ll go for the naive approach and code the creator methods in the FruitMart
class. Let’s write this code now and factor it into a private method called attachFruitBasketItems
as in Sample 10. Once again, make sure to update your import statements:
import java.util.ArrayList; import java.util.Iterator; import java.util.List;
Now we need to implement similar functionality to fill the fruit stands tab panel with the fruit item and fruit item type widgets. This should also be a straightforward process, following the same style used for the fruit basket panel. Make those changes and once you’re done the code should look something like the code snippet in Sample 11. Now that we’re done with the UI design for our application, let’s add some final CSS styling rules to complete the finishing touches.
First, let’s style the” Fruit Basket” label. This requires creating the styling rules in the fruitmart.css file, and then applying the style to the fruit basket label.
In fruitmart.css:
.fm-FruitBasketLabel { font-family:arial, sans-serif; font-size: large; font-weight: bold; font-stretch: expanded; }
In FruitMart.java, right after the creation of fruitBasketLabel in the onModuleLoad method:
fruitBasketLabel.setStyleName("fm-FruitBasketLabel");
We also want to bold and enlarge the fruit basket item display names. Let’s apply similar styling rules to the fruitBasketItemDisplayName label in the FruitBasketItemWidget.java file. In fruitmart.css add:
fm-FruitBasketItemLabel { font-family: arial, sans-serif; font-size: medium; font-weight: bold; }
In FruitBasketItemWidget.java, in the class constructor add fruitBasketItemDisplayName.setStyleName(”fm-FruitBasketItemLabel”);
The last element to style is the tab panel. The CSS styling rules for the com.google.gwt.user.client.ui.TabPanel
and com.google.gwt.user.client.ui.TabBar classes are predefined (e.g. .gwt-TabPanel, .gwt-TabBar). We will borrow the TabPanel styles from the KitchenSink sample application that ships with the GWT distribution.
The KitchenSink sample can be found at gwt_dist_dir/gwt-linux-1.4.60/samples/KitchenSink. Copy the .gwt-TabPanel
and .gwt-TabBar defined in the KitchenSink.css file and into the fruitmart.css file. Notice that because the TabPanel styles are predefined, we don’t need to explicitly call the setStyleName method on the TabPanel to apply the CSS styling rules.
At this point of the tutorial, the FruitMart application should look identical to the screenshot. Try running the hosted mode launch script to see how the application looks in the hosted mode browser.
Wiring Event Listeners
Finally, to finish up our FruitMart application we’ll hook up event listeners to the fruit stand” Pick” and the fruit basket” Confirm” buttons.
The event listener we’ll want to add to the” Pick” button is the com.google.gwt.user.client.ui.ClickListener
which, upon receiving a click event, will add the fruit picked to the fruit basket. This sounds simple enough, but there is a trick involved.
The problem is, depending on which fruit item type widget’s” Pick” button was clicked, the fruit that gets added to the fruit basket will vary. For example, if the” Red Delicious” apple item type’s” Pick” button was clicked, the application should update the” Red Delicious” apple count in the fruit basket. We’ll need a way to associate the click listeners that are hooked up to the pick button to the appropriate fruit basket item types.
Let’s leave this on hold for now and move on to the more straightforward case of the fruit basket’s” Confirm” button. Here we want to display a message notifying the user that the order has been submitted and a fruit basket will be delivered at their door. Let’s add a click listener to the” Confirm” button now to make that happen. Open the FruitMart.java file and add an anonymous click listener to the” Confirm” button. This is shown in Sample 12 online. Remember to add the import for ClickListener, Widget and Window:
import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.ClickListener; import com.google.gwt.user.client.ui.Widget;
Now let’s get back to hooking up click listeners to the” Pick” buttons. Solving this problem isn’t as straightforward as adding the click listener for the” Confirm” button, because we have to find a way to associate appropriate click listeners to the right” Pick” buttons. Additionally, the click listeners hooked up to the fruit item type widget’s” Pick” buttons must update the fruit basket item type quantity whenever they receive a click event.
This presents a situation where one widget needs to communicate with another, so we need to determine where the code linking the two widgets should go. This kind of situation seems ideally suited to the Mediator pattern, where a mediating class is responsible for passing messages between two or more widgets.
With this design pattern in mind, the solution becomes a bit clearer. We would add appropriate click listeners to each of the” Pick” buttons as each fruit item type widget is created, and on click, the listeners would call methods defined in the mediator class that would update the proper fruit basket item type quantity. This would be a suitable solution for the current state of the application, but the code would get a little messy, and it would take away from the system’s cohesion. This solution probably wouldn’t scale to a growing application.
A better approach may be to use an event-driven architecture. In an event driven architecture, events can be fired from various system components, and listeners are registered to these events and are updated whenever the event is fired. The event information is passed along from the firing component and gets picked up by event handlers that the registered listeners have defined. GWT allows for this kind of architecture.
Take the fruit item type widgets, which contain the” Pick” button. In the event-driven model, it seems these widgets would be the ones firing” Pick” events and updating registered listeners whenever a” Pick” event is fired. These widgets would also be the players who construct the pick events.
Next we identify the listeners: the widgets whose quantities get updated whenever a pick event occurs. The fruit basket item type widgets are also the players that will define Pick event handlers. Given this, the fruit item type widgets will be maintaining the registry list of fruit basket item type widget listeners and update them each time a pick event occurs.
This model works, now it’s time to implement it. We need a way to identify the fruit item type widgets as those who fire pick events. Define a FiresPickEvents
interface that will denote classes that fire pick events. Any class that fires pick events must register pick event handlers, so define the interface with methods that add and remove pick event listeners. Let’s create this interface.
At this point, you should probably create a new package to better structure our application code. However for sake of simplicity, we will create the interface in the com.google.fruitmart.client
package.
package com.google.fruitmart.client; public interface FiresPickEvents { public void addPickHandler(PickHandler handler); public void removePickHandler(PickHandler handler); }
Next, let’s create the PickHandler
interface:
package com.google.fruitmart.client; import com.google.gwt.user.client.EventListener; public interface PickHandler extends EventListener { public void onPickEvent(PickEvent event); }
Next, we need to create the PickEvent
class. First we need to identify the information that the event should contain. We want the quantity of the fruit item type picked. We also need to know the sender itself. Now that we know what information the event should contain, let’s create the PickEvent
class, as in Sample 13.
Finally, we need to make our widgets implement these new interfaces so that they can play their new roles. First, let’s update the fruit item type widget. We need to make it implement the FiresPickEvents
interface, and we also need to add a list of pick event handlers to register event listeners as in Sample 14 and make the fruit basket item type widget implement the PickHandler
interface as in Sample 15.
At this point, we’ve finished setting up the event wiring between our widgets. Now we need to make the wires active. This means we need to register the fruit basket item type widgets to their respective fruit item type widgets. Because our widgets are created independently, we’ll need to retain the information about which fruit basket item widget should register for which fruit item type widget after their creation. To hold this information, we could introduce a HashMap that uses the fruit item type names as the key (since this is a linking factor between our widgets) and holds the event dispatchers as a value.
To make this happen we will first need to create the HashMap
:
import java.util.HashMap; ... public class FruitMart implements EntryPoint { private HashMap pickEventsMap = new HashMap(); ...
Then add each of the fruit item types to the pickEventsMap as event dispatchers during their creation in the createFruitItemType
method and register each fruit basket item type as a listener to the pick event dispatchers in the pickEventsMap as in Sample 16.
And finally, the last step to giving power to the wired event system is to actually trigger the event and alert the listeners. This is done by adding a click listener to the” Pick” button which, once clicked, will trigger the click listener to create a pick event and alert each of the pick event listeners. Open the FruitItemTypeWidget class and add the click listener to the” Pick” button as in Sample 17. Don’t forget to add the imports:
import com.google.gwt.user.client.ui.ClickListener; import com.google.gwt.user.client.ui.Widget;
This was the last bit of code we needed to write for this tutorial. Now we have a fully functional application! However, we’ve only been viewing it in hosted mode, so let’s deploy it on a live server.
Deploying a GWT application
Deploying a GWT application is simple. The only thing you need to do is host the GWT generated files on a public path on your Web server and have the host HTML application page include your application’s bootstrap JavaScript file.
The first step is to generate the GWT application files. You can use the FruitMart-compile script to generate these files. Open a terminal and change to your some_dir/FruitMart project path. Run the FruitMart-compile script by executing ./FruitMart-compile
and you should see the following output after running the command:
Output will be written into some_dir/FruitMart/www/com.google.fruitmart.FruitMart Copying all files found on public path Compilation succeeded
Take a look at the output directory. You’ll find all the files that were in the project’s public folder, such as the FruitMart.html page and the fruitmart.css file. You’ll also find files following a 12AB498CEE312AD312CBA3.cache.js pattern. These are the stripped down, browser-optimized combinations of our GWT application.
The”. cache” in the file is to note that these files can safely be cached by your client’s browser forever. If ever your GWT application code changes and you redeploy that changes to your Web server, the GWT bootstrap process will do the right thing in fetching the updated 12AB498CEE312AD312CBA3.cache.js- type files to load your application.
The other critical file you’ll find in the output directory is com.google.fruitmart.FruitMart.nocache.js. This is the GWT application bootstrap file. You will need to include it via a <script> tag in the application host HTML page. In the case of the FruitMart application, the FruitMart.html application host page should already include the proper <script> tag. The”. nocache” indicates that this file should never be cached. It’s responsible for all the magic that goes on under the hood to load the right combination of your GWT application for your client’s browser.
All that’s required to deploy your application is to host the GWT generated files and the application host HTML page on the Web server.
Let’s take a break
This tutorial covered a lot of material. However, there is still more to cover before you can go on to develope full-blown applications with confidence: server-side integration. That is, how to integrate GWT code with server-side code, completing the client-server architecture. GWT was designed so as not to be a bottleneck on any front, client or server side, and with an open architecture to facilitate customizations to suit developers needs easily and intuitively.
GWT also provides a convenient Request Builder class that allows your client code to build and send requests to any service you have defined on your server-side. What’s more, GWT also provides its own RPC mechanism to allow developers to create services and easily integrate their GWT client-side code with these services. This will be the topic of the second part of this tutorial.
As mentioned earlier, another major benefit of GWT development is the fact that developers can leverage existing IDEs and tools. GWT development also allows developers to leverage existing Web application frameworks that have made Web development easier. The second part of this tutorial will also include detailed instructions on integrating GWT with popular Web application frameworks, such as Spring and Struts. The next tutorial aims to complete the picture showing how GWT application development makes moving enterprise-grade Web applications to the Web 2.0 world easier.
Последние комментарии
47 минуты 19 секунды назад
59 минуты 54 секунды назад
1 час 1 минута назад
1 час 17 минуты назад
1 час 27 минуты назад
2 часа 3 минуты назад
2 часа 22 минуты назад
2 часа 59 минуты назад
3 часа 51 минуты назад
8 часа 47 минуты назад