2008-11-15

Java 6 も Update 10 か...。

JView(MSJava)との互換性を気にしていた頃が夢のようだ。

2008-10-12

Folder Lock(R)の試用期間が切れた

35日経って、フォルダのロックができなくなった(もちろん、過去にロックしたフォルダの解除は可能)。
仕方ないのでアンインストール。
使えるソフトだったんだがなあぁ。

2008-09-27

古いWin32APIで取得していたCPU使用率が変になった

Win9x向けに自作したパフォーマンスモニタ(chkperf.exe)を久々にWindowsXPで起動してみたら、CPU利用率の表示が変だ。タスクマネージャの表示が0%の時に、65%とか表示される。Win98/ME互換モードにしても、1%で止まったままになる。
pdh.dllを使うとか、新しいやり方じゃないともう駄目なんだろーなー、と思いつつ、今更手を掛ける時間も無いので、そのままにしておく。

2008-09-05

Folder Lock(R)入れてみた

今使っているWindowsパソコンに、Webメールのバックアップ用のフォルダがあって、このフォルダに鍵を掛けたくなった。
フォルダにパスワードを付けるという意味では、Windows XPの暗号化機能があるのだけれど、あくまでもフォルダに一時的な鍵を掛けられれば良く、データの暗号化までやってしまうのはありがた迷惑だった。

ちょっとGoogleで検索してみたところ、Folder Lock®が良いらしいということで、無料版をダウンロードして入れてみた。
ソフトを起動すると、金庫(ロッカー?)のようなメイン画面が現れる。入力ボックスにパスワードを入れると、脇の鍵穴に"鍵を掛ける"アニメーションが表示される。後は、Folder Lock®の用意したフォルダにロックしたいファイル・フォルダを入れて操作するか、メイン画面の"Browse"リンクからフォルダを選択してロックを掛けることが出来る。
英語だけれど、やることが明確なUIで使いやすい。画面の主だった選択項目は3~4個程度なので分かりやすく(それでも慣れないUIなので最初は迷ったが)、操作の大きな区切りの間に気の利いたTipsが入る。
最近は開発者向けのコマンドラインツールばかり触ってたので、こういったUIがやたら新鮮に感じられた。

FAQに開発体制について書いてあった。
Q74. How many programmers and designers have made this software?
3 hard-working programmers and 2 highly-skilled designers.
素晴らしい。

2008-08-31

jrunscriptでGUIスクリプトを起動してみて気づいたこと

  1. jrunscriptのバッチモード(-fオプション)でAWTやSwingのウィンドウを表示するスクリプトファイルを起動した場合、ウィンドウが一瞬だけ表示されて終了してしまう。
  2. スクリプトの最後にjava.lang.Thread.currentThread().sleep(1000);を付け足すと、スレッドを待機させている間はウィンドウが表示された。
  3. どうやらスクリプトを処理するメインスレッドが、スクリプトを読み終えた時点で(GUIのスレッドが生きていても)exitしているように見える。
  4. そこで、wait-notifyの組合せを使って、ウィンドウがクローズされるまでメインスレッドを待機させることを思い付いた。
  5. Rhinoで同期処理を上手くやる方法はあったっけ?
  6. "バッチモード"という位なので、これはこれで正しいのかもしれない、と勝手に自分を納得させる。
  7. あえなく完。
  8. Rhino組み込みのsync関数に気付き、sync(function() {this.wait();})の返す同期化された関数を使ってみる。
  9. wait関数が見つからないとか言われた...。確かにtypeof this.waitはundefinedだった。
  10. やっぱり完。
  11. スクリプトの最後に while (frame.isDisplayable()) {java.lang.Thread.currentThread().sleep(1000);} を付けたところ、GUI側でウィンドウクローズ時にちゃんとdispose()してれば想定通りに動く。
  12. 何か納得いかないものの完。
ちなみに、対話モードでload('GUIスクリプトファイル名');を使うなら問題なし。

イベントアダプタをJava Scripting EngineのJavaScriptで真似する

Java1.6付属のRhinoでJavaインタフェースを実装する場合、以下のように書ける(jrunscriptで実行)。
js> var runner = new java.lang.Runnable() { run: function() { print(this); }};
js> new java.lang.Thread(runner).start();
js> [object Object]
問題は、GUIのイベントリスナを書こうとした場合、使いもしないメソッドまで記述することになるので面倒くさい。
Javaで実装する場合はアダプタクラスがあるのだけれど、アダプタクラスはインタフェースではなく抽象クラスなので、下記のようなスクリプトは通らない。
// 変数frameにはjava.awt.Frameが入っているものとする
frame.addWindowListener(new java.awt.event.WindowAdapter() {
    windowClosing: function(evt) {
        java.lang.System.exit(0);
    }
});
// 上記構文はインタフェース用なので、抽象クラスに適用できない
以下のスクリプトは一応通るものの、実装しないでおいたイベントハンドラが後で呼ばれると、java.lang.NoSuchMethodExceptionが発生する。
frame.addWindowListener(new java.awt.event.WindowListener() {
    windowClosing: function(evt) {
        java.lang.System.exit(0);
    }
});
// この後、frameを表示するとwindowActivatedやwindowOpenedが未実装なので例外が発生する
そこで、必要なイベントハンドラの連想配列を渡すとWindowListener(を実装したクラスのインスタンス)を作成して返す関数を書いてみた。イベントハンドラごとにベタベタ似たような処理を書いている箇所がもっとスマートにならないものか...。
// 渡された連想配列からWindowListenerを作成する関数
function createWindowListener(tbl) {
    function ignoreEvent(evt) {}
    function getValue(value, defaultValue) { return value ? value : defaultValue; }
    return new java.awt.event.WindowListener() {
        windowActivated: getValue(tbl['windowActivated'], ignoreEvent),
        windowClosed: getValue(tbl['windowClosed'], ignoreEvent),
        windowClosing: getValue(tbl['windowClosing'], ignoreEvent),
        windowDeactivated: getValue(tbl['windowDeactivated'], ignoreEvent),
        windowDeiconified: getValue(tbl['windowDeiconified'], ignoreEvent),
        windowGainedFocus: getValue(tbl['windowGainedFocus'], ignoreEvent),
        windowIconified: getValue(tbl['windowIconified'], ignoreEvent),
        windowLostFocus: getValue(tbl['windowLostFocus'], ignoreEvent),
        windowOpened: getValue(tbl['windowOpened'], ignoreEvent),
        windowStateChanged: getValue(tbl['windowStateChanged'], ignoreEvent)
    };
}

// 使ってみる(ウィンドウが表示されて、閉じるボタンを押すと終了する)
// jrunscriptから実行する場合は、load関数で読み込ませないと一瞬で終了する
var frame = new java.awt.Frame("Test Frame");
var panel = new java.awt.Panel();
panel.setPreferredSize(new java.awt.Dimension(320, 240));
frame.add(panel);
var handlers = { windowClosing: function(evt) {
    var window = evt.getSource();
    window.setVisible(false);
    window.dispose();
    //java.lang.System.exit(0); 最近のJVMでは不要になったらしい
} };
frame.addWindowListener(createWindowListener(handlers));
frame.pack();
frame.setVisible(true);

2008-08-23

LCC-Win32が自由にダウンロードできた頃

私がまだコマンドラインで何かすることさえ思いもよらないプログラミング初心者だった頃、LCC-Win32が手元にある唯一のグラフィカルな統合開発環境だった。
プログラミングに必要なツールが一通り揃っているのはもちろん、C言語チュートリアルやWin32SDKのヘルプ(これらは単独でも役に立つ)、それに、LCC-Win32でビルドできるサンプルソースを公開しているWebサイトもあるので、(ちょっと英語が読めれば)初心者でも手元に何も無い状態から始められるという点で画期的だった。
特にC言語チュートリアルは素晴らしかった。そこには開発者であるJacob Navia氏の意見があり、C言語や"昨日今日の言語"、メモリ管理と自動ガーベジコレクタに関する(今では古いかもしれない)熱い主張を見ることができた。当時の私が難解なWin32向けC言語プログラミングを続けられたのは、このチュートリアルが与えてくれた情熱のお陰なのだと、今でも思っている。
一方で当時ちょっと不安に感じたのは、「LCC-Win32で作ったソフトウェアを売って良いか」について、なぜかライセンス条項に明確な記述がなかったことだった(作ったソフトウェアの"著作権"が作成者にある、という記述はあったはず)。
私が自作したDLLを商用利用も可能な条件でユーザに配布したいと思った時に、どうしてもこの問題が引っ掛かり、あれこれ調べた末、最終的にはMinGWに乗り換えた。
あれから5年以上経った今、LCC-Win32のWebサイトのトップページには「License: 」が加わり、商用利用に関する細かい記述が並ぶ。閲覧者が何かダウンロードしたければ会員登録が必要で、それが無料だとしても、私は何もかも最初から自由にダウンロードできた当時と比べてしまい、どこか違和感を感じる。

2008-08-09

モノクロアニメをdrawLine()で描画する

「へらへらアニメ」を表示するアプレットを作ろうとした時に念頭にあったのは、できるだけ沢山のパソコン上で楽しめるようにしたいということで、当時はWin9x+MSJavaという組合せも考慮する必要があった。これは、Java1.1.x互換なコードを書く必要があることを意味する。
AWTの解説書やWebサイトで調べてみると、ビットやバイトで構成されたイメージでアニメーションをやりたい場合、MemoryImageSourceを使うのが手堅いやり方のようだった。さらにJava APIのドキュメントを読んでみて、MemoryImageSourceでやるしかないのだと確信した。
そこで、実際にアプレットを作って動かしてみた。

なんか変だ。

アニメーション自体の速度がGIFアニメよりも若干まずい点は、まあ、そういうものだと諦めるとしても、定期的に極端に低速になるというか、何かがロックされているかのごとくカクカクした動きになることがあって、このままだとソフトウェアの不具合だとみなされてしまいかねない動きだったので、さすがに公開はしなかった。
注意しておくと、AWTの解説書もWebサイトもJava APIドキュメントも、全く落ち度はない。異なるスペックのパソコンを借りたりして調べた限りでは、どうもWin9xがプリインストールされたマシンをそのまま使い続けているような古い環境だと上記の問題が起こるようだった。
困ったことに、調べたり人に聞いたりしてもこの問題の原因は分からなかった。
あれこれ変な方法を試したり失敗したりを繰り返した末に、一番あり得ない手段だと思っていた、drawLine()で左から右へ線を何度も引くやり方でイメージを描画することにした。すると、確かに速度がまずくなる瞬間は発生するものの、MemoryImageSourceを使った時よりはずっとマシになっていた。
結局、drawLine()で描画する方を公開することにした。それから忙しくなったりパソコンが変わったりしているうちに、MemoryImageSourceを使った方のソースはどこかに行ってしまった。
現在公開されている「へらへらアニメ」用のアプレットはdrawLine()で描画されていて、今でも問題なく動いている。が、いまだにこのやり方が本当に良かったのかどうか疑問に思うことがある。

2008-08-03

文字エンコーディング名かCharsetか

Javaでテキスト処理をする時に、
Reader createReader(String fileName, String encoding)
なメソッドを書いていて思った。
最近はjava.nio.charset.Charsetがあるので、以下のようにも書ける。
Reader createReader(String fileName, Charset charset)
後者はちゃんと目的に特化したクラスを使っているので、前者よりも手堅い印象がある。特に、文字エンコーディング名がCharsetに変換される時の例外処理をcreateReader()が抱えなくて済むという安心感がある。
一方で、createReader()を使う側としては、前者のオーバーライドも用意しておいてくれた方が便利でうれしい。

似たような話は、以下のような場合にも出てくる。
  • ファイルパスかjava.io.Fileか
  • URLかjava.net.URLか(URIの場合も同様)
実装する前にちょっと考えないと、チェック処理の責任が色んなメソッドに波及して面倒なんだよね...。

いつの間に文字列は汎用データ型みたいになったんだろう。
Win32 APIをC言語から利用する場合、32ビット整数が色んなオブジェクトやら何やらを表していて(ハンドルとかいった)、持ち運び易い反面、危なっかしいところがあった。(Win32 APIを使うスクリプト言語まで同様のやり方でリソース管理するようユーザに要求する流れが現れたことで、問題はさらにややこしくなる...)

2008-08-02

MinGWのサイトがリニューアル中

Win9X向けのソフトを作り始めた頃から、大変お世話になっているサイト。
久しぶりに覗いてみたら、ど真ん中にMySQLのエラーメッセージが...。
8/3 追記: 直ってた。

MinGW
http://www.mingw.org/

2008-07-27

Bloggerの改行タグ設定をOFFにしてみた

過去の投稿まで<br />タグが付かなくなった...。
まだBloggerを使い始めて間もないので、手作業で地道に修正。

2008-07-22

(x == undefined)と(typeof x == 'undefined')は同じだと思ってた

単純な比較結果で満足してた。
>jrunscript
js> var a = undefined;
js> if (a == undefined) {println('a == undefined');}
js> a == undefined
js> if (typeof a == 'undefined') {println("typeof a == 'undefined'");}
js> typeof a == 'undefined'
後で変数aをnullにしてみて、気が付いた。
js> a = null;
js> if (a == undefined) {println('a == undefined');}
js> a == undefined
js> if (typeof a == 'undefined') {println("typeof a == 'undefined'");}
js> (変数aは未定義ではないので、何も出力されない)
ちなみに、undefined変数は、Java6付属のRhinoでも書き換え可能だった。
なので、結果が確実そうな(typeof 変数 == 'undefined')を使うとして、文字列比較のパフォーマンスを気にする必要はあるんだろうか?
今はちょっとした書き捨てスクリプトに使っている程度なので、特に問題なさそうだ。

Rhinoのソースファイルを見ると、同じオブジェクト参照同士の同値比較ならJavaの==で片付けてもらえたと思うので、事前に(typeof 変数名)の返す文字列をキャッシュしておいて、以降の比較に使えば速いのかな、とか思ったものの、そんな細工が必要になるほどシビアな使い方をすることは無い...と思う。

2008-07-21

RhinoのContext.evaluateString()は行番号を設定できたのだが

ScriptEngine.eval()に行番号を渡すオーバーロードがなかったので、ちょっとしたフィルタプログラムを作ろうとした時に困った。

自分のWebサイトのHTMLファイルを、埋め込みスクリプトのやり方で静的に生成したいと思った時、当初は埋め込みタグをScriptEngine.eval(java.lang.String)で再帰的に評価する方法を考えていた。

<% //内側の埋め込みスクリプトの結果を外側でさらに利用する
    var ret = "<%=内側のスクリプト%>";
    ...
%>
これは変なやり方だし、フィルタプログラムのソースも込み入ったものになるのだけれど、当時は、わざわざ自作するならC言語のマクロとかでいわれた「プリプロセッサの結果をプリプロセッサに書けることはできない」に対応する必要があるんじゃないかと思っていた。
また、こっちの方が評価される範囲が明示的で、スクリプト例外の起こりうる箇所を(埋め込みタグを飛び越えてforやwhileなどの制御構文を使うよりは)特定しやすい、とも思っていた。

問題は、埋め込みタグを評価する度に行番号が初期値に戻ってしまうので、スクリプト例外が発生した時、問題の発生箇所を示す行番号がファイル全体から見た行番号になっていない、ということだった。

これに対応しようとあれこれ調べたものの、
  • 評価するスクリプトの行番号(のオフセット)をContext.evaluateString()みたいに渡すことはできない
  • ScriptExceptionがコンストラクタの時点で行番号付きメッセージを作成しちゃってる
ので、泥臭い対処法としては、ScriptExceptionのメッセージを取得した後、「行番号っぽい箇所」を本当の行番号で置換してから表示すれば何とかなるようだ。うーん。

結局、最終的に作ったフィルタプログラムは、よくある埋め込みスクリプトと同じものになった。
日付: <%=new java.util.Date()%>
=> g_out.print('日付: ');g_out.print(new java.util.Date());g_out.print(' ');
=> 日付: Mon Jul 21 13:27:17 JST 2008

このやり方だと、(JSPみたいに)うっかり床を踏み抜いた時の問題があるものの、今の使い方はテキストの一部を変数で置き換えたりファイルの日付を自動取得したりしているだけなので、まあ、滞りなく使えている。

RhinoでcloseStream関数に相当するものが欲しかった

// 入出力例外をスローしないclose()
function doClose(stream) {
    if (stream) {
        try {
            stream.close();
        } catch(e) {
            // 入出力例外をダンプ?
            java.lang.System.err.println(e);
        }
    }
}
JavaScriptはJavaよりも幅広くcatchするということを忘れていた。
function doClose(stream) {
    // 使い方次第ではCloseableかどうか調べた方が確実かも
    if (stream) {
        try {
            stream.close();
        } catch(e if e.javaException instanceof java.io.IOException) {
            // 入出力例外だけcatchして出力する
            var err = java.lang.System.err;
            err.println(e.message);
            err.println(e.stack);
        }
    }
}
今使っている書き捨てスクリプトで問題なく動いている。
(2012-09-19: 条件付きcatchを使うように変更した。変更前は、スローされたオブジェクトを全てcatchして目的外のオブジェクトなら再スローするように記述していたが、これは冗長だった)

2008-07-20

load関数は除かないで欲しかった

従来のRhino(js.jar)からJava6のスクリプトエンジンに切り替えた時に一番ビビった。
いずれ標準的な方法にまとまるのだろうけれど、それまでの間はjs.jarとの互換性からいってもload()みたいな機能が標準で残っていた方がありがたいわけで。

Using JavaScript code modules
http://developer.mozilla.org/ja/docs/Using_JavaScript_code_modules

ScriptEngine#eval(Reader)を使えば20行程度で自作できるものの、一度標準っぽく搭載されていた機能をスクリプトエンジンの利用者それぞれにコピペやら再実装させるのは、悩ましいやり方の気がする。
※jrunscript経由でスクリプトを実行する場合は、スタートアップスクリプトのお陰で使える。スクリプトエンジンからロードできると助かるのだけれど、出来るのかどうか分からない。

Mozilla Rhinoを使ってみて、とりあえずハマったこと(と、その対策)

問題1. Javaクラスのコンストラクタがambiguousとかいうエラーが発生する
問題2. Javaクラスのメソッドがambiguousとかいうエラーが発生する
問題3. Javaの文字列とJavaScriptの文字列が混在した時に、JavaScript向けの関数でエラーが発生する

(2012-09-16更新: mozilla.orgに上記3つの対応方法を説明したページがあったのだが、いつのまにか無くなってしまったようだ。http://www.mozilla.org/js/liveconnect/lc3_method_overloading.html)

対策1. new java.io.File["(java.lang.String)"](fileName); のように直接シグネチャを指定する
対策2. java.lang.String["valueOf(java.lang.Object)"](null); のように直接シグネチャを指定する
対策3. String(obj).replace(/regex/, "repstr"); のようにString(変数)でJavaScriptの文字列に変換する

どこまで厳密に対応するかは、作るスクリプトの役割次第。

細々と初めてみました

まだBlogger自体の使い方とか手探り状態ですが、
まあ、書いた日本語が表示できてれば何とかなるんじゃないかと。