woensdag 14 april 2010

GWT en Webservices

Een webservice is een service of programma welke beschikbaar is over een netwerk. Om gebruik te maken van de service, hoeft deze niet lokaal geinstalleerd te worden. De service kan over het netwerk aangeroepen worden. Het idee is vergelijkbaar met Remote Procedure Calls maar niet langer moet de service in dezelfde taal geschreven zijn als het programma dat gebruik wil maken van de service.

Een service wordt gedefinieerd in een op XML gebaseerde taal (WSDL). Dit WSDL bestand beschrijft wat de service doet, welke inputs nodig zijn, en welke outputs eruit komen. Aan de hand van deze WSDL kunnen de service- en clientstubs ontwikkeld worden. Veel software pakketten maken het mogelijk om een WSDL te genereren uit een reeds gebouwde service. Evengoed kan een clientstub gegenereerd worden uit deze WSDL-definitie. Voor het transport van de boodschappen worden ook XML berichten gebruikt (SOAP, XML-RPC of REST). Echter, nadat de service- en clientstub klaar zijn, heb je hier niks meer mee te maken. Je roept gewoon een methode aan in de clientstub en je krijgt, met een netwerk afhankelijke vertraging, een antwoord terug.

Het voordeel van webservices dat het platform onafhankelijk is. Betekent dat dat we een webservice ook kunnen aanroepen vanuit een website? Als de webservice draait op dezelfde server als waar de website draait, moet dat mogelijk zijn, maar wanneer deze op een andere server draait, komen we in aanraking met het "same origin policy". Het is in een browser om veiligheids redenen niet mogelijk om via JavaScript contact op te nemen met een vreemde server. Maar er is een omweg en GWT geeft ons wat we nodig hebben.

In GWT kunnen via RPC direct communiceren met Java code op de server. Voor onze server, geldt er geen "same origin policy", dus van daaruit kunnen gewoon gebruik maken van elke bereikbare webservice. Hieronder zal ik een voorbeeldje uitwerken. De webservice die ik zal gebruiken maakt het mogelijk om SQL achtige queries te doen op de databron achter de service. In die databron bevinden zich klantnamen. Wat we gaan maken is een textsuggestbox die suggesties levert die uit de webservice komen en afhankelijk zijn van de reeds ingetypte karakters.

De eerste stap bij het gebruiken van een webservice is het genereren van een clientstub. Er zijn een hoop verschillende tools die dit kunnen. Deze keer heb ik Axis (van Apache) gebruikt. Hierbij zit een scriptje genaamd WSDL2Java, wat precies doet wat je verwacht. Er wordt een class aangemaakt met daarin de methodes die de webservice levert. Ook worden er, indien nodig, allerlei complexe datatypen gemaakt.

De tweede stap is het aanmaken van een nieuw GWT project. Voeg hier de zojuist gegenereerde classes toe aan het classpath. Dit kan door alles in een jar-file in te pakken en deze in het buildpath van het project op te nemen, of door simpelweg alle genegereerde classes naar ons project te kopieren.

Definieer de volgende interface:
String[] getSuggestions(String start);
Maak hiervoor ook de asynchrome variant en implementeer de service op de webserver door gebruik te maken van de gegenereerde webservice clientstub. Ik ga ervanuit dat dat wel moet lukken.

Om onze suggestbox te voorzien van suggesties hebben we een zogenaamd Oracle nodig. Dit is een class, afgeleid van SuggestOracle, waarbij de requestSuggestions methode opnieuw gedefinieerd wordt. Dat ziet er als volgt uit:
private class XServerOracle extends SuggestOracle {

  @Override
  public void requestSuggestions(final Request request, final Callback callback) {
   testService.getSuggestions(request.getQuery(), new AsyncCallback() {
    @Override
    public void onSuccess(String[] result) {
     Collection suggestions = new ArrayList();
     for (final String row : result) {
      suggestions.add(new Suggestion() {
       @Override
       public String getDisplayString() {
        return row;
       }

       @Override
       public String getReplacementString() {
        return row;
       }
      });
     }
     Response resp = new Response(suggestions);

     callback.onSuggestionsReady(request, resp);
    }

    @Override
    public void onFailure(Throwable caught) {}
   });
  }
 }

Dit Oracle wordt vervolgens gebruikt bij het aanmaken van het SuggestBox object:
final SuggestBox box = new SuggestBox(new XServerOracle());

Klaar.

Een voorbeeld staat op:
http://waalwijk.yall.nl:8080/CustomerSearchWidget

Geen opmerkingen: