Hatena::ブログ(Diary)

tomoTakaの日記

2015-12-31

SDKMANを使ってSpringBootのインストールを試してみました

久しぶりにSpringBootを復習してみようとドキュメントを読んでいるとSDKMANを使ったインストール方法と、WebApplicationをGroovyを使ったサンプルがSpring Boot Reference Guideここで紹介されていたので試してみました。

インストール

sdk install springboot

f:id:tomoTaka:20151231112827p:image:w360

groovyでweb applicationを実装

上記のドキュメントを実装

@RestController
class ThisWillActuallyRun {
    @RequestMapping("/")
    String home() {
        "Hello World!"
    }
}
  • 起動コマンド
spring run app.groovy

f:id:tomoTaka:20151231113352p:image:w200

Javaでも動作するかを試してみました

上記のドキュメントを実装

import org.springframework.boot.*;
import org.springframewowk.boot.autoconfigure.*;
import org.springframework.boot.stereotype.*;
import org.springframework.web.bind.annotatin.*;

@RestController
@EnableAutoConfiguration
public class Example {
    @RequestMapping("/")
    String home() {
        return "Hello World!(Java) ";
    }

    public static void main(String... args) throws Exception {
        SpringApplication.run(Example.class , args);
    }
}
  • 起動コマンド
spring run Example.java

f:id:tomoTaka:20151231112246p:image:w200
Javaでもコンパイルしないで動作しました。すごく便利です!

2015-12-20

ちょっと試してみた

ここGet started with Dockerを参考に再度インストール

インストール

インストールできた。っと思ったらエラーが発生して動作しない。そもそも以前にboot2dockerインストールしたままだった(汗)
f:id:tomoTaka:20151219152137p:image:w380

ここDocker uninstallを参考にいろいろ削除などして、再度インストール、なんとかDocker run コマンドは動作するようになりましたが、、、

  • boot2dockerを削除
boot2docker stop
boot2docker delete
  • 不要なファイルを削除

/usr/local/bin 配下のファイルなどを削除

.bash_profile のDOCKERに関する指定を削除

次に以下のコマンドでのDocker Hub へのログインで認証エラー?

docker login --username=xxx --emial=xxxx

ぐぐった結果以下のコマンドを実行。ユーザー、パスワード、emailがきかれるのでそれぞれ入力して無事loginできました。

docker login

Docker Hub

なんとか作成したRepositoryにpushできました。
f:id:tomoTaka:20151220090318p:image:w550

まだまだ勉強しないと、、、

2015-12-13

JDK9で起動しなくなった時の対処

JDK9をダウンロードインストールNetBeansが起動しなくなった、、、
で調べてみると、なんだか「Perm Gen options」が問題なようです。[JDK-8038827] Perm Gen options partially removed and partially only ignored - Java Bug System
NetBeansのここUsing NetBeans IDE on Mac OS Xをみてjdkhomeが指定できるようなので
以下のようにjdk8で起動するようにしたら起動できました。

  • ApplicationのNetBeans.appで「control」+クリックで、「パッケージの内容を表示」をクリック

f:id:tomoTaka:20151213073526p:image:w350

  • 以下のフォルダの「netbeans.conf」ファイルを開く

f:id:tomoTaka:20151213073542p:image:w350

「netbeans_jdkhome」の行でJDK8を指定
f:id:tomoTaka:20151213073614p:image:w550
いろいろ知らないことがあったのですが、とても勉強になりました。

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パターンの実装は、ここno titleを参考にしました。

画面

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

  • 初期表示時

f:id:tomoTaka:20151212153445p:image:w350

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

f:id:tomoTaka:20151212153517p:image:w370

実装

  • 非同期処理

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

    @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);
    }    

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

2015-12-05

Java EEエヴァンジェリストによる!EE 8最新動向!に行ってきました!

Java EEエヴァンジェリストによる!EE 8最新動向! - connpassに行ってきました。

JavaOne 2015 サンフランシスコ サマリー

@さんによるJavaOneのお話。
現場での裏話(ケーキのお話とか、蟹パーティー)もあったりして楽しかったです。
それとJavaチャンピオンJCP、などJavaに関するお話もあって初めて勉強会に参加した方がJavaに関心を持ってくれたのも嬉しかったです!
(実際1週間前に別のイベントOsaka Satellite: Rakuten Technology Conference 2015 on Nov. 21st - Mitsuyuki.Shiibaでお会いした学生さん@が参加してJavaEEに興味を持っていただいて良かったです)

Java EE 8 最新動向

@さんによるJavaEE8のお話。
JavaEE8で追加される機能の紹介で、JSON, HTTP2, Server Sent Eventなど盛りだくさんでした。
David Delabassee’s Presentations on SlideShare
最後に質問タイムがあって、質問者にはJavaOneのTシャツがプレゼントされました。

でServer Sent Event はJerseyですでに実装されているとお聞きしたので早速試してみました。
no titlePage not found · GitHubを参考にサーバ側を実装。
HTML5 Server-Sent Eventsを参考にクライアント側を実装。

Server Sent Event を試してみました

  • 画面1(URLを指定しただけ)

f:id:tomoTaka:20151205161044p:image:w300

なぜかエラーイベントが発生?
f:id:tomoTaka:20151205161148p:image:w380

EventOutput、OutboundEventなど初めて知りました。勉強しないといけないことが沢山です。(汗)

package com.mycompany.sseserversample;

import java.io.IOException;
import java.net.URI;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.media.sse.EventOutput;
import org.glassfish.jersey.media.sse.OutboundEvent;
import org.glassfish.jersey.media.sse.SseFeature;
import org.glassfish.jersey.server.ResourceConfig;

/**
 * Sever Sent Event Sample.
 * 
 * @author tomo
 */
@Path("event/{task-cnt}/{task-interval}")
public class ServerSample {
    public static void main(String... args) throws IOException, InterruptedException{
        ResourceConfig config = new ResourceConfig(ServerSample.class, SseFeature.class);
        URI uri = URI.create("http://localhost:8080/");
        HttpServer server = GrizzlyHttpServerFactory.createHttpServer(uri, config, false);
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            server.shutdownNow();
        }));
        server.start();
        System.out.println("Server started. Stop the Application using CTR-C");
        Thread.currentThread().join();
        System.out.println("Server end.");
    }
    
    @GET
    @Produces(SseFeature.SERVER_SENT_EVENTS)
    public EventOutput getServerSentEvents(@PathParam("task-cnt") int taskCnt,
            @PathParam("task-interval") int taskInterval){
        System.out.println("*taskcnt=" + taskCnt +", " + taskInterval);
        final EventOutput eventOutput = new EventOutput();
        new Thread(() -> {
            try {
                for (int i = 0; i < taskCnt; i++) {
                    TimeUnit.SECONDS.sleep(taskInterval);
                    final OutboundEvent.Builder eventBuilder = new OutboundEvent.Builder();
                    eventBuilder.name("message-client");
                    eventBuilder.data(String.class, "Hello world " + i);
                    eventBuilder.comment("comment"+ i);
                    eventBuilder.id("id"+ i);
                    final OutboundEvent event = eventBuilder.build();
                    eventOutput.write(event);
                }
            } catch (IOException | InterruptedException ex) {
                Logger.getLogger(ServerSample.class.getName()).log(Level.SEVERE, null, ex);
            } finally {
                try {
                    eventOutput.close();
                } catch (IOException ex) {
                    Logger.getLogger(ServerSample.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }).start();
        return eventOutput;
    }
}

EventSource初めて知りました。本当に次々新しい機能があって楽しいです!

<!DOCTYPE html>
<html>
    <head>
        <title>Server Sent Event Sample</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
    </head>
    <body>
        <h2>Server Sent Event Sample</h2>
        <div>
            <label>Task count:</label>
            <input type="number" id="task_count" />
            <label>Task interval:</label>
            <input type="number" id="task_interval" />
        </div>
        <div>
            <button id="sendBtn">Server Send Event Start</button>
            <button id="closeBtn">Server Send Event Close</button>
        </div>
        <div>
            <h3>Received Messages</h3>
            <output id="result"></output>
        </div>
        <script>
            'usestrict';
            (function(){
                var sendBtn = document.getElementById('sendBtn');
                var closeBtn = document.getElementById('closeBtn');
                var result = document.getElementById('result');
                var eventSource = null;
                // close button click event 
                closeBtn.addEventListener('click', function(){
                    if (eventSource){
                        eventSource.close();
                    }
                });
                // start button click event 
                sendBtn.addEventListener('click', function(){
                    if (typeof (EventSource) !== void 0){
                        //EventSource がサポートされている場合
                        result.insertAdjacentHTML('beforeend', 
                            '<li>EventSource supported!</li>');
                        var taskCnt = document.getElementById('task_count').value;
                        var taskInterval = document.getElementById('task_interval').value;
                        var url = 'http://localhost:8080/event/' 
                                + taskCnt + '/' + taskInterval + '/';
                        eventSource = new EventSource(url);
                        eventSource.addEventListener('message-client', function(event){
                        result.insertAdjacentHTML('beforeend', 
                            '<li>' + event.data + '</li>');
                        });
                        eventSource.onerror = function(){
                            result.insertAdjacentHTML('beforeend', 
                            '<li>EventSource Error!</li>');
                            eventSource.close();
                        };
                    } else {
                        //EventSource がサポートされていない場合
                        result.insertAdjacentHTML('beforeend', 
                            '<li>not support EventSource</li>');
                    }
                });
            }());
        </script>
    </body>
</html>

サーバ側はここGitHub - tomoTaka01/SseServerSample: Server Send Event Server Sampleにアップ
クライアントHTMLはここHTML file for Server Sent Event JavaScript Sample ? GitHubにアップ
参加者全員にJava20年のステッカーいただきました!
f:id:tomoTaka:20151205181530p:image:medium
スタッフの方々、参加者の皆さんお疲れさまでした。とても楽しく有意義な時間を過ごせました!!!

2015-11-22

Rakuten Technology Conference2015

This is the third time for me to participate in Rakuten Technology Conference.
When I registered they gave me a pretty charm and a introduction card.
f:id:tomoTaka:20151122064409j:image:w250:leftf:id:tomoTaka:20151122064340j:image:w250

I was so nervous and made a mistake on my card. The word greate should be great. :-(
You can get the Time Table and some information about the conference here.Osaka Satellite: Rakuten Technology Conference 2015 on Nov. 21st - Mitsuyuki.Shiiba
I felt that all speakers have passions for their idea. And I was impressed by them.
Also I talked with a lot of nice people.
The staff allowed me to introduce the workshop which is hold next weekend about JavaEE8 in English.
Java EEエヴァンジェリストによる!EE 8最新動向! - connpass
It is very difficult for me to write the blog in English.
I would like to thank all of staff!!!

Connection: close