Challenge Engineer Life !

エンジニア人生を楽しみたい!仕事や趣味で学んだ技術的なことを書いていくブログです。

SendGridFX : JavaFX meets SendGrid ! #JavaFX #SendGrid

I'm new to JavaFX and want to make something interesting.

A month ago I signed up SendGrid, because my old colleague @nakansuke starts to new business with SendGrid company.
He advised me that there is a good Java wrapper library of SendGrid WebAPI, it's sendgrid4j.
http://oss.flect.co.jp/libs/en/sendgrid4j.html

Exactly, it's good and easy to use SendGrid WebAPI.

Today I was having fun with JavaFX and SendGrid.
My simple idea is sending HTML mail with HTMLEditor on JavaFX.

This is my simple application.
I only use Label, TextField, Button and HTMLEditor.

f:id:kikutaro777:20131025233829j:plain

Only input sending e-mail address and subject and contents of mail by HTML.

f:id:kikutaro777:20131025234142j:plain

HTMLEditor component on JavaFX is good to write HTML.

I sent this mail to my web-mail of Yahoo, so checked it.

I think JavaFX programmer might say "Hey guy, why don't you check your web mail by WebView?" Yeah, that's true. I did it :)

This is my JavaFX application includes WebView.
Yes! I got the mail!
f:id:kikutaro777:20131025234414j:plain

I opened it and saw HTML mail.

f:id:kikutaro777:20131025235010j:plain

Of course, it's same looking of HTMLEditor :)

I show my code of JavaFX Controller class. It's very simple.

package jp.co.hoge.sendgridfx;

import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.web.HTMLEditor;
import jp.co.flect.sendgrid.SendGridClient;
import jp.co.flect.sendgrid.SendGridException;
import jp.co.flect.sendgrid.model.WebMail;

public class SendGridFXController implements Initializable {
    
    //SMTP authentication info of SendGrid
    private static final String SMTP_AUTH_USER = "blah-blah-blah";
    private static final String SMTP_AUTH_PWD  = "blah-blah-blah";
    
    //Mail from info
    private static final String MAIL_FROM = "kiku@test.com";
    private static final String MAIL_FROM_NAME = "Test from Kiku";
    
    SendGridClient client;
    
    @FXML
    private HTMLEditor editor;
    
    @FXML
    private TextField textTo;
    
    @FXML
    private TextField textTitle;
    
    @FXML
    private Label message;
    
    @FXML
    private void sendButtonAction(ActionEvent event) {
        try {
            WebMail mail = new WebMail();
            
            //setting mail from
            mail.setFrom(MAIL_FROM);
            mail.setFromName(MAIL_FROM_NAME);
            
            //setting mail to
            mail.setTo(textTo.getText());
            
            //setting mail subject
            mail.setSubject(textTitle.getText());
            
            //setting HTML content
            mail.setHtml(editor.getHtmlText());
            
            //sending mail
            client.mail(mail);
            
            message.setText("Sending mail is success.");
        } catch (IOException | SendGridException ex) {
            message.setText("Sending mail is failed.");
        }
    }
    
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        client = new SendGridClient(SMTP_AUTH_USER, SMTP_AUTH_PWD);
    }    
}

We can use sendgrid4j by maven.

Here is pom.xml.
Repository setting of sendgrid4j.

<repositories>
    <repository>
        <id>jp.co.flect</id>
        <name>FLECT maven repository</name>
        <url>http://flect.github.io/maven-repo/</url>
    </repository>
</repositories>

Dependency is here.

<dependencies>
    <dependency>
        <groupId>jp.co.flect</groupId>
        <artifactId>sendgrid4j</artifactId>
        <version>0.9.1</version>
    </dependency>
</dependencies>

That's it :)

JavaFXとSendGridで簡易送信メーラーSendGridFXを作る!

少し前にSendGridへ登録したのですが、結構放置してました(^^;

登録の流れやJavaで送信する簡易プログラムは前のエントリを参照下さい↓

JavaでSendGridを利用したメール送信

sendgrid4j使うとJavaで簡単にSendGrid経由にメール送れるので何か面白いことできないかなぁ、と思ってたのですが、最近遊んでるJavaFXと合わせてみました。

名付けてSendGridFX!(なにそれ

すごい簡単なプログラムですが、JavaFXのHTMLEditorコンポーネントを使って、SendGrid経由でHTMLメールを送る、というものです(^^;それだけ

画面は以下のような感じで、ラベルとテキストとボタン、そしてHTMLEditorだけの超シンプルな構成です。

f:id:kikutaro777:20131025193729j:plain

宛先とタイトルを入れて、メール内容をHTMLEditorで書きます。

f:id:kikutaro777:20131025193805j:plain

HTMLEditorで

  • フォント色やサイズ、太字・イタリックに変えたり
  • 横罫線入れたり
  • 箇条書き(番号つきも)
  • センタリングや右寄せ

などなどしてみました。

で、送信!!

受信したメーラ(ThunderBird)でみると(本当はメーラもJavaFXで作ってるとかっこいい気も…)

ちゃんとHTMLメール!!(あたりまえっ

f:id:kikutaro777:20131025194056j:plain

せっかくなので、Yahooメール辺りに送って、JavaFXのWebViewからみてみます(^^;

こんなメールを

f:id:kikutaro777:20131025195149j:plain

送信!

JavaFXでWebViewを置いたアプリでYahooのメールをみてみます。

f:id:kikutaro777:20131025195218j:plain

おおー

f:id:kikutaro777:20131025195227j:plain

やはりJavaFX面白い!そしてSendGridも便利そう!

ちなみにSendGridは前に一緒に仕事していた後輩がSendGrid社とパートナーになって最近力を入れていますので興味ある方は是非彼に!ブログも始めたらしい(^^↓

プログラム

NetBeans7.4からJavaFXプロジェクトをMavenで作れるようになったので、sendgrid4jもpom.xml

リポジトリ

<repositories>
    <repository>
        <id>jp.co.flect</id>
        <name>FLECT maven repository</name>
        <url>http://flect.github.io/maven-repo/</url>
    </repository>
</repositories>

依存性を書けばOKですね。

<dependencies>
    <dependency>
        <groupId>jp.co.flect</groupId>
        <artifactId>sendgrid4j</artifactId>
        <version>0.9.1</version>
    </dependency>
</dependencies>

Maven使えるとやはり楽w

コードはこんなレベルです(^^;JavaFXのコントローラだけですが

package jp.co.hoge.sendgridfx;

import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.web.HTMLEditor;
import jp.co.flect.sendgrid.SendGridClient;
import jp.co.flect.sendgrid.SendGridException;
import jp.co.flect.sendgrid.model.WebMail;

public class SendGridFXController implements Initializable {
    
    //SendGridのSMTPアクセス情報
    private static final String SMTP_AUTH_USER = "hogehoge";
    private static final String SMTP_AUTH_PWD  = "hogehoge";
    
    //送信元の情報
    private static final String MAIL_FROM = "kiku@test.com";
    private static final String MAIL_FROM_NAME = "キクタローテスト";
    
    SendGridClient client;
    
    @FXML
    private HTMLEditor editor;
    
    @FXML
    private TextField textTo;
    
    @FXML
    private TextField textTitle;
    
    @FXML
    private Label message;
    
    @FXML
    private void sendButtonAction(ActionEvent event) {
        try {
            WebMail mail = new WebMail();
            
            //送信元情報
            mail.setFrom(MAIL_FROM);
            mail.setFromName(MAIL_FROM_NAME);
            
            //送信先
            mail.setTo(textTo.getText());
            
            //送信タイトル
            mail.setSubject(textTitle.getText());
            
            //HTMLエディタ入力内容
            mail.setHtml(editor.getHtmlText());
            
            //メール送信
            client.mail(mail);
            
            message.setText("メールの送信に成功しました。");
        } catch (IOException | SendGridException ex) {
            message.setText("メールの送信に失敗しました。");
        }
    }
    
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        client = new SendGridClient(SMTP_AUTH_USER, SMTP_AUTH_PWD);
    }    
}

簡単なメール送信するだけなら、こんなレベルで作れます(^^;

ちなみにJDK8で作っていたのですが、HTMLEditorを使うと実行時に以下のエラーで落ちました…。


Exception in Application start method
java.lang.StringIndexOutOfBoundsException: String index out of range: -1
at java.lang.String.substring(String.java:1959)
at com.sun.javafx.scene.web.skin.HTMLEditorSkin$15$1.updateItem(HTMLEditorSkin.java:699)
at com.sun.javafx.scene.web.skin.HTMLEditorSkin$15$1.updateItem(HTMLEditorSkin.java:694)
at javafx.scene.control.ListCell.updateItem(ListCell.java:442)
at javafx.scene.control.ListCell.indexChanged(ListCell.java:320)
at javafx.scene.control.IndexedCell.updateIndex(IndexedCell.java:115)
at com.sun.javafx.scene.control.skin.VirtualFlow.setCellIndex(VirtualFlow.java:1730)
at com.sun.javafx.scene.control.skin.VirtualFlow.getCell(VirtualFlow.java:1627)
//略
java.lang.reflect.InvocationTargetException
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:491)
//略
Caused by: java.lang.RuntimeException: Exception in Application start method
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:868)
at com.sun.javafx.application.LauncherImpl.access$000(LauncherImpl.java:55)
at com.sun.javafx.application.LauncherImpl$1.run(LauncherImpl.java:157)
at java.lang.Thread.run(Thread.java:724)
Caused by: java.lang.StringIndexOutOfBoundsException: String index out of range: -1
at java.lang.String.substring(String.java:1959)
at com.sun.javafx.scene.web.skin.HTMLEditorSkin$15$1.updateItem(HTMLEditorSkin.java:699)
at com.sun.javafx.scene.web.skin.HTMLEditorSkin$15$1.updateItem(HTMLEditorSkin.java:694)
at javafx.scene.control.ListCell.updateItem(ListCell.java:442)
//略
at com.sun.glass.ui.win.WinApplication.access$300(WinApplication.java:39)
at com.sun.glass.ui.win.WinApplication$3$1.run(WinApplication.java:101)
... 1 more
Exception running application jp.co.hoge.sendgridfx.MainApp

JDKというよりmavenまわりなのかな(^^;JDK7にしたら動いたので、とりあえず今回のサンプルはNetBeans7.4とJDK7で作りました。

JavaOne 2013 San Francisco報告会に参加しました!#jjug #j1jp

先週末の10/19にJJUG(日本Javaユーザグループ)主催の「JavaOne 2013 San Francisco報告会 Tokyo」に行ってきました。
http://www.java-users.jp/?p=682
去年の会場はグリーでしたが、今年は青山のOracleでした。

内容は…スライドが公開されているものが多いので、そちらをみてもらうほうが良いです(^^;
しかも今回の報告会映像自体、@yusukeさんによりYouTubeにあがっているので、そちらを参照下さい(^^)


土曜日だったので予定があって参加できなかった方もいらっしゃると思うので、こういう映像はホント助かりますね。

以下個別にもリンクつけておきます。

Java ME のアップデート

大山さんからJava ME、というかJava Embeddedに関するJavaOne報告がありました。
去年のJavaOne報告会に参加した際、大山さんが楽しそうに発表してるのをみて、JavaOneって楽しいんだろうなぁ、って思ったのを思い出します。
今回もとても楽しそうでした(^^)

http://www.youtube.com/watch?v=kSNIhAiH1t4&list=PLuLCOB9HcrT2kH75HGOpQI2HtyNtg6Q1K&index=2

Java SE のアップデート

櫻庭さんからJava SEに関する報告でした。
Javaの世界って、よく人の名前が出てくる(特にSpec Leadとかだと思いますが)ので面白いなぁと思うのですが、今回の櫻庭さんの発表は人物から入る形式でとても面白かったです(^^)

http://www.youtube.com/watch?v=qB-r71oAxFY&list=PLuLCOB9HcrT2kH75HGOpQI2HtyNtg6Q1K&index=3

JavaFX のアップデート

去年の報告会では櫻庭さんが発表されていたJavaFXですが、今年は青江さんからの発表でした!
最近自分もJavaFX触り始めたので、色々勉強になりました(^^)SceneBuilderで帳票っぽいの作って印刷するデモはインパクト大でしたw

印刷の様子はYouTubeにアップされてましたw

http://www.youtube.com/watch?v=mxKGSZwMvOs&list=PLuLCOB9HcrT2kH75HGOpQI2HtyNtg6Q1K&index=4

Java EE のアップデート

アリエル・ネットワークの井上さんからJava EEに関するお話でした。
以下ブログにて資料の公開と内容についてまとめられているようですので、参照下さい。
http://dev.ariel-networks.com/wp/archives/4134

http://www.youtube.com/watch?v=5mJVbep2c7I&list=PLuLCOB9HcrT2kH75HGOpQI2HtyNtg6Q1K&index=5

JavaOne 2013 Backstage pass – Road to JavaOne

今年のJavaOneでスピーカーとして発表されたAcroquest Technologyの谷本さん、勝本さんによる発表でした。
JavaOneの舞台裏(都市伝説とかw)やJavaOneスピーカーになるまでの道のり、JavaOneの発表で工夫されたことなどをメインに発表されていて、すごく面白かったです。

http://www.youtube.com/watch?v=bKcCnwIerb8&list=PLuLCOB9HcrT2kH75HGOpQI2HtyNtg6Q1K&index=6

楽天株式会社における GlassFish の活用事例

同じくJavaOneでスピーカーとして発表された楽天の橋山さんによる発表でした。
JavaOneで発表されたスライドベースに、楽天市場で利用されているGlassFishの運用に関する内容で、私自身もGlassFishを利用しているので大変参考になりました。

橋山さんとはGlassFish Partyで海外の方含めてお話させて頂いたのですが、個人的には記念です(^^;

http://www.youtube.com/watch?v=eTGo3YynQTQ&list=PLuLCOB9HcrT2kH75HGOpQI2HtyNtg6Q1K&index=7

JavaOne 参加者 LT 大会

bck2brwsr紹介

@yusukeさんからチャックノリス、ではなくbck2brwsrの紹介、兼デモがありました。
JavaScriptでクラスファイル読むとか…ええ、みたいな話が(^^;

http://www.youtube.com/watch?v=u1MzKQ7Yq_E&list=PLuLCOB9HcrT2kH75HGOpQI2HtyNtg6Q1K&index=9

AeroGear & Java EEで簡単プッシュ通知

@n_agetsuさんからイントラでもプッシュ通知をする話がありました。
スライドも公開されていました~。

http://www.youtube.com/watch?v=Wg1DLzqXup4&list=PLuLCOB9HcrT2kH75HGOpQI2HtyNtg6Q1K&index=14

JavaVM、増えてきました

@chi9rinさんからZulu(Windows Azureで動くJVM)などに関する話&デモがありました。

http://www.youtube.com/watch?v=uix8wrU8TCk&list=PLuLCOB9HcrT2kH75HGOpQI2HtyNtg6Q1K&index=10

How to make the Future Java

北野さんからの発表でした。
今年のJavaOneでは子供たちへのプログラミング教育に関する話が多かったようで、日本でもやりたい!という熱い発表でした。

MeetUpのサイトも作られてるとのことです。
http://www.meetup.com/Code-For-Kids-YOKOHAMA/

http://www.youtube.com/watch?v=3KrR-18Un8s&list=PLuLCOB9HcrT2kH75HGOpQI2HtyNtg6Q1K&index=13

本場JavaOneに参加して得たことなど

@boochnichさんからのLTでした。JavaFXで作成された3Dの地球デモが印象的でした(^^)

http://www.youtube.com/watch?v=F4rfYLitEvg&list=PLuLCOB9HcrT2kH75HGOpQI2HtyNtg6Q1K&index=11

Java1年生がJavaOneに行ってきました

つたないですが自分のLTでした(^^;
練習で5分オーバーしてたので、かなり早口でした…反省。

http://www.youtube.com/watch?v=F4rfYLitEvg&list=PLuLCOB9HcrT2kH75HGOpQI2HtyNtg6Q1K&index=11

warをばらしましょう!

岡澤さんによるLTでした。

http://www.youtube.com/watch?v=HkSTSvljnTs&list=PLuLCOB9HcrT2kH75HGOpQI2HtyNtg6Q1K&index=15

あとがき

自分がJavaOne 2013に行くきっかけとなったのは去年のJavaOne 2012報告会でした。
本当に皆さん楽しそうで、いつか行ってみたいなと。
それが1年後になるとは思ってもみなかったですが(^^;

来年も参加したい!

Java Puzzlerとは言えないけどJavaの要素削除で理解できなくて頭を抱えたコード

Javaを長らくやられてる方からするとピンとくるのかもしれないですが…。

先日「Javaでリストをループでまわして要素削除するのにハマったこと」を書きましたが、若手から「ループで要素ぶっこ抜いても動きますよ(ドヤ」と言われたコードが以下でした。

普通に拡張for文の中で要素削除してるコード(^^;

package arrayloopremove;

import java.util.ArrayList;
import java.util.List;

public class ArrayLoopRemove {

    public static void main(String[] args) {
        List<String> meiboList = new ArrayList<>();
        meiboList.add("堀北真希");
        meiboList.add("能年玲奈");
        meiboList.add("宮崎あおい");
               
        System.out.println("remove後 -> " + meiboList);
        
        for(String name : meiboList){
            if(name.startsWith("能年")){
                //本来タブーなループ処理での要素抜き
                meiboList.remove(name);
            }
        }

        System.out.println("remove後 -> " + meiboList);
    }
}

普通に「え、駄目じゃない?ConcurrentModificationException出ると思うよ」と言いつつ実行してみると…

remove後 -> [堀北真希, 能年玲奈, 宮崎あおい]
remove後 -> [堀北真希, 宮崎あおい]

動いた!ええっ…なぜ…。

………

……

わからんです(-_-;

ちなみにですが、ループ内のstartWithを"堀北"や"宮崎"にすると

remove後 -> [堀北真希, 能年玲奈, 宮崎あおい]
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:819)
at java.util.ArrayList$Itr.next(ArrayList.java:791)
at arrayloopremove.ArrayLoopRemove.main(ArrayLoopRemove.java:32)
Java Result: 1

とConcurrentModificationExceptionになります。

「ほら、やっぱり出るじゃん!」

「でも、さっきの出ませんでしたよね?」

と、謎すぎる orz

中々わからなくて、ググってみたら以下の記事がドンピシャっぽい。

Listを直接変更してもIteratorがConcurrentModificationExceptionをスローしない件

Listの最後から2番目って…(^^;でも確かに要素をもう1つ追加して後ろから2番目を消すと消せる;

remove後 -> [堀北真希, 能年玲奈, 宮崎あおい, 橋本愛]
remove後 -> [堀北真希, 能年玲奈, 橋本愛]

まあ、そもそもこういう処理したら駄目というのは割と既知のことなので、普通はしないと思うのですが、こんな風にたまたま動いてしまうケースがあって怖いのぉ…と。

なおJDKは7です。

まあ、JavaDocArrayListの部分を読むと、駄目よ、と書いてるので、まあそもそもやるなという話ですね(^^;
http://docs.oracle.com/javase/jp/7/api/java/util/ArrayList.html

ちなみにC#2.0(手元にVisualStudio2005しかないので…)で試したら後ろから2番目だろうが、ちゃんと駄目でした(^^;当たり前か

JavaOne 2013 San Francisco報告会 TokyoでLTさせて頂きました!

今日はJJUG(日本Javaユーザグループ)主催の「JavaOne 2013 San Francisco報告会 Tokyo」に行ってきました(^^)
http://www.java-users.jp/?p=682

聞いた内容をまとめるのは後日ゆっくりしたいと思います。

今回、最後に行われたLT大会で私も発表させて頂きました。
練習では5分オーバーだったので、かなり早口になってしまいました(^^;

※発表では人物写真ありましたが、アップしたスライドからは削除していますm(_ _)m

Javaをはじめて1年ですが、今回JavaOne2013に思いきって参加したきっかけの1つに去年参加したJavaOne報告会があります。ちょうど参加した感想をブログにしてました。

JavaOne 2012 San Francisco 報告会@グリーに参加

JavaOne報告会って発表者の方々が本当に楽しそうに話すんですよね。
発表者の方々の発表がうまい、というのもあるのですが、本当にJavaOneが楽しかったんだろうなぁって感じさせるような、そんな発表が多いです。

自分が初めて参加した社外イベントがたまたまJavaOne2012の報告会だったから、余計印象的だったのかもしれませんが(^^;でも、今日もそうでしたよね(^^)

今日の発表ではJavaOneでスピーカーとして発表された方々からの話もあって、ああいった大舞台で日本のエンジニアの方が発表されるなんて凄いなぁと改めて思いました。

とりあえず懇親会まで参加して、ジャンケン大会でGlassFishのTシャツもらいました(^^)/


f:id:kikutaro777:20131019235737j:plain


f:id:kikutaro777:20131019235742j:plain

Javaが良いか悪いか、自分は1年生だし、そんなこと全然語れないですが、仕事で強制的にJavaをやることになって、ネガティブになりながらやるよりポジティブにやってみよう、とチャレンジしてきた1年でした(^^;社内に閉じこもっていたらしんどかったかもしれないですが、社外の勉強会とか参加するようになって楽しむことができるようになった気がします。

Javaでリストをループでまわして要素削除するのにハマったこと

以下色々なサイトで既出なのですが、自戒を込めて書いておこう(-_-;

仕事で書いてたプログラムですが、よくある「リストをループでまわして要素を削除する」処理で少しハマってました。実行時にjava.lang.UnsupportedOperationExceptionで落ちるっていう。

まず「リストをループでまわして要素を削除する」処理についてJavaで標準的なのって何だろと調べた所、StackOverflowにありました。

Calling remove in foreach loop in Java

結構評価あるのでiterator使うのが良いみたい。

以下はブログ用に簡単なコードにしてみました。

まずは普通に成功するパターン。

package arrayloopremove;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class ArrayLoopRemove {

    public static void main(String[] args) {
        List<String> meiboList = new ArrayList<>();
        meiboList.add("堀北真希");
        meiboList.add("能年玲奈");
        meiboList.add("宮崎あおい");
        
        System.out.println("remove前 -> " + meiboList);

        Iterator<String> i = meiboList.iterator();
        while(i.hasNext()){
            String name = i.next();
            //接頭辞が「堀北」以外は除外
            if(!name.startsWith("堀北")){
                i.remove();
            }
        }
        
        System.out.println("remove後 -> " + meiboList);
    }
}

実行結果
remove前 -> [堀北真希, 能年玲奈, 宮崎あおい]
remove後 -> [堀北真希]

これを以下のように書いてました(^^;
最初のリスト定義が違うだけで、それ以降は上記と同じコードです。

package arrayloopremove;

import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

public class ArrayLoopRemove {

    public static void main(String[] args) {
        //名簿リストを配列から生成しただけ
        List<String> meiboList = Arrays.asList("堀北真希", "能年玲奈", "宮崎あおい");

        System.out.println("remove前 -> " + meiboList);

        Iterator<String> i = meiboList.iterator();
        while(i.hasNext()){
            String name = i.next();
            //接頭辞が「堀北」以外は除外
            if(!name.startsWith("堀北")){
                i.remove();
            }
        }
        
        System.out.println("remove後 -> " + meiboList);
    }
}

実行結果
remove前 -> [堀北真希, 能年玲奈, 宮崎あおい]
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.AbstractList.remove(AbstractList.java:161)
at java.util.AbstractList$Itr.remove(AbstractList.java:374)
at arrayloopremove.ArrayLoopRemove.main(ArrayLoopRemove.java:39)
Java Result: 1

えー、なんでダメなの?なぞだー、とハマってた(^^;
原因は最初にあげた参考元の以下ブログに書いてあります。
悪あがきプログラマー - String配列から指定要素を削除する。

で、以下ならいける。地味にハマったなぁ。

package arrayloopremove;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

public class ArrayLoopRemove {

    public static void main(String[] args) {
        List<String> meiboList = new ArrayList<>();
        meiboList.addAll(Arrays.asList("堀北真希", "能年玲奈", "宮崎あおい"));
        
        System.out.println("remove前 -> " + meiboList);
        
        Iterator<String> i = meiboList.iterator();
        while(i.hasNext()){
            String name = i.next();
            //接頭辞が「堀北」以外は除外
            if(!name.startsWith("堀北")){
                i.remove();
            }
        }
        
        System.out.println("remove後 -> " + meiboList);
    }
}

JavaFXでYouTubeのダウンローダ的なサンプルを作ってみる ~動画の自動再生と履歴ページ遷移~

ブログと関係ないですが、昨日から堀北真希さん主演ドラマ「ミス・パイロット」が始まりました(^^)/システム屋らしく緊急対応で観れないっていう残念な事態になりましたが…とほほ(-_-;

まあ、録画したので、後日楽しみます。フジテレビの公式サイトはこちら↓
http://www.fujitv.co.jp/misspilot/index.html

……

宣伝はさておき、今日は先日サンプルで作ったJavaFXのYouTubeダウンローダ的なサンプルを少し改造しました。作ったときのブログはこちら↓
JavaFXでYouTubeのダウンローダ的なサンプルを作ってみる

すごいショボイですが、以下2つトライしました。

  • ダウンロードが終わったら動画を自動再生する
  • サイトの履歴を表示して、選択した履歴を表示できるようにする

ダウンロードが終わったら動画を自動再生する

本当は落としたファイルをJavaFXのMediaViewで観れるようにしてみよう!とか思ったのですが、SceneBuilderにMediaViewがない(^^;そういうものなのかな。

あと、YouTubeで落とした動画もWEBM形式というのに(最近?)なっているので、MediaViewが使えても再生できるかわからなかったので、とりあえずベタにChromeのexeを叩いて実行する、という方法でやりました。

Javaからexe叩く方法は以下サイトを参考にさせて頂きました。
ひしだまさんのサイト 外部プロセス起動

実行結果はこんな感じ。

起動するとYouTubeページを表示

f:id:kikutaro777:20131016192734j:plain

せっかくなので「ミスパイロット」で検索して

f:id:kikutaro777:20131016192822j:plain

適当な動画を選びます。
ジャケット着る姿が超りりしい (*´Д`)ハァハァ

f:id:kikutaro777:20131016192846j:plain

ダウンロードボタンを押すと、前回と同様に動画のダウンロードされます。

f:id:kikutaro777:20131016192947j:plain

で、ダウンロード完了と同時にChromeが起動して自動再生します。
二度目の (*´Д`)ハァハァ。

f:id:kikutaro777:20131016193010j:plain

こんだけ(^^;

履歴ページ遷移

画面にコンボボックスを設けてページ遷移の履歴を一覧表示するようにしました。

適当に色々たどった状態でコンボボックスを開くと

f:id:kikutaro777:20131016193204j:plain

以下のような感じで履歴が出ます。

f:id:kikutaro777:20131016193230j:plain

横が長すぎて不格好(^^;
今はWebEngineから取得できるHistoryのリストをそのままコンボボックスにぶっこむ雑な処理をしてるためです。
HistoryのEntryクラスを継承してtoStringをオーバーライドすればいいのかなと思ったら、Entryクラスがfinalでした;ここら辺はもう少し綺麗にしたいところ。

で、とりあえず選択イベントで履歴URLのページへ遷移するようになってます。

f:id:kikutaro777:20131016193843j:plain

コード

前回のをベースに以下のような感じです。

Chromeの実行はProcessBuilderでexeファイルを叩いてるだけ(^^;
履歴もWebEngineのHistoryにListChangeListenerをつけて履歴が変わるタイミングでコンボボックスの中身を入れ替えてるだけです。

package maki.makimakidownloader;

import com.github.axet.vget.VGet;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.collections.ListChangeListener;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ComboBox;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebHistory.Entry;
import javafx.scene.web.WebView;

public class MakiMakiDownloaderController implements Initializable {

    private static final String DL_DIR = "D:\\movie\\horikita";
    
    private static final String CHROME_EXE = "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe";
    
    @FXML
    private WebView webView;
    
    @FXML
    private ComboBox historyComboBox;
    
    private WebEngine webEngine;
    
    /**
     * ダウンロードボタン押下時のイベント.
     * 
     * 動画をダウンロードして、Chromeでビューする。
     * 
     * @param event 
     */
    @FXML
    private void handleBtnDownloadAction(ActionEvent event) {     
        try {
            //動画のダウンロード
            URL downloadUrl = new URL(webEngine.getLocation());
            VGet vget = new VGet(downloadUrl, new File(DL_DIR));
            vget.download();

            //ダウンロードしたファイル(webm形式)をChromeで実行する
            ProcessBuilder processBuilder 
                    = new ProcessBuilder(CHROME_EXE, "\"" + vget.getTarget().getAbsoluteFile() +"\"");
            Process process = processBuilder.start();
            
            //実行結果の判定
            int ret = process.waitFor();
            if(ret == 0){
                System.out.println("正常終了しました。");
            }else{
                System.out.println("異常終了しました。コードは" + ret);
            }
        } catch (IOException | InterruptedException ex) {
            System.out.println(ex.getMessage());
        }
    }
    
    /**
     * コンボボックス選択時のイベント.
     * 
     * 選択された履歴のURLに遷移する。
     * 
     * @param event 
     */
    public void selectHistoryComboBox(ActionEvent event){
        if(historyComboBox.getValue() instanceof Entry){
            Entry selectedEntry = (Entry) historyComboBox.getValue();
            webEngine.load(selectedEntry.getUrl());
        }
    }
    
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        webEngine = webView.getEngine();
        
        //YouTubeのサイトを表示
        webEngine.load("http://www.youtube.com/?gl=JP&hl=ja");
        
        //サイト履歴が変わる度にコンボボックスの値を更新する
        webEngine.getHistory().getEntries().addListener(new ListChangeListener<Entry>(){

            @Override
            public void onChanged(ListChangeListener.Change<? extends Entry> change) {
                change.next();
                historyComboBox.getItems().clear();
                historyComboBox.getItems().addAll(webEngine.getHistory().getEntries());
            }
            
        });
    }
}

JavaFXおもしろいなぁ。

JavaFXでYouTubeのダウンローダ的なサンプルを作ってみる

今や便利なダウンロードツールが色々あるので、作る意味はあまりないのですが、JavaYouTube動画とか取るには…と探したらライブラリがあったので、JavaFXと合わせてみました(^^;

注意
ちなみにYouTubeの動画をダウンロードすること自体、本来は(自分の著作物を上げた場合以外は)いけないことですね;利用規約はこちら。「5. お客様によるサイト上のコンテンツの使用」の部分です。
http://www.youtube.com/static?template=terms&hl=ja&gl=JP

その他の参考
http://ihoudownload.chosakuken-kouza.com/q/q2.html

というわけで、今回のブログ、不適切だったら後で削除するかも…です。

ちなみにJavaYouTubeをダウンロードする、で調べたら海外にわんさか(^^;
自分が参考にしたのは

How to download videos from youtube on java?

でした。で、回答の1つに「vget」なるライブラリがあって簡単そうだったので使ってみました。

https://github.com/axet/vget

このライブラリの内部では他のライブラリを使っているようで、Maven使うのが楽そうです。

で、NetBeans7.3.1を使っていたのですが、MavenのメニューにJavaFXがない!とつぶやいたら@sk44_さんと@aoetkさんからNetBeans7.4から使えます、と教えて頂きました。
というわけで7.4RC1入れていたので(今はもうRC2出てますが)やってみたところ

f:id:kikutaro777:20131014234914j:plain

あった!やったー(^^)/

ということで、MavenJavaFXプロジェクト作りました。

このvgetというライブラリ、URLがわかればダウンロードできるので、JavaFXのWebView使ってURLを取るようにしただけの雑なサンプルです(^^;

起動するとYouTubeのトップを表示するようにして、検索して目的の動画へ。
自分の著作物であげたものがないので…一時的に堀北さんのCMを試してみました。

f:id:kikutaro777:20131014233457j:plain

ダウンロードボタンを押してしばらくするとwebm形式のファイルを取得。

f:id:kikutaro777:20131014234132j:plain

実行するとこんな感じ!取れてる!

f:id:kikutaro777:20131014234103j:plain

コードは超適当ですが、こんなんで動いてます。
ちなみにViewのFXMLはWebViewとVBox、Buttonだけです。

package maki.makimakidownloader;

import com.github.axet.vget.VGet;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;

public class MakiMakiDownloaderController implements Initializable {
    
    @FXML
    private WebView webView;
    
    private WebEngine webEngine;
    
    @FXML
    private void handleBtnDownloadAction(ActionEvent event) {
        try {
            URL downloadUrl = new URL(webEngine.getLocation());
            VGet vget = new VGet(downloadUrl, new File("D:\\movie\\horikita"));
            vget.download();
        } catch (MalformedURLException ex) {
            System.out.println(ex.getMessage());
        }
    }
    
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        webEngine = webView.getEngine();
        webEngine.load("http://www.youtube.com/?gl=JP&hl=ja");
    }    
}

真面目に作るなら欲しい機能として

  • ダウンロード中はプログレスバーを表示
  • 落とせない形式(があるっぽい)の場合にはメッセージダイアログを表示
  • 非同期で複数ダウンロードできるようにする

などなど(^^;他にもあるよなぁ。

先日のマキマキビューアも途中だけど、これも真面目に作ってみようかな。って個人で楽しむためのツールですが。

てか、最近JavaFXネタが増えつつある(^^;

Java EEは仕事でガッツリ開発入って今まで使ってないようなものを触らないと中々書くことがない今日この頃。もっとガッツリ開発したいなぁ。

JDOM2でXMLファイルを出力してみる

以下のようなちょっとしたXMLJavaで出力したかったのですが

<?xml version="1.0" encoding="UTF-8"?>
<Product>
  <Option Id="Opt">
    <Name>
      <JPN>オプション品</JPN>
      <ENG>Option Item</ENG>
    </Name>
  </Option>
  <!-- Optionタグの繰り返し -->
</Product>

Java XML 出力」とか調べると色々方法がありそうで、どれがいいのやら…と(^^;

後日@kazuhira_rさんがまとめて下さってました!参考になりますm(_ _)m
JavaXMLを書き出す
http://d.hatena.ne.jp/Kazuhira/20130905/1378394482

とりあえず出力するだけで読み込んで解析するようなものではないので、以下サイトの2つを見比べて、試しにJDOMなるものを使ってみました。

JDOMサイト

http://www.jdom.org/

今はJDOM2.x系が最新のようです。

pom.xml

MavenのセントラルリポジトリにJDOM2があるので、以下定義。

<dependency>
    <groupId>org.jdom</groupId>
    <artifactId>jdom2</artifactId>
    <version>2.0.5</version>
</dependency>
コード
package jp.co.hoge.xmlexample;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jdom2.Attribute;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;

public class App 
{
    public static void main( String[] args )
    {
        try {
            new App().createByJdom();
        } catch (IOException ex) {
            Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    public void createByJdom() throws IOException{
        //商品
        Element product = new Element("Product");
        Document document = new Document(product);
        
        //オプション品いくつか並べる
        for(int i = 0; i < 5; i++){
            Element option = new Element("Option");
            option.setAttribute(new Attribute("Id", "Opt" + i));
            document.getRootElement().addContent(option);
            
            Element name = new Element("Name");
            option.addContent(name);
            
            Element jpn = new Element("JPN");
            jpn.setText("オプション品" + i);
            name.addContent(jpn);
            
            Element eng = new Element("ENG");
            eng.setText("Option Item" + i);
            name.addContent(eng);
        }
        
        XMLOutputter xmlOut = new XMLOutputter(Format.getPrettyFormat());
        xmlOut.output(document, Files.newOutputStream(Paths.get("c:\\temp\\product.xml"), StandardOpenOption.CREATE_NEW));
    }
}

DOM Parserで書くより少し簡単に書ける、という感じなのかな。
他にどんなメリットがあるのか(性能とか)、もう少し要調査。
ってか日本語の情報も少ないので、あんまり使われない感じなのかな。。。

未だJavaで何かを書くときに、素で書くのがいいのか、ライブラリ使うのがいいのか、使うなら何がいいのか?の調査に時間かかってる…(-_-;

JavaOne2013参加予定メモ

ひょんなきっかけからJavaOne2013に行く機会を得ることができました(^^;

Javaを触り始めて約1年、国内の勉強会に参加しても、まだまだ知らないこと、理解できていないことがたくさんあるのに、JavaOneなんて超ビッグイベント…自分みたいな素人が参加していいのか!と思いながら…。

もちろん単にJavaOne目的だけでは行けるはずもなく、ちょうど海外出張で米パートナー企業の挨拶訪問があるので、その帰りがけにサンフランシスコへ寄る形です。
残念ながらフル参加はとてもできないのですが22日,23日の2日間は終日参加する予定です。

英語が不安極まりないのですが…ボイスレコーダーとかも駆使しつつ、頑張って吸収したいと思います(^^)

今のところ、参加を申し込んでいるのは以下です(変わる可能性はあり)
Java EEを中心に、Java 8やNetBeans辺りのキーワードがメインです。

22日(Sun)

[UGF10329] Introduction to Java 7 and 8: JVM, Language, and Platform

[UGF10366] Fifteen Years of the NetBeans IDE

[UGF10520] The Good Parts
→[UGF10336] NetBeans Power Tools with James and Kirk
James Goslingさんが講演されるようなので、こっちに変更(^^;ミーハー

[KEY11050] Java Strategy and Technical Keynotes

[UGF10388] NetBeans Community Tools with JRebel, Jelastic, and More

[KEY11026] Oracle Welcome Keynote

23日(Mon)

[CON3638] 10 Tips for Java EE 7 with PrimeFaces

[CON3298] JSF for Multitenant-Enabled Applications

[CON3733] Expression Language 3.0

[CON8001] Case Studies in Testable Java EE Development

[CON4456] Coding Java EE 7: Making Easy Even Easier

[BOF3473] The NetBeans Roadmap for Cutting-Edge Tooling for Cutting-Edge Java

[BOF7807] Best Practices for Interoperable XML/XML Schema Data Binding with JAXB

[BOF4255] Ten Things You Should Know When Writing Good Unit Test Cases in Java

[BOF5290] Play with Vaadin

[BOF4040] NetBeans Platform BOF

23日(Tue)

[CON3294] JSF 2.2 New Features in Context
※飛行機に間に合えば参加

既に緊張気味(^^;

にほんブログ村 IT技術ブログへ
にほんブログ村 にほんブログ村 IT技術ブログ Javaへ
にほんブログ村