Bash on Windows上のファイルをうっかりWindows側でいじってしまったときの対処

Windows10 になってから Linux サブシステムが搭載され、Windows 上で Bash on Ubuntu が動かせるようになりました。Windows 上で仮想環境ではない生の Linux 環境と Bash シェルが使えるようになってとっても嬉しいですね。
この Bash on Ubuntu on Windows を利用する上での注意点として Linux サブシステム上のファイルを Windows 側のアプリからいじってはいけない というものがあります。Linux 側のファイルのメタデータ情報は NTFS の拡張属性に保存していますが、Windows 側のアプリケーションでこのファイルを操作すると拡張属性に入っている情報を消してしまう可能性があるためです。
ですが、先日実際にそれをやらかしてしまい、ファイルシステムがおかしくなってしまって焦りました。何とか復帰できたので備忘録的にまとめておきました。

まず Bash on Ubuntu 上でファイルを作ってみます。 f:id:aoe-tk:20170921235906p:plain

このファイルをうっかり Windows 側のツールで開いて修正、保存しちゃいます。 f:id:aoe-tk:20170921235924p:plain f:id:aoe-tk:20170921235943p:plain

これをもう一度 Bash 側で見てみます。 f:id:aoe-tk:20170922000003p:plain

あれ、タイムスタンプもファイルサイズも変わっていない (ファイルが消えてしまう場合もあります) 。 Ubuntu 上の Vim で開いてみると Windows 側で追加した文字列が反映されていません。 f:id:aoe-tk:20170922000123p:plain

しかも書き換えようとしても保存に失敗します! f:id:aoe-tk:20170922000142p:plain

じゃあファイルを消して作り直そうと思ったら、ファイルを消したはずなのに「入力/出力エラーです」と出て、消したはずのファイルを作ることもできません! f:id:aoe-tk:20170922000206p:plain

実際にこの現象が起きたときはかなり焦りました。以下に対処方を示していきますね。

Windows の Explorer でファイルの状態を確認します。ただし、Linux サブシステムのファイルは「保護されたオペレーティングシステムファイル」に当たるため、デフォルトでは Explorer から見えないようになっています。Explorer の設定を変更し、「保護されたオペレーティングシステムファイルを表示しない」のチェックを外します。 f:id:aoe-tk:20170922000234p:plain

Linux サブシステムのファイルシステム%LOCALAPPDATA%\lxss 以下にあります。 f:id:aoe-tk:20170922000249p:plain

Explorer で問題となったファイルのあるパスを確認すると、消したはずのファイルが残っていることが分かります。これを Explorer 上で削除します。 f:id:aoe-tk:20170922000304p:plain

これで再び Ubuntu 上でファイルを作成できるようになります。やれやれ。 f:id:aoe-tk:20170922000334p:plain

復旧したら Explorer の設定は元に戻しておきましょう。またうっかり触ってしまわないように。

とまあこんな感じで直すことができました。このように色々おかしなことになるので、Windows 側のアプリから Linux サブシステム上のファイルをいじってしまわないように注意しましょう (逆は問題ありません) 。もうちょっと何とかならないかなあ。

getterやsetter以外のメソッドをJavaBeansのアクセッサにする

ネット上で、Java への dis として「なんで Java のプロパティアクセッサはわざわざ get/set で始まる名前のメソッドにしないといけないんだ!」というのをよく見かけます。ですが実は JavaBeans の仕様としてはいわゆる getter/setter でないメソッドもプロパティのアクセッサにすることができます。余りにも JavaBeans のことがボロクソに言われるのでかっとなって書きましたw

まずは以下の Java クラスを見てください。

/**
 * getter/setterを使わないJavaBeansの例.
 */
public class Test {
    private String わーい;

    public String すごーい() {
        return わーい;
    }

    public void たーのしー(String myProperty) {
        this.わーい = myProperty;
    }

    @Override
    public String toString() {
        return "Test{" +
                "わーい='" + わーい + '\'' +
                '}';
    }
}

いわゆる getter/setter がありませんね。このクラスを次のように Introspector に掛けてプロパティを抽出し、実行してみます。

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;

/**
 * Beanの利用例.
 */
public class JavaBeansSampleApp {
    public static void main(String[] args) {
        try {
            Test test = new Test();
            BeanInfo testBeanInfo = Introspector.getBeanInfo(test.getClass());
            PropertyDescriptor[] propertyDescriptors = testBeanInfo.getPropertyDescriptors();
            for (PropertyDescriptor pd : propertyDescriptors) {
                if ("わーい".equals(pd.getName())) {
                    System.out.println("わーいプロパティのsetter: " + pd.getWriteMethod());
                    System.out.println("わーいプロパティのgetter: " + pd.getReadMethod());
                    pd.getWriteMethod().invoke(test, "なにこれー?");
                }
            }
            System.out.println(test);
        } catch (IntrospectionException | InvocationTargetException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

結果は次のようになります。

わーいプロパティのsetter: public void aoetk.sample.Test.たーのしー(java.lang.String)
わーいプロパティのgetter: public java.lang.String aoetk.sample.Test.すごーい()
Test{わーい='なにこれー?'}

set で始まっていない たーのしー() メソッドが setter として認識され、get で始まっていない すごーい() メソッドが getter として認識されています。プロパティの writeMethod を実行するとちゃんと たーのしー() メソッドが実行されて値が設定されています。

からくりについて解説しましょう。次のように Bean に対応した BeanInfo 実装クラスを用意し、Bean と同じパッケージに置きます。以下の例では BeanInfo インターフェースのデフォルトメソッドを実装した SimpleBeanInfo クラスを継承し、必要なメソッドだけ実装しています。

/**
 * {@link Test}のJavaBeans情報.
 */
public class TestBeanInfo extends SimpleBeanInfo {
    @Override
    public PropertyDescriptor[] getPropertyDescriptors() {
        try {
            return new PropertyDescriptor[]{
                    new PropertyDescriptor("わーい", Test.class, "すごーい", "たーのしー")
            };
        } catch (IntrospectionException e) {
            return null;
        }
    }
}

ここでは getPropertyDescriptors() メソッドをオーバーライドし、 PropertyDescriptorインスタンスを返しています。もうお分かりですね。ここでこの JavaBean のプロパティの情報 (プロパティ名、アクセッサメソッド) を返しているわけです。

Introspector の API ドキュメント には次のような解説が記載されています。

Fooクラスについては、情報の問い合わせ時にnull以外の値を提供するFooBeanInfoクラスがあれば、明示的な情報を取得できます。まず、ターゲットのBeanクラスの完全指定されたパッケージ名に「BeanInfo」を付加して新規のクラス名とし、BeanInfoクラスを検索します。これに失敗した場合は、この完全指定されたパッケージ名の最後のクラス名にあたる部分を使って、BeanInfoパッケージ検索パスに指定されたパッケージごとに該当クラスを検索します。
(中略)
クラスの明示的なBeanInfoが見つからない場合は、低レベルのリフレクションを使ってクラスのメソッドを調べ、標準設計パターンを適用して、プロパティのアクセス用メソッド、イベント・ソース・メソッド、publicメソッドを識別します。
(以下略)

つまり、JavaBeans を作るとき、本来は対になる BeanInfo 実装クラスを用意し、Bean の情報を提供する必要があるのです。ですが、毎回それをやっては面倒なので、便宜的にあの命名規則が用意されているわけです。CoC の先駆けだったわけですね (ちなみに JavaBeans は 20 世紀に誕生した仕様です) 。

この BeanInfo ですが次のような情報を提供することができます。

  • プロパティの情報
  • イベントの情報
  • メソッドの情報
  • アイコン

アイコンとかイベントって何?と思いましたか。JavaBeans は本来可搬性のあるソフトウェアコンポーネント、特に GUI コンポーネントを開発するために作られた規格です。つまり、IDE の「ポトペタツール」に追加して使えるソフトウェア部品を作るためのものなのです。BeanInfo ではそのツールに対して提供する情報を定義します。

f:id:aoe-tk:20170426222842p:plain

こうして考えると、単なる DTO として JavaBeans を使うのはオーバースペックであることも分かりますね。なぜこんなにあちこちで JavaBeans が使われるようになったのかは歴史的な経緯が色々あるのですが、まあそれはまたの機会で。

なお、このエントリでやったいたずらは業務のコードではやらないでくださいね。いたずらに混乱を招くだけです。酒の席でのネタにとどめてくださいw

全体のコードは gist にアップしてあります。

https://gist.github.com/aoetk/e5a09f67f2ebbc206d0770b21116b69e

パーフェクトJava EEの感想

Java EE 7 に対応した解説本として出版されたパーフェクト Java EE を 著者のお一人である上妻 (id:n_agetsuma) さんから頂きました。ありがとうございます! 簡単ではありますが、本についての感想をまとめました。

gihyo.jp

実は本を頂いたのはもう半年前の夏のことだったのですが、色々と忙しい状況が続き、感想文の公開がこんなに遅くなってしまいました。ごめんなさい!

本の特色

この本の特色は、Java EE の Web Profile に内容を絞ったという思い切った点にあります。説明する対象を絞ることで、これまでの和書の Java EE 解説本よりも、各仕様の解説が深くなっており、多様な機能、意外と知られていない新機能などがしっかり網羅されています。ただ、そのために jBatch が対象から抜けちゃったのはちょっと残念だったかなと思っています。

また、著作メンバーが Oracle に近くない人で構成されているので、変にバイアスが掛かっていないというのも特色かなと思っています。いわゆる「よいしょ」的な内容が少なく、かなりぶっちゃけたことも書かれているので、実際に利用する人にとっても参考になるのではないでしょうか。

良かったと思った点

この本で特によかったと思ったのは次のような点です。

  • CDI についてガッツリ解説された初めての和書です。
    • Web 上の情報でもここまできっちり網羅された解説は (少なくとも日本語では) 見たことがありません。
    • この点だけでも買う価値があると言ってもいいと思っています。
  • 最新の JPA 仕様をきっちりカバーしています。
    • 新機能である Entity Graph もしっかり押さえられています。
    • JPA を利用するうえで必要とされる解説が一通り網羅されています。
  • Web Profile の範囲で EE6、7 で新たに追加された新機能をしっかりと押さえています。
    • 特に日本語で紹介される機会が少なかった非同期 ServletServlet のモジュール化、WebSocket、JPA Criteria API もきっちり解説されています。
    • 「こんなことできるかな?」を調べるためのリファレンスとして使えると思います。
  • JTA の解説がきちんとされているのも個人的にはポイント大でした。
  • そして、先行して EE8 の MVC も取り上げられている!と言いたかったところですが...嗚呼、あんなことになるなんて...。

イマイチだなと思った点

ちょっとここは良くなかったかなあと思った点も挙げておきます。

  • 読者の対象に初めて Java EE を使って Web アプリケーションを開発しようとしている人が入っていましたが、その割には開発環境構築の説明が不親切だと思いました。
    • やはり、IDE とセットでの環境構築の解説はすべきだと思います。
    • 記述内容も過去に古い J2EE での開発をしてきたことを前提としたところもありました。
  • 章立てが良くないと感じました。
    • いきなり CDI から入るのは違和感がありました。
    • 実際に作って試しながら進めてもらうには、やはりフロントから入っていくのが王道だと思います。
  • JSP は省略すべきではなかった!
    • 一応最後に付録で説明されていますが、ちょっとおざなりすぎかなと。その割には本文中で JSP を使っている箇所も多いですし。
    • ここは異論がある人も多いと思いますが、私は JSP はまだまだ重要だと思っています。JSP はまだまだ利用されている箇所が多く、情報を必要としている人は多くいるはずです。
    • JSP もバージョンアップごとに地味に機能追加がされています。そのような情報をカバーしていると喜ぶ人も多いんじゃないかなと思いました。

この本を読むべき人

以上、感じたことをつらつらと書きましたが、中々の良書だと思っています。特に次のような人にお勧めしたいですね。

  • これまで Java EE (J2EE) で開発してきたけど、最新の仕様にキャッチアップできていないなあと感じている人。
  • 現在 Java EE (J2EE) ベースのシステムを開発、保守しており、リファレンスを求めている人。
  • Spring Framework ベースのシステムを開発している人も読むべきです。Spring も何だかんだ言って EE を利用しており (特に ServletJPA) 、役に立つ記述は多いです。

Java 9で強化されたデスクトップ環境関連のAPIをJavaFXで使ってみる

このエントリは JavaFX Advent Calendar 2016 の 18 日目のエントリです。前日は id:nodamushi さんによる「 JavaFX9からPlatformに追加されるAPIについて 」でした。

はじめに

今回のエントリは JDK9 に新たに取り込まれる "JEP 272: Platform-Specific Desktop Features" を JavaFX から触ってみるというものです。

実は JDK9 では AWT/Swing/Java2D にかなり手が入ります。次のように多くの JEP が 9 には取り込まれます。

利用者に見えない内部的な強化や HiDPI 対応のような流石に対応しないとまずいものが中心ですが、その中でも JEP 272 はアプリケーション開発者側から見ても大きな機能追加になります。

まずはこの JEP 272 について紹介し、そしてこれが JavaFX からどの程度利用できるか調べてみた結果について述べていきたいと思います。

JEP 272 について

JEP 272 は "Platform-Specific Desktop Features" の名の通り、デスクトップ環境特有の機能を Java からも利用できるようにするというものです。それもプラットフォーム固有の機能も積極的に利用するというものです。

ご存じの通り Java のデスクトップ GUI アプリケーションでは、そのアプリケーションを実行するデスクトップ環境が提供している機能を利用することは中々難しかったりします。クロスプラットフォームアプリケーションの宿命かも知れません。

ですが、過去に Java 6 でそのための API が追加されたことがありました。

  • 特定のファイル・タイプに関連付けられたデフォルト・アプリケーションと対話する機能を提供する java.awt.Desktop クラス。
    • デスクトップ環境で設定されたデフォルトブラウザやエディタ、メーラなどを Java 側から起動することができます。
  • デスクトップ環境のシステムトレイにアクセスし、アプリケーション独自のトレイアイコン、メニューを追加できる java.awt.SystemTray クラス。

システムトレイを使ったりすると、よりネイティブアプリケーションっぽくなりますよね。ですが、その後の各 OS の進化に伴い、Java から使えないデスクトップ環境の機能がどんどん増えてきました。

例えば、Windows のタスクバー、Mac の Dock では次のようにプログレスバーを表示することができるようになっています。

f:id:aoe-tk:20161218003523p:plain:w1000 f:id:aoe-tk:20161218003543p:plain:w1000

バッジも表示できるようになっていますね。

f:id:aoe-tk:20161218003757p:plainf:id:aoe-tk:20161218003806p:plain:h94

でもこれらの機能には Java からアクセスすることができません。

また、Mac 特有の話ですが、Mac で実行するアプリケーションでは、メニューバーにアプリケーション名のメニューが通常のメニューの左に表示されます。アプリケーションの About ダイアログや環境設定ダイアログはここから開けるようにするよう Mac 上で動くアプリケーションは統一されています。でも、Mac 特有の話なので、Java アプリケーションはここにアクセスすることができません。

f:id:aoe-tk:20161218004452p:plain:w250

JEP 272 はこういったデスクトップ環境が提供する機能へ Java アプリケーションでもアクセスできるようにするものなのです。

提供されている機能を列挙します。

  • デスクトップ環境が起こすイベント (スリープ、サインアウト、フォアグラウンド/バックグラウンドの切り替えなど) に対してイベントリスナやイベントハンドラを登録する。
  • タスクバーへのアクセス。プログレス表示やバッジ表示、コンテキストメニューの追加を行える。
  • Mac 特有のアプリケーションメニューへのアクセス。

API レベルでは次のような追加になります。

  • java.awt.desktop パッケージの追加
    • デスクトップ環境で発生するイベントに対応した各種イベントクラスや、それに対するイベントリスナ、ハンドラが定義されている。
  • java.awt.Desktop クラスにメソッド追加
    • デスクストップ環境で発生する各種イベントに対して、イベントリスナの追加、ハンドラの登録を行うメソッドが追加されている。
  • java.awt.Taskbar クラスの新規追加
    • タスクバー (Mac での Dock) を操作するためのメソッドが定義されている。

この APIAWT の API です。でもこのエントリは JavaFX Advent Calendar のエントリです! なので、JavaFX からこれら機能を利用できるかを調べてみることにしましょう。

JavaFX から JEP 272 を利用する

それでは JavaFX から試してみることにします。ソースコードの全体は gist にアップしています。

https://gist.github.com/aoetk/7d5cc13e64239d1233e6dd879fed682e

Desktop クラスの利用

java.awt.Desktop クラスを使うと、デスクトップ環境で発生する様々なイベントに対して応答することができるようになります。まずはこのクラスのインスタンスを取得してみます。

if (Desktop.isDesktopSupported()) {
    Desktop desktop = Desktop.getDesktop();
    addAppEvents(desktop);
    setSystemMenuHandler(desktop);
} else {
    System.out.println("デスクトップはサポートされていません.");
}

実行している環境が Desktop クラスをサポートしているかを確認するメソッドがあるので、どの環境でも動かせるよう、必ずこれでチェックするようにしましょう。static メソッドである getDesktop() メソッドを使ってインスタンスを取得します。

デスクトップ環境で発生するイベントに対して応答できるようにしてみます。イベントが発生するとその旨を ListView に表示するようにします。スクリーンのスリープを例に取ると次のようになります。

// (中略)
@FXML
ListView<String> displayList;

private ObservableList<String> eventList = FXCollections.observableArrayList();
// (中略)

private void addAppEvents(Desktop desktop) {
    // (中略)
    if (desktop.isSupported(Desktop.Action.APP_EVENT_SCREEN_SLEEP)) {
        desktop.addAppEventListener(new ScreenSleepListener() {
            @Override
            public void screenAboutToSleep(ScreenSleepEvent screenSleepEvent) {
                addMessage("画面がスリープしようとしています.");
            }

            @Override
            public void screenAwoke(ScreenSleepEvent screenSleepEvent) {
                addMessage("画面がスリープから復帰しました.");
            }
        });
    } else {
        System.out.println("ScreenSleepEventはサポートされていません.");
    }
    // (中略)
}

// (中略)
private void addMessage(String msg) {
    Platform.runLater(() -> eventList.add(msg));
}

Desktop#addAppEventListner() メソッドを使って各種イベントリスナを登録します。画面スリープに対応するイベントは ScreenSleepEvent になります。イベント別にサポート有無をチェック可能なので、チェックするようにしましょう。

JavaFX からの利用に当たって注意点があります。それはイベントリスナの処理は AWT のイベントディスパッチスレッドで実行されるということです。このスレッドは JavaFX のアプリケーションスレッドとは別スレッドです。従って、 Platform.runLater() メソッドに処理をくるむ必要があります (addMessage() メソッドの実装に注目) 。

この他にも AppForegroundEvent (フォアグランド/バックグラウンドの変化に反応するイベント) 、 AppHiddenEvent (Mac 特有の「アプリケーションを隠す」に反応するイベント) 、SystemSleepEvent (システムのスリープに反応するイベント) 、 UserSessionEvent (ログインユーザのスイッチに反応するイベント) に対するリスナをセットして実行してみました。

Mac では全てのイベントに対応しています。アプリケーション起動後、「アプリケーションを隠して復帰 -> スクリーンをスリープして復帰 -> システムをスリープして復帰 -> ユーザスイッチをして復帰」を行った結果を示します。

f:id:aoe-tk:20161218020017p:plain:w532

バックグラウンドに回ったことを検知できるのはいいですね。そのタイミングで処理を停止してリソースの消費を防いだりするようなことができますね。

Windows 環境では残念ながら SystemSleepEventUserSessionEvent にしかサポートしていませんでした。システムをスリープ、復帰させた結果を示します。

f:id:aoe-tk:20161218020602p:plain:w301

Mac のアプリケーションメニューの利用

次に Mac のアプリケーションメニューにアクセスしています。これも Desktop クラスに対してハンドラを登録する形でカスタマイズします。まずは About メニューから。

if (desktop.isSupported(Desktop.Action.APP_ABOUT)) {
    // 現時点ではJavaFXでは何も起きない
    desktop.setAboutHandler(aboutEvent -> {
        Alert alert = new Alert(Alert.AlertType.INFORMATION);
        alert.setContentText("オリジナルのAboutダイアログです.");
        alert.setHeaderText("設定");
        alert.show();
    });
} else {
    System.out.println("Aboutメニューはサポートされていません.");
}

Desktop#setAboutHandler() メソッドを使い、About メニューがクリックされた時の応答処理を登録します。オリジナルのダイアログを出そうとしたのですが...JavaFX ではそもそも About メニューの追加がされませんでした。( ;∀;)

ちなみに Swing アプリケーションで試したときはうまく動作しました。

次に設定メニューです。こちらは Desktop#setPreferencesHandler() メソッドを使い、設定メニューがクリックされた時の応答処理を登録します。

if (desktop.isSupported(Desktop.Action.APP_PREFERENCES)) {
    // 現時点ではJavaFXではエラーが起きる
    desktop.setPreferencesHandler(preferencesEvent -> {
        Alert alert = new Alert(Alert.AlertType.INFORMATION);
        alert.setContentText("オリジナルの設定ダイアログです.");
        alert.setHeaderText("設定");
        alert.show();
    });
}

ですが、このコードを実行すると Cocoa 側から次のエラーメッセージが返ってきました...。

2016-12-17 21:21:08.978 java[1903:815004] *** -[__NSArrayM insertObject:atIndex:]: object cannot be nil
2016-12-17 21:21:08.984 java[1903:815004] (
    0   CoreFoundation                      0x00007fff88a2c452 __exceptionPreprocess + 178
    1   libobjc.A.dylib                     0x00007fff89405f7e objc_exception_throw + 48
    2   CoreFoundation                      0x00007fff88942a40 checkForCloseTag + 0
    3   AppKit                              0x00007fff8e19f8ce -[NSMenu insertItem:atIndex:] + 521
    4   libawt_lwawt.dylib                  0x00000001353c156f addMenuItem + 174
    5   libawt_lwawt.dylib                  0x00000001353c13f0 -[ApplicationDelegate _updatePreferencesMenu:enabled:] + 195
    6   JavaNativeFoundation                0x000000013536fd60 +[JNFRunLoop _performCopiedBlock:] + 17
(以下略)
)

AWT のフレームが生成されていることを前提に処理を進めているように推測されます。これはちょっと残念。なお、Swing で試したときはちゃんと動作しました。

というわけで、結論としては JavaFX では現状 Mac のアプリケーションメニューの利用はできないということになります。

Taskbar の利用

次にタスクバー (Dock) の利用を試してみることにします。バッジの表示とプログレス表示を試してみます。

if (Taskbar.isTaskbarSupported()) {
    Taskbar taskbar = Taskbar.getTaskbar();
    if (taskbar.isSupported(Taskbar.Feature.ICON_BADGE_NUMBER)) {
        taskbar.setIconBadge("10");
    } else {
        System.out.println("タスクバーのアイコンバッジへの数値登録はサポートされていません.");
    }
    addAction(taskbar);
} else {
    System.out.println("タスクバーはサポートされていません.");
}

タスクバーへのアクセスは Taskbar クラスを通して行います。インスタンスは static メソッドである Taskbar.getTaskbar() メソッドを使って取得します。

アイコンバッジのセットには Taskbar#setIconBadge() メソッドを使います。Mac 環境で試すと次のようにバッジの表示に成功しました!

f:id:aoe-tk:20161218174009p:plain:w423

Windows 環境は Taskbar クラスの利用そのものは可能だったものの、アイコンバッジの設定はサポートされていませんでした。まあ、Windows でのタスクバーアイコンへのバッジ登録が可能になったのは Anniversary Update からですしね。

次にプログレス表示を試してみます。次のように、JavaFX アプリ側のプログレス表示と、タスクバー側のプログレス表示を同時に行うようにしてみました。 AnimationTimer を使って表示しています。

AnimationTimer timer = new AnimationTimer() {
    private long startTime;

    @Override
    public void handle(long currentTime) {
        long elapsedTime = currentTime - startTime;
        if (elapsedTime > PROGRESS_TIME) {
            stop();
            progress.setProgress(1.0);
            startButton.setDisable(false);
        } else {
            double rateForProgressBar = Long.valueOf(elapsedTime).doubleValue() / PROGRESS_TIME;
            progress.setProgress(rateForProgressBar);
            int rateForTaskBar = (int) (rateForProgressBar * 100);
            if (taskbar.isSupported(Taskbar.Feature.PROGRESS_VALUE)) {
                taskbar.setProgressValue(rateForTaskBar);
            }
        }
    }

    @Override
    public void start() {
        startTime = System.nanoTime();
        progress.setProgress(0);
        if (taskbar.isSupported(Taskbar.Feature.PROGRESS_VALUE)) {
            taskbar.setProgressValue(0);
        } else {
            System.out.println("タスクバーのプログレス表示はサポートされていません.");
        }
        super.start();
    }
};

タスクバーのプログレス表示は Taskbar#setProgressValue() メソッドを使います。0 から 100 の間の数値をセットします。JavaFXプログレスバーは 0 から 1 と違うんですよね...。

Mac で試したところ、次のように Dock 側に進捗を表示できるようになりました!

f:id:aoe-tk:20161218175830g:plain

Windows は残念ながら未サポートでした。何でや、Windows7 の時からサポートしてたのに!

まとめ

というわけで JEP 272 の機能を JavaFX で試してみました。分かったことをまとめると次の通りです。

  • JavaFX からも JEP 272 の機能は一部を除き利用可能。
    • ただし、イベントリスナの処理は AWT のスレッドで実行される点に注意。
  • Mac のアプリケーションメニューにアクセスする機能は JavaFX からは使えない。
  • フル機能が使えるのは Mac だけ。Windows では一部の機能しかサポートしていない。
    • Linux では Ubuntu の Unity 環境でのみ使えるようです。今回は時間がなくて試せませんでした。

Mac から優先して実装されているのは理由があります。かつて Mac 環境向けの JavaApple 自身が開発、提供しており、こういた Mac 環境特有の機能にアクセスするために EAWT という API を提供していました。

Java 7 以降、Mac 向けの Java は OpenJDK で開発されるようになりますが、この EAWT は 7、8 にはバンドルが続いていました。ですが 9 からは提供をやめることになり、代替機能を Java 側で用意することになりました。それがこの JEP 272 であるということです。

ともあれ、よりネイティブアプリケーションっぽく振る舞えるような機能が実装されたのは嬉しいことです。今後のアップデートで Mac 以外の環境向けにも実装が進んでいくことでしょう。JavaFX 向けには 10 から同等機能の実装が予定されていますが、前倒しで実装とかされないかなあ。 *1

明日は誕生日枠の id:yumix_h さんの予定です。

*1:8 の時も u40 でかなりの機能追加が入ったことがあったので

Lavie Direct HZを購入しました

携帯の PC 端末として新たに NECLavie Direct HZ を購入しました。

それまで携帯 PC 端末として使っていたのは 2 年半前に購入した VAIO Tap 11 です。それが次のような理由で色々辛くなってきたので、新しい端末を探していました。

  • 軽量、高解像度で、スペック的にはまずまず満足していたが、肝心の品質が悪かった。
    • 電源を入れても起動しないトラブルが頻発 (マザーボード交換やファームウェアアップデートを繰り返すことで多少改善はした) 。
      • 勉強会とかに持っていっても、電源を入れても立ち上がらずに何度困ったことか...。
      • 他にも電源周りのトラブルも多く、キーボードの蓋をしてもスリープにならないことがあった。
    • 使用中にフリーズや BSOD もしばしば発生。
  • 無線通信する分離式のキーボードは打鍵の取りこぼしが多く、ラップトップと比べるとやはり辛い。
    • トラックパッドの操作性が非常に悪かったのもフラストレーションが溜まった。
  • やはり 2 in 1 という形態は中途半端だった。
    • 大は小を兼ねるというか、PC があれば基本的にタブレットがなくても問題ない場面が多い。
    • 携帯電話の方がファブレット化が進み、十分にタブレット的な役目を果たせるようになった。

そんな折、NEC のオンラインショップで 1 年前のハイエンドモデルがアウトレットで安く売られていたのをたまたま見掛けたので、やや衝動的にポチってしまいました。

この機種は「世界一軽量なノート PC」が売りのシリーズで、その中でも一番ハイエンドのモデルであったので、昨年の製品とは言え、次のように中々優れたスペックです。

  • Core i7
  • ディスプレイは 13 インチで解像度は 2560 x 1440 の高精細液晶
    • 映り込みのないノングレア。
    • Retina MBP 13 インチと同じ解像度です。
  • メモリ 8GB
  • ストレージ 512GB
    • 薄型ラップトップでストレージ 512GB となると極端に値段が上がるものが多いので、これはお得でした。
  • 重量なんと 779g!

とにかく軽いです。次の写真のように片手で楽々持てちゃいます。これに比べると MBA ですらもズシリと感じるようになります。

f:id:aoe-tk:20161015175617j:plain

以下、ちょっと触ってみた感想をば。

  • 良かった点
    • とにかく軽いので鞄に入れても全く苦にならず、どこにでも持っていきたいと思えます。
    • ディスプレイが非常に高精細で素晴らしい。最近の携帯電話と同様、全くドットが見えないレベルです。
      • あの MS ゴシックフォントも印刷した場合と同じようなレベルで滑らかに見えます *1
      • デフォルトではスケーリングが 200% に設定されていますが、これでは 98dpi 換算で 1280 x 720 相当と、作業領域として少し手狭です。自分は 175% に設定しました。少し字が小さくてもいいという人は 150% でもいいかもしれません。
    • ストレージ 512GB は安心感があります。
    • メーカー製 PC にしては初期インストールされているアプリが少ないです。
    • Windows PC はトラックパッドが小さいものが多いのですが、この機種は大きめで使い易いです。
    • 薄型端末にしてはインターフェースがしっかり揃っており、USB が 2 つの他に HDMI ポート、SD カードスロットもちゃんとあります。
  • イマイチな点
    • 軽量化のため、素材はプラスチッキーで質感としてはどうしても劣ります。
      • 「ぺらぺらした ThinkPad」といった感じでしょうか *2
    • キーボードの打鍵感は最低ラインはクリアしているというレベル。素材についてもしばらく使っていると表面がツルテカになりそう。
    • トラックパッドは MacBook のようにパッドとボタンが一体化したタイプですが、パッドの押し込みがちょっと固いです。
      • この部分については MacBook を超えるものを見たことが無いですねえ。

とまあこんな感じです。もし同じような機種を買おうと思っている人がいたらご参考に。とりあえず外出時のお供として 3 年くらいこれで戦えそうです。

*1:もっともそれでも美しいフォントではないですけど...

*2:今の NEC PC は Lenovo の傘下に入っていることも影響しているんですかね

JJUG CCC 2016 Springに参加しての感想

2016/05/21 に開催された JJUG CCC 2016 Spring に参加してきました。ちょっと遅くなりましたが参加した各セッションについて感想を簡単にまとめました。

参加したセッション

基調講演2: Raspberry Pi with Java

Java エバンジェリストである Stephen Chin さんによるキーノートセッション。Stephen さんは Night Hacking Tour というのを行っていて、世界の色んな国をバイクで駆け巡り、Java を使った面白い勉強会を行っていますが、今回日本でそれを行っています。既に岡山や大阪などを回っていますが、今回この JJUG CCC で東京版を行うことになったというものでした。

内容は Raspberry Pi を使って、ファミコンのゲームコンソール (筐体の形はゲームボーイアドバンス風) を作るというもの。ソフトウェア、ハードウェアの両面から様々なハッキングを行ったという内容でとても楽しい内容でした。

ソフトウェア面では Raspberry Pi 上の JavaJavaNES エミュレータ halfnes を使用した点が目を引きました。オリジナルは Swing 製でデスクトップ向けでしたが、これを Raspberry Pi 向けに GUI 部分を JavaFX で作り直したとのこと! X を使わず直接フレームバッファに書き込む JavaFX の利点をアピールしていました。 *1

ボタンの数に対する GPIO の不足を左・右ボタンは同時に押さない点に着目して回避したり、3D プリンタでのヒンジの作成で様々な試行錯誤したりなど、ハードウェア面でのハックの話も面白かったです。

こう言っちゃあれかもしれませんが、Oracle にもまだこういう遊び心たっぷりな方がエバンジェリストとして残っていて良かったなあと思いました。

E-3 Spring Boot で Boot した後に作る Web アプリケーション基盤

エムスリーの吉田さんによる、Spring Boot で構築した Web アプリケーション開発について、開発環境を構築した後の開発方針についてどうしていったかについてのお話でした。

Spring Boot では開発環境構築のお膳立てをしてくれますが、その後は Spring Framework を用いたアプリケーション開発になっていきます。そこで例外処理やトランザクション設計、URL 設計、バッチ処理、設定ファイル、ログ、セキュリティといった、共通的に考慮しないといけないことをどう設計したかを説明してもらいました。

バッチ設計のところなど、所々自分の考えとは違うところはあったものの、参考になる情報が多かったです。実は近々自分も Spring Framework を久々に使うことになりそうなので、Spring については浦島状態になっている自分にはとても助かる内容でした。

AB-4 Introduction to JShell: The Java REPL Tool

Kulla プロジェクトのコミッタになった bitter_fox さん自身による JShell の解説です。今年から就活する点をちょっとアピールしてましたw

JShell でやれることを全体的にとても分かり易く説明していました。他の言語では大体あったものですが、ようやく Java にも来てくれて嬉しいです。今まで自分自身は IntelliJ の Groovy コンソールを使ってこの用途を満たしていましたが。 *2

少し驚いたのが、JShell の開発者に JavaFX Script コンパイラの作者が入っていた点です。JavaFX Script が無くなった後、こういうことをしていたのかあ。

I-5 JavaデスクトッププログラムをふつーのWindowsプログラムのように配布・実行する方法とPCの動きが重くならないよう気を付けること

高橋さんによる、Windows 環境へ javapackager を用いてパッケージングした JavaFX アプリケーションを配布する際に工夫したことを説明するというセッションです。

このセッションで取り上げられていた javapackager については手前味噌ながら自分のブログエントリでも紹介しています。

aoe-tk.hatenablog.com

この javapackager、中々良くできているのですが、上書きインストールができない、インストールディレクトリの指定をさせることができない、など細かい点で足りないところが目に付きます。そこを Wix Toolset 側の設定に手を入れることで乗り切ったという話がとても参考になりました。

javapackager の存在については驚いた人が多かったようで、セッションの最後に沢山質問が出てきたのが印象的でした。やはりこういうものを求めていた人が多かったんでしょうねえ。*3 その割に知られていないというのが残念です。もっと Oracle はこのツールの存在をアピールした方がいいですよー。

M-6_1 十徳ナイフとしてのGradle

grimrose さんによる Gradle についてのショートセッションです。何と立ち見状態になっていて、床にべたっと座って聞く形になっちゃいました。Gradle 本当に注目を浴びてますねえ。

https://nbviewer.jupyter.org/github/grimrose/JJUG-CCC-2016-Spring/tree/master/Gradle%20as%20Army%20Knife.ipynb

内容としては Gradle 徹底入門を補完するような内容になっていて、Gradle のタスクランナーとしての側面に着目し、日常のタスク処理に Gradle を活用するためのお話になっていました。特にスクリプト実行環境があまり強力ではない Windows 環境での活用を推してましたねえ。

ホットな話題である、Kotlin Gradle についても少し触れましたが、「うーん、これ嬉しいですか?」と聞いたところで場が爆笑で包まれたのが印象的でした。 *4

I-6_2 OpenJDK コミュニティに参加してみよう

OpenJDK のコミッタである久保田さんによる、OpenJDK コミュニティに参加するための最初の一歩について説明するというセッションでした。

OpenJDK のような巨大なプロジェクトになると、参加するのはとても敷居が高い印象がありますが、やはりパッチを送るのが一番良いとのことでした。ML へパッチを送るくらいならば、OCA にサインすればできるようになるようです。

多数あるリポジトリの歩き方、パッチや意見の送り先となる ML の雰囲気など、OpenJDK プロジェクトに参加されている方ならではの話が満載でとても面白かったです。

GH-7 Java Puzzlers

最後はさくらばさん、てらださんのコンビによる、Java Puzzlers のセッションでした。

Java Puzzlers と言えば、Joshua Bloch さんと Neal Gafter さんによる JavaOne の名物セッションでしたが、今や前者は Google 、後者は Microsoft に籍を移しているため *5 、行われなくなっちゃいました。

日本版はさくらばさんとてらださんコンビになりましたが、意図的なのか自然にそうなったのか、てらださんがボケ、さくらばさんがツッコミというスタイルでの進行になっていましたw

内容としては基本的な演算子やクラス、Java8 で加わったラムダ式のコーナーケースについて問うものでした。選択肢式だったこともあり、間違った理解で回答したものもいくつかあったのですが、終わってみたら全問正解は私一人という結果になっちゃいました。(^^ゞ

全問正解ということで、さくらばさん作「Java SE 7/8 速攻入門」を頂いちゃいました。ありがとうございました。

最後に

こういう技術者が集まる場に参加するのは恐らく昨年の CCC Spring 以来だったと思いますが、やはり他のエンジニアの方々と交流すると色々な刺激が得られていいですね。

非常に規模が大きくなって驚いたのですが、これを運営するのも大変だったと思います。JJUG 運営の皆様、本当にご苦労様でした。

*1:セッションの後の休憩時間で harfnes のソースも覗いてみましたが、色々興味深かったです。

*2:自分の周囲を見ていると、Java で REPL 使いたい、というときは Groovy 使う派と Scala 使う派に分かれているように見受けられます。

*3:このセッションの影響か、私の javapackager についてのブログエントリへもアクセス、ブックマークが増えているような。

*4:でも、今後 Gradle は Kotlin ファーストで行くらしいですね。

*5:特に前者が効いとりますな (^^;;

JavaFX Maven PluginのWebサイトが復活して便利になっていた

JavaFXMaven で開発する際に便利なプラグインとして JavaFX Maven Plugin というものがあります。これは javapackager を使ったビルド、パッケージング作業を Maven 経由で実行できるようにするプラグインです。

蓮沼さんの以下のブログエントリでも紹介されています。

www.coppermine.jp

NetBeans にも JavaFX 開発向けの Maven プロジェクトを作成するためのウィザードがあるのですが、こちらは Exec Maven Plugin を使って javapackager のコマンド実行をラップしただけのものです。パッケージングについても、依存ライブラリの JAR を全て解凍してから 1 つの JAR にパッケージングするようになっており、今ひとつという印象です。

この JavaFX Maven Plugin ですが、ドメインを維持することができなくなったのか、ドキュメントを載せていた Web サイトが途中で消滅してしまいました。 GitHub リポジトリの README でも Web Archive の方 にリンクが貼られているという状態ですw

ところが最近になって github.io 上に新たに Web サイトが作られるようになり、中々便利な作りになっていました。 (GitHub のコミットログを見ていると、メンテナが最初の作者とは別の人になったようで、そのことも影響している?)

http://javafx-maven-plugin.github.io/

以下のキャプチャを見てもらうと分かりますが、作りたいプロジェクトの内容を画面上でぽちぽち選択していくと、右側に pom.xml に記述すべき内容が吐き出されるようになっています。これを自分のプロジェクトの pom.xml にコピーすればいいわけです。最近こういうの増えましたねえ。

f:id:aoe-tk:20160417210337g:plain

出力を JAR にするかネイティブパッケージにするか、ビルドは Maven JavaFX Plugin のゴールを直接叩くのか、それとも Maven ライフサイクルの中で実行するのか、などといった選択肢が用意されています。

以上、ちょっと嬉しかったのでお知らせまで。