10.4. Supplying Services to the ClientIt's no surprise that, given a zip code, we need a service to look up the city and state. But how should we do that? One slick option is to use a Remote Procedure Call (RPC), which is a mechanism that allows a computer to cause a program running on another computer to execute. GWT provides an RPC mechanism that eliminates the need to work directly with the XMLHttpRequest object that other Ajax applications must use. To use GWT's RPC plumbing, you must define two Java interfaces and one class. The first interface (ResponseService, shown in Example 10-6) extends com.google.gwt.user.client.rpc.RemoteService and defines the service. Example 10-6. ResponseService.java
This service interface must define the method displayResponse( ). The second interface (ResponseServiceAsync, shown in Example 10-7) specifies a method (displayResponse( )) that the client uses to call the service. That interface extends com.google.gwt.user.client.rpc.AsyncCallback. Example 10-7. ResponseServiceAsync.java
The AsyncCallback handles the response for the client. The class that must be implemented should extend com.google.gwt.user.server.rpc.RemoteServiceServlet. We'll call this class ResponseServiceImpl; its code is presented in Example 10-8. Example 10-8. ResponseServiceImpl.java sits on the server
The ResponseServiceImpl class extends RemoteServiceServlet, which in turn extends javax.servlet.http.HttpServlet. That means that this class is actually a servlet and will be deployed in the servlet container. For this application, the service returns a JSON-formatted string with the state set to "state" and the city set to "city". 10.4.1. Connecting the Client to the ServiceThe client is not yet connected to the service. We can accomplish this by adding a FocusListener to the zipCodeBox element, as shown in Example 10-9. This is done with an inner class, just as you would add a listener to a widget in Swing. Example 10-9. The client ZipCodes class with the service connected
The work of detecting that the zip code field has lost focus is done in the onLostFocus( ) method of the FocusListener. The onFocus( ) method must be implemented to satisfy the FocusListener interface, but the body of the method can be left blank because this application doesn't do anything when the zipCodeBox element comes in focus. The entry point for the Ajax service is added to the ResponseServiceAsync object by passing the service's URLin this case, /responseServiceinto setServiceEntryPoint( ). Then, in the try block at the end of the onLostFocus( ) method, the response service (respService) configures the service, passing in the text of the zipCodeBox and the AsyncCallback object: respService.displayResponse(zipCodeBox.getText( ), callback); The callback parameter was set earlier to the instantiated AsyncCallback object. The AsyncCallback interface defines what happens to the client when the Ajax call is returned. This is the callback function that XMLHttpRequest uses, but because we are using GWT, the details of that call are hidden from the developer. The AsyncCallback interface has two methods that this application must implement: onFailure( ) and onSuccess( ). The onSucess( ) method is invoked when the Ajax call returns successfully. This is handled by decoding the JSON object, which should contain the city and state information. The city and state are displayed by calls to the setText( ) method on the cityTextBox and the stateTextBox. If there is an error, the onFailure( ) method is invoked and the application displays an error message. The project directory structure should now look like Figure 10-11. Figure 10-11. ZipCodes project with servicesWe have modified the ZipCodes class to use the new service. The new service is implemented by the com.oreilly.ajax.server.ResponseServiceImpl class; the interfaces to the service are ResponseService and ResponseServiceAsync, which are both in the client package. Figure 10-11 also shows some JSON support classes that are part of the client package. JSON support is not currently implemented in GWT. To facilitate use of JSON, download the JSON RPC example from http://code.google.com/webtoolkit/documentation/examples. Then copy the JSON classes into the application's client package. The ZipCodes application needs JSON to handle the data passed asynchronously to the onSuccess( ) method of the AsyncCallback object. 10.4.2. Connecting the Service to the Servlet URLOne last item must be addressed: we must connect the service to the /responseService URL. That's handled in ZipCodes.gwt.xml (Example 10-10). Example 10-10. ZipCodes.gwt.xml with the servlet configuration
With the <servlet> tag added to ZipCodes.gwt.xml, the entire application is ready for testing. |