Johan Vos: 1995 年から Java に関わる。 ソーシャル・ネッ トワーキング・ ソフトウェア向 けの Java ベー ス・ソリューショ ンに取り組む LodgON の共同 創設者。組込み 開発とエンター プライズ開発の 両方に熱心で あり、徹底して JavaFX と Java EE を使用したエ ンド・ツー・エ ンドの Java に 専念。 Java 8 Is Here 写真: TON HENDRIKS J avaFX が、Raspberry Pi 上 Java SE 8 を使用して、近距離 で稼働する素晴らしいプラッ 無線通信(NFC)対応型カード・ トフォームであることは、すで リーダーとの通信、画面への に実証されています。 ステータス・メッセージの表示、 組込みデバイスのクライアン バックエンド・システムへの情 ト・サイド Java 開発に携わっ 報送信を行う方法を説明しま ていれば、おそらくJavaFX と す。 Raspberry Pi の相性のよさはご 注:本記事で紹介するサン 存知でしょう。組込みデバイス プルのソース・コードは https:// はキオスク端末環境で多用さ bitbucket.org/johanvos/ れます。その一例がカード・リー javafx-pi-nfc からダウンロード ダーを接続した組込みデバイ できます。 スで、利用者は何ら 対象システムのコン かのアクション(入 準備万端 ポーネント 室許可を得る、支払 NFC 仕様では、デ いを行う、融資を受 現在の Java ス けるなど)を開始す キルを活用して、 バイス間の近距離 無線通信(近接す るために、カードを 異なる環境に及 るデバイス間の非 スキャンする必要が あります。 ぶエンド・ツー・ 接触通信)に関す る標準が多数定義 世の中には、さま エンドのアプリ されています。さま ざまなカード・リー ケーションを構 ざまな種類のチッ ダー、カード、プ プセット搭載型カー ロトコルが存在し 築できます。 ドがありますが、本 ます。本記事では、 記事では MIFARE Raspberry Pi 用の ORACLE.COM/JAVAMAGAZINE ///////////////////////////// MARCH/APRIL 2014 DESFire カードを使用します。 カード・リーダーは、 Raspberry Pi で標準的に動作 するものを選択する必要があり ます。 Advanced Card Systems Ltd. 製の USB ベース・カード・リー ダーである ACR122U は、広範 に利用されているデバイスであ り、Raspberry Pi に簡単に接続 して、MIFARE カードを読み取 ることができます。 注:カード・リーダーは 電力を大量に消費するため、 Raspberry Pi との接続には、電 源付き USB ハブを使用するこ とをお勧めします。 視覚的なフィードバックを得 るために、Raspberry Pi に画 面を接続する必要があります。 一般的な HDMI モニターをは じめ、車両やキオスク端末、 コピー機に適した小型画面ま で、さまざまな画面が販売さ れています。 本記事で利用するセットアッ プ方法は一例です。 Raspberry Pi のセットアップ このプロジェクトのコードを実 行するためには、実際に動作 するセットアップが必要です。 本記事で利用する Raspberry Pi 向けイメージはこちらからダ ウンロードできます。 ACR122U カード・リーダー をこのイメージと連携させるた めに、さらに 2 つのパッケー ジをインストールする必要があ ります。以下のコマンドを実行 してインストールします。 sudo apt-get update sudo apt-get install libpcsclite1 pcscd Java のインストール Java SE 8 をダウンロードして、 Raspberry Pi にインストールし ます。 Java SE では javax. smartcardio パッケージを使用 してスマート・カード・リーダー COMMUNITY JAVA IN ACTION JOHAN VOS 現在の Java スキルを活用して、組込みデバイスに接続されたカード・リーダーから バックエンド・システムに及ぶエンド・ツー・エンドのアプリケーションを作成する JAVA TECH Raspberry Pi 上で稼働する JavaFX と 近距離無線通信 ABOUT US //embedded / blog 52 private StringProperty latestId = new SimpleStringProperty(" --- "); この単純なユーザー・インタフェー Task task = new Task() { … }; Thread thread = new Thread(task); thread.start(); この Task は以下の操作を実行しま す。 1. カード・リーダーを検出します。 2. カード・リーダーで認識されて いるカードを検出します。 3. そのカードの識別子を読み取り ます。 4. latestId の値を更新します。 5. カードが離されるまで待機しま す。 6. ステップ 2 に戻ります。 カード・リーダーの検出:カー ド・リーダーにアクセスするため には、TerminalFactory が必要で す。javax.microcard パッケージの 静的メソッドを使用して、デフォル トの TerminalFactory を取得できま す。また、カード・リーダーの種類 ORACLE.COM/JAVAMAGAZINE ///////////////////////////// MARCH/APRIL 2014 リスト4 リスト5 リスト6 HBox hbox = new HBox(3); Label info = new Label("Last checkin by: "); Label latestCheckinLabel = new Label(); latestCheckinLabel.textProperty().bind(latestId); hbox.getChildren().addAll(info, latestCheckinLabel); Scene scene = new Scene(hbox, 400, 250); primaryStage.setScene(scene); primaryStage.show(); すべてのリストのテキストをダウンロード に応じた固有の TerminalFactory イ ンスタンスを作成することもできま す。デフォルトの TerminalFactory では、前項で Raspberry Pi にインス トールした PC/SC スタックが使用さ れます。リスト 2 のコードの呼出し により、TerminalFactory を取得しま す。次に、リスト 3 のコードにより terminalFactory を問い合わせて、イ ンストールされているカード・リー ダーを検出できます。 この例ではセットアップが成功し ており、cardTerminalList に 1 つ の要素が含まれています。リスト 4 のコードを実行して、この 1 つの CardTerminal を取得します。 カードの検出:カード・リーダーの 参照を取得した後、カードの読取り を開始できます。カードの読取りは、 リスト 5 のように無限ループを使用し て実行します。なお、現実的には、 読取りを停止する手段としてダミーの カードを使用することが考えられま す。 リーダーによってカードが検出さ れるまで、スレッドがブロックされま す。カードの検出後は、次項で説明 する方法によりカードを処理します。 その後、カードが離されるまでスレッ ドが再度ブロックされます。 カードの処理:カードがカード・リー ダーの近距離にあることを検出した ときに、handleCard メソッドを呼び 出します。カードは読取り中にも離 される可能性があるため、適切な例 外処理も必要であることに注意してく ださい。 カードへの接続は、リスト 6 のコー ドを実行して取得できます。 カードの識別子を読み取るために は、読取り中のカードの種類を把握 する必要があります。カードの種類 に応じて異なるアドレスに識別子が 保管されます。この単純なデモでは、 MIFARE DESFire カードのみを対象と していますが、対応するカードの種 類を増やすようにサンプルを拡張す ることも簡単です。 読取り中のカードの種類に関する 情報は、以下のようにカードの ATR (Answer To Reset)バイト・データ を調べることで取得できます。 JAVA TECH java -Dsun.security.smartcardio .library=/path/to/libpcsclite.so JavaFX アプリケーション カード・リーダーと接続してカードを 読み取る動作には、ある程度の時間 がかかる場合があります。そのため、 これらのタスクを JavaFX アプリケー ション・スレッドのレベルで実行する のは得策ではありません。代わりに、 カード・リーダーを処理し、JavaFX の標準的な手法でユーザー・インタ フェースを更新する専用のスレッドを 作成します。 ユーザー・インタフェースの作成最後 にスキャンされたカードの識別子を 表示する、ごく単純なユーザー・イ ンタフェースを作成します。この識別 子は、以下のように StringProperty latestId に格納されます。 スは、静的情報を含むラベルと最後 にスキャンされたカードの識別子を 含むラベルを並べた 1 つの HBox の みで構成されます。この HBox の作 成方法をリスト 1 に示します。 カード・リーダーとの通信:カー ド・リーダーと通信するスレッドを doCardReaderCommunication とい う関数内で作成します。この関数を JavaFX アプリケーションの start() メ ソッド内で呼び出します。 以下のように JavaFX の Task が作成 され、新しいスレッドに割り当てられ た後、開始されます。 リスト3 ABOUT US と通信できます。このパッケージは デフォルトで、システム上の PC/SC (Personal Computer/Smart Card) 実装を検索します。 必要な Linux パッケージを Raspberry Pi にインストールした後 は、Java 仮想マシンから pcsclite ラ イブラリの場所を参照できるようにす るだけです。 そのためには、以下のようにシ ステム・プロパティ sun.security. smartcardio.library の値として pcsclite ライブラリの場所を設定しま す。 リスト2 COMMUNITY リスト1 JAVA IN ACTION //embedded / blog 53 リスト7 Platform.runLater(new Runnable() { public void run() { latestId.setValue(uid); } このように処理を分離することで、 カード・リーダーとの通信とユー ザー・インタフェースのアクティビティ が相互に阻害されないことも保証さ れます。 バックエンドへのデータ送信:多くの 場合、リーダーでカードがスキャン された際には視覚的なフィードバッ クが必要です。また、場合によって は、バックエンド・システムに情報 を送信する必要があります。次項で は、データをバックエンドに送信す るごく単純なクライアント・サーバー・ モジュールを使用して、識別子を Raspberry Pi から Java EE 7 バックエ ンドに送信し、Web ページに表示し ORACLE.COM/JAVAMAGAZINE ///////////////////////////// MARCH/APRIL 2014 リスト10 リスト11 リスト12 JAVA IN ACTION static byte[] desfire = new byte[]{0x3b, (byte) 0x81, (byte) 0x80, 0x01, (byte) 0x80, (byte) 0x80}; すべてのリストのテキストをダウンロード ます。JavaFX アプリケーションから REST ベース・バックエンド・システ ムへのデータ送信は、DataFX を使 用して容易に実行できます。 リスト 11 のコードは、識別 子 uid を REST エンドポイン ト(http://192.168.1.6:8080/ webmonitor/rest/card/checkin)に 送信します。 この送信では、REST リクエスト内 でフォームのパラメータを指定して いるため、POST メソッドを使用し ます。新しい識別子を読み取るたび に、このメソッドを呼び出す必要が あります。スレッド管理は DataFX に よって行われるため、このメソッドは JavaFX アプリケーション・スレッドか ら呼び出す必要があります。したがっ て、latestId プロパティの値を設定す るコード・ブロック内で、このメソッ ドを呼び出すことができます(リスト 12)。 実際のアプリケーションでは、サー バーからクライアントに他の情報 (カード利用者の実名など)も送信 されると考えられます。クライアント・ アプリケーションではこの情報を利用 して、各利用者に合わせたユーザー・ インタフェースを作成できます。 バックエンド 次に、REST リクエストを受信して Web ページに表示する、ごく単純な バックエンドを作成します。前提とし て、いつカードがスキャンされてい るかは Web ページの利用者にはわ かりません。そのため、カードのス キャンが完了するたびに Web ペー ジを動的に更新することは合理的 です。動的な更新は、Java EE 7 の WebSocket API を利用して容易に実 行できます。必要なコード量の少な さに驚くはずです。 まずは Web ページの作成に取り 掛かります。この Web ページは、 checkins という名前のブロック要素 JAVA TECH Arrays.equals( desfire, atr.getBytes()); リスト 7 に示すとおり、desfire は 期待する情報を格納した静的バイト 配列です。 対応している種類のカード(つま り DESFire カード)である場合は、 その識別子を問い合わせることがで きます。そのためには、カードの基 本論理チャネル経由で APDU(アプ リケーション・プロトコル・データ・ ユニット)コマンドを送信し、レス ポンスを読み取る必要があります。 この一連の処理は javax.microcard パッケージを利用して行います(リス ト 8)。 このコードで渡している getAddress パラメータは、DESFire カードの識別子 キオスク端末の基 を読み取る方法 本 を定義した静的 キオスク端末では、カー バイト配列です。 このパラメータの ド・リーダーが組込みデ 宣言をリスト 9 に バイスに接続され、ユー 示します。必要 なバイト配列は、 ザーがカードをスキャン カードの種類に して何らかのアクション よって異なりま す。 を開始します。 リスト9 ABOUT US ATR atr = card.getATR(); 次に、以下のように、この atr オ ブジェクト内のバイト・データを DESFire カードで期待されるバイト・ データと比較します。 readable(byte[]) 関数は、バイト配 列を人間に判読できる形式にするた めに、各バイト値を 16 進の String 表現に変換します(リスト 10)。 これで、判読可能なカード識別子 を作成できたので、次は、この識別 子をユーザー・インタフェースに表 示する必要があります。識別子の取 得は、JavaFXアプリケーション・スレッ ドとは異なるスレッド(通信用スレッ ド)で行っています。そのため、通 信用スレッドから直接 StringProperty latestId を変更するのではなく、以下 のように JavaFX アプリケーション・ スレッド上で変更を行う必要があり ます。 リスト8 COMMUNITY //embedded / blog 54 ORACLE.COM/JAVAMAGAZINE ///////////////////////////// MARCH/APRIL 2014 リスト15 リスト16 function openConnection() { connection = new WebSocket('ws://localhost:8080/webmonitor/endpoint'); JAVA TECH } connection.onmessage = function(evt) { var date = new Date(); var chld = document.createElement("p"); chld.innerHTML = date + " : " + evt.data; var messages = document.getElementById("checkins"); messages.appendChild(chld); }; すべてのリストのテキストをダウンロード WebSocket クライアントに識別子を 送信するように変更できます(リスト 16)。 まとめ 本記事では、組込み Java アプリケー ションの作成、単純な JavaFX ユー ザー・インタフェースによるアプリ ケーションの強化、外部ハードウェ ア(カード・リーダー)への接続、 Java EE システムへの接続、そして HTML5 を使用した情報の視覚化を、 いずれも容易に行えることを確認しま した。 基盤となるすべてのシステムで同 じ Java SE コードが使用されます。 そのため、開発者は現在の Java ス キルを活用して、異なる環境に及ぶ エンド・ツー・エンドのアプリケーショ ンを構築できます。</article> ABOUT US (div)を含む単純な HTML ページ を受信する専用メソッドは checkin です。このブロック要素内に識別子 というパスに関連付けられます。ま のリストと、各カードのスキャン実行 た、この専用メソッドは、id という 時のタイムスタンプを表示します。 名前のフォーム・パラメータを受け HTML ページのロード時に、単 取ります。このパラメータに識別子 純なバックエンドを参照する が格納されています(リスト 14)。 WebSocket が作成されます。この この情報を WebSocket クライア WebSocket 経由でメッセージが到着 ント(例:前項で作成した単純な するたびに、checkins Web ページ)に送信す ブロック要素の内容が再 試してみよう る場合は、WebSocket 設定されます。リスト 13 エンドポイントも登録す 組込み Java アプリ に示すコードにより、こ る必要があります。1 つ ケーションの作成、 の目的を容易に達成で のクラスに複数のアノ 単純な JavaFX ユー きます。 テーションを追加でき この HTML ページで るため、この目的でも ザー・インタフェース は、localhost:8080/ CardHandler を利用で によるアプリケーショ webmonitor/endpoint きます。こうして、すべ に対する WebSocket ンの強化、カード・リー てのバックエンド・コー が開かれます。一方、 ドを単一のファイル内 ダーへの接続、Java JavaFX アプリケーション に配置します。単一ファ EE システムへの接続、 では、localhost:8080/ イルによる実装は、複 webmonitor/rest/card/ 雑な本番システムの場 HTML5 を使用した情 checkin に対して識別子 合、おそらく最適では 報の視覚化を容易に がプッシュされます。こ ありません。しかし本記 れらのコンポーネントを 事の実装から、REST と 行うことができます。 まとめるのが、単一ファ WebSocket を組み合わ イルによるバックエンド・ せた Java エンタープラ システムです。このバッ イズ・アプリケーション クエンド・システムを CardHandler の構築がいかに簡単であるかがわか クラス内で実装します。 ります。 CardHandler は REST エンドポ WebSocket エンドポイントで接続 イントとなるため、javax.ws.rs. リクエストを受信したときには、作 core.Application を継承します。ま 成されたセッションを Set に格納しま た、REST インタフェースの場所 す。接続が閉じられるときには、こ の値が rest であることを示す @ のセッションを Set から削除します(リ ApplicationPath アノテーションが スト 15)。 付加されます。このハンドラ自体は さらに、リスト 14 で作成した card というパスに登録され、識別子 checkin メソッドを、接続中の リスト14 COMMUNITY リスト13 JAVA IN ACTION //embedded / MORE ON TOPIC: Java 8 Is Here blog LEARN MORE • Raspberry Pi • JavaFX 55
© Copyright 2024 ExpyDoc