リアルタイムシステムで多く使われているWatchdogパターンです。
Watchdogとは、装置を監視したりするプログラムで、他のプログラムから一定の間隔でポーリングや電文の応答を行う機能です。Watchdogプログラム内で、装置のエラーや電文シーケンスのアンマッチなどを見つけると、これらの送り手であるプログラムに通知を行います。
通知は、サービスのリセットやシャットダウンなどが考えられます。組み込み系のプログラミングテクニックとしては、定番になっています。
それでは、具体的にサンプルを見ていきます。この例では、サービスを受けるクラスをChannel、監視を行うのは Watchdogとしました。
図1のクラス図からわかるように、Channelオブジェクトは複数存在できる仕様にしたいので、多重度を使用して表現しています。実際のJavaのコード上では、わかりやすくするためにひとつしか生成していません。
それでは、シーケンス図によるメッセージのやりとりは、図2のようになります。
WatchdogオブジェクトからStart()メッセージをChannelに送り、サービスを開始します。
その後にRequest(1)としてシーケンス番号(1)の電文を送り、番号(2)の電文も続けます。
また、Watchdogオブジェクトでエラーを検出したときには、error()により Restart()メッセージをChannelに送り、サービスをリセットします。実際のJavaのコードは次のようになります。
WatchdogサンプルのJavaコード
class Channel extends Object{
PrintPanel pt = new PrintPanel();
void Start(Watchdog wd){
pt.Print("Start");
wd.Request(1); //1番目の電文を送信
wd.Request(2); //2番目の電文を送信
}
void Restart(Watchdog wd){
pt.Print("Restart");
this.Start(wd);
}
}
class Watchdog extends Object{
Channel channel;
int seq=0; //電文シーケンス番号のチェック用
PrintPanel pt = new PrintPanel();
Watchdog(){
channel=new Channel();
}
void Connect(){
channel.Start(this);
}
void Request(int s){
if (s != seq+1){
this.error();
}
else{
seq = s;
pt.Print("Sequesnce No:"+seq);
}
}
void error(){
pt.Print("Error");
seq=0;
channel.Restart(this);
}
}
class PrintPanel{
void Print(String s){
System.out.println(s);
}
}
Watchdogサンプルのメイン部分
Watchdog wd;
wd = new Watchdog();
wd.Connect();
エラーが起こったときに、wd.error();
Watchdogオブジェクトがメイン部分で生成されると、ChannelオブジェクトもWatchdogの中で作られます。
サービスの開始を始めたいので、この場合はwd.Connect()を呼び出して、その中でStart()メッセージをChannelに送っています。そうすると図2のシーケンス図の通り、Request(1)、Request(2)として電文をシーケンス番号を付加して送ります。この時の送り先のWatchdogオブジェクトは、 Start(this)として、引数で渡してやります。
ここでは、電文を受け取ったWatchdogオブジェクトは、単純にRequest()の中でシーケンス番号のチェックをしているだけです。さらに、メイン部分でWatchdogオブジェクトにエラーが起きた場合は、wd.error()として、この error()の中でChannelオブジェクトにRestart()を送り、リセットを行います。
このように、装置を監視するようなオブジェクトがある場合に、Watchdogパターンを有効に使うことができます。このWatchdogパターンは、「REAL-TIME UML」Addison -Wesley刊で解説されています。