<< 1月 2010 | Home | 3月 2010 >>
PR: 転職    ドメイン    電子機器    インプラント    転職サイト    ダイエット 食事    転職    コンタクトレンズ    流行キーワード    英会話   

猫ページ

猫ページ更新完了。

Akumaで、Javaプログラムをデーモン化

Akumaを使用した、Javaプログラムのデーモン化を実験してみた。環境は、Ubunt 9.10 AMD64 IBM版Java 1.6.0(build pxa6460sr5-20090529_04(SR5))。

Akumaは、https://akuma.dev.java.net/からakuma-1.3-jar-with-dependencies.jarを入手。ファイル名が長いんで、akuma-all-1.3.jarにリネーム。

サイトに掲載されているサンプルは、クラス名が間違っているようで、Demonizerというのを、Daemonに直してやると動くようになった。とりあえず、以下のように/tmp/test.logにHelloと書き続けるデーモンを作成。

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;

import com.sun.akuma.Daemon;

public class Test {
public static final File PID_FILE = new File("/var/run/test.pid");

public static void main(String[] args) throws Exception {
System.err.println("(1)");
Daemon d = new Daemon();
if (d.isDaemonized()) {
System.err.println("(2)");
d.init(PID_FILE.getAbsolutePath());
}
else {
System.err.println("(3)");
d.daemonize();
System.exit(0);
}

System.err.println("(4)");
BufferedWriter wr = new BufferedWriter(new FileWriter("/tmp/test.log"));
while (true) {
wr.append("Hello");
wr.newLine();
wr.flush();
Thread.sleep(2000);
}
}
}

プロセスを終了する時に、自動クローズされるので、ファイルのクローズは省略。気になる人は、Runtime.addShutdownHook()してください(かなり面倒になるけど)。これを、以下のコマンドで起動。

sudo java -cp bin:akuma-all-1.3.jar Test

 

init()にファイルパスを与えると、デーモンのpidが記録される。/tmp/test.logを観察すると、サイズが増えていくので、動いている模様。ちなみに動かした時の画面は、こんな感じ。

 

shanai@shanai-laptop:~/java/akuma-test$ java -cp bin:akuma-all-1.3.jar Test
(1)
(3)
shanai@shanai-laptop:~/java/akuma-test$ (1)
(2)

動きとしては、最初は、デーモン化されていないから、elseの方に入り、demonize()が実行され、ここでforkして終了。forkされた方は、if()の方に入った後、(4)を実行する。ただ、init()で標準入出力が閉じられるので、表示は行われない、という感じのようだ。psで確認すると、

shanai@shanai-laptop:~/java/akuma-test$ ps auxw | grep akuma
shanai 17509 3.2 0.8 690292 33180 ? Ssl 19:07 0:01 java -Dcom.sun akuma.Daemon=daemonized -cp bin:akuma-all-1.3.jar Test

システムプロパティを確認すれば、デーモンとして動いているかどうか、Javaで確認することも可能のようだ。あとは自分で、psとkillで運用しても良いのだけど、ちょっと面倒だ。これだと二重起動を防ぐこともできない。そこでデーモン起動、終了のスクリプトを作ってみる。Ubuntuには、start-stop-daemonというのが用意されているので、これを使うのが簡単そう。以下は開始用のスクリプト。

--- start.sh ---
#!/bin/sh

start-stop-daemon --oknodo --pidfile /var/run/test.pid --exec /home/shanai/bin/java --start -- -cp /home/shanai/java/akuma-test/bin:/home/shanai/java/akuma-test/akuma-all-1.3.jar Test

--oknodoは、すでにプロセスが上がっていた時でも終了ステータスを0にするもの。

--pidfileは、上でTestデーモンが作成した、pidが書かれたファイルだが、start-stop-daemonは内容については関知しない。何に使うかというと、start-stop-daemonが、デーモンのプロセスを特定するために使用する。このファイルを作ったプロセスであれば、start-stop-daemonが対象とするデーモンプロセスであると識別するのだ。

--execは、実行するプログラムの指定であると同時に、デーモンの特定にも使用される。もしも、上で説明した--pidfileが指定されていないと、--execに指定した/home/shanai/bin/javaだけで識別してしまうので、javaで動かすデーモンが複数あったら、識別できなくなってしまう

--startの指定は、デーモンの起動を指定している。--オプションの後に書いた内容は、デーモンプロセスにそのまま渡される。

これを、sudo ./start.shで起動すると、

shanai@shanai-laptop:~/java/akuma-test$ sudo ./start.sh
[sudo] password for shanai:
(1)
(3)
shanai@shanai-laptop:~/java/akuma-test$ (1)
(2)

直接起動した時と同じように、起動される。もう一度起動しようとすると、

shanai@shanai-laptop:~/java/akuma-test$ sudo ./start.sh
/home/shanai/bin/java already running.

このように二重起動を防いでくれる。次に状態を調べるコマンドを作成する。

--- status.sh ---
#!/bin/sh
set -e

. /lib/lsb/init-functions

status_of_proc -p /var/run/test.pid /home/shanai/bin/java akuma-test

/etc/init.dを眺めてみたら、status_of_procという関数があるらしいので、ありがたく使わせてもらう。これは、/lib/lsb/init-functionsに入っている。第3パラメータは、このコマンドが表示する時に使う名前なので、好きなものを使えば良い。これを起動すると、

shanai@shanai-laptop:~/java/akuma-test$ sudo ./status.sh
* akuma-test is running

最後にデーモンを止めるためのスクリプト。

#!/bin/sh

start-stop-daemon --oknodo --pidfile /var/run/test.pid --stop --exec /home/shanai/bin/java

起動の時と同様に、start-stop-daemonを使う。今度は、--stopを指定して、停止する。停止した後に、status.shを起動してみると、

shanai@shanai-laptop:~/java/akuma-test$ sudo ./status.sh
* akuma-test is not running

ちゃんと停止していることが分かる。akumaのjarを見ると分かるように、様々な環境用の、dllやsoが同梱されているので、このjarファイルだけでok。この点、とても手軽で良くできているなと思う。

可変引数

可変引数を使っていると、可変引数を受け取りつつ、別のメソッドに引数を追加しながら引き渡すようなコードを書きたくなることが良くある。

static final String[] defaultArg = {...};

Foo(String... arg) {
super (defaultArg, arg);
}

コンパイラがこれ、許してくれればいいんだけど、残念ながらコンパイルエラー。super()呼ぶ前に自分で配列を作ろうかと思っても、super()呼び出しは先頭に置かなければならないという掟があるため、うまくいかない。でまぁ、こういう場合は、やはりビルダパターンかなと。

public class TypedVarArgBuilder<T> {
List<T> args = new ArrayList<T>(8);

public TypedVarArgBuilder<T> add(Collection<T> itr) {
args.addAll(itr);
return this;
}

public TypedVarArgBuilder<T> add(T... array) {
args.addAll(Arrays.asList(array));
return this;
}

public T[] build() {
...

はうっ、Generic array生成か。new T[size]というのは無理なんで、Array.newInstance()とか使うことになってしまう。引数リスト1つ作るたびにリフレクションは避けたいよねぇ。どうもうまくいかないな。やはり配列をnewするファクトリを渡してもらうというあたりが落とし所かなぁ。

    public T[] build() {
return args.toArray(createArray(args.size()));
}

abstract protected T[] createArray(int size);
class Foo {
Foo(String... arg) {
for (String s: arg) System.out.println(s);
}
}

public class Bar extends Foo {
static final String[] defaultArg = {"Hello", "World"};

Bar(String... arg) {
super (new TypedVarArgBuilder<String>() {
protected String[] createArray(int size) {
return new String[size];
}
}
.add(defaultArg)
.add(arg)
.build());
}

public static void main(String[] args) {
new Bar("Foo", "Bar");
}
}

う〜んメンドイな。あとは実行時にバイトコード生成するか。さすがにやり過ぎな気がする。

猫ページ

猫ページ更新完了。

エシャロット


エシャロットで乾杯。

サンシャイン牧場データ

jQueryの勉強を兼ねて、ついカッとなって、サンシャイン牧場データを作成。今後はサーバサイドはデータだけ作って、プレゼンテーションは、JavaScriptって感じになるんかな。

猫カメラ復活

猫カメラ復活。Zaurusを引退させてから、無線のセキュリティをようやくWEPから、WPA2に切り替え。そのままライブカメラの設定を変えるのを忘れていたのだけど、今日やっと切り替えた。

さっそく、うっとんを乗せてみたら、そのままうたた寝。寝ぼけて頭がずり落ちていたりして、おもしろい。

池上梅園

近所の池上梅園へ。ちょっと早くて3分咲きといった感じだけど、花も痛んでいないし、すいているしで割と良かったかも。寒かったけど。





































































このサイトの掲載内容は私自身の見解であり、必ずしもIBMの立場、戦略、意見を代表するものではありません。
日本アイ・ビー・エム 花井 志生 Since 1997.6.8