水曜日 2 13, 2013

Nashorn でシェルスクリプトを書く

はじめに

Nashorn は日常のスクリプティングにも力を発揮します。Nashorn でシェルスクリプトを書く実例が紹介されていましたので、翻訳してみました。ご覧下さい。

おことわり

以下は jlaskey による Nashorn Blog への投稿の翻訳です。原文は https://blogs.oracle.com/nashorn/entry/csi_nashorn_shell_scripting_in でご覧頂けます。翻訳文の URL は https://blogs.oracle.com/nashorn_ja/entry/csi_nashorn_shell_scripting_in です。

訳文

The Register の『Gnome プロジェクトが唯一のアプリ開発言語に JavaScript を採用』と題された記事を読んでいた時、Nashorn を使ったシェルスクリプティングについて、まだお話をしていない事を思い出しました。

これは JavaScript のユーザにとってもシェルスクリプトのユーザにとっても守備範囲から外れる話かもしれませんが、一考の価値があります。ウェブブラウザ上の JavaScript にとって利便性の高い機能は、シェルスクリプトでも同じように良い機能です。その上、Nashorn は Java のライブラリや JavaFX にもアクセスできます(プログラムに視覚的な効果を追加する事も可能です)。

Nashorn には -scripting オプションが用意されており、JavaScript を拡張して、シェルスクリプトを書き易くする機能を追加する事が出来ます(ファイルの先頭行が #! で始まるスクリプトファイルも作成出来ます)。-scripting オプションを付けた場合に有効になる機能は以下の通りです。

  • $EXEC("コマンド名 引数", "入力文字列") 関数で OS のコマンドを別プロセスとして実行
  • 標準入力の引き渡し
  • 標準出力 ($OUT)
  • 標準エラー($ERR)
  • 終了コード ($EXIT)
  • `コマンド名 引数` 形式でのコマンド実行文字列の簡易指定
  • ダブルクォートで括った文字列とコマンド実行文字列は置換可能で、シングルクォートで括った文字列は置換不可
  • ヒアストリングによる複数行文字列(<<TAG...TAG 形式のヒアストリングは最後に改行が入り、<<<TAG...TAG 形式のヒアストリングは最後の改行が入りません)
  • 環境変数へのアクセス ($ENV)
  • コマンドライン引数へのアクセス ($ARG)
  • exit(code) と quit() によるスクリプトの終了
  • # によるコメント

今後もスクリプト作成の実例をたくさんご用意する予定ですが、今回の記事では手始めとしてスクリプトを一つご紹介します。

ソースコードを書いたプログラマの調査

私たちが Nashorn の開発を行っている中で、意図が掴めないコードに突き当たり、そのコードを書いたプログラマを探し出して話をしたいと思うことがよくあります。blaming (問責)と呼ばれる事もありますが、なるべく苦労することなしにコードを理解するには、書いた人に聞くのが一番です。Nashorn は openjdk.java.net にある Mercurial のリポジトリで管理されています。Mercurial もソースコードの変更毎の注釈を保存する機能を持っていますが、ソースコードの特定の場所を直接指定して調査できると便利です。

次のシェルスクリプト(suspect スクリプト)は、ソースコードのファイル名と調べたい箇所の行番号を与えると、ソースコードの変更履歴からその行に関連する情報を抜き出して表示します。

#!/usr/bin/jjs
# このスクリプトはソースコードのファイル名と行番号からソースコードの
# 変更情報を見つけ出します
#

// コマンドの使用方法を表示
function usage() {
    error(<<EOS);
usage: suspect javaFileName lineNumber
    javaFileName - name of file in local mercurial repository
    lineNumber   - file line number
EOS
}

// 標準エラー出力にメッセージを出力
function error(message) {
    java.lang.System.err.print(message);
    exit(1);
}

// コマンドの引数にわかりやすい名前を与える
var fileName   = $ARG[0];
var lineNumber = $ARG[1];

// 引数が足りない場合は、コマンドの使用方法を表示
if (!fileName || !lineNumber) {
    usage();
}

// ファイル名に .java が欠けていた場合は補完
if (!fileName.endsWith(".java")) {
    fileName += ".java";
}

// 引数で与えたファイル名にマッチするファイルを探し、
// 見つかったパス名を配列に格納
var where = `find . -name ${fileName}`.trim().split("\n");

// ファイルがみつからなかった場合
if (where == "") {
    error("File ${fileName} is not in the current repository.\n");
} else if (where.length != 1) {
    error("File ${fileName} found in multiple locations\n${where.join('\n')}\n");
}

// ファイルの注釈情報を変更履歴番号付きで取得
var annotated = `hg annotate -c ${where}`.split("\n");

// 引数で指定した行番号の行を抜き出す
var line = annotated[lineNumber];

// 行が存在している事を確認
if (!line) {
    error("File ${fileName} does not contain line number ${lineNumber}\n");
}

// 履歴番号を抜き出す
var revision = line.substring(0, 12);

// 履歴番号から履歴情報を取り出して表示
print(`hg log -r ${revision}`);

もし SpillProperty.java ファイルの 63 行目の履歴情報を調べたくなったら、suspect スクリプトを以下の様に実行して下さい。

>> suspect SpillProperty 63
changeset:   2:da1e581c933b
user:        jlaskey
date:        Fri Dec 21 16:36:24 2012 -0400
summary:     8005403: Open-source Nashorn

今回はまだほんの手始めです。今後の更新にもご期待下さい。

土曜日 12 22, 2012

Nashorn のソースコードが公開されました

はじめに

昨日、予告通りに Nashorn のソースコードが公開されました。プロジェクトのウェブページメーリングリストも用意されています。オープンソースになった Nashorn のこれからが楽しみですね。

おことわり

以下は jlaskey による Nashorn Blog への投稿の翻訳です。原文は https://blogs.oracle.com/nashorn/entry/open_for_business でご覧頂けます。

訳文

沢山の血と、汗と、涙が流されて、ついに Nashorn が OpenJDK に加わりました。

ソースコードの取得は Mercurial を使って

hg fclone http://hg.openjdk.java.net/nashorn/jdk8 nashorn~jdk8

とするか、単に Nashorn を指定します。

hg clone http://hg.openjdk.java.net/nashorn/jdk8/nashorn nashorn

より詳細な手順と OpenJDK の使い方は、開発者ガイドをご参照ください。

http://openjdk.java.net/guide/index.html

今回のコードリリースはまだ序の口で、これから更に大きな統合作業が待ち構えていますが、ソースコードを読んだり、ビルドして動かして頂く準備は整いました。まずは README と RELEASE_README からご覧下さい。質問や問題点を見つけたら、それらを是非 nashorn-dev@openjdk.java.net に投稿して下さい。冬休みの間は反応が遅くなるかもしれませんが、必ず返信するつもりです。

土曜日 12 08, 2012

OpenJDK が Nashorn プロジェクトを承認

はじめに

Nashorn が OpenJDK のプロジェクトとして承認されました。Nashorn は OpenJDK の一部として、オープンソースで公開されます。以前の話では、公開は冬休み前との事でしたので、ダウンロードが可能になるまで時間は掛からないと思われます。楽しみですね。

おことわり

以下は jlaskey による Nashorn Blog への投稿の翻訳です。原文は https://blogs.oracle.com/nashorn/entry/the_vote_is_in でご覧頂けます。

訳文

先ほど、こんなメールが届きました。来週は忙しくなりそうです。

Jim Laskey 氏が初期リーダーを務める Nashorn プロジェクト承認の投票 [1] が
締め切られました。

賛成: 20
反対: 0
棄権: 0

明確な反対が無ければ賛同されたものと看做すという決まりにより、
これでこの新プロジェクトとプロジェクトのリーダーは承認されました。

-John Coomes

[1] http://mail.openjdk.java.net/pipermail/announce/2012-November/000139.html

木曜日 12 06, 2012

Twitter 上の Nashorn への反響(続き)

はじめに

Nashorn と Java を組み合わせて Twitter にアクセスするサンプルの続きです。今回は JavaFX を使用してグラフを表示します。

おことわり

以下は jlaskey による Nashorn Blog への投稿の翻訳です。原文は https://blogs.oracle.com/nashorn/entry/nashorn_in_the_twitterverse_continued でご覧頂けます。

訳文

Twitter にアクセスするサンプルが完成しましたので、今度は JavaFX を使用してグラフ化してみましょう。この記事を書いている時点では Nashorn には JavaFX 用のシェルがありませんので、JavaFX アプリケーションを作成するには少し工夫が必要になります。今回ご紹介する方法で、Nashorn と Java を相互に呼び出すプログラムのイメージを掴んで頂けるのではないかと思います(JavaFX 用のシェルは今後の実装予定に加える予定です)。

まずはアプリケーションの中で実質的な処理を行う部分を見て行きましょう。こちらが前回ご紹介した Twitter にアクセスするサンプルを書き直したプログラムです。

var twitter4j      = Packages.twitter4j;
var TwitterFactory = twitter4j.TwitterFactory;
var Query          = twitter4j.Query;

function getTrendingData() {
    var twitter = new TwitterFactory().instance;
    var query   = new Query("nashorn OR nashornjs");
    query.since("2012-11-21");
    query.count = 100;
    var data = {};

    do {
        var result = twitter.search(query);
        var tweets = result.tweets;
        for each (var tweet in tweets) {
            var date = tweet.createdAt;
            var key = (1900 + date.year) + "/" +
                      (1 + date.month) + "/" +
                      date.date;
            data[key] = (data[key] || 0) + 1;
        }
    } while (query = result.nextQuery());

    return data;
}

今回は、ツイートを表示する代わりに、getTrendingData() 関数の中でサンプリング期間中(このプログラムでは、Nashorn のプロジェクトが OpenJDK に申請された 2012 年 11 月 21 日以降)の日別のツイート数を計算し、結果をオブジェクトに格納して返しています。

続いて、JavaFX の BarChart でデータを表示します。

var javafx         = Packages.javafx;
var Stage          = javafx.stage.Stage
var Scene          = javafx.scene.Scene;
var Group          = javafx.scene.Group;
var Chart          = javafx.scene.chart.Chart;
var FXCollections  = javafx.collections.FXCollections;
var ObservableList = javafx.collections.ObservableList;
var CategoryAxis   = javafx.scene.chart.CategoryAxis;
var NumberAxis     = javafx.scene.chart.NumberAxis;
var BarChart       = javafx.scene.chart.BarChart;
var XYChart        = javafx.scene.chart.XYChart;
var Series         = javafx.scene.chart.XYChart.Series;
var Data           = javafx.scene.chart.XYChart.Data;

function graph(stage, data) {
    var root = new Group();
    stage.scene = new Scene(root);
    var dates = Object.keys(data);
    var xAxis = new CategoryAxis();
    xAxis.categories = FXCollections.observableArrayList(dates);
    var yAxis = new NumberAxis("Tweets", 0.0, 200.0, 50.0);
    var series = FXCollections.observableArrayList();
    for (var date in data) {
        series.add(new Data(date, data[date]));
    }
    var tweets = new Series("Tweets", series);
    var barChartData = FXCollections.observableArrayList(tweets);
    var chart = new BarChart(xAxis, yAxis, barChartData, 25.0);
    root.children.add(chart);
}

このサンプルプログラムの中には興味深い点が沢山あります。例えば、stage.scene = new Scene(root) は stage.setScene(new Scene(root)) と同じ処理をより簡潔に記述出来ています。Nashorn が stage オブジェクトに scene プロパティを見つけられなかった場合は、(Dynalink ライブラリを通して)Java Beans の命名規則的に同等となるメソッド (setScene()) を探して来るので、こういう記述が可能になっています。もう一つ、Nashorn は FXCollections 等の総称クラスのハンドリングも自動で行ってくれます。そして、observableArrayList(dates) 呼び出しの部分では、Nashorn が JavaScript の配列 (dates) を Java のコレクションに自動で変換しています。どのオブジェクトが JavaScript のオブジェクトで、どのオブジェクトが Java のオブジェクトであるかを判定するのはとても難しい問題ですが、それをプログラマが明示的に指定しなくても良い様になっています。

プログラムの本質的な処理の部分の説明は以上で終わりましたので、次は JavaFX と連携するための仕組みについて見て行きましょう。

JavaFX のプログラムを作成する際は、javafx.application.Application クラスのサブクラスをメインクラスにします。このクラスが JavaFX ライブラリの初期化とイベント処理を行います。こちらがこのサンプルプログラム用に作成したコードです。

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import javafx.application.Application;
import javafx.stage.Stage;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class TrendingMain extends Application {

    private static final ScriptEngineManager
                                        MANAGER = new ScriptEngineManager();
    private final ScriptEngine engine = MANAGER.getEngineByName("nashorn");
    private Trending trending;

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) throws Exception {
        trending = (Trending) load("Trending.js");
        trending.start(stage);
    }

    @Override
    public void stop() throws Exception {
        trending.stop();
    }

    private Object load(String script) throws IOException, ScriptException {
         try (final InputStream is = TrendingMain.class.getResourceAsStream(script)) {
            return engine.eval(new InputStreamReader(is, "utf-8"));
         }
    }
}

ここでは Nashorn の初期化の為に JSR-223 の javax.script を使用しています。

private static final ScriptEngineManager MANAGER = new ScriptEngineManager();
private final ScriptEngine engine = MANAGER.getEngineByName("nashorn");

コードのこの部分は JavaScript を処理するための Nashorn エンジンのインスタンスを作成しています。

load メソッドで外部スクリプトをメモリ上に読み込み、engine でそのスクリプトを評価します。load は評価した結果を返します。

ここからが特に面白い部分です。Java のメインクラスと外部スクリプトの間で相互にデータをやりとりする方法は何通りかありますが、このサンプルでは Java のインターフェイスを使用します。JavaFX のメインクラスは start メソッドと stop メソッドを実行する必要がありますので、この様なインターフェイスを作成します。

public interface Trending {
    public void start(Stage stage) throws Exception;
    public void stop() throws Exception;
}

そして、サンプルスクリプトの最後に、次のコードを追加します。

function newTrending() {
    return new Packages.Trending() {
        start: function(stage) {
            var data = getTrendingData();
            graph(stage, data);
            stage.show();
        },

        stop: function() {
        }
    }

}

newTrending();

このコードは Trending クラスのサブクラスのインスタンスを作成し、start メソッドと stop メソッドをオーバーライドしています。この関数から返されたオブジェクトが eval を通して Java のメインメソッドに返されます。

trending = (Trending) load("Trending.js");

全体の動きを簡単にまとめますと、Trending.js スクリプトには getTrendingData 関数の定義と、一番最後に newTrending 関数の呼び出しが実装されています。そこから Java のコードに戻って、newTrending 関数を評価している eval メソッドの返り値を Trending クラスにキャストしています。そして、その返ってきたオブジェクトを使用して、次のコードでスクリプトの実行を行います。

trending.start(stage);

これで完成です。

twitterverse

訳者補足

Nashorn のリンカーの動きは http://www.myexpospace.com/JavaOne2012/SessionFiles/CON5251_PDF_5251_0001.pdf をご参照下さい。 Dynalink に付きましては https://github.com/szegedi/dynalink をご参照下さい。

火曜日 12 04, 2012

Twitter 上の Nashorn への反響

はじめに

Nashorn を使用して Twitter にアクセスするサンプルがありましたので翻訳してみました。

おことわり

以下は jlaskey による Nashorn Blog への投稿の翻訳です。原文は https://blogs.oracle.com/nashorn/entry/nashorn_in_the_twitterverse でご覧頂けます。

訳文

Nashorn がインターネット上でどれだけ話題になっているのかを追ってみました。Project Nashorn をアナウンスしてから、Nashorn についての沢山のツイートがありましたので、Nashorn の日毎のトレンドがどうなっているのか調べてみたくなりました。出来れば結果をグラフ化出来ると面白そうです。その為に、ツイート数をひとつひとつ数えるのは賢いやり方とは言えません。集計用のプログラムを作って数えてみましょう。

実は、これこそ Nashorn + Java の組み合わせが得意としている分野です。Java には Twitter4J https://github.com/yusuke/twitter4j という素晴らしいライブラリがあり、Twitter に関することは全てお任せ出来ます。bin/getAccessToken.sh を実行し、twitter4j.properties に認証情報を記録したら、後は簡単な調査用アプリを実行するだけです。

nashorn -cp $TWITTER4J/twitter4j-core-3.0.1.jar GetHomeTimeline.js

GetHomeTimeline.js の中身はこうです。

var twitter4j      = Packages.twitter4j;
var TwitterFactory = twitter4j.TwitterFactory;
var Query          = twitter4j.Query;

var twitter = new TwitterFactory().instance;
var query   = new Query("nashorn OR nashornjs");
query.count = 100;

do {
    var result = twitter.search(query);
    var tweets = result.tweets;

    for each (tweet in tweets) {
        print("@" + tweet.user.screenName + "\t" + tweet.text);
    }
} while (query = result.nextQuery());

とても簡単ですね。さて、次は JavaFX のグラフ化ライブラリと連携させてみましょう...

火曜日 11 27, 2012

Project Nashorn 申請 (オープンソース)

はじめに

Nashorn の OpenJDK への申請がアナウンスされていましたので、翻訳してみました。

おことわり

以下は jlaskey による Nashorn Blog への投稿の翻訳です。原文は https://blogs.oracle.com/nashorn/entry/request_for_project_nashorn_open でご覧頂けます。

訳文

先週の木曜日(2012 年 11 月 22 日)、OpenJDK のコミュニティに Project Nashorn が申請されました。 http://mail.openjdk.java.net/pipermail/announce/2012-November/000139.html Project 承認の投票期限は 2012 年 12 月 6 日、UTC の深夜です。うまく行けば、OpenJDK に Nashorn が入り、この冬休みにはお試し頂ける事になると期待しています。幸運に恵まれますように。

月曜日 10 29, 2012

Nashorn Blog へようこそ

はじめに

JavaOne での Nashorn のセッションが紹介されていましたので、翻訳してみました。

おことわり

以下は jlaskey による Nashorn Blog への投稿の翻訳です。原文は https://blogs.oracle.com/nashorn/entry/welcome_to_the_nashorn_blog でご覧頂けます。

訳文

皆さんようこそ。沈黙を破り、Nashorn ブログを開始する時が来ました。このブログは定期的に更新して行きたいと思っておりますが、ちょうど次の開発マイルストーンに向けてとても忙しくしており、もちろん Nashorn をオープンソースとして公開する為の準備もあります。ですので、万が一、更新が滞る事がありましたらご容赦下さい。

我々は丁度 JavaOne から戻ったばかりで、Nashorn のセッションへの好意的な反応にとても感激しています。キーノートの Georges Saab のスライドの中で重要な位置を占められた事は我々のチームにとって素晴らしいことでした。色々な方からの支持を頂けていると感じています。

JavaOne の殆どのセッションは動画が用意されています。リンク先をご覧下さい。

『Nashorn: JVM 上での JavaScript と動的言語の実行の最適化』 不幸にも、マーカス(コード生成の神様)は初日の最初のセッションを仰せつかりました。それでも、なかなかの出席者数に恵まれました。話の内容は、JVM から良い性能を引き出すために、我々が施した最適化についてでした。まだまだやるべきことは沢山残っていますが、良い感触を得ています。

『Nashorn: JVM 上の JavaScript』 これが Nashorn に関するメインのセッションです。このセッションでは私がオーバービューやオープンソース化についての補足、Nashorn の概要の紹介、デモなど、様々な内容について話しました。250 席くらいの部屋が満席でした。一番素晴らしかったのは、Twitter の Sam Pullara による Mustache.js が如何に快適に(Rhino の 20 倍の速度で)実行できるかの説明と、NetBeans の John Ceccarelli による Nashorn が Netbeans でどんなに不可欠な位置を占めているかの説明です。最後には有益な Q & A もあり、とても励みになりました。

『Nashorn JavaScript Team 懇談会』 Michel と Attila と Marcus と私で Q & A を開催しました。出席者は数名(他の良いセッションとかち合ってしまった為だと思います)でした。殆どの質問は Node.jar についてでしたので、Nashorn + Node.jar の組み合わせが最も注目されているという印象を受けました。ミスター Node.jar の Akhil が参加者からの質問に受け答えしました。

『Nashorn と Node と Java Persistence』 Doug Clarke と Akhil と私で表題の件について討論を行い、(警備員によって解散 させられるまで)長時間に渡る Q & A を行いました。出席者は 80 名ほどでした。 多くの質問は Node.jar についてでした。Doug の Nashorn + JPA の使い方の話は とても素晴らしかったです。Nashorn が優雅に上品に活用されていました。

『メタオブジェクトプロトコルの適用 : Nashorn の Java バインディング』 Attila が、どのように Dynalink を Nashorn に適用したかについて話しました。このセッションもなかなかの盛況でした。ここで扱われた技術が一般に行き渡れば、JVM 上の全てのプログラミング言語で素晴らしいことが起きそうな予感がしました。

最後に、JavaOne では Java 以外の言語や、それらが JVM に与えている影響についてのセッションが沢山ありました。私はいつも、誰もが複数のプログラミング言語を使い分けるべきだと思っています。問題の領域やタスクに応じて使い分けるだけでなく、問題解決への考え方やアプローチを向上させる事にも役立ちます。

概ね、今後の記事は Nashorn に関する how to について書いていこうと思っています。もし何か書いてほしい題材がありましたら、お知らせ下さい。

それでは、ご機嫌よう!

About

JavaVM 用 JavaScript エンジンの Nashorn について情報発信しているブログです。Nashorn の読み方はナズホーンです。

Search

Archives
« 4月 2014
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today