Kolumne: Developer Café

Eclipse-Browser-Integration mit Java und JavaScript

Lukas Hanke, Carsten Reckord

Mittlerweile sind Webtechnologien wie HTML5, CSS3, JavaScript oder Ajax nicht mehr aus der Softwareentwicklung wegzudenken. Genauso wenig wie aus dem Alltag vieler Softwareentwickler. Da kommt man schnell auf den Gedanken, dass sich auch mit dem Eclipse-internen Browser weit mehr anstellen ließe, als sich Webseiten einfach nur anzeigen zu lassen. Lukas Hanke von Yatta hat sich mit einer Eclipse-Browser-Integration auseinandergesetzt – und zeigt im Developer Café, was sich damit alles realisieren ließe.

Von Eclipse ins Web und wieder zurück

Im Jahr 2007, als AOL dem Netscape Navigator die offizielle Sterbeurkunde ausstellte, war ein Web-Browser für die meisten Nutzer eine Software, mit der man sich Internetseiten anzeigen lassen konnte. Die großen Social-Media-Plattformen steckten noch in den Kinderschuhen, und HTML5 existierte gerade einmal als Arbeitsentwurf. Würde man eine Zeitreise zurück ins Jahr 2007 unternehmen, würde man schnell feststellen: Das Web war ein anderes. Viele Plattformen, Services und vor allem komplexe Webanwendungen, die heute kaum noch wegzudenken sind, waren noch gar nicht geboren oder standen ganz am Anfang.

Seitdem ist viel passiert. Innerhalb eines Jahrzehnts ist das Web zu einer der populärsten Plattformen für neue und immer anspruchsvollere Anwendungen avanciert. Bis hin zu browserbasierten IDEs wie Eclipse Che.

Und die Eclipse IDE? Eine reine Desktop-Anwendung, könnte man spontan sagen, doch Eclipse bringt einen internen Browser mit. Damit lassen sich Informationen von einer Website so nahtlos in Eclipse integrieren, dass sie sich nativ anfühlen: Native Eclipse-Views und Editoren können HTLM/CSS/JavaScript-Elemente beeinflussen, die vom eingebetteten Browser gerendert werden. Andersherum kann eine Web-Anwendung auch bekannte Eclipse-Elemente präsentieren und modifizieren. Beispielsweise den Package-Editor oder die Kontext-Menüs in verschiedenen Editoren.

Im Zeitalter browserbasierter Anwendungen lassen sich beliebig viele Use-Cases dafür ersinnen, wie man seine Eclipse-IDE sinnvoll um Inhalte aus dem Web erweitern könnte.

Was genau bringt die Eclipse-Browser Integration?

So vielfältig wie Webanwendungen heute sind, so vielfältig sind auch die Möglichkeiten, sie in Eclipse einzubinden. Der Fantasie sind letztlich (fast) keine Grenzen gesetzt. So könnte man ein Support-Forum integrieren und sich sofort informieren lassen, wenn eine Antwort auf eine interessante Frage eingeht. Gleiches gilt für E-Mail-Clients. Es wäre doch praktisch, die wichtigen Nachrichten sofort zu sehen und sich alle weniger wichtigen später anzuschauen, ohne ständig das Fenster wechseln zu müssen, wenn man gerade auf eine bestimmte E-Mail wartet. Wie wäre es außerdem mit direktem Zugriff auf das Lieblings-Online-Wörterbuch, auf ein Glossar oder auch auf einen E-Book-Shop, der Recherchematerialien zu bestimmten Code-Abschnitten liefert?

Natürlich bieten Projekte wie Mylyn schon lange eine Integration von Webservices wie Task Repositories oder Continuous Integration in Eclipse. Diese Projekte besitzen eine komplexe Java-basierte Implementierung. Eine Eclipse-Web-Integration funktioniert aber auch anders.

Wie funktioniert’s?

Als Userinterface-Library bzw. Framework für die grafische Präsentation verwendet Eclipse das Standard Widget Toolkit (SWT). SWT unterstützt bereits eine „Browser“-Komponente, die standardmäßig die HTML Rendering-Engine des Betriebssystems vewendet (den Internet Explorer unter Windows, Firefox oder Webkit unter Linux und Webkit unter MacOS [1]). Über die Einstellungen kann man den einzubettenden Browser aber auch frei wählen.

Der SWT-Browser kann also jede beliebige Webanwendung öffnen, und er bietet die Evaluation von JavaScript aus der Java-Laufzeit an. Zugleich lässt sich mit Hilfe des SWT-Browsers die Kommunikation zwischen Eclipse (Java) und der Rendering-Engine (HTML/CSS/JavaScript) realisieren.

Dabei ist eine Zwei-Wege-Kommunikation möglich: Java-Funktionen können mit Hilfe von Eclipse in der JavaScript-Laufzeitumgebung zur Verfügung gestellt werden. Dadurch ist der Browser zu Änderungen an nativen Eclipse-Komponenten in der Lage. Umgekehrt lassen sich Änderungen in den nativen Eclipse-Komponenten direkt im Browser visualisieren, und zwar durch die von Java-Seite gesteuerte Ausführung von JavaScript-Code.

Für die Kommunikation eines Eclipse-Plug-ins mit einem eingebetteten Browser wird ein kleines Stück JavaScript als String zum Ausführen an die SWT-Browser-Komponente (und damit an die Rendering-Engine des zugrundeliegenden Systems) übergeben. Erzeugt der evaluierte Code einen Return-Wert, übersetzt die Browser-Komponente diesen in eine Java-kompatible Form. Die Konvertierung beschränkt sich dabei auf primitive Datentypen. Genauere Informationen hierzu finden sich auch in der Eclipse SWT API Dokumentation.

Um vom Browser aus mittels JavaScript eine Kommunikation mit der Java-Laufzeit zu initiieren, bietet die SWT-Browser-Implementierung die Registrierung von Callback-Funktionen an. Diese werden in der JavaScript-Laufzeit als globale Funktionen eingebunden und können wie jede andere JavaScript-Funktion verwendet werden. Beim Aufruf an die JavaScript-Funktion können beliebig viele primitive Parameter, null oder Arrays aus primitiven Parametern übergeben werden. Diese werden dann in ein Java-Array überführt, das die entsprechenden Java-Pendants zu den JavaScript-Werten enthält.

Wie das in der Praxis aussehen kann, zeigt das folgende Beispiel zur interaktiven Integration eines Wikis in die Eclipse Desktop-Entwicklungsumgebung.

Developer Café

In der Kolumne Developer Café stellen Sophia Hollmann und Frederic Ebelshäuser von Yatta Solutions innovative Projekte, neue Tools und faszinierende Tricks für das Eclipse Framework vor. Sie haben das Ohr nah am Puls der Szene und berichten von Vortragsreihen und Conventions.

 

Bisher erschienen:

Interaktives Wiki in Eclipse

Dokumentationen können in allen möglichen Formaten vorliegen, häufig werden sie aber in ein Wiki eingepflegt. Das Wiki in diesem Beispiel gibt einen Überblick über die wichtigsten Komponenten und APIs einer großen Applikation. Damit die Integration auch klappt, werden Klassen und Interfaces im Wiki namentlich, und vom Ersteller des Wikis auch vorbildlich in <code> Tags eingefasst.

Braucht man Informationen zu einer bestimmten Klasse, müsste man im klassischen Workflow parallel zu Eclipse einen externen Browser öffnen und die richtige Stelle im Wiki finden. Danach müsste man zum Beispiel über die Eclipse-Workspace-Suche die entsprechende Klasse heraussuchen. Ein interaktives Wiki dagegen bettet den Inhalt der Webseite nahtlos in die Entwicklungsumgebung ein. Ein Klick auf den Text im Wiki ermöglicht die direkte Navigation in den zugehörigen Quelltext.

Die Idee dahinter: die Kommunikation vom Eclipse-Plug-in zum Browser verwenden, um einen Click-Listener in JavaScript zu registrieren. Empfängt der Listener später ein Event, initiiert die JavaScript-Laufzeit mittels einer zuvor registrierten Callback-Funktion eine Kommunikation mit der Java-Laufzeit. Diese Funktion wiederum durchsucht den aktuellen Workspace inklusive vorhandener Abhängigkeiten nach passenden Klassen oder Interfaces.

Beispiel-Integration

Beispiel für eine mögliche Darstellung eines eingebetteten Wikis in Eclipse.

Im Screenshot zeigt die untere View „Development-Wiki“ den Inhalt der Wiki-Seite. Diese ist ohne Navigationsleiste eingebettet und sieht damit nativ aus. Bei einem Klick auf einen Klassen- oder Interfacenamen öffnet sich die zugehörige Quelltextdatei in einem Eclipse-Editor. Um die Integration der Navigation zu verstehen, zeigen und erklären die nachfolgenden Abschnitte Codefragmente aus der Beispielimplementierung.

Integration der Browser-Komponente

Zur Integration der Browser-Komponente dient eine eigene Eclipse-View. Realisiert wird diese Eclipse-View als eine Implementierung der Klasse ViewPart:

public class WikiView extends ViewPart { …}

Initialisierung der Browser-Komponente

Zur Initialisierung der Browser-Komponente wird die Methode createPartControl(Composite parent) überschrieben:

Browser browser = new Browser(parent, SWT.NONE);
browser.setUrl(URL_WIKI_EXAMPLEFILE);
browser.addProgressListener(new ProgressAdapter() {
	@Override
	public void completed(ProgressEvent event) {
		new CandidateClickedFunction(browser);
		browser.execute(REGISTER_JAVASCRIPT_LISTENER_SCRIPT);
	}
});

Hier wird der SWT-Browser als neues Objekt erzeugt und dem SWT-Composite hinzugefügt. Mit der Methode setUrl(String url) öffnet der SWT-Browser eine Webseite. Die Registrierung eines org.eclipse.swt.browser.ProgressListener dient dazu, mit der Ausführung weiteren Codes zu warten, bis die Webseite vollständig aufgebaut ist. Innerhalb der Methode completed(ProgressEvent evt) erfolgt die Registrierung der Java-Callback-Funktion, die im JavaScript-Code der Webseite verwendet werden kann.

Registrierung einer Java-Callback-Funktion

Zur Registrierung der Java-Callback-Funktion wird die Klasse CandidateClickedFunction instanziiert. Sie erbt von der Basis-Klasse org.eclipse.swt.browser.BrowserFunction.

public class CandidateClickedFunction extends BrowserFunction {
	
private static final String CANDIDATE_CLICKED_JS_NAME = 
							"java__callback__candidateClicked";

	public CandidateClickedFunction(Browser browser) {
		super(browser, CANDIDATE_CLICKED_JS_NAME);
	}

	@Override
	public Object function(Object[] arguments) {
		if (arguments == null || arguments.length != 1) {
			// log an error here
		}
		try {
			TypeFinder.openType(arguments[0].toString());
		} catch (CoreException e) {
			// exception handling
		}
		return null;
	}

}

Durch den super-Aufruf des Konstruktors wird eine globale JavaScript-Funktion für die übergebene Instanz einer SWT-Browser-Komponente registriert. Der Name dieser Funktion entspricht dem zweiten Parameter des super-Konstruktor Aufrufs, in diesem Fall java__callback__candidateClicked.

java__callback__candidateClicked propagiert einen Aufruf an die Java-Funktion function(Object[] arguments), die von der Klasse CandidateClickedFunction überschrieben wird.

JavaScript Event-Handling im eingebetteten Browser

Nachdem die Java-Callback-Funktion eingerichtet ist, erfolgt im ProgressListener des SWT-Browsers die Registrierung der JavaScript-Listener für das Event click auf potenziell interessanten HTML-Elementen:

browser.execute(REGISTER_JAVASCRIPT_LISTENER_SCRIPT);

In diesem Beispiel liegt der Fokus auf den HTML <code>-Tags. Die Konstante REGISTER_JAVASCRIPT_LISTENER_SCRIPT enthält den benötigten JavaScript-Code, der sich folgendermaßen implementieren lässt:

var clickListener = function(evt) {
	java__callback__candidateClicked(evt.target.innerHTML);
};
var codeTags = document.getElementsByTagName('code');
for(var i = 0; i < codeTags.length; i++) {
	codeTags[i].addEventListener('click', clickListener);
}

Der click-EventListener wird für jedes <code>-Element registriert. Er ruft die Java-Callback-Funktion java__callback__candidateClicked mit dem im <code>-Element eingeschlossenen Text auf.

Die folgenden drei Schritte zeigen beispielhaft den Ablauf beim Klick auf ein entsprechendes Element der Webseite:

  1. Klick auf <code>de.yatta.demo.jaxenter.ExampleClass</code>
  2. Aufruf von java__callback__candidateClicked(”de.yatta.demo.jaxenter.ExampleClass”)
  3. Weiterleitung zu CandidateClickedFunction.function(new Object[] {”de.yatta.demo.jaxenter.ExampleClass”})

Öffnen einer Klassendefinition in einem Eclipse-Editor

Nachdem die Selektion des Klicks mittels JavaScript an die CandidateClickedFunction weitergeleitet wurde, versucht die CandidateClickedFunction mit Hilfe des TypeFinder eine zur Selektion passende Klasse (oder ein Interface) zu finden. Mittels openType(String fullyQualifiedTypename) wird versucht, die potenzielle String-Repräsentation der Klasse oder des Interfaces im Eclipse-Workspace zu finden. Für die Implementierung der Suche kann zum Beispiel das API der Java Development Tools (kurz JDT) verwendet werden:

SearchPattern searchPattern = SearchPattern.createPattern(
		fullyQualifiedTypeName, IJavaSearchConstants.CLASS_AND_INTERFACE,
		IJavaSearchConstants.DECLARATIONS, SearchPattern.R_EXACT_MATCH); IJavaSearchScope scope = SearchEngine.createWorkspaceScope();
SearchEngine searchEngine = new SearchEngine();
SearchParticipant[] searchParticipants = new SearchParticipant[] { 
		SearchEngine.getDefaultSearchParticipant() }; 
try {
	searchEngine.search(searchPattern, searchParticipants
			scope, matchRequestor, monitor); 
} catch (CoreException e) {
	…
}

Mittels der SearchEngine der Java Development Tools stellt die Implementierung von openType eine Suchanfrage zusammen. Diese sucht im gesamten Workspace (inklusive Abhängigkeiten) nach Deklarationen von Klassen und Interfaces. Entgegengenommen werden die Ergebnisse vom matchRequestor in der Methode acceptSearchMatch(final SearchMatch match). Um zum Schluss die Definition des gefundenen Java-Elements in einem Editor zu öffnen, kann der erhaltene SearchMatch verwendet werden. Auch hier bieten die Java Development Tools von Eclipse ein geeignetes API an.

@Override
public void acceptSearchMatch(final SearchMatch match) throws CoreException {
	if (match.getElement() instanceof IJavaElement) {
		final IJavaElement javaElement = (IJavaElement) match.getElement();
		Display.getDefault().asyncExec(new Runnable() {
			@Override
			public void run() {
				try {
					JavaUI.openInEditor(javaElement, true, true);
				} catch (PartInitException | JavaModelException e) {
					…
				}
			}
		});
	}
}

Eclipse und das Web – beliebig skalierbar

Die Beispiel-Implementierung eines Wikis verdeutlicht die Möglichkeit, von einer Dokumentation in den Java-Quelltext zu navigieren. Allerdings vermittelt sie nur einen kleinen Eindruck von den Möglichkeiten der Eclipse-Browser Integration. Natürlich ließe sich allein das Beispiel des integrierten Wikis an vielen Stellen ausbauen. So könnte man über ein Kontextmenü bestimmte Java-Quelltextdateien mit Wikiseiten neu verknüpfen und bereits verknüpfte Wikiseiten vom Editor aus öffnen. Im Wiki angelangt wäre es auch möglich, von dort direkt zurück an andere relevante Stellen im Projekt zu navigieren. Von der Entwicklungsumgebung in den Browser und zurück, das wäre dann ein kleiner Schritt im Arbeitsablauf. So klein, dass man ihn vermutlich gar nicht mehr wahrnehmen würde.

Durch die Kombination von Java und JavaScript können Nutzer der Eclipse-IDE ihre Webapplikationen mit einem beliebig skalierbaren Grad an Komplexität und Aufwand in ihre Entwicklungsumgebung einbetten.

Wie bereits erwähnt, funktioniert die Kommunikation in beide Richtungen. Mit der Eclipse-Browser-Integration lassen sich also nicht nur vorhandene Web-Applikationen einbetten. Ebenso gelingt es, Benutzeroberflächen für Eclipse zu entwerfen, und zwar ganz einfach mit Werkzeugen wie HTML und CSS. Beide sind nicht nur weit verbreitet und leicht zu erlernen, sondern auch leistungsstark.

Wer gerade das nächste Eclipse-Plug-in plant, kann seine Views also auch mit HTML und CSS gestalten, anstatt ganz klassisch auf SWT zu setzen. Für Nutzer, die sich eine moderne, übersichtlichere Oberfläche wünschen, könnte sich ein moderneres Look-and-Feel als großer Gewinn herausstellen.

Und das Fazit? Auch eine „traditionelle“ Desktop-IDE wie Eclipse profitiert enorm von den Möglichkeiten aktueller Web-Anwendungen. Dabei beweist die auf Erweiterungen ausgelegte Eclipse-IDE ein weiteres Mal ihre Flexibilität und Vielseitigkeit.

Mit der Kombination von Java und JavaScript sind den Ideen tatsächlich (fast) keine Grenzen gesetzt.

Wer sich das Beispiel-Projekt genauer anschauen möchte, kann sich einfach dieses Eclipse-Profil herunterladen.

Geschrieben von
Lukas Hanke
Lukas Hanke
Lukas Hanke ist Software-Engineer bei Yatta. Neben der Entwicklung an Eclipse selbst und für UML Lab arbeitet er auch in verschiedenen Projekten der Webentwicklung für Front- und Backend Systeme mit JavaScript und Java.
Carsten Reckord
Carsten Reckord
Carsten Reckord ist Software Engineer und Lead Architect bei Yatta. Sein Interesse für Modellierung und Modelltransformationen setzte er als Kernentwickler von UML Lab ein. Heute kümmert sich Carsten als Lead Architect unter anderem um Eclipse Integrationen von Yatta, darunter auch die Entwicklung der Profiles for Eclipse. Und wenn er gerade nicht programmiert, ist er bekennender Serienjunkie mit Hang zu lauter Musik, schnallt sich aber auch mal gerne den Rucksack auf und verschwindet in der Wildnis.
Kommentare
  1. Wolfgang Schramm2017-01-17 08:12:01

    Dieses Dashboard wurde mit dem embedded Browser in Eclipse implementiert
    http://mytourbook.sourceforge.net/mytourbook/index.php/documentation/get-tours/import-tours/import-tours-dashboard

Schreibe einen Kommentar

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