程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 利用OSGi解決Eclipse插件難題

利用OSGi解決Eclipse插件難題

編輯:關於JAVA

使用 Open Services Gateway Initiative API 消除 Eclipse 插件依賴性

本文介紹了一個采用 XML 的插件示例,以便為定義好的擴展點注冊擴展。通過使插件能夠感知 Extention Registry 並提供 OSGi 服務,我們可以完成這一完整的組件退耦操作。

插件、擴展點、OSGi

如您所知,Eclipse 的組件架構是基於插件 的 -- 這意味著將一組代碼組件化為單一的組件,然後利 用 Eclipse 框架注冊為其組件之一,其他組件可以綁定該組件或調用該組件。擴展點 是插件允許其他插 件向公開擴展點的插件提供附加功能的方法。現在利用所有這些插件並將其包裝到受控的運行時,插件可 在其中動態進出,並且您可以獲得 OSGi(基本上來說)。

示例插件

讓我們從公開擴展點的基本插件開始,這樣可以為同義詞服務注冊新的字符串映射。此項服務允許其 他服務注冊一個詞並將其映射到另一個詞(同義詞)。基本擴展包含非常簡單的元素:一個詞,當然還有 一個新的同義詞。此插件擴展點的基本結構如表 1 所示。

表 1. 示例插件的元素

插件名稱 com.company.SynonymRegistry 擴展點 同義詞 元素 詞 -- 您想要為其添加同義詞的詞

同義詞 -- 您想要注冊的同義詞

我們還要將插件注冊為 OSGi 服務。這意味著它只在顯式執行此操作時被加載,並將可供其他客戶聲 明性地使用。為了使用該服務,其他客戶只需了解 Interface 和 OSGi 類名稱。在我們的示例中,我們 不會真正調用該服務,因為擴展點是假設的。我們將使用 OSGi API 以告知我們此項服務出入的時間,所 以我們可以正確地注冊擴展點。

現在這只是一個示例,並且使用針對此概念的擴展點可能不是最好的方法。我們用此基本示例要達到 的目的是如何動態注冊新的擴展,同時說明使用 OSGi API 的插件生命周期事件。

Mediator 插件

下一個插件是第三方插件,該插件了解已知的服務和擴展點,但不想綁定到此插件,因為後面它將依 靠該插件進行運行時解析。這意味著該插件可以駐留在所引用的插件 (com.company.SynonymRegistry) 可能不存在的機器上。因為我們現在生活在 OSGi 和動態運行時世界,所以我們想確保插件在不引起運行 時故障或錯誤的情況下運行。我們的 mediator 插件將接受同義詞的 XML 文件,並且通過使用提供的擴 展點用 SynonymRegistry 插件注冊每個同義詞。

清單 1. 用於概念驗證的示例 XML 文件

Synonyms.xml
<?xml version="1.0" encoding="UTF-8"?>
<synonyms>
  <entry word="mediator" synonym="broker"/>
  <entry word="mediator" synonym="go-between"/>
  <entry word="mediator" synonym="interceder"/>
  <entry word="mediator" synonym="intermediary"/>
<synonyms>

Mediator 插件在其 start() 方法中做的第一件事是用 OSGi 服務注冊為一個服務初始化偵聽器。我 們要在傳入 start() 方法的 BundleContext 對象上調用 OSGi 服務方法 addServiceListener()。以下 代碼展示了一個通過傳入代碼和我們感興趣的服務 ID 調用此 API 的示例。

context.addServiceListener( this, "com.company.SynonymRegistry" );

通過提供過濾器,可以告知 OSGi 服務注冊中心只需通知您指定服務中的狀態更改。在本例中,過濾 器只是 SynonymRegistry 類的類名稱。

您可能會尋根究底。答案就在啟動序列中。在 OSGi 領域,我們不是總知道另一服務可用的時間,因 此我們需要對此進行說明。通過注冊為服務偵聽器,我們可得知服務開始和停止的時間。如果服務不可用 ,則允許我們緩存同義詞。當服務確實可用時,我們會得到通知並注冊擴展。

注冊新擴展

下面我們將講述本文的核心內容。現在我們有了想為其提供動態擴展的數據 (Synonyms.xml) 和已知 的擴展點 (com.company.SynonymRegistry. Synonym)。由於我們不知道何時初始化插件,也不知道是否 初始化 Synonym 插件,所以我們只要在加載插件時嘗試注冊 XML 文件中的條目即可。請記住:這是一個 展示概念的示例,不應在生產代碼中這樣實施。通常,我們盡可能多地以惰性方式(延遲或在需要時)執 行初始化。

Eclipse V3.2 中的新特性是能夠在運行時提供擴展。例如,客戶可以編寫一個包含某個視圖的應用程 序,該視圖可以在單擊按鈕時創建一個透視圖。透視圖被添加到擴展注冊表,然後在可用透視圖的列表中 顯示。此功能的重要好處之一是它可以減輕插件之間的“硬”依賴性。插件 A 可供在插件 B 中定義的平 台使用,無需依賴插件 B。而且,通過將此功能與 OSGi 框架結合,插件可以檢查服務的存在性,如果存 在,可從服務中定義的擴展點創建擴展。這在使用面向服務架構的原則同時,促進了真正動態的環境。

Eclipse V3.2 中新公開的是 addContribution() 方法,該方法在 IExtensionRegistry 接口中定義 。清單 2 中的代碼展示了可以通過 addContribution() API 添加擴展的方法。addContribution() 方法 旨在采用普通 XML 作為第一個參數中的 InputStream。

清單 2. 通過 addContribution() API 添加擴展的方法

IExtensionRegistry registry = RegistryFactory.getRegistry( );
Object key = ((ExtensionRegistry) registry).getTemporaryUserToken( );
ByteArrayInputStream is =
    new ByteArrayInputStream( buffer.toString().getBytes() );
    
try {
  registry.addContribution(is, bundle, null, null, key);  
}  
finally {  
try {
    is.close( );
  }catch (IOException e) {
        
  }
}

編寫本文的時候 -- 意味著這是一個更改 Eclipse 未來版本的好機會 -- 允許公眾訪問注冊表的用戶 標記可以使用此內部 Eclipse 調用獲得。下面的代碼展示了內部 API (getTemporaryUserToken()) 的使 用。

Object key = ((ExtensionRegistry)registry).getTemporaryUserToken();

但是,在裡程碑式的下一版本 Eclipse V3.2 版本中,此標記不能公開訪問。為了支持應用程序中的 動態擴展,啟動程序必須提供以下針對虛擬機的設置:

-Declipse.registry.nulltoken=true

此定義現在允許我們將 null 用作 addContribution() API 中的 User Token。現在,我們的代碼看 上去類似如下。有關此問題中的 Bugzilla 對話,請參見 Bugzilla bug 清單。

清單 3. getTemporaryUserToken()

...
try {
  registry.addContribution(is, bundle, null, null, null);  
}  
...

上面顯示的緩沖區變量表示實際的 XML 塊。此 XML 是我們可以在 plugin.xml 文件內看到的精確副 本。回到我們的 SynonymRegistry 示例,此擴展的 XML 將類似清單 4。

清單 4. SynonymRegistry 的 XML

<plugin>
  <extension point="com.company.synonymregistry" id="myExtension">
    <synonyms
      word="mediator"
      synonym="broker"/>
  </extension>
</plugin>

客戶可以考慮創建一個接受以下參數的包裝工廠類,如擴展點 ID、擴展 ID、元素名稱(本例中是同 義詞)、實際屬性和資源包 ID。該包裝類將參數格式化為類似上面代碼的 XML 字符串。然後將此 XML 字符串讀入將被傳入到 IExtensionRegistry 接口的 addContribution() 方法的 ByteArrayInputStream 中。只有此方法的其他必需參數是用戶標記和資源包 ID。值得注意的一點是,資源包 ID 應是做出該貢 獻的資源包的 ID,不是在其中定義擴展點的資源包的 ID。

警告和提示

在 M5(於 2006 年 2 月 17 日構建的 Eclipse)中引入的一個特性是,對 addContributions() 的 調用是異步調用。這意味著該擴展不可立即使用,因為 Eclipse 啟動了一項執行實際注冊的作業。簡單 地說,您必須開始自己的作業並與之同步,以獲得任何類型的同步行為。

為了使此項任務更容易,下面給出了三條提示:

創建一項將其本身注冊為一個 RegistryChangeListener 的新作業。

該作業運行時,確保您的作業代碼偵聽 RegistryListener 回調的 isRegistered 集合。

一旦所有注冊完成,即退出您的作業。

當然,現在我們必須將調用代碼與生成的作業結合起來,以獲得同步調用。這只有在代碼要求立即使 用擴展時才得到保證。希望您的代碼設計為惰性,這樣初始化就變得不重要。

結束語

動態擴展的使用可以通過編程方式創建。通過使用 OSGi 框架偵聽服務何時可用(加載或卸載),動 態擴展增強了退耦功能。一起使用這些技術將允許聲明性的貢獻和組件之間 100% 退耦。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved