Aglets Specification 1.1 Draft


Draft 0.55
1998 年 7 月 2 日
著者: Mitsuru OshimaGuenter Karjoth
コメントの送付先 aglets@yamato.ibm.co.jp.
本仕様書はドラフトであり、内容が変更される可能性があります。
更新記録
Draft 0.05
限られた対象向けに配布されたごく初期のドラフト。
Draft 0.06
リモートメッセージングについての説明、 Aglets のシリアライズ、 readObject/writeObject と listener の相違、システムアーキテクチャ、 Aglets サーバ API とクライアント API を追加。
Draft 0.07
Guenter Karjoth 博士の手によるメッセージングでのプライオリティとセキュリティについての説明を追加。
Draft 0.08
「 aglet API 概要」と題したセクションを追加。
ライフサイクル、メッセージング、移住 (migration) の章を更新。
美馬さんからのフィードバックを取り入れた。
Draft 0.09
「クラスローディングと移動 (mobility)」および「 proxy 経由の HTTP tunneling 」の章を追加。
Guenter Karjoth 博士と Mike McDonald さんによる内容確認。
「 Aglet サーバ APIとクライアント API 」の章の題名を「 Aglets によるアプリケーション構築」に変更。
Draft 0.1
本ドキュメントの最初のパブリックリリース作成。アーキテクチャの章は削除された。
Draft 0.11
「aglet トランスファプロトコル」と「 ATP でのスレッドの利用法」の二つの章を追加。
アーキテクチャの章とセキュリティの章の概要部分を更新。
Draft 0.12
「 Aglets によるアプリケーション構築」の章の内容を追加。.
Draft 0.20
パブリックドラフトの第二版。 Mike McDonald さんによる内容確認。
Draft 0.30
パッケージ名の変更およびベータ版への移行。
Draft 0.50
複数の章の題名変更および改訂。 (「オブジェクト移動 (mobility)」、「クラスローディングと移動 (mobility)」、「アーキテクチャ概要」。) 「aglet オブジェクトストラクチャ」追加。 「セキュリティ」の章では「ベータ」のセキュリティについて説明。
Draft 0.55
チケットの説明。

はじめに


概要

Aglets は、ネットワーク上をホストからホストへ移動することが可能な Java オブジェクトです。 あるホスト上で実行中の aglet が突然実行を中止してリモートのホストに発送され、そこで新たに実行を開始することが可能なわけです。 aglet の移動時には、運んでいるオブジェクトすべての状態だけでなく、プログラムコードも携帯します。 信頼できるか判らない aglet の受け入れの安全性をビルトインセキュリティメカニズムが提供します。

システムの目的


aglet オブジェクトモデル


aglet API 概要

aglet API はモバイルエージェントの基本的な機能を定義します。 aglet API で定義されたインタフェースおよびクラスの主なものとその関係を下図に示します。
com.ibm.aglet.Aglet

Aglet 抽象クラスは、モバイルエージェントの移動 (mobility) とライフサイクルをコントロールするために利用される基本的なクラス (dispatch(URL) 等) を定義します。 Aglet で定義された移動エージェントはすべて この抽象クラスを拡張する必要があります。 Aglet.dispatch(URL) プリミティブは aglet をローカルマシンから argument で指定された destination に移動させます。 Aglet.deactivate(long time) プリミティブは aglet を二次記憶装置に保存します。 Aglet.clone() プリミティブは、元の aglet と同じ状態を持つ aglet のインスタンスを生成します。 clone プリミティブが返すオブジェクトは Aglet オブジェクトではなく AgletProxy オブジェクトであることに注意してください。

Aglet クラスは aglet に関連付けられた属性にアクセスする場合にも利用されます。 Aglet.getAgletInfo() プリミティブによって取得される com.ibm.aglet.AgletInfo オブジェクトは、 aglet の到着時刻やカレントコンテキストの address 等のような動的な属性だけでなく、 aglet の生成時刻やコードベース等の aglet の継承属性を保有しています。

基本的なメソッドとそのセマンティクスを以下の表に示します。
Method Behavior
dispose() aglet を処分する。
dispatch(URL) aglet を URL で指定された destination に発送する。
deactivate(long duration) 自分自身を persistent medium で保存するように aglet に指示する。
getAgletInfo() aglet の情報を取得する。

com.ibm.aglet.AgletID

aglet インスタンスはすべて、その aglet のライフサイクルの中で変わることのないユニークな ID を持っています。 ID は、ユーザ ID やエージェントシステムのタイプ、なんらかの大きな数字等の複数の属性から成ります。 AgletID は、 aglet の表現の詳細のカプセル化に際してエージェントの一意の ID を保つためのオブジェクトです。

com.ibm.aglet.AgletProxy

AgletProxy インタフェースオブジェクトは aglet のハンドルとして機能し、 aglet へのアクセスの一般的な方法を提供します。 aglet クラスは複数の public メソッドを持つため、セキュリティ上の問題から、他の aglet からのダイレクトなアクセスは避ける必要があります。他の aglet とコミュニケーションをとりたい場合にはまず proxy オブジェクトを取得し、その後このインタフェースを通して作用することになります。 言い換えると、 aglet proxy はエージェントを悪意のあるエージェントから守るための盾となるわけです。 proxy オブジェクトは呼び出しを受けると SecurityManager で呼び出したエージェントがそのメソッドの実行を許可されているかを調べます。 AgletProxy インタフェースのもう一つの重要な役割は、 location transparency を持つ aglet の提供です。 aglet がリモートのホストに駐在している場合、この aglet はリモートのホストに要求を転送しその返答をローカルホストに返します。

AgletProxy は以下の方法で取得可能です。

runtime ライブラリは AgletProxy インタフェースの実装の提供について責任を持ちます。これにより、 aglet プログラマはこのインタフェースを実装する必要がなくなりました。
com.ibm.aglet.AgletContext

AgletContext クラスは aglet を占有する runtime 環境へのインタフェースを提供します。 aglet はすべて、 Aglet.getAgletContext() プリミティブを通してカレントの AgletContext オブジェクトへのリファレンスを取得しこれをホストのコンテキストのアドレスや AgletProxy の enumeration 等のローカル情報の取得に利用したりそのコンテキスト中で新しい aglet を生成したりすることが可能です。 aglet が一度発送されると、カレントに占有されていたコンテキストオブジェクトはこれ以上利用することができなくなり、到着時には destination コンテキストオブジェクトが代わりに添付されます。

runtime ライブラリは、このインタフェースの実装の提供について責任を持ちます。これにより、 aglet プログラマはこのインタフェースを実装する必要がなくなりました。

com.ibm.aglet.Message

Aglet オブジェクトは Message クラスのオブジェクトを交換することでコミュニケーションをとります。 メッセージオブジェクトはそのメッセージの種別を示す String オブジェクトと任意のオブジェクトを argument として持ちます。 メッセージは Object AgletProxy.sendMessage(Message msg) FutureReply AgletProxy.sendAsyncMessage(Message msg) void AgletProxy.sendOnewayMessage(Message msg) のどれかを呼び出すことで aglet に送付することができ、 argument として Aglet.handleMessage(Message msg) に渡されます。 詳細については section on messaging をご覧ください。

com.ibm.aglet.Ticket

チケットオブジェクトは destination とトランスファの品質の両方を指定するために使われます。 言い換えれば、 aglet のトランスファの方法を定義するわけです。 チケットオブジェクトには destination、利用するプロトコル、タイムアウトや保証されるべき完全性 (integrity) やコンフィデンシャリティのレベル等のような品質情報を保持します。 このオブジェクトは、 destination を指定する方法として URL が使われる場合に利用されます。

com.ibm.aglet.FutureReply

FutureReply インタフェースのオブジェクトは非同期のメッセージ送信で返され、返答を受け取るための場所ホルダとして非同期に利用されます。 このインタフェースによって、受け手が返答が到着したかを判断し指定した時間内に返答が戻らない場合にも実行を続けることができるように指定したタイムアウト値まで返答を待つことが可能になります。

aglet の動作をコントロールするためのクラスやインタフェースについて次の節でさらに説明します。

Aglet クラスの拡張

以下に、抽象 Aglet クラスのサブクラスを定義するための一般的なガイドラインを示します。
  • ユーザ定義の Aglet クラスは com.ibm.aglet.Aglet クラスを拡張します。
  • 他の Aglet 実装クラスの拡張も可能です。
  • aglet のシリアライズプロセスをカスタマイズするために java.io.Externalizable インタフェースを実装することが可能です。 しかし、この場合 Aglet class で定義した状態を適切にシリアライズ/非シリアライズするために super.writeExternal および super.readExternal を呼び出す必要があります。
  • dispatch()getAgletContext() 等のように既に定義されている Aglet API は、既に最終的な状態で宣言されていますので override することはできません。
  • Aglet クラスのインスタンスはインスタンス化後に初期化されるため、一般の Java オブジェクトと異なりオブジェクトを初期化するためのコンストラクタを実装しません。代わりに onCreation メソッドを利用します。
  • java.io.Externalizable を実装する場合は、オブジェクトを確実に非シリアライズするために argument 無しの public コンストラクタが必要になります。 さらに、このコンストラクタは非シリアライズが発生するたびに毎回呼ばれるため、副作用を持たないことが求められます。
以下に紹介する Aglet クラスメソッドは、 aglet 毎に特定の振る舞いを実装することを許すためサブクラスに override されると仮定されています。
void Aglet.onCreation(Object init)

このメソッドは aglet のライフサイクルの中で一度だけ、その aglet が生成された時に呼ばれます。 Aglet API (dispatch(URL) 等) はコンストラクタ中に用意されていないので、 aglet プログラマは aglet の初期化のため onCreation(Object init) を使う必要があります。

void Aglet.onDisposing()

このメソッドは dispose() メソッドが呼ばれた直後に呼ばれます。 aglet はそれまでアロケートされていたリソースをすべて放棄することになります。処分に応じて追加動作を実行することも可能です。

void Aglet.run()

Aglet クラスの run() メソッドはインスタンスが生成された時および回復された時に毎回呼ばれます。 このメソッドはコンテキストを占有する時に毎回呼ばれるため、共通のタスクを定義するのに適した場所です。

boolean Aglet.handleMessage(Message msg);

aglet に送られたメッセージはすべて handleMessage メソッドに渡されます。 aglet プログラマは、入ってくるメッセージが既知のメッセージかを調べ、そのメッセージの種別に応じたタスクを実行することが可能です。

    public class HelloAglet extends Aglet {
        public void onCreation(Object init) {
            System.out.println("created!");
        }
        public void run() {
            System.out.println("hello!");
        }
        public boolean handleMessage(Message msg) {
            if (msg.sameKind("sayHelloAgain") {
                System.out.println("hello!");
                return true;
            }
            return false;
        }
        public void onDisposing() {
            System.out.println("bye!");
        }
    }

Aglet オブジェクトとそのライフサイクル

com.ibm.aglet.Aglet クラスは移動オブジェクトのための基本的な機能を提供します。 aglet (aglet オブジェクト) はすべてこのクラスのサブクラスのインスタンスでなければなりません。 aglet を利用するにはまずインスタンス化する必要があります。 aglet のインスタンスを新しく生成する方法は二通りあります。 一つ目は、 AgletContext.createAglet(URL codebase, String name, Object init) を呼び出すことでクラス定義からまったく新しい aglet をインスタンス化する方法です。 このプリミティブは指定したコンテキスト中での新しいインスタンスを生成し、必要な場合には初期化を行なって、 createAglet プリミティブに渡された初期化オブジェクトを伴う生成されたオブジェクトについて Aglet.onCreation(Object init) を呼び出します。 もう一つの方法は、 Aglet.clone() プリミティブを利用して既に存在している aglet のコピーを作成するというものです。 複製された aglet は元のものと同じ状態を持ちますが、異なった ID を与えるため、別の AgletID オブジェクトを持たせます。

aglet オブジェクトは一度生成されると、リモートのサーバに発送されたり、リモートのサーバから撤収されたり、非活性化されてセカンドストレージに移されたりした後、活性化されます。

aglet は Aglet.dispatch(URL dest) プリミティブを呼び出すことで自分自身をリモートのサーバに発送することができます。 正確に言えば、 aglet はaglet コンテキストを占有し実行中にこのコンテキストから他のものへ移動することが可能であるということです。 サーバは一つの Java VM 中で複数のコンテキストサーブする可能性があり、一つのホストが複数のサーバをサーブすることもありえるため、コンテキストは以下の集合によって名前を付けられています。
例:
   atp://aglets.ibm.com:1434/context_name
発送処理によって、 aglet は実行を中止してその内部状態とバイトコードをスタンダードフォームでシリアライズし、 destination へ移送させられます。 受け手側では、 受け取ったデータに応じて Java オブジェクトが再構築され、新しいスレッドがアサインされて実行されます。

aglet は永続的に動くことが可能です。 モバイル aglet は bit ストリーム中でシリアライズ可能である必要があるため、モバイル aglet はすべて本質的に永続が可能です。 Aglet.deactivate(long timeout) プリミティブは aglet をセカンドストレージに保管して、指定された時間 (ミリ秒単位)の間スリープを掛けます。 与えられた時間が過ぎるか、あるいは他のプログラムが活性化を要求するかすると aglet は非活性化されたのと同じコンテキスト中で活性化されます。

ガベージコレクタに自動的に解放される一般の Java オブジェクトと異なり、 aglet オブジェクトは活性化されているためごみとなるか否かを決定することができます。 aglet を kill するよう dispose() メソッドを呼べば、対象となる aglet の現在の状態に適した終了作業を実行するための onDisposing() が呼ばれます。 (これは、 Java でオブジェクトをガベージコレクションで回収させる finalizer() とは異なるものです。 ) ファイルデスクリプタや DB コネクション等アロケートしたリソースは自動的に解放されないため、 aglet プログラマには、リソースの解放を行なう責任があります。


インスタンスは一度消滅すると無効になり、それ以降このインスタンスを処理しようとすると SecurityException が返ります。(他の Exception クラスに置き換えられる可能性があります。).

aglet イベントと委譲イベントモデル

Java VM ではスタックフレームの保管やスレッドオブジェクトの回復等が許可されていません。 従って、スレッドオブジェクトがその実行状態を維持したまま一つの JVM から他に移住するのは不可能です。
それに対して、 Aglets は移住 (migration) をエミュレートする action の実装の手段をプログラマに与えるためにイベントモデルを利用します。 aglet が発送される時、 Aglet runtime システムは対象となる aglet に発送されたことまたは destination に到着しようとしていることを notify するための関連イベントを発行します。
例として、 Aglet クラスを拡張する MobilityListener インタフェースと MyAglet とを実装する MyListener クラスを定義するコードを以下に示します。
    import com.ibm.aglet.Aglet;
    import com.ibm.aglet.event.MobilityEvent;
    import com.ibm.aglet.event.MobilityListener;
    class MyListener implements MobilityListener {
        public void onDispatching(MobilityEvent l) {
            closeWindow();
            closeFile();
        }
        public void onReverting(MobilityEvent l) {
            openWindow();
            donNextJob();
        }
        public void onArrival(MobilityEvent l) {
        }
    }
    public class MyAglet extends Aglet {
        public void onCreation(Object init) {
            MobilityListener listener = new MyListener();
            addMobilityListener(listener);            
        }
    }

MyListener オブジェクトの onDispatching() メソッドは aglet が実際に発送される前に、 onArrival() メソッドは aglet が destination に到着した後に呼ばれます。 aglet が複数の listener を持つ場合には、添付された順に呼び出されます。 このようにして、 aglet プログラマは後に続くイベントに応じて実行される onDispatching のような action を、 aglet がいつ誰に発送されたかに関係なく実装することができます。

状況 イベントオブジェクト Listener 呼ばれるメソッド
複製 (clone) を生成する直前 CloneEvent CloneListener onCloning
複製 (clone) が生成された時 CloneEvent CloneListener onClone
複製 (clone) が生成された後 CloneEvent CloneListener onCloned
発送の直前 MobilityEvent MobilityListener onDispatching
撤収の直前 MobilityEvent MobilityListener onReverting
destination への到着後 MobilityEvent MobilityListener onArrival
非活性化の直前 PersistencyEvent PersistencyListener onDeactivating
活性化した後 PersistencyEvent PersistencyListener onActivation
複数の listener オブジェクトを追加することが可能です。 複雑なタスクは、他の aglet がそのいくつかを拒否するということが可能なように複数の listener に分けることができます。 例として RegistryAglet に登録された location の情報を更新する Updater クラスを定義するコードを以下に示します。 この listener オブジェクトはプラグ可能なため、 runtime に追加される可能性があり、しかもすべての aglet が利用するものです。
    public class Updater extends MobilityAdapter {
        AgletProxy _finder;
        Message _update_msg = new Message("update");
        public Updater(AgletProxy finder, String name) {
            _finder = finder;
            _update_msg.setArg("name", name);
        }
        public void onArrival(MobilityEvent ev) {
            try {
                _update_msg.setArg("proxy", ev.getAgletProxy());
                _finder.sendMessage(_update_msg);
            } catch (Exception ex) {
            }       
        }
        public void removeFromRegistry() {
            try {
                Message remove = new Message("remove");
                remove.setArg("name", _update_msg.getArg("name"));
                _finder.sendMessage( remove );
            } catch (Exception ex) {
            }
        }
    }
    public class Registry extends Aglet {
        Hashtable _registry = new Hashtable();
        public boolean handleMessage(msg msg) {
            if (msg.sameKind("Lookup") {
                msg.sendReply(_registry.get(msg.getArg("name")));
            } else if (msg.sameKind("Update") {
                _registry.put(msg.getArg("name"), msg.getArg("proxy"));
            } else if (msg.sameKind("Remove") {
                _registry.remove(msg.getArg("name"));
            } else return false;
            return true;
        }
    }
これらの listener オブジェクトはシーケンシャルに呼ばれるということをプログラマは心に留めておく必要があります。 このため、後から追加された listener オブジェクトは、それ以前の listener の振る舞いによっては呼ばれないことがあります。 例えば、 listener オブジェクトが onArrival で対象となっている aglet を消滅させた場合、それ以降の listener は呼ばれることはありません。
これらのイベントのコールバックも同様にキューに入れられ一つずつ処理されることに注意してください。 現在のメッセージの処理が完了するまではコールバックを受け取ることはできません。 詳細については「aglets でのメッセージング」の章をご覧ください。

オブジェクトの移動 (Mobility)

aglet オブジェクトのシリアライズ

aglet が発送、複製または非活性化される時、 aglet は byte 配列に整列させられ、その後解放されます。 aglet の整列および整列からの解放に、 Aglets はスタンダード Java ObujectSerialization メカニズムを利用しています。 シリアライズ実行中は、 aglet インスタンスから始まるオブジェクトグラフ中のオブジェクトはすべて整列させられるべき状態にあるとみなされます。 それゆえ、これらのオブジェクトは java.io.Serializable インタフェースまたは java.io.Externalizable インタフェースを実装するか、あるいは transient として参照されるかしている必要があります。 オブジェクトグラフ中にシリアライズ可能でないオブジェクトが見つかった場合には、結果として java.io.NotSerializableException が投げられます。
   class ListingAglet extends Aglet {
       // result and its contents are transferred.
       private Vector result = new Vector();
       transient InputStream in = new InputStream(); // will not be transferred
   }

値に依って移動するオブジェクト

シリアライズ化および非シリアライズ化のプロセスにおいて、その状態の一部であるオブジェクトは普通に依って移動します。 この結果の一つとして、複数の aglet に共有されるオブジェクトは一度シリアライズ化されると、複製され、発送、複製、非活性化、活性化を施された後共有されなくなります。

参照に依って移動するオブジェクト

一方、 aglet の proxy はトランスファされる時に aglet の ID とアドレスを保持し、元の aglet への正しい参照を回復するためにこの情報を使います。 そのため AgletProxy オブジェクトは、 aglet が同じ location に駐在している間だけでなく、 proxy がリモートのホストにトランスファされたり非活性化されたりした場合でも正しい aglet への参照を保つことができます。

   class Transferrable implements java.io.Serializable {
       Hashtable hash; // Hashtable is also serializable
   }
   class NotTransferrable {
       int dummy;
   }
   class MyClass extends Aglet {
       transient FileDescriptor fd; // never get transferred.
       int value;  // moved by value
       String str; // moved by value
       Object transferable = new Transferrable(); // move by value
       Object not_transferable = new NonTransferable(); // throws NotSerializableException.
       AgletProxy proxy; // moved by reference
   }

クラス変数

クラス変数はオブジェクトの一部ではないので、クラス変数の値がシリアライズされることはありません。 従って、クラス変数は各クラスがローカルに持つものであり、aglet は新しい destination に到着すると異なった値を持つ可能性があります。

    public class MyAglet {
        static int class_variable = 0;
        public void onCreation(Object init) {
            class_variable = 10;
            dispatch("atp://next.place");
        }
        public void run() {
            if (class_variable != 10) {
                System.out.println("Class variable never get transferred!");
            }
        }
    }

RMI オブジェクトのトランスファ

RMI のリモートインタフェースは、リモートから呼び出し可能なメソッドを持つリモートオブジェクトを定義するために利用されます。 クライアント側の RMI オブジェクト (stub) は更新を必要とせずに Aglets ライブラリと仕事をすることができます。 aglet がリモートオブジェクトと共に発送された場合、リモートオブジェクトは aglet が整列から解放された時に自動的にサーバオブジェクトに戻ります。

しかし、 Aglets はサーバオブジェクトを取り扱うことはできません。 RMI のサーバオブジェクトのトランスファを行なうと、 destination サイトでこのサーバオブジェクトの複製を生成することになります。

  public class MyAglet extends Aglet {
      RMIHelloImpl impl = new RMIHelloImpl();
      String naming = "//naming.com/hello";
      public void onCreation(Object init) {
          java.rmi.Naming.rebind(naming, impl);
          addMobilityListener(new MobilityAdapter() {
              void onArrival(MobilityEvent ev) {
                  java.rmi.Naming.rebind(naming, impl);
                  impl.hello(); // calling local method
                                // It cannot be Stub anyway because it's impl!
              }
          });
      }
  }
これは、 JDK1.1 での RMI の制限です。 (JDK1.2 ではリモートオブジェクトの「 unexporting 」をサポートしており、この問題は解決されました。)

writeObject/readObject メソッドの実装

シリアライズ可能なオブジェクトについて writeObject/readObject メソッドをカスタマイズしようとする Aglet プログラマは、 writeObject() が aglet をサスペンドした後に呼ばれるのと違って onDispatching() は aglet 実行中に呼ばれることに注意する必要があります。 同様に readObject() は aglet が整列から解放されている間に呼ばれるため、 getAgletContext() のような aglet プリミティブは動作しません。 逆に、 onArrival() は aglet 全体の回復および活性化に成功した後に呼ばれるため、 Aglet API を呼ぶことが可能です。

aglet が発送された Proxy オブジェクト

現在のところ、 AgletProxy は動きまわる aglet を完全に把握することができません。 aglet が発送されてしまうと、それまで aglet を参照していた proxy は無効になります。 参照を貯蔵するためのメカニズムは将来提供される予定です。

Aglets でのメッセージング

アプリケーションや aglet は、メッセージを送信することで他の aglet とコミュニケーションをとることが可能です。 他の aglet とコミュニケーションをとろうとしている aglet は、まずメッセージオブジェクトを生成し、これをターゲットの aglet に送ります。 メッセージオブジェクトは kind とオプションで argument オブジェクトを持っています。 受け手 aglet は受け取ったメッセージのkind を調べて何をすべきかを決定し、パラメータを Aglet.handleMessage() メソッドの argument オブジェクトとして取得します。
    MyAglet extends Aglet {
        public boolean handleMessage(Message msg) {
            if (msg.sameKind("doJob")) {
                doJob();
            } else if (msg.sameKind("shutdown")) {
                deactivate(0);
            }
        }
    }
Aglets はメッセージ送信として以下のタイプをサポートしています。
Now-タイプ: AgletProxy.sendMessage(Message msg)
now-タイプのメッセージは同期的で、受け手がメッセージの取り扱いを完了するまで現在の実行をブロックします。
     String answer = proxy.sendMessage(new Message("question"));
     System.out.println(answer);
Future-タイプ: AgletProxy.sendAsyncMessage(Message msg)
future-タイプのメッセージは非同期的で、現在の実行をブロックすることはありません。 メソッドは、結果の取得または結果待ちをするのに利用される FutureReply オブジェクトを返します。
     FutureReply future =
         proxy.sendAsyncMessage(new Message("question"));
     int num_task = 10;
     // do private job at most 10 times while waiting for the result.
     while(future.isAvailable() == false && num_task-- >0) {
         doPrivateJob();
     }
     System.out.println( (String)future.getReply() );
注: aglet が自分自身にメッセージを送った場合、デッドロックを防ぐためそのメッセージはキューの最後尾ではなくキューの頭に置かれ即座に実行されます。
Oneway-タイプ: AgletProxy.sendOnewayMessage(Message msg)
oneway-タイプのメッセージは非同期的で、現在の実行をブロックすることはありません。 このタイプのメッセージは aglet が自分自身に送った場合でもキューの最後尾に置かれる点で future-タイプのメッセージと異なります。
       proxy.sendOnewayMessage(new Message("question"));
Delegation-タイプ: AgletProxy.delegateMessage(Message msg)
受け手 aglet は、入ってくるメッセージを取り扱うために handleMessage(Message msg) メソッドを定義する必要があります。 handleMessage() メソッドではメッセージオブジェクトは argument として渡され、そのメッセージの kind に応じた処理を実行するために利用されます。 このメソッドでは、取り扱われたか否かを示す boolean 値を返す必要があります。
    public boolean handleMessage(Message msg) {
        if (msg.sameKind("sayHello")) {
            System.out.println("Hello");
            return true; // i know this message...
        }
        return false; // false, otherwise
    }
false が返った場合には、メッセージの送り主は NotHandledException を受け取ることでこのメッセージが取り扱われなかったことを知ります。 oneway message が取り扱われたかを知る方法はありません。
    Future future = proxy.sendAsyncMessage();
    ...
    try {
        Object reply = future.getReply();
    } catch (NotHandledException ex) {
        // the receiver didn't handled the message
    } catch (MessageException ex) {
        // an exception has been thrown in the receiver's handleMessage()
        System.out.println(ex.getException());
    }
Aglets でのメッセージングは、 acknowledge-タイプの返答もサポートしています。 このタイプを利用することで受け手はそのメッセージの取り扱いを完了するよりも前に返答 (結果) を送ることが可能です。 返り値がある場合には、その値を返すためにこのインタフェースを利用する必要があります。 一度 Message.sendReply() メソッドを経由して返答を送ると二度と返答を送ることはできず、 handleMessage の返り値は無視されます。
    public boolean handleMessage(Message msg) {
        if (msg.sameKind("accessDB")) {
            openDB(); // pseudo code
            Object reply = accessDB(msg.getArg());
            msg.sendReply(reply);
            closeDB();
            return true; // i know this message...
        }
        return false; // false, otherwise
    }

メッセージキューとプライオリティ

aglet オブジェクトはすべてメッセージキューオブジェクトを持っています。 入ってくるメッセージはすべてこのメッセージキューに格納され、順番に取り扱われます。 Aglets でのメッセージングは transmission-ordering law に従い、メッセージは送られた順に到着します。 例えば、メッセージを「 A 」「 B 」「 C 」の順に送れば、受け手も同じ順に「 A 」「 B 」「 C 」と受け取るわけです。
                   キュー
         [A]  ->         {}: Aglet
         [B]  ->      {[A]}: Aglet
         [C]  ->   {[B][A]}: Aglet
                   {[C][B]}: Aglet ([A] 取り扱い中)
                      {[C]}: Aglet ([B] 取り扱い中)
                         {}: Aglet ([C] 取り扱い中)
メッセージには、 kind に応じたプライオリティを指定することができます。 プライオリティの高いメッセージは、プライオリティの低いメッセージよりも早く取り扱われます。 メッセージは並行して扱われるため、プライオリティは順序を保証しません。 あるメッセージが他のものよりも先に取り扱われる可能性を高くすることができるだけです。

今、キューの中にそれぞれ 3、 5、 6 というプライオリティを持つ 3 つのメッセージが入っているとし、さらに、プライオリティがそれぞれ 4 と 7 の 2 つのメッセージを非同期に送る場合を考えます。 先にプライオリティ 4 のメッセージを送った場合でも、プライオリティ 7 のメッセージの方が先に扱われます。

                 {[3][5][6]}: Aglet
       [4]  ->   {[3][5][6]}: Aglet
       [7]  ->   {[3][4][5]}: Aglet ([6] 取り扱い中)
              {[3][4][5][7]}: Aglet ([6] 取り扱い継続中)
                 {[3][4][5]}: Aglet ([7] 取り扱い中)
Aglets はプライオリティとしてメッセージをキューに入れない NOT_QUEUED もサポートしています。 今プライオリティとして NOT_QUEUED を持つメッセージ [D] が送られてきたとすると、このメッセージは aglet に直接渡されて即座に並列実行されることになります。
         [A]  ->         {}: Aglet
         [B]  ->      {[A]}: Aglet
         [D]  ->   {[B][A]}: Aglet
                      {[B]}: Aglet ([A] 取り扱い中) ([D] 取り扱い中)
                         {}: Aglet ([B] 取り扱い中) ([D] 取り扱い中)
                         {}: Aglet ([D] 取り扱い中)
メッセージのプライオリティは MessageManager.setPriority(String, int) プリミティブで設定することができ、エージェントの MessageManager オブジェクトは Aglet.getMessageManager() プリミティブ経由で取得することができます。

メッセージの同期化

メッセージは通常は一つずつ扱われますが、現時点でメッセージを扱っているスレッドが aglet の状態がある条件に合うようになるまで待たなければいけない、あるいは待ちに入っているスレッドや入ってくるメッセージに条件が整ったことを連絡しないといけないといったことは頻繁に起こります。 aglet メッセージング API は、 Java に似た方法でこれらの並列実行を表現するためのモニタをサポートしています。 aglet API はメッセージの同期化のために 5 つのメソッドを用意しています。
Aglet.waitMessage();

Aglet.waitMessage(long timeout);
Aglet.waitMessage() は、他のメッセージから実行再開の指示が出るまで現在のスレッドを待たせます。 モニタを所有するスレッドだけがこのメソッドを読んで待ちに入ることが可能です。 その他の場合には IllegalMonitorStateException が投げられます。

他のメッセージを扱っている他のスレッドが Aglet.notifyMessage() を呼んで待ちに入っているスレッドに再開の指示を出した場合、このスレッドは目覚めて実行を再開します。 待ちに入ったスレッドは、再開の指示が出なければ、止められるまで永遠に待ち続けます。 それに対して、待ち時間の最大値 timeout をミリ秒単位で指定してその時間が過ぎた後目覚める waitMessage(long timeout) も利用できます。

Aglet.notifyMessage();

Aglet.notifyAllMessages();
Aglet.notifyMessage() は、待ちに入っているスレッドに目覚めて実行を再開するよう指示します。 caller スレッドはメッセージキューの最初に置かれ、再開したスレッドがメッセージの扱いを完了するかモニタを抜けるかするまで待ちます。 メッセージ取り扱いモニタを所有するスレッドだけがこのメソッドを呼び出すことができます。 それ以外の場合には IllegalMonitorStateException が投げられます。
          キュー          待ち
        {[D][C]}: Aglet {[A][B]}
           {[D]}: Aglet {[A][B]} ([C] 取り扱い、notifyMessage() 呼び出し)
        {[D][C]}: Aglet {[B]} ([A] 取り扱い)
Aglet.notifyAllMessages() は、待ちに入っているスレッドすべてを順番に起こします。 起こされたスレッドはメッセージキューの最初に置かれ、一番振るい待ちスレッドが即座に再開されます。 caller スレッドは起こされたスレッドの次の位置に置かれ、再開されたスレッドが完了した後に再開されます。
        キュー           待ち
       {[D][C]}: Aglet {[A][B]}
          {[D]}: Aglet {[A][B]} ([C] 取り扱い、 notifyAllMessages() 呼び出し)
    {[D][C][B]}: Aglet ([A] 取り扱い)
Aglet.exitMonitor();
exitMonitor() メソッドは、現在実行しているスレッドに、そのスレッドが所有しているモニタを解放させます。 キューに次に入っているメッセージ (もしあれば) が次に実行されます。 exitMonitor() は入ってくるメッセージだけを活性化させ、待ちに入っているメッセージは活性化させません。
        キュー
       {[C][B]}: Aglet ([A]* 取り扱い、exitMonitor() 呼び出し)
          {[C]}: Aglet ([B]* 取り扱い) ([A] 取り扱い)
注: * はモニタの所有者を示します。
この API を利用することで、メッセージを受け取っている間のバックグラウンドタスクを実装することが可能です。
      public void SiteWatcherAglet extends Aglet {
          public void run() {
              exitMonitor(); // now the next message would start.
              while( condition == true) {
                  watchSite("http://home/index.html");
              }
          }
      }
以下の例「 StackAglet 」は、メッセージ間の同期化がどのようになされるかを示します。
    public StackAglet extends Aglets {
        static int capacity = 10;
        Object stack[] = new Object[capacity];
        int num = 0;
        public handleMessage(Message msg) {
            if (msg.sameKind("push")) {
                push(msg);
            } else if (msg.sameKind("pop")) {
                pop(msg);
            } else if (msg.sameKind("isFull")) {
                msg.sendReply( num == capacity);
            } else if (msg.sameKind("isEmpty")) {
                msg.sendReply( num == 0 );
            } else return false;
            return true;
        }
        private void push(Message msg) {
            while (num == capacity) {
                waitMessage();
            }
            stack[num++] = msg.getArg();
            if (num==1) {
                notifyMessage(); // wake up "pop" message
            }
        }
        private void pop(Message msg) {
           while(num==0) {
               waitMessage();
           }
           msg.sendReply(stack[--num]);
           if (num == (capacity -1)) {
               notifyMessage(); // wake up "push" message
           }
        }
    }

Aglets でのリモートメッセージング

Aglets はリモートメッセージ送信をサポートしており、 aglet オブジェクトはローカルにだけでなくリモートでもメッセージに依ってコミュニケーションをとることが可能です。 ローカルでのメッセージングの argument としてどんな kind のオブジェクトでも渡せたのと同様、リモートメッセージングで渡される argument や返り値も java.io.Serializable を実装する Java タイプであればどんなものでも可能で、 ObjectSerialization で整列したり整列から解放したりすることができます。 リモートメッセージの送付は、 リモートメッセージは byte コードのトランスファをおこさない点で aglet の発送とは異なり、メッセージで使われるクラスもそれぞれのホストでインストールされている必要があります。
リモートのメッセージ送信は異なるホストに駐在する aglet 間のコミュニケーションの軽い方法として利用することができ、接続が切れた場合の処理やホストとの強いインタラクション等、 aglet 発送が locality の点で有利なのに対して、ネットワークトラフィックやクラス定義のコスト、セキュリティ問題等を削減するというメリットを持っています。

Aglets での例外の取り扱い

T.B.D.

システムアーキテクチャ


アーキテクチャ概要

Aglets のアーキテクチャは 2 つのレイヤから成っており、それぞれの関数にアクセスするためのインタフェースを定義する 2 つの API を備えています。

Aglets の runtime レイヤは aglet API の実装で、 AgletProxy や AgletContext 等のような API コンポーネントの振る舞いを定義しています。 runtime レイヤは aglet の生成、管理、リモートのホストへの発送についての基本的な関数を提供しています。 コミュニケーションレイヤは基本的に、シリアライズ化されたエージェントを destination にトランスファしそれを受け取るということについての責任を担っています。 このレイヤは、エージェント間のコミュニケーションやエージェント管理の機能をもサポートしています。

Aglets Runtime レイヤ

Aglets runtime レイヤは AgletContext 等のような Aglets のインタフェースを実装します。 このレイヤはコアフレームワークとサブコンポーネントから成ります。 コアフレームワークは、以下に示す aglet 実行のメカニズムの基礎を提供します。 サブコンポーネントは、拡張およびカスタマイズが可能であるようにデザインされています。 これは、拡張やカスタマイズといったサービスが、要求される条件や環境によって異なると考えられるためです。 例えば、アプレットの PersistenceManager は非活性化した aglet をウェブサーバ上に格納できればそれを実行し、そうれなければメモリ中にしか格納しない、といったことが要求されることもあれば、ウェブブラウザで設定されたデフォルトのセキュリティマネージャを使わなければならないといったこともありえます。 これらのコンポーネントはインタフェースまたは抽象クラスとして定義されており、サーバ開発者はこれらのコンポーネントを自分自身の利用のために実装し runtime にプラグすることができます。 残念なことに、これらのコンポーネントのための API はサーバ開発者用を対象に作られており aglet アプリケーションプログラマ用ではないため、パブリックになっておらず、現状では一般のユーザは利用できません。

Communication Layer

The Aglets runtime itself has no communication mechanism for transferring the serialized data of an aglet to destinations. Instead, the Aglets runtime uses the communication API that abstracts the communication between agent systems. This API defines methods for creating and transferring agents, tracking agents, and managing agents in an agent-system- and protocol-independent way.

The current Aglets uses the Agent Transfer Protocol (ATP) as the default implementation of the communication layer. ATP is modeled on the HTTP protocol, and is an application-level protocol for transmission of mobile agents. To enable remote communication between agents, ATP also supports message-passing.

Communication API (MASIF for Java)

The communication API used by Aglets runtime is derived from the OMG standard, MASIF (Mobile Agent System Interoperability Facility), which allows various agent systems to interoperate. This interface abstracts the communication layer by defining interfaces and providing a common representation in Java that conforms to the IDL defined in the MASIF standard.
 // MAF IDL
 module MAF {
     .....
     struct Name {
         Authority           authority;
         Identity            identity;
         AgentSystemType     agent_system_type;
     };
     ....
     interface MAFAgentSystem {
         // Agent creation and transfer
         Name create_agent(in Name agent_name, ...) raises (..);
         void receive_agent(in Name agent_name,
                            in AgentProfile agent_profile,
                            in octet_string agent, ...) raises (..);
         // Agent management
         void get_agent_status(in Name agent_name) raises (..);
         void list_all_agents(in Name agent_name) raises (..);
         void suspend_agent(in Name agent_name) raises (..);
         void resume_agent(in Name agent_name) raises (..);
         void terminate_agent(in Name agent_name) raises (..);
         // etc...
     }
 }
Although MASIF interfaces are intended for CORBA objects, the interfaces actually defined in Aglets are not CORBA-based. In fact, they are defined as normal Java classes, interfaces or abstract classes that act as common wrappers for the protocols actually being used. Thus, it is possible and easy to use various kinds of protocol other than CORBA/IIOP such as ATP and RMI.

We chose this approach because relying on the specific transport protocol or the specific transport mechanisms has at least two disadvantages. First, it would be technically inadequate to require mobile agent systems to use a specific protocol unless it became pervasive and widely supported. One of the benefits of mobile agents is in their ability to hide the existence of network communication. Second, some Java environments such as PersonalJava have neither RMI nor CORBA as their core API. Therefore, it would be more practically desirable if the runtime could choose the communication mechanisms in accordance with its system requirements.

Communication Layer Architecture

The following figure shows the architecture of the communication layer. com.ibm.maf.MAFAgentSystem is an abstract class that defines a set of methods equivalent to the MASIF interface. There are two kinds of class that extend this abstract class. One is an implementation class that provides the agent system facility, and the other is a stub object that transfers a request to a destination.

An application or client uses a stub object to send a request to the destination. An agent system must have a stub class for each protocol it supports. Applications or clients can then get and use a stub object for a given protocol. Note that it is an agent system's responsibility to instantiate and manage stub objects. The latest beta (as of this writing) version of Aglets supports two protocols, ATP and RMI.

On the other hand, an aglet server has an implementation of MAFAgentSystem that actually handles the requests. It is the agent-system provider's responsibility to provide the implementation of MAFAgentSystem. Aglets has the com.ibm.aglets.MAFAgentSystem_AgletsImpl class as an implementation. Furthermore, a server has one or more daemons to accept requests from a sender. A server may support multiple protocols by having multiple daemons to handle each protocol. When a daemon accepts requests, it then forward these requests to the MAFAgentSytem_AgletsImpl.
Note: CORBA-based transport layer will be provided in a future release of Aglets.

Aglet Object Structure

An AgletRef object is an internal representation of an aglet object. It has all necessary components for the aglet a MessageManager to control incoming messages, and a ResourceManager to manage resources consumed by the aglet and to manage its related resources such as security information and the AgletInfo object. It is also the implementation of the abstract methods defined in Aglet class. It implements most of the functionality to be provided by the com.ibm.aglet.Aglet class. The AgletRef object is what the aglets framework deals with. The latter has a reference table to store the mapping from the AgletID to the actual aglet instance. An AgletRef object is created and inserted into this table when an aglet is created or arrives, and removed from it when the aglet is dispatched or disposed of.

Message Manager

An aglet has a MessageManager object, which governs all incoming messages sent to the aglet. The MessageManager manages and controls the order and concurrency of these messages. See the Messaging section for more details.

Resource Management

An aglet uses local resources such as files or threads to carry out its tasks during its lifetime. It may open a dialog window to interact with users, or create a new thread to perform some concurrent task.

These resources are managed by a ResourceManager object, which is allocated for each aglet. Currently all threads and windows created by the aglet are managed by this ResourceManager. When an aglet is dispatched, deactivated, or disposed of, these two resources are immediately stopped and disposed of. Other kinds of resources such as file and socket, however, are not captured by this manager. It is left to the garbage collector to decide whether or not such resources will be released, and if so when. Therefore, the programmer must release them manually to ensure their immediate release.

Garbage Collection of Aglet Objects

Unlike normal Java objects, aglets are never garbage-collected (GC) automatically, because an aglet is active and has its own threads of control. An aglet programmer needs to explicitly dispose of an aglet.

When an aglet has been dispatched, deactivated, or disposed of, the AgletRef object is removed from the reference table. In addition, the internal reference to that aglet and associated components such as MessageManager object or properties are set to null so that the garbage collector can sweep up these dangling objects.

This means that if you have a live reference to this aglet elsewhere, it will not be GCed. For example, if you have a reference to the static variable of the class, it will not be GCed.

    public MyAglet extends Aglet {
        static MyAglet aglet = null; // the previous one may be GCed.
        public void onCreation(Object init) {
            aglet = this; // keep the reference
        }
    }

Class Loading and Transfer

In mobile agent systems, classes for an agent need to be available at the server on which the agent is running. The class of an agent needs to be available at the server at the time of creation, and to be available at the destination to which it moves. Therefore, a mobile agent system needs to have a facility for loading bytecode on demand, or for transferring the bytecode along with the agent.

Aglets supports two schemes for transferring bytecode more efficiently ways, and also make use of a cache to reduce unnecessary downloading of classes. It is important for aglet programmers to understand class mobility, how a class is loaded, and when a class is transferred. The rules of class mobility are explained in the following sections:

Class Loading

In Aglets, a class for an aglet is determined dynamically at runtime; thus, the class for the aglet needs to be loaded dynamically on demand. This dynamic class-loading may also happen at certain points in the aglet's execution, such as when it is visiting other hosts as well as the original host.

Java has a special class, called ClassLoader, that is capable of defining a new class from bytecode. Once a class has been defined by the class loader, all requests for new classes within that class are handled by that class loader. Aglets has a dedicated subclass of ClassLoader, called AgletClassLoader. Each aglet is associated with exactly one class loader, and all classes required by the aglet are managed by that class loader. (Note that one class loader may manage multiple aglet instances.) Suppose there is an aglet

   Ex.1
   class MyAglet extends Aglets {
       MyDialog dialog = null;
       public void onCreation() {
           dialog = new MyDialog();
       }
   }
and that both MyAglet and MyDialog classes are placed in the codebase below:
atp://aglets.codeserver.com/public
In this example, both MyAglet and the MyDialog classes are managed by one AgletClassLoader.

How a class is chosen

There may be several sources of the bytecode of a given class. It is therefore worth understanding which class definition is actually chosen by the class loader and used. AgletClassLoader maintains a cache table for classes formerly defined by the class loader, and it first looks up a definition in that cache table. If a definition is not found in the cache , it asks the system class loader to load it from CLASSPATH (for security). If this is not successful either, it defines a new class by extracting bytecode from CacheManager if this is available, or by loading from the codebase otherwise. Once the new class has been defined, it is cached in the cache table and will be reused by other aglets later.

  Ex.2
  class MyAglet2 extends Aglets {
      MyDialog dialog = null;
      String str = "Hi";
      // LocalData is installed on the CLASSPATH
      LocalData data = new LocalData();
      public void onCreation(Object init) {
          dialog = new MyDialog();
      }
  }
If MyAglet2 is loaded by the same classloader of MyAglet, the cached class is used to resolve the MyDialog class. If it is loaded by a different classloader, it will use the bytecode in the CacheManager to define a new MyDialog class in the class loader. Since both the java.lang.String class and the LocalData class are locally available on the CLASSPATH, they will be loaded by the system class loader and then become system classes.

Class Transfer

As mentioned before, there are two possible ways of bringing bytecode to the server. The first is to download and define a class on demand after an aglet moves, and the second is to transfer bytecode as an agent moves. Aglets supports these two schemes, and in some case uses a combination of the two. This subsection illustrates the rules according to which classes are transferred.

Which Class is Transferred?

Since an aglet needs its classes in order to execute, it is very important to understand which class is transferred and which is resident, so as to ensure that the aglet can complete its execution. If even one of the necessary classes has not been transferred, execution of the aglets will fail.

Aglets classifies Java classes into four categories, according to where they came from, and manages them in different ways:

Archived Classes
Classes that are archived in the JAR file.
Codebase Classes
Classes that are loaded from the aglets' codebase.
System Classes
Classes that are loaded from CLASSPATH and thus do not have a codebase.
Others
An aglet might refer to other classes that are loaded from other codebases by other aglets. This happens when an aglet receives a message that includes as an argument an object whose class was loaded from the sender's codebase.
If the class is archived in the JAR file specified as the aglet's codebase, all bytecode in the archive are simply transferred as the aglet moves, and is stored in the CacheManager. Therefore, if MyAglet and MyDialog are archived in the JAR file, both files are transferred along with the aglet itself. Note that what is guaranteed is only that "bytecode" is transferred to and available at the destination. The class actually used by the aglet whose execution is resumed at the destination is chosen according to the above rule.

If no archive is specified, only classes loaded from the codebase are transferable along with the aglet. By this we mean that all classes located in the aglet's codebase can be transferred when it moves except when a class with the same name exists on the CLASSPATH. Such system classes are never transferred. In that of Ex.2, the bytecode of the LocalData class would never be transferred while that of MyDialog might be. The set of classes to be transferred are determined at runtime in the serialization process. That is, the classes of all objects visited during the serialization are collected and transferred.

Note that the class of a reference with null value is never transferred. So what happens if such a reference exists and the class is used after the aglet is dispatched? Let's take a look at an example:

   Ex.3
   class MyAglet extends Aglet {
       MyDialog dialog = null;
       public void onCreation(Object init) {
           addMobilityListener(new MobilityAdapter() {
                public void onArrival(MobilityEvent ev) {
                    // create MyDialog after arriving at the destination.
                    dialog = new MyDialog();
                }
           });
           dispatch(....);
       }
   }
Since the reference "dialog" is null, the MyDialog class is not transmitted when the aglet is dispatched. Instead, the aglet is sent without the MyDialog class and then searches for the MyDialog class after it arrives. Because it tries to load the class by following the class loading rule explained above, it may load the class definition from its codebase, or it may use the cached class, if any exists.

If you want to make sure that such classes are also transferred, you may include the class instance as its state, like this:

   Ex.4
   class MyAglet extends Aglet {
       MyDialog dialog = null;
       Class class_used_later = MyDialog.class;
   }
This forces the system to transmit MyDialog along with the aglet.

Finally, if an aglet attempts to transfer an object whose class loader is different from the aglet's class loader, it fails with a SecurityException. This is because Aglets does not allow an aglet either to load a class from two different codebases or to extract the bytecode from other aglets, for security reasons.

Class Resumption and Evolution

When an aglet arrives at the destination, bytecode in the stream is retrieved and cached in the CacheManager. They are then used by a ClassLoader to define the classes needed to reconstruct the aglet.

Since ClassLoader cannot define two classes with the same name, the old class already stored in the cache may be used even if the updated class has been sent. This would cause a problem in deserializing objects because the serialized data might not compatible with it. Even worse, the class will behave differently.

  Ex.5
  // old class
  class MyAglet extends Aglet {
     MyDialog dialog = new MyDialog();
  }
  // revised class
  class MyAglet extends Aglet {
      MyDialog dialog = new MyDialog();
      public void onCreation(Object init) {
          dialog.show();  // I forgot to show the dialog..
      }
  }
  # MyAglet must be used at the destination
Even if you fix the source code (Ex.5), you may get the same result as before because it might be cached. Therefore, a class definition must be forcibly updated as it evolves, while the cost of transmitting and defining new classes must be reduced. The Aglets solves this problem by allocating different class loaders for different sets of classes. In the following section, we describe how a class loader is chosen and when one is newly created.

To avoid the version conflict problem, Aglets sends the information on the version of a class as well as its name along with the class definition. AgletClassLoader also maintains this information in the cache. This version information is taken from the MANIFEST file in a JAR archive or computed at runtime.

With this information, the receiver can find out what classes are used within the aglet even before receiving all the bytecode. Thus, it can determine the class loader that matches the information in the "ClassLoader cache". Note that only classes sent along with the aglet are evaluated in searching the class loader. If an aglet requires another class that has not appeared in this version table since the aglet arrives (MyDialog in Ex.3), the same problem may occur.

Note that Aglets does not support the automatic version detection of aglets created from plain codebase (without JAR). You may therefore get an old version of classes. We recommend you to use a JAR archive if you want to make sure that the correct version is used for creation.

Other Considerations in Class Mobility

Efficiency

Not surprisingly, in most cases sending all classes would not be efficient, since it would consume unnecessary bandwidth. But if we can assume that the likelihood of the availability of classes is high, it would be possible to reduce the cost of transmitting an agent by not sending class definitions. This assumption may hold in most cases, since a mobile agent is quite often sent to the same destination.

The current Aglets, however, sends as much bytecode as possible, because the above scheme has several drawbacks and the *best* scheme is not yet established. For example,

We understand that there must be a more efficient way than the current approach, and such a scheme will be adopted as Aglets evolves.

Class Mobility in Remote Messaging

Aglets supports remote message passing, and aglet objects can communicate through messages remotely as well as locally. Parameter objects or return values passed by remote messaging can be of any Java type that implements java.io.Serializable or Java primitive types, and they can be marshaled and unmarshaled by ObjectSerialization. Sending a remote message is different from dispatching an aglet in the sense that a remote message does not cause any transfer of bytecode. Instead, the classes of objects passed along with a message must be available at both sites, either as the system class installed or as the aglets's codebase class.

Security

When bytecode is being transferred, the runtime consults the SecurityManager to determine whether the aglet is allowed to carry it out. When bytecode is carried in, the runtime consolts the SecurityManager to determine whether the aglet is allowed to carry the bytecode into the runtime and to define the class. Furthermore, a request from an aglet that left the server to fetch a class file must also be referred to the SecurityManager. If the requested file is not allowed to be fetched, the SecurityManager refuses the request.

Agent Transfer Protocol

ATP is a simple application-level protocol designed to transmit an agent in an agent-system-independent manner. An ATP request consists of a request line, header fields, and a content. The request line specifies the method of the request, while the header fields contain the parameters of the request. ATP defines the following four standard request methods:
Dispatch
The dispatch method requests a destination agent system to reconstruct an agent from the content of a request and to start executing the agent. If the request is successful, the sender must terminate the agent and release any resources consumed by it.
Retract
The retract method requests a destination agent system to send a specified agent back to the sender. The receiver is responsible for reconstructing and resuming the agent. If the agent is successfully transferred, the receiver must terminate the agent and release any resources consumed by it.
Fetch
The fetch method is similar to the GET method in HTTP; it requests a receiver to retrieve and send any identified information (normally class files).
Message
The message method is used to pass a message to an agent identified by a agent-id and to return a reply value in the response. Although the protocol adopts a request/reply form, it does not lay down any rules for a scheme of communication between agents.
See the ATP specification for more details.

HTTP Tunneling via Proxy Servers

The ATP layer normally attempts to make a direct connection to hosts on the network. In almost all intranet situations, however, there is a firewall that prevents users from opening a direct socket connection to an external node. This means that an aglet cannot be dispatched or retracted through the firewall. To make it possible, the ATP layer supports a technique called HTTP tunneling that enables an ATP request to be sent outside of the firewall as a HTTP POST request and the response to be retrieved as the HTTP response. In addition, the Aglets server has to be somehow capable of receiving that HTTP-wrapped ATP request. Therefore, the Aglets server can be configured so that it can receive an HTTP POST message with the content type "x-atp" and can unwrap the ATP request. If it receives an HTTP-wrapped ATP request, it sends an HTTP response in the same way.

Configuring a Sender

To send a HTTP tunneling request, you have to specify the HTTP proxy host to be used:
  1. Open the Network Configuration panel by selecting:

  2. Options -> Network Preference
  3. Check the "Use HTTP Proxy" in the "HTTP Tunneling" panel.
  4. Type the host name and port number of the proxy server.
  5. Input the beginning string or ending string of the address for which you do not want to use a proxy.
  6. Press the OK button

Configuring a Receiver

To receive an HTTP tunneling request, a receiver has to be configured so that it can receive an HTTP-wrapped ATP request:
    C
  1. Open the Network Configuration panel by selecting.

  2. Options -> Network Preference
  3. Check the "Accept HTTP Tunneling Request" in the "HTTP tunneling" panel.
  4. Press the OK button.

Limitation of HTTP Tunneling

Because the firewall allows only a one-way connection to the outside, the dispatched aglet cannot fetch a class on demand. Make sure that all necessary classes are stored in the stream and transferred to the destination either by making references to those classes inside the object, or by putting them into one JAR archive and specifying it as the aglet's codebase.

Furthermore, it is impossible for an aglet to dispatch itself back into the intranet through the firewall. To get back inside a firewall, an aglet has a unique primitive, called retract, which lets a client "pull" the dispatched aglet from a remote site. This allows you to dispatch an aglet outside the firewall and get it back into the intranet.


Aglets のセキュリティ


Security is essential to any mobile agent system, because accepting a hostile agent may lead to your computer being damaged or your privacy intruded upon. For secure agent execution, the agent system must provide the following security services:
Authentication of the Sender, the Manufacturer and the Owner of the Agent.
Who is responsible for this agent?
Who is responsible for the agent code?
Has the agent (code and state) been tampered with?
Authorization of the Agent (or Its Owner)
What can this agent do? (E.g, can this agent access files?)
Secure Communication between Agent Systems.
Can the agent protect its privacy?
Non-repudiation and Auditing.
How can we ensure that a deal has been actually carried out?
Security-sensitive activities of agents must be recorded, and an administrator must be able to audit them.
In mobile agent systems, agents must present proper user identities so that agent systems can control them according to the access rights of the users and the agent's manufacturers. It is therefore important for agent systems to be able to authenticate an agent's user and manufacturer. The former is much more difficult than the latterr. It is reasonably easy to identify the manufacturer by code-signing. However, it is difficult to verify the ownership of the agent since the state of the agent varies during its travels, and it is practically impossible to sign the state part of the agent.

Aglets uses an organizational approach whereby all agent systems in a certain domain are deemed trustworthy, and evaluates the authenticity of the agent depending on the domain in which it has been roaming around. A user first authenticates himself/herself to the system, and the system then issues the credentials of the user's agent. The agent system then evaluates the authenticity of the credentials, to determine whether or not they were issued within the same domain. It may downgrade the authenticity or simply deny access, depending on conditions such as where the agent has traveled and so forth. Host authentication is used to identify the domain to which the communicating host belongs.

Although the current Aglets does not fully support these services because of the limited support for encryption in JDK, it does provide a reasonable level of security to make it safe to use mobile agent applications. The following security features are supported in the latest Aglets runtime:

Domain Authentication

Aglet servers are able to authenticate whether the contacting server belongs to a certain domain. All servers that belongs to one domain share a secret key, and can authenticate the contacting server by means of that secret key using MAC (Message Authentication Code: a secure hash value computed from a content and nonce value). The advantage of this is that MAC does not have to be signed by means of encryption algorithms, and it can simply be implemented on top of vanilla JDK.

After the authentication between servers has been established, the credentials of the aglet are sent along with the aglet. The receiver will then decide how much it trusts the credentials sent by the server on the basis of the information obtained by the host authentication. In Aglets, the server simply trusts the credentials if they were sent from the server in the same domain.

To use the domain authentication, each user (or server administrator) needs to obtain the secret key of the domain from the domain authority. The domain authority is responsible for generating a domain key for a specific server. The shared secret key is signed with the user's password, and thus the user is required to give the correct user id and password to make it effective. This key file must be kept secret, because it is not encrypted.

One disadvantage is that it cannot identify and verify the communicating hosts. Once the shared key is stolen from a server in the domain, there is no way of distinguishing valid servers and the server from which the key was stolen. As a result, all servers in the same domain are exposed to dangers.

Integrity-Checked Communication

Since all aglet servers within one domain share a secret, the integrity checking can be done in the same way as that described under the domain authentication. The sender computes the MIC (Message Integrity Code; same as MAC) value of the the content and the shared secret, and sends it along with the nonce and the content. The receiver then verifies the MIC by using the nonce, the content and the secret maintained by the receiver itself. Because only a server that knows the secret can generate the same MIC, the receiver can make sure that the content was sent by a server in the same domain and has not been tampered with.

Program Identification

In the current Aglets, the identification of the agent code uses only its codebase. As of the time of writing, code signing is not supported.

Authorization of Aglets

When an aglet accesses the security-sensitive information and resources such as Java properties, threads, and/or any other external resources such as files, it must be controlled under the permissions given to the aglet. The permissions can be specified either by a GUI or by direct editing of the policy database. The format of the policy database used by Aglets is designed to conform to that in the JDK1.2 specification. A user can specify the following permissions in the policy database.
java.io.FilePermission            : File read/write/execute
java.net.SocketPermission         : Socket open/connect/listen/accept/multicast
java.awt.AWTPermission            : topLevelWindow, systemClipboard
java.util.PropertyPermission      : Java property 
java.lang.RuntimePermission       : print.queueJob, load library
java.lang.reflect.ReflectPermission : class field access
com.ibm.aglets.security.ContextPermission  : context property, start, shutdown
com.ibm.aglets.security.AgletPermission    : dispatch, deactivate, etc.
com.ibm.aglets.security.MessagePermission  : messaging
Aglets are identified by their code base and owner. The manufacturer of an aglet is currently anonymous because code signing is not supported in the current Aglets. Thus, the permissions for aglets are defined in terms of the aglets' owners and codebase information. For example, the following configuration gives the aglets owned by "oshima" that have the codebase "http://truted.com" read access to local files on "C:\temp", write access to any property in the context, and permission to dispose of any aglet owned by oshima.
grant codeBase "http://trusted.com",
      owned by "oshima"
{
   permission java.io.FilePermission  "C:\\temp", "read";
   permission com.ibm.aglet.security.ContextPermission  "property.*", "write";
   permission com.ibm.aglet.security.AgletPermission  "oshima", "dispose";
}
This policy file is created at $HOME/.aglets/security/aglets.policy on an idividual user basis. A domain-based policy is not yet supported. Once supported, the domain authority should be able to specify domain-wide permissions. Once code signatures are supported, "signedBy" will be available as a means of specifying the manufacturer of an aglet.

Setting Security Options

Although it should be possible to directly edit the policy file to specify permissions, Tahiti provides you with the GUI that make easy to define the security group and set permissions.

File Access Control

Tahiti controls the access to the local file system. For each category of aglets, a file access path specified by a list of directory path names defines the part of the file system that is accessible in either read or read/write mode.

Network Access Control

Specified <port number>s are kept in the Listen list box. Aglets server in the current aglet security category is enabled to listen to these ports. Specified <hostname:port number>s are kept in the Connect list box. Aglets server in the current aglet security category is enabled to connect to these ports.

Properties

T.B.D.

Others

When the box labeled "Warning Message on Aglet Windows" for a trusted aglet is checked, a warning window appears at the bottom of the window when the aglet performs an operation, even if it was created as a trusted aglet.

When the box labeled "Enable to Open Windows" for an untrusted is checked, untrusted aglets are allowed to open windows.

Possible Attacks


Aglets によるアプリケーション構築


The Aglets library provides developers with a set of APIs to build and configure your applications using Aglets technology. With one of these APIs, an application can have its own configured viewer, import a portion of server facilities, or create and launch an aglet without server capabilities.

Scenarios

There are several scenarios for building an application by using Aglets technology. While a server can host running aglets, a client can create and control an aglet remotely without any aglet context. Users may want to use aglets through their web browsers. In this case, applets can be used either as a context or a client, although it is impossible to dispatch an aglet to an applet.

Aglet Components Only

This typical scenario does not require any additional APIs. The application only consists solely of set of aglets built on an Aglet API. Such a configuration normally includes a stationary aglet that has privileged access to local resources such as databases and file systems, and provides services for incoming aglets. The classes used to define the stationary aglet can be from either local disk (CLASSPATH) or a given codebase. If it's loaded from CLASSPATH, no security limitation is enforced by the security manager, the aglet has the highest privileges. If it is loaded from a codebase, appropriate security enforcement will be applied in accordance with its identity.

With this configuration, an incoming aglet normally gains access to services via message passing. Then, it can leave for the next server along with the result obtained in the server, or send it to the home server by remote message passing and die. Message passing is also under the control of the security manager and a receiver aglet can also deny a request.

The server can be also configured so that it allows a limited set of aglets to access the local resources and services. In this case, for example, an aglet may open a direct connection to a database and issue a SQL request. This gives an aglet great flexibility in an using the server resources, while this also creates the risk that an aglet may misuse or abuse these resources, and eventually may cause the system to misbehave or even crash.

Customized Aglet Viewer

A viewer of an Aglets server can be configured by using the context event and listener API, and a server can define its own viewer. Such a viewer may provide a sophisticated management tool for an administrator, or a easy-to-use and application specific interface for end users.

For example, a administration tool would provide comprehensive ways of creating service aglets, monitoring visiting aglets, and disposing of them if necessary. Furthermore, the viewer can provide service for an incoming aglet in response to its arrival. For example, a gateway server may offer an incoming aglet the itinerary object for a further trip inside the gateway when it arrives.

On the other hand, the viewer can be customized for users or specific services. For example, a desktop-like interface may use an icon for aglets and drag and drop operations to manipulate them for people who is familiar with PCs, while a kiosk for novice users will define a single-click, Web style interface.

Applications embedding Aglets Server Facility

This scenario is a typical way of adding the functionality of accepting and hosting aglets into a traditional application. For example, a simple groupware application may use Aglets to provide service and to use it, or to communicate with members. It would be inadequate for such applications to just use the aglet server as it is, even if the developer can implement its own viewer.

The Aglets Server API allows developers to embed and bootstrap the aglets server in their applications, and to configure the server's SecurityManager, Persistence, Viewer, and so on.

Furthermore, an application may not want to accept incoming aglets while it is creating an aglet or dispatching and retracting it to obtain a service. The Server API allows an application to run the Aglets runtime library without daemon capability for this purpose.

Client Applications

A client application has no server facility; it only has communication facilities for creating and controlling an aglet remotely, or for sending a remote message. Therefore, this configuration requires fewer resources to use aglets and reduce security threats, because it downloads no bytecode, although it can still take advantage of mobile agents on the server sides.

For example, the console of a massive network management system may not have to install the server facility. The console application, which typically has a client capability, can create a monitor aglet on a machine, and let a detective aglet roam multiple machines and send information back to the console.

Server API Overview

Aglets provides developers with a set of APIs that support several kinds of server scenario.

The ContextEvent class and ContextListener interface allow you to monitor the activities of aglets in the context and to take actions in response to these activities. The typical application of this API is "AgletViewer" which displays a list of aglets running in the context and lets you control them by, for example disposing of them or dispatching them.

The Aglets Server interface makes it possible to write an application capable of hosting, receiving, and dispatching aglets. With this interface, you can take advantage of mobile agent technology in your application without running an independent, separate server program such as Tahiti.

com.ibm.aglet.event.ContextListener
The ContextListener interface defines a set of methods to be called when a context related event occurs. The Listener object can be set by calling the AgletContext.addContextListener(ContextListener) primitive. The contextStarted method is called when the context is started, and should define the initialization process to validate the context. The contextShutdown method is called when the context is shutdown, and should perform a finalization process to invalidate the context and release the resources used by the context. Note that if you add the context listener after the context is started, or if you remove the context before the context is shutdown, these two methods will not be called.

The other methods are for receiving notification of the activities of aglets. It is guaranteed that when an event occurs, the proxy of an aglet given as a parameter in the ContextEvent will still be available via the getAgletProxies() primitive. If an aglet is being disposed of, however, the instance of the aglet is in the middle of an invalidating process and may have an intermediate state. Therefore checking methods such as isValid(), may not return correct values.

package com.ibm.aglet.system;
public interface ContextListener {
    public void contextStarted(ContextEvent ev);
    public void contextShutdown(ContextEvent ev);
    public void agletCreated(ContextEvent ev);
    public void agletCloned(ContextEvent ev);
    public void agletArrived(ContextEvent ev);
    public void agletActivated(ContextEvent ev);
    public void agletReverted(ContextEvent ev);
    public void agletDisposed(ContextEvent ev);
    public void agletDispatched(ContextEvent ev);
    public void agletDeactivated(ContextEvent ev);
    public void agletStateChanged(ContextEvent ev);
    public void showDocument(ContextEvent ev);
    public void showMessage(ContextEvent ev);
}
agletStateChanged() is called when an aglet changes its state by, for example, calling the Aglet.setText(String) primitive. showDocument() is called when an aglet calls the Aglet.showDocument(URL) primitive to request that a specified document be shown. It is left to the context implementor to decide whether or how to implement the showDocument method. The default implementation of Tahiti launches an external Web browser, but another implementation may use an internal browser written in Java to load and display an HTML document.
com.ibm.aglet.event.ContextEvent
The ContextEvent class is an Event class, which is delivered to listeners when the state of the context or aglets in it changes.
package com.ibm.aglet.system;
public class ContextEvent extends AgletEvent {
    public static final int CONTEXT_FIRST = 1000;
    public static final int CONTEXT_LAST  = 1014;
    public static final int STARTED             = CONTEXT_FIRST;        // 1000
    public static final int SHUTDOWN            = CONTEXT_FIRST + 1;    // 1001
    public static final int CREATED             = CONTEXT_FIRST + 2;    // 1002
    public static final int CLONED              = CONTEXT_FIRST + 3;    // 1003
    public static final int DISPOSED            = CONTEXT_FIRST + 4;    // 1004
    public static final int DISPATCHED          = CONTEXT_FIRST + 5;    // 1005
    public static final int REVERTED            = CONTEXT_FIRST + 6;    // 1006
    public static final int ARRIVED             = CONTEXT_FIRST + 7;    // 1007
    public static final int DEACTIVATED         = CONTEXT_FIRST + 8;    // 1008
    public static final int ACTIVATED           = CONTEXT_FIRST + 9;    // 1009
    public static final int STATE_CHANGED       = CONTEXT_FIRST + 10;   // 1010
    public static final int SHOW_DOCUMENT       = CONTEXT_FIRST + 12;   // 1012
    public static final int MESSAGE             = CONTEXT_FIRST + 13;   // 1013
    public static final int NO_RESPONSE         = CONTEXT_FIRST + 14;   // 1014
    public Object arg = null;
    public AgletContext getAgletContext();
    public AgletProxy getAgletProxy();
    public String getMessage();
    public String getText();
    public URL getDocumentURL();
    public ContextEvent(int id, Object context, AgletProxy target, Object arg);
    public ContextEvent(int id, Object context, AgletProxy target);
}
com.ibm.maf.MAFAgentSystem

The com.ibm.maf.MAFAgentSystem is an abstract class that defines a set of method for creating, transferring, and managing agents. The interface is (almost) equivalent to methods defined in the MASIF standard specification, but not identical to the MASIF IDL, because this is not CORBA interface, as mentioned before. See the Architecture of Communication Layer section for more details of the architecture.
The getMAFAgentSystem primitive returns the instance of MAFAgentSystem for the given address. The AgletsRuntime then uses this object to communicate with the remote agent system. The returned object may be a stub object for remote access, or a local server object if the address is its own.

package com.ibm.maf.MAFAgentSystem;
public class MAFAgentSystem {
    static public MAFAgentSystem getMAFAgentSystem(Ticket ticket);
    static public MAFAgentSystem getMAFAgentSystem(String address);
    static public MAFAgentSystem getLocalMAFAgentSystem();
    static public void initMAFAgentSystem(MAFAgentSystem runtime, Name name);
    static public void startMAFAgentSystem(MAFAgentSystem runtime, String protocol);
    // MASIF interfaces
    public Name create_agent(Name name,
                             AgentProfile profile,
                             byte[] agent,
                             Object[] arguments,
                             ClassName[] class_names,
                             String code_base,
                             MAFAgentSystem class_provider);
    public abstract void receive_agent(Name agent_name,
                                       AgentProfile agent_profile,
                                       byte[] agent,
                                       String place_name,
                                       ClassName[] class_names,
                                       String code_base,
                                       MAFAgentSystem class_sender);
    public abstract byte[][] fetch_class(ClassName[] class_name_list,
                                         String code_base,
                                         AgentProfile agent_profile);
    public abstract String find_nearby_agent_system_of_profile(AgentProfile profile);
    public abstract MAFFinder get_MAFFinder();
    public abstract AgentStatus get_agent_status(Name agent_name);
    public abstract AgentSystemInfo get_agent_system_info();
    public abstract AuthInfo get_authinfo(Name agent_name);
    public abstract Name[] list_all_agents();
    public abstract Name[] list_all_agents_of_authority(byte[] authority);
    public abstract String[] list_all_places();
    public abstract void resume_agent(Name agent_name);
    public abstract void suspend_agent(Name agent_name);
    public abstract void terminate_agent(Name agent_name);
}

com.ibm.aglet.system.AgletRuntime Class

The com.ibm.aglet.system.AgletRuntime abstract class provides an interface for creating and managing the context. The class actually used and the instance are automatically chosen and created by the framework. Applications should not try to create a runtime object by themselves. Instead, an application must use the getAgletRuntime() primitive to obtain a reference to the runtime object.

ThecreateAgletContext(String name) primitive creates a new instance of the runtime with the given name. If there is an existing context with the same name, the primitive throws an IllegalArgumentException. These contexts created in the AgletRuntime object can be obtained by either the getAgletContext(String name) or the getAgletContexts() primitive. removeAgletContext(AgletContext cxt) removes the specified context from the internal context table. A living AgletContext can be removed from the runtime table without shutdown. Such a context becomes invisible, and cannot be accessed either remotely or locally. This can be used to create a sort of "private" context into which no aglet be dispatched.

class AgletRuntime {
    AgletRuntime getAgletRuntime();
    public AgletContext createAgletContext(String name);
    public AgletContext getAgletContext(String name);
    public void removeAgletContext(AgletContext cxt);
    public AgletContext[] getAgletContexts();
}

Client API

Aglets Class

The com.ibm.aglet.system.Aglets class lets an application program create and control an aglet remotely without requiring the AgletContext.
class Aglets {
    public static AgletProxy createAglet(String contextAddress,
                                         URL codebase,
                                         String classname,
                                         Object init);
    public static AgletProxy getAgletProxy(String contextAddress, AgletID id);
    public static AgletProxy[] getAgletProxies(String contextAddress);
}
You are not required to do the bootstrapping for client applications.
    public void main(String args[]) throws Exception {
        String contextAddress = "atp://host.name:434/contextName";
        AgletProxy proxy = Aglets.createAglet(contextAddress, null,
                                              "your.Aglet", null);
        proxy.sendMessage(new Message("buy", "jewel"));
        AgletProxy proxies[] = Aglets.getAgletProxies(contextAddress);
        // dispose all aglets
        for (int i=0; i < proxies.length; i++) {
            proxies[i].dispose();
        }
    }

Bootstrapping the Server

For the Aglet runtime to be able to create AgletContexts, to accept incoming aglets, and to host aglets, a bootstrapping application is required to properly initialize the system and start up the daemon. The application program must follow the steps below:
  1. Set option definitions if any.
  2. Initialize the AgletRuntime with optional arguments and obtain the runtime object. This automatically imports the options specified in the arguments.
  3. Authenticate the user id if necessary.
  4. Create a instance of the MAFAgentSystem_AgletsImpl class, which is ASDK's implementation of the MAFAgentSystem.
  5. Install the factory components if any. Tahiti.installFactories() can be used to install default factories.
  6. Initialize the communication layer with the instance of MAFAgentSystem_AgletsImpl and the given protocol.
  7. Create an AgletContext with/without a name.
  8. Create a ContextListener for the context and add the listener (if any) to it.
  9. Install the security manager, if any exists. Tahiti.installSecurity() can be used to install the default security manager.
  10. Start the context.
  11. Start the communication layer.
  12. From here on, you can use the Aglets facility.
The following example shows how to bootstrap the daemon and Aglets runtime.
public class MyServer {
    static private Opt options[] = {
        Opt.Entry("-protocol", "maf.protocol", null),
    };
    static public void main(String args[]) {
        Opt.setopt(options);
        AgletRuntime runtime = AgletRuntime.init(args);
        runtime.authenticate(username, password);
        Name system_name = new Name(username.getBytes(), null, (short)1);
        MAFAgentSystem maf_system = new MAFAgentSystem_AgletsImpl(runtime);
        MAFAgentSystem.initMAFAgentSystem(maf_system, "atp");
        Tahiti.installFactories();
        //
        // Creates a named context. To dispatch to this context, you have to
        // specify a destination such as "atp://aglets.trl.ibm.com:434/test"
        //
        AgletContext cxt = runtime.createAgletContext("test");
        ContextListener listener = new ContextAdapter () {
            public void agletArrived(ContextEvent ev) {
                AgletProxy proxy = ev.getAgletProxy();
                try {
                    System.out.println("Aglet is arriving."+
                                       proxy.getAgletInfo());
                } catch (InvalidAgletException ex) {
                    ex.printStackTrace();
                }
            }
            public void agletDispatched(ContextEvent ev) {
                AgletProxy proxy = ev.getAgletProxy();
                try {
                    System.out.println("Aglet is leaving."+
                                       proxy.getAgletInfo());
                } catch (InvalidAgletException ex) {
                    ex.printStackTrace();
                }
            }
        }
        cxt.addContextListener(listener);
        Tahiti.installSecurity();
        //
        // Start a context
        //
        cxt.start();
        MAFAgentSystem.startMAFAgentSystem(maf_system, protocol);
        //
        AgletProxy myAglet = cxt.createAglet(null, "MyAglet", null);
        myAglet.sendMessage(new Message("startTrip"));
    }
}

Properties in Aglets

Aglets Properties

The following table contains a list of properties typically used by the Aglets runtime library for configuration.
Property Name Description Example
aglets.class.path Specifies the default lookup path for a codebase. This is used when a null value is given as a codebase in the AgletContext.createAglet(..) primitive. /usr/local/AWB/Aglets/public:/myhome/public C:\AWB\Aglets\public:D:\myaglets\public
aglets.viewer Specifies the class name that is used for the server.
The class must implement a ContextListener interface.
com.ibm.aglets.tahiti.Tahiti
The script or executable for the Aglets runtime often uses the environment variables to make it easy to specify those values in their platform.

ATP Properties

The following table contains a list of properties typically used by the ATP transport layer for configuration.
Property Name Description Example
atp.useHttpProxy Switch on and off the http proxy. true/false
atp.http.proxyHost Host firewall.ibm.com
atp.http.proxyPort Port number 8080
atp.noProxy The proxy is not used for the hosts whose addresses start with the string specified here. ibm.com

Tahiti Properties

The following table contains a list of properties typically used by the Tahiti viewer for configuration.
Property Name Description Example
tahiti.browser_command openurl Specifies the command to launch the browser

Other Properties

T.B.D

旅行計画 (itinerary) とパターン


T.B.D.
Copyright (C) 1997, 1998, IBM Corp. All rights reserved.
Aglets is a trademark of IBM Corp.
Java is a trademark of Sun Microsystems, Inc.