第2回 JXTA-ShellとJXTA Java APIの関連

丸山不二夫
稚内北星学園大学学長
(http://www.wakhok.ac.jp/)
2001/10/31

 本連載では、成長過程にあるJXTAのテクニカルな部分に触れながら、JXTAによって実現可能となるPtoPサービスの可能性にアプローチしていきたい。また、大きなリリースのタイミングでは、その詳細について解説する。(編集局)


 前回は、JXTA-Shellのメッセージ通信について見ましたが、今回は、こうしたスクリプトがJXTA Javaの「告知」を使ったメッセージ通信プログラムとどのように関連があるかを見てみたいと思います。

JXTA Shellのメッセージ通信のまとめ

shareとsearchのソースを読む
JXTAのDiscoveryの働き(1)

 今回は、shareコマンドとsearchコマンドのソースを読みます。JXTA-Shellのコマンド作成に必要な情報を紹介しながら、JXTAがどのように「告知」の公開・探索を行っているのかを見ていきたいと思います。

■JXTA-Shellのコマンド・クラスをどこに作るか
 JXTA-Shellのコマンドは、すべてがnet.jxta.impl.shell.ShellAppクラスを継承して作られます。JXTA-Shellコマンドを作成するためには、このクラスのほかに、net.jxta.impl.shell.*以下のクラスが必要になります。

 shareコマンド・クラスのパッケージ名とクラス名を示します。パッケージ名ですが、net.jxta.impl.shell.bin.+shareという形をしています。このshare以前の名前は予約されています。この固定部分にコマンド名(この例の場合にはshare)を付けたのが、Shellコマンド・クラスのパッケージ名になります。さらに、コマンド名と同じ名前のクラスが、このパッケージの中にある必要があります。

---------------------------------------------------------------------------------
package net.jxta.impl.shell.bin.share;

import net.jxta.impl.shell.*;
  ...........
  ...........

public class share extends ShellApp {

private Discovery disco=null;
ShellEnv env;
  ...........
  ...........

}
---------------------------------------------------------------------------------

 もしもcmdXという名前のJXTA-Shellコマンドを作りたいのであれば、./net/jxta/impl/shell/bin/cmdX/cmdX.classというパス名を持つクラスファイルが必要だということです。なにか、cmdXが二重になっていると思われるかもしれませんが、そうではありません。もしも、コマンドcmdX用に補助的なヘルパー・クラスが必要であれば、これらのcmdXに関連するファイルたちを、cmdXディレクトリ以下に次のように配置すればいいのです。

---------------------------------------------------------------------------------

   ./net/jxta/impl/shell/bin/cmdX/cmdX.class
   ./net/jxta/impl/shell/bin/cmdX/cmdXHelper1.class
   ./net/jxta/impl/shell/bin/cmdX/cmdXHelper2.class
.............
   ./net/jxta/impl/shell/bin/cmdX/cmdXHelperN.class
   ./net/jxta/impl/shell/bin/cmdX/cmdXImage1.gif
.............
   ./net/jxta/impl/shell/bin/cmdX/cmdXIcon.ico

---------------------------------------------------------------------------------

JXTA Shellのメッセージ通信のまとめ

■JXTA-Shellのイディオム --- getEnvとgetDiscovery
 JXTA-Shellでは、コマンド文字列の実行はShellAppインスタンスのstartAppメソッドの呼び出しとして実行されます。このとき、コマンドに与えられていた引数たちは文字列の配列としてこのstartAppメソッドに渡されます。次に示すのは、shareコマンドのstartAppメソッドのリストです。

---------------------------------------------------------------------------------
public int startApp (String[] args) {

if ((args == null) || (args.length !=1)) { // 引数配列がnull、あるいは、1つ以外の引数を
return syntaxError(); // 持てば、エラー
}

env = getEnv(); // 環境とdiscoveryサービスを獲得する
disco = group.getDiscovery();

String name = args[0]; // share に与えられた引数=告知の名前

ShellObject obj = env.get ("stdgroup"); // 環境変数stdgroupに設定されている値を
PeerGroup group = (PeerGroup) obj.getObject(); // groupに設定する

obj = env.get (name);             // 引数の告知は、あらかじめ変数に
if (obj == null) { // 入っていなければいけない
println ("share: cannot access " + name);
return ShellApp.appMiscError;
}

StructuredDocument doc = null;
Advertisement adv = null;

try {
adv = (Advertisement) obj.getObject(); // 引数の告知の名前から、告知を獲得する
publishAdv(adv); // 告知の公開
} catch (Exception e) {
println ("share: " + name + " is not a proper Document");
return ShellApp.appMiscError;
}
return ShellApp.appNoError;
}
---------------------------------------------------------------------------------

 このソースの次の処理は、ほとんどすべてのJXTA-Shellコマンドで行われている基本的なイディオムといっていいものです。

---------------------------------------------------------------------------------
env = getEnv();
disco = group.getDiscovery();
---------------------------------------------------------------------------------

JXTA Shellのメッセージ通信のまとめ


■Shell内部の変数の値を獲得するには
 env = getEnv();のenvはShellEnvクラスのインスタンスで、JXTA-Shell内部の変数の値を獲得する際に用いられます。envはHashtableと同じようなものなのですが、直接変数を格納しているわけではなく、オブジェクトと変数名のペアから成るShellObjectというオブジェクトのインスタンスを格納しています。これは、変数名を表す文字列がnullのときに、自動的に変数名を生成して値を格納する際に利用される仕掛けなのですが、そのために、変数名を指定してその値を引き出すときには、次の例のように、いったんgetメソッドでShellObjectを獲得してから、getObjectメソッドを実行しなければなりません。

ShellObject obj = env.get ("stdgroup");
PeerGroup group = (PeerGroup) obj.getObject();

 この2段階のシーケンスはよく登場しますので、このパターンを頭に入れておいてください。

JXTA Shellのメッセージ通信のまとめ

■Discoveryインスタンスの獲得
 Discoveryインスタンスのdiscoは、share/searchコマンドをはじめ、JXTA-Shellのいくつかのコマンドの中でdisco = group.getDiscovery();で獲得されます。このdiscoは重要な役割を果たします。つまり、discoはShellAppクラスを拡大したコマンド・クラスの中でprivate Discovery disco=null;と定義されているのですが、net.jxta.discovery.Discoveryはインターフェイスなので、正確にいえば、discoはDiscoveryインターフェイスを実装したインスタンスということになります。

 次に、コマンドsearchのソースの一部を示します。ここでもgetEnvメソッドとgetDiscoveryメソッドが使われていることを確認してください。

---------------------------------------------------------------------------------
public class search extends ShellApp {
private ShellEnv env;
private Discovery discovery=null;
.............
.............

public int startApp(String[] args) {

env = getEnv();
discovery = group.getDiscovery();
   .............
   .............

try {
if (rflag || pflag ) {
return(discover(pid,attr,val));
} else {
return(getLocal(attr,val));
}
}
catch(Throwable ex) {
      .............
}
}

---------------------------------------------------------------------------------

JXTA Shellのメッセージ通信のまとめ

■shareコマンドとsearchコマンドの処理
 先のshareコマンドとsearchコマンド、2つのstartAppメソッドのソースを眺めれば、shareコマンドの処理の中心がpublishAdv(adv);というメソッド呼び出しであり、searchコマンドの処理の中心がdiscover(pid,attr,val)とgetLocal(attr,val)いう2つのメソッド呼び出しであることが分かります。これらのメソッドのソースを次に示します。

---------------------------------------------------------------------------------
private void publishAdv(Advertisement adv) {
try {
disco.publish(adv, Discovery.ADV);
} catch( Exception ignored ) {
    }
}
---------------------------------------------------------------------------------

---------------------------------------------------------------------------------
private int discover(String address, String attr, String val ) {
discovery.getRemoteAdvertisements(address,discovery.ADV, attr, val,threshold);
println("JXTA Advertisement search message sent");
return ShellApp.appNoError;
}
---------------------------------------------------------------------------------

---------------------------------------------------------------------------------
private int getLocal(String attr, String val) {
Enumeration res;
try {
res = discovery.getLocalAdvertisements(discovery.ADV, attr, val);
} catch (Exception e) {
println("nothing stored");
return ShellApp.appNoError;
}
..............
..............
}
---------------------------------------------------------------------------------

 こうして整理すると、shareコマンドは基本的にはDiscoveryインスタンスに対するpublishメソッドの呼び出しであり、searchコマンドは同じくDiscoveryインスタンスに対するgetRemoteAdvertisementsメソッド、あるいはgetLocalAdvertisementsメソッドの呼び出しであることが分かります。

JXTA Shellのメッセージ通信のまとめ

■publishメソッドとgetLocalAdvertisementsメソッド
 net.jxta.impl.discovery.DiscoveryServiceクラスのpublishメソッドのソースの一部を示します。publishは、告知のタイプがGROUPかPEERかそのほかの告知かによって、基本的にはそれらのIDを取り込んで一意なファイルの名前を作り、告知のXMLドキュメントを格納しローカルなディレクトリ上に書き出します。

---------------------------------------------------------------------------------
public void publish(Advertisement adv, int type,
long timeoutForMe, long timeoutForOthers) throws IOException {

ID advID = null;
String advName = null;
// タイプは、GROUPかPEERか、それ以外か?
switch( type ) {
case GROUP :
advID = ((PeerGroupAdv)adv).getGid();
break;
case PEER :
advID = ((PeerGroupAdv)adv).getPid();
break;
default:
advID = ID.nullID;
break;
}
// 告知からXML文書を生成する
StructuredDocument doc;
try {
doc = (StructuredDocument) adv.getDocument(new MimeMediaType("text/xml"));
} catch (IOException error) {
throw error;
} catch (Exception everything) {
throw new IOException
("Advertisement couldn't be saved because of :"
+ everything.toString());
}

// 告知のXML文書を格納するファイル名を決める
if( advID.equals( ID.nullID ) )
advName = cm.createTmpName(doc);
else
advName = advID.getUniqueValue().toString();

if (LOG.isDebugEnabled()) {
LOG.debug("publishing " + advName + " in " + dirname[type]);
}

// cmディレクトリ下にセーブする
cm.save(dirname[type], advName, doc, timeoutForMe, timeoutForOthers);
}
---------------------------------------------------------------------------------

 publishされた告知、また、次に見るgetRemoteAdvertisementsでネットワーク上で発見された告知は、具体的にはJXTAが起動されたディレクトリ下のcmという名前のディレクトリの下に、次のように収められています。画面1を参照してください。ここでは、Advと名付けられたディレクトリ下に、cmで始まる名前を持ついくつかのファイルがあることが分かりますね。このファイルの中にいくつかの告知がXML文書として公開されているわけです。

画面1(chache.jpg)

 今回、getLocalAdvertisementsメソッドのソースは省略しますが、こうしたcmディレクトリ下のXMLドキュメントから、attributeやvalueといった検索条件に合致した告知たちを選び出す働きをしています。publishメソッドが告知を書き出して、getLocalAdvertisementsメソッドがそれを読み出すわけですから、この2つのメソッドは、相互に補い合う働きをしていることになります。

JXTA Shellのメッセージ通信のまとめ

■getRemoteAdvertisementsメソッドのソースを読む
 先の2つのメソッドが、ともにローカルに働いているのに対して、searchコマンドが-rオプションを付けて呼ばれたときに、内部で呼び出されるgetRemoteAdvertisementsメソッドは、ネットワークを越えてほかのPeer上の告知を見つけに行きます。Discoveryインスタンス上で定義されたこれらのメソッドのこうした働きは、本連載のJavaでのJXTAプログラムの紹介ですでに見てきました。

 JXTA-Shellのコマンドが、JXTA-JavaのAPIを利用して書かれていることをこれまで見てきたのですが、publishやgetRemoteAdvertisementsといった、JXTA-JavaのAPIに登場するメソッドのソースも簡単に手に入ります。今回は、これらのソースのメソッドの内部の処理をもう少し詳しく見てみることにします。次に、getRemoteAdvertisementsメソッドのソースを示します。

---------------------------------------------------------------------------------
public int getRemoteAdvertisements(String peer, int type,
String attribute, String value, int threshold) {

DiscoveryQuery dquery = new DiscoveryQuery(type,
advToString(myGroup.getAdvertisement()),
attribute, value, threshold);

if ((attribute == null) || (value == null)) {
dquery.setAttr("null");
dquery.setValue("null");
} else {
dquery.setAttr(attribute);
dquery.setValue(value);
}
// Private copy for thread safety
int myQueryID = qid++;
LOG.debug("sending query: " + attribute + " = " + value);
ResolverQuery query = new ResolverQuery(advertisement.getName(),
"JXTACRED", localPeerId, dquery.toString(), myQueryID);
resolver.sendQuery(peer, query);
return myQueryID;
}
---------------------------------------------------------------------------------

 初めにDiscoveryQueryというクラスのインスタンスdqueryが生成されています。このインスタンスに、setAttrやsetValueを使い、引数で与えられているattributeやvalueの値を設定しているようです。続いてResolverQueryクラスのインスタンスを生成しています。そのコンストラクタの引数をよく見ると、dquery.toString()という形で、先に作ったdqueryインスタンスを文字列にしてqueryを作るのに使っていますね。このqueryがsendQueryメソッドの引数に与えられます。Resolverインスタンスに対するsendQueryメソッドの呼び出しが、getRemoteAdvertisementsメソッドの中心部分を構成しています。このnet.jxta.impl.resolver.ResolverServiceのsendQueryメソッドは、JXTAのメッセージ交換メカニズムの特徴をよく表しています。

JXTA Shellのメッセージ通信のまとめ

■探索メッセージは、どのように送られるか?
 ここでQueryと呼ばれているものは、まず、「これこれの告知を検索せよ」という探索命令だと考えてください。細かなメカニズムは後で見ることとして、最初に確認したいのは、各ピアは、こうしたQueryを受け取るとその問い合わせに対する「回答」を作り出して、それを質問者に送り返そうとするということです。探索ですから、できるだけ多くのPeerに対してこうした問い合わせを行う必要があります。問題は、Peer to Peerの通信を特色とするJXTAが、どのようにして多数のピアに対する問い合わせを実行するかということです。

 net.jxta.impl.resolver.ResolverServiceのsendQueryのソースを次に示します。このメソッドは、第1引数がnullのときには、まさに、たくさんのピアに探索メッセージを送りつける働きをします(逆に、第1引数が与えられれば、そのピアに対してだけ、メッセージを送ろうとします)。

---------------------------------------------------------------------------------
public void sendQuery(String rdvPeer,
ResolverQueryMsg query)
{
ResolverResponse doc=null;
LOG.debug("sending query");

Message propagateMsg = endpoint.newMessage();

if (rdvPeer == null){
try {
propagateMsg.push(outQueName,(InputStream)((Document)
(query.getDocument(new MimeMediaType("text/xml")))).getStream());
rendezvous.propagateInGroup(propagateMsg,
advertisement.getName(),
outQueName,
7,
null);
} catch (Exception e) {
LOG.info( "Error during propagate" ,e);
throw new RuntimeException ("Error during propagate :"
+e.toString());
}
} else {

//unicast instead
try {
respond (rdvPeer,
advertisement.getName(),
outQueName,
outQueName,
((Document)
(query.getDocument(new MimeMediaType("text/xml")))).getStream());
} catch (Exception e) {
LOG.info( "Error while unicasting query :", e );
throw new RuntimeException ("Error while unicasting query :"
+e.toString());
}
}
}

---------------------------------------------------------------------------------

 問い合わせメッセージを、たくさんのピアに伝播(Propagate)する働きを担っているのは、次のpropagateInGroupです。後に、sendToNetwork、sendToEachRendezVous、sendToEachClientという3つのメソッドが並んでいますね。この3つのメソッドの並びが、JXTAに特徴的なPropagateの働きをよく表しています。

---------------------------------------------------------------------------------
public void propagateInGroup(Message msg, String serviceName,
String serviceParam, int defaultTTL,
String prunePeer)
throws IOException {

Message dupMsg = msg.dup();
if (updatePropHeader(dupMsg, defaultTTL)) {
sendToNetwork(dupMsg, serviceName, serviceParam, prunePeer);
sendToEachRendezVous(dupMsg, serviceName, serviceParam, prunePeer);
sendToEachClient(dupMsg, serviceName, serviceParam, prunePeer);
}
}
---------------------------------------------------------------------------------

 sendToNetworkメソッドは、一番近い所に存在するピア同士がメッセージを交換するときに用いられます。同じネットワークに属するピア同士が、マルチキャストを通じて、メッセージを送るときに利用されるメソッドです。図1で、ピアAから、同一ネットワーク(正確にいえば、マルチキャスト・メッセージが到達可能なサブネット)内のピアB、C、Dに対するメッセージの送り出しです。

(図1入る)

 sendToEachRendezVousは、あるピアから、そのピアが利用しているすべてのRendezVousに対してメッセージを送り出します。図2で、E、F、G、HはRendezVousを表しています。DからE、F、Gへの送り出し、CからHへの送り出しは、sendToEachRendezVousメソッドの働きを表しています。
(図2入る)

 sendToEachClientが意味を持つのは、送り手側のピアがRendezVousである場合だけです。そうしたとき、このメソッドは、そのピアをRendezVousとしているすべてのクライアント・ピアに対してメッセージを送ります。図3で、RendezVousであるE、F、G、Hから発せられるメッセージが、このsendToEachClientメソッドの働きを示しています。

 このようにして、この3つのメソッドを内に含む、propagateInGroupメソッドの働きによって、Aから出発した探索メッセージは、ネットワークの中に大きく広がることができます。このメソッドの第4引数であるdefaultTTLは、こうした拡大を無限に続けるのではなく、ここで指定された整数値のホップでpropagateを終了せよという意味を持っています。defaultでは、このTTL(Time To Live)の値は7に設定されています。

JXTA Shellのメッセージ通信のまとめ

■Discoveryの働きの中間まとめ
 Discoveryの働きの探索はまだまだ続きます。ここまでの過程を、ひとまずまとめておきましょう。

 DiscoveryインスタンスでのgetRemoteAdvertisementsメソッドの呼び出しは、探索queryメッセージを引数に与えた、Resolverインスタンス上でのsendQueryメソッドの呼び出しを引き起こします。このことは、DiscoveryServiceがより基本的なサービスであるResolverServiceに「問題解決」の仕事を依頼していると考えることができます。ResolverServiceが解決すべき問題が、この場合は、「探索依頼」だったということです。

 Resolverインスタンス上でのsendQueryメソッドの呼び出しは、今度は、Rendezvousインスタンス上でのpropagateInGroupメソッドの呼び出しを引き起こします。このメソッドによって、最初のgetRemoteAdvertisementsメソッドを発したピアからの探索queryは、ネットワーク上の数多くのピアに広がっていきます。

 ところで、この最後のメッセージのPropagateの説明には少しおかしいところがあります。先に、propagateInGroup内の3つのメソッドの働きを3つの図で説明したのですが、それぞれのPropagateの中心には別のピアが存在しています。ピアAでpropagateInGroupメソッドが呼ばれたなら、ピアB、C、Dにはメッセージが届きますが、それ以上にはメッセージは広がらないはずです。

 先の説明のようにメッセージが広がってゆくというのなら、メッセージを受け取ったピアが、バケツリレーのようにメッセージを、次のピアに送り出さなくてはなりません。JXTAには、実際そうしたメカニズムが組み込まれています。

 次回は、JXTA?Discoveryの働きを、さらに見ていきたいと思います。

 

 

 

 

 

 前回は、途中から2つのJXTA-Shellコンソールを使うことになったので流れが少し分かりにくかったかもしれません。あらためて、「受け手」側のコマンド列をまとめてみると次のようになります(先頭のJXTA>は、JXTA-Shellのプロンプトであり、コマンドの一部ではありませんので注意してください)。

「受け手」側 JXTA-Shellスクリプト
JXTA>pipeadv = mkadv -p
JXTA>inpipe = mkpipe -i pipeadv
JXTA>msg = recv inpipe
JXTA>data = get msg mytag

 続いて、同じくJXTA-Shellでのメッセージの「送り手」側のコマンド列をまとめると次のようになります。

「送り手」側 JXTA-Shellスクリプト
JXTA>opipe = mkpipe -o pipeadv
JXTA>importfile -f jxtaConfig mydata
JXTA>msg = mkmsg
JXTA>put msg mytag mydata
JXTA>send opipe msg

 JXTA-Shellで、このような「告知」を使ったパイプでのメッセージ通信のスクリプトがスラスラ書けるようになったら、JXTA-Shellのコマンドの主要な部分をほとんど使いこなせていると考えて間違いありません。マニュアルを見なくても、こうしたコマンド列が頭に浮かぶようになってください。

receiver.javaとsender.java

 今回は、Javaで書かれたJXTAでの通信プログラムで利用されているAPIが、JXTA-Shellでの通信のコマンド列ときれいに対応していることを見ていきます。「Viva! JXTA 〜JXTAはネットワークを変える」で紹介した2つのJavaプログラム、receiver.javaとsender.javaを再掲します。コメントを省いてありますので、印象が違うかもしれませんが同じものです。コメントなしでも、少し読んでみてください。

「受け手」側 Javaプログラム receiver.java
public class receiver extends ShellApp {

private Discovery discovery;
private Pipe pipes;
private InputPipe msgPipe;
private Message message;
private PeerGroupID gid;


 public int startApp (String[] args) {


  try {
   PipeAdvertisement pipeAdv = (PipeAdvertisement)
   AdvertisementFactory.newAdvertisement("jxta:PipeAdvertisement");
   pipeAdv.setName("Pipe Maruyama-1");
   pipeAdv.setPipeID(new PipeID(group.getID()));


   ServiceAdvertisement serviceAdv = (ServiceAdvertisement)
   AdvertisementFactory.newAdvertisement("jxta:ServiceAdvertisement");
   serviceAdv.setName("Maruyama-1");
   serviceAdv.setProvider("wakhok.ac.jp");
   serviceAdv.setVersion("Version 1.0");
   serviceAdv.setPipe(pipeAdv);


   discovery = group.getDiscovery();
   discovery.publish(serviceAdv, Discovery.ADV);
   discovery.remotePublish(serviceAdv, Discovery.ADV);
   println("Service advertisement was published" );


   pipes = group.getPipe();
   msgPipe = pipes.createInputPipe(pipeAdv);


  } catch (Exception ex) {
   ex.printStackTrace();
   System.err.println("receiver: Error publishing the service");
  }


  while (true) {
   println("Waiting ......");
   try {
    message = msgPipe.waitForMessage();
   } catch (Exception e) {
    System.err.println("Error listening");
    msgPipe.close(); return 1;
   }

   try {
    InputStream info = message.pop ("HelloTag");
    if (info != null) {
     byte[] msgbuffer = new byte [info.available()];
     int n = info.read (msgbuffer);
     println("receive message: " + new String(msgbuffer));
     info.close();
    } else
     System.err.println("receiver: no tag");
    } catch (Exception e) {
     System.err.println("receiver: error ");
    }

  }
 }
..............
..............
}

「送り手」側 Javaプログラム sender.java
public class sender extends ShellApp {

private Discovery discovery;
private Pipe pipes;
private OutputPipe msgPipe;
private Message message;


 public int startApp (String[] args) {
  try {


   String strings = "";
   if ((args == null) || (args.length < 1)) {
    strings = "Hello World!";
  } else {
    for( int i=0; i<args.length; i++ )
    strings += args[i] + " ";
   }


   discovery = group.getDiscovery();


   println("searching for the Maruyama-1 Service advertisement");
   Enumeration enum = null;
   while (true) {
    try {
     enum = discovery.getLocalAdvertisements(Discovery.ADV, "Name", "Maruyama-1");
     if ((enum != null) && enum.hasMoreElements()) break;
     discovery.getRemoteAdvertisements(null, Discovery.ADV, "Name", "Maruyama-1",1);
     try { Thread.sleep(2000); } catch (Exception e){}
    } catch (Exception e){}
  }

    ServiceAdvertisement serviceAdv = (ServiceAdvertisement)    enum.nextElement();
    PipeAdvertisement pipeAdv = serviceAdv.getPipe();


    pipes = group.getPipe();
    msgPipe = pipes.createOutputPipe(pipeAdv, Pipe.NonBlocking, 5000);
    message = pipes.createMessage();


    ByteArrayInputStream info = new ByteArrayInputStream (strings.getBytes());
    message.push ("HelloTag", info);
    msgPipe.send (message);
    println("Message: \"" + strings + "\" sent");


   } catch (Exception ex) {
    ex.printStackTrace();
    System.err.println("Error sending message");
   }
    return ShellApp.appNoError;
 }

..............
..............
}

「受け手」のスクリプトとreceiver.javaの比較

 まず、「受け手」のスクリプトとreceiver.javaの比較から始めましょう。

(1)パイプ告知の生成

 JXTA-Shellのmkadvコマンドは、次のようにJavaプログラムのAdvertisementFactoryクラスでのnewAdvertisementメソッドの呼び出しに対応しています。mkadvコマンドの-pオプションは、newAdvertisementメソッドの引数jxta:PipeAdvertisementに対応します。

●パイプ・サービス告知を生成して、告知に必要なパラメータを設定する
コマンド
JXTA>pipeadv = mkadv -p
Javaプログラム
PipeAdvertisement pipeAdv = (PipeAdvertisement)
AdvertisementFactory.newAdvertisement("jxta:PipeAdvertisement");
pipeAdv.setName("Pipe Maruyama-1");
pipeAdv.setPipeID(new PipeID(group.getID()));
..........

(2)パイプの生成

 JXTA-Shellの-iオプション付きのmkpipeコマンドは、JXTA Javaでは、次のようにパイプ・サービス告知のインスタンスに対するcreateInputPipeメソッドの呼び出しに対応します。このメソッドは引数にパイプ告知を取っていますが、コマンドmkpipeも引数にパイプ告知pipeadvを用います。

●先に作ったパイプ・サービス告知を利用して、入力用のパイプを生成する
コマンド
JXTA>inpipe = mkpipe -i pipeadv
Javaプログラム
pipes = group.getPipe();
msgPipe = pipes.createInputPipe(pipeAdv);
..........

(3)メッセージの受け取り

 メッセージの受け取りは、Java APIではwaitForMessageメソッドが使われています。

●パイプ・サービス告知を生成して、告知に必要なパラメータを設定する
コマンド
JXTA>msg = recv inpipe
Javaプログラム
message = msgPipe.waitForMessage();
..........

(4)メッセージ文字列の獲得

 メッセージからタグの部分を取り出すJXTA-Shellのgetコマンドは、JXTA Javaでは、メッセージ・インスタンスに対するタグ文字列を引数とするpopメソッドの実行に対応します。この例でのJXTA-Shellのタグはmytagで、JXTA JavaでのタグはHelloTagです。

●メッセージからタグ部分を取り出す
コマンド
JXTA>data = get msg mytag
Javaプログラム
InputStream info = message.pop ("HelloTag");
..........

「送り手」のスクリプトとプログラムsender.javaの比較

 今度は、「送り手」のスクリプトと、sender.javaの比較です。

(1)出力パイプの生成

 JXTA-Shellの-oオプションを持ったmkpipeコマンドは、JXTA Javaのパイプ・サービス告知のインスタンスに対するcreateOutputPipeメソッドの呼び出しに対応しています。

●パイプ・サービス告知を生成して、ほかのピアに接続している「出力パイプ」を生成する
コマンド
JXTA>opipe = mkpipe -o pipeadv
Javaプログラム
pipes = group.getPipe();
msgPipe = pipes.createOutputPipe(pipeAdv, Pipe.NonBlocking, 5000);

(2)空メッセージの生成

 JXTA-Shellで空のメッセージを生成するmkmsgコマンドは、JXTA JavaではcreateMessageメソッドに対応します。

●パイプ・サービス告知を生成して、告知に必要なパラメータを設定する
コマンド
JXTA>msg = mkmsg
Javaプログラム
message = pipes.createMessage();
..........

(3)メッセージの形成

 JXTA-Shellのgetコマンドが、JXTA Java APIのpopメソッドに対応していましたが、putコマンドにはpushメソッドが対応します。

●文字列にタグを付けてメッセージに押し込む。
コマンド
JXTA>put msg mytag mydata
Javaプログラム
ByteArrayInputStream info = new ByteArrayInputStream (strings.getBytes());
message.push ("HelloTag", info);

(4)メッセージの送出

 JXTA-Shellのsendコマンドは、そのままJXTA Java APIのsendメソッドに対応しています。

●パイプ・サービス告知を生成して、告知に必要なパラメータを設定する
コマンド
JXTA>send opipe msg
Javaプログラム
msgPipe.send (message);
..........

 さて、ここまでコマンドとJavaプログラムの対応を単純に比較してきました。次に、これらの間に考察を加えてみましょう。

  なぜ、対応しない部分が存在するのか?


Index
Page1
● JXTA Shellのメッセージ通信のまとめ
●receiver.javaとsender.java
●「受け手」のスクリプトとreceiver.javaの比較
●「送り手」のスクリプトとプログラムsender.javaの比較
  Page2
●なぜ、対応しない部分が存在するのか?
●「告知」の公開と獲得に、shareとsearchを使う
●「告知」をJXTA-Shellコマンドから獲得する
●searchコマンドの利用


連載記事一覧




Java Agile フォーラム 新着記事
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Java Agile 記事ランキング

本日 月間