Building fat GWT web clients [Intro] – How to create a GWT RPC client?
Posted by Igor Moochnick 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 getContacts(String filter); } package com.igorshare.client; public interface ContactManagerServiceAsync { void getContacts(String filter, AsyncCallback<List> callback); } package com.igorshare.server; public class ContactManagerServiceImpl extends RemoteServiceServlet implements ContactManagerService { public List 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>() { public void onFailure(Throwable caught) { // Show the RPC error message to the user GWT.log("Remote Procedure Call - Failure", caught); } public void onSuccess(List 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:
contactsServlet com.igorshare.server.ContactManagerServiceImpl contactsServlet /contactmanager/contacts
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
Спасибо за статью оказалась очень полезной.
Blessed Geek said
Hmmm … I have always considered GWT a thin client technology. Especially with REST.
— Come unto me, all ye who are weary of fat and heavy clients, and I will give you REST.