AJAX is a proven candidate for creating interactive Web applications where
Web pages have increased responsiveness and work well even at low bandwidths.
However, because of the fact that it is script based, writing applications in
AJAX becomes an uphill task. And as most of you would agree, more time is spent
on debugging common scripting errors and removing type inconsistencies than
actually looking into application building.
In this article, we will look into Google Web Toolkit (GWT), which allows
coding AJAX applications in Java and then compile it to AJAX scripts. What's
so great about it? You may ask that until you think of the inherent advantages.
For one, you can take up any Java IDE of your choice that would give you greater
control over common errors such as type mismatch. The other being that you work
with an object oriented language that gives modularity to your code which is the
toughest to achieve while writing an application in a scripting language. In
addition to this, you have all the advantages of Java at your service using this
toolkit. So, just in case you are a Java developer and find yourself working for
AJAX code, you can pick up this toolkit and do your work as you did earlier in
the language you have been using to develop Web applications.
|
GWT basics
Setting up GWT is pretty easy. All you have to do is download the package and
unzip it to a location of your choice. You can get the latest version viz.
1.0.21 (beta) from:
http://code.google.com/webtoolkit/download.html
The root directory contains three command shell scripts: 'projectCreator'
for creating a simple project directory structure; 'applicationCreator' for
creating an application; and 'junitCreator' for creating a test case in your
application. While the toolkit provides its own libraries for writing the client
side code, you can use any library of your choice to implement the server side
code of your application. The SDK ships with in-built Eclipse support, so you
can simply import your application in Eclipse using the import wizard. For all
other IDEs you have to import the gwt-user.jar and gwt-dev-windows.jar
libraries.
GWT applications consist of 'Modules'. These modules are defined in XML
and describe the application configuration for GWT. It is up to the modules to
define the publicly available static resources, binding rules that include class
generators and property providers, inherited modules and entry-points to
back-end services (if any) in your application.
There are distinct directory locations specified by GWT for an application.
The client-side of your code should be located in the 'client' package,
where as the server side code should be in 'server' package of your project
directory structure. The publicly accessible resource, we described earlier,
should be placed in 'public' sub-directory. There are two other resources
defined by modules. The 'source path', for defining which packages contain
'translatable source' i.e. source to be compiled to JavaScript. All packages
specified in this resource get converted to JavaScript, thus you can mix server
and client side code in the same classpath without conflict. The 'public path'
is an application, which as the name
suggests, specifies publicly accessible resources such as 'style-sheets',
html files and images.
Getting started
To create a project from scratch we use the projectCreator command script. In
case you want to work with Eclipse for your AJAX application you simply need to
provide the '-eclipse' switch while using the script.
projectCreator —eclipse PCQ-GWT
Exclude the switch if you don't want an eclipse enabled project. Next you
need to create an application which is done as follows:
applicationCreator —eclipse PCQ-GWT
com.pcq.client.PCQApp
You can then import the project using the import wizard in Eclipse. Now, that
we are through with most of the basics we will get down to coding an AJAX
application that presents user with a form and then sends it to a servlet which
displays the values entered in the form. The application has been built to
explain how to go for creating the client side UI and creating a server side
implementation for the application's client end.
The Configuration file
The configuration file that defines the complete project in GWT is named
GWT, is referenced by its logical module names by application's pages and the
modules that inherit from it. This file is also present in the classpath. It is
however not referenced with its path, as on the local file system, but as a
class name along with the complete package structure. In our case the file 'src/com/pcq/PCQApp.gwt.xml'
will be represented as com.pcq.PCQApp.Let's look at the module definition in
our sample application:
The '
attribute to the application. You can specify any number of modules you want to
inherit in your application over here. In our case, we inherit the 'User'
class, which is a standard entry generated by the 'applicationCreator'
script while creating an application. The '
the class that will be responsible for the functions and UI rendered when our
AJAX page is loaded. This class implements the 'onModuleLoad()' method from
the 'EntryPoint' interface. Again the entry is script generated and you can
also add multiple entry point classes. The third tag viz. '
is an interesting one. Basically, we are defining our servlet that will be
loaded using RPC and the 'path' specified in the attribute of this tag. The
'class' attribute as you would know by now defines the servlet class to be
used.
Java coded client side We will now look into the contents of the package 'client'
in our application. We define one class and two interfaces in this package. The
first one, PCQAppService interface in our application is an RPC interface. It
extends the 'RemoteService', a mandatory task. This interface is one which
should be extended by all the interfaces defining services to be used by client
side, in other words implemented on the server side.
package com.pcq.client;
import com.google.gwt.user.client.rpc.RemoteService;
public interface PCQAppService extends RemoteService{
public String sendMessage(String s);
}
Next we implement another interface for receiving a response from an RPC .
The name of this interface 'has to be' the same as the interface in 'client'
package (that finds implementation on the server side) with 'Async'
appended. Thus our interface will be called 'PCQAppServiceAsync'. An 'onSuccess(Object
obj) method is called if RPC is successful and 'onFailure(Throwable th) is
called otherwise.
package com.pcq.client;
import com.google.gwt.user.client.rpc.AsyncCallback;
public interface PCQAppServiceAsync{
public void sendMessage(String str, AsyncCallback asb);
}
We are now left with our implementation of the client side UI which makes
good use of widgets to create an interface. This class is named PCQApp.
package com.pcq.client;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.ui.FlexTable;
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.TextBox;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.google.gwt.user.client.ui.HTML;
/**
* Entry point classes define onModuleLoad()
.
*/
public class PCQApp implements EntryPoint {
private FlexTable table;
private Button submit,reset;
private TextBox fName,lName;
String str;
/**
* This is the entry point method.
*/
public void onModuleLoad() {
table = new FlexTable();
submit = new Button("Submit");
reset = new Button("Reset");
fName = new TextBox();
lName = new TextBox();
table.setWidget(0,0, new Label("Enter your First Name"));
table.setWidget(0,1,fName);
table.setWidget(1,0, new Label("Enter your Last Name"));
table.setWidget(1,1,lName);
table.setWidget(2,0,submit);
table.setWidget(2,1,reset);
RootPanel.get().add(table);
reset.addClickListener( new ClickListener(){
public void onClick(Widget wd){
fName.setText("");
lName.setText("");
}
}
);
submit.addClickListener( new ClickListener(){
public void onClick(Widget wd){
str = fName.getText();
str += " ";
str += lName.getText();
}
}
);
PCQAppServiceAsync svc = (PCQAppServiceAsync)GWT.create(PCQAppService.class);
ServiceDefTarget sdt = (ServiceDefTarget) svc;
sdt.setServiceEntryPoint("/pcqService");
AsyncCallback asb = new AsyncCallback(){
public void onSuccess(Object obj){
RootPanel.get().add(new HTML(obj.toString()));
}
public void onFailure(Throwable exp){
RootPanel.get().add(new HTML(exp.toString())); }
};
svc.sendMessage(str,asb);
}
}
The User Interface is defined using a FlexTable object in the 'com.google.user.client.ui'
package that provides a table in which components can be added dynamically. We
add text, label and button objects to the form and also implement event
handlers. What's more interesting is the code that follows after the UI and
event handler works. We first instantiate the PCQAppService class with deferred
binding and type cast it to the PCQAppServiceAsync. The object thus created is
type casted to 'ServiceDefTarget'. This is the class responsible for
creating an URL for our server side implementation. We then define AsyncCallBack
objects with implementations for success and failure and finally call the
service with variable 'str' containing the text entered.
Server side implementation
The implementation of the class we defined in the 'server' package is pretty
trivial. We define a 'PCQServiceImpl' class that simply returns a string
message along with the inputs submitted. This method is none other than the
method we had defined in the 'PCQAppService' interface in the client
package. This class extends the 'RemoteServiceServlet' class that
deserializes the client requests and serializes the response for a client to
server RPC.
package com.pcq.server;
import com.pcq.client.PCQAppService;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
public class PCQAppServiceImpl extends RemoteServiceServlet implements
PCQAppService {
public String sendMessage(String s) {
return "Welcome to GWT '" + s + "'";
}
}
It is a very simple implementation for server side as our client simply
forwards values entered in the form. In a real life implementation you can even
make use of libraries from other frameworks such as JSF to provide the server
side of your implementation. After all the classes have been coded and
interfaces implemented you can run the application by simply hitting the 'run'
button on your Eclipse IDE or execute the 'PCQ-App-shell.cmd' script to view
the running application.
Bottomline
Kudos to Google for making AJAX development look simpler to work with. Plus, you
also have an RPC mechanism for making calls back to your server application in
the form of a servlet. The RemoteServiceServlet allows you to implement service
methods on an implementation and expose these to your generated Ajax application
as we have seen in the example. Things that will certainly fade away your
worries of going through scripting
hassles. However, although you get it for free, Google doesn't allow you to
distribute software associated or derived from this tool outside your
organization.
Anadi Misra