Server Event Client Sample

JavaFX Advent Calendar 2015 - Qiitaの13日目です。
昨日は@さんのJavaFX と Project Jigsaw - JavaFX in the Boxでした。
明日は@さんです。
前回Server Sent Event のサーバー処理についてちょっと実装を試したJava EEエヴァンジェリストによる!EE 8最新動向!に行ってきました! - tomoTakaの日記のですが、クライアントもJavaで実装できると紹介されていたので、JavaFXでサーバーから受信したレスポンスをアニメーションで表現してみるのに挑戦しました。
ですが、そもそもアニメーションがよくわかっていなくて、、、
2パターンの実装は、ここChapter 15. Server-Sent Events (SSE) Supportを参考にしました。

画面

リクエスト送信ボタンをクリックした後、指定したタスク数の「Task0〜5の結果」ラベルが左(サーバー)から右(クライアント)へタスク処理時間で指定した時間の間隔で移動します。
「リクエスト送信(非同期)」ボタンの処理は思ってようにアニメーションしますが、「リスエスト送信(同期)」ボタンの処理は、アニメーションで複数のラベルが同時になってしまいます???

  • 初期表示時

  • リスエスト送信(非同期)ボタンクリック後

実装

  • 非同期処理

アニメーションの部分はコメントいただいて修正しています。

    @FXML
    private void requestAction2(ActionEvent event){
        listeningProperty.setValue(Boolean.TRUE);
        disableProperty.setValue(Boolean.FALSE);
        int taskCntVal = taskCnt.getValue();
        int taskIntervalVal = taskInterval.getValue();
        String url = "http://localhost:8080/event/" 
                + taskCntVal + "/" + taskIntervalVal;
        Client client = ClientBuilder.newBuilder().register(SseFeature.class).build();
        WebTarget target = client.target(url);
        eventSource = EventSource.target(target).build();
        eventSource.register(inboundEvent ->{
            String data = inboundEvent.readData(String.class);
            int id = Integer.parseInt(inboundEvent.getId());
            Label label = labels[id];
            TranslateTransition t = transitions[id]; // **サーバーより受信したIDで実行するアニメーションを設定
            Platform.runLater(()->{
                label.setText(data); // **ラベルにサーバーより受信した結果を設定
                new Timeline(new KeyFrame(Duration.millis(500), e-> t.play())).play(); / **アニメーション開始
            });
        }, "message-client");
        eventSource.open();
    }

修正後

            Platform.runLater(()->{
                 label.setText(data);
                TranslateTransition t = new TranslateTransition(Duration.millis(300), label);
                t.setFromX(0);
                t.setToX(-200);
                t.play();  // **アニメーション開始
            });
  • 同期処理
    @FXML
    private void requestAction1(ActionEvent event) {
        listeningProperty.setValue(Boolean.TRUE);
        disableProperty.setValue(Boolean.FALSE);
        Arrays.stream(labels).forEach(l -> l.setText(null));
        int taskCntVal = taskCnt.getValue();
        int taskIntervalVal = taskInterval.getValue();
        String url = "http://localhost:8080/event/" 
                + taskCntVal + "/" + taskIntervalVal;
        Client client = ClientBuilder.newBuilder().register(SseFeature.class).build();
        WebTarget target = client.target(url);
        EventInput eventInput = target.request().get(EventInput.class);
        while (!eventInput.isClosed()){
            InboundEvent inboundEvent = eventInput.read();
            if (inboundEvent == null){
                break;
            }
            int id = Integer.parseInt(inboundEvent.getId());
            Label label = labels[id];
            String data = inboundEvent.readData(String.class);
            label.setText(data);                
            TranslateTransition t = transitions[id];
            new Timeline(new KeyFrame(Duration.millis(500), e-> t.play())).play();
        }
    }
  • 初期処理

アニメーションの初期設定など

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        labels = new Label[] {label1, label2, label3, label4, label5};
        Arrays.stream(labels).forEach(l -> l.setText(null));
        transitions = new TranslateTransition[]{
            new TranslateTransition(Duration.millis(500), label1)
           ,new TranslateTransition(Duration.millis(500), label2)
           ,new TranslateTransition(Duration.millis(500), label3)
           ,new TranslateTransition(Duration.millis(500), label4)
           ,new TranslateTransition(Duration.millis(500), label5)
        };
        Arrays.stream(transitions).forEach(t -> {
            t.setFromX(0);
            t.setToX(-200);
        });
        // Buttonの使用制御
        listeningProperty = new SimpleBooleanProperty(false);
        startBtn1.disableProperty().bind(listeningProperty);
        startBtn2.disableProperty().bind(listeningProperty);
        disableProperty = new SimpleBooleanProperty(true);        
        closeBtn.disableProperty().bind(disableProperty);
    }    

実装はここtomoTaka01/SseClientSample: Server Sent Eve... - GitHubにアップしています。
JavaFXの問題ではないのですが、非同期処理を実行するとサーバーへ何度もリクエスト送信されてしまいます?(汗)
すごく中途半端な状態で申し訳ないですが、アドバイスいただければ幸いです、、、
アニメーション難しいです、まだまだ勉強不足です、、、