Section 10.4. Supplying Services to the Client


10.4. Supplying Services to the Client

It'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

 package com.oreilly.ajax.client; import com.google.gwt.user.client.rpc.RemoteService; public interface ResponseService extends RemoteService {     String displayResponse(String req); } 

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

 package com.oreilly.ajax.client; import com.google.gwt.user.client.rpc.AsyncCallback; public interface ResponseServiceAsync {     public void displayResponse(String s, AsyncCallback callback); } 

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

 package com.oreilly.ajax.server; import com.google.gwt.user.server.rpc.RemoteServiceServlet; import com.oreilly.ajax.client.ResponseService; public class ResponseServiceImpl extends RemoteServiceServlet         implements ResponseService {     public String displayResponse(String req) {         if (req.length( ) < 1) {             throw new IllegalArgumentException(                     "Blank submissions from the client are invalid.");         }         Zipcode zipcode = ZipcodeManager.getZipcode(req);         String state = zipcode.getState( );         String city = zipcode.getCity( );         if ((state==null || state.length()<1) || (city==null || city.length( )<1))           return null;         String jsonString = "{\"state\":\""+state+"\", \"city\":\""+city+"\"}";         return jsonString;     } } 

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 Service

The 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

 zipCodeBox.addFocusListener(new FocusListener( ) {     public void onFocus(Widget sender) {     }     public void onLostFocus(Widget sender) {         ResponseServiceAsync respService = (ResponseServiceAsync)                 GWT.create(com.oreilly.ajax.client.ResponseService.class);         ServiceDefTarget endpoint = (ServiceDefTarget) respService;         endpoint.setServiceEntryPoint("/responseService");         displayFormattedMessage("getting data...", "blue");         AsyncCallback callback = new AsyncCallback( ) {             public void onSuccess(Object result) {                 JSONObject jsonObject;                 try {                     displayFormattedMessage("Parsing JSON data...", "blue");                     jsonObject = JSONParser.parse((String) result);                     String[] keys = jsonObject.getKeys( );                     if (keys.length >= 2) {                         String city = jsonObject.get("city").toString( );                         String state = jsonObject.get("state").toString( );                         cityTextBox.setText(city);                         stateTextBox.setText(state);                         displayFormattedMessage("", "blue");                     }                     else {                         cityTextBox.setText("");                         stateTextBox.setText("");                         displayFormattedMessage("This zip code was not found in                                                 the database.", "red");                     }                 } catch (JSONException e) {                     displayFormattedMessage("Error parsing JSON data \n"                                             + e.getMessage( ), "red");                 }             }             public void onFailure(Throwable caught) {                 displayFormattedMessage(                         "Server request raised an error; Java exception : " +                         caught == null ? "An unknown exception"                         : caught.getMessage( ), "red");             }         };         try {             displayFormattedMessage("getting request", "green");             respService.displayResponse(zipCodeBox.getText( ), callback);         } catch (Exception e) {             displayFormattedMessage("Server request raised an error: "                                     + e.getMessage( ), "red");         } finally {             displayFormattedMessage("", "green");         }     } }); 

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 services


We 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 URL

One 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

 <module>     <!-- Inherit the core Web Toolkit stuff.                  -->     <inherits name='com.google.gwt.user.User'/>     <!-- Specify the app entry point class.                   -->     <entry-point class='com.oreilly.ajax.client.ZipCodes'/>     <!-- GWT's RPC Servlet path                               -->     <servlet path='/responseService'              class='com.oreilly.ajax.server.ResponseServiceImpl'/> </module> 

With the <servlet> tag added to ZipCodes.gwt.xml, the entire application is ready for testing.




Ajax on Java
Ajax on Java
ISBN: 0596101872
EAN: 2147483647
Year: 2007
Pages: 78

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net