JavaScriptによるEtupirkaCMSのアップデートプログラム
EtupirkaCMS絡みでちょっとネタになりそうなプログラムを作ったので紹介します。内容としては、JSR223(スクリプト言語サポート)を使いJavaScriptでランチャープログラム(Swingアプリ)の更新を行う仕組みの解説です。
動機
EtupirkaCMSのウリとしてJavaだとかGAEだとかを意識せずに使って貰えるようなユーザビリティを目指しています。昨今のアプリでは自動アップデートなんて当たり前ですから、EtupirkaCMSも自動アップデートが出来る必要があります。しかし、Javaのスタンドアローンプログラムなど珍しいこの時代、WindowsアプリやWebStartのようにちょとしたAPIを使えば自動アップデートが出来るというわけにはいきません。そこでほとんどを自分で実装するわけですが、色々と課題もあります。
ランチャーの起動中にランチャーの使っているjarは(簡単には)更新できない
最初の問題として、ランチャーが起動しているときにそのjarは触れません。なので、元からあるetupirka.jarに加え、updater.jarを配置します。ランチャー起動時に更新が必要と判断すると、updater.jarを外部プロセスとして起動し、etupirka.jarは終了します。
更新内容は毎回異なる
当然ですが更新内容は毎回異なります。従って、更新プログラムをダウンロードしてローカルで実行するのがセオリーかと思われます。しかし、仕組みとしてやや煩雑になってしまうでしょう。もっとシンプルにできないのかと考え、更新用のプログラムをスクリプトとしてダウンロードし実行する方法を思いつきました。JSR223の出番です、JavaScriptです*1。
ファイルのコピーとか削除をJavaScriptで行う
・・・ことは出来ません。ところが、JSR223の特徴としてスクリプト側からJavaのクラスを使えます。Javaで書くのをやめてスクリプトで書いているというのに、Javaを使いたいとは意味不明とも思えますが、JavaScriptやJRubyでSwingのコードを書けるなどやっぱり意味が夢があります。例えばjava.io.Fileを使ったコードは次のようになります。
var dir = new java.io.File("foo"); dir.mkdir();
完全修飾名で書くのが嫌ならImportしましょう。
importPackage(java.io); var dir = new File("foo"); dir.mkdir();
実例
実際のアップデートに関するコードはこんな形になっています(抜粋)。
// 共通部 importPackage(org.etupirkacms.updater); var sys = { baseDir: Commands.baseDir(), baseUrl: "http://etupirka.googlecode.com/files/", // file file: function(filename) { return Commands.newFile(this.baseDir, filename.split('/')); }, // mkdir mkdir: function(pathname) { Commands.mkdir(this.file(pathname)); }, // rm rm: function(filename) { Commands.rmr(this.file(filename)); }, // mv mv: function(srcfilename, destfilename) { Commands.mv(this.file(srcfilename), this.file(destfilename)); }, // cp cp: function(src, dest) { Commands.cpr(this.file(src), this.file(dest)); }, // download download: function(filename, dirname) { Commands.downloadAndUnzip(this.baseUrl + "/" + filename, this.file(dirname)); }, }; function update(func) { func.apply(sys); } // バージョン毎の更新スクリプト update(function() { // download new version this.mkdir("../etupirkacms/0.2.0"); this.download("EtupirkaCMS-0.2.0.zip", "../etupirkacms/0.2.0"); // replace _mng directory this.rm("war/_mng"); this.cp("../etupirkacms/0.2.0/EtupirkaCMS/your-site/war/_mng", "war/_mng"); // replace static/_mng directory this.rm("war/static/_mng"); this.cp("../etupirkacms/0.2.0/EtupirkaCMS/your-site/war/static/_mng", "war/static/_mng"); // replace lib this.rm("war/WEB-INF/lib/etupirka-0.1.0.jar"); this.cp("../etupirkacms/0.2.0/EtupirkaCMS/your-site/war/WEB-INF/lib/etupirka-0.2.0.jar", "war/WEB-INF/lib/etupirka-0.2.0.jar"); this.rm("etupirka.jar"); this.cp("../etupirkacms/0.2.0/EtupirkaCMS/your-site/etupirka.jar", "etupirka.jar"); });
これでupdate.jarは更新が不要になったのです。
全体のソースは、こちらを参照のこと。ちなみに、このJavaScriptのコードはJUnitでユニットテストしています。
まとめ
JSR223を使う事で処理の一部を外部リソースとして定義することが出来ます。そこではJavaではなくJavaScriptなどスクリプト言語で書くことが可能です。必要があれば、Javaのクラスにアクセスできます。
*1:他の言語も使えるが、あくまで追加ライブラリが必要なので現実的でない