![]() |
|
![]() |
![]() |
The Google Web Toolkit (GWT) is a unique entry among AJAX toolkits in that it is built for Java developers who may not know the latest web coding standards, but want to harness the power of AJAX. Until now, AJAX toolkits or frameworks have consisted of Javascript widget libraries and implementing them involved detailed knowledge of Javascript, HTML and CSS. With GWT's Java-centric approach, much of the pain has been removed with Swing-like creation of the front-end code, real debugging from within your favorite IDE and guaranteed cross-browser support.
The GWT download comes with two scripts:
projectCreator and applicationCreator.
The projectCreator script can be thought of
as an Eclipse
project
creator as it is used to create an application directory, Eclipse
classpath and project files. All output is in blue.
${path_to_gwt}/projectCreator -eclipse SimpleHelloWorld -out SimpleHelloWorld
Created directory SimpleHelloWorld/src
Created directory SimpleHelloWorld/test
Created file SimpleHelloWorld/.project
Created file SimpleHelloWorld/.classpath
The applicationCreator script generates a src/
directory, a
moduleName-compile script and an moduleName-shell script. I
use
the convention of 'moduleName' here to denote that GWT refers to
an application as a module. The src/
directory is
comprised
of the package name given during creation, some stubbed out
classes and an XML file in the form of moduleName.gwt.xml.
This XML file marks the entry point to
the
application. The compile script sends all class files and
generated JavaScript to the www/
directory. The shell script is used for debugging purposes
and
launches a GWT embedded browser that is actually executing Java
bytecode — this is generally known as Hosted
mode.
Support
for hosted mode is currently only available for Windows and Linux
users; however, there are rumors of an OS X version on the
horizon.
The output from using the applicationCreator
script looks like this:
${path_to_gwt}/applicationCreator -out SimpleHelloWorld
com.ociweb.client.SimpleHelloWorld
Created directory SimpleHelloWorld/src
Created directory SimpleHelloWorld/src/com/ociweb
Created directory SimpleHelloWorld/src/com/ociweb/client
Created directory SimpleHelloWorld/src/com/ociweb/public
Created file SimpleHelloWorld/src/com/ociweb/SimpleHelloWorld.gwt.xml
Created file
SimpleHelloWorld/src/com/ociweb/public/SimpleHelloWorld.html
Created file
SimpleHelloWorld/src/com/ociweb/client/SimpleHelloWorld.java
Created file SimpleHelloWorld/SimpleHelloWorld-shell
Created file SimpleHelloWorld/SimpleHelloWorld-compile
Modules are the configuration files within the GWT framework that define the entry point to the application. A single GWT module consists of an XML file that binds the necessary files for a given GWT function. Module definitions are flexible; they allow for inheritance, Javascript and CSS injection, package filtering, resource path configuration and multiple modules - as long as they are compiled separately.
Below is the generated SimpleHelloWorld.gwt.xml
file.
By
default, modules denote one entry point and inherit
from the User module.
<module>
<!-- Inherit the core Web Toolkit stuff. -->
<inherits name='com.google.gwt.user.User'/>
<!-- Specify the app entry point class. -->
<entry-point class='com.ociweb.client.SimpleHelloWorld'/>
</module>
Here is the client java class (SimpleHelloWorld.java)
that will be
converted into Javascript. While this code is a bit
trivial,
it demonstrates some basic concepts of GWT GUI building. See
the
comments
inline with the source.
package com.ociweb.client;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;
/**
* Entry point classes define <code>onModuleLoad()</code>.
*/
public class SimpleHelloWorld implements EntryPoint {
/**
* This is the entry point method and MUST be implemented.
*/
public void onModuleLoad() {
final Button button = new Button("Click me");
final Label label = new Label();
button.addClickListener(new ClickListener() {
public void onClick(Widget sender) {
if (label.getText().equals(""))
label.setText("Hello World!");
else
label.setText("");
}
});
/*
Assume that the host HTML has elements defined whose
IDs are "slot1", "slot2". In a real app, you probably would not
want to hard-code IDs. Instead, you could, for example, search for
all elements with a particular CSS class and replace them with widgets.
*/
RootPanel.get("slot1").add(button);
RootPanel.get("slot2").add(label);
}
}
One of the key benefits of the GWT is debugging a user interface from
within your
IDE. To launch a debugging session in eclipse follow
these steps:
GWT's embedded browser:

Debugging client side code from my favorite IDE:
Loosely speaking, the GWT considers a service to be any
server-side
code that is invoked from a client. The GWT provides an RPC
mechanism for asynchronous calls removing the need for direct access to
the XMLHttpRequest Object, although
access to this object is obtainable
if desired. GWT accomplishes this through the use of a
configuration file (moduleName.gwt.xml),
two interfaces per
service
(synchronous and asynchronous) and a server-side
implementation
of the synchronous interface.
The user types in the top text box and the output from the service call is displayed in the textbox using blue characters - all without refreshing the page.

The directory structure for the service components looks like this:
com.ociweb.CopyText.gwt.xml
com.ociweb.client.CopyText.java
com.ociweb.client.CopyTextAsync.java
com.ociweb.server.CopyTextImpl.java
CopyText.gwt.xml:
<module>
<!-- Inherit the core Web Toolkit stuff -->
<inherits name='com.google.gwt.user.User'/>
<!-- Specify the application entry point class. -->
<entry-point class='com.ociweb.client.CopyText'/>
<!-- The servlet implementation to map our service to. -->
<servlet path='/copyTextService'
class='com.ociweb.server.CopyTextServiceImpl'/>
</module>
RemoteServiceServlet.
package com.ociweb.client;
import com.google.gwt.user.client.rpc.RemoteService;
public interface CopyTextService extends RemoteService {
public String copyText(String s);
}
Asynchronous interface — method signature
similar to synchronous with additional
method parameter of type
AsyncCallback and a return type of void.
package com.ociweb.client;
import com.google.gwt.user.client.rpc.AsyncCallback;
public interface CopyTextServiceAsync {
public void copyText(String s, AsyncCallback callback);
}
CopyTextServiceImpl is the service
implementation. The RemoteServiceServlet
is the base class for RPC service implementations
and controls serialization of requests and responses. This
implementation class returns the input string typed by the user.
package com.ociweb.server;
import com.google.gwt.user.client.rpc.IsSerializable;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.ociweb.client.CopyTextService;
public class CopyTextServiceImpl extends RemoteServiceServlet
implements CopyTextService, IsSerializable {
private static final long serialVersionUID = 1L;
public String copyText(String s) {
System.out.println("Text received:"+s);
return s;
}
}
CopyText - This is the client code
that gets converted into
Javascript and hosts the call to the services as well as creating the
user interface
package com.ociweb.client;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.KeyboardListener;
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;
import com.google.gwt.user.client.ui.Widget;
/*
* Entry point classes define <code>onModuleLoad()</code>.
*/
public class CopyText implements EntryPoint {
VerticalPanel vPanel;
TextBox textResult;
/*
* This is the entry point method.
*/
public void onModuleLoad() {
final TextBox text = new TextBox();
final Label label = new Label("Type text here:");
textResult = new TextBox();
//creating Async object using GWT.create() for callback
final CopyTextServiceAsync copyTextService = (CopyTextServiceAsync)
GWT.create(CopyTextService.class);
//service entry entry point, which is defined in moduleName.gwt.xml
ServiceDefTarget serviceTarget = (ServiceDefTarget) copyTextService;
String myUrl = GWT.getModuleBaseURL()+"/copyTextService";
serviceTarget.setServiceEntryPoint(myUrl);
vPanel = new VerticalPanel();
vPanel.add(label);
vPanel.add(text);
text.addKeyboardListener(new KeyboardListener() {
public void onKeyDown(Widget sender, char keyCode, int modifiers) {
}
public void onKeyPress(Widget sender, char keyCode, int modifiers) {
}
public void onKeyUp(Widget sender, char keyCode, int modifiers) {
copyTextService.copyText(((TextBox)sender).getText(),
getCopyTextServiceCallback());
}
});
RootPanel.get("slot1").add(vPanel);
}/* AsyncCallback is the primary interface that a user must
* implement to receive a response from the remote procedure call.
*/
public AsyncCallback getCopyTextServiceCallback() {
return new AsyncCallback() {
public void onFailure(Throwable ex) {
RootPanel.get().add(new HTML(ex.toString()));
Window.alert("The call failed.");
}
public void onSuccess(Object result) {
//Added to support Internet Explorer and Mozilla -
//Safari Worked fine without removing result first
vPanel.remove(textResult);//call to external CSS file
textResult.addStyleName("gwt-TextBox-blue");
textResult.setText(result.toString());
vPanel.add(textResult);
}
};
}
}
The GWT has many benefits other than those previously mentioned, such as: JUnit integration, browser history management, the ability to plugin in custom Javascript (using the Javascript Native Interface), and of course a robust widget library to choose from when building a composite user interface. For these reasons, as well as, the RPC mechanism and code generation, GWT is worth a serious look when developing page-centric web applications such as Google does with its varied web applications.
There are however some problematic areas that any serious implementers should be aware of. The main issue is the non-open source licensing agreement. As a result, any bugs or featured enhancements will have to be fixed by an official GWT release. It's not hard to imagine how this could be a problem. A related issue is backward compatibility. As I've discovered over the course of writing this article, there are no guarantees that future releases will not break current code, nor is there much in the way of documentation letting you know what will break. This brings me to one final issue - the lack of official documentation. While there is some documentation available, it is largely scattered and lacking examples. To remedy this, I found the GWT user group very useful and to that end, the GWT developers are responsive to most if not all issues.
OCI is the leading provider of Object Oriented technology training in the Midwest. More than 3,000 students participated in our training program over the last 12 months. Targeted toward Software Engineers and the development community, our extensive program of over 50 hands-on workshops is delivered to corporations and individuals both throughout the U.S. and internationally. OCI's Educational Services include Group Training events and Open Enrollment classes.
For further information regarding OCI's Educational Services programs, please visit our Educational Services section on the web or contact us at training@ociweb.com.
|
|
|