Posts filed under ‘Java’
祝 Java EE 7 ローンチの日本における反応
日本時間の深夜から午後に掛けて、世界に渡る Java EE 7 ローンチ・イベントがおかげさまで無事終了致しました。日本から深夜、もしくは午後にご参加頂いたエンジニアもいらっしゃいますが、本イベントにご参加頂いた皆様には、Java EE 7 の3つテーマ(HTML 5 対応、開発生産性の向上、エンタープライズ・ニーズへの対応)をご理解頂けたのではないかと思います。
また主要な統合開発環境(Eclipse, NetBeans, Intellij)も Java EE 7 へ対応する事で、今後日本におけるエンタープライズ開発の標準も Java EE 7 へ移行していく物と思われます。今回リリースされた Java EE 7 には様々なテクノロジーが含まれますが、Java EE 7 に含まれる各種機能を試された方は、是非その試された内容をブログや Wiki 等で記載して頂ければ嬉しく思います。

Java EE 7 は EE 6 に対して開発生産性を向上したバージョンであるため、本来であれば Java EE 7 を直接試していただきたいのですが、仮に Java EE にはじめて触れられる方で Java EE の全体像が理解できない方、もしくは英語が大の苦手な方は、既存の Java EE 6 の日本語書籍(Amazon : Beginning Java EE 6 GlassFish 3で始めるエンタープライズJava (Programmer’s SELECTION) [大型本]) をご参照頂き全体像をご理解頂いた上で、Java EE 6 と EE 7 の差分を抑えて頂く事も可能ですので、いずれかのやりやすい方法で Java EE 7 に触れていただければ幸いです。
最後に、Java EE 7 のローンチに関連して各種メディア、ブログ等に記載された内容を下記にご紹介します。今まで Java EE に実際に触れて来られた方も、この新しい Java EE 7 に期待している内容などが記載されていますので、是非下記の記事もご参照頂ければ幸いです。
(※ 私もブログ書いたよという方がいらっしゃいましたら是非ご連絡ください、下記に追加させて頂きます。)
オンラインメディア
- Publickey:Java EE 7対応のアプリケーションサーバ「GlassFish 4」オープンソース版が公開
- マイナビ ニュース:Oracle、Java EE 7を提供開始
- クラウド Watch : 米OracleがJava EE 7をリリース、HTML5対応アプリの構築を支援する新機能などを追加
- SourceForge.JP:「Java EE 7」が正式発表、米Oracleから初の登場
- @IT : HTML5のサポート強化や開発者の生産性を向上:Oracle、「Java EE 7」を提供開始
個人ブログ
- 武者返し.com:祝! Java EE 7リリース
- きしだのはてな:WebSocketをネタにJava EE 7正式版を試してみる
- しんさんの出張所 はてな編:JavaEE 7 登場
- Challenge Java EE !:NetBeans7.3.1でJava EE7とGlassFish4を少しのぞいてみました チラ| |д・)
- Programming Studio : GlassFish 4.0 正式リリース (GlassFish ユーザ・グループ・ジャパン副会長)
- yoshio3.com:Java EE 7 ローンチ (US 時間: 06/12 午前9時)
Java EE 7 対応関連書籍
Java EE 7 ローンチ (US 時間: 06/12 午前9時)
US 時間で 2013 年 6 月 12 日 午前 9 時より Java EE 7 のローンチ・イベントが開始します (日本では 2 回目のローンチ・イベントで 6 月 13 日 午後 1 時から参加頂けます)。Java EE 7 は、 2009 年にリリースされた Java EE 6 をベースに、4 つの新機能 (WebSocket, JSON, Batch, Concurrency Utilities for EE) と、既存の機能に対する大幅な更新 (JSF 2.2, JAX-RS, EL 3.0, JMS 2.0)を加えた、最新のエンタープライズ向け Java 標準技術です。

Java EE 7 に含まれる各種技術に触れたい場合、Java EE 7 の参照実装である GlassFish v4 を入手した上で、Java EE 7 のチュートリアルをご参照いただきお試しください。また、GlassFish v4.0 をバンドルし、 Java EE 7 の開発に対応した NetBeans 7.3.1 を入手いただく事で余計な設定は不要でいち早く Java EE 7 の開発を体験していただく事ができます。
Java EE 7 の新機能
- Web Socket API
- JSON Processing
- Batch
- Concurrency Utilities for Java EE
今日は、Java EE 7 の正式リリースを記念して、私が今まで様々な所で紹介してきた Java EE 7 のプレゼン資料をまとめ、また過去に発表した内容の中で、正式リリース時点で変更してしまった部分等も改めて見直し、最新情報にアップデートした資料を下記に共有します。全部で P165 ありますので、必要に応じて SlideShare よりダウンロードしてご参照ください。
本ブログをご参照頂いた皆様へ:
もしよろしければ、下記のアンケートにご協力頂けないでしょうか。今後の情報提供の際に役立てたいと思います。(※ アンケートにお応え頂くと他の方の結果をご覧頂けます。)
下記に Java EE 7 の技術のうち新規追加された 4 つの機能について簡単にご紹介します。
* Java API for WebSocket 1.0 (JSR-356):
WebSocket は RFC 6455 で定義された HTTP をアップグレードした TCP ベースのプロトコルで、双方向・全二重の通信が可能なプロトコルです。最新バージョンのブラウザであれば IE 10 を含む、ほぼ全てのブラウザが WebSocket に対応しています。JSR-356 は Java EE に含まれる技術ですのでアプリケーション・サーバ上で動作する WebSocket を実装する事はもちろんできますが、Java SE の環境上でも WebSocket のプログラムを実装するための API を提供しています。サーバ、クライアント共にクラスに対してアノテーション(@ServerEndpoint, @ClientEndpoint) を付加、もしくは javax.websocket.Endpoint クラスを継承したクラスを定義し実装します。クラス内には WebSocket の各ライフサイクルで必要な実装をそれぞれ、OnOpen, OnClose, OnError, OnMessage 内で実装します。
WebSocket はクライアントとサーバ間の通信において、HTTP のように通信時に余分なデータ(HTTP ヘッダ)を互いに送り合う事はなく通信コストを大幅に削減し、リアルタイム通信が必要な環境などで大きな注目を浴びている技術です。今まで、Comet, Reverse Ajax 等の技術を使って実装していたリアルタイムの情報配信システムにとっては、大幅にパフォーマンス向上が可能なWebSocket が標準の Java EE に含まれる事で、エンタープライズ環境でも安心して使う事ができます。
参考資料:
http://slideshare.net/arungupta1/websocket-10-21153123
● Java EE 7新機能の目玉「WebSocket対応」、「バッチ処理」をアルン・グプタが解説──Java Day Tokyo 2013レポート
● Java EE 7 チュートリアル : WebSocket API
● DZone : JSR 356, Java API for WebSocket
● java.net WebSocket Spec
* Java API for JSON Processing (JSR-342)
JSON-P は JSON の処理(パース、生成、クエリなど)を Java で実施するための API を提供します。実装は、ストリーミング API もしくは オブジェクト・モデル API の2種類の方法のいずれかを利用することができます。
ストリーミング API は、イベント・ベースのパーサを利用して、発生するイベントに応じて JSON の解析処理、生成処理などのプログラミングを行う事ができます。開発者はコールバックイベントではなく、次に発生するイベントの処理を実装していきます。ストリーミング API を利用するためには、javax.json.stream パッケージ内の JsonParser や JsonGenerator を利用します。
オブジェクト・モデル API はメモリ上に JSON のデータをオブジェクトのツリー構造として表現し、開発者はこのツリーに対して解析や修正を行います。この方法はとても簡単でさらに直感的に扱う事ができますが、その一方で Streaming モデルよりも若干遅く、またメモリもより消費します。オブジェクト・モデル API を利用するためには、javax.json パッケージ内の JsonReader, JSonWriter, ビルダー(JsonObjectBuilder, JsonArrayBuilder)等を利用します。
参考資料:
http://www.slideshare.net/reza_rahman/jsonp-19896185
● Java EE 7 チュートリアル:JSON
● java.net : JSON
● Java EE エキスパートグループ・メンバー(Markus Eisele):Test driving Java API for Processing JSON with GlassFish 4.0
● InfoQ :
JSON用標準JavaAPI
* Batch Application for the Java Platform (JSR-352)
バッチは、ユーザとのインタラクティブな操作が不要な処理を実行します。jBatch ではバッチ・ジョブの定義、実装方法を提供します。ジョブ仕様言語を XML で定義し 、バッチ関連アノテーション、インタフェースから構成されるビジネスロジックを実装します。またバッチ・コンテナでバッチ・ジョブの実行を管理します。
バッチ・ジョブはチャンク形式とタスク(Batchlet)形式のステップを含んでいます。
チャンク形式のステップはデータ・ソースからデータを読み込み、各データに対してビジネスロジックを適用し結果を保存します。
チャンク形式は3つの要素(入力、操作、出力)から構成されます。まず、はじめにデータ入力の部分では、データ・ソースから一度に一つのデータを読み込みます。たとえばデータベースのエントリやファイル、ディレクトリ、ログファイルに含まれるエントリ等がこれに当てはまります。次にビジネス・ロジックの適用部分では、アプリケーションで定義されたビジネス・ロジックを使用して一度に一つのデータの操作を行います。例えばデータのフィルタリング処理、データのフォーマットなどがこれに当てはまります。最後の出力部分では処理が行われたデータの保存を行います。データの入力では、javax.batch.api.chunk.ItemReader インタフェースを実装したクラスを定義します。データの処理には、javax.batch.api.chunk.ItemProcessor インタフェースを実装したクラスを定義します。出力ではjavax.batch.api.chunk.ItemWriter インタフェースを実装したクラスを定義します。
タスク形式のステップは、データ・ソースからデータを取得して処理を行うのではなく、任意のタスクを実行します。例えば、ディレクトリの作成、削除、ファイルの変更、データベース・テーブルの作成・破棄、リソース設定等がこれに当てはまります。タスク・ステップはチャンク形式とは異なり通常短時間で終わる処理を実装します。タスク形式のステップでは、javax.batch.api.chunk.Batchlet インタフェースを実装したクラスを定義します。
参考資料:
http://www.slideshare.net/arungupta1/jbatch-21153200
http://www.slideshare.net/agetsuma/batch-applicationforthejavaplatform
● Java EE 7新機能の目玉「WebSocket対応」、「バッチ処理」をアルン・グプタが解説──Java Day Tokyo 2013レポート
● Introducing JSR-352 – Batch Applications for the Java Platform
* Concurrency Utilities for Java EE (JSR-236)
Concurrency Utilities for Java EE はエンタープライズ環境における並列処理タスクの実装方法を提供します。Java EE 6 まではWeb コンテナ(JSP/Servlet)、もしくは EJB コンテナ(EJB)上から新しいスレッドを生成する事は禁止されていました。これは、これらのコンテナ上からスレッドを生成した場合、生成されたスレッドがコンテナ外部で動作しコンテナから生成されたスレッドを管理する事ができなくなるためです。Concurrency Utilities for Java EE ではコンテナ上で安心して新しいスレッドを生成する方法を提供します。
最も簡単に並列タスクを EE 環境で利用するためには、javax.enterprise.concurrent.ManagedExecutorService を利用します。ManagedExecutorService は Java SE の Concurrency Utilities で提供されるjava.util.concurrent.ExecutorService インタフェースを継承していますが ManagedExecutorService は Java EE の実行環境(つまりアプリケーション・サーバ)で実装されています。サーバ側の ManagedExecutorService の実装への参照を、自身のプログラム上で JNDI ルックアップ、もしくは @Resource アノテーションを使用してインジェクトし利用できるようにします。リソースをインジェクトした後は、Runnable, Callable インタフェースを実装したタスクを execute(), submit(), invokeAll(), invokeAny() 等のメソッドを呼び出して実行します。
参考資料:
http://www.slideshare.net/OracleMiddleJP/concurrency-utilities-for-java-ee-7
● JSR 236 スペックリード:Anthony Lai の説明資料 (PDF) : Concurrency Utilities for Java EE
● Concurrency Utilities for EE の説明(私のブログ)
● ZDNet builder : マルチコア時代のCPUリソースを有効活用–Java EE 7で進化した並列処理を理解する
● @IT : エンタープライズ環境におけるマルチスレッド/並列処理の過去・現在・未来
● DZone : Modern concurrency and Java EE
以上が Java EE 7 で提供される新機能です。Java EE 7 の参照実装である GlassFish v4 をダウンロードして頂き、Java EE 7 の新機能を是非お試しください。
※ 下記に JSF 2.2 と EL 3.0 に関して説明していますが、これらは Java EE 6 から更新された技術です。
JavaServer Faces 2.2(JSR-344)
JSF は Java EE 環境におけるデフォルトの Web 開発フレームワークで世界中で幅広く使用されています。Java EE 6 の正式リリース時には JSF 2.0 が標準で提供され、その後、JSF 2.1 がリリースされました。
JSF 2.1 では JSP ベースのページを .jspx ファイルとする事で、Facelets として扱う事ができるようなり、JSF 1.2 で実装されたコードをマイグレーションしやすいような方法を抵抗した他、プラグイン可能な Facelet のキャッシュ機能を実装しています。また ServletContainerInitializer が追加されデフォルトの設定で問題ない場合、web.xml での設定は不要となりました。
そして、Java EE 7 では JSF 2.2 としてさらに大きな変更が加わりました。
* HTML 5 への対応(Pass-througu の属性が追加)
* 画面遷移における新機能の追加
Faces Flow
* ステートレス・モードの追加
* リソース・ハンドリング機能の改善
(マルチ・テンプレート機能は次のバージョンへ持ち越されました)
/contracts, META-INF/contracts にテンプレートのリソースを配置
* その他
この中で、特筆すべき事は JSF にステートレス・モードが追加された事です。JSF は 1.x のリリース当初から JSF における View の全てのステート(状態の情報)を保持していました。これはメモリも大量に消費し、パフォーマンスも良くありませんでした。そこで JSF 2.0 からは、部分的に状態を保存する Partial State Saving の機能が追加され、JSF 1.x の頃に比べパフォーマンスを改善する事ができました。そして JSF 2.2 からはついに状態を持たないステートレス・モードが JSF 2.2 に追加されました。これは現在の流行にそう形ですが、パフォーマンスが大幅に改善しメモリの使用量も減ります。またクラスタ環境で任意のノードに対してリクエストを送信する事が可能になります。今まで JSF をパフォーマンスの観点から見送っていた方々も JSF 2.2 の stateless (<f:view transient=”true”>)モードをご使用ください。
* Expression Language 3.0 (JSR-341)
EL は Java Beans のプロパティやメソッドとのバインディングに使用する式言語で、通常、JSP, JSF のビューから CDI で実装されたバッキング・ビーンのプロパティやメソッド呼び出しなどを結びつけるために使用します。
EL 3.0 では新たな構文が追加されています。新たに Java のコレクションに対して LINQ式を記述できるようになった他、Lambda 式も EL 式内に記述できるようになりました。ただし、EL における LINQ 式はコレクションに対する操作のみが許可されているため、直接 DB を操作する事はできません。また、EL 内で記述する Lambda 式は Java SE 8 で提供される Lambda 式の文法と同一ですが、動作環境は Java SE の環境には依存しません。つまり Java SE 7 の環境上でも EL 式内においてのみ Lambda 式を記載できるようになっています。
また EL は今まで Java EE の環境でしか動作しませんでしたが、EL 3.0 では Java SE 環境上でも動作するようになりました。
最後に、本日正式リリースされた Java EE 7 は Java EE 6 をベースに、プラスαの要素をご理解いただく事で、簡単に Java EE 7 に移行する事ができます。
ご注意(NOTE): WebSocket with Concurrency for EE
Java EE 7 のリリースが控えておりますが、先日 Java Day Tokyo で私のセッションの中でデモした WebSocket (JSR-356) と Concurrency Utilities for EE (JSR-236) を組み合わせたデモのコードについてご紹介すると共に、実装時の注意点をご報告いたします。
下記は、実際に私が WebSocket (JSR-356) と Concurrency Utilities for EE (JSR-236) を組み合わせたコードを実装する際にハマった内容をお届けします。
コードは下記のようなコードを記載しています。
package jp.co.oracle.websocket;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Resource;
import javax.enterprise.concurrent.ManagedExecutorService;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import jp.co.oracle.tasks.WebSocketAIRSearchTask;
import jp.co.oracle.tasks.WebSocketHotelSearchTask;
@ServerEndpoint(value = "/asyncResult")
public class AsyncResultWebSocketEndpoint {
private static final Logger logger = Logger.getLogger(AsyncResultWebSocketEndpoint.class.getPackage().getName());
// Concurrency Utilities for EE の ManagedExecutorService をインジェクト
@Resource(name = "concurrent/DefaultManagedExecutorService")
ManagedExecutorService managedExecsvc;
// WebSocket のコネクションがオープンした際の処理
@OnOpen
public void initOpen(Session session) {
executeTasks(session);
}
// WebSocket クライアントからメッセージを受信した際の処理
@OnMessage
public void receivedMessage(String message, Session session) {
if (!message.equals("re-execute")) {
return;
}
executeTasks(session);
}
// 実際の処理内容
private void executeTasks(Session session) {
// 複数タスクの実行の際に終わった順に処理結果を取り出す
ExecutorCompletionService<String> execCompService = new ExecutorCompletionService<>(managedExecsvc);
// 複数タスクの登録
List<Future<String>> futures = new ArrayList<>();
for (int i = 0; i < 100; i++) {
WebSocketHotelSearchTask task = new WebSocketHotelSearchTask(i);
futures.add(execCompService.submit(task));
}
try {
// 終了したタスクの順番に処理結果を取得し
// 処理結果を WebSocket のクライアント・エンドポイント
// に対して処理結果を送信
for (Future<String> results : futures) {
String resultString = execCompService.take().get();
session.getBasicRemote().sendText(resultString);
}
} catch (IOException | InterruptedException | ExecutionException ex) {
logger.log(Level.SEVERE, null, ex);
}
}
}
ダミーのタスク
package jp.co.oracle.tasks;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;
public class WebSocketHotelSearchTask implements Callable<String> {
private static final Logger logger = Logger.getLogger(WebSocketHotelSearchTask.class.getPackage().getName());
private int counter;
public WebSocketHotelSearchTask(int counter) {
this.counter = counter;
}
// タスクの処理内容によっては時間のかかるタスクもあるため
// 半分のタスクをわざと 4 秒待たせ、タスクの登録順にタスクが
// 完了しないように作成
@Override
public String call() {
String result = "";
if (counter % 2 == 1) {
Thread.sleep(4000);
}
result = "ホテル検索タスク完了 : 終了タスクの ID" + counter;;
} catch (InterruptedException ex) {
logger.log(Level.SEVERE, null, ex);
}
return result;
}
}
今回、なぜ下記のようにタスクの一括登録を行った後に、タスクの処理が終わった順に WebSocket のクライアント・エンドポイントに対してメッセージ配信を行うコードを実装したかというと(つまり、タスクの処理コード中から WebSocket のクライアントに対してメッセージ配信をしていない)、WebSocket 側のスレッドの制限があったためです。
// 複数タスクの登録
List<Future<String>> futures = new ArrayList<>();
for (int i = 0; i < 100; i++) {
WebSocketHotelSearchTask task = new WebSocketHotelSearchTask(i);
futures.add(execCompService.submit(task));
}
try {
// 終了したタスクの順番に処理結果を取得し
// 処理結果を WebSocket のクライアント・エンドポイント
// に対して処理結果を送信
for (Future<String> results : futures) {
String resultString = execCompService.take().get();
session.getBasicRemote().sendText(resultString);
}
当初、下記のように Runnable (Callable の call() 中で実装も可)のインタフェースを実装したタスクを作成し、タスクの処理の中で WebSocket のエンドポイントに対してメッセージを配信するコードを記載しました。例えば、下記のような感じです。
public class SomeMyTask implements Runnable{
Session session;
public SomeMyTask(Session session){
this.session = session;
}
@Override
void run(){
// 何らかの処理を実施
// タスクの処理の最後に、WebSocket のクライアント・エンドポイント
// に対してメッセージを配信
session.getBasicRemote().sendText(resultString);
}
}
そして、下記のコードを書いてタスクを実行しました。
for( int i = 0 ; i < 10 ; i++ ){
SomeMyTask task = new SomeMyTask(session);
managedExecsvc.submit(task);
}
すると下記の例外が発生しました。
例外の出力内容:
| java.lang.IllegalStateException: HeapBuffer has already been disposed at org.glassfish.grizzly.memory.HeapBuffer.checkDispose(HeapBuffer.java:802) at org.glassfish.grizzly.memory.HeapBuffer.position(HeapBuffer.java:188) at org.glassfish.grizzly.nio.transport.TCPNIOAsyncQueueWriter.fillByteBuffer(TCPNIOAsyncQueueWriter.java:194) at org.glassfish.grizzly.nio.transport.TCPNIOAsyncQueueWriter.writeComposite0(TCPNIOAsyncQueueWriter.java:151) at org.glassfish.grizzly.nio.transport.TCPNIOAsyncQueueWriter.write0(TCPNIOAsyncQueueWriter.java:80) at org.glassfish.grizzly.nio.AbstractNIOAsyncQueueWriter.processAsync(AbstractNIOAsyncQueueWriter.java:458) at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:110) at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77) at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:838) at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:113) at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:115) at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:55) at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:135) at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:564) at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:544) at java.lang.Thread.run(Thread.java:722) |
なぜだろうと、Grizzly のソースコードを追ってみると、既にヒープが開放されてしまっているようです。
800 protected final void [More ...] checkDispose() {
801 if (heap == null) {
802 throw new IllegalStateException(
803 "HeapBuffer has already been disposed",
804 disposeStackTrace);
805 }
806 }
当初バグかとも思ったのですが念のため、WebSocket (JSR-356) 仕様のスレッド関連部分をチェックしてみました。すると下記の 5.1 に WebSocket に関するスレッドの注意書きが記載されておりました。
| 5.1 Threading Considerations Implementations of the WebSocket API may employ a variety of threading strategies in order to provide a scalable implementation. The specification aims to allow a range of strategies. However, the implementation must fulfill certain threading requirements in order to provide the developer a consistent threading environment for their applications. Unless backed by a Java EE component with a different lifecycle (See Chapter 7), the container must use a unique instance of the endpoint per peer. [WSC-5.1-1] In all cases, the implementation must not invoke an endpoint instance with more than one thread per peer at a time. [WSC-5.1-2] The implementation may not invoke the close method on an endpoint until after the open method has completed. [WSC-5.1-3] This guarantees that a websocket endpoint instance is never called by more than one container thread at a time per peer. [WSC-5.1-4] If the implementation decides to process an incoming message in parts, it must ensure that the corresponding onMessage() calls are called sequentially, and do not interleave either with parts of the same message or with other messages [WSC-5.1.5]. |
つまり、タスクの実行自身は複数のスレッドで実行できるのですが、WebSocket のクライアント・エンドポイントへのメッセージ送信は1箇所にまとめて実装しなければならない事に気付き上記のようなコードを書いています。
個人的には、マルチスレッドから WebSocket のクライアント・エンドポイントにメッセージ送信ができるようになるとより便利になるのではないかと思いますが、皆様如何でしょう? もちろん、既に仕様は FIX して Java EE 7 のリリース時点では無理ですし、Grizzly 等サーバ側の実装も今のままだと難しい部分があるかもしれません。しかし、皆様で声を上げていけば、時期 Java EE 8 の WebSocket 1.1 当たりで、マルチスレッドからのメッセージ送信もできるかも?!しれないので、賛同して頂ける方がいらっしゃったら、まとめて報告したいなと思っております。
(仕様上ダメって断られる可能性ももちろんありますが。(^_^;))
でも、昔と違って今の Java はこういった事がスペック・リードやエキスパート・グループメンバーに伝えやすい環境なんですよ!!
JJUG として Adopt-A-JSR プログラムに参加し、日本から改善要望なども出していけるといいですね。
WebLogic Server 12c Forum 2013 開催
「WebLogic Server 12c Forum 2013
~ Java EEの現在と未来、WebLogicが拓く新たな可能性 ~ 」
日時 :2013年2月1日(金)13:30~17:30 (受付開始 13:00~)
場所: オラクル青山センター
〒107-0061 東京都港区北青山2-5-8
お申し込み:コチラから
2013/02/01 にオラクル青山センターで WebLogic/Java EE 関連のイベントを開催します。本セミナーでは US 本社より Fusion Middleware の Product Management である、マイク・リーマンを招き、世界のJava EE 6活用状況や、昨年開催した Oracle OpenWorld における WebLogic Server の最新情報、さらには今後のWebLogic の姿に至るまで、様々なトピックをご紹介致します。
| アジェンダ
13:30~13:35 開催のご挨拶 |
個人的には、中でも Oracle RAC の性能を最大限に引き出す Active GridLink for RAC の性能検証に興味があります。これは Oracle と NEC さんとで実際に検証を行なった内容の詳細を発表する予定ですが、とても興味深い内容です。
皆様のご参加を心よりお待ち申し上げます。
Java EE 7 WebSocket Client Sample Application with JavaFX
At the previous entry, I wrote how to WebSocket application on Server Side. However JSR 356 Java API for WebSocket is providing Client API also. So in this entry, I will explain the WebSocket Client API with JavaFX.
The image of this application is like following video. There is one button on the bottom of application. If you click the button, the application connect to WebSocket Server and receive the messages and show the message on the TableView.
Preparation :
In order to compile and run the application, you need following libraries.
* grizzly-framework-2.2.19.jar
* grizzly-http-2.2.19.jar
* grizzly-http-server-2.2.19.jar
* grizzly-websocket-2.2.19.jar
* tyrus-servlet-1.0-b08.jar

You can download the Grizzly related libraries from following site.
http://grizzly.java.net/nonav/docs/docbkx2.2/html/dependencies.html
* Grizzly is a popular NetWork Server framework which is wrote by Java NIO. And originally the grizzly was created for the server engine for GlassFish. It has high scalability and good performance. If you use the grizzly libraries, you don’t need to write the low level socket programing by Java.
In this client application, I will use the Grizzly to connect the WebSocket Server with less code.
Also, you need to get the jar file as tyrus-servlet (reference implementation of Java API for WebSocket) and it include the javax.net.websocket package. Please get the libraries from following site ?
http://repo1.maven.org/maven2/org/glassfish/tyrus/tyrus-servlet/1.0-b08/
Then I will start to create a NetBeans Project by selecting JavaFX FXML Application.

In this Project, I will specified the project name as “JavaFX-WebSocket”. After that in order to be able to use the downloaded libraries in the project,I configured and added the libraries to the project.

If the project had created successfully , following 3 classes will be created by NetBeans.
”JavaFXWebSocket.java”, ”Sample.fxml”, ”SampleController.java”.

I will try to update the above 3 classes as follows. At first , I will customize the view(FXML). If you already configured the SceneBuilder, you can show the SceneBuilder screen on your desktop after you click the Sample.fxml file on NetBeans Project.
This Sample Application is very simple. So I only change the size of the Window and added two component as Label and TableView. After drag and drop these component, I inserted the ID as “table” for TableView. And there is TableColumn inside of TableView. So I specified the ID as “column” for TableColumn.

If you change the screen, you may get the FXML code like follows.
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="453.0" xmlns:fx="http://javafx.com/fxml" fx:controller="javafx.websocket.SampleController">
<children>
<Button fx:id="button" layoutX="326.0" layoutY="365.0" onAction="#handleButtonAction" text="Start TimeLine" />
<Label fx:id="label" layoutX="126.0" layoutY="120.0" minHeight="16.0" minWidth="69.0" />
<Label layoutX="14.0" layoutY="14.0" prefWidth="292.0" text="WebScoket Twitter TimeLine Client Smaple" underline="true" />
<TableView fx:id="table" layoutX="14.0" layoutY="45.0" prefHeight="311.0" prefWidth="425.0">
<columns>
<TableColumn id="" maxWidth="445.0" prefWidth="445.0" text="Message List from Twitter" fx:id="column" />
</columns>
</TableView>
</children>
</AnchorPane>
After customize the View, I will start to implement the Controller of JavaFX. For JavaFXWebSocket.java , there is no need to modify in this application. So I will use the NetBeans created code.
package javafx.websocket;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class JavaFXWebSocket extends Application {
@Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("Sample.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
I implemented the SampleController.java as follows. At first , I inserted the “@FXML TableView table” and “@FXML TableColumn column”. The field name is the same id of FXML(fx:id=”table”, fx:id=”column” ). And I implements the action of push the button on handleButtonAction method. Twitter Streaming is long running process. So I need to implement the check program as multi thread. At JavaFX ,javafx.concurrent.Service, javafx.concurrent.Task classes is prepared to implement the Task. So I had used the Service class to do it.
package javafx.websocket;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javax.websocket.ClientEndpointConfiguration;
import javax.websocket.DefaultClientConfiguration;
import javax.websocket.DeploymentException;
import org.glassfish.tyrus.client.ClientManager;
public class SampleController implements Initializable {
@FXML
private TableView table;
@FXML
private TableColumn<RowData,String> column;
@FXML
private void handleButtonAction(ActionEvent event) {
TwitterCheckService thread = new TwitterCheckService(table);
thread.start();
}
@Override
public void initialize(URL url, ResourceBundle rb) {
table.setEditable(true);
column.setResizable(true);
column.setCellValueFactory(new PropertyValueFactory<RowData, String>("message"));
}
class TwitterCheckService extends Service {
private TableView table;
private CountDownLatch messageLatch = null;
public TwitterCheckService(TableView table) {
this.table = table;
}
@Override
protected Task createTask() {
Task<Void> task = new Task<Void>() {
@Override
protected Void call() throws Exception {
messageLatch = new CountDownLatch(1);
try {
URI clientURI = new URI("ws://localhost:8080/TwitterTimeLine/twitter");
// ClientContainer cliContainer = ContainerProvider.getClientContainer();
ClientManager cliContainer = org.glassfish.tyrus.client.ClientManager.createClient();
ClientEndpointConfiguration clientConfig = new DefaultClientConfiguration();
cliContainer.connectToServer(new TwitterClient(table), clientURI);
messageLatch.await(1, TimeUnit.SECONDS);
} catch (DeploymentException | URISyntaxException | InterruptedException ex) {
Logger.getLogger(SampleController.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
};
return task;
}
}
}
In the above class, there is initialize() method to initialize the class. In the method, I wrote column.setCellValueFactory(new PropertyValueFactory(“message”)) . This is the value configuration of the Table column. In fact, the field of “message” in RowData class will be showed on every column in the Table. I specified the javafx.scene.text.Text type instead of String type, because it was difficult to manage the size of String in the Column of TableView. So instead of String, I used the Text and Text#setWrappingWidth could manage the size of viewable String.
package javafx.websocket;
import javafx.scene.text.Text;
public class RowData {
private Text message;
public RowData(Text message) {
this.message = message;
message.setWrappingWidth(400);
}
public Text getMessage() {
return message;
}
public void setMessage(Text message) {
this.message = message;
}
}
I will pick up and explain the important point of WebSocket Client in SampleController class as follows. I wrote the comment in the code as “// ClientContainer cliContainer = ContainerProvider.getClientContainer();” In fact the above code is recommended as standard. And you should write the following property on the system property.
“webocket.clientcontainer.classname= actual class name ”
However in this programing , I faced the error. Thus I wrote the following in order to get the instance of ClientContainer. “ClientManager cliContainer = org.glassfish.tyrus.client.ClientManager.createClient();”
URI clientURI = new URI("ws://localhost:8080/TwitterTimeLine/twitter");
// ClientContainer cliContainer = ContainerProvider.getClientContainer();
ClientManager cliContainer = org.glassfish.tyrus.client.ClientManager.createClient();
ClientEndpointConfiguration clientConfig = new DefaultClientConfiguration();
cliContainer.connectToServer(new TwitterClient(table), clientURI);
messageLatch.await(20, TimeUnit.SECONDS);
I specified the “TwitterClient(table)” inside of cliContainer.connectToServer(new TwitterClient(table), clientURI) line. It is a WebSocket Client code which equal to the class of adding the @WebSocketEndpoint annotation at the server side. Instead of the “@WebSocketEndpoint” annotation, we must specify the “@WebSocketClient” annotation at the client side code. Following is the client side code of WebSocket client.
package javafx.websocket;
import javafx.collections.ObservableList;
import javafx.scene.control.TableView;
import javafx.scene.text.Text;
import javax.websocket.Session;
import javax.websocket.WebSocketClient;
import javax.websocket.WebSocketClose;
import javax.websocket.WebSocketMessage;
import javax.websocket.WebSocketOpen;
@WebSocketClient
public class TwitterClient {
TableView table;
ObservableList<RowData> list;
public TwitterClient(TableView table) {
this.table = table;
}
@WebSocketOpen
public void onOpen(Session session) {
System.out.println("Connection had opened.");
}
@WebSocketMessage
public void onMessage(String message) {
if (message.length() == 0) {
return;
}
// In order to adjst the size of String in Table, I used Text.
Text text = new Text(message);
list = table.getItems();
list.add(0,new RowData(text));
}
@WebSocketClose
public void closeConnection(Session session) {
System.out.println("Connection had closed.");
}
}
Actually the code is very similar to the server side code. Instead of the @WebSocetEndpoint, I specified the @WebSocketClient annotation. And inside of the class, we can implements the method which is added @WebSocketOpen, @WebSocketMessage and @WebSocketClose annotation. In this program, client receive the message from the server. And there is no need to send the data to server. So I implemented the @WebSocketMessage public void onMessage(String message) method. In this method, the client receive the message from server and wrapping the String to Text object in order to adjust the length of the viewable String (Text text = new Text(message)). Finally the message is inserted into the first line of the Table.
This WebSocket client code is very easy to implement. So you can write the WebSocket program very easily not only server side but also Java Application like JavaFX.
はじめての JavaFX エンタープライズ・アプリケーション : JavaFX と JPA で実装するアプリケーション
本日は少しだけ JavaFX を触ってみました。正直 JavaFX は櫻庭大先生や、関谷さん、他の Embedded チームの皆様に助けて頂いているので、私自身あまり JavaFX に触っておらず自信もないのですが、今日は、JavaFX から JPA を使って DB に接続するクライアント・サーバのアプリケーションの作成してみました。
開発環境:
- JDK 1.7 (Mac OSX 1.7.0_04)
- NetBeans 7.1.1 or later (Mac OSX 1.7.0_04)
- JavaDB (今回は GlassFish に付属の JavaDB を使用しました)
必要なライブラリ:
- eclipselink-2.3.0.jar
- javax.persistence-2.0.jar
- org.eclipse.persistence.jpa.jpql_1.0.0.jar
- derbyclient.jar (JavaDB 用のドライバ)
アプリケーションの概要:
このアプリケーションは DB に存在する顧客情報を参照するだけの簡単なアプリケーションです。JavaFX のアプリケーションから JPA を使用して DB に接続し顧客名とメールアドレスをアプリケーション上に表示します。「データの取得」ボタンを押下すると DB よりデータを取得し、テーブル内に表示し、「データのクリア」ボタンを押下すると表示内容をクリアします。


それでは実際に作成してみましょう。まず、NetBeans の「新規プロジェクト」を作成します。

次に、「JavaFX アプリケーション」のプロジェクトを選択します。

選択すると下記の画面が表示されますので、「プロジェクト名 (N) :」と「アプリケーションクラスを作成 (C)」を編集しプロジェクトに対して適切な名前、パッケージ、クラス名を指定します。
以上で JavaFX アプリケーションのプロジェクトが生成されました。この状態で「主プロジェクトを構築 (B)」を選択した後、「主プロジェクトを実行 (R)」を実行するとボタンが一つだけ表示される Window が表示されます。ボタンを押下すると標準出力に ”Hello World !”が表示されます。今回はこの自動生成されたJavaFX プロジェクトのひな形を改造しアプリケーションを作成します。
デフォルトで生成される Main クラスのひな形ソースコード
public class Main extends Application {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Hello World!");
Button btn = new Button();
btn.setText("Say 'Hello World'");
btn.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
System.out.println("Hello World!");
}
});
StackPane root = new StackPane();
root.getChildren().add(btn);
primaryStage.setScene(new Scene(root, 300, 250));
primaryStage.show();
}
}
次にエンティティ・クラスを作成します。
※ 下記の方法は、既存で DB が存在し、既にテーブルが存在している場合の方法です。テーブルが存在しない状態でもエンティティクラスを生成できますが、簡単に説明するため今回は既存のテーブルを利用してエンティティクラスを生成します。
「新規」→「持続性」→「データベースからのエンティティクラス…」を選択します。

選択すると下記の画面が表示されます。ここで「関係する表を含める (I)」のチェックを外し「CUSTOMER」テーブルを選択した後、「次へ」ボタンを押下します。

ボタンを押下すると下記の画面が表示されます。ここでエンティティ・クラスのパッケージ名を適切に入力し「次へ」ボタンを押下します。

ボタンを押下すると下記の画面が表示されます。ここではデフォルトの設定のままで最後に「完了(F)」ボタンを押下します。

既存の DB テーブルを元に NetBeans で自動生成されたエンティティ・クラス
package jp.co.oracle.javafxsample.dao;
import java.io.Serializable;
import javax.persistence.*;
import javax.xml.bind.annotation.XmlRootElement;
/**
*
* @author Yoshio Terada
*/
@Entity
@Table(name = "CUSTOMER")
@XmlRootElement
@NamedQueries({
@NamedQuery(name = "Customer.findAll", query = "SELECT c FROM Customer c"),
@NamedQuery(name = "Customer.findByCustomerId", query = "SELECT c FROM Customer c WHERE c.customerId = :customerId"),
@NamedQuery(name = "Customer.findByName", query = "SELECT c FROM Customer c WHERE c.name = :name"),
@NamedQuery(name = "Customer.findByAddressline1", query = "SELECT c FROM Customer c WHERE c.addressline1 = :addressline1"),
@NamedQuery(name = "Customer.findByAddressline2", query = "SELECT c FROM Customer c WHERE c.addressline2 = :addressline2"),
@NamedQuery(name = "Customer.findByCity", query = "SELECT c FROM Customer c WHERE c.city = :city"),
@NamedQuery(name = "Customer.findByState", query = "SELECT c FROM Customer c WHERE c.state = :state"),
@NamedQuery(name = "Customer.findByPhone", query = "SELECT c FROM Customer c WHERE c.phone = :phone"),
@NamedQuery(name = "Customer.findByFax", query = "SELECT c FROM Customer c WHERE c.fax = :fax"),
@NamedQuery(name = "Customer.findByEmail", query = "SELECT c FROM Customer c WHERE c.email = :email"),
@NamedQuery(name = "Customer.findByCreditLimit", query = "SELECT c FROM Customer c WHERE c.creditLimit = :creditLimit")})
public class Customer implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Basic(optional = false)
@Column(name = "CUSTOMER_ID")
private Integer customerId;
@Column(name = "NAME")
private String name;
@Column(name = "ADDRESSLINE1")
private String addressline1;
@Column(name = "ADDRESSLINE2")
private String addressline2;
@Column(name = "CITY")
private String city;
@Column(name = "STATE")
private String state;
@Column(name = "PHONE")
private String phone;
@Column(name = "FAX")
private String fax;
@Column(name = "EMAIL")
private String email;
@Column(name = "CREDIT_LIMIT")
private Integer creditLimit;
public Customer() {
}
public Customer(Integer customerId) {
this.customerId = customerId;
}
public Integer getCustomerId() {
return customerId;
}
public void setCustomerId(Integer customerId) {
this.customerId = customerId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddressline1() {
return addressline1;
}
public void setAddressline1(String addressline1) {
this.addressline1 = addressline1;
}
public String getAddressline2() {
return addressline2;
}
public void setAddressline2(String addressline2) {
this.addressline2 = addressline2;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getFax() {
return fax;
}
public void setFax(String fax) {
this.fax = fax;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Integer getCreditLimit() {
return creditLimit;
}
public void setCreditLimit(Integer creditLimit) {
this.creditLimit = creditLimit;
}
@Override
public int hashCode() {
int hash = 0;
hash += (customerId != null ? customerId.hashCode() : 0);
return hash;
}
@Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Customer)) {
return false;
}
Customer other = (Customer) object;
if ((this.customerId == null && other.customerId != null) || (this.customerId != null && !this.customerId.equals(other.customerId))) {
return false;
}
return true;
}
@Override
public String toString() {
return "jp.co.oracle.javafxsample.dao.Customer[ customerId=" + customerId + " ]";
}
}
これで、JPA のエンティティクラスが生成されましたので、これを元に JavaFX で DB のデータを参照するアプリケーションを作成します。
まず、DB に接続し全データを取得する部分ですが、getData() メソッドで実装します。GlassFish の Java DB を利用した場合、上記までの手続きにより、自動的に Persistence Unit (持続性ユニット) の設定が行われています(※ その他の DB を利用する場合、別途 NetBeans の「新規」→「持続性」→「持続性ユニット…」を選択し持続性ユニットの設定を行ってください)。
持続性ユニットの設定が適切に行われている場合、プロジェクト内に persistence.xml というファイルが生成されています。この persistence.xml 設定ファイルには DB サーバへ接続するための情報(JDBC ドライバ、接続 URL、ユーザ名、パスワード)等が記載されていますが、プログラム上からどの持続性ユニットを利用するかを指定できるように持続性ユニット名が記載されています(この例では JavaFX-JPA-SamplePU)。
persistence.xml 中の持続性ユニット名の設定(全設定は最後にまとめて記載)
<persistence-unit name="JavaFX-JPA-SamplePU" transaction-type="RESOURCE_LOCAL">
JavaFX のアプリケーションではこの持続性ユニット名を指定してエンティティを管理するための、EntityManager を生成します。EntityManager を生成した後、JPQL の NamedQuery (NetBeans では上記エンティティ・クラスに記載されているように、基本的な Named クエリが複数自動生成。ここではCustomer に記載されている @NamedQuery(name = “Customer.findAll”, query = “SELECT c FROM Customer c” ),) を使用して全データを取得します。取得したデータは List にコピーし返します。
getData() の EntityManager 生成部分(全ソースコードは最後にまとめて記載)
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("JavaFX-JPA-SamplePU");
EntityManager em = emf.createEntityManager();
TypedQuery tquery = em.createNamedQuery("Customer.findAll", Customer.class);
List<Customer> list = tquery.getResultList();
「データの取得」ボタンが押下された際に、DB に接続しデータを JavaFX のテーブルに表示するため、ボタンが押下された際のイベントをハンドリングします。この際 JavaFX では javafx.scene.control.TableView の setItems(ObservableList < S > value) を利用してプロパティを設定する事ができます。List から ObservableList を生成するために、JavaFX で用意されている便利なユーティリティクラス FXCollections を使用して変換します。変換後 TableView#setItems() メソッドの引数に代入し実行します。
btn.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
ObservableList<Customer> data =
FXCollections.observableArrayList(getData());
table.setItems(data);
}
});
後は、説明の必要もないかと思いますが、TableColumn でどの項目を表示するかを記載して完了です。FXCollections という便利なユーティリティツールが用意されている事もあり、JPA のエンティティをとても簡単に扱う事ができます。もちろん昔ながらの JDBC で記載する事も可能かと思いますが、JPA の方がとても簡単に効率良く実装できる事がわかるかと思います。
さて実装が終わったので、プロジェクトを構築して実行するわけですが、実はこの状態でプログラムを実行するとエラーが発生します。なぜなら現時点で本プロジェクトに JDBC ドライバのライブラリを組み込んでいないためです。
[EL Severe]: 2012-05-24 18:42:32.336–ServerSession(1090664123)–Local Exception Stack: Exception [EclipseLink-4003] (Eclipse Persistence Services – 2.3.0.v20110604-r9504): org.eclipse.persistence.exceptions.DatabaseException Exception Description: Configuration error. Class [org.apache.derby.jdbc.ClientDriver] not found. |
そこで、JavaDB 用の JDBC ドライバを組み込みます。ライブラリを選択し「JAR/フォルダを選択…」を選択してください。

選択すると下記の画面が表示されますので、JavaDB 用の JDBC ドライバを選択します(derbyclient.jar)。

ライブラリを組み込むと下記のように表示されます。

ドライバを組み込んだ後、プロジェクトを構築します。

次にアプリケーションを実行します。


最後に、今回は JavaFX アプリケーションとして、アプリケーションを作成しました。つまりこのアプリケーションでは、コネクション・プール等を利用していない為、ボタンを押下する度に DB に対して接続が発生します。そこでこのアプリケーションを大量に配布した場合、DBに対して高負荷を与える可能性もあります。
そのような場合、もちろんこのアプリケーションをアプリケーション・クライアント・コンテナを含めて作成する事も可能です。アプリケーション・クライアント・コンテナ上で作成すると、アプリケーション・サーバ上のリソースをアノテーションを利用して注入できるようになる他、アプリケーション・サーバ上で EJB を作成し、それを参照するようにする事でコネクション・プールの利用もできるようになるため、DB に対する負荷も軽減できるようなります。要件に応じてはクライアント・サーバ型のアプリケーションの実装が必要になる場合もあるかと思いますが、場合によってはアプリケーション・クライアント・コンテナ上でアプリケーションを実行する事もご検討ください。
Main クラスの全ソースコード:
package jp.co.oracle.javafxsample;
import java.util.List;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javax.persistence.*;
import jp.co.oracle.javafxsample.dao.Customer;
/**
*
* @author Yoshio Terada
*/
public class Main extends Application {
/**
* @param args the command line arguments
*/
private TableView table = new TableView();
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
Scene scene = new Scene(new Group(), 500, 400, Color.LIGHTGRAY);
primaryStage.setTitle("顧客情報参照アプリケーション");
final Label label = new Label("顧客情報の参照");
//テーブルの初期化
TableView table = initTable();
//ボタンの初期化
Button getBtn = initGetButton();
Button clrBtn = initClearButton();
VBox vbox = new VBox();
vbox.setSpacing(2);
vbox.getChildren().addAll(label, table,getBtn,clrBtn);
vbox.setPadding(new Insets(10, 0, 0, 10));
vbox.setPrefSize(480, 380);
((Group) scene.getRoot()).getChildren().addAll(vbox);
primaryStage.setScene(scene);
primaryStage.show();
}
private TableView initTable() {
TableColumn nameCol = new TableColumn("顧客名");
nameCol.setMinWidth(200);
nameCol.setCellValueFactory(new PropertyValueFactory<Customer, String>("name"));
TableColumn emailCol = new TableColumn("電子メール");
emailCol.setMinWidth(280);
emailCol.setCellValueFactory(new PropertyValueFactory<Customer, String>("email"));
table.setEditable(true);
table.setPrefWidth(480);
table.getColumns().addAll(nameCol, emailCol);
return table;
}
private Button initGetButton() {
Button btn = new Button();
btn.setText("データの取得");
btn.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
ObservableList<Customer> data =
FXCollections.observableArrayList(getData());
table.setItems(data);
}
});
return btn;
}
private Button initClearButton() {
Button btn = new Button();
btn.setText("データのクリア");
btn.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
table.setItems(null);
}
});
return btn;
}
// JPA を使用して DB よりデータの取得
private List getData() {
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("JavaFX-JPA-SamplePU");
EntityManager em = emf.createEntityManager();
TypedQuery tquery = em.createNamedQuery("Customer.findAll", Customer.class);
List<Customer> list = tquery.getResultList();
if(em != null)
em.close();
if(emf != null)
emf.close();
return list;
}
}
persistence.xml の内容
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="JavaFX-JPA-SamplePU" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>jp.co.oracle.javafxsample.dao.Customer</class>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:derby://localhost:1527/sample"/>
<property name="javax.persistence.jdbc.password" value="app"/>
<property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.ClientDriver"/>
<property name="javax.persistence.jdbc.user" value="app"/>
</properties>
</persistence-unit>
</persistence>
Turning the potter’s wheel at JavaOne Tokyo
Recently the word of “Turning the potter’s wheel” is very popular in Japan.
One Japanese guy(Kouhei Iida-san) asked why the presentator always “Turning the potter’s wheel” at the explanation?
And another guys evaluate whether it is right or not as follows.
Turning the potter’s wheel
As a result, so many presentator even though Steave Jobs had turned the potter’s wheel. And It’s not a bad meaning at all. And it’s a one of the expression of the enthusiastic.
And Today I confirmed JavaOne Tokyo speakers.
(Sorry all of ther speakers I coulnd’t take the photos.)
And so many speaker had turned the potter’s wheel as follows.
For All of JavaOne Tokyo speakers :
Great Thank you so much for your excellent presentation !!
Thank you & Best Regards.
Yoshio.











JavaOne Tokyo のお礼

JavaOne Tokyo にご参加頂いた皆様、誠にありがとうございました。心より御礼申し上げます。
開催前日は、あいにくの空模様で交通機関が完全に麻痺してしまったため、地方からご参加いただいた皆様の中には前日に東京にお越し頂く事ができなかった方がいらっしゃる事を伺っております。また当日お越し頂けた皆様の中には、新幹線に切り替えて、それでも新幹線が東京に到着するのが深夜となり、ホテルまでタクシーで移動された方もいらっしゃると聞いています。そのような大変な状況にも関わらず、北は北海道から南は沖縄まで日本全国から、JavaOne Tokyo にご参加頂きました皆様、本当にありがとうございました。

JavaOne Tokyo がこれだけ盛り上がったのも、一重に日本全国からご参加頂いた数多くの Java 開発者の皆様のおかげでございます。皆様のご参加、心より御礼申し上げます。
今回の JavaOne は7年振りという事もあり、JavaOne を全くご存知ない世代の方々も数多く参加して頂けたのではないかと思います。JavaOne をご存知ない世代の方々に対して、Java の開発者の祭典である JavaOne を再び日本でお届けできた事を心より嬉しく思っております。
また、この2日間、Twitter 上に JavaOne のメッセージで溢れ帰る程の多くのつぶやきが見受けられました。この JavaOne の盛り上がり、Java 開発者の皆様のメッセージは、本社社員や、日本のオラクル社員にも十分伝わっておりますし、今回残念ながらご都合が悪くご参加いただけなかった皆様も、皆様のツイートを見て、次回は是非参加したいと言って下さっている方もお見かけ致しました。これもご参加頂いた皆様が数多くのフィードバックをしてくださったからだと思います。本当にありがとうございました。

さらにはブログで、本場 JavaOne サンフランシスコに参加された Nobeans さんも、下記のように本場 JavaOne サンフランシスコのようで楽しかったというようなメッセージも頂きました。単なる日本における Java の勉強会ではなく JavaOne Tokyo ができたんだなと嬉しく思いました。
| あと、JavaOneTokyo全体の感想としては、一言で言えば超楽しかったです。 去年と一昨年にSFのJavaOneに参加してきたんですが、 “今回タワーホールとかでセッション開始待ちしてるときの雰囲気とか 音楽とかもう去年のSFのJavaOneそのもので、すっごいテンション あがりました。もうそのままSFにいるみたいな気分。” |
その他にも下記のように数多くのブログの投稿を頂いております(すいません全てハンドリングできていないかもしれません、もし自分も書いたという方がいらっしゃいましたら、是非教えていただけないでしょうか)。多くの皆様から楽しかった!!というようなメッセージを頂き、次回開催希望も多く承っております。これら開発者の皆様の声はちゃんと US や日本の上層部にお伝え致します。(実は既にこのブログを書く前に、社長、取締役に報告しております。(^_^))
JavaOne Tokyo に参加してくださった皆様のブログ:
- http://d.hatena.ne.jp/nobeans/20120406/1333697766
- http://d.hatena.ne.jp/zephiransas/20120406/1333713459
- http://d.hatena.ne.jp/megascus/20120406/1333683449
- http://d.hatena.ne.jp/s-ishigami/20120406/p1
- http://johtani.jugem.jp/?eid=74
- http://d.hatena.ne.jp/ynie/20120406/1333671989
- http://grimrose.blogspot.jp/2012/04/javaone-tokyo-2012-1-javaonejp.html?spref=tw
- http://d.hatena.ne.jp/t-horikiri/20120406/1333732983
- http://d.hatena.ne.jp/den2sn/20120407/1333724943

その他、下記のように Togetter にまとめて下さった方々も多数いらっしゃいます。誠にありがとうございます。
Togetter のまとめ一覧:
- JavaOne Tokyo 2012 NIO.2を使って、簡単ファイル操作 #JavaOneJP
- JavaFX + FXML + CSS = Javaの次世代GUI #JavaOneJP
- What’s coming in Java Message Service 2.0 #JavaOneJP
- Project Jigsaw: Putting it all Together #JavaOneJP
- Introduction to the JavaFX Scene Builder
- JavaFX and Web Integration
- Introduction to JavaFX 2.0
- JavaOne Tokyo 2012 The New JSR-107 Caching Standard #jt12_b204
- JavaOne Tokyo 2012 ForgeとArquillianを利用したJava EEアプリケーションの迅速な開発 #jt12_s231
- Learn how the JVM is fundamental to our architecture #jt12_b203
- JavaOne Tokyo 2012 JVM言語BoF #jt12_b101
- JavaOne Tokyo 2012 コンテナでテストをまわせ!Java EEへの自動テストの導入 #jt12_b202
- JavaOne Tokyo 2012 コンテナでテストをまわせ!Java EEへの自動テストの導入 #jt12_b202
- JSR 353 : Java API for JSON #やまもとゆうすけがんばれ #jt12_s233
- JSR 353 : Java API for JSON #やまもとゆうすけがんばれ #jt12_s233
- How to write low latency Java Applications #jt12_s221
- The Java EE 6 Programming Model Explained #JavaOneJP

最後に、
繰り返しになりますが、この度は JavaOne Tokyo 2012 にご参加頂きまして誠にありがとうございました。JavaOne Tokyo がまたいつか開催できればと思っております。誠に簡単ではございますが、JavaOne Tokyo に携わってくださった全ての皆様に御礼のご挨拶まで!!
JavaOne 受講票引換券の印刷のお願い
JavaOne Tokyo 2012 にご参加の皆様
JavaOne 当日、マイページから入手可能な、受講票引換券をプリントアウトし受付にお持ちください、受講票と交換致します。
仮にマイページのログイン方法が分からない場合、もしくは受講票の引換券が表示されない等のなどの問題がございましたら、下記のレジストレーション事務局までお問い合わせください。
お問い合わせ:
JavaOne Tokyo レジストレーション事務局
E-Mail:info-javaone_jp AT oracle.com
TEL:03-6834-4694(平日10:00~18:00)
詳細:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
JavaOne Tokyo 2012 受講票引換券発行/当日のご来場に関するご案内
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
申込番号:[XXXXXXXXXX]
この度は、JavaOne Tokyo 2012にお申し込みいただきありがとうございます。マイページより受講票引換券の発行を開始させていただきましたのでお知らせいたします。お手数ではございますが、ご来場前にご自身で受講票引換券を印刷し、当日はお忘れのないようお持ちください。
また、下記のご案内につきましては、ご来場前に必ずご一読くださいますようお願い申し上げます。
■受講票引換券の印刷/受講票のお渡し
マイページにログイン後、お申込み内容(選択セッション)一覧の右側の列に表示される「受講票の印刷」を押下し、受講票引換券を印刷してください。ご来場の際は、受講票引換券をお忘れなくお持ちください。受付にて受講票をお渡しいたします。
マイページURL: https://oj-events.jp/public/mypage/login?type=jo
ログインID:[XXXXXXXXXX]
パスワード:ご登録時にご自身で設定されたパスワード
※パスワードをお忘れの方は、上記マイページログインページに記載の
「パスワードをお忘れの方はこちら」より、再設定ください。
「ご注意」
◇受講票引換券を一度印刷した後、セッションの変更をされた場合は、再度
受講票引換券を印刷してください。当日は受講票引換券に記載のお申込み内容(選択セッション)を確認させていただき、記載がないセッションにはご入場いただけない場合がございますのでご注意ください。
◇受講票引換券及び受講票は2日間共通となります。
受講票引換券をお忘れになりますと再発行までにお時間がかかる場合があり
ますのでご注意ください。また、当日お渡しいたします受講票の再発行は致しかねますので、開催期間中は無くさないよう大切に保管してください。
■当日の受付
[受付場所] 六本木アカデミーヒルズ49
(〒106-6149 東京都港区六本木6-10-1 六本木ヒルズ森タワー49階)
[受付オープン時間] 4月4日(水)-5日(木) 8:00-19:30
印刷した受講票引換券を受付にてご提示ください。
当日朝は混雑が予想されますので、お時間に余裕をもってご来場ください。
※学生向け特別プログラムにてご参加の方は受講票引換券とともに「学生証」をご提示ください。
■来場者特典(カンファレンスバッグ/オリジナルTシャツ)
各日11時より会場内引換所にてお渡しいたします。来場者特典の引換券は受付にてお渡しいたします(お1人様1回限り)。
お問い合わせ:
JavaOne Tokyo レジストレーション事務局
E-Mail:info-javaone_jp AT oracle.com
TEL:03-6834-4694(平日10:00~18:00)
日本オラクル株式会社
新しい Java SE API リファレンスの入手先について
2012 年 03 月 25 日、sun.com のドメインが利用不可になりました。これに併せ、java.sun.com で提供されていた Java SE API 日本語ドキュメントもオンライン経由で参照する事ができなくなりました。今後、日本語の Java SE API レファレンスはオンライン経由では参照できなくなりますので、アーカイブを御入手の上、ローカル環境でご参照ください。お手数をお掛けし申し訳ございませんが、どうぞ宜しくお願いします。
Java API の日本語ドキュメントはコチラから入手が可能です。
ドキュメントの再配布ポリシーはコチラをご参照ください。
新しい日本語 API ドキュメントのオンライン参照先URL (2012/4/11 訂正、追記)
- http://docs.oracle.com/javase/jp/1.3/api/
- http://docs.oracle.com/javase/jp/1.4/api/
- http://docs.oracle.com/javase/jp/1.5.0/api/
- http://docs.oracle.com/javase/jp/6/api/
- http://docs.oracle.com/javase/jp/7/api (2013/05/29 追記:Java SE 7 API も日本語化されました)
PS.
引き続き、英語の API ドキュメントはオンラインで参照可能です。
Java SE 7 API Documentation
Java SE 6 API Documentation
J2SE 5 API Documentation
J2SE 1.4.2 Documentation
J2SE 1.3.1 Documentation




