Archive

Archive for August, 2008

GWT SuggestBox backed by DTO Model

August 25th, 2008 admin 9 comments

In this post I am writing a tutorial on how to use the Google Web Toolkit SuggestBox when you want it to provide Data Transfer Objects (DTO’s) suggestions.

According to GWT’s official docs you can Associate DTO objects with SuggestBox suggestions but I struggled to find any guiding tutorials on how to achieve this.

Having said this I have to give credit to Lombardi who went someway to helping me to work out how to do this. Good explanations are posted on their blog.

First of all lets make a simple Data Transfer Object

 
import com.google.gwt.user.client.rpc.IsSerializable;
 
public class PersonDTO implements IsSerializable
{
    private int id = 0;
    private String firstname = null;
    private String lastname = null;
 
    /**
     * @return the firstname
     */
     public String getFirstname()
     {
         return firstname;
     }
 
    /**
     * @param firstname the firstname to set
     */
     public void setFirstname(String firstname)
     {
         this.firstname = firstname;
     }
 
     /**
      * @return the lastname
      */
      public String getLastname()
      {
          return lastname;
      }
 
     /**
      * @param lastname the lastname to set
      */
      public void setLastname(String lastname)
      {
          this.lastname = lastname;
      }
 
     /**
      * @return the id
      */
      public int getId()
      {
          return id;
      }
 
     /**
      * @param id the id to set
      */
      public void setId(int id)
      {
          this.id = id;
      }
}

Thats the DTO object I’ll use throughout the tutorial.

Now we can make our Suggestion object as the following:

import com.google.gwt.user.client.ui.MultiWordSuggestOracle.MultiWordSuggestion;
 
/**
 * @author James Heggs - jheggs@axonbirch.com
 *
 */
public class PersonMultiWordSuggestion extends MultiWordSuggestion
{
    private PersonDTO personDTO = null;
 
    public PersonMultiWordSuggestion(PersonDTO user)
    {
        super(user.getFirstname() + " " + user.getLastname(), 
              user.getFirstname() + " " + user.getLastname() );
 
        this.personDTO = user;
    }
 
 
    /**
     * @return the personDTO
     */
     public PersonDTO getPersonDTO()
     {
         return personDTO;
     }
}

The super() call sets up the first parameter as the replacement String and the second parameter as the display string. You can of course change these.

Next we need to make our own Suggest Oracle. This is done relatively easy. My oracle is shown below:

 
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
 
import com.google.gwt.user.client.ui.SuggestOracle;
 
/**
 * @author James Heggs - jheggs@axonbirch.com
 *
 */
public class PersonNameSuggestOracle extends SuggestOracle
{
    private List<PersonMultiWordSuggestion> personSuggestions = null;
 
    @Override
    public void requestSuggestions(Request request, Callback callback)
    {
        Response resp = new Response( matchingPeople( request.getQuery(),
                                                      request.getLimit() ) );
 
        callback.onSuggestionsReady(request, resp);
    }
 
    /**
     * 
     * @param query The current text being entered into the suggest box
     * @param limit The maximum number of results to return 
     * @return A collection of people suggestions that match.
     */
     public Collection<PersonMultiWordSuggestion> matchingPeople(String query, int limit)
     {
         List<PersonMultiWordSuggestion> matchingPeople = new ArrayList<PersonMultiWordSuggestion>(limit);
 
         // only begin to search after the user has type two characters
         if ( query.length() >= 2 )
         {
             String prefixToMatch = query.toLowerCase();
 
             int i = 0;
             int s = personSuggestions.size();
 
             // Skip forward over all the names that don't match at the beginning of the array.
             while (i < s && !personSuggestions.get(i).getDisplayString().toLowerCase().startsWith(prefixToMatch) )
             {
                 i++;
             }
 
             // Now we are at the start of the block of matching names. Add matching names till we
             // run out of names, stop finding matches, or have enough matches.
             int count = 0;
 
             while (i < s && personSuggestions.get(i).getDisplayString().toLowerCase().startsWith(prefixToMatch) && count < limit) 
             {
                 matchingPeople.add( personSuggestions.get(i) );
                 i++;
                 count++;
             }
 
         }
 
             return matchingPeople;
     }
 
 
 
        /**
         * @param o 
         * @return
         * @see java.util.List#add(java.lang.Object)
         */
         public boolean add(PersonMultiWordSuggestion o)
         {
             if ( personSuggestions == null )
             {
                personSuggestions = new ArrayList<PersonMultiWordSuggestion>();
             }
 
             return personSuggestions.add(o);
         }
 
 
 
        /**
         * @param o
         * @return
         * @see java.util.List#remove(java.lang.Object)
         */
         public boolean remove(Object o)
         {
             if ( personSuggestions != null)
             {
                 return personSuggestions.remove(o);
             }
 
             return false;
          }
 
}

I think for most developers that enough code to get going but just to clear things up the following code snippets show the use of the DTO and SuggestBox as to how it could be used. Also in the code snippets I am assuming you are familar with GWT’s RPC architecture.

First an RPC call to fetch the DTO objects from a server (Production mode could ask for persistent objects from hibernate or something similar.)

 
PersonNameSuggestOracle oracle = new PersonNameSuggestOracle();
SuggestBox nameSuggestBox = new SuggestBox(oracle);
 
 
//fetch names
  MyServiceAsync serviceRPC = GWT.create(MyService.class);
  serviceRPC.fetchPeople(new AsyncCallback&lt; List&lt;PersonDTO&gt; &gt;()
  {
   public void onFailure(Throwable caught)
   {
    // TODO Auto-generated method stub
 
   }
 
   public void onSuccess(List&lt;PersonDTO&gt; results)
   {
    if ( results != null && results.size() &gt; 0 )
    {
     for ( PersonDTO person : results )
     {
      oracle.add(new PersonMultiWordSuggestion(person) );
     }
    }
 
   }
  });

Then for those interest snippet code on how to handle the selected suggestion

nameSuggestBox.addEventHandler(new SuggestionHandler()
{
    public void onSuggestionSelected(SuggestionEvent event)
    {
        PersonMultiWordSuggestion suggestion = (PersonMultiWordSuggestion)event.getSelectedSuggestion();
 
        // Do what you want with the suggestion and DTO
        // suggestion.getPersonDTO
 
 
    }
});

Thats basically it. If people have any questions or ideas please post them as a comment in order to help others.