・アプレット間通信のデサインバターン 37 : 38 : 39 : 40 : 41 : 42 : 43 : 44 : 45 : 46 : 47 : 48 : 49 : 50 : 51 : 52 : 53 : 54 : 55 : 56 : 57 : 58 : 59 : 60 : 1 : 2 : 3 : 4 : 5 : 6 : 7 : 8 : 9 : 10 : 11 : 12 : 13 : 14 : 15 : 16 : 17 : 18 : 19 : 20 : 21 : 22 : 23 : 24 : 25 : 26 : 27 : 28 : 29 : 30 : 22 SendButton. addActionListener (this) ; add (SendButton) ; public interface App1etCommunicator{ InputArea = new TextFie1d() ; InputArea. setBounds(my—insets . left + 17 , 106 , 196 , 28 ) ; InputArea. setBackground(C010r. white) ; add(InputArea) ; my—lnsets . top 十 / / defines method to send a command to another / / App1etCommunicator. public VOid postCommand(ObJ ect command) ; / / defines method vhich adds App1etCommunicators with / / which the App1et can communicate. public void addApp1et (App1etCommunicator remote_applet) ; / / defines method which removes App1etCommunicators as / / they are removed from the browser. public VOid removeApp1et (App1etCommunicator remote_applet) ; リスト 2 AppIetContext を利したアプレットコード private void link(){ App1etContext my—context = getApp1etContext ( ) ; Enumeration applets = my_context . getApp1ets ( ) ; while (applets . hasMoreE1ements ( ) ) { addApp1et ( (App1etCommunicator) applets. nextE1ement ( ) ) ; public void addApp1et (App1etCommunicator remote_app) { if (RemoteApps Ⅱ u11 ) { / / Has hashtable been created? RemoteApps = new Hashtab1e ( ) ; public void removeApp1et (App1etCommunicator remote_app) { if (RemoteApps ! = Ⅱ u11 ) { / / Hashtab1e must have been created. RemoteApps . remove (remote-app ・ getName ( ) ) ; if (remote—app ! = this) { / / Don' t add current App1et. / / Use App1et name as hashtable key to applet reference. RemoteApps. put (remote-app. getName ( ) , remote—app) ; if (RemoteApps. size() RemoteApps Ⅱ u11 ; public void postCommand(Object command){ UNIX MAGAZINE 1999.4
アプレット間通信のテサインバターン・ Apps ・ put ( ( (App1etCommunicator) remote—applet) . getName ( ) , remote-applet) ; 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 →ー 7 7 →ーー 7 7 7 public static synchronized void removeApp1et (App1et remote—applet) { if(Apps ! = null){ / / Hashtab1e must have been created first . Apps ・ remove ( ( (App1etCommunicator) remote—applet) . getName ( ) ) ; if(Apps . size() Apps = Ⅱ u11 ; / / Dereference if not in use ・ public static synchronized String ロ getApp1etNames ( ) { Enumeration keys = Apps ・ keys ( ) ; new Vector() ; for (int i=O ; keys . hasMoreEIements ( ) ; i + + ) { names . addE1ement (keys . nextE1ement ( ) ) ; new String[names . size()] ; String ロ applet—names for(int i=O; i く names . size() ; i + + ) { applet—names [i] (String) names. e1ementAt(i) ; return(applet-names) ; public static synchronized App1et getApp1et (String applet—name) { (App1et) Apps ・ get (applet—name) ; App1et remote—applet if (verifyApp1etRef (remote—applet) ) { return (remote—applet) ; }else{ return(null) ; public static void postCommand(String applet—name , Obj ect command) { AppIetCommunicator remote—applet (App1etCommunicator) getApp1et (applet—name) ; remote—applet . postCommand (command) ; private static boolean verifyApp1etRef (App1et remote—applet) { boolean valid = false; if (remote—applet. isActive() ) { return(true) ; }else{ removeApp1et (remote—applet) ; return(false) ; 25 UNIX MAGAZINE 1999.4
アプレット間通信のテサインノヾターン・ if (command instanceof String){ textArea1. appendText ( (String) command + ' \ Ⅱ ' ) ; 3 3 3 3 リスト 3 JavaScript と Java を第したアプレットコード 1 : く SCRIPT> 2 : 3 : var Apps = Ⅱ u11 ; 4 : function addApp1ets (frame) { 5 : if (Apps 皿 11 ) { 6 : 7 : Apps = new Java. util. Vector; 8 : 9 : 10 : 11 : 12 : 13 : 14 : 15 : 16 : 17 : 19 : 20 : 21 : 22 : 23 : 24 : 25 : 26 : 27 : 28 : 29 : 30 : 31 : 32 : 33 : 34 : 35 : 36 : 37 : 38 : 39 : 40 : 41 : 42 : 43 : 44 : 45 : 46 : 47 : 48 : 49 : 50 : var applet ; var new——applet ; f0 て (i=O ; i く frame. document . applets. length; new—applet = frame . document. applets , if(Apps ・ size() > 0 ) { for(j=O; j く Apps ・ size(); j + + ) { applet = Apps ・ e1ementAt (j ) ; applet . addApp1et (new—applet) ; new—applet . addApp1et (applet) ; Apps . addE1ement (new-applet) ; } / / End of addApp1ets function function removeApp1ets (frame) { if (Apps ! = null){ fo て (i=O ; i く frame. document . applets. length; frame. document . applets [i] ; old—applet if(Apps ・ size() > 0 ) { for(j=O; j く Apps ・ size(); j + + ) { Apps ・ e1ementAt (j) ; applet applet . removeApp1et (old-applet) ; Apps ・ removeE1ement (old—applet) ; if (Apps ・ size() = = 0 ) { Ⅱ u11 ; / / Dereference storage 0bj ect . App s } / / End of removeApp1ets function Vector Obj ect for JScript Support / / This to support IE only... for NS 0 Ⅱ ly , use java. util. Vector function Vector ( ) { this . length = 0 ; thi s . addE1 ement = addE1 ement ; this . removeE1ement = removeE1ement ; 23 UNIX MAGAZINE 1999.4
マルチスレッド・サーハ・ return port ; * Returns the Mu1tiThreadedHand1er obj ect public abstract Mu1tiThreadedHand1er getHand1er (Socket soc) throws IOException ; * Returns the Messenger ob 」 ect public abstract Messenger getMessenger ( ) throws IOException, CIassNotFoundException; /**When a thread is started this method creates a server socket ob 」 ect * at the specified port and waits for the client connection. When * a client request servxce , it creates a concrete Mu1tiThreadedHand1er * object and starts the handler in a separate thread. public void run() Socket soc=null; t ry server=new ServerSocket (port) ; System. out . println( "Server waiting at " 十 InetAddress. getLoca1Host() + " 0 取 port" 十 port) ; while(true) soc=server. accept() ; System. out ・ printIn("C1ient Connected") ; Mu1tiThreadedHand1er hand1er=getHand1er (soc) ; handler. setMessenger (getMessenger ( ) ) ; handler. start() ; catch(IOException error) System. out . println(error) , catch(CIassNotFoundException error) System. out . println(error) ; finally try server. close() ; catch(IOException error) System. out . println(error) ; UNIX MAGAZINE 1999.4 31
まとめ 以 E 、アプレット間通信を寒見する 3 つのアプローチを 検討してきたが、いすれのアプローチも一長一 - ・ - 短である。 同時に、いすれも Command や Proxy 、 Mediator な どのテサインパターンを利用するといった、優れた言村支 法を組み合わせる余地がある。さらに、 Java のインター フェイスを利用してオプジェクトへの共通アクセスを提供 すれば、問題の単純化にもつながる。 Motorola の Advanced Media Platforms ( テキサス州オースチン ) に在職する Java 技術者。同社における Java に関するトッフ技術者の 1 ん Sun か認竈した Java 開発者でもある。 リスト 1 基本アプレットコード ・ Joseph Cozad アプレット間通信のテサインバターン・ [ 赭文献 ] ◎ 1998 , WEB Techniques (). S. A. ) WEB Techniques 1998 年 10 月号より 「 A Design pattern for Inter-Applet Communications 」 『 JavaScript リファレンス』、オライリー・ジャノヾン、 1997 : 村上列監訳、安藤進訳 tJavaScript プログラミング』 2 れ d 市 0 れ , O'Reilly & Associates, 1997 ( 邦訳 [ 2 ] David FIanagan, ノ似 Sct 、挈た・ The Dq 五れれ加 e Guide ターン』、ソフトバンク、 1995 年 ) 真一訳『オプジェクト指旬における再利用のためのデサインパ ented So れ協 7 ℃ , Addison-Wesley, 1995 ( 邦訳 : 本位田 Design Patterns: EIements 可月 e れ sa 尻 e Obyect- 0 - [ 1 ] E. Gamma, R. Helm, R. Johnson, and J. M. Vlissides, 2 : 3 : 4 : 5 : 6 : 7 : 8 : 9 : 10 : 11 : 12 : 13 : 14 : 15 : 16 : 17 : 18 : 19 : 20 : 21 : 22 : 23 : 24 : 25 : 26 : 27 : 28 : 29 : 30 : 31 : 32 : 33 : 34 : 35 : 36 : import j ava. applet . * ; import 」 ava. awt . * ; import j ava. awt . event . * ; App1etTit1e = new Labe1(name + ” Messages Received: " ) ; add(MessageArea) ; 32 , 264 , 71 ) ; MessageArea. setBounds(my—insets. left 十 16,my—insets. top + MessageArea. setEditab1e(faIse) ; MessageArea. setBackground ( C010 て . white) ; MessageArea = new TextArea() ; setLayout (null) ; setBackground(C010r ・ gray) ; lnsets my_insets = getlnsets() ; setName (name) ; String name = getParameter("name") ; public void init ( ) { Vector RemoteApps = Ⅱ u11 ; TextFieId InputArea; Button SendButton ; Labe1 App1etTit1e ; TextArea MessageArea ; public class TestAppIet extends App1et implements ActionListener{ App1etTit1e. setBounds(my—insets. left + 16 , 11 , 141 , 21 ) ; add(App1etTit1e) ; SendButton = new Button ( "Send" ) ; SendButton. setBounds (my—insets. left + 219 , 110 , 60 , 23 ) ; UNIX MAGAZINE 1999.4 my—insets. top 十 my—insets . top + 21
&add($out [ $ level + 1 ] , $ le Ⅱ [ $ level + 1 ] ) ; sub add { # 既存データに新しいデータを追加 local($buf ,$len) = if ($env C$Ieve1] eq 's' ) { # データを連接 $out [$level] . = ×hift($buf,$len[$level] ) ; $len ) ; $len[$level] ($len[$level] > $len ? $len [$level] $out [$level] = ×ort ($out [$level] . $buf) ; else { # データをマージ $len[$level] + = $len; 10Ca1 ()t , $buf , $note , $notename) ; 10Ca1 ( $ ー ) sub play { 0 インターフェイスの街角 @a = sort bytime @a; 10Ca1 ()a ) ; local($s) = sub timesort { # イベントを時刻順にソート @a IocaI(@a.$i.$s1.$s2); local($s,$t) sub timeshift { # イベント発生時刻をシフト while()— ne $offset [$channel] $offset [$channel] + = $t + = $unitlen; next; $sharpflat = $notename = $ 1 ; 12 ; 12 ; next ; next ; sub sub if()t > 0 & & $note > の { $buf . = sprintf ( "%d Off ch=%d n=%d v=O\n" $t-l ,$channel,$note + $offset [ $ 曲Ⅱ el ] ) ; $buf . = sprintf ( "%d Off ch=%d n=%d v = 0 \ Ⅱ” if()t > 0 & & $note > の { $t + = $unitlen ; else { $t , $channel , $note + $offset [$channel] ) ; $buf . = sprintf ( "%d On ch=%d n=%d v=96\n" if ($note > 0 ) { $sharpflat eq 'b' ? ー 1 : 0 ) ; $note + = ($sharpflat eq ' # ' ? 1 $note{$notename} ; $note $t-l,$channel,$note + $offset [$channel] ) ; UNIX MAGAZINE 1999.4 $ta く = > $tb; $tb = $ 1 ; $ta = $ 1 ; local($ta,$tb) ; sub bytime { &add($buf , (t) ; $sl $ 1 ; $s2 = $sl + $t prologue { print " $len [ 0 ] Meta TrkEnd\n" print $out [ 0 ] ; ep i 1 ogue { print " 0 Tempo 200000 \ n " ・ print "MTrk\n" ・ print "MFi1e 0 1 96 \ Ⅱ " ・ print "TrkEnd\n" ・ 161
・アプレット間通信のテサインバターン く 1 っ 4 っ 0 4 ロ ) 6 「′ 8 0 -1 っっ ) 4- 5 6 「′ 8 -1 っ】っ ) 4- 5 ( 0 ー 8 0 1 2 っ 0 4 ・ 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 8 8 8 8 8 this . e1ementAt e1ementAt ; this . size SIZe; this . array = new array ( ) ; function array(){} function size(){ return(this. length) ; function addEIement (obj ect) { this . array [this . length] this . length 十 = 1 ; 0bj ect ; function removeEIement (obj ect) { var new_array = new array ( ) ; var new—size = 0 ; \par 70 if (this . array Ci] ! = object){ new_array [new_size] this . array[i] ; new_size 十十・ for(var i=O; i く this . length; i + + ) { this . array = new—array ; this . length = new—size ; function eIementAt (index) { return(this . array [index] ) ; リスト 4 プラウサの JVM を不堋したアプレットコード 1 : import java. util. *; 2 : import j ava ・ applet ・ App1et ; 3 : 5 : 6 : 7 : 8 : 10 : 11 : public class MessageRe1ayer{ 12 : private static HashtabIe Apps = nuII ; / / Stores App1et references . 13 : 14 : private MessageReIayer(){} / / Ensures class can't be instantiated. 16 : public static synchronized void addApp1et (AppIet remote—applet) { 17 : if (Apps null){ / / Has a hashtable been created. 18 : Apps = new Hashtab1e ( ) ; 19 : 20 : 21 : MessageReIayer maintains a11 the applet references . You can either use the getApp1et ( ) method to post directly t0 the and applet or use the postCommand() method tO post through the MessageRe1ayer. 24 UNIX MAGAZINE 1999.4
連載 / / Linux でリラックス 図 1 umssync の実行 /mnt /dev/hdal # mount —t ums do s # cd /mnt # touch Long—Fi1e Name # ls 10 Ⅱ g ー f11 # rm long-fil # umssync # touch Long—Fi1e—Name # ls Long—Fi1e—Name ← UMSDOS ファイルシステムをマウント ←長い名前のファイルを作成 ←ファイルの一覧を表示 ← DOS のファイル名になっている ーーファイルを作成 、一——linux— ←もう 1 回、長い名前のファイルを作成 ←今度はまちがいなくできている LOADLIN には、 Windows のコマンド・プロンプト ( バージョン 1.0.9 ) ためか、私の計算機では起動しませ では実行できす、 DOS の英語モードで実行する必要があ んでした。 MicroLinux は上交的新しいのですが、英語 るなど、いくつかの制限があります (É田は 1 月号を参照 のドキュメントがありません。なんとかインストールには 成功したものの、キーポードマップが ASCII 配列では してください ) 。 なく、表示されるメッセージもまったく理解できない 1 の UMSDOS ファイルシステム で、まともに使えませんでした。このため、 MiniLinux と MicroLinux については紹介しません。 UMSDOS ファイルシステムは、 DOS/Windows の 各配布パッケージの紹介を始める前に、プートローダで FAT ファイルシステムをそのまま利用して、 UNIX ファ ある LOADLIN と UMSDOS ファイルシステムについ イルシステムの : 機能を実見する Linux ファイルシステム て簡単に復習しておきましよう ( 1 月号の「 LOADLIN です [ 1 ] 。 UMSDOS ファイルシステムを使えば、 DOS と Linux カーネルの起第ヤヾラメータ」も参照してくだ のファイルシステムではサポートされていない次のような さい ) 。 機能が使えます。 LOADLIN 8 十 3 文字を超える長いファイル名 ファイルのユーザー ID LOADLIN は、 DOS 上で動く Linux カーネルのプー ファイルのグループ ID トローダです。今回紹介する配布パッケージは、いすれ ファイルの許可ビット も LOADLIN を用いて Linux カーネルを起動します。 シンポリック・リンク はとんどの配布パッケージには、 LOADLIN を実行する UMSDOS ファイルシステムでは、 DOS ファイルシス ためのバッチファイルが含まれています。ルートデバイ ーという名前のファ テムのディレクトリに ス ( ここでは DOS のファイルシステムが置かれている —linux— イルがあれは、このファイルを用いて長いファイル名やユ デバイス ) が、プライマリ・マスターである IDE ハ ーザー ID などを変換します ( このファイルは UMSDOS ディスクの 1 番目の基本バーティション ( L ⅲ ux のテンヾ のユーザーからは見えません ) 。一方、このファイルがディ イスファイルでいえば /dev/hdal) であれば、たいてい レクトリになけま、通常の FAT ファイルシステムと同 はこのバッチファイルがそのまま使えます。ルートデバ しように扱われます。 --linux-. イスがそれ以外の場合には、バッチファイルを編集して ーは、 umssync コ マンドで作成します ( 図 1 ) 。 umssync は、 DOS からファ LOADLIN の起重加芋パラメータを変更します。以降では、 イルの追加や削除をおこなったとき、 DOS のファイルシステムが、 IDE ハードディスクの C: -linux. ーーーファ イルの整合性を保っためにも使います。 ドライプ (/dev/hdal) であるものとして説明します。 UMSDOS ファイルシステムを使って、同しファイル 1 URL のトップレ , マレ・ドメインか引すると、セルピア・クロアチ システムを DOS/Windows と Linux の両方で共有する ア言韶 ) ようてす。 89 UNIX MAGAZINE 1999.4
if (c OP_FILE & & ()s . name = = NULL Ⅱ = 〉 strcmp()s . name, valsp—>u. string) ) ) { fs . name = valsp—>u. string, stat (valsp—>u. string , &fs . stat) ; fs . rcode このコードを見れば、同しファイル名に対する stat シ ステムコールを繰り返さずにすむのが分かるのではないで 構文斤の方針 しようか。 ですが、どうやら一筋縄ではいかないようです。 test. c に ・と言いたいところ それではさっそく構文角斤を、 comply vith POSIX P1003.2 / D11.2 Section * POSIX scripts . The f0110 ing special cases requirements tO assure correct evaluation for consistency, we special case the POSIX 1003.2 grammer. In order tO assure some degree Of * Test ( 1 ) implements an inherently ambiguous は、次のようなコメントがあります。 4 . 62.4. TEST. sh というファイルを見ると、まだ解釈できないこ せん。ソース・ディレクトリにある TEST. README や し、このガ去はすべての場合に適用できるわけではありま ます。つまり、解釈できる範囲が広がるわけです。ただ を進め、うまく解釈できなければ通常どおりに構文角斤し ガ去です。このガ去を適用してうまくいけはそのまま処理 う面倒なガ去はとらす、いきなり解釈する " という大胆な これは、、いくっかの簡単な場合には構文角斤などとい いるとあります。 ドは去か瞹昧であり、それを鮹肖するための工夫をして これを読むと、 POSIX で定義されている test コマン 構文解析 ( 1 ) ともあるようです。 最初は、決まった形式の角斤です。こちらは、引数の数 switch(argc に応じて角斤をおこないます。 プログラミング・テクニック switch に、、 argc - 1 " という値を指定しているのは、 1 を引くことによってちょうど引数の数になるからです。引 数カ甘旨定されていない場合 ( 0 ) には、値として 1 を返し ます ( コマンドとしては偽を返します ) 。 引数が 1 つの場合には、文字列カ甘旨定されているとみな し、そオ功ゞ空文字列かどうかを詩ヾます。 case 1 : return (argv [ 1 ] *argv[l] break; / * % test arg * / = NULL Ⅱ 空文字列の場合にも 1 を返し、コマンドの結果は偽と なります。条件判断の部分で、 argv[l] が NULL でない 場合に限って * argv [ 1 ] を検査する点に注意してください。 C 言語では、論理演算の途中てイ直を調べなくても結果が分 かる場合には、残りを実際に調べることはありません。前 半で、、 argv[l] = = NULL" としているため、 こカイ為で あるときだけ後半の牛か検査されます。 引数が 2 つの場合には、知頁が ! なら、引数が 1 つの ときの逆を返すようにします。 2 : argv[l] ; opna.me / * % test op arg * / case 0 : return ( 1 ) ; break ; UNIX MAGAZINE 1999.4 test if (IS_BANG(opname) ) return (*argv [ 2 ] IS-BANG マクロは、 : 頁が ! で、次が \ 0 であるこ とを石忍するマクロです。 これ以外の場合には、知頁が単項演算子であるとみなし て検査をおこないます。 else { ret—val = posix—unary-op (&argv [ 1 ] ) ; if (ret—val > = 0 ) return (ret—val) ; break; posix-unary-op は値として 0 以 E を返すことになっ ており、エラーのときには負の数を返します。単項演算子 だった場合には 0 以止の値カ弡っているはすなので、そ の値をコマンドの戻り値とします。負の数カってきたと きは単項演算子ではなかったことになるので、きちんと解 析するために switch 文を抜けます。 引数が 3 個の場合は、知頁が ! であれば 2 個のときと 同しです。 115
・マルチスレッド・サーハ * Constructor takes the Socket object created in the protected Messenger mess ; protected Socket soc; public abstract class Mu1tiThreadedHand1er extends Thread import j ava. net. * ; lmport java. iO. * ; * This abstract class handles the client 's requests リスト 2 MultiThreadedHandler クラス * Mu1tiThreadedServer class public Mu1tiThreadedHandIer (Socket SOC) throws IOException, thiS . SOC =soc ; StreamCorruptedException * SubcIasses implements this abstract method vhich does the * communication between the client and server public abstract VOid communicate() throws lOException; * Simp1y calls the communicate ( ) method when this thread is * started. This method is called by the run() method in the 32 soc . close() ; public void close() throws IOException * C10se the opened socket connection System. out. println(error) ; catch(IOException error) communicate() ; try public void run() * Mu1tiThreadedServer class UNIX MAGAZINE 1999.4