Kenji Tachibana's Weblog

« 前の日(Dec月 16日, 2008年) | 日付別メイン | 次の日(Dec月 18日, 2008年) »

http://blogs.sun.com/kenji/date/20081218 2008年 12月 18日 木曜日

翻訳: JavaFX Async 操作

Clarkeman's Weblog からの翻訳です。以前に作った JavaFX から DB へのアクセス方法で、「それじゃまずいだろ!」というコメントをもらって、AsyncOperation について調べていたときに見つけました。とりあえず、これを翻訳して、私のプログラムも直してみます...

I am helping a client with a JavaFX application and the client caches data locally using Mysql, after fetching it from a web service. To start the application, an animated splash screen is shown, then the initial fetch of data is done, before showing the main application screen.
---------------
わたしは、現在 JavaFX アプリケーションのクライアントを作っていて、そのクライアントは、web サービスから、データをフェッチしたあと、ローカルの Mysql にデータをキャッシュしています。アプリケーションをスタートさせると、短いアニメーションを表示させ、データのフェッチを完了した後とで、メインアプリケーションを表示させるようになっています。

What I noticed is that if I did the fetch routines in JavaFX script, the animation on the splash screen would pause. This is because JavaFX script executes on a single thread (Event Dispatch Thread, EDT, in the Desktop environment). To get around this, I needed the database and web service access to happen off the EDT in their own Thread. JavaFX does not support creating you own threads, so I had to resort to the javafx.async package.
----------------
アプリケーションを作成実行して気づいたのですが、フェッチを JavaFX から始めると、アニメーションが手停止してしまいます。これは、JavaFX が、単一のスレッド (デスクトップ環境の EDT - イベントディスパッチスレッド) で実行されているためです。これを回避するためには、データベースや web サービスへのアクセスを、EDT ではなく、別のスレッドで実行する必要があります。JavaFX では、独自のスレッドを作成することはサポートされていないので、javafx.async パッケージを使うことにしました。

Currently, there is built in support for asynchrously retrieving a remote text document from the Web via the javafx.async.RemoteTextDocument class. However, my problem is I had to implement logic that would first check locally in the database, and if not present there, then go out over the web. Because of this, I could not use this class; off to write my own accessor class.
----------------
現在、JavaFX では、 javafx.async.RemoteTextDocument クラスを使って、リモートにあるテキストファイルを web から取得することがデフォルトできます。しかし、私のケースでは、最初に、ローカルのデータベースをチェックし、もし存在しない場合は、web から取得するというロジックを実装しなくてはなりません。なので、このクラスを使うのではなく、自前の accessor クラスを実装しなくてはなりません。

To do this, I had to write a Java class that extends com.sun.javafx.runtime.async.AbstractAsyncOperation. This class requires a constructor that takes at a minimum, a com.sun.javafx.runtime.async.AsyncOperationListener object. The AsyncOperationListener provides various call back methods allowing control over the asynchrounous call and reporting of status, such as completion or failure. The could news here is that in the JavaFX side, the javafx.async.AbstractAsyncOperation class handles this plumbing.
------------------
このため、com.sun.javafx.runtime.async.AbstractAsyncOperation クラスを継承したクラスを書く必要があります。また、このクラスは、com.sun.javafx.runtime.async.AsyncOperationListener オブジェクトをコンストラクタの引数として、取る必要があります。AsyncOperationListener は、asynchrounous コールの操作や、完了/失敗のステータスをレポートしてくれる多くのコールバックメソッドを提供してくれます。


import com.mycompany.model.Employee;
import com.sun.javafx.runtime.async.AbstractAsyncOperation;
import com.sun.javafx.runtime.async.AsyncOperationListener;
import java.util.List;
import javax.sql.DataSource;
/* EmployeeLoadImpl.java */
public class EmployeeLoadImpl extends AbstractAsyncOperation {
private Employee employee;
public EmployeeLoadImpl(Employee employee, AsyncOperationListener listener) {
super(listener);
this.employee = employee;
}
@Override
public Object call() throws Exception {
DataSource ds2 = MyDatasource.getCommonsPooledDatasource();
java.sql.Connection con = ds2.getConnection();
// getDirectReports checks local db, and then web service if needed
List directReports = EmployeeReportsDB.getDirectReports(con, employee.getId());
employee.setDirectReports(directReports);
return employee;
}
}

The reason this is done in Java, is that the Call method executes its own Thread, and is not on the Event Dispatch Thread (EDT). By not attempting this in JavaFX, you can avoid unintended clashes with the JavaFX runtime. For example, you avoid clashes with binding or triggers. To be totally safe, the Employee model object is in Java, also.
--------------------
Java で行っている理由は、call メソッドが EDT ではなく、独自のスレッドを実行するためです。JavaFX で実行していない理由は、意図しない理由で JavaFX ランタイムをクラッシュしないようにするためです。たとえば、バインドやトリガーのクラッシュを避けることができます。なので、Employee モデルオブジェクトは、Java で実装した方が安全です。

The second part of this is to write a JavaFX class that extends javafx.async.AbstractAsyncOperation. javafx.async.AbstractAsyncOperation provides the basic plumbing to interact with the asynchronous runtime. Here is an example:
--------------------
次に、javafx.async.AbstractAsyncOperation クラスを継承して、JavaFX のクラスを作成します。javafx.async.AbstractAsyncOperation は、asynchronous ランタイムとの、基本的な相互接続方法を提供してくれます。以下に例を載せます:


import javafx.async.AbstractAsyncOperation;
import com.mycompany.model.Employee;
/**
* @author jclarke
*/
public class EmployeeLoad extends AbstractAsyncOperation {
var peer: EmployeeLoadImpl;
public-init var employee:Employee;
public var onComplete: function(employee: Employee): Void;
public override function cancel() : Void {
if (peer != null) then peer.cancel();
}
protected override function start() : Void {
peer = new EmployeeLoadImpl(employee, listener);
peer.start();
}
protected override function onCompletion(value : Object) : Void {
onComplete(employee);
}
}

To use this in a program:
--------------------------
これをプログラムで使うには以下のようにします:


EmployeeLoad {
employee: employee
onComplete: function(emp: Employee) : Void {
employeeUI = EmployeeUI {
employee: emp
}
}
};

This is a little cumbersome, having to jump down into Java to execute the asynchrounous logic. The JavaFX team is currently looking at solutions to asynchronous use cases and hopefully enhanced language support or more Aysnchrounous framework classes will make this easier.
-------------
asynchrounous ロジックを使うために、java を利用しなくてはならないのは、ちょっと扱いにくい感じがします。JavaFX チームは、asynchronous のユースケースを解析しているので、もしかしたら、JavaFX の機能拡張や、Aysnchrounous フレームワーククラスをもっと簡単につくれるようになるかもしれません。


Valid HTML! Valid CSS!

This is a personal weblog, I do not speak for my employer.