3.4.2. Setup, Setup Builder, Descriptor und Widget Schnittstellen

Ein Widget (der Typ, nicht die Instanz) ist durch seine BluePrint Schnittstelle und seine Widget Schnittstelle eindeutig festgelegt.

Die Widget Schnittstelle definiert die Schnittstelle des Widgets, die nach seiner Erzeugung (zum Beispiel für Modifikationen, Abfragen und Funktionen) zur Verfügung steht.

Die BluePrint Schnittstelle vereint die folgenden Aspekte:

Für die Core Widgets sind diese Aspekte in unterschiedliche Schnittstellen aufgeteilt.[6]

Label Widget Beispiel

Die Aufteilung der Schnittstellen soll anhand des Label Widgets verdeutlicht werden. Ein Label Widget setzt sich aus einem Icon und einem Text Label zusammen. Ein Label Widget hat die BluePrint Schnittstelle ILabelBluePrint und die Widget Schnittstelle ILabel.

Widget Schnittstelle

Die Widget Schnittstelle legt den Vertrag des Widgets (nach seiner Erzeugung) fest. Ein Widget Interface muss mindestens von IWidget abgeleitet sein. Widgets welche zu einem Container hinzugefügt werden sollen, sind mindestens von IControl abgeleitet usw..

Die Schnittstelle ILabel ist von ITextLabel und IIcon abgeleitet, welche wiederum von IControl, IComponent und IWidget abgeleitet sind, und hat damit die folgenden Methoden:

  1      //inherited from IIcon
  2      
  3      void setIcon(IImageConstant icon);
  4      
  5      IImageConstant getIcon();
  6  
  7      //inherited from ITextLabel
  8      
  9      void setFontSize(int size);
 10  
 11      void setFontName(String fontName);
 12  
 13      void setMarkup(Markup markup);
 14  
 15      void setText(String text);
 16      
 17      String getText();
 18      
 19      //inherited from IWidget
 20      
 21      Object getUiReference()
 22      
 23      //...and a lot more
 24      
 25      //inherited from IComponent
 26      
 27      void setForegroundColor(final IColorConstant colorValue);
 28      
 29      //...and a lot more
 30      
 31      //inherited from IControl
 32      
 33      void setToolTipText(String toolTip);
 34       
 35      //...and a lot more

Anmerkung: Die von IControl, IComponent und IWidget geerbten Methoden wurden dabei nicht vollständig aufgezählt.

Widget Setup

Das Widget Setup liefert der Widget Implementierung die Konfiguration eines Widgets. Ein Setup besteht immer aus Properties, welche mit get(), is() oder has() abgefragt werden können. Setup Schnittstellen können von anderen abgeleitet sein. Zum Beispiel leitet ILabelSetup von IIconSetup und von ITextLabelSetup ab, und hat keine zusätzlichen Methoden.

Ein ILabelSetup hat dadurch die folgenden Methoden:

    IImageConstant getIcon();
    
    String getText();

    String getToolTipText();

    @Mandatory
    Markup getMarkup();

    AlignmentHorizontal getAlignment();
    
    Integer getFontSize();

    String getFontName();
    
    Boolean isVisible();

    IColorConstant getForegroundColor();

    IColorConstant getBackgroundColor();

Die @Mandatory gibt an, dass diese Properties nicht null sein dürfen. Wenn es (sinnvoll) möglich ist, haben solche Properties einen Defaultwert. Für das Markup und das Alignment ist ein sinvoller Default möglich (Markup.DEFAULT und AlignmentHorizontal.LEFT). Stellt eine Property zum Beispiel ein Interface dar, welches der Nutzer des Widgets implementiert (sozusagen als SPI), ist es unter umständen nicht möglich, dafür einen sinnvollen Default anzubieten. Dann führt das Weglassen dieser Property zu einem Fehler, wenn das Widget erzeugt wird.

Widget Setup Builder

Ein Widget Setup Builder liefert die Setter Methoden zu einen Widget Setup. Diese sind alle nach dem folgenden Muster aufgebaut:

    BLUE_PRINT_TYPE set(PROPERTY_TYPE property);

Dabei ist PROPERTY_TYPE der Java Typ der Property, die gesetzt werden soll. Der BLUE_PRINT_TYPE ist der Typ des BluePrint, um verkettete Aufrufe zu ermöglichen.

Die Schnittstelle ILabelSetupBuilder ist von IIconSetupBuilder und ITextLabelSetupBuilder abgeleitet und hat die folgenden einfachen Setter Methoden:

    BLUE_PRINT_TYPE setIcon(IImageConstant icon);
    
    BLUE_PRINT_TYPE setText(String text);

    BLUE_PRINT_TYPE setToolTipText(String text);

    BLUE_PRINT_TYPE setMarkup(Markup markup);

    BLUE_PRINT_TYPE setAlignment(AlignmentHorizontal alignmentHorizontal);
    
    BLUE_PRINT_TYPE setFontSize(Integer size);

    BLUE_PRINT_TYPE setFontName(String fontName);

    BLUE_PRINT_TYPE setVisible(Boolean visible);

    BLUE_PRINT_TYPE setForegroundColor(final IColorConstant foregroundColor);

    BLUE_PRINT_TYPE setBackgroundColor(final IColorConstant backgroundColor);

Zusätzlich zu den Bean Property Setter Methoden kann ein Setup Builder weitere Convenience Methoden haben. Die Schnittstelle ILabelSetupBuilder hat folgende Convenience Methoden:

    INSTANCE_TYPE alignLeft();

    INSTANCE_TYPE alignCenter();

    INSTANCE_TYPE alignRight();

    INSTANCE_TYPE setStrong();
    
    INSTANCE_TYPE setEmphasized();

Diese Methoden ermöglichen eine verkürzte Schreibweise. So kann man zum Beispiel anstatt:

    final ILabelBluePrint labelBp = 
        BPF.label().setAlignment(AlignmentHorizontal.RIGHT).setMarkup(Markup.STRONG);

auch

     final ILabelBluePrint labelBp = BPF.label().alignRight().setStrong();

Sowohl die Getter Methoden eines Widget Setup als auch die einfachen Setter Methoden eines Widget Setup Builders werden mit Hilfe eines Java Proxy implementiert. Einen solchen BluePrintProxy erhält man von der BluePrint Proxy Factory. Insbesondere bei der Erstellung eigener Widget Bibliotheken reicht also die Definition der Setup und Setup Builder Schnittstelle aus. Die Convenience Methoden sind durch (eine oder mehrere) eigene Schnittstellen definiert. Eine Implementierung der Convenience Schnittstelle muss bei der BluePrint Proxy Factory registriert werden.

Die Widget Setup Builder von jowidgets sind von der Schnittstelle ISetupBuilder abgeleitet. Diese hat die folgende Methode:

     INSTANCE_TYPE setSetup(IComponentSetupCommon descriptor);

Dadurch kann ein anderes Setup, welches auch einen anderen Typ haben kann, auf dem Builder gesetzt werden. Dabei werden alle Properties mit gleichen Namen und gleichem Typ auf dem Builder gesetzt. Auf diese Weise lassen sich leicht Kopien von Setups erzeugen.

Widget Descriptor

Jeder Widget Typ benötigt seinen eigenen Widget Descriptor Typ, welcher mit Hilfe einer Schnittstelle definiert wird, die von IWidgetDescriptor abgeleitet ist.

Die Schnittstelle ILabelDescriptor ist zum Beispiel wie folgt definiert:

    public interface ILabelDescriptor extends ILabelSetup, IWidgetDescriptor<ILabel> {}

Für die Schnittstelle ILabelDescriptor kann genau eine Implementierung (zur selben Zeit) in der Generic Widget Factory registriert sein. Der Widget Descriptor ist gleichzeitig auch ein Widget Setup (im konkreten Fall ein ILabelSetup). Ein Widget Descriptor liefert somit alles, was von der Generic Widget Factory für die Erzeugung eines Widget benötigt wird.

BluePrint Schnittstelle

Die BluePrint Schnittstelle fügt dem Widget Descriptor noch den Widget Setup Builder Aspekt hinzu.

Die Schnittstelle ILabelBluePrint ist zum Beispiel wie folgt definiert:

    public interface ILabelBluePrint extends ILabelSetupBuilder<ILabelBluePrint>, ILabelDescriptor {}

Hinweis: Für jedes Widget existiert genau eine eigene BluePrint Schnittstelle, während unterschiedliche Widgets sich die gleiche Widget Schnittstelle Teilen können (z.B. IFrame für das Frame Widget (IFrameBluePrint) und das Dialog Widget (IDialogBluePrint). Die Hierarchien der Setup und Widget Schnittstellen müssen nicht zwingend gleich sein. So ist ein LoginDialogSetup zum Beispiel vom ITitledWindowSetup abgeleitet, obwohl ein ILoginDialog nicht von IWindow abgeleitet ist.

Hinweis: Der Begriff BluePrint wird oft stellvertretend für den Begriff WidgetDescriptor verwendet. Dies liegt unter anderem daran, dass ein BluePrint einen Widget Typ genauso eindeutig spezifiziert wie ein WidgetDescriptor und in der Praxis beide Aspekte oft in einer Schnittstelle vereint sind. Ein BluePrint fügt zu einem separierten (in einer eigenen Schnittstelle befindlichen) WidgetDescriptor noch den Aspekt des Setup Builder hinzu, weshalb der Begriff WidgetDescriptor nicht synonym für BluePrint verwendet werden sollte, wenn der Builder Aspekt in diesem Kontext auch relevant ist.

Zusammenfassen des Builder und Setup Aspekts

Die ursprüngliche Idee, den Builder und Setup Aspekt zu trennen, hat sich in der Praxis nicht bewährt. Es wird daher empfohlen, bei der Erstellung eigener Widget Bibliotheken die Builder und Setup Methoden in einer Schnittstelle unterzubringen. Für das Label würde man dann zum Beispiel die ILabelSetupBuilder Schnittstelle wie folgt definieren:

    IImageConstant getIcon();

    BLUE_PRINT_TYPE setIcon(IImageConstant icon);
    
    String getText();
    
    BLUE_PRINT_TYPE setText(String text);

    String getToolTipText();
    
    BLUE_PRINT_TYPE setToolTipText(String text);

    @Mandatory
    Markup getMarkup();
    
    BLUE_PRINT_TYPE setMarkup(Markup markup);

    AlignmentHorizontal getAlignment();
    
    BLUE_PRINT_TYPE setAlignment(AlignmentHorizontal alignmentHorizontal);
    
    Integer getFontSize();
    
    BLUE_PRINT_TYPE setFontSize(Integer size);

    String getFontName();
    
    BLUE_PRINT_TYPE setFontName(String fontName);

    Boolean isVisible();
    
    BLUE_PRINT_TYPE setVisible(Boolean visible);

    IColorConstant getForegroundColor();
    
    BLUE_PRINT_TYPE setForegroundColor(final IColorConstant foregroundColor);

    IColorConstant getBackgroundColor();

Dann wäre auch die Trennung von Descriptor und BluePrint überflüssig und die Schnittstelle ILabelBluePrint würde also wie folgt aussehen:

    public interface ILabelBluePrint extends 
        ILabelSetupBuilder<ILabelBluePrint>, 
        IWidgetDescriptor<ILabel> {}

Die Trennung der BluePrint Schnittstelle und er SetupBuilder Schnittstelle wird jedoch nach wie vor empfohlen, um die Möglichkeit zu haben, von einem Setup Builder ableiten zu können. Von einem BluePrint sollte nicht abgeleitet werden, unter Anderem weil für das abgeleitete BluePrint der Descriptor Typ nicht mehr eindeutig sein könnte.



[6] Dies muss bei der Erstellung eigener Widget Bibliotheken nicht zwingend so gemacht werden. Das Zusammenfassung von Setup und Setup Builder in eine Schnittstelle hat sich durchaus als praktikabel erwiesen und wird zum Beispiel auch bei den Widgets der jo-client-platform so umgesetzt.


Siehe auch PDF Version dieses Dokuments, Jowidgets API Spezifikation