利用 OSGi 解決 Eclipse 插件難題

發表于:2007-05-24來源:作者:點擊數: 標簽:eclipseOSGi難題插件利用
本文介紹如何在代碼中為其他插件編寫擴展,而不是用 Eclipse V3.2 的動態擴展 API 創建對其他插件的依賴性??墒褂瞄_放服務網關協議 (Open Services Gateway Initiative,OSGi) 服務 API 和動態 API 完成所有這些任務甚至更多任務。 本文介紹了一個采用 XML
本文介紹如何在代碼中為其他插件編寫擴展,而不是用 Eclipse V3.2 的動態擴展 API 創建對其他插件的依賴性??墒褂瞄_放服務網關協議 (Open Services Gateway Initiative,OSGi) 服務 API 和動態 API 完成所有這些任務甚至更多任務。

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

插件、擴展點、OSGi

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

示例插件

讓我們從公開擴展點的基本插件開始,這樣可以為同義詞服務注冊新的字符串映射。此項服務允許其他服務注冊一個詞并將其映射到另一個詞(同義詞)?;緮U展包含非常簡單的元素:一個詞,當然還有一個新的同義詞。此插件擴展點的基本結構如表 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 領域,我們不是總知道另一服務可用的時間,因此我們需要對此進行說明。通過注冊為服務偵聽器,我們可得知服務開始和停止的時間。如果服務不可用,則允許我們緩存同義詞。當服務確實可用時,我們會得到通知并注冊擴展。

注冊新擴展

下面我們將講述本文的核心內容?,F在我們有了想為其提供動態擴展的數據 (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?,F在,我們的代碼看上去類似如下。有關此問題中的 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% 退耦。

原文轉自:http://www.anti-gravitydesign.com

国产97人人超碰caoprom_尤物国产在线一区手机播放_精品国产一区二区三_色天使久久综合给合久久97