Building fat GWT web clients [Intro] – How to create a GWT RPC client?
Posted by igormoochnick on 05/18/2009
After months of working (mainly fighting with quirks of Java) with GWT I’ve accumulated so much knowledge on the topic so, I feel, it starts spilling over. I’m planning to convert this spill into a series of articles on how to build fat REST-full GWT web fat clients both on Java and .NET.
Here is the list of topics I’ll cover:
- Building GWT fat client
- Java REST-full Web services
- .NET REST-full Web services
- Internationalization and localization
- IOC/DI
- Unit testing and integration testing of all the components of the system
- Build automation
- and much, much more …
Here is a draft list of technologies I’ll be using:
- GWT
- Eclipse
- Spring
- Jersey
- Tomcat
- XStream
- AJAX
- JSON/XML
- WCF
- JUnit/TestND/NUnit
- Selenium
- Ant
- TeamCity
- and much, much more …
For starters, let’s see how to create a simple GWT fat client that talks to the REST-full Web services. As an example,
let’s think about contact management scenario where we’re going to create a web client that will be used to browse all your existing contacts.
We’re going to use:
- GWT 1.6 + GWT RPC
- Eclipse Ganymede + GWT Eclipse plugin
After creating a basic GWT project (in Eclipse you can use “Create GWT Project” icon on the toolbar), create a simple client (see the attached source code).
The client I’ll be using in my examples is very simple, but there are a couple of key points you should note. To make the GWT client to connect to the back end via GWT RPC you need to create 3 different classes:
- ContactManagerService – Client side RPC stub
- ContactManagerServiceAsync – The asyncronous counterpart of GreetingService
- ContactManagerServiceImpl – The server side implementation of the RPC service
package com.igorshare.client;
@RemoteServiceRelativePath("contacts")
public interface ContactManagerService extends RemoteService {
List<ContactInfo> getContacts(String filter);
}
package com.igorshare.client;
public interface ContactManagerServiceAsync {
void getContacts(String filter, AsyncCallback<List<ContactInfo>> callback);
}
package com.igorshare.server;
public class ContactManagerServiceImpl extends RemoteServiceServlet implements
ContactManagerService {
public List<ContactInfo> getContacts(String filter) { ... }
}
Note that only serializable types can go over the wire. To make your own structure serializable, inherit it from IsSerializable interface. This will notify GWT generator to create a JSNI representation for this structure and an appropriate proxy.
This is how the ContactInfo class looks like:
package com.igorshare.client;
public class ContactInfo implements IsSerializable {
public String FirstName;
public String LastName;
public String Company;
...
}
This is as much ceremony as need to make sure that there is a REST-full communication between the server side and the client side.
To make a call to our new server, on the client side, a reference to the server proxy is needed as well as definition an asynchronous callback which will handle a success and a failure of the execution. In our example the failure is not really handled – only an error message logged. On success – the contact table is cleaned and populated with the new data that came from the server.
private final ContactManagerServiceAsync greetingService = GWT
.create(ContactManagerService.class);
...
// Add a handler to send the search criteria to the server
sendButton.addClickHandler(new ClickHandler() {
/**
* Fired when the user clicks on the sendButton.
*/
public void onClick(ClickEvent event) {
sendNameToServer();
}
/**
* Send the name from the nameField to the server and wait for a
* response.
*/
private void sendNameToServer() {
greetingService.getContacts(filterField.getText(),
new AsyncCallback<List<ContactInfo>>() {
public void onFailure(Throwable caught) {
// Show the RPC error message to the user
GWT.log("Remote Procedure Call - Failure", caught);
}
public void onSuccess(List<ContactInfo> result) {
contacts = result;
updateContactTable();
}
private void updateContactTable()
{
// Clean contacts table
for(int i=contactsTable.getRowCount()-1; i>0; i--)
contactsTable.removeRow(i);
// Fill the table with the data from the server
for(ContactInfo contact : contacts)
{
int row = contactsTable.getRowCount();
contactsTable.setText(row, 0, contact.FirstName);
contactsTable.setText(row, 1, contact.LastName);
contactsTable.setText(row, 2, contact.Company);
}
}
});
}
});
One more thing you should remember is that the relative path to the service (See the @RemoteServiceRelativePath("contacts") annotation on the ContactManagerService) should correspond to the path in the web.xml file:
<servlet> <servlet-name>contactsServlet</servlet-name> <servlet-class>com.igorshare.server.ContactManagerServiceImpl</servlet-class> </servlet> <servlet-mapping> <servlet-name>contactsServlet</servlet-name> <url-pattern>/contactmanager/contacts</url-pattern> </servlet-mapping>
On the next post I’ll show how to make this GWT client to talk to a JAX-RS REST-full web service. I’ll use Jersey to enable our back-end service. Stay tuned …





Building GWT web clients [Part 2] – How to expose REST-full JAX-RS service with Jersey on Tomcat server? « IgorShare Weblog said
[...] Building fat GWT web clients [Intro] – How to create a GWT RPC client? [...]
Danilla said
Спасибо за статью оказалась очень полезной.