Extensions und Extension-Points: Unterschied zwischen den Versionen

Aus Eclipse
Wechseln zu: Navigation, Suche
 
Zeile 208: Zeile 208:
 
</source>
 
</source>
 
<br/>
 
<br/>
Siehe hierzu auch folgendes [[Beispiel]].
+
Siehe hierzu auch [[Ausgabe der Namen aller Extensions zu einem ExtenstionPoint inklusive deren Elemente und Attribute]].
  
 
=Die Übergabe des Kontrollflusses von einem Plugin zu einem anderen=
 
=Die Übergabe des Kontrollflusses von einem Plugin zu einem anderen=

Aktuelle Version vom 15. Juli 2010, 15:09 Uhr

Extension Points und Extensions stellen ein Mechanismus dar, mittels dessen Bundles untereinander kommunizieren können. Extensions und Extension Points werden dabei deklarativ im entsprechendem Bundle definiert. Beim Installieren eines Bundles werden diese Informationen dann der Extension Registry des Frameworks zur Verfügung gestellt. Diese kann dann programmatisch nach bestimmten Extensions oder Extension Points abgefragt werden. Dies gilt auch für die deklarativ beschriebenen Eigenschaften einer Extension.

Extension Points

Abb.14: Der grafische xml Editor zur Definition von ExtensionPoints

Extension Points stellen eine Schnittstelle zu einem Bundle dar, an die sich ein anderes Bundle andocken kann. Ein Extension Point wird in der plugin.xml deklariert. Bei der Deklaration eines Extension Points müssen die Parameter, die ein Bundle das diesen ExtensionPoint nutzt, spezifiziert werden. Dies erfolgt über einen grafischen xml Editor.
Das folgende Beispiel deklariert einen Extension Point, der genau eine Klasse erwartet, die das Interface IFrasenProvider implementieren muss.

Die vom Editor im obigen Beispiel erzeugte plugin.xml Datei sieht dann wie folgt aus:

<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
   <extension-point id="getFrase" name="get Frase ExtensionPoint" schema="schema/getFrase.exsd"/>
 
</plugin>


Abb.15: Der grafische xml Editor zur Definition von ExtensionPoint Schemata

Die Parameter für diesen Extensinpoint werden über einen XLM - Schemaeditor deklariert. Das Element Extension mit den Attributen point, id und name ist dabei für jeden ExtensionPoint obligatorisch. Das Element Client wurde hier hinzugefügt. Es deklariert ein Attribut vom Typ java, welchem eine Klasse, die das Interface IFrasenProvider implementiert, zugeordnet werden kann. Da unter Use required angegeben wurde, ist zur Erweiterung dieses Extensionpoints, die Angabe einer entsprechenden Klasse zwingend notwendig.
Die Schema-Datei wird im Projektverzeichnis im Verzeichnis schema unter dem Namen des Extensionpoits abgelegt.
Das im obigen Beispiel erzeugte .exsd Schema sieht dann wie folgt aus:

<?xml version='1.0' encoding='UTF-8'?>
<!-- Schema file written by PDE -->
<schema targetNamespace="PluginSucher" xmlns="http://www.w3.org/2001/XMLSchema">
<annotation>
      <appinfo>
         <meta.schema plugin="PluginSucher" id="getFrase" name="getFraseEP"/>
      </appinfo>
      <documentation>
         [Enter description of this extension point.]
      </documentation>
   </annotation>
 
   <element name="extension">
      <annotation>
         <appinfo>
            <meta.element />
         </appinfo>
      </annotation>
      <complexType>
         <sequence>
            <element ref="Client"/>
         </sequence>
         <attribute name="point" type="string" use="required">
            <annotation>
               <documentation>
 
               </documentation>
            </annotation>
         </attribute>
         <attribute name="id" type="string">
            <annotation>
               <documentation>
 
               </documentation>
            </annotation>
         </attribute>
         <attribute name="name" type="string">
            <annotation>
               <documentation>
 
               </documentation>
               <appinfo>
                  <meta.attribute translatable="true"/>
               </appinfo>
            </annotation>
         </attribute>
      </complexType>
   </element>
 
   <element name="Client">
      <complexType>
         <attribute name="class" type="string" use="required">
            <annotation>
               <documentation>
 
               </documentation>
               <appinfo>
                  <meta.attribute kind="java" basedOn=":IFrasenProvider"/>
               </appinfo>
            </annotation>
         </attribute>
      </complexType>
   </element>
 
   <annotation>
      <appinfo>
         <meta.section type="since"/>
      </appinfo>
      <documentation>
         [Enter the first release in which this extension point appears.]
      </documentation>
   </annotation>
 
   <annotation>
      <appinfo>
         <meta.section type="examples"/>
      </appinfo>
      <documentation>
         [Enter extension point usage example here.]
      </documentation>
   </annotation>
 
   <annotation>
      <appinfo>
         <meta.section type="apiinfo"/>
      </appinfo>
      <documentation>
         [Enter API information here.]
      </documentation>
   </annotation>
 
   <annotation>
      <appinfo>
         <meta.section type="implementation"/>
      </appinfo>
      <documentation>
         [Enter information about supplied implementation of this extension point.]
      </documentation>
   </annotation>
 
 
</schema>

Die in einem Bundle deklarierten ExtensionPoints werden bei der Installation des Bundles vom Framework geparsed und als Datenstruktur in der Extensionpoint Registry abgelegt. Über diese können dann alle im Framework installierten Plugins auf den Extensionpoint zugreifen.

Extensions

Abb.16: Der grafische xml Editor zur Definition von Extensions

Eine Extension ist der Gegenpart zu einem ExtensionPoint. Möchte ein Bundle einen ExtensionPoint nutzen, so muss es für diesen ExtensionPoit eine Extension bereitstellen. Die Extension muss dabei den Kriterien genügen, die im Extensionpoint des anbietenden Bundles definiert wurden.
Um Extensions zu deklarieren, kann ähnlich wie bei den ExtensionPoints ein Editor genutzt werden. Das folgende Beispiel deklariert eine Extension für den ExtensionPoint PluginSucher.getFrase (wie weiter oben deklariert), dessen Attribut spiellängenfraseprovider mit der Klasse spiellaengefraseproviderplugin.SpiellaengeFrase belegt wird. Diese Klasse muss das Interface IFrasenProvider implementieren.

Der Extensionpoint Editor speichert alle Deklarationen genau wie der Extensionpoit Editor in der Plugin.xml Datei des Plugins ab. Im obigen Beispiel sieht diese dann wie folgt aus:

<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
   <extension
         id="SpiellaengeFrase"
         name="Spiellaenge Frase"
         point="PluginSucher.getFrase">
      <Client
            class="spiellaengefraseproviderplugin.SpiellaengeFrase">
      </Client>
   </extension>
 
</plugin>

Im Gegensatz zu Services können Extensions auch von einem Bundle bereitgestellt werden, das nicht gestartet worden ist. Da die plugin.xml, wie beschrieben, bei der Installation des Plugins vom Framework geparsed wird, werden die hierin enthaltenen Extensions zu diesem Zeitpunkt dem Framework bekanntgegeben. Extensins werden in der Extension Registry verwaltet. Über diese können sie von allen Plugins, die im Framework installiert sind, erfragt werden.

Extension Registry

Abb.15: Das Interface der Extension Registry

Die Extension Registry ist ein Service im Equinox-Framework.
Alle Extensions und ExtensionPoints werden bei der Installation eines Bundles an der Extension Registry registiert. Diese dient dann für alle anderen Bundles als Informationsquelle und Steuereinheit für die im Framework existierenden Extensions und ExtensionPoints. Dabei hat die Extension Registry folgende Aufgaben:

  • Registrieren aller Extensions und Extension Points, die in der plugin.xml eines zu installierenden Bundles definiert sind
  • Entfernen der zu einem Bundle gehörenden Extensions und Extension Points, wenn das Bundle aus der Plattform entfernt wird
  • Abfragen von Extensions und ExtensionPoints
  • Abfragen von Konfigurationselementen
  • An- und Abmelden von Registry Change Listenern



Der Zugriff auf diesen Service erfolgt über das Interface IExtensionRegistry.

Zugriff auf die Extension Registry

Der Zugriff auf einen Service im Equinox Framework kann über den Bundlecontext erfolgen. So auch auf den Service Extension Registry:

		ServiceReference refER = context.getServiceReference(IExtensionRegistry.class.getName());
		IExtensionRegistry er = (IExtensionRegistry)context.getService(refER);

oder alternativ über die statische Klasse RegistryFactory, des Packages org.eclipse.core.runtime:

		IExtensionRegistry er = RegistryFactory.getRegistry();

oder über die statische Klasse Plattform, ebenfalls aus dem Package org.eclipse.core.runtime:

		IExtensionRegistry er = Platform.getExtensionRegistry();

Zugriff auf Extensions

Der Zugriff auf bestimmte Services, die bei der Extension Regeistry registriert wurden, erfolgt dann über die zuvor ermittelte Referenz auf die Extension Regeistry. Um alle Extensions, die zu einem ExtensisionPoint passen zu finden, bedient man sich der Referenz des entsprechenden ExtensionPoints.
Folgendes Beispiel erfragt Extensions, die zu einem ExtensionPoint passen, über den entsprechenden ExtensionPoint ab:

 	       IExtension[] extensions = extensionPoint.getExtensions();
 
               for(IExtension extension : extensions){
                       // tue etwas mit der gefundenen Extension
               }

Zugriff auf die Configurationselemente einer Extension

Der Zugriff auf die Konfigurastionselemente einer Extension erfolgt über das Interface IExtension einer Extension. Ein Konfigurationselement entspricht dabei einem Element der Schema exsd Datei, wie es der ExtensionPoint bei seiner Deklaration angibt. Folgendes Beispiel fragt alle Konfigurationselemente einer Extension ab:

 	       IConfigurationElement[] elements = extension.getConfigurationElements();
 
               for(IConfigurationElement element: elements ){
                       // tue etwas mit der Configuration
               }

In der Schema XML Datei liegen unterhalb der Elemente meist noch Attribute, die an der Instanz eines Konfigurationselements natürlich ebenfalls abgefragt werden können. Folgendes Beispiel fragt alle Attribute eines Konfigurationselements ab:

               String nameDesConfigurationselements = configurationElement.getAttribut("titel");
               // Iteriere über alle Attribute und Unterelemente einer Extension
               IConfigurationElement subElements = configurationElement.getChildren();
               for(IConfigurationElement subElement: subElements ){
                       // tue etwas mit dem Attribut
               }


Siehe hierzu auch Ausgabe der Namen aller Extensions zu einem ExtenstionPoint inklusive deren Elemente und Attribute.

Die Übergabe des Kontrollflusses von einem Plugin zu einem anderen

Ein Plugin kann auf zweierlei Weisen den Kontrollfluss auf ein zweites Plugin übergeben:

  • per Extension eines fremden Bundles über den eigenen ExtensionPoint
  • per Aufruf eines Services, der von einem anderem Plugin bereitgestellt wird


In jedem Fall muss ein Bundle zunächst einmal das Framework kontaktieren, um eine Referenz auf das gewünschte Bundle, Extension oder Service zu erhalten. Über diese Referenz kann dann die entsprechende Funktionalität abgerufen werden.
Während die Registrierung von Extensions und ExtensionPoints, bei der Installation von Bundels, vollautomatisch vom Framework übernommen wird, muss die Registrierung eines Services über den Activator eines Bundles erfolgen. Hier ist unbedingt darauf zu achten, dass der Service beim Stoppen des Bundles am Framework de- registriert wird.
Beide oben genannten Aufrufkonzepte sind ähnlich. Das Equinox Framework stellt eine Infrastruktur zur Verfügung, die es Bundles ermöglicht, Abhängigkeiten zu definieren, ohne diese aneinander zu koppeln. Abhängigkeiten können zur Laufzeit ermittelt werden und auf Änderungen kann über einen entsprechenden Listener reagiert werden. Wo liegen die Unterschiede?

  • es gibt eine 1:n Beziehung zwischen ExtensionPoint und Extension. Dies manifestiert sich auch in den gettern der entsprechenden Objeke. Von einer ExtensionPoint Reference kann mit getExtensions() eine Liste der kompatiblen Extensions erfragt werden. Von einer Extension mit getExtensionPointUniqueIdentifier() nur genau eine ExtensionPoint ID. Ein Service kann jedoch über context.getServiceReference(<class>) von beliebig vielen Bundles genutzt werden.
  • Wie im Beispiel oben können über eine Extension alle Eigenschaften, die zu dieser gehören, ermittelt werden. Diese sind in der plugin.xml, zu der diese Extension gehört, persistiert. Daher kann eine Extension auch genutzt werden, um Daten anderen Bundels zu Verfügung zu stellen. Hierzu muss insbesondere keine Klasse instanziiert werden. Services sind dagegen immer an eine Klasse gebunden.
  • Extensions werden schon bei der Installation dem Framework bekannt gemacht. Um Extensions nutzen zu können, muss das Bundle nicht gestartet werden. Auf die Informationen, die die Extension bereitstellt, kann schon früher zugegriffen werden. Services dagegen sind erst verfügbar, wenn das implementierende Bundle gestartet wurde.
  • Da Services erst dann verfügbar sind, wenn das implementierende Bundle erfolgreich gestartet wurde, sind zu diesem Zeitpunkt auch alle Abhängigkeiten vom Framework aufgelöst. Das ist bei Extensions dann nicht der Fall wenn das zugehörige Bundle noch nicht gestartet wurde. Bei dynamischen Abhängigkeiten muss man sich in diesem Falle selber darum kümmern.
  • Bundles die Extensions oder ExtensionPoints definieren müssen Singelton Bundles sein. Daher kann das gleiche Bundle nicht gleichzeitig in mehreren verschiedenen Versionen im Framework installiert werden. Diese Einschränkung gilt nicht für Bundles, die nur Services zur Verfügung stellen.


Siehe hierzu auch folgendes Beispiel zum Zugriff auf einen Service und eine Extension durch ein anderes Plugin.