2013-08-18 30 views
0

我最近開始使用OSGi框架。我有一個名爲Bundle-A的包。我想從我的主應用程序中調用Bundle-A jar中的一個方法。如何在安裝到OSGi容器中之後調用我的Bundle-A jar文件中的某個方法

我已經從我的主應用程序中加載並安裝了Bundle-A。以下是我在安裝Bundle-A的主應用程序中的代碼。

private void initializeModelFramework() { 

    try { 

     FileUtils.deleteDirectory(new File("felix-cache")); 
     FrameworkFactory frameworkFactory = ServiceLoader.load(FrameworkFactory.class).iterator().next(); 

     Framework framework = frameworkFactory.newFramework(new HashMap<String, String>()); 
     framework.start(); 

     BundleContext bundleContext = framework.getBundleContext(); 

     modulesNameVersionHolder.put("Bundle-A", "1.0.0"); 

     List<Bundle> installedBundles = new LinkedList<Bundle>(); 

     String basePath = "C:\\ClientTool\\LocalStorage"; 

     for (Map.Entry<String, String> entry : modulesNameVersionHolder.entrySet()) { 
      String version = entry.getValue(); 
      final String filename = name + Constants.DASH + version + Constants.DOTJAR; 
      final String localFilename = GoldenModulesConstants.FILE_PROTOCOL + basePath+ File.separatorChar + filename; 

      installedBundles.add(bundleContext.installBundle(localFilename)); 
     } 

     for (Bundle bundle : installedBundles) { 
      bundle.start();// this will start bundle A 
     } 

     // After starting the Bundle-A, now I need to call one of the methods in Bundle-A 
     for(int i=0; i<=10; i++) { 
      //call processingEvents method of Bundle-A class GoldenModelFramework 
     } 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 

現在Bundle-A已經啓動。以下是我的Bundle-A的Activator類。

public class Activator implements BundleActivator { 

    private static final String BUNDLE_VERSION_KEY = "Bundle-Version"; 
    private static Logger s_logger = Logger.getLogger(Activator.class.getName()); 

    @Override 
    public void start(BundleContext context) throws Exception { 

     final Bundle bundle = context.getBundle(); 
     final String bundleName = bundle.getSymbolicName(); 
     final String bundleVersion = (String) bundle.getHeaders().get(BUNDLE_VERSION_KEY); 

     System.out.println(bundleName+" - "+bundleVersion); 
    } 

    @Override 
    public void stop(BundleContext context) throws Exception { 
      System.out.println("Bye.!"); 
    } 
} 

下面是我在Bundle-A jar中的類。一旦Bundle-A啓動,我需要從我的上述主應用程序代碼中調用processingEvents方法。

public class GoldenModelFramework { 

    private static final Logger LOGGER = Logger.getLogger(GoldenModelFramework.class.getName()); 
    private static final long checkingAfterEveryXMinutes = 15L; 


    public GoldenModelFramework() { 
     // following the traditions 
    } 

    public static void processingEvents(final String item) { 

     for (BundleRegistration.HolderEntry entry : BundleRegistration.getInstance()) { 
      final String response = entry.getPlugin().process(item); 
      System.out.println(response); 
     } 
    } 
} 

我不知道什麼是正確的做法嗎?我知道一種方法是在我的主應用程序pom.xml文件中添加此Bundle-A的依賴項,因爲我使用的是基於Maven的項目。但我認爲這不是正確的做法。因爲最終,我會有更多的捆綁包,所以應該有其他方法來解決這個我不知道的問題。

我應該在這裏使用ServiceListener還是ServiceTracker?我的代碼的任何簡單的示例基礎將幫助我更好地理解。謝謝。

我希望問題很清楚。我試圖在加載並安裝Bundle-A後調用其中一種方法。

+0

從更方便的級別開始,您可能會好得多,現在您正在嘗試運行,然後才能抓取。最簡單的方法就是使用bndtools。這是一個很好的開始:http://bndtools.org/tutorial.html –

回答

2

您有幾種選擇:

導入包動態

可以使用DynamicImport-包裝代替進口包裝。在這種情況下,當主包開始時,bundle-A不必處於活動狀態。雖然這可行,但我不推薦這種解決方案,因爲我不喜歡DynamicImport-Package。在這種情況下,束A必須是主束的依賴性。

使用反射

你可以打電話給你想這樣(例如草案)反映的方法:

Class<GoldenModelFramework> clazz = bundleA.loadClass("GoldenModelFramework"); 
Method m = clazz.getMethod("processingEvents", String.class); 
m.execute(null, myParam); 

這是一個好一點,但是這種解決方案還是有點雲裏霧裏,我不會說這是一個乾淨的代碼。

使用接口和OSGi服務

最乾淨的方式將需要一點重構。在這種情況下,您應該創建一個接口,並在捆綁軟件A的激活器中註冊一個基於該接口的服務。在主包中,您應該使用服務跟蹤器來捕獲該服務並調用該服務。

如果你真的想讓你的方法processEvent是靜態的,註冊的服務對象(基於接口)應該簡單地調用裏面的靜態方法。

沒有必要將bundle A作爲依賴項添加到主包中,那麼應該將接口放入第三個bundle中,這是依賴於main和A bundle的依賴關係。

雖然這個解決方案似乎是最複雜的,我會建議這一個。

一個例子:

創建的接口,並把它像goldenframework-API新的組合。

public interface GoldenModelFrameworkOSGi { 
    void processingEvents(final String item); 
} 

goldenframework-api將是主包和bundle-A的依賴關係。主包將使用它,而捆綁-A將執行它。

這裏是束一個如何實現它:

public class GoldenFrameworkOSGiImpl { 
    public void processingEvents(final String item) { 
     GoldenModelFramework.processEvents(item); 
    } 
} 

創建束-A(我將離開你的代碼在活化劑具有更少的輸入)的活化劑類:

public class Activator { 
    private ServiceRegistration goldenFrameworkSR; 

    @Override 
    public void start(BundleContext context) { 
    goldenFrameworkSR = context.registerService(GoldenFrameworkOSGi.class, new GoldenFrameworkOSGi(), new HashTable()); 
    } 

    @Override 
    public void stop(BundleContext context) { 
    goldenFrameworkSR.unregister(); 
    } 
} 

正如你所知道的Bundle-A的代碼,你可以作弊一點。當bundle-A處於活動狀態時,您可以確定所需的服務已註冊。但是,將來你應該考慮基於事件進行工作(比如使用ServiceTracker)。我的意思是,這將是一個不好的做法:):

ServiceReference sr = context.getServiceReference(GoldenServiceOSGi.class); 
GoldenServiceOSGi gs = context.getService(sr); 
gs.processEvents(...); 
context.ungetService(sr); 

這可能會解決您的問題,現在,你可以用你的工作繼續進行。不過,請考慮閱讀「OSGi in Action」這樣的書籍,以感受OSGi捆綁包和服務生命週期,以便您可以重新設計框架。

+0

謝謝你給我所有的建議。你有可能爲你提供第三個例子的簡單範例嗎?通過這種方式,我將更容易理解並相應地編寫代碼。我對OSGi框架完全陌生。謝謝您的幫助。 – ferhan

+0

用一個例子編輯我的答案。請注意,我對你的問題和答案有一種奇怪的感覺。我展示了一些技巧,但是如果您深入挖掘OSGi世界,您可能會設計代碼,甚至不需要像這樣的技巧。 –

+0

感謝Balazs的建議。你能告訴我你對我的問題有什麼疑問嗎?通過這種方式,我可以考慮我在設計中做了什麼錯誤,以及我可以做些什麼來改進它。 – ferhan

相關問題