Luben Park

          Java Ben 成長(zhǎng)之路

          Java 技巧 101:applet 間通信的替代方法

          作者 Tobias Hill



          摘要
          您可能認(rèn)為能讓 applet 彼此通信的唯一選擇就是使用 getApplet。不幸的是,getApplet 方法僅返回與發(fā)出調(diào)用的 applet 在同一個(gè) HTML 頁面上的 applet,這樣就限制了您通過 applet 間的通信構(gòu)建有趣界面的方式。這篇技巧說明的替代方法能使處于不同框架甚至不同瀏覽器窗口中的 applet 彼此調(diào)用對(duì)方的方法。

          java.applet 包中的 AppletContext 類包含兩個(gè)成員方法,即 getApplet 和 getApplets。通過使用這兩個(gè)方法,一個(gè) applet 就可以找到其他 applet 并調(diào)用它們的方法。要這樣做必須滿足下面的安全要求:

        1. 這些 applet 來自同一個(gè)服務(wù)器上的同一個(gè)目錄中。
        2. 這些 applet 運(yùn)行于同一個(gè)瀏覽器窗口中的同一個(gè)頁面上。

          這樣設(shè)計(jì)安全限制可能有很好的原因;但是,后一個(gè)要求限制了利用 applet 間的通信制作有趣的多 applet 界面的方式。

          試考慮這樣一種情況:

          您剛編好一個(gè)很好的股票市場(chǎng)交易 applet,并決定為它編寫一個(gè)良好的幫助系統(tǒng)。您希望幫助系統(tǒng)也是一個(gè) applet,并希望將它與股票市場(chǎng)交易 applet 在不同的瀏覽器框架中運(yùn)行。您作出這個(gè)決定可能是出于網(wǎng)站結(jié)構(gòu)方面的考慮,也可能是出于始終顯示幫助系統(tǒng)的需要。另外,您希望使幫助系統(tǒng)根據(jù)用戶當(dāng)前在股票交易 applet 中進(jìn)行的操作轉(zhuǎn)至正確的信息/指導(dǎo)(就像 Microsoft Office 套件中的“回形針”一樣)。您甚至計(jì)劃在幫助系統(tǒng)中編制向?qū)В@些向?qū)Э蛇h(yuǎn)程指出問題,并可遠(yuǎn)程執(zhí)行股票市場(chǎng)交易 applet 中的任務(wù)。

          這一方案中體現(xiàn)的思想很不錯(cuò)。但是,因?yàn)檫@兩個(gè) applet 處于不同的頁面上,所以 AppletContext 中的 Java API 無法幫助您實(shí)現(xiàn)這個(gè)想法 -- 但這篇技巧可以幫助您。


          使用 AppletContext API

          在說明 applet 間通信的替代機(jī)制前,我將首先簡(jiǎn)要說明一下 getApplet 和 getApplets 這兩個(gè)方法是如何工作的。一個(gè) applet 通過使用 getApplet 方法可以按名稱找到同一個(gè) HMTL 頁面中的另一個(gè) applet,而通過使用 getApplets 方法可以找到同一個(gè)頁面上的所有 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>

          通過使用 applet 標(biāo)記中的 name 屬性,您就可以用下面的方式引用一個(gè)特定的 applet:
          PHP代碼:
          Applet theOtherApplet = getApplet("app1");
          theOtherApplet.anyMethod(); //調(diào)用任一個(gè)公用方法

          或者,您也可以用以下的代碼來檢索這個(gè)頁面上的所有 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 頁面上檢索到一個(gè)或幾個(gè) applet 之后,它就可以調(diào)用這些 applet 的公用方法。

          使用靜態(tài)數(shù)據(jù)結(jié)構(gòu)

          不幸的是,如果使用標(biāo)準(zhǔn)方法,則只能與同一個(gè) HTML 頁面中的 applet 通信。幸運(yùn)的是,您很容易就可以避開這個(gè)限制。使 applet 間跨頁面通信的方法基于這樣一個(gè)事實(shí),即如果兩個(gè) applet 的 codebase 相同,則即使它們是在不同的瀏覽器窗口中被加載的,它們也共享同一個(gè)運(yùn)行時(shí)環(huán)境。粗略地說,codebase 就是從中加載 applet 的那個(gè)目錄。請(qǐng)參閱文后的參考資源,其中有一個(gè)鏈接指向有關(guān) codebase 的一篇教程。

          由于運(yùn)行時(shí)環(huán)境是共享的,因此所有 applet 實(shí)例都可以訪問靜態(tài)域和靜態(tài)結(jié)構(gòu),這樣這些靜態(tài)域和結(jié)構(gòu)就可用來在不同 applet 之間傳遞信息。

          applet 不僅可以存儲(chǔ)諸如整數(shù)、字符和字符串這樣的簡(jiǎn)單數(shù)據(jù)類型,而且每個(gè) applet 都可以將其自身(實(shí)例)的一個(gè)引用存儲(chǔ)在一個(gè)靜態(tài)域(可能在它自己的類中)中。任何 applet 都可以訪問這個(gè)域,從而獲得指向這個(gè)實(shí)例的引用。

          這聽起來復(fù)雜嗎?不,一點(diǎn)也不復(fù)雜。我首先舉一個(gè)簡(jiǎn)單的例子。假定您的一個(gè) applet (AppletA.class) 在一個(gè)框架中,而另一個(gè) applet (AppletB.class) 在另一個(gè)框架中,而且這兩個(gè) applet 都是從同一個(gè) codebase 加載的。

          您現(xiàn)在希望授予 AppletA 訪問 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 訪問 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è)頁面上,這個(gè)方法同樣奏效。

          值得注意的一點(diǎn)是,上面的代碼并沒有處理在啟動(dòng) AppletB 之前就調(diào)用 AppletA 中的 callAppletB 方法的情況。如果發(fā)生這種情況,則 selfRef 將是 null,這樣不能進(jìn)行任何通信。

          一種更通用的方法

          當(dāng)然,還有一種更通用的方法。您可以創(chuàng)建這樣一個(gè)類,創(chuàng)建它的唯一目的就是在靜態(tài)數(shù)據(jù)結(jié)構(gòu)中存儲(chǔ) applet 的引用。稍后您將看到的 AppletList 類就屬于這種情況。希望其他 applet 訪問自己的公用方法的 applet 實(shí)例通過 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ì)它的訪問權(quán):
          PHP代碼:
          public class AppletB {
          public
          void run() {
          AppletA tradeApplet =
          (
          AppletA) AppletList.getApplet("Stock-trade-applet");
          ...
          }
          }

          當(dāng)該 applet 停止運(yùn)行時(shí),您必須緊記在 AppletList 中撤銷注冊(cè):
          PHP代碼:
          public void stop() {
          AppletList.remove("Stock-trade-applet");
          ...
          }

          AppletList 類的完整源代碼如下所示:
          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: }

          要獲得說明如何使用這個(gè)類的示例,請(qǐng)?jiān)趨⒖假Y源中下載 exampleCode.zip。

          局限性

          正如我在前面提到的那樣,必須從同一個(gè) codebase 中加載這些 applet。此外,如果瀏覽器的兩個(gè)不同副本正在運(yùn)行,并且 applet 被加載到每個(gè)副本中,則 applet 可能無法彼此通信(取決于瀏覽器的版本和設(shè)置),因?yàn)樗鼈兛赡懿辉俟蚕硗粋€(gè)運(yùn)行時(shí)環(huán)境。但是,如果是瀏覽器本身衍生出新的瀏覽器窗口,則沒有任何問題。

          該技巧已在幾個(gè)平臺(tái)和幾個(gè)瀏覽器版本中通過測(cè)試,但在某些配置中每個(gè) applet 的運(yùn)行時(shí)環(huán)境可能是獨(dú)立的。該技巧已在下面的操作系統(tǒng)和瀏覽器組合中通過測(cè)試:
        3. Windows2000: Internet Explorer 5.0,Internet Explorer 5.5,Netscape Navigator 4.72,Opera 4.01
        4. Windows 98: Internet Explorer 4.72,Internet Explorer 5.0,Netscape Navigator 4.02
        5. Mac OS 9: Internet Explorer 4.5,
        6. Netscape Navigator 4.5
          Red Hat 6.2: Netscape Navigator 4.73

          小結(jié)

          這篇技巧說明了能使 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 年開始用 Java 編程,參與了許多項(xiàng)目,從為自主控制的機(jī)器人編程到開發(fā)在線焰火明信片制作程序等等。

          參考資源

          * 說明如何使用 AppletList 類的示例:
          exampleCode.zip
          * Sun 提供的關(guān)于 applet 間通信的 Java 教程:
          http://web2.java.sun.com/docs/books...tsonly/iac.html
          * Sun 提供的有關(guān) codebase(在其他問題中)的 Java 教程:
          http://web2.java.sun.com/docs/books...sonly/html.html
          * 查看以前的所有 Java 技巧以及提交您自己的技巧:
          http://www.javaworld.com/javatips/j...tips.index.html
        7. posted on 2005-12-23 17:06 Ben 閱讀(371) 評(píng)論(0)  編輯  收藏


          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 潼关县| 神木县| 晋宁县| 综艺| 安宁市| 延吉市| 海丰县| 黎川县| 永嘉县| 柳江县| 射阳县| 枞阳县| 客服| 麻阳| 合阳县| 石狮市| 江源县| 安西县| 尉氏县| 邢台市| 丁青县| 神池县| 沙湾县| 诸城市| 防城港市| 邢台市| 晋江市| 无为县| 巴林左旗| 濮阳市| 格尔木市| 丰宁| 黑河市| 瑞昌市| 广丰县| 兴和县| 武清区| 萨迦县| 犍为县| 黔江区| 安阳市|