JavaFX統合戦略

Luxoft Trainingが主催するITの達人による一連のマスタークラスの一環として、Adam Bienの記事「Integration Testing for Java EE」の翻訳に精通することをお勧めします。



著者について

本のアドバイザー兼著者であるAdam Bienは、Java EEエキスパートグループ6および7、EJB 3.X、JAX-RS、およびJPA 2.X JSRのメンバーです。 JDK 1.0以降のJavaテクノロジ、およびサーブレット/ EJB 1.0で動作します。 彼は現在、Java SEおよびJava EEプロジェクトの設計者および開発者です。 彼は、JavaFX、J2EE、およびJava EEに関するいくつかの本を編集しました。 彼は、Real World Java EEパターン—ベストプラクティスとReal World Java EEナイトハックの再考—ビジネス層の分析の著者です。 Adamは、Javaチャンピオン、トップJavaアンバサダー2012、JavaOne 2009、2011、2012 Rock Star Awardsを受賞しています。 ミュンヘン空港ビル(http://airhacks.com)でJava EEワークショップを定期的に開催しています。





ラムダ式と非同期通信のサポートにより、JavaFXはサーバーサービスの新しい統合オプションを導入します。



組織では、孤立したアプリケーションを見つけることはほとんどありません。 エンタープライズデスクトップアプリケーションは、アプリケーションサーバーによって表される1つ以上のサーバーサービスからのデータを表示および操作します。 SwingおよびJ2EEでは、メッセージは単方向および同期でした。 JavaFXおよびJava EE 6および7は、さまざまな新しい同期、非同期、プッシュおよびプル統合戦略を導入しました。 この記事では、Java EEサービスとJava FXアプリケーションの統合に焦点を当てます。

JavaFXはJavaです

JavaFXはJavaです。 したがって、Swingアプリケーションに適用されるベストプラクティスは、JavaFXにも適用できます。 サーバーサービスの統合は、使用されるプロトコルやテクノロジーとは無関係です。

サービスには、IPアドレス、ポート、プロパティファイルなど、さまざまな構成があります。 また、APIメソッドは、java.rmi.RemoteExceptionなどのプロトコル固有の例外をスローすることが多いため、不必要な詳細でプレゼンテーションロジックを詰まらせます。 独自のサービスの薄いラッパーは、実装の詳細をカプセル化し、より意味のあるインターフェイスの詳細を提示します。 これは、古典的なGoFアダプターパターンです。



ビジネスデリゲートの復活

J2EEクライアントは、Internet Inter-ORB Protocol(RMI-IIOP)に基づくRemote Method Invocationテクノロジに大きく依存し、後にXMLベースのRPC(JAX-RPC)用のJava APIとXML Webサービス用のJava APIに依存しました。 (JAX-WS)サーバーサービス。 両方のAPIは、制御された例外を多用し、テクノロジー固有です。 プレゼンテーションロジックとプロトコルを分離するには、ビジネスデリゲートパターンが必要でした。



「ビジネスデリゲートを使用して、プレゼンテーションレベルのクライアントとビジネスサービスの間のつながりを減らします。 ビジネスデリゲートは、EJBアーキテクチャの検索やアクセスなど、ビジネスサービスの実装の詳細を隠します。



多くの場合、ビジネスデリゲートはファクトリメソッドによって拡張され、デフォルトのバージョンで実際のプロキシが作成され、テスト環境でモックオブジェクトが作成されました。 Mockitoなどの最新のモックライブラリを使用すると、ビジネスデリゲートを直接シミュレートできます。 JavaFXおよびJavaEEのコンテキストでのビジネスデリゲートは、実装の詳細をカプセル化し、JavaFXへの便利なインターフェイスを提供するPlain Old Java Object(POJO)アダプターとして実装できます。





図1




最初のリクエスト、次にレスポンス

アプリケーションサーバーにブロッキングリクエストを送信し、データの受信を待機することは、サーバーパーツとの最も簡単な統合です。 リスト1に示すように、Business Delegateはバックエンドと通信するサービスになります。



リスト1




MethodMonitoringクラスは、実装、テスト、およびプレゼンターとの統合が簡単です。 getMethodStatisticsメソッドは、UIリスナーメソッドからの同期呼び出しを無制限の時間ブロックする可能性があるため、これを使用するとUIが応答しなくなります。



非同期統合

幸いなことに、JAX-RS 2.0 APIは非同期コールバックモデルもサポートしています。 ブロックする代わりに、getMethodStatisticsメソッドはリクエストを開始し、コールバックを登録します(リスト2を参照)。





リスト2




コールバックは、着信JsonObjectをドメインオブジェクトに変換し、それをjava.util.function.Consumer関数実装に渡します。 ビジネスデリゲートの実装は、JavaFX APIから独立しており、Java 8 java.util.function.Consumerをコールバックとして使用します。 Java 7では、任意のカスタムインターフェイスまたはクラスをコールバックとして使用できます。 ただし、Java 8では、リスト3に示すように、JavaFXプレゼンターの実装を大幅に簡素化できます。





リスト3




java.util.function.Consumerは、コードの量を大幅に削減するラムダ式として実装できます。 JavaFXは、ユーザーインターフェイスを開発するためのシングルスレッドツールキットであるため、複数の非同期スレッドからアクセスすることはできません。



java.lang.Runnableインターフェースのラムダ実装はPlatform.runLaterメソッドに渡され、実行のためにイベントキューに追加されます。 Javadocで述べたように、「将来の任意の時点で、JavaFXアプリケーションスレッドで特定のRunnableを実行します。 このメソッドは任意のスレッドから呼び出すことができ、Runnableをイベントキューに入れてから、それを呼び出すプログラム(関数、メソッド)にすぐに返します。 すべてのRunnableは、キューに入れられた順序で実行されます。 runLaterメソッドに渡されたRunnableは、Runnableが次のrunLater呼び出しに渡される前に実行されます。



Platform#runLaterメソッドは、長期的なタスクには適していませんが、非同期ストリームからJavaFX UIコンポーネントを更新するのに役立ちます。



実作業のタスク

Platform.runLaterは、難しいタスクを実行するようには設計されていませんが、JavaFXノードを迅速に更新するのに役立ちます。 長期的なメソッドを非同期的に呼び出すにはスレッドが必要で、最初はjavafx.concurrent.Task JavaFXクラスによってサポートされています。 Taskクラスは、WorkerおよびEventTargetインターフェースを実装し、java.util.concurrent.FutureTaskクラスを継承し、JavaスレッドとJavaFXイベントメカニズム間のブリッジと見なすことができます。 タスクは、スレッドによって通常のRunnableとして直接使用されるか、CallableとしてExecutorServiceに渡されます。 いずれにしても、IIOPなどの非同期実行の可能性のない同期Java EE APIは、最初にビジネスデリゲートにパッケージ化できます。





リスト4




次のステップでは、Business DelegateロックメソッドがTaskにラップされ、非同期実行が可能になります。



次のステップでは、Business DelegateロックメソッドがTaskにラップされ、非同期実行が可能になります。





リスト5




TaskクラスはRunnableおよびFutureであるため、スレッドで直接実行するか、Executorに渡すことができます。 JavaFXにはjavafx.concurrent.Serviceクラスが付属しています。このクラスは、バインド可能なバインディングプロパティを使用して、ストリーム処理とUIをシームレスに統合します。 サービスは、基本的にファクトリーのTaskメソッドです。





リスト6




サービスの状態とタスク実行の結果は、JavaFXバインド可能プロパティとして利用可能になります。





リスト7




Taskクラスは、継承された同期リソースの非同期統合、またはクライアント側で連続プロセスを実行するための便利なツールです。



非同期ブロッキング

Cometモデルと長いポーリングは、ブラウザーとのプッシュHTTP通信をシミュレートする最良の方法ではありません。 HTTPは要求/応答プロトコルであるため、応答は要求への応答でのみ送信できます。 したがって、初期リクエストなしでHTTP経由でブラウザにデータをプッシュすることはできません。 ロングポーリング通信は簡単に実装できます。ブラウザはサーバーによってブロックされた接続を開始します。 サーバーはブロック接続を使用してデータをブラウザーに転送し、ブラウザーはすぐに接続を終了します。 ブラウザはデータを処理し、サーバーへの後続のブロッキング接続を再開始します。 情報がもうない場合、サーバーはブラウザにリクエスト204を送信します。



JavaFXアプリケーションは、企業内の個別のJavaアプリケーションとしてデプロイされるため、HTTP通信に限定されません。 ただし、RESTエンドポイントは多くの場合HTML5クライアントで使用でき、JavaFXアプリケーションで再利用できます。 RESTおよびJSONは、HTML5クライアント、Javaアプリケーション、さらには低レベルのデバイスと通信するための新しい低グレードの方法になりつつあります。

JavaFXアプリケーションは、HTML5クライアントと同じ方法で長時間のポーリングに直接参加し、通知を受信できます。 同期通信とロングポーリングの唯一の違いは、ブロッキングコールの再開始です。 重複ポーリングは、javafx.concurrent.Serviceを介して直接実装できます。 成功するかどうかに関係なく、サービスはリセットされてから再起動されます。





リスト8




プッシュ統合

プッシュ通信は、要求と応答の通信スタイルであり、要求部分はありません。 アプリケーションサーバーはいつでもデータをプッシュできます。 Java Message Service(JMS)、WebSocket、およびメモリグリッドには、ファイアアンドフォーゲットベースで動作し、JavaFXと簡単に統合できる通知メカニズムがあります。

JSR 356はWebSocketプロトコルを実装し、Java EE 7の一部であり、JavaクライアントAPIが付属しています。 WebSocket仕様では、双方向バイナリプロトコルが導入されており、UIクライアントの統合に最適です。 リスト9に示すように、WebSocketメッセージはバイナリまたはテキストであり、エンドポイントサブクラスで受信されます。





リスト9




SnapshotEndpointクラスは文字列メッセージを受信し、XMLバインディング(JAXB)APIのJavaアーキテクチャを使用してそれを変換します。 スナップショットドメインオブジェクトは、注釈付きのPOJOです。





リスト10




JSR 356 APIは拡張機能をサポートしているため、シリアライゼーションとデシリアライゼーションを専用のクラスに移動できます。 また、JAXBだけに限定されません。 JSONやシリアル化など、利用可能なオブジェクトのプレゼンテーションを使用できます。 SnapshotEndpointは専用のWebSocketスレッドによってクライアント側で実行されるため、UIを更新するためだけにメッセージを使用することはできません。 Platform.runLaterメソッドを使用すると、メッセージはWebSocketからJavaFXストリームに正しく渡されます。



エンドポイントは、実際の通信のみを担当します。 さらに、WebSocketコンテナには、専用クラスで実装されるものの初期設定と初期化が必要です。





リスト11




これまでのところ、JavaFXの統合機能は実際には使用していませんが、さまざまな統合スタイルにのみ焦点を当てています。 ただし、JavaFXの機能により、同期および非同期統合が特に興味深いものになります。

JavaFX統合

javafx.beans.property.ObjectPropertyプロパティは、Objectのインスタンスをパックし、バインド可能です。 関心のあるクライアントは、リスナーとして登録するか、プロパティに直接アタッチして、パックされたコピーを置き換えるときに通知を受け取ることができます。 (Java Magazine記事「JavaFX Data Binding for Enterprise Applications」の「Narrow Interfacesのバインディング」セクションを参照してください。)通信プロトコルと同期に関係なく、応答にはUIに反映する必要があるドメインオブジェクトが含まれます。 ObjectPropertyを使用すると、UIは値に直接バインドし、データを受信したときに自動通知を受信できます。 プレゼンターはObjectPropertyに直接接続されているため、追加の管理方法が冗長になります。



リスト12




「接続された」ObjectPropertyはごみを取り除き、インターフェースを非常に「狭く」します。 スナップは、アウトバウンド通信にも適用できます。 プレゼンターは、オブジェクトまたはドメインモデルの状態を変更します。これにより、サービス(ビジネスデリゲート)が通知されます。 発信通信では、UIストリームとの同期は不要です。 非同期操作はUIスレッドから直接実行でき、長時間実行される操作はサービスにパッケージ化するか、ビジネスデリゲートで非同期に実行できます。 ただし、すべてのUI操作がドメインオブジェクトの状態を変更するわけではありません。 「保存」や「更新」などの単純なユーザーアクションを、Business Delegateメソッドの呼び出しに直接渡すことができます。



さらなる応答性と簡素化

JavaFX UIはイベント駆動型であり、非同期です。 また、JAX-RS 2.0、JMS、またはWebSocketなどのJava EE 7 APIには非同期機能があります。 JavaFXを非同期Java EE 7 APIと組み合わせて使用​​すると、コードが大幅に簡素化されます。 すべてのBusiness Delegate操作は、UIまたはBusiness Delegate自体をブロックすることなく非同期に実行できます。 対話パターンは通信プロトコルに依存せず、すべての非同期Java EE 7 APIに順番に適用できます。

要求は、「起動して忘れた」モードでサーバーに送信されます。 応答を待つ代わりに、応答を処理するためにコールバックメソッドが登録されます。 コールバックはデータを受信し、サブジェクトエリアオブジェクトに入力し、現在のオブジェクトをPlatform.runLaterメソッドで設定されたObjectProperty#に置き換えます。 サブジェクトエリアの変更はプレゼンターにブロードキャストされ、プレゼンターは変更に関するメッセージをすべての関心のある受信者に送信します。

完全な非同期通信により、必要なコードの量が大幅に削減されます。 データバインディングを使用して双方向で「実行して忘れる」アプローチを使用すると、時間モデルとサーバー側のメイン状態の間でデータを同期する必要がなくなります。 すべてのアクションはビジネスデリゲートに直接渡され、アプリケーションサーバーからのすべての要求はUIを直接更新します。

また、完全に非同期の対話を使用することで、対話(UX)のエクスペリエンスを大幅に改善できます。 サーバーとのやり取りがどれほど高価であっても、UIがブロックすることはありません。



おわりに

一見、JavaFXとサーバーサービスの統合はSwingと非常によく似ています。 プラットフォーム#runLaterはjavax.swing.SwingUtilities#invokeLaterと同等であり、javafx.concurrent.Serviceのコンテンツはjavax.swing.SwingWorkerと非常に似ています。



最新のJava EE 7 API、JavaFXデータバインディング(「エンタープライズアプリケーションのJavaFXデータバインディング」を参照)、およびFXMLとScene Builderを使用した逆制御機能(「JavaFX Scene Builderのエンタープライズアプリケーションへの統合」を参照)により、ロジックとマルチビューデスクトップアプリケーションを実装するための一貫したアプローチを導入します。



Java EE 6および7のサーバー部分を使用すると、サーバー側で非同期相互作用スタイルを引き続き使用できます。



Adam BienのマスタークラスJava EE:アーキテクチャ、パターン、およびソリューションは、6月3〜5日に開催されます。 マスタークラスと参加条件の詳細はこちらをご覧ください

画像







All Articles