2013-11-26 12 views
4

我對OSGi世界有點新鮮。有些概念仍然沒有我。OSGi UI應用程序的最佳實踐

我正在嘗試使用Swing,Equinox和Declarative Services創建圖形OSGi應用程序。目標是簡化爲應用程序創建插件和擴展。

我偶然發現了一個設計問題,因爲我從頭開始做這件事,所以我想使用我所能做的所有最佳實踐。

我確實有一個包含API的包,並且只公開要作爲服務實現的接口。

public class SomeClass { 
} 

public interface Manager<T> { 
    void add(T obj); 
    void update(T obj); 
    void remove(T obj); 
} 

public interface SomeClassManager extends Manager<SomeClass> { 
} 

public interface Listener<T> { 
    void added(T obj); 
    void updated(T obj); 
    void removed(T obj); 
} 

public interface SomeClassListener extends Listener<SomeClass> { 
} 

比方說,我有一個包(核心),提供一種服務,是特定類型的對象(它基本上包含一個內部列表和添加,刪除和更新它)的經理。

public class SomeClassCoreManager implements SomeClassManager { 

     private ArrayList<SomeClass> list = new ArrayList<SomeClass>(); 
     private ArrayList<SomeListener> listeners = new ArrayList<SomeListener>(); 

     protected void bindListener(SomeListener listener) { 
      listeners.add(listener); 
     } 

     protected void undindListener(SomeListener listener) { 
      listeners.remove(listener); 
     } 

     public void add(SomeClass obj) { 
      // Adds the object to the list 
      // Fires all the listeners with "added(obj)" 
     } 


     public void update(SomeClass obj) { 
      // Updates the object in the list. 
      // Fires all the listeners with "updated(obj)" 
     } 

     public void remove(SomeClass obj) { 
      // Removes the object from the list. 
      // Fires all the listeners with "removed(obj)" 
     } 

} 

我也有需要主UI的護理的第二束(UI)。它不應該「關心」管理自身的對象,而應該在添加,刪除或更改對象以便更新JTree時收到通知。爲此,我使用了一個白板模式:UI捆綁包實現了一個服務,Core包使用該服務來觸發對象更改事件。

public class MainWindow extends JFrame { 

    private JTree tree = new JTree(); 
    private SomeClassManager manager; 

    protected void activate() { 
      // Adds the tree and sets its model and creates the rest of the UI. 
    } 

    protected void bindManager(SomeClassManager manager) { 
      this.manager = manager; 
    } 

    protected unbindManager(SomeClassManager manager) { 
      this.manager = null; 
    } 
} 

public class SomeClassUIListener implements SomeClassListener { 
    public void added(SomeClass obj) { 
      // Should add the object to the JTree. 
    } 

    public void updated(SomeClass obj) { 
      // Should update the existing object in the JTree. 
    } 

    public void removed(SomeClass obj) { 
      // Should remove the existing object from the JTree. 
    } 

} 

我在這裏的問題是:

的主窗口中的DS組件。我正在使用其激活器來啓動整個用戶界面。實例創建由OSGi處理。

爲了從管理器獲取更新,我將SomeClassUIListener作爲聲明服務公開。它的實例也由OSGi處理。

我應該如何從SomeClassUIListener訪問JTree模型的實例?

我已經提出了幾種選擇,但我不知道該使用哪個:

選項1: 使用某種類型的用戶界面包(如吉斯或微微)內部DI系統,並把它在一個靜態方法的類中獲取並在整個bundle中使用它。

這種方法似乎被一些人所淹沒。

選項2: 注入到主窗口的引用(通過將其變成服務)在通過的OSGi的SomeClassUIListener和從那裏。這是可能的還是可取的?在我看來,這是更簡單的解決方案。但是,另一方面,隨着用戶界面變得越來越複雜,這不會讓組件配置文件變得混亂嗎?

選項3: 爲聽衆創建單獨的包並使用OSGi更新MainWindow。這在我看來有點極端,因爲隨着UI複雜性的增長,我將不得不創建大量的bundle。

選項4: 使用MainWindow類實現偵聽器。但是,主UI界面中的服務越多,MainWindow類就越大。我認爲這不是一個好的選擇。

我想不出更多的選擇。上述任何一條路要走嗎?還是有另一種選擇?

預先感謝您。

編輯:

只是爲了澄清爲彼得柯瑞恩斯了這個問題有些疑惑。

我的目標是將用戶界面從Manager中分離出來。由經理我的意思是一種存儲庫,其中存儲某種類型的對象(例如,如果您考慮Oracle的JTree教程http://docs.oracle.com/javase/tutorial/uiswing/components/tree.html,管理器將包含Books的實例)。

經理可能會被任何其他套件使用,但根據我目前的計劃,它會通知任何在其中註冊的收聽者。監聽器可能是主要的用戶界面包,但也可能是任何其他選擇監聽更新的包。

+1

Richard Hall的OSGi in Action書中有一個基於此模型的GUI程序。你也可能想看看http://felix.apache.org/site/apache-felix-application-demonstration.html –

+0

我檢查過你提到的例子。本書的源代碼的確有些東西可以回答我的問題!在第11章的paint-example-ds中,windowlistener暗示了一個解決方案:我可以在將SomeClassCoreManager綁定到MainWindow時註冊監聽器。這樣我就可以在監聽器中注入我需要的任何組件。我提到的來源可以在[link](https://code.google.com/p/osgi-in-action/) –

回答

0

這裏的一些選項是將樹模型實例作爲參數傳遞給監聽器方法。

public void added(JTree tree, SomeClass obj) 

這種方式監聽器管理員將只負責監聽邏輯,而不是樹狀態。

另一個不錯的選擇是創建一個單獨的TreeProviderService,負責爲應用程序保存和提供單例實例JTree。在這種情況下,您將直接從聽衆處消費TreeProviderService

+0

中找到。感謝您的輸入,Henryk。關於你的第一個選擇。 JTree是由UI提供的服務,而另一個捆綁包是否會在觸發事件更改時使用它?關於你的第二個選擇:它需要一個單獨的包來保存JTree?或者服務在UI捆綁中提供和使用? –

1

我不確定我是否完全掌握了您的建議,感覺就像您正在創建一整套基礎設施。在OSGi中這通常不是必需的,所以爲什麼不從小而簡單的開始。

您的基本模型是經理和擴展。這是領域模型,我會嘗試在這裏流動:

@Component(immediate) 
public class ManagerImpl { // No API == immediate 
    List<Extension> extensions = new CopyOnWriteArrayList<Extension>(); 
    JFrame frame = new JFrame(); 

    @Reference(cardinality=MULTIPLE) 
    void addExtension(Extension e) { 
     addComponent(frame, e.getName(), e.getComponent()); 
     extensions.add(e); 
    } 

    void removeExtension(Extension e) { 
    if (extensions.remove(e)) { 
     removeComponent(frame, e.getName()); 
    } 
} 

@Component 
public class MyFirstExtension implements Extension { 
    public String getName() { return "My First Extension";} 
    public Component getComponent() { return new MyFirstExtensionComponent(this); } 
} 

這不是你要找的嗎?要小心不要創建各種監聽器,一般情況下你會發現OSGi註冊表中已有的事件。

+0

它似乎並不是我正在尋找的東西。但我可能錯了!在我給出的例子中,我有一個數據源(經理)和一個顯示器(UI),我怎麼能適應這一點?無論如何,我已更新該帖子以提供更多信息。 –

0

我建議簡單地將DS用於UI創建和接線。如果使用Peter提到的註釋,則不會使用XML形式混淆包含組件描述符的包。

因此,您的偵聽器是一個@Component,並將需要更新的UI元素注入它。

Btw。你打算做什麼聽起來有點像數據綁定到我這樣你應該也調查這些提供已經。 參見:Swing data binding frameworks

Btw。你也可能想要尋找比swing更先進的框架。例如前段時間,我爲vaadin做了一個小教程:https://github.com/cschneider/Karaf-Tutorial/tree/master/vaadin 它已經有了java bean的數據綁定。所以這讓我很容易編寫UI。完整的用戶界面只是這個小類:https://github.com/cschneider/Karaf-Tutorial/blob/master/vaadin/tasklist-ui-vaadin/src/main/java/net/lr/tutorial/karaf/vaadin/ExampleApplication.java

在舊版本中,我仍然需要一個橋樑來在OSGi中運行vaadin,但版本7應該是相當OSGi準備好的。

+0

在您提出使用DS的建議中,我會將服務綁定到自己的捆綁包中,還是應該創建其他捆綁包?關於數據綁定,這似乎也很有趣。但是這意味着我應該放棄整個OSGi架構?此外,使用除Swing以外的更高級框架可能也是可能的。將事情保持分開可能會讓我有機會在將來改變UI框架。 –

+0

我不確定數據綁定如何與OSGi協同工作。它可能取決於數據綁定框架。在vaadin它運作良好。順便說一句。我自己目前正在考慮在OSGi上使用CDI。它的優勢在於它對於JavaEE人員來說是熟悉的,並且它具有很好的內部和內部連接線的分離。我還沒有嘗試用它來連接一個swing UI,但它應該是非常好的:https://github.com/cschneider/Karaf-Tutorial/tree/master/tasklist-cdi –