作者 Tobias Hill
摘要 您可能認(rèn)為能讓 applet 彼此通信的唯一選擇就是使用 getApplet。不幸的是,getApplet 方法僅返回與發(fā)出調(diào)用的 applet 在同一個(gè) HTML 頁(yè)面上的 applet,這樣就限制了您通過(guò) applet 間的通信構(gòu)建有趣界面的方式。這篇技巧說(shuō)明的替代方法能使處于不同框架甚至不同瀏覽器窗口中的 applet 彼此調(diào)用對(duì)方的方法。 java.applet 包中的 AppletContext 類(lèi)包含兩個(gè)成員方法,即 getApplet 和 getApplets。通過(guò)使用這兩個(gè)方法,一個(gè) applet 就可以找到其他 applet 并調(diào)用它們的方法。要這樣做必須滿(mǎn)足下面的安全要求:
這些 applet 來(lái)自同一個(gè)服務(wù)器上的同一個(gè)目錄中。
這些 applet 運(yùn)行于同一個(gè)瀏覽器窗口中的同一個(gè)頁(yè)面上。
這樣設(shè)計(jì)安全限制可能有很好的原因;但是,后一個(gè)要求限制了利用 applet 間的通信制作有趣的多 applet 界面的方式。
試考慮這樣一種情況:
您剛編好一個(gè)很好的股票市場(chǎng)交易 applet,并決定為它編寫(xiě)一個(gè)良好的幫助系統(tǒng)。您希望幫助系統(tǒng)也是一個(gè) applet,并希望將它與股票市場(chǎng)交易 applet 在不同的瀏覽器框架中運(yùn)行。您作出這個(gè)決定可能是出于網(wǎng)站結(jié)構(gòu)方面的考慮,也可能是出于始終顯示幫助系統(tǒng)的需要。另外,您希望使幫助系統(tǒng)根據(jù)用戶(hù)當(dāng)前在股票交易 applet 中進(jìn)行的操作轉(zhuǎn)至正確的信息/指導(dǎo)(就像 Microsoft Office 套件中的“回形針”一樣)。您甚至計(jì)劃在幫助系統(tǒng)中編制向?qū)?,這些向?qū)Э蛇h(yuǎn)程指出問(wèn)題,并可遠(yuǎn)程執(zhí)行股票市場(chǎng)交易 applet 中的任務(wù)。
這一方案中體現(xiàn)的思想很不錯(cuò)。但是,因?yàn)檫@兩個(gè) applet 處于不同的頁(yè)面上,所以 AppletContext 中的 Java API 無(wú)法幫助您實(shí)現(xiàn)這個(gè)想法 -- 但這篇技巧可以幫助您。
使用 AppletContext API
在說(shuō)明 applet 間通信的替代機(jī)制前,我將首先簡(jiǎn)要說(shuō)明一下 getApplet 和 getApplets 這兩個(gè)方法是如何工作的。一個(gè) applet 通過(guò)使用 getApplet 方法可以按名稱(chēng)找到同一個(gè) HMTL 頁(yè)面中的另一個(gè) applet,而通過(guò)使用 getApplets 方法可以找到同一個(gè)頁(yè)面上的所有 applet。這兩個(gè)方法如果成功執(zhí)行,則會(huì)向調(diào)用者返回一個(gè)或多個(gè) Applet 對(duì)象。調(diào)用者一旦找到一個(gè) Applet 對(duì)象,它就可能調(diào)用這個(gè) Applet 的公用方法。
假定有下面這樣一段 HTML 代碼:
PHP代碼:
<applet code="Applet1" width="400" height="100" name="app1">
</applet>
<applet code="Applet2" width="400" height="100" name="app2">
</applet>
通過(guò)使用 applet 標(biāo)記中的 name 屬性,您就可以用下面的方式引用一個(gè)特定的 applet:
PHP代碼:
Applet theOtherApplet = getApplet("app1");
theOtherApplet.anyMethod(); //調(diào)用任一個(gè)公用方法
或者,您也可以用以下的代碼來(lái)檢索這個(gè)頁(yè)面上的所有 applet:
PHP代碼:
Enumeration allAppletsOnSamePage = getApplets();
while(allAppletsOnSamePage.hasMoreElements()) {
Applet appl = (Applet) allAppletsOnSamePage.nextElement();
appl.anyMethod(); //調(diào)用任一個(gè)公用方法
}
當(dāng)發(fā)出調(diào)用的 applet 在它所在的同一個(gè) HTML 頁(yè)面上檢索到一個(gè)或幾個(gè) applet 之后,它就可以調(diào)用這些 applet 的公用方法。
使用靜態(tài)數(shù)據(jù)結(jié)構(gòu)
不幸的是,如果使用標(biāo)準(zhǔn)方法,則只能與同一個(gè) HTML 頁(yè)面中的 applet 通信。幸運(yùn)的是,您很容易就可以避開(kāi)這個(gè)限制。使 applet 間跨頁(yè)面通信的方法基于這樣一個(gè)事實(shí),即如果兩個(gè) applet 的 codebase 相同,則即使它們是在不同的瀏覽器窗口中被加載的,它們也共享同一個(gè)運(yùn)行時(shí)環(huán)境。粗略地說(shuō),codebase 就是從中加載 applet 的那個(gè)目錄。請(qǐng)參閱文后的參考資源,其中有一個(gè)鏈接指向有關(guān) codebase 的一篇教程。
由于運(yùn)行時(shí)環(huán)境是共享的,因此所有 applet 實(shí)例都可以訪問(wèn)靜態(tài)域和靜態(tài)結(jié)構(gòu),這樣這些靜態(tài)域和結(jié)構(gòu)就可用來(lái)在不同 applet 之間傳遞信息。
applet 不僅可以存儲(chǔ)諸如整數(shù)、字符和字符串這樣的簡(jiǎn)單數(shù)據(jù)類(lèi)型,而且每個(gè) applet 都可以將其自身(實(shí)例)的一個(gè)引用存儲(chǔ)在一個(gè)靜態(tài)域(可能在它自己的類(lèi)中)中。任何 applet 都可以訪問(wèn)這個(gè)域,從而獲得指向這個(gè)實(shí)例的引用。
這聽(tīng)起來(lái)復(fù)雜嗎?不,一點(diǎn)也不復(fù)雜。我首先舉一個(gè)簡(jiǎn)單的例子。假定您的一個(gè) applet (AppletA.class) 在一個(gè)框架中,而另一個(gè) applet (AppletB.class) 在另一個(gè)框架中,而且這兩個(gè) applet 都是從同一個(gè) codebase 加載的。
您現(xiàn)在希望授予 AppletA 訪問(wèn) AppletB 的公用方法的權(quán)限。您必須讓 AppletB 將其自身的一個(gè)引用存儲(chǔ)在一個(gè)靜態(tài)公用域中,就像下面這樣:
PHP代碼:
public class AppletB {
public static AppletB selfRef = null; // 初始?xì)w零
public void init() {
// 生成對(duì)該實(shí)例的引用
selfRef = this;
}
...
}
現(xiàn)在您就可以從 AppletA 訪問(wèn) AppletB 的實(shí)例了:
PHP代碼:
public class AppletA {
AppletB theOtherApplet = null;
public void callAppletB() {
// 獲取靜態(tài)域,其中存儲(chǔ)著指向 AppletB 的
// 實(shí)例的指針。
theOtherApplet = AppletB.selfRef;
// 此后就可以調(diào)用實(shí)例方法了,
// 如下所示...
theOtherApplet.repaint();
}
...
}
這就是我們所要做的全部工作。因?yàn)檫\(yùn)行時(shí)環(huán)境是由不同的 applet 共享的,所以即便 applet 不在同一個(gè)頁(yè)面上,這個(gè)方法同樣奏效。
值得注意的一點(diǎn)是,上面的代碼并沒(méi)有處理在啟動(dòng) AppletB 之前就調(diào)用 AppletA 中的 callAppletB 方法的情況。如果發(fā)生這種情況,則 selfRef 將是 null,這樣不能進(jìn)行任何通信。
一種更通用的方法
當(dāng)然,還有一種更通用的方法。您可以創(chuàng)建這樣一個(gè)類(lèi),創(chuàng)建它的唯一目的就是在靜態(tài)數(shù)據(jù)結(jié)構(gòu)中存儲(chǔ) applet 的引用。稍后您將看到的 AppletList 類(lèi)就屬于這種情況。希望其他 applet 訪問(wèn)自己的公用方法的 applet 實(shí)例通過(guò) AppletList 將自己注冊(cè)。按照 AppletContext.getApplet(string name) 中的模式,每個(gè)注冊(cè)項(xiàng)都與一個(gè)字符串相關(guān)聯(lián)。當(dāng)一個(gè) applet 調(diào)用某個(gè) applet 的引用時(shí),這個(gè)字符串就起關(guān)鍵字的作用。
通常,applet 是按下面的方式注冊(cè)的:
PHP代碼:
public class AppletA {
public void start() {
AppletList.register("Stock-trade-applet", this);
...
}
}
另一個(gè) applet 獲取對(duì)它的訪問(wèn)權(quán):
PHP代碼:
public class AppletB {
public void run() {
AppletA tradeApplet =
(AppletA) AppletList.getApplet("Stock-trade-applet");
...
}
}
當(dāng)該 applet 停止運(yùn)行時(shí),您必須緊記在 AppletList 中撤銷(xiāo)注冊(cè):
PHP代碼:
public void stop() {
AppletList.remove("Stock-trade-applet");
...
}
AppletList 類(lèi)的完整源代碼如下所示:
PHP代碼:
0: import java.util.*;
1: import java.applet.Applet;
2:
3: public class AppletList {
4: private static Hashtable applets = new Hashtable();
5:
6: public static void register(String name, Applet applet) {
7: applets.put(name,applet);
8: }
9:
10: public static void remove(String name) {
11: applets.remove(name);
12: }
13:
14: public static Applet getApplet(String name) {
15: return (Applet) applets.get(name);
16: }
17:
18: public static Enumeration getApplets() {
19: return applets.elements();
20: }
21:
22: public static int size() {
23: return applets.size();
24: }
25: }
要獲得說(shuō)明如何使用這個(gè)類(lèi)的示例,請(qǐng)?jiān)趨⒖假Y源中下載 exampleCode.zip。
局限性
正如我在前面提到的那樣,必須從同一個(gè) codebase 中加載這些 applet。此外,如果瀏覽器的兩個(gè)不同副本正在運(yùn)行,并且 applet 被加載到每個(gè)副本中,則 applet 可能無(wú)法彼此通信(取決于瀏覽器的版本和設(shè)置),因?yàn)樗鼈兛赡懿辉俟蚕硗粋€(gè)運(yùn)行時(shí)環(huán)境。但是,如果是瀏覽器本身衍生出新的瀏覽器窗口,則沒(méi)有任何問(wèn)題。
該技巧已在幾個(gè)平臺(tái)和幾個(gè)瀏覽器版本中通過(guò)測(cè)試,但在某些配置中每個(gè) applet 的運(yùn)行時(shí)環(huán)境可能是獨(dú)立的。該技巧已在下面的操作系統(tǒng)和瀏覽器組合中通過(guò)測(cè)試:
Windows2000: Internet Explorer 5.0,Internet Explorer 5.5,Netscape Navigator 4.72,Opera 4.01
Windows 98: Internet Explorer 4.72,Internet Explorer 5.0,Netscape Navigator 4.02
Mac OS 9: Internet Explorer 4.5,
Netscape Navigator 4.5
Red Hat 6.2: Netscape Navigator 4.73
小結(jié)
這篇技巧說(shuō)明了能使 applet 彼此通信的一種替代方法。這種方法以 Java API 的 getApplet() 方法不支持的方式工作。這篇技巧中介紹的知識(shí)增大了將 applet 作為網(wǎng)站或內(nèi)部網(wǎng)的一部分的可能性 -- 可以用它替代或補(bǔ)充 getApplets 方法。
作者簡(jiǎn)介
Tobias Hill 是 Citerus 的創(chuàng)辦者之一,該公司以瑞典為基地,致力于在 Java 平臺(tái)上構(gòu)建因特網(wǎng)、內(nèi)部網(wǎng)和外部網(wǎng)系統(tǒng)。Hill 從 1996 年開(kāi)始用 Java 編程,參與了許多項(xiàng)目,從為自主控制的機(jī)器人編程到開(kāi)發(fā)在線焰火明信片制作程序等等。
參考資源
* 說(shuō)明如何使用 AppletList 類(lèi)的示例:
exampleCode.zip
* Sun 提供的關(guān)于 applet 間通信的 Java 教程:
http://web2.java.sun.com/docs/books...tsonly/iac.html
* Sun 提供的有關(guān) codebase(在其他問(wèn)題中)的 Java 教程:
http://web2.java.sun.com/docs/books...sonly/html.html
* 查看以前的所有 Java 技巧以及提交您自己的技巧:
http://www.javaworld.com/javatips/j...tips.index.html