SeamFramework.orgCommunity Documentation

Capitolo 26. Seam e il Google Web Toolkit

26.1. Configurazione
26.2. Preparare i componenti
26.3. Collegare un componente GWT ad un componente Seam
26.4. Target Ant per GWT

Per chi preferisce utilizzare Google Web Toolkit (GWT) per sviluppare applicazioni AJAX dinamiche, Seam fornisce uno strato di integrazione che consente ai componenti GWT di interagire direttamente con i componenti Seam.

Per usare GWT, si suppone che ci sia già una certa familiarità con gli strumenti GWT. Maggiori informazioni si possono trovare in http://code.google.com/webtoolkit/. Questo capitolo non cercherà di spiegare come funziona GWT o come si usa.

Non è richiesta una particolare configurazione per usare GWT in una applicazione Seam, ad ogni modo la servlet delle risorse Seam deve essere installata. Vedi Capitolo 30, Configurare Seam ed impacchettare le applicazioni Seam per i dettagli.

Il primo passo per preparare i componenti Seam che saranno richiamati tramite GWT è di creare sia l'interfaccia per il servizio sincrono che quella per il servizio asincrono per i metodi che si desidera chiamare. Entrambe queste interfacce devono estendere l'interfaccia GWT com.google.gwt.user.client.rpc.RemoteService:

public interface MyService extends RemoteService {

    public String askIt(String question);      
 }

L'interfaccia asincrona deve essere identica, salvo che contiene un parametro aggiuntivo AsyncCallback per ciascuno dei metodi che dichiara:

public interface MyServiceAsync extends RemoteService {

   public void askIt(String question, AsyncCallback callback);
}

L'interfaccia asincrona, MyServiceAsync in questo esempio, sarà implementata da GWT e non dovrà mai essere implementata direttamente.

Il passo successivo è di creare un componente Seam che implementa l'interfaccia sincrona:

@Name("org.jboss.seam.example.remoting.gwt.client.MyService")

public class ServiceImpl implements MyService {
   @WebRemote
   public String askIt(String question) {
   
      if (!validate(question)) {
         throw new IllegalStateException("Hey, this shouldn't happen, I checked on the client, " +
         "but its always good to double check.");
      }
      return "42. Its the real question that you seek now.";
   }
   
   public boolean validate(String q) {
      ValidationUtility util = new ValidationUtility();
      return util.isValid(q);
   }
}

Il nome del componente Seam deve corrispondere al nome completo dell'interfaccia client GWT (come illustrato), altrimento la servlet delle risorse non riuscirà a trovarlo quando un client farà una chiamata GWT. I metodi che si vogliono rendere accessibili tramite GWT devono anche essere annotati con l'annotazione @WebRemote.

Il prossimo passo è scrivere un metodo che restituisce l'interfaccia asincrona al componente. Questo metodo può essere posizionato all'interno della classe del componente GWT e sarà usato da questo per ottenere un riferimento al client di collegamento asincrono:

private MyServiceAsync getService() {       

   String endpointURL = GWT.getModuleBaseURL() + "seam/resource/gwt";      
      
   MyServiceAsync svc = (MyServiceAsync) GWT.create(MyService.class);
   ((ServiceDefTarget) svc).setServiceEntryPoint(endpointURL);
   return svc;     
}

Il passo finale è scrivere il codice del componente GWT che invoca il metodo sul client di collegamento. Il seguente esempio definisce una semplice interfaccia utente con una label, un campo di input e un bottone:



public class AskQuestionWidget extends Composite {
   private AbsolutePanel panel = new AbsolutePanel();
   
   public AskQuestionWidget() {      
      Label lbl = new Label("OK, what do you want to know?");
      panel.add(lbl);
      final TextBox box = new TextBox();
      box.setText("What is the meaning of life?");
      panel.add(box);
      Button ok = new Button("Ask");
      ok.addClickListener(new ClickListener() {
         public void onClick(Widget w) {
            ValidationUtility valid = new ValidationUtility();
            if (!valid.isValid(box.getText())) {
               Window.alert("A question has to end with a '?'");
            } else {
               askServer(box.getText());
            } 
         }
      });
      panel.add(ok);
      
      initWidget(panel);
   }
   private void askServer(String text) {
      getService().askIt(text, new AsyncCallback() {
         public void onFailure(Throwable t) {
            Window.alert(t.getMessage());
         }
         public void onSuccess(Object data) {
            Window.alert((String) data);
         }         
      });      
   }
   
   ...

Facendo click, il bottone invoca il metodo askServer() passando il contenuto del campo input (in questo esempio viene fatta anche una validazione per assicurare che il testo inserito sia una domanda valida). Il metodo askServer() acquisisce un riferimento al client di collegamento asincrono (restituito dal metodo getService()) e invoca il metodo askIt(). Il risultato (o il messaggio di errore se la chiamata fallisce) è mostrato in una finestra di segnalazione.

Il codice completo di questo esempio si trova nella distribuzione Seam sotto la cartella examples/remoting/gwt.

Per eseguire applicazioni GWT c'è un passaggio di compilazione da Java a JavaScript (che compatta il codice e lo rende illeggibile). C'è uno strumento Ant che può essere utilizzato al posto della linea di comando o dello strumento grafico fornito con GWT. Per usarlo occorre avere il jar con lo strumento Ant nel classpath di Ant, e anche l'ambiente GWT scaricato (che sarebbe comunque necessario per far eseguire il componente in modalità hosted).

Quindi nel file Ant va scritto (verso l'inizio del file Ant):


<taskdef uri="antlib:de.samaflost.gwttasks"
   resource="de/samaflost/gwttasks/antlib.xml"
   classpath="./lib/gwttasks.jar"/>
   
   <property file="build.properties"/>

Creare un file build.properties, con il seguente contenuto:

gwt.home=/gwt_home_dir

Questo naturalmente deve puntare alla cartella dove si è installato GWT. A questo punto per usarlo creare il target:


<!-- Le seguenti sono istruzioni pratiche per lo sviluppo in GWT.
   Per usare GWT occorre aver scaricato GWT separatamente -->
   <target name="gwt-compile">
      <!-- in questo caso stiamo riposizionando la roba generata da gwt, perci� in questo caso
      possiamo avere solo un modulo GWT - facciamo in questo modo appositamente per mantenere breve l'URL -->
      <delete>
         <fileset dir="view"/>
      </delete>
      <gwt:compile outDir="build/gwt"
         gwtHome="${gwt.home}"
         classBase="${gwt.module.name}"
         sourceclasspath="src"/>
      <copy todir="view">
         <fileset dir="build/gwt/${gwt.module.name}"/>
      </copy>
   </target
>

Quando viene chiamato, questo target compila l'applicazione GWT e la copia nella cartella indicata (che dovrebbe trovarsi nella parte webapp del war. Si ricordi che GWT genera oggetti HTML e JavaScript). Il codice risultante dalla generazione con gwt-compile non va mai modificato. Le modifiche vanno fatte sulla cartella dei sorgenti GWT.

Si tenga presente che GWT contiene un browser per la modalità hosted che andrebbe utilizzato se si sviluppa con GWT. Non utilizzandolo e compilando ogni volta, si rinuncia alla maggior parte del toolkit (in effetti a chi non può o non vuole usare il browser in modalità hosted, sarebbe da dirgli che NON dovrebbe usare GWT per niente, dato che quella è la cosa migliore!).