月別アーカイブ: 2013年7月

JavaFXとWebsocketを連携してみる(On Glassfish4.0) その2

前回からスレッド周りの制約事項にかかってうまくいっていないけど状況の整理。

やろうとしていることは、前回は表の中にWebsockeで取得したデータを反映しようとしていたものを、Labelに変更して表示しようというもの。

1

起きているエラーはJavaFXのコンポーネントをJavaFX配下以外のスレッドで呼んではいけないというもの。

スタックトレースは以下。

java.lang.IllegalStateException: Not on FX application thread; currentThread = Grizzly-worker(1)
エラーです:e9e8fea3-96b6-46be-ad8e-a393e1499784
    at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:237)
    at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:397)
    at javafx.scene.Parent$1.onProposedChange(Parent.java:245)
    at com.sun.javafx.collections.VetoableObservableList.setAll(VetoableObservableList.java:90)
    at com.sun.javafx.collections.ObservableListWrapper.setAll(ObservableListWrapper.java:314)
    at com.sun.javafx.scene.control.skin.LabeledSkinBase.updateChildren(LabeledSkinBase.java:602)
    at com.sun.javafx.scene.control.skin.LabeledSkinBase.handleControlPropertyChanged(LabeledSkinBase.java:209)
    at com.sun.javafx.scene.control.skin.SkinBase$3.changed(SkinBase.java:282)
    at javafx.beans.value.WeakChangeListener.changed(WeakChangeListener.java:107)
    at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:196)
    at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:100)
    at javafx.beans.property.StringPropertyBase.fireValueChangedEvent(StringPropertyBase.java:121)
    at javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:128)
    at javafx.beans.property.StringPropertyBase.access$100(StringPropertyBase.java:67)
    at javafx.beans.property.StringPropertyBase$Listener.invalidated(StringPropertyBase.java:236)
    at com.sun.javafx.binding.ExpressionHelper$SingleInvalidation.fireValueChangedEvent(ExpressionHelper.java:155)
    at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:100)
    at javafx.beans.property.StringPropertyBase.fireValueChangedEvent(StringPropertyBase.java:121)
    at javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:128)
    at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:161)
    at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:67)
    at jp.co.epea.firstfxclient.ObjData.setDataValue(ObjData.java:26)
    at jp.co.epea.firstfxclient.WSClient.onMessage(WSClient.java:30)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.glassfish.tyrus.core.AnnotatedEndpoint.callMethod(AnnotatedEndpoint.java:431)
    at org.glassfish.tyrus.core.AnnotatedEndpoint.access$100(AnnotatedEndpoint.java:83)
    at org.glassfish.tyrus.core.AnnotatedEndpoint$WholeHandler$1.onMessage(AnnotatedEndpoint.java:518)
    at org.glassfish.tyrus.core.SessionImpl.notifyMessageHandlers(SessionImpl.java:391)
    at org.glassfish.tyrus.core.EndpointWrapper.onMessage(EndpointWrapper.java:498)
    at org.glassfish.tyrus.container.grizzly.GrizzlyClientSocket.onMessage(GrizzlyClientSocket.java:393)
    at org.glassfish.tyrus.websockets.frametypes.TextFrameType.respond(TextFrameType.java:66)
    at org.glassfish.tyrus.websockets.DataFrame.respond(DataFrame.java:102)
    at org.glassfish.tyrus.container.grizzly.WebSocketFilter.handleRead(WebSocketFilter.java:300)
    at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:288)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:206)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:136)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:114)
    at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
    at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:837)
    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:565)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:545)
    at java.lang.Thread.run(Thread.java:724)

 

現在の書き方(ソース)でかかっている場所は、ClientManager#connectToServerでGrizzlyのスレッドがたっていて、

        @Override
        protected Task createTask() {
            Task<Void> task = new Task<Void>() {
                @Override
                protected Void call() throws Exception {

                    try {
                        URI clientURI = new URI("ws://localhost:8080/first/hello/");
                        ClientManager cliContainer = org.glassfish.tyrus.client.ClientManager.createClient();
                        cliContainer.connectToServer(new WSClient(data), clientURI);

                    } catch (DeploymentException  ex) {
                        Logger.getLogger(SampleController.class.getName()).log(Level.SEVERE, null, ex);
                    }
                    return null;
                }
            };
            return task;
        }

その中で動いているOnmessegeで値を書き換えようとしていること

    ObjData data;

    @OnMessage
    public void onMessage(String message) {
        if (message.length() == 0) {
            return;
        }
        System.out.println(data.getDataValue());
        data.setDataValue(message);//下の自分で作ったメソッド
        System.out.println(data.getDataValue());
    }

// ObjDataの中
    private SimpleStringProperty dataValue;
    public void setDataValue(String dataValue) {
        dataValueProperty().set(dataValue);
    }

改めて前回サンプルにしたソースを見直すとObservableListの変更をトリガーにした通知機能をうまく使っているみたい。

なお、自前でスレッドを管理している場合のドキュメントはこちら

spam対策

ここ数日198.245.49.39と137.175.15.131から数時間おきにspamコメントが寄せられるうになってきた。

ipは決まっているのでとりあえずiptablesではじくように設定。

iptables -I INPUT -s 198.245.49.39 -j DROP
iptables -I INPUT -s 137.175.15.131 -j DROP
/etc/rc.d/init.d/iptables save
(各IPからのパケットをはじく設定&保存。)

今のところは、他のIPからのスパムはないから出てきたベースで拒否していけばいいけど頻度増えてきたらAkismetとかのプラグインではじいた方がいいのかな。

スタックトレースを頼りに海外から来てくれている人もいるので国でばっさりと絞りたくはないし。

(2013/8/6までにスパムが来たIP)

216.244.85.234
205.164.24.90
58.22.70.108
137.175.15.134
185.25.48.24
198.2.200.9
137.175.105.39
137.175.118.101
137.175.15.133
137.175.68.241
137.175.105.38
114.251.150.133
123.184.133.84
163.125.181.151
137.175.15.132
137.175.118.100
137.175.68.178
71.61.84.216
117.27.138.148
137.175.118.99
198.27.82.114
137.175.15.131
198.245.49.39
198.100.144.195

Eclipse(Luna)のスケジュール感

Eclipse(Luna)のJDK 8対応状況をみるとJava Model とかもぼちぼち手がつけられそうな状況になってきた。いまのところMLにあった感じに秋(original GA in September)にはぼちぼち触れるようになりそうかなぁ。

ラムダ式周りをPMDかFindbugsのカスタムルール作りつつ様子見ようと思ったけど、自分が手を出すには技術不足感に満ち溢れているので挫折。

なおJDTのgitレポジトリは以下。

  • JDT Core repository – git://git.eclipse.org/gitroot/jdt/eclipse.jdt.core.git
  • JDT UI repository – git://git.eclipse.org/gitroot/jdt/eclipse.jdt.ui.git

詳細情報は

http://wiki.eclipse.org/Platform-releng/Git_Workflows

 

 

 

Effectively final

先日のJJUGナイトセミナー(前半資料/後半資料)でfianlつけていなくてもfinalとみなされるEffectively finalというものがJava 8から導入されるという話を聞いた。(前半資料16pに出てくる「実質的final」)

public class JavaApplication1 {
    public static void main(String[] args) {
        String hoge = "こんにちは世界。";
        Runnable r1 = new Runnable() {
            @Override
            public void run() {
                System.out.println(hoge);
            }
        };
        r1.run();

        Runnable r2 = () -> {
            System.out.println(hoge);
        };
        r2.run();
    }
}

上みたいなfinalの付いていない変数(String hoge)も代入していなければfinalとみなして匿名クラス、ラムダ式の中で使えるようになったとのこと。

 

ちなみにJava 7までだと下みたいにエラー。

a

 

final付いていないけどfinal扱いなので再代入したらだめ。

String hoge = "こんにちは世界。";
        hoge ="こんばんわ";
        Runnable r1 = new Runnable() {
            @Override

とか

            public void run() {
                hoge ="こんばんわ";
                System.out.println(hoge);
            }

とか

        Runnable r2 = () -> {
            hoge ="こんばんわ";
            System.out.println(hoge);
        };

とか。

エラーがある状態で(Netbeansから?)実行すると

Exception in thread "main" java.lang.RuntimeException: Uncompilable source code - 内部クラスから参照されるローカル変数は、finalまたは事実上のfinalである必要があります

とか

Exception in thread "main" java.lang.RuntimeException: Uncompilable source code - ラムダ式から参照されるローカル変数は、finalまたは事実上のfinalである必要があります

わかりやすいメッセージが表示される。

軽く触った感じだときれいに動いている。

(講演してくれた方がこのfinalまわりでよくはまったといっていたので、まだトラップありそうな気がする)

JDK8バグ?

先日のJDK 8をWindowsにインストールするとレジストリに書き込まれるっぽい問題を避けるために、NetbeansとJDK 8をCentOS(6.4 64bit)にインストールした。起動しようとしたところ下のようなエラーが発生。

java.lang.IllegalArgumentException: committed = 52752384 should be < max = 50331648
    at java.lang.management.MemoryUsage.<init>(MemoryUsage.java:162)
    at sun.management.MemoryImpl.getMemoryUsage0(Native Method)
    at sun.management.MemoryImpl.getNonHeapMemoryUsage(MemoryImpl.java:75)
    at org.netbeans.core.ui.warmup.DiagnosticTask.logParams(DiagnosticTask.java:193)
    at org.netbeans.core.ui.warmup.DiagnosticTask.run(DiagnosticTask.java:82)
[catch] at org.netbeans.core.startup.WarmUpSupport.run(WarmUpSupport.java:98)
    at org.openide.util.RequestProcessor$Task.run(RequestProcessor.java:1432)
    at org.openide.util.RequestProcessor$Processor.run(RequestProcessor.java:2042)

JDKのバグ??

WarmUpSupportとかいうのが死んだっぽいけどcommittedがmax越えるって設定ミスじゃなさそうだし、まぁ多分JDKもNetbeansも両方EAだし。ハローワールドのレベルだと動いたのでとりあえず放置。

 

 

 

JavaFXソース、JavaDoc添付(Eclipse 4.3 Kepler)

JavaFXのソースとJavaDocのアタッチのをしていなく何かと不便なので添付する。

そもそもPleiadesに入っていたJava 7にくっついていたもの程度の意識なのでまずはこちらのソースを使ってバージョンを調べる。

javafx.runtime.version: 2.2.25-b15

だそう。

まずJavaDocから入れようとダウンロードサイトを開くとjavafx-2_2_25-apidocs.zipとbuild番号が付いていない。ダウンロードしてみて、レポジトリのチェンジログと比べるとb19の変更が反映されているので時系列に差がある模様。とはいえ、リリースノートが下な感じで、大きな修正は言ってもいないのでそのまま突き進む。

The full version string for this update release is 1.7.0_25-b15 (where "b" means "build") except for Windows on which it is 1.7.0_25-b17. The version number is 7u25.

 

疲れたので、以下作業予定で今日は挫折。 (7/22 再開)

ソースダウンロード(そもそもMercurial入れなければいけないので入れる) -> リンク先の右上にダウンロード用リンクあったので、zipでダウンロード。

ソースとJavaDocを適宜フォルダを作って配備。(C:\dev\attachment\javafx2.2.25)

pomの修正(Localレポジトリを作成しないときれいに添付できないかもしれない。参照先)

プロパティー->Javaのビルドパス->ライブラリー->maven依存関係->jafxt.jarのJavadoc添付、ソース添付から設定することで妥協。

 

JavaFX&Websocket連携(エラーパターン)

対向のサーバが落ちているとき。

素直にハンドシェイクできないという。まぁ、そのまんま。

7 20, 2013 5:43:29 午後 jp.co.epea.firstfxclient.SampleController$TwitterCheckService$1 call
SEVERE: null
javax.websocket.DeploymentException: Handshake response not received.
    at org.glassfish.tyrus.client.ClientManager.connectToServer(ClientManager.java:300)
    at org.glassfish.tyrus.client.ClientManager.connectToServer(ClientManager.java:172)
    at jp.co.epea.firstfxclient.SampleController$TwitterCheckService$1.call(SampleController.java:65)
    at jp.co.epea.firstfxclient.SampleController$TwitterCheckService$1.call(SampleController.java:1)
    at javafx.concurrent.Task$TaskCallable.call(Task.java:1259)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
    at java.util.concurrent.FutureTask.run(FutureTask.java:166)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:724)

 

URI clientURI = new URI(“ws://localhost:8080/first/hellohoge/”);

みたいにURLが間違っている場合。

Handshake errorというやつとスタックとレースにレスポンスコードが返ってくる。

この例だと存在しないパスなので404が返っているけど、WebsocketじゃないただのHTMLだとUpdate Protocolの時に失敗しているので(?)200が返ってくる。

なお、パスの指定時は最後の”/(スラッシュ)”も厳密に見る模様。

7 20, 2013 8:46:51 午後 jp.co.epea.firstfxclient.SampleController$TwitterCheckService$1 call
SEVERE: null
javax.websocket.DeploymentException: Handshake error.
    at org.glassfish.tyrus.client.ClientManager.connectToServer(ClientManager.java:285)
    at org.glassfish.tyrus.client.ClientManager.connectToServer(ClientManager.java:172)
    at jp.co.epea.firstfxclient.SampleController$TwitterCheckService$1.call(SampleController.java:65)
    at jp.co.epea.firstfxclient.SampleController$TwitterCheckService$1.call(SampleController.java:1)
    at javafx.concurrent.Task$TaskCallable.call(Task.java:1259)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
    at java.util.concurrent.FutureTask.run(FutureTask.java:166)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:724)
Caused by: org.glassfish.tyrus.websockets.HandshakeException: Response code was not 101: 404
    at org.glassfish.tyrus.websockets.HandShake.validateServerResponse(HandShake.java:314)
    at org.glassfish.tyrus.websockets.draft06.HandShake06.validateServerResponse(HandShake06.java:98)
    at org.glassfish.tyrus.container.grizzly.WebSocketFilter.handleClientHandShake(WebSocketFilter.java:368)
    at org.glassfish.tyrus.container.grizzly.WebSocketFilter.handleHandshake(WebSocketFilter.java:353)
    at org.glassfish.tyrus.container.grizzly.WebSocketFilter.handleRead(WebSocketFilter.java:274)
    at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:288)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:206)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:136)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:114)
    at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
    at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:837)
    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:565)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:545)
    ... 1 more

Connection had closed.

 

ちなみに、エラーログをはいているのはSampleController#createTaskの中にあるキャッチ節。

        @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/first/hellohoge/");
                        ClientManager cliContainer = org.glassfish.tyrus.client.ClientManager.createClient();
                        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;
        }

下の@OnErrorは通らずに、@OnClose(前のログだと緑字部分)で終わるので注意。

    @OnClose
    public void closeConnection(Session session) {
        System.out.println("Connection had closed.");
    }

    @OnError
    public void onError(Session session,Throwable t) {
        System.out.println("error");
        t.printStackTrace();
    }

javafx.concurrent.Taskの使い方次第でもっとハンドリングできそうな気がする。
とりあえず参考になりそうなサイト

JavaFXとWebsocketを連携してみる(On Glassfish4.0) その1

サーバサイドはいつものようにGlassfish 4.0。まずは寺田さんのブログを見つつメッセージ送信用のページで入れたメッセージが表示されるようにするとこまで持っていく。(元のブログのようにツイッターを見に行きはしないで、index.htmlで入れたものが表示されるようにする。)

サーバ用のエンドポイント(ws://localhost:8080/first/hello/)

package jp.co.epea.first;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint("/hello/")
public class HelloWorld {

    static Set<Session> sessions = Collections
            .synchronizedSet(new HashSet<Session>());

    @OnMessage
    public void onMessage(String message) {
        System.out.println("message[" + message + "]");

        for (Session s : sessions) {
            s.getAsyncRemote().sendText(message);
        }
    }

    @OnOpen
    public void open(Session sess) {
        System.out.println("開始します:" + sess.getId());
        sessions.add(sess);
    }

    @OnClose
    public void close(Session sess) {
        System.out.println("終了します:" + sess.getId());
        sessions.remove(sess);
    }

    @OnError
    public void error(Session sess,Throwable t) {
        System.out.println("エラーです:" + sess.getId());
        t.printStackTrace();
    }
}

メッセージ送信用のページ(http://localhost:8080/first/index.html)

<!DOCTYPE html>
<html>
    <head>
        <title>WebSocketテスト</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
        <script type="text/javascript">
            var socket;
            $(document).ready(function(){
                var host="ws://localhost:8080/first/hello/";
                socket = new WebSocket(host);

                socket.onmessage = function(message){
                    $('#log').append(message.data + "<br/>");
                }

                $('#send').click(function(){
                    var text = $('#msg').val();
                    socket.send(text);
                    $('#msg').val('');
                })

            });
        </script>        
    </head>
    <body>
        <h1>WebSocketテスト</h1>
        <div id="log">
        </div>
        <input id="msg" type="text"/>
        <button id="send">送信</button>
    </body>
</html>

 

クライアントサイドの作成の流れは

  1. MavanプロジェクトとしてJavaFXを作成(前回ブログ)
  2. 足りない依存関係を追加
  3. 寺田さんのブログのクライアントサイドプログラムをコピペ
  4. とりあえず動くようになるために最低限の修正を加える

(手順1と3は省略)

2.足りない依存関係を追加

tyrus-clientとtyrus-container-grizzlyはこちらのブログを参考にしたときに「Grizzly 関連の jar」の今版として使えそうなので試したところいけたっぽいので持ってきた。(ユーザガイド)

    <dependencies>
        <dependency>
            <groupId>com.oracle</groupId>
            <artifactId>javafx</artifactId>
            <version>2.0</version>
            <scope>system</scope>
            <systemPath>C:\dev\pleiades43\java\7\lib/jfxrt.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>org.glassfish.tyrus</groupId>
            <artifactId>tyrus-client</artifactId>
            <version>1.1</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.glassfish.tyrus</groupId>
            <artifactId>tyrus-container-grizzly</artifactId>
            <version>1.1</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

 

4.とりあえず動くようになるために最低限の修正を加える

TwitterClientのアノテーションを@ClientEndpoint、@OnOpen、@OnMessage、@OnCloseに変更。

SampleController.javaのURLを修正。

ClientEndpointConfigurationの行をコメントアウト。

URI clientURI = new URI("ws://localhost:8080/first/hello/");
//ClientEndpointConfiguration clientConfig = new DefaultClientConfiguration();

 

動作確認

サーバを起動する。

JavaFXを起動する。

a

start timelineボタンをクリックしてサーバと接続

(コンソールメッセージ)
Connection had opened.

 

index.htmlからメッセージを送信

b

 

JavaFX側に表示される

c

 

一応これで動作しているようなのでこいつを基点に触っていくことにする。

(JavaFX側をXボタンで閉じたときにOncloseが呼ばれてないっぽいけど、実装的にそういう動きになるのか環境がおかしいのか。。。。。)

2013/11/03追記

子の実装ではJavaFXのTableViewを使用することで、WebSocket側のスレッドによる変更がJavaFXのスレッドに通知されている。(オブザーバ)

桜庭さんに伺ったところ、「(GUIはそっちのスレッドから動かすのが基本なので)きちんと動かないことあるかもよ」とのことでした。

他の日記ではLabelで同期しようとした場合にPlatform.runLaterでJavaFXのスレッドに処理を戻しているけど、そちらの方法が基本とのことでした。

 

JavaFXのMaven(M2E)設定(Eclipse 4.3 Kepler)

Eclipse4.3(実際に使っているのはPleiades all in one)にてM2Eを使ってJavaFXをMavenプロジェクトとして動かすまでのメモ。

新規->その他->Maven->Mavenプロジェクトから次へ次へといってアーキタイプの選択を開く

以前入れたリモートレポジトリに入っているorg.codehaus.mojo.archetypesのjavafxを選択

注:JavaFXのアーキタイプは何種類かあるようでディレクトリ構造は、JavaFX用アークテクとタイプの中でも結構ばらついている。なのでスタンダードな構造はきちんと調べた方がいいかも。

a

 

任意の名前をつけてプロジェクトを作成。

そのままだとJavaFX用のJarをMavenが見えていないので「FXML を型に解決できません」とか「インポートされた javafx は見つかりません」とかで怒られる。

pom.xml(プロジェクト直下ある)にjarのパスを依存関係に追加してやって「Maven->プロジェクトの更新」とやってやると動くようになる。(今のとこ無難に動いている模様。)

追加した内容

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>jp.co.epea</groupId>
    <artifactId>firstfxclient</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>firstfxclient</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <mainClass>jp.co.epea.firstfxclient.MainApp</mainClass>
    </properties>

    <organization>
        <!-- Used as the 'Vendor' for JNLP generation -->
        <name>Your Organisation</name>
    </organization>

    <dependencies> <-アーキタイプによってはすでにあるので注意(dependencyタグだけでよい)
        <dependency>
            <groupId>com.oracle</groupId>
            <artifactId>javafx</artifactId>
            <version>2.0</version>
            <scope>system</scope>
            <systemPath>C:\dev\pleiades43\java\7\lib/jfxrt.jar</systemPath> <-パスは実際にある場所
        </dependency>
    </dependencies>
    <build>

(8/5追記)

パスの外部化と、参考サイトへのリンク記事追加

(12/15追記)

実行可能Jarの作り方リンク

 

JDK8とScene Builder 1.0の併用不可?

(7/25追記)

この件はJDK 8インストール時にPublic JREのインストールをはずしておけば大丈夫だった。

a

 

他にもちょこちょこ触っていたので濡れ衣かもしれないけどもWindwos7の64bitではJDK 8(EA)とScene Builder 1.0の併用は単純には不可っぽい。

64bit版Windows7にてJDK 8(Early AccessのBuild b98)をインストールした翌日に、Scene Builder 1.0を起動しようとしたところ起動できなくなっていた。

java -versionで1.8を呼んでいるので

JAVA_HOME=C:\Program Files\Java\jdk1.7.0_25
Path=C:\Program Files\Java\jdk1.7.0_25\bin;~

な感じに環境変数をセットして1.7にパスを通しなおしてみたけどだめ。

レジストリのHKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime EnvironmentをみるとCurrentVersionに1.8とかレジストリはいろいろ書いてある。

scenebuilder.exeなのでそっちを見てうまくいかないのかな??

ということで、JDK 8(とアプリ的には別にインストールされていたJRE 8)をアンインストールしたら無事に起動できた。

濡れ衣かも知れないけどそういうことと思っておこう。。。。