Die Eclipse-OSGi-Konsole für eigene Zwecke nutzen

OSGi-Konsolen, Affen und seltsame Schleifen

Wolfgang Werner

In der Praxis selten genutzt, aber gerade bei der serverseitigen Verwendung der Equinox Runtime sind eigene Kommandos in der OSGi-Konsole ein mächtiges Werkzeug, um applikationsspezifische Wartungsaufgaben durchzuführen. Wie wäre es beispielsweise mit einem Kommando, das alle Log-Einträge für einen bestimmten Zeitraum extrahiert, einen Heapdump erzeugt und alles in ein Archiv packt, um es danach auf einen FTP-Server zu stellen und Ihnen den Link per Mail zu senden? Oder wollen Sie einfach nur einige Integritätstests durchführen? In diesem Artikel werden wir die OSGi-Konsole um ein einfaches Kommando erweitern, das einen JUnit-Test ausführt und die Ergebnisse auf der Konsole ausgibt. Um herauszufinden, wie das funktioniert, werden interne Eclipse-Workbench-Pakete näher betrachtet. Sie werden sehen, wie man effektiv „schnüffelt“ und die Dynamik von OSGi nutzen kann, um Entwicklungsprozesse schlank zu halten.

Um die in diesem Artikel beschriebenen Schritte nachvollziehen zu können, benötigen Sie die Helios Classic Edition [1], da diese die Eclipse-Quelltexte enthält. Alternativ können Sie die Source Bundles auch über eine Updatesite nachinstallieren. Nachdem wir Eclipse gestartet haben, öffnen wir als Erstes die OSGi-Konsole. Neu ist die Konsole nicht, seit Eclipse 3.6M7 [2] ist es aber möglich, die Konsole der laufenden Eclipse-Instanz direkt über die GUI zu erreichen. Dazu öffnen wir den Dialog SHOW VIEW mithilfe der Tastenkombination Alt-Shift-Q,Q und wählen die Sicht CONSOLE aus. Um die gewünschte View ohne das Öffnen aller Kategorien zu finden, verwenden wir die Filterfunktion des Dialogs. In der geöffneten View finden wir im OPEN CONSOLE-Menü den Eintrag HOST OSGI CONSOLE. Die Konsole begrüßt uns mit einer Warnung und dem OSGi Prompt (Abb. 1).

Abb.1: Host OSGi Console

Wir maximieren die CONSOLE View mit Ctrl-M und geben das Kommando help ein, das uns die von der Konsole unterstützten Befehle anzeigt. Auch wenn sie ein versierter Eclipse-Veteran sind, sollten sie einen Blick in die Hilfe werfen. In den letzten Jahren hat sich der Funktionsumfang der OSGi-Konsole deutlich erhöht. Natürlich gibt es noch die gewohnten Befehle, um Bundles zu installieren, zu starten und zu stoppen und Runtime Properties zu setzen, aber auch neue, um mit OSGi Services zu interagieren, die Extension Registry oder registrierte Equinox-Applikationen auszulesen.

Aber zurück zu unserem Eingangsszenario: Wir möchten die Möglichkeit schaffen, auf einem produktiven System eine Reihe von Diagnosetests ausführen zu können, um sicherzugehen, dass gemeldete Fehler nicht auf Dateninkonsistenzen oder Installationsprobleme zurückzuführen sind. Unter Umständen möchten wir sogar die Testsuite um weitere Tests ergänzen – natürlich ohne das System neu starten zu müssen. Gehen wir davon aus, dass unsere Applikation bereits eine Reihe von Diagnosetests beinhaltet. Unsere Aufgabe ist es, diese Tests über die Konsole ausführbar zu machen. Sollten Sie das Buch Pragmatic Project Automation [3] im Regal stehen haben, können Sie im Kapitel 5.4 noch ein paar Anregungen zum Thema Diagnosetests finden.

Test First

Nein, hier geht es nicht um testgetriebene Entwicklung, sondern um die Tests, die unser Kommando ausführen soll. Wir schreiben einen einfachen JUnit-Test und einen Test Runner, der den Test ausführt und das Ergebnis zurückliefert. Um sicherzugehen, dass wir auch etwas zu sehen bekommen, lassen wir einen Test fehlschlagen. Bei der Projekterstellung müssen wir darauf achten, als Target Platform Equinox anzugeben, da die Eclipse-OSGi-Konsole Equinox-spezifisch ist. Die OSGi-Spezifikation beschreibt nur das Vorhandensein von Management Agents, nicht aber deren genaue Funktion oder Implementierung. Wir erstellen also ein neues Plug-in Project über den New Project Wizard und wählen als Target Equinox. Das neue Bundle wird sowohl unsere Test- als auch die Kommandoimplementierung enthalten.

OSGi Management Agents

Die OSGi-Spezifikation ([11], Kapitel 4.4 und [12], Kapitel 110, 110.5) beschreibt in Management Agents als Mittel, um den Lebenszyklus von Bundles zu steuern. Management Agents liegen dabei selbst in Form eines oder mehrerer Bundles vor. Während die Spezifikation die Services beschreibt, die von Management Agents verwendet werden können/sollen, sind hinsichtlich Funktionsumfang und Möglichkeiten zur Benutzerinteraktion keine Vorgaben enthalten.

Eine Implementierung eines Management Agents ist die in diesem Artikel beschriebene OSGi-Konsole des Eclipse-Equinox-Projekts. Die folgende Liste enthält eine kleine Auswahl weiterer Implementierungen:

Dabei nehmen Felix GoGo und Posh eine Sonderstellung ein, da mit RFC 147 parallel versucht wird, ein gemeinsames Set von Managementkommandos für alle OSGi-Implementierungen zu standardisieren [17], [18]. Der Vorgänger von RCF 147, RFC 132 ist noch einem OSGi 4.2 Early Specification Draft zu finden [19]. Ein Specification Draft für RFC 147 wird Ende 2010 erwartet.

Listing 1
import static org.junit.Assert.assertTrue;
import org.junit.Test;

public class Tests {
 @Test
 public void fineTest() {
   assertTrue("All is well", true);
 }

 @Test
 public void badTest() {
   assertTrue("Sweet guinea pig of Winnipeg! How did that happen?", false);[4]
 }
}

Interessanter ist der Code, der die Tests ausführt. JUnit stellt uns ein einfaches API [5] für diesen Zweck zur Verfügung: org.junit.runner.JUnitCore. Diese Klasse bietet statische Methoden, um Tests auszuführen. Die Ergebnisse werden als Objekte der Klasse org.junit.runner.Result zurückgeliefert. Result bietet die Möglichkeit, die Anzahl der durchgeführten und fehlgeschlagenen Tests, die Laufzeit und die aufgetretenen Fehler (org.junit.runner.notification.Failure) abzufragen. Über Failure erhalten wir Zugang zu Testnamen , -beschreibungen, Fehlermeldungen und aufgetretenen Exceptions.

Listing 2
import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;

public class TestRunner {
 public static String run() {
   Result testResult = JUnitCore.runClasses(Tests.class);

   StringBuilder resultMessage = new StringBuilder();
   for (Failure failure : testResult.getFailures()) {
   	  resultMessage.append(failure.toString());
   }
   return resultMessage.toString();
 }
}
Geschrieben von
Wolfgang Werner
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.