Extension Point

Aus Eclipse
Version vom 15. Juli 2010, 14:05 Uhr von Thies (Diskussion | Beiträge)

(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)
Wechseln zu: Navigation, Suche

Damit ein Plugin durch andere Plugins erweitert werden kann, kann es einen oder mehrere Extension Points (Erweiterungspunkte) anbieten. Andere Plugins docken dann an dem Extension Point an, indem sie eine passende Extension (Erweiterung) anbieten.

Ein Extension Point ist ein XML-Element in der plugin.xml-Datei eines Plugins. Zusätzlich kann in dem XML-Element ein Interface deklariert werden, das Extensions implementieren, die den Extension Point erweitern. Es sind auch noch andere Arten von Extension Points möglich, aber hier soll ein Extension Point besprochen werden, der durch Extensions erweitert wird, die eine Instanz eines bestimmten Java-Typs zur Verfügung stellen.

Eigenschaften von Extension Points

Ein Extension Point wird durch eine ID identifiziert. Die ID ist eine Bezeichnung, die deutlich machen sollte, welche Funktionalität über den Extension Point angebunden wird. Da ein Extension Point immer von mehreren Extensions angesprochen werden kann, sollte diese Bezeichnung im Plural stehen. Die ID des Extension Points wird später relativ zur ID des Plugins interpretiert, das den Extension Point deklariert. Neben der ID wird für den Extension Point noch ein Name definiert, der die gleiche Aussage haben muss, wie die ID, jedoch dafür gemacht ist, von Menschen gelesen zu werden.

Zusätzlich verfügt ein Extension Point über ein XML-Schema-ähnliche Datei, die beschreibt, wie valide XML-Elemente von Extensions aussehen müssen, die den Extension Point erweitern.

Extension Point definieren, der ein Interface vorgibt

Um die Definition eines Extension Points zu beschreiben, verwenden wir folgendes Szenario: Plugin A definiert einen Extension Point P1. P1 hat die ID chatters und den Namen Chatters sowie folgendes Interface, das Extensions implementieren müssen, die den Extension Point erweitern wollen:

public interface Chatter {
   public String saySomething();
}
.

Die folgenden Schritt werden im Plugin-Manifest-Editor des Plugins A durchgeführt, für das der Extension Point P1 deklariert wird. Alternativ kann man auch direkt den XML-Quellcode bearbeiten. Die Verwendung des Plugin-Manifest-Editors hat jedoch den Vorteil, dass der Editor weitere Schritte verweigert, wenn ein Zwischenergebnis nicht korrekt ist und man so sich so einfach von einem korrekten Zwischenschritt zum nächsten hangeln kann.

  1. Durch Doppelklickt auf die plugin.xml-Datei im Package Explorer den Plugin-Manifest-Editor für das Plugin öffnen.
  2. Im Tab Extension Points des Plugin-Manifest-Editors einen neuen Extension Point anlegen. Dazu in dem sich öffnenden Dialog ID und Name eintragen. Der Schema-Pfad wird automatisch voreingestellt. Die Checkbox 'Edit extension point schema when done' sollte ausgewählt bleiben. Ein Klick auf 'Finish' erstellt den Extension Point.
  3. Der Extension Point Schema Editor des Extension Points wird automatisch geöffnet.
  4. Im Tab 'Definition' gibt es bereits das Element extension. Wir müssen ein Element hinzufügen, mit dem die Extensions die Klasse angeben können, die das Chatter-Interface implementiert.
  5. Ein neues Element mit dem Namen chatter erstellen.
  6. Dem Element chatter ein neues Attribut mit dem Namen class erstellen, dessen Verwendung required ist, das den Typ java hat. Es sollte festgelegt werden, dass die Werte im Feld das Interface Chatter implementieren. Zur Auswahl des Chatter-Interface sollte der Browse-Button verwendet werden.
  7. Dem bestehenden Element extension eine neue Sequenz hinzufügen.
  8. Der neuen Sequenz eine Referenz auf das chatter-Element hinzufügen, indem das Element chatter per Drag-and-Drop auf die neue Sequenz gezogen wird.
  9. Speichern
  10. Falls nicht automatisch gebaut wird: das Projekt bauen.

Extension Point definieren, der eine abstrakte Klasse vorgibt

Anstatt ein Interface vorzugeben, das die von den Extensions bereitgestellten Instanzen implementieren müssen, kann auch eine abstrakte Klasse vorgegeben werden, die die bereitgestellten Instanzen beerben müssen.

Extensions finden und laden

Bevor ein Plugin Extensions finden kann, die an seinem Extension Point andocken, müssen die Extensions implementiert werden. Beim Laden der Extensions muss folgendes beachtet werden:

  • das Laden der Extension kann fehlschlagen
  • die Extension kann einen anderen als den im Extension Point spezifizierten Typ haben
  • es ist möglich und erwünscht, dass sich mehr als eine Extension an den Extension Point andocken.

Die folgenden beiden Methoden geben für eine ID eines Extension Points eine Liste mit angedockten Implementierungen des Interfaces des Extension Points zurück.

private <T> List<T> loadPluginObjects(String extensionPointId) {
	List<T> adapters = new ArrayList<T>();
	IExtensionRegistry registry = Platform.getExtensionRegistry();
	IExtensionPoint extensionPoint = registry.getExtensionPoint(extensionPointId);
	IExtension[] extensions = extensionPoint.getExtensions();
	for(int i=0; i<extensions.length; i++) {
		loadPluginObject(adapters, extensions[i]);
	}
	return adapters;
}
 
private <T> void loadPluginObject(List<T> adapters, IExtension extension) {
	IConfigurationElement[] elements =
		extension.getConfigurationElements();
	for(int j=0;j<elements.length;j++) {
		try {
			// Provoke a ClassCastException because we cannot access the type T at runtime
			// to ensure that the returned object is an instance of T
			T extInstance = (T)elements[j].createExecutableExtension("class");
			adapters.add(extInstance);
		} catch (ClassCastException cce) {
			IStatus status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Error while loading plugin objects", cce);
			Activator.getDefault().getLog().log(status);
		} catch (CoreException ce) {
			IStatus status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Error while loading plugin objects", ce);
			Activator.getDefault().getLog().log(status);
		}
	}
}