Está en la página 1de 14

Examining the project components

Let's examine some of the generated files and see how they fit together to form your GWT project.

The module XML file


Open the module XML file, StockWatcher/src/com/google/gwt/sample/stockwatcher/StockWatcher.gwt.xml. It contains the definition of the GWT module, the collection of resources that comprise a GWT application or a shared package. By default, StockWatcher inherits the core GWT functionality required for every project. Optionally, you can specify other GWT modules to inherit from.
<?xml version="1.0" encoding="UTF-8"?> <module rename-to='stockwatcher'> <!-- Inherit the core Web Toolkit stuff. <inherits name='com.google.gwt.user.User'/> -->

<!-- Inherit the default GWT style sheet.

You can change

--> --> -->

<!-- the theme of your GWT application by uncommenting <!-- any one of the following lines. <inherits name='com.google.gwt.user.theme.standard.Standard'/>

<!-- <inherits name="com.google.gwt.user.theme.chrome.Chrome"/> --> <!-- <inherits name="com.google.gwt.user.theme.dark.Dark"/> -->

<!-- Other module inherits

-->

<!-- Specify the app entry point class.

-->

<entry-point class='com.google.gwt.sample.stockwatcher.client.StockWatcher'/> </module>

In the module XML file, you specify your application's entry point class. In order to compile, a GWT module must specify an entry point. If a GWT module has no entry point, then it can only be inherited by other modules. It is possible to include other modules that have entry points specified in their module XML files. If so, then your module would have multiple entry points. Each entry point is executed in sequence. By default, StockWatcher uses two style sheets: the default GWT style sheet, standard.css (which is referenced via the inherited theme), and the application style sheet, StockWatcher.css which was generated by webAppCreator. Later in this tutorial, you'll learn how to override the default GWT styles.

The Host Page


Open the host page, StockWatcher/war/StockWatcher.html. The code for a web application executes within an HTML document. In GWT, we call this the host page. For example, the host page for the StockWatcher project is StockWatcher.html. The host page references the application style sheet, StockWatcher.css. The host page references the path of JavaScript source code (generated by GWT) responsible for the dynamic elements on the page. The contents of the entire body element can be generated dynamically, for example, as it is with starter application. However, when you implement the StockWatcher application, you will use a mix of static and dynamic elements. You'll create an HTML <div> element to use as placeholder for the dynamically generated portions of the page.

The GWT History Mechanism


GWT's History mechanism has a lot in common with other Ajax history implementations, such as RSH (Really Simple History). The basic premise is to keep track of the application's "internal state" in the url fragment identifier. This works because updating the fragment doesn't typically cause the page to be reloaded.

This approach has several benefits:


It's about the only way to control the browser's history reliably. It provides good feedback to the user. It's "bookmarkable". I.e., the user can create a bookmark to the

current state and save it, email it, et cetera.

History Tokens
GWT includes a mechanism to help Ajax developers activate browser history. For each page that is to be navigable in the history, the application should generate a unique history token. A token is simply a string that the application can parse to return to a particular state. This token will be saved in browser history as a URL fragment (in the location bar, after the "#"), and this fragment is passed back to the application when the user goes back or forward in history, or follows a link. For example, a history token named "page1" would be added to a URL as follows:
http://www.example.com/com.example.gwt.HistoryExample/HistoryExample.html#page1

When the application wants to push a placeholder onto the browser's history stack, it simply invokes History.newItem(token). When the user uses the back button, a call will be made to any object that was added as a handler with History.addValueChangeHandler(). It is up to the application to restore the state according to the value of the new token.

Example
To use GWT History support, you must first embed an iframe into your host HTML page.
<iframe src="javascript:''" id="__gwt_historyFrame" style="width:0;height:0;border:0"></iframe>

Then, in your GWT application, perform the following steps:

Add a history token to the history stack when you want to enable a Create an object that implements the ValueChangeHandler

history event.

interface, parses the new token (available by calling ValueChangeEvent.getValue()) and changes the application state to match. The following short example shows how to add a history event each time the user selects a new tab in a TabPanel.
import com.google.gwt.core.client.EntryPoint; import com.google.gwt.event.logical.shared.SelectionEvent; import com.google.gwt.event.logical.shared.SelectionHandler; import com.google.gwt.event.logical.shared.ValueChangeEvent; import com.google.gwt.event.logical.shared.ValueChangeHandler; import com.google.gwt.user.client.History; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.TabPanel;

/** * Entry point classes define <code>onModuleLoad()</code>. */ public class BrowserHistoryExample implements EntryPoint {

TabPanel tabPanel; /** * This is the entry point method. */

public void onModuleLoad() { tabPanel = new TabPanel();

tabPanel.add(new HTML("<h1>Page 0 Content: Llamas</h1>"), " Page 0 "); tabPanel.add(new HTML("<h1>Page 1 Content: Alpacas</h1>"), " Page 1 "); tabPanel.add(new HTML("<h1>Page 2 Content: Camels</h1>"), " Page 2 ");

tabPanel.addSelectionHandler(new SelectionHandler<Integer>(){ public void onSelection(SelectionEvent<Integer> event) { // TODO Auto-generated method stub History.newItem("page" + event.getSelectedItem()); }});

History.addValueChangeHandler(new ValueChangeHandler<String>() { public void onValueChange(ValueChangeEvent<String> event) { String historyToken = event.getValue();

// Parse the history token try { if (historyToken.substring(0, 4).equals("page")) { String tabIndexToken = historyToken.substring(4, 5); int tabIndex = Integer.parseInt(tabIndexToken); // Select the specified tab panel tabPanel.selectTab(tabIndex); } else {

tabPanel.selectTab(0); }

} catch (IndexOutOfBoundsException e) { tabPanel.selectTab(0); } } });

tabPanel.selectTab(0); RootPanel.get().add(tabPanel); } }

What's with all the cache/nocache stuff and weird filenames? During its bootstrap process, a Google Web Toolkit application goes through a series of sometimes oddly-named files. These files, generated by the GWT Compiler, usually seem strange to new users. To effectively deploy a GWT application, however, it is necessary to understand these files so that they can be placed appropriately on the web server. These are the important files produced by the GWT Compiler:

<Module Name>.nocache.js (or <Module Name>-xs.nocache.js for <Alphanumeric>.cache.html <Alphanumeric>.gwt.rpc

cross-site script inclusion)


Each of the items above is described below. However, first it's important to understand Deferred Binding since that notion is at the heart of the bootstrap process, so you might want to read this link before continuing.

Before explaining what each file does, it's useful to summarize the overall bootstrap procedure for a GWT application: 1. 2. The browser loads and processes the host HTML page. When the browser encounters the page's <script src="<Module

Name>.nocache.js"> tag, it immediately downloads and executes the JavaScript code in the file. 3. The .nocache.js file contains JavaScript code that resolves the Deferred Binding configurations (such as browser detection, for instance) and then uses a lookup table generated by the GWT Compiler to locate one of the .cache.html files to use. 4. The JavaScript code in .nocache.js then creates a hidden <iframe>, inserts it to the host page's DOM, and loads the .cache.html file into that iframe. 5. The .cache.html file contains the actual program logic of the GWT application. That's the process in a nutshell. The sections below describe each file in detail. The .nocache.js File In previous versions of GWT, the bootstrap process included the gwt.js file which kicked off the startup procedure. Its responsibility was to scan the host HTML page and gather the information required to locate the next phase in the bootstrap process. Although the formulation using gwt.js still works (read more on this bootstrap process here), it is no longer necessary as much of what used to be done in gwt.js has now been factored to the .nocache.js file. The "nocache" file is where Deferred Binding occurs. Before the application can run, any dynamically-bound code must be resolved. This might include browserspecific versions of classes, the specific set of string constants appropriate to the user's selected language, and so on. In Java, this would be handled by simply loading an appropriate service-provider class that implements a particular interface. To maximize performance and minimize download size, however, GWT does this selection up-front in the "nocache" file. The reason the file is named ".nocache.js" is to indicate that the file should never be cached. That is, it must be downloaded and executed again each time the browser starts the GWT application. The reason it must be re-downloaded each time is that the GWT Compiler regenerates it each time, but under the same file name. If the browsers were allowed to cache the file, they might not download

the new version of the file, when the GWT application was recompiled and redeployed on the server. One of the key features of the "nocache.js" file is a lookup table that maps Deferred Binding permutations to .cache.html filenames. For example, "Firefox in English" and "Opera in French" would both be entries in the lookup table, pointing to different .cache.html files. The .cache.html Files The "cache" files contain your application's logic. If you were to look inside a .cache.html file, you would see that it is JavaScript code wrapped in a thin HTML wrapper. You might wonder why the GWT Compiler doesn&apos;t simply emit it as a JavaScript .js file. The reason for this is that certain browsers do not correctly handle compression of pure-JavaScript files in some circumstances. This would effectively mean that users unfortunate enough to be using such a browser would download the .js file uncompressed. Since the GWT mantra is nocompromise, high-performance AJAX code, the GWT Compiler wraps the JavaScript in an HTML file to wiggle around this browser quirk. The .cache.html files are named according to the MD5 sum of their contents. This guarantees deterministic behavior by the GWT Compiler: if you recompile your application without changing code, the contents of the output will not change, and so the MD5 sums will remain the same. Conversely, if you do change your source code, the output JavaScript code will likewise change, and so the MD5 sums and thus the filenames will change. Because of this uniqueness guarantee, it is safe (and indeed preferable) for browsers to cache these files, which is reflected in their .cache.html file extension. The .gwt.rpc File In previous versions of GWT, if your application used GWT RPC, the types that you wanted to serialize across the wire had to implement the IsSerializable interface. In GWT 1.4, types that implement the java.io.Serializable interface now also qualify for serialization over RPC, with some conditions. One of these conditions is that the types that you would like to serialize over the wire must be included in the .gwt.rpc file generated by the GWT compiler. The .gwt.rpc file serves as a serialization policy to indicate which types implementing java.io.Serializable are allowed to be serialized over the wire. For more details on this and other conditions to use Serializable types in GWT RPC, check out this FAQ.

Summary That is the story behind the somewhat strange GWT file names. There is indeed a method to the madness: nocache.js performs the Deferred Binding resolution and selects a cache file based on the execution context.

3. Embedding the application in the host page


To get the StockWatcher application to run in the browser, you need to embed it in an HTML file, the HTML host page. The host page for the StockWatcher project, StockWatcher.html, was generated by webAppCreator. For the starter application, StockWatcher.html had an empty body element. As a result the Root panel wrapped the entire body element. Everything displayed in the browser was dynamic, built with GWT. If your application had no static elements, you wouldn't need to edit the HTML host page at all. However, for StockWatcher you will use some static HTML text and an image in addition to the dynamic elements. You will embed the GWT application in the browser page using a placeholder, a <div> element named stockList. This implementation strategy is especially useful for embedding GWT into an existing application. 1. 2. 3. 4. 5. Open the host page, StockWatcher/war/StockWatcher.html. In the head element, change the title text to StockWatcher. In the body element, add an <h1> heading, StockWatcher. In the body element, add a <div> element and give it an id of Delete the unneeded elements from the starter project application.

stockList.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8">

<link type="text/css" rel="stylesheet" href="StockWatcher.css">

<title>StockWatcher</title>

<script type="text/javascript" language="javascript" src="stockwatcher/stockwatcher.nocache.js"></script> </head>

<body>

<h1>StockWatcher</h1>

<div id="stockList"></div>

<iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1' style="position:absolute;width:0;height:0;border:0"></iframe>

4. Implementing widgets and panels


Next you will construct the user interface from GWT widgets and panels. Most of the UI is displayed as soon as StockWatcher starts up. So you'll implement them in the onModuleLoad method. In this section, you will: 1. 2. 3. 4. 5. Instantiate each widget and panel. Create the table that holds the stock data. Lay out the widgets using the Add Stock panel and the Main panel. Associate the Main panel with the Root panel. Move the cursor focus to the input box.

You can follow this section of the tutorial step-by-step, or you can cut and paste the entire block of code from the Summary at the end.
package com.google.gwt.sample.stockwatcher.client;

import com.google.gwt.core.client.EntryPoint; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.FlexTable; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.user.client.ui.VerticalPanel;

public class StockWatcher implements EntryPoint {

private VerticalPanel mainPanel = new VerticalPanel(); private FlexTable stocksFlexTable = new FlexTable(); private HorizontalPanel addPanel = new HorizontalPanel(); private TextBox newSymbolTextBox = new TextBox(); private Button addStockButton = new Button("Add"); private Label lastUpdatedLabel = new Label();

/** * Entry point method. */

public void onModuleLoad() { // Create table for stock data. stocksFlexTable.setText(0, 0, "Symbol"); stocksFlexTable.setText(0, 1, "Price"); stocksFlexTable.setText(0, 2, "Change"); stocksFlexTable.setText(0, 3, "Remove");

// Assemble Add Stock panel. addPanel.add(newSymbolTextBox); addPanel.add(addStockButton);

// Assemble Main panel. mainPanel.add(stocksFlexTable); mainPanel.add(addPanel); mainPanel.add(lastUpdatedLabel);

// Associate the Main panel with the HTML host page. RootPanel.get("stockList").add(mainPanel);

// Move cursor focus to the input box. newSymbolTextBox.setFocus(true);

Step4:- Create the following Classes. GWTService.java:- This is the client-side definition of the service.
package org.yournamehere.client; import com.google.gwt.user.client.rpc.RemoteService; public interface GWTService extends RemoteService{ public String myMethod(String s); }

GWTServiceAsync.java:-This is the client side definition. It provides a callback object that enables the asynchronous communication between server and client.
package org.yournamehere.client; import com.google.gwt.user.client.rpc.AsyncCallback; public interface GWTServiceAsync { public void myMethod(String s, AsyncCallback callback); }

GWTServiceImpl.java:-This is the servlet that implements the interface. it provides the functionality for retrieving a quote via RPC.
package org.yournamehere.server; import com.google.gwt.user.server.rpc.RemoteServiceServlet; import org.yournamehere.client.GWTService; public class GWTServiceImpl extends RemoteServiceServlet implements GWTService { public String myMethod(String s) { return "Server says: " + s; } }

GWTServiceUsageExample.java:-This is the interface that will instantiates the service.


package org.yournamehere.client; import import import import import import import import import com.google.gwt.core.client.GWT; com.google.gwt.user.client.rpc.AsyncCallback; com.google.gwt.user.client.rpc.ServiceDefTarget; com.google.gwt.user.client.ui.Button; com.google.gwt.user.client.ui.ClickListener; com.google.gwt.user.client.ui.Label; com.google.gwt.user.client.ui.TextBox; com.google.gwt.user.client.ui.VerticalPanel; com.google.gwt.user.client.ui.Widget;

public class GWTServiceUsageExample extends VerticalPanel { private Label lblServerReply = new Label(); private TextBox txtUserInput = new TextBox(); private Button btnSend = new Button("Send to server"); public GWTServiceUsageExample() {

add(new Label("Input your text: ")); add(txtUserInput); add(btnSend); add(lblServerReply); final AsyncCallback callback = new AsyncCallback() { public void onSuccess(Object result) { lblServerReply.setText((String)result); } public void onFailure(Throwable caught) { lblServerReply.setText("Communication failed"); } }; btnSend.addClickListener(new ClickListener(){ public void onClick(Widget w) { getService().myMethod(txtUserInput.getText(), ca }); } public static GWTServiceAsync getService(){ GWTServiceAsync service = (GWTServiceAsync) GWT.create(GWTServi ce.class); ServiceDefTarget endpoint = (ServiceDefTarget) service; }

llback);

An interface implemented by client-side RPC proxy objects. Cast the object returned from GWT.create(Class) on a RemoteService should be cast to this interface to initialize the target URL for the remote service.
String moduleRelativeURL = GWT.getModuleBaseURL() + "gwtservice endpoint.setServiceEntryPoint(moduleRelativeURL); return service; } }

";

Step4:-Change the entry point of class MainEntryPoint.java.Modify the


onModuleLoad() method of the class to the following :public void onModuleLoad() { RootPanel.get().add(new GWTServiceUsageExample()); }

How to get remote service at client side in GWT ? http://code.google.com/webtoolkit/tutorials/1.6/RPC.html

También podría gustarte