2014-01-16 55 views
2

我一直在嘗試一些關於Karaf的OSGi聲明式服務(其中包括諸如Blueprint)的示例。我想現在要解決的問題是如何在運行時獲取對某些服務的引用(這樣的註解和/或XML這裏是不是一個真正的選擇)OSGi聲明式服務在運行時過濾引用

我會解釋我的使用情況:

我試圖設計(迄今爲止只在我的腦海中,這就是爲什麼我仍然只是試驗OSGi :))一個系統來控制工業中的某些自動化過程。爲了與設備通信,正在使用一組特殊的協議。爲了使組件儘可能重用,我設計了一個基於圖層的通信模型(例如用於網絡的ISO/OSI模型,但更簡單)

要將其轉換爲OSGi,我的系統的每一層一套捆綁。一個用於該層的接口,然後是該層的每個實現的一個插件(想象爲OSI的傳輸層上的TCP與UDP)。

要引用此類網絡中的任何設備,將使用自定義地址格式(此類地址的兩個示例可以是xpa://12.5/03FE或xpb://12.5/03FE)。這樣的地址包含了訪問所請求的設備所需的所有關於圖層及其值的信息。你可以猜到,這個地址的每個部分代表了我的網絡模型的一個層。

這些地址將被存儲在某個配置數據庫中(所以再次簡單的.cfg或.properties文件不是一個選項),以便它們可以在運行時遠程更改。

我正在考慮創建一個工廠,它將解析這個地址,並根據它的所有組件,創建一個對象鏈(從OSGi獲得適當的服務),實現所有層並相應地配置它們。由於可以有更多的單層實現(因此,更多的服務實現單個接口),因此這個工廠需要在運行時(當它獲取設備地址作爲字符串傳遞時),決定哪個特定的實現選擇(根據服務將聲明的其他屬性)。

這怎麼可能在OSGi中實現? DS,Blueprint還是其他什麼方法更好?

回答

4

我意識到,這是現在一個很遲的回答這個問題,但答案都錯過了明顯的內置在聲明式服務過濾支持。

目標過濾器可以用於使用@Reference註釋的DS基準來定義:也可以使用配置添加

@Component 
public class ExampleComponent { 
    @Reference(target="(foo=bar)") 
    MyService myService; 
} 

該目標過濾器(或重寫)。對於組分:

@Component(configurationPid="fizz.buzz") 
public class ExampleComponent { 
    @Reference 
    MyService myService; 
} 

的結構字典用於PID fizz.buzz然後可以使用該密鑰myService.target設置一個新的過濾器。

這是一個比跳轉到原始OSGi API更好的選擇,並且已經可用於多個規範版本。

+0

謝謝Tim!我們遇到了這個問題,在閱讀完所有DS規範後,並沒有變得更聰明。目標過濾器屬性是動態的事實在任何地方(或是否?)都沒有提及或解釋,並且可能被誤認爲是DS運行時的實現細節。 –

+0

OSG R5綱要第112.3.6節(選擇目標服務): –

+0

謝謝,我將接受的答案改爲你的答案 –

0

我看到這個用例的唯一選擇是直接使用OSGi API。聽起來好像你每次得到處理地址時都必須進行服務查找。因此,每次您要處理地址時,您都必須獲得相應的服務實施(基於過濾器)。

像DS和Blueprint這樣的聲明性方法不會使您執行此操作,因爲過濾器在運行時不能更改。

+0

謝謝。我通過在運行時管理服務實例的ServiceRepository解決了這個問題。根據提供的地址字符串,我的組件要求此存儲庫實現服務。如果該協議名稱下不存在服務,則會引發相應的異常。 存儲庫在註冊/註銷時動態管理其服務實例。這樣,所有東西都可以作爲聲明式服務來實現。 –

+0

查看Tim的回答。在引擎蓋下,實際的組件屬性是動態的;目標= 屬性僅僅是一個靜態便利幫手。 –

+0

聲明性服務目標過濾器可以在運行時使用配置管理進行更改。這是規範的一部分,可以依賴。在這種情況下,我不會推薦使用低級API。 –

2

OSGi給出了一種稱爲服務跟蹤器的好方法。您可以在聲明式服務中使用。在這個例子中,有一個配置保存你想要使用的服務的過濾器。如果過濾器配置發生變化,整個組件重新啓動,所以跟蹤機制正在重新啓動。

import org.apache.felix.scr.annotations.Activate; 
import org.apache.felix.scr.annotations.Component; 
import org.apache.felix.scr.annotations.Deactivate; 
import org.apache.felix.scr.annotations.Properties; 
import org.apache.felix.scr.annotations.Property; 
import org.osgi.framework.BundleContext; 
import org.osgi.framework.InvalidSyntaxException; 
import org.osgi.framework.ServiceReference; 
import org.osgi.service.component.ComponentContext; 
import org.osgi.util.tracker.ServiceTracker; 
import org.osgi.util.tracker.ServiceTrackerCustomizer; 

@Component(immediate = true, metatype = true) 
@Properties(value = { 
     @Property(name = "filterCriteria", value = "(objectClass=*)") 
}) 
public class CustomTracker { 

    private CustomServiceTracker customServiceTracker; 

    @Activate 
    protected void activate(ComponentContext componentContext) throws InvalidSyntaxException { 
     String filterCriteria = (String) componentContext.getProperties().get("filterCriteria"); 
     customServiceTracker = new CustomServiceTracker(componentContext.getBundleContext(), filterCriteria); 
     customServiceTracker.open(true); 
    } 

    @Deactivate 
    protected void deactivate() { 
     customServiceTracker.close(); 
    } 

    /** 
    * OSGi framework service tracker implementation. It is able to listen all serivces available in the system. 
    */ 
    class CustomServiceTracker extends ServiceTracker { 

     CustomServiceTracker(BundleContext bundleContext, String filterCriteria) throws InvalidSyntaxException { 
      super(bundleContext, bundleContext.createFilter(filterCriteria), (ServiceTrackerCustomizer) null); 
     } 

     @SuppressWarnings("checkstyle:illegalcatch") 
     @Override 
     public Object addingService(ServiceReference serviceReference) { 
      try { 
       Object instance = super.addingService(serviceReference); 
       // TODO: Whatever you need 
       return instance; 
      } catch (Exception e) { 
       LOGGER.error("Error adding service", e); 
      } 
      return null; 
     } 

     @Override 
     public void removedService(ServiceReference serviceReference, Object service) { 
      // TODO: Whatever you need 
      super.removedService(serviceReference, service); 
     } 

     @Override 
     public void modifiedService(ServiceReference serviceReference, 
            Object service) { 
      super.modifiedService(serviceReference, service); 
     } 
    } 
}