1.仕様

1.1 概要

本エージェントシステムを構成する4つの要素を以下に示します.

要素 説明
メッセージ エージェント間で送受信されるデータ
エージェント 互いにメッセージを交換し処理を進めるプログラム
TAGサーバ エージェントを動作させるPCで起動しておくプログラム
Web UI TAGサーバが提供するユーザインタフェース

1.2 メッセージ

形式

特別なメッセージ:リクエストメッセージ

パフォーマティブが「request」で始まるメッセージを「リクエストメッセージ」と呼びます.以下はリクエストメッセージの例です.

[_p:'request', action:'shutdown']
[_p:'request-information', point:'max']

メッセージのID

注意:必須知識ではありません.自分で独自のプロトコルを実装する場合には便利です.

メッセージにはMapに記述される内容の他に次の属性があります.これらはStringで表現されます.

UUIDは次のように取得できます.

1.3 エージェント

概要

記述形式

エージェントプログラムはエージェント名.groovyというファイルに記述します.スクリプト言語Groovyを用います.コンパイルは不要です.文字コードはUnicode(UTF-8 BOMなし),改行コードはCR+LFです(CRだけ/LFだけでも大丈夫かも).記述内容を示します.

import TAG

class エージェント名 extends TAG {

  void setup() { ... }

  void loop(Map msg) { ... }

}

ライフサイクル

エージェントは次のように動作します.

  1. プログラムは./agent フォルダ内に保存されています.TAGサーバはこのプログラム全てを起動し,サーバ情報をセットします.スタンドアロンで起動された場合(groovyコマンドで起動された場合)はエージェントがサーバ情報をTAGサーバから取得します.
  2. 起動されると,groovyインタプリタはJavaスレッドを1つ作り,TAG.run()の実行を開始します.エージェント1つにつき1つのスレッドが割り当てられます.
  3. setup() が呼び出されます.ここでエージェントの初期化を行います.
  4. メッセージが届くまで停止します.メッセージが届くとloop() が呼び出されます.loop()内の処理の終了後,再びメッセージが届くまで停止します.

エージェントの起動方法は2種類あります.いずれもTAGサーバの起動が必要です.

TAGサーバによる起動 groovyコマンドによる起動
TAGサーバ起動時に起動 TAGサーバ起動後、端末から起動
./agent/に保存(スクリプトでもOK) 任意の場所に保存
WebUIによる再起動可 WebUIからは再起動不可
WebUIで編集可 WebUIでは編集不可
stdout/errはWeb UIに接続 stdout/errは端末に接続

※groovyコマンドによる起動は動作確認が不十分です

組み込みメソッド

組み込みメソッドとしてクラスTAGに定義されているメソッドは次の通りです.

(1) send()

メッセージを送信します.送信したメッセージのUUIDを返します.送信後は次の行に進みます(返信待ちしない).

String send(String agent, Map msg) // agentにメッセージmsgを送信する
String send(List agents, Map msg)  // 複数のagentsにメッセージmsgを送信する(全てのUUIDは同一)

用例:
String uuid = send('ODB_aomori', [_p:'inform', point:50])
String uuid = send(['ODB_aomori', 'ODB_iwate'], [_p:'inform', point:50])

(2) reply()

メッセージを返信します.送信したメッセージのUUIDを返します.送信後は次の行に進みます(返信待ちしない).送信したメッセージのreplyIDがメッセージmのUUIDとなるところがsend()との違いです(send()で送信した場合はreplyIDはnull).

String reply(Map m, Map msg) // mへの返信メッセージmsgを送信する (msgのreplyIDは,mのUUID)

用例:
String uuid = reply(m, [_p:'inform', point:50])

(3) request()

リクエストメッセージを送信します.送信したリクエストメッセージに対する返信メッセージ(あるいは返信メッセージを要素とするList)を返します.返信が届くまで待ちます(次の行に進まない).

Map request(String agent, Map msg) // agentへのリクエストメッセージmsgを送信し,返信が届くまで待つ
List request(List agents, Map msg) // 複数のagentsへのリクエストメッセージを送信し,全ての返信が届くまで待つ※
Map request(Map m, Map msg)        // mに対する返信としてリクエストメッセージを送信し,返信が届くまで待つ

用例:
Map m = request('ODB_aomori', [_p:'request-information', point:'max'])
Map m = request(['ODB_aomori', 'ODB_iwate'], [_p:'request-information', point:'max'])
Map m = request(msg, [_p:'request_information', point:max])

(4) static start()

複数のエージェントを同時に起動するときに,起動用スクリプト内で使います.

※以下は未実装の仕様

以下は通常のプログラムでは使わなくても済む特殊なメソッドです.TAG.loop()を使わずに自分でTAG.run()メソッドを記述する場合や,Javaプログラム内部にメッセージ待ちループを作る場合,あるいは独自のプロトコルを作る場合に有用です.

(5) fetch()

メッセージサーバ内にある全てのメッセージを取得し,ローカルバッファに取り込みます.新たに取り込んだメッセージの数を返します.

int fetch()

(6) waitAny/All()

指定されたUUIDのメッセージの到着を待ちます(次の行に進まない).到着したメッセージを返します.

TagMessage waitAny(List uuids) // uuidsに含まれるreplyIDのメッセージの到着を待つ.最初に到着したものを返す.
List waitAll(List uuids)       // uuidsに含まれる全てのreplyIDのメッセージの到着を待つ.到着した全てのものを返す.

Javaプログラムのエージェント化

TAGをJavaプログラムに組み込むことで,そのJavaプログラムがメッセージ送受信可能になります.※実装中

1.4 TAGサーバ

エージェントを動作させるPCで起動しておくプログラムです.メッセージサーバ機能とエージェントサーバ機能の2つの機能を兼任します.メッセージサーバ機能により名前空間が規定されます.設定ファイルtag.iniで動作設定します.

メッセージサーバ機能

エージェントサーバ機能

設定ファイル

初回起動時に以下のようなtag.iniが生成されます.これらはエージェントが動作するのに必要なサーバ情報です.サーバ情報はエージェント起動時にエージェントにセットされます.

#property file for TAG
#Sat Jan 20 23:40:22 JST 2018
msgServerPort=8080
msgServerHost=localhost
containerUUID=1b4dcf13-11ac-4c34-8c7f-09a65b801488
containerName=noname1
エントリ 意味
msgServerPort TAGサーバ配下のエージェントが使うメッセージサーバのポート番号
msgServerHost TAGサーバ配下のエージェントが使うメッセージサーバのホスト名
containerUUID TAGサーバのUUID(自動的に生成されます)
containerName TAGサーバの名前(自動的に生成されます)

PC間通信

異なるPC上のエージェントが通信するためには,メッセージサーバ機能の共用が必要です.tag.ini内のmsgServerHostmsgServerPortを書き換えることで,他のTAGサーバから提供されるメッセージサーバ機能を使うことができます.

(1)単一のPCでの運用

TAGサーバは自前のメッセージサーバ機能を使います.TAGサーバの初回起動時に生成されるtag.iniで設定される運用方法です.

%0 clusterPC PC AgentServer TAG Server [MessageServer] Agent1 Agent1 AgentServer->Agent1 Agent2 Agent2 AgentServer->Agent2 browser browser browser->AgentServer

tag.iniの項目 PC
msgServerHost localhost

(2)同一のLAN上のPCでの運用

PC1で動作しているTAGサーバのメッセージサーバ機能を共有する例です.PC2のtag.iniPC1を記述することで,エージェント3,4 はエージェント1,2と通信することができます.PC2からPC1にネットワーク接続できる場合に適用できます.3台以上で共有することもできます.

%0 clusterPC1 PC1 clusterPC2 PC2 AgentServer TAG Server [MessageServer] Agent1 Agent1 AgentServer->Agent1 Agent2 Agent2 AgentServer->Agent2 Agent3 Agent3 AgentServer->Agent3 Agent4 Agent4 AgentServer->Agent4 browser1 browser browser1->AgentServer LocalServer TAG Server LocalServer->AgentServer LocalServer->Agent3 LocalServer->Agent4 browser2 browser browser2->LocalServer

tag.iniの項目 PC1 PC2
msgServerHost localhost PC1

(3)異なるLAN上のPCでの運用

PC1とPC2が直接つながらない場合,双方からアクセス可能な場所にあるPC0をメッセージサーバとして共有することができます.図ではPC0のエージェントサーバ機能は使っていませんが,使うこともできます.

%0 clusterPC0 PC0 clusterPC1 PC1 clusterPC2 PC2 AgentServer0 TAG Server [MessageServer] Agent1 Agent1 AgentServer0->Agent1 Agent2 Agent2 AgentServer0->Agent2 Agent3 Agent3 AgentServer0->Agent3 Agent4 Agent4 AgentServer0->Agent4 AgentServer1 TAG Server AgentServer1->AgentServer0 AgentServer1->Agent1 AgentServer1->Agent2 browser1 browser browser1->AgentServer1 AgentServer2 TAG Server AgentServer2->AgentServer0 AgentServer2->Agent3 AgentServer2->Agent4 browser2 browser browser2->AgentServer2

tag.iniの項目 PC0 PC1 PC2
msgServerHost localhost PC0 PC0

1.5 名前空間

TAGサーバは,同一PC上で動くエージェントを管理するエージェントサーバ機能と,メッセージをバッファリングするメッセージサーバ機能として動作します.この2つの機能により名前空間が規定されます.

対応関係

TAGサーバは,自分自身,あるいは他のTAGサーバをメッセージサーバとして利用します.

名前

エージェント名 TAGサーバ名 TAGサーバのUUID メッセージサーバ名
TAGサーバで
ユニーク
メッセージサーバで
ユニーク
UUIDなので
ユニーク
IPアドレス:ポート
ユーザが決定 ユーザが決定 初回起動時に
ランダムに決定
IPアドレス:ポート
クラス名,あるいは
コンストラクタの
引数として記述
tag.ini内の
containerName
に記述
自動生成されるので
ユーザは記述しない
tag.ini内の
msgServerHost
msgServerPort
に記述

1.A 内部の動作

WebUIは必ずContainerを通す(ajaxクロスドメイン回避)
エージェントも。localhost:8080とのみfetch/sendする

WebUIWebUIMsgServer(local)MsgServer(local)Agent(local)Agent(local)MsgServer(remote)MsgServer(remote)Agent(remote)Agent(remote)Container起動時cinfo.txt(コンテナ情報)名前, UUID, MsgServerWebUIからの送信履歴messages.txt履歴エージェントリスト, メッセージ表list.txttable.txt(メッセージ表)opt[remote]list/table.txt返事返事websocketconnectheartbeat, newMessage,newAgent, newOutopt[relayさせる場合]connectheartbeat, newMessage,newAgent, newOutメッセージ送信(local)メッセージfetchメッセージメッセージ送信(remote)メッセージメッセージfetchメッセージ

エージェント間

AgentAgentContainerContainerMsgServerMsgServerAgent2Agent2Container2Container2メッセージ送信メッセージfetchopt[Container2 != MsgServer]fetchメッセージメッセージ