(運用 OSGi 有二個重要的概念,Extender Model 與 Whiteboard Pattern), 這邊主要針對Whiteboard Pattern做例子。
實現OSGi Extender Model非常的簡單,編寫一個Bundle Listener,監聽Bundle的安裝、卸載、更新。
Extender Model 的運作模式就是,您預先準備好一個 Bundle。這個 Bundle 會在您要啟用的子系統前先啟動完畢。它會註冊 Bundle Listener,發現有 Bundle 啟動時,就去它的 metadata 或找到需要作用的特徵。並對它自動地,做某些事情。
可以參考
OSGi 4.2: Extender Pattern and BundleTracker
(Spring DM 就實作了類似的 Extender Bundle,當您的 Bundle 有採用 Spring Framework 時(通常是判斷 /META-INF/spring/ 資料夾),它會將 Spring Configuration 取出,做 Bean 初始化的動作。)
WhiteBoard actors
OSGi的白板模式(White board Pattern) , 是什麼?Whiteboard Pattern比原始監聽模式的要更進一步,利用OSGI本身的ServiceTracker服務跟踪監聽class作為Listener的觸發機制,這樣,基於OSGI開發事件模式,就不用把Listener註冊到Source,從而發生緊耦合,只要雙方直接註冊到OSGI中就可以了。
在OSGi WhiteBoard Pattern 的pdf中提到一些information ,
可在這找到
Listeners Considered Harmful:The “Whiteboard” Pattern
文中主要是針對Listener Pattern 跟 Whiteboard Pattern的比較,這邊我只實作whiteboard pattern ,建立一個Interface ,提供getUpdateMessage()的method , 有2個Consumer實作Interface ,
一個Producer包含了ServiceTracker,可取得目前要監看的Interface service
Bundle class list show as below:
WhiteBoardPattern.Interface Bundle Detail
WhiteBoardPattern.Interface 裡面只包含一個IUpdateCommand Interface , Export-package 出去
WhiteBoardPattern.Interface.IUpdateCommand
package WhiteBoardPattern.Interface; public interface IUpdateCommand { public String getUpdateMessage(); }
Manifest.mf 檔
Manifest-Version: 1.0 Export-Package: WhiteBoardPattern.Interface;version="1.0.0" Unversioned-Imports: * Build-Jdk: 1.6.0_24 Built-By: momo Bundle-Version: 1.0.0 Tool: Bnd-1.15.0 Bnd-LastModified: 1304393278593 Bundle-Name: Spring OSGi Bundle Bundle-ManifestVersion: 2 Created-By: Apache Maven Bundle Plugin Bundle-SymbolicName: WhiteBoardPattern.Interface
WhiteBoardPattern.Consumer Bundle Detail
WhiteBoardPattern.Consumer.PluginConsumer
package WhiteBoardPattern.Consumer; import WhiteBoardPattern.Interface.IUpdateCommand; /** * @author momo * */ public class PluginConsumer implements IUpdateCommand { public String getUpdateMessage() { return "Update Class is " this.getClass().getName(); } }
Bundle-Context.xml 設定
<bean id="pluginConsumer1" class="WhiteBoardPattern.Consumer.PluginConsumer"></bean>
Osgi-Context.xml 設定
<osgi:service ref="pluginConsumer1" interface="WhiteBoardPattern.Interface.IUpdateCommand" />
Manifest.mf 檔
Manifest-Version: 1.0 Export-Package: WhiteBoardPattern.Consumer;version="1.0.0";uses:="Whit eBoardPattern.Interface" Unversioned-Imports: * Built-By: momo Tool: Bnd-1.15.0 Bundle-Name: Spring OSGi Bundle Created-By: Apache Maven Bundle Plugin Bundle-Version: 1.0.0 Build-Jdk: 1.6.0_24 Bnd-LastModified: 1304392985843 Bundle-ManifestVersion: 2 Import-Package: WhiteBoardPattern.Interface Bundle-SymbolicName: WhiteBoardPattern.Consumer
WhiteBoardPattern.Consumer2 設定跟WhiteBoardPattern.Consumer1 是一樣的
2個都Implements IUpdateCommand,不同的只有Bundle-SymbolicName
WhiteBoardPattern.Producer Bundle Detail
Bundle project as below:
WhiteBoardPattern.Producer.WhiteBoardProducer
WhiteBoardProducer 本身包含了一個ServiceTracker, implements BundleContextAware, Spring 做IOC的動作
package WhiteBoardPattern.Producer; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleEvent; import org.osgi.framework.BundleListener; import org.osgi.framework.SynchronousBundleListener; import org.osgi.util.tracker.ServiceTracker; import org.springframework.osgi.context.BundleContextAware; import WhiteBoardPattern.Interface.IUpdateCommand; public class WhiteBoardProducer implements BundleContextAware{ private volatile boolean stop = false; private ServiceTracker tracker; private BundleContext bundleCtx; public void setBundleContext(BundleContext bundleContext) { this.bundleCtx = bundleContext; } public void start() throws Exception { tracker = new ServiceTracker(bundleCtx,IUpdateCommand.class.getName(),null); tracker.open(); Thread t = new Thread(){ public void run(){ try { Thread.sleep(1000); System.out.println("tick"); // Get a list of the IWhiteboardExample services and notify them. Object[] services = tracker.getServices(); System.out.println("services = " services); if (services != null) { for(Object s : services) { IUpdateCommand iupdate = (IUpdateCommand)s; System.out.println("getUpdateMessaget = " iupdate.getUpdateMessage()); } } } catch (InterruptedException e) { // Ignore interruptions. } } }; t.start(); } public void stop() throws Exception{ stop = true; tracker.close(); } }
bundle-context.xml 設定,Producer 本身不會註冊到Osgi service 裡面,
<bean id="activator" class="WhiteBoardPattern.Producer.WhiteBoardProducer" init-method="start" destroy-method="stop"></bean>
Manifest.mf 檔
Manifest-Version: 1.0 Export-Package: WhiteBoardPattern.Producer;version="1.0.0";uses:="org. osgi.framework,org.osgi.util.tracker,org.springframework.osgi.context " Unversioned-Imports: * Built-By: momo Tool: Bnd-1.15.0 Bundle-Name: Spring OSGi Bundle Created-By: Apache Maven Bundle Plugin Bundle-Version: 1.0.0 Build-Jdk: 1.6.0_24 Bnd-LastModified: 1304392978718 Bundle-ManifestVersion: 2 Import-Package: WhiteBoardPattern.Interface,org.osgi.framework,org.osg i.util.tracker,org.springframework.osgi.context Bundle-SymbolicName: WhiteBoardPattern.Producer
先把WhiteBoardPattern.Interface , WhiteBoardPattern.Consumer1, WhiteBoardPattern.Consumer2
都安裝到OSGi container 裡, 之後再把WhiteBoardPattern.Producer 啟動
簡單的Resout 如下
當WhiteBoardPattern.Producer 啟動時, 會去從ServiceTracker 監聽IUpdateCommand.class實作出來的Service , 然後調用該Interface 的method 。
這樣可以做什麼? 比如說我想要知道新的Bundle Install 進來時要把一些MANIFEST裡的header or BundleContext 下的Resource Information回傳過來,集中對ServiceTracker裡面的service list做處理,
這樣做每個Bundle 只需要implements interface 所置定的method,並註冊到OSGi裡面。
每次WhiteBoardPattern.Producer啟動時就會找出全部IUpdateCommand Service 的information。
*如果需要Listener 的話可以實作BundleListener,ServiceListener or FrameworkListener,
Reference :
The Whiteboard Pattern for OSGi
The Whiteboard Pattern
沒有留言:
張貼留言