SeamFramework.orgCommunity Documentation

第26章 SeamとGoogle Web Toolkit

26.1. 設定
26.2. コンポーネントの用意する
26.3. GWTウィジェットを Seam コンポーネントに関連づける
26.4. GWTとAntターゲット

こういった動的なAjaxアプリケーションをGoogle Web Toolkit (GWT)を使って開発したいときのために、SeamはGWTウィジェットが直接Seamコンポーネントと連携できる統合レイヤを用意しています。

GWTを使う上でGWT toolsについては既に知っていることを前提にしています。より細かい情報については http://code.google.com/webtoolkit/を参照ください。この章ではGWTがどう機能し、どのように使うかといったところについては説明しません。

SeamアプリケーションでGWTを使う場合に特別な設定は必要ではありません、しかしSeamリソースサーブレットが動作するように設定されていなければなりません。詳細は章 29. Seam の設定と Seam アプリケーションのパッケージングを参照ください。

GWT経由で呼ばれるSeamコンポーネントを用意する最初のステップは、呼び出したいメソッドをもつ同期、非同期サービス両方のインタフェースを作成することです。両インタフェースともGWTの提供するcom.google.gwt.user.client.rpc.RemoteServiceを継承します。

public interface MyService extends RemoteService {

    public String askIt(String question);      
 }

非同期インタフェースは一意であるべきですが、AsyncCallback パラメタを各メソッドで宣言している場合は除きます。

public interface MyServiceAsync extends RemoteService {

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

このMyServiceAsyncのサンプルのような非同期インタフェースはGWTで実装され、直接的に実装することはありません。

次のステップでは同期インタフェースを実装するSeamコンポーネントを作成します。

@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);
   }
}

The methods that should be made accessible via GWT need to be annotated with the @WebRemote annotation, which is required for all web-remoteable methods.

次のステップは、コンポーネントに非同期インタフェースを返すメソッドを書きます。このメソッドはウィジェットクラスで用意し、非同期クライアントのスタブへの参照を取得するために利用されます。

private MyServiceAsync getService() {       

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

最後のステップはクライアントスタブのメソッドを呼び出すウィジェットのコードを書きます。次のサンプルではラベルとテキスト入力フィールドとボタンで構成される画面を作成します。



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);
         }         
      });      
   }
   
   ...

ボタンをクリックするとaskServer()メソッドを呼び出し、入力テキストを渡します(この例では、入力値が正しい質問か確認するバリデーションも行なわれます)。askServer()メソッドは非同期クライアントスタブ(getService()メソッドで返される)への参照を取得し、askIt()メソッドを呼び出します。その結果 (もしくは呼び出し失敗時のエラーメッセージ)はアラートメッセージとして表示されます。

このサンプルの完全なコードはSeamのインストールディレクトリ内の examples/remoting/gwtディレクトリにあります。

GWTアプリのデプロイにはコンパイル-Javascriptステップ(コードをコンパクトにして難読化します)があります。そしてコマンドラインの代わりに使えるantユーティリティやGWT標準のGUIユーティリティがあります。これらを使うためにはant-taskのjarとダウンロードしてあるGWT(これはホストモードのときに必要)がクラスパスに存在していなければなりません

次にそれらをantファイルの最初の方に置きます。


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

その内容を持つ、build.propertiesファイルを作成します。

gwt.home=/gwt_home_dir

もちろん、これはGWTがインストールされた場所を直接指しています。次にターゲットを作成します。


<!-- GWT�zg�)j��ƣ�ƣgY.
   GWT�F4oS6gYLGWT� %k&����Y�ŁLB�~Y -->
   <target name="gwt-compile">
      <!-- Sn4 GWT�� "re homing" WfD~Yng
      GWT����`QcfD~Y - URL�����kY�_�kLjcfD~Y -->
      <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
>

呼ばれたときにこのターゲットはGWTアプリケーションをコンパイルし、そのコンパイル結果を指定されたディレクトリ(warのwebappにある. GWTはHTMLとJavascriptも生成するので憶えておいてください)にコピーします。gwt-compile が生成するコードは一切編集しません、編集する時はGWTソースディレクトリのリソースにて行います。

GWTはホストモードブラウザがあることを覚えておいてください。GWT開発をしているのであれば使っているべきです。もし使ってなく、毎回コンパイルをしているといった場合、ツールを最大限に活用できていません。(本音でいうと、もしホストモードを使えないもしくは使わないのであれば、絶対GWTを使うべきではない、とまで言い切ります。それぐらい価値のあるものだからです)