Category Archives: Java

WindowsでJavaな人に捧げる素敵なスクリプティングツール jrunscriptの使い方

これは Java Advent Calendar 2015 の3日目です。昨日は@kawasima さんの「Webアプリ開発/テストのお供に『WAITT』」で、明日は @akihyro さんです。

もしもLLが使えたなら

業務にWindowsを使用していて、開発言語はもっぱらJava、LLを使えたらかっこいいと思うけど、Windowsだし。。。。Powershellとかよく知らないしでもっぱらサクラエディタ、、、そんな方はいらっしゃいませんか?

僕は、そんなあなたを応援します!なぜなら僕がそうだからです!

僕は大量のファイルを作ったり、複雑なファイル検索をしたいなどのデータ処理に、よくJDK付属のjrunscriptコマンドを使っています。例えばこの記事でも使っています。

jrunscriptとは

jrunscriptはJDK6以上に付属しているコマンドで、JVM上でJavaScriptエンジンを実行することが出来るコマンドラインツールです。cd()やdir()などの若干のシェル的な組み込み関数をバンドルしています。

JavaScriptなら、Web開発を経験していれば、Javaばかりの人も自由に書けるのではないでしょうか?

Javaプログラマーがjrunscriptコマンドを使いこなすメリット

  • JDKさえ入っていれば、WindowsでもMacでもLinuxでも動く
  • 使い慣れたJavaAPIが使える

冒頭に述べた僕みたいな人にぴったりなツールです。確かに、LLに比べてJavaScriptはfunctionなどの入力量が多いです。

しかし、APIを調べたり、言語仕様を勉強している時間がほぼいらないので、やりたいことが最短で実現できます。

しかも、LinuxやMacにそのまま持っていけます!やった\(^o^)/

JVMの状態を見よう

jrunscriptのもう一つの用途として、即座にJavaのシステムプロパティどうなっているんだっけ?など、JVMの状態をしれてしまうことがあります。

$ jrunscript -e "print(java.lang.System.getProperty('user.timezone'))"

システムプロパティを列挙するならこんな感じです。

$ jrunscript -e "for (var key in java.lang.System.properties) print(key + "-" + java.lang.System.properties[key]);"

組み込み関数を知ろう

次のURLに記載された関数が組み込まれています。
http://docs.oracle.com/javase/7/docs/technotes/tools/share/jsdocs/GLOBALS.html

これらの関数は地味ながら、時々役立ちます。例えばjrunscriptで簡単なインストーラーを作るときなどは重宝すると思います。

JavaとJavaScriptの橋渡し

JavaAPIを使ってしまうと、Javaの配列を受け取ったりします。Nashorn/Rhinoの世界では、JavaScriptの配列とJavaの配列は明確に区別されており、JavaScriptとして使うならJavaScript配列を使ったほうが便利です。

例えば、次のようにES5風のforEachが書けます。

nashorn> [1,2,3,4,5].forEach(function(i){print(i);})
1
2
3
4
5

しかし、Java配列の場合はできません。

nashorn> new java.io.File(".").list().forEach(function(i){print(i);})
script error: TypeError: [Ljava.lang.String;@5a63f509 has no such function "forEach" in <STDIN> at line number 1

この場合は、Java.fromというメソッドが使えます。

nashorn> Java.from(new java.io.File(".").list()).forEach(function(i){print(i);})
aaa.txt
bbb.js
xxx.zip

応用編

あるディレクトリ以下の全てのファイルを探索

これはよく使うのでイデオムではないでしょうか。

function f(i) {
    if (i.isDirectory()) {
        Java.from(i.listFiles()).forEach(function(e) {f(e);})
    } else { doSomething(i) }
}
doSomething = function(i) {print(i);};
f(new java.io.File("."));

以下、このfを定義していたとします。

例題1. あるディレクトリ以下で、拡張子がjavaのファイルで10日以内に変更したファイル一覧を取得

doSomething = function(i) {
    if (i.lastModified() > java.lang.System.currentTimeMills() - 1000 * 3600 * 24 * 10) {print(i);}};
f(new java.io.File("."));

例題2. あるディレクトリ以下で、ファイル名がAdminから始まっているファイルの容量の合計

doSomething = function(i) {
    if (i,getName().startsWith("Admin")) {print(i.length()); sum += i.length()}};
var sum = 0; f(new java.io.File(".")); print(sum);

例題として微妙ではありますが、関数を組み立ててやりたいことを実現していくのが気持ち良くなってきませんか?

まとめ

このように、JDKさえあれば使える、クロスプラットフォームなスクリプティングツールとして、いざというときに役立つのではないでしょうか。

Java6がリリースされてから9年経ちますので、9年前以降のしすてむであったら使うことが出来ます。

JavaAPIが使えるので、いちいち慣れない言語のAPIを調べる手間が省けるのが嬉しいです。あれ、これ、Rubyではどう書くんだろう?と思う必要がありません。

また、ある程度うまく行ったら、Javaで同等なことが出来るので、本番のコードとして流用することもあるかも知れません。

これで、LL弱者の僕も、ワンライナーを駆使できるようになりました。

次はあなたの番です!

jjsコマンドについて

jrunscriptの他に、Java8からはjjsというコマンドが搭載されています。jrunscriptは試験的に作られたコマンドという位置づけなので、本来はjjsコマンドを使うべきです。

しかし、標準組み込み関数が微妙に異なることと、java6,7環境も依然として存在すると思われますので、僕はjrunscriptを好んで使います。

JSPで書かれたシステムをMayaaに移行する

これは Mayaa Advent Calendar 2015 の2日目です。昨日は「Mayaaとの出会い」でした。

JSPで書かれたシステムのMayaaへの移行

さて、前回、MayaaはJSPと同じレイヤーで動いているから、JSPでデザインが描かれているシステムは簡単に移行できると書きました。

今回は実例を元に、その様子を解説しようと思います。

何でも良いので、JSPをビューに使っているMVCフレームワークがあるとします。

例えばこれは、SAStrutsのコード例です。

import org.seasar.struts.annotation.Execute;
public class IndexAction {
    @Execute(validator = false)
    public String index() {
        return "index.jsp";
    }
}

今から新規にStrutsのコードを書くことはないと思いますが、StrutsライクなMVCフレームワークなら何でも同じようにできると思います。自分の使っているフレームワークに脳内変換してください。
(後日、最近のメジャーなフレームワークとMayaaを連携する例を書きたいと思います。)

MayaaServletをweb.xmlに登録

もし使っているのが、レガシーServletでWeb.xmlを書いているなら、次の設定を書き加えましょう。

    
    <servlet>
        <servlet-name>MayaaServlet</servlet-name>
        <servlet-class>org.seasar.mayaa.impl.MayaaServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>MayaaServlet</servlet-name>
        <url-pattern>*.xhtml</url-pattern>
    </servlet-mapping>

<url-pattern>*.xhtml</url-pattern>という部分は、標準のMayaaの流儀ではないかもしれません。しかし、多くのWebシステムは既にhtmlをマッピングしているのではないでしょうか?私の現場もそうでした。そこで私はxhtmlファイルをMayaaのテンプレートとして設定しました。その結果、テンプレートファイルは正しいxhtml書式で書く文化がチーム内に浸透したため、良い判断だったと思います。

あとは、Java側でフォワードしている部分のJSPの部分を

import org.seasar.struts.annotation.Execute;
public class IndexAction {
    @Execute(validator = false)
    public String index() {
        return "index.xhtml";
    }
}

のように書き換えましょう。後はindex.jspの代わりにindex.xhtmlを置くだけです。

この方法の良い所は、JSPとMayaaを同居できることです。移行作業中は、古いJSPのテンプレートも残すことが出来ます。ただし、JSPにMayaa、MayaaにJSPをインクルードすることは出来ませんので、そのあたりはご注意ください。

テンプレートを書く

次にテンプレートを書きましょう。例えばJSPがあったとします。ちなみに、僕はJSPのtaglibが嫌いで、ほとんど使いません。なので、MayaaにもJSPのtaglibをサポートする機能を持っていますが、全然使ったことがありませんので、公式のマニュアルを参照してください(笑)

ちなみに、EL式も使いません。何か文句ありますか?

<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ page import="info.susumuis.sample.ViewHelper" %>
<%@ page import="info.susumuis.sample.SampleBean" %>
<% SampleBean bean = (SampleBean) request.getAttribute("bean"); %>
<html>
<head>
  <title ><%= ViewHelper.escape(bean.getTitle()) %> </title>
</head>
<body>
<%= ViewHelper.escape(bean.getMessage()) %>
</body>
</html>

ViewHelper.escapeは、HTMLエスケープをする共通メソッドだと思ってください。

これをMayaaに移植する最も手っ取り早い方法は、JSPを実行した結果のHTMLをいきなり貼り付けてしまうことです。

 



<html>
<head>
<title >たいとる</title>
</head>
<body>
ハローワールド
</body>
</html>

このままでは文字化けしてしまいますので、metaタグで文字コードを指定します。Mayaaはmetaタグでコンテントタイプを設定しておくと、勝手にヘッダを書き換えてくれますので活用しましょう。

このとき、注意として、HTML5の、<meta charset="">を使わないことです。使っても良いのですが、text/html;の部分の情報が抜けてしまうので、以下のように古い書き方を使うことをおすすめします。

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

また、JSP特有の空行は消していきましょう。また、拡張子をxhtmlファイルにしてしまったので、ブラウザでプレビューできるようにxmlns指定を書きます。本当は先頭行に宣言が必要ですがこれはサボっても表示できるようです。(この辺りは、MayaaがContent-Typeを見て最終的に適切な出力に調整してくれます)

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title >たいとる</title>
</head>
<body>
ハローワールド
</body>
</html>

このテンプレートはWebブラウザでそのまま開くことが出来るはずです。

これで、サーバーで実行するのと同じ出力を得ることができますね。

え、動的な部分が固定されてしまっている?その通りです。しかし、Mayaaのページ作りの流儀としてはこれでよいのです。この後の説明を読めば分かります。

動的部分を実装する

元のコードはSampleBeanから、タイトルとメッセージを取得していましたね。Mayaaでは動的な出力を実現するために、m:idというものを使います。

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:m="http://mayaa.seasar.org">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title m:id="TITLE_TAG">たいとる</title>
</head>
<body>
<span m:id="MESSAGE_HERE">ハローワールド</span>
</body>
</html>

htmlタグに名前空間xmlns:mを追加しています。
m以外を指定しても動きますが、普通はm:に割り当てます。"m:id"は「エム・アイ・ディー」と読みます。Mayaaの世界では非常に多用する単語なので、覚えましょう。

動的にしたいタグにm:idを加えていきます。もともとタグがなかったところはspanタグで補います。

ところで、Mayaaは非常に柔軟ですが、自由に使い過ぎると、デザイナーさんとの連携をスムーズにできません。お互いにある程度ルールを定めるべきです。そこで、僕はm:idは次の4種類に限定しています。

  • _HERE

    • その場所に文字列を出力する
  • _TAG

    • そのタグの属性を変化させたり要素を足したりする
  • IF_

    • そのタグ及びその子要素が特定の条件にもとづいて消える
  • LOOP_

    • そのタグ及びその子要素を特定の条件に基づいて繰り返す

m:idを発行するときは、出来る限り、HTMLとしてvalidになるように心がけましょう。
例えば、tableタグの中に、divタグを入れたり、titleタグの中にspanタグを入れるのは無しです。そのようなことをすると、Mayaaの良さを喪失してしまうので気をつけてください。

このままページを出力してみましょう。
ローカルでそのままダブルクリックしてブラウザに表示させても、サーバーで実行させても相変わらず表示は同じです。

mayaaファイルを書く


<m:mayaa xmlns:m="http://mayaa.seasar.org">
    <m:beforeRender>
        var bean = request.bean;
    </m:beforeRender>

    <!-- タイトルタグです -->
    <m:echo m:id="TITLE_TAG">
        <m:write value="${bean.getTitle()}" />
    </m:echo>

    <!-- メッセージを出力します -->
    <m:write m:id="MESSAGE_HERE" value="${bean.getMessage()}" />
</m:mayaa>

このようにm:idの動作を記述していきます。実は命名規則を定めたので、これらの書き方はある程度定型化できます。Mayaaはm:idだけ定義しておいて、mayaaファイルに実装していないとログにエラーメッセージを吐くので、エラーメッセージから雛形を出力するマクロを作るのも良いでしょう。僕も過去に作りました。

Mayaaファイルを命名規則から一括作成するEmEditorマクロ

本当は、標準のm:write, m:ifなどは使い勝手が悪いので、自分でプロセッサーを作ることをおすすめします。これについては、後日ご紹介します。

もう一つ、JSPのコードからViewHelper.escapeの記述が消えました。Mayaaでは、出力をエスケープするのがデフォルトの動作です。なので、「必要に応じてエスケープを解除する」というスタイルになります。昨今脆弱性が対策は必須となっていますので、この流儀は大変便利です。

このようにして1ページの移行が完了しました。あとは、全てのページを同じように移行していくことです。

しかし、実際のページはもっと複雑で、難しいことも多いと思います。次回から、個別にハマリポイントとその回避方法を紹介して行こうと思います。

Mayaaとの出会い

これは Mayaa Advent Calendar 2015 の1日目です。

明日は @susumuis の「JSPで書かれたシステムをMayaaに移行する」です。-->

今日からMayaaについての記事を書いていきます。

Mayaaってなに?

Mayaaはエンジニアとデザイナーとの連携を強く意識して設計されたJavaテンプレートエンジンです。

Mayaaを使用したプロジェクトが上手くいくと、Webデザイナーはプログラムを意識することなく、Webアプリケーションのデザインコーディングをすることができ、プログラマーはHTMLやJSPなどのコーディングから開放されます。

お前誰?

初めてこのブログを読んでくれた方には申し遅れました。私は、2009年より、仕事でMayaaを使用していて、2015年よりMayaaコミッターの末席に名を連ねさせていただいたものです。

おそらく、現在私が関わったプロジェクトが、Mayaaを使用した最も大規模なシステムの一つではないかと思っています。なので、どちらかと言うとMayaaの開発者視点というより、ユーザー視点の方が強いです。

Mayaaとの出会い

先ほど述べたとおり、2009年に自分の仕事でMayaaを利用し始めました。既にリリースから数年経過していますから、少し遅いほうだと思います。

当時、私は、ECサイトシステム構築におけるプログラミングコストの削減と、デザインテンプレートの充実化を課題として持っていました。

そこではじめはApache Wicketを試してみたのですが、確かにWicketは素晴らしいアーキテクチャでしたが、プログラミングの考え方がガラッと変わりすぎてしまい、既存の資産の活用が困難であるとわかり、導入を見送りました。

Wicket導入を振り出しに戻し、次にMayaaを検討することにしました。当時はまだThymeleafやMixer2はありませんでした。

Mayaaの導入がうまく行った理由

嬉しいことにMayaaの導入は非常にスムーズに行きました。それは、Mayaaが、システムの構成上、JSPと同じレイヤーに位置づけられるように設計されているため、他の部分を変える必要が一切なかったことです。

JSPファイルの横にxhtmlファイル(Mayaa標準ではhtmlを推奨していますが、htmlは既にフロントのサブレットに割り当てられていました)を配置して、.jspへフォワードする代わりに、.xhtmlへフォワードするだけで、後は、テンプレートを書くだけで移行が完了してしまいました。

mayaa_jsp

バックオフィスツールなど、デザインが重視されない部分については従来通りJSPを維持することも可能でした。

このようにアーキテクチャの変更をほとんどすることがなく、JSPから移行ができたことが、最大のメリットだったと思います。

次回予告

次回は、JSPで書かれたテンプレートをMayaaによるテンプレートに移行するときの手順、ハマったことなどを書こうと思います。