= Java Webstart =

[Java Webstart|http://java.sun.com/javase/6/docs/technotes/guides/javaws/index.html] ist eine geniale Methode, um Java-Programme zu verteilen. Hat man einmal eine JVM bei sich installiert (was auf den meisten Rechnern der Fall sein dürfte), bedarf es nur noch eines einzigen Klicks auf einen Weblink, um eine Swing-Applikation zu starten. Webstart sorgt dafür, daß alle benötigten Teile der Applikation von dem Webserver heruntergeladen (oder ggf. aktualisiert) werden und startet das Programm. Es läuft danach als eigenständiges Java-Programm, d.h. ohne den Browser weiterhin zu benötigen (und natürlich auch nicht im Browserfenster wie z.B. JavaApplets). Ds Programm läuft normalerweise in einer Sandbox, d.h. es kann auf dem Rechner des Benutzers keinen Schaden anrichten. Es kann allerdings mit dem Server, von dem es geladen wurde, weiterhin Daten austauschen. Beim zweiten Mal startet alles viel schneller, weil die Programmdateien gecacht werden.

Für den Benutzer muss man eigentlich gar nichts erklären. Draufklicken und fertig.

Ein paar Erklärungen bedarf natürlich die Erstellung eines Java Webstart-Programms. Dies möchte ich hier tun:

== Funktionsweise ==

Im Grunde funktioniert webstart so: Ich habe einen Link auf eine *.jnlp-Datei. Diesem Dateityp ist vom Webserver ein besonderer MIME-Type zugewiesen. Der Browser erkennt also einen speziellen Dateityp (am MIME-Type oder an der Dateiendung). Habe ich mein Java anständig installiert, weiss der Brwoser nun, daß er für diese Datei "javaws" startet. Dieses Programm ist das eigenrliche Webstart und liest nun aus der *.jnlp-Datei die Beschreibung der Applikation und welche Komponenten sie benötigt. Diese werden dann entsprechend heruntergeladen oder aus dem Cache geholt. Danach wird die Applikation normal gestartet.

== Anforderungen an das Programm ==

Grundsätzlich benötigen wir ein ganz gewöhnliches Swing-Programm. Hierbei gibt es im Grunde keine Einschränkungen.

Einschränkungen gibt es lediglich dort, wo die Sandbox verlassen werden soll. Wer also Dateien lokal speichern oder z.B. auf das Netzwerk zugreifen will, muss besondere Maßnahmen ergreifen. Hierzu gibt es die Möglichkeit, besondere Rechte freizugeben (der Benutzer muss dann beim Start des Programmes zustimmen) oder einige [Hilfsklassen aus den Webstart-Paketen|http://java.sun.com/javase/6/docs/technotes/guides/javaws/developersguide/examples.html] zu benutzen (z.B. Drucken läuft dann immer über einen Druckdialog, womit der Benutzer dann im Moment des Druckes zustimmt, ein "sofort Drucken" geht dann nicht). Bei normalen Programmen sollten die Sandbox-Einschränkungen nicht wichtig sein. Außerdem hinterlassen sie ein besseres Gefühl beim User. Wir leben also erstmal mit Ihnen.

== Erstellung einer Distribution ==

Wer ein Programm an andere verteilen will, muss immer erstmal eine Distribution davon erzeugen. Im Prinzip heisst das, ich erzeuge (automatisiert) eine ZIP-Datei, die ich jemand fremden gebe, der dann damit meine Applikation starten kann. Wer noch nicht soweit ist, sollte Webstart noch etwas aufschieben...

Ich habe mir dazu ein Ant-File "build.xml" erstellt, das
* alle meine Klassen übersetzt
* Ein Verzeichnis "dist" erstellt
* diese Klassen zusammenpackt in eine "*.jar"-Datei in "dist"
* alle benötigten Bibliotheken nach "dist/lib" kopiert
* meine sonstigen Dokumentationen nach "dist/docs" kopiert
* evtl. eine Javadoc API-Dokumentation in "dist/docs/api" erstellt
* Evtl. eine von mir vorbereitete Website nach "dist" kopiert

Dieses "dist"-Verzeichnis ist jetzt meine Distribution (die ich als ZIP versenden kann).

== Erstellung der JNLP-Datei ==

Nun wird's endlich "webstartig". Die Syntax des JNLP-Files ist sehr gut im [Webstart Developers Guide|http://java.sun.com/javase/6/docs/technotes/guides/javaws/developersguide/syntax.html] beschrieben. Hier stelle ich deshalb nur ein einfaches Beispiel vor, das gut als Einstieg dienen kann:

{{{
  <?xml version="1.0" encoding="utf-8"?>
  <jnlp spec="1.0+" codebase="http://localhost/~tbayen/JEmpire/docs/" href="JEmpire.jnlp">
    <information>
      <title>JEmpire</title>
      <vendor>Thomas Bayen</vendor>
      <offline-allowed/>
    </information>
    <resources>
      <j2se version="1.5+"/>
      <jar href="../JEmpire.jar"/>
      <jar href="../lib/forms-1.0.7.jar"/>
      <jar href="../lib/junit-4.1.jar"/>
      <jar href="../lib/log4j-1.2.14.jar"/>
      <extension name="jogl" href="http://download.java.net/media/jogl/builds/archive/jsr-231-webstart-current/jogl.jnlp" />
    </resources>
    <application-desc main-class="de.bayen.Demo" />
  </jnlp>
}}}

Wie man sieht, ist die Datei fast selbsterklärend. Diese Datei kommt in "dist/docs" und dann kopiere ich das ganze "dist"-Verzeichnis in meinen Webserver. Einige Bemerkungen möchte ich dennoch loswerden:
* Die URL der endgültigen Adresse muss oben in "codebase" entsprechend angepasst werden (siehe Frage unten).
* Das "extension"-Tag bindet eine komplette externe Bibliothek ein. Dies hat den Vorteil, daß das Extension-Paket für JOGL, das Sun auf seinem Server hat, von Sun digital signiert ist. JOGL enthält nämlich native Teile, die in der Java Sandbox sonst nicht ausgeführt werden könnten. So spare ich mir ein Bestätigungsfenster beim Start der Applikation. Dies ist der dritte Weg, um die Beschränkungen durch die Sandbox zu umgehen.
* Der "application-desc" Eintrag gibt die Klasse an, die gestartet wird (die also eine statische main(...)-Methode enthält)
* Weitere Eintragungen sind durchaus sinnvoll, ich wollte das hier allerdings erstmal möglichst kurz halten.

=== der richtige MIME-Type ===

Obige Datei darf vom Webserver nicht als Textdatei ausgeliefert werden, sondern muss den richtigen MIME-Type bekommen. Mein lokaler Apache2 hat das von ganz alleine richtig gemacht. Ansonsten ist es eine gute Idee, das im Apache fest einzustellen, wie im [Developer Guide|http://java.sun.com/javase/6/docs/technotes/guides/javaws/developersguide/setup.html] beschrieben. Wer das nicht kann, weil die Webseite bei einem Provider liegt, der das nicht erlaubt, kann im gleichen Verzeichnis eine Datei ".htaccess" erstellen mit folgendem Inhalt:

  AddType application/x-java-jnlp-file .jnlp


== Erstellung der Webseite ==

Was jetzt noch fehlt, ist eine hübsche Webseite, um auf unsere *.jnlp-Datei zu verlinken. Dies kann man einfach mit einem Link machen und fertig. Man sollte jedoch etwas mehr Arbeit investieren und nach der Anleitung aus dem [Developers Guide|http://java.sun.com/javase/6/docs/technotes/guides/javaws/developersguide/launch.html] vorgehen. Dadurch bekommen Benutzer, die kein Java installiert haben, direkt die Gelegenheit, dies in einem Rutsch zu tun. Hierzu evtl. später mehr.

== Beispiel ==

Unser JEmpire-Projekt kann man unter http://jempire.javaproject.de besichtigen und auch direkt starten.

== Debugging ==

Zum Thema "Debugging unter Webstart" habe ich hier einige interessante Links zusammengestellt:

* [Webstart Java-Console|http://java.sun.com/j2se/1.5.0/docs/guide/deployment/deployment-guide/console.html]
* [Webstart Tracing and Logging|http://java.sun.com/j2se/1.5.0/docs/guide/deployment/deployment-guide/tracing_logging.html]
* [Sun Troubleshooting and debugging Guide|http://java.sun.com/j2se/1.5.0/docs/guide/javaws/developersguide/troubleshooting.03.06.html]
* [unofficial Webstart FAQ|http://lopica.sourceforge.net/faq.html]

Falls man das Gefühl hat, daß Verbesserungen im Programm nie beim Benutzer ankommen, ist zu beachten, daß alles gecacht wird. Im Grunde muss man sowohl den Webstart Cache (mit "javaws -viewer" anzeigen) als auch den Firefox Cache komplett leeren.

== Probleme und Fragen ==

Ich habe immer noch ein Problemchen mit Java Webstart und da gestern mindestens Jens sagte, er hätte Erfahrungen damit, hier meine Frage:

Ich möchte eine JNLP-Datei erzeugen, die ich an verschiedenen Orten benutzen kann. D.h. ich erzeuge ein Verzeichnis mit meiner Webstart-Applikation mit allem Drum und dran. Dieses Verzeichnis kopiere ich zum Testen nach ~/public_html. Nun kann ich unter "http://localhost/~tbayen/JEmpire" meine Webseiten und mein WebStart-Programm benutzen. Nun möchte ich genau das gleiche Verzeichnis einfach auf einen Webserver hochschieben und das dort dann genauso benutzen. Das geht aber nicht, weil ich im JNLP immer alle URLs absolut angeben muss. Alternativ kann ich eine "codebase" eintragen, dann muss die aber absolut sein. Ja - ich weiss, ich muss nur jeweils eine Zeile ändern. Trotzdem ärgert mich das.

Gibts da jemanden, der das Brett findet, das ich vor dem Kopf habe?!? -- ThomasBayen
:Ist eventuell nicht das was du dir vorstellst, würde aber funktionieren: Trage doch die Endung ".jnlp" bei deinem Webserver als durch PHP ausführbar ein. Dann kannst du anstelle der URL einfach ein kleines PHP-Kommando eintragen. Z.B. "<?= $_SERVER~["DOCUMENT_ROOT"~] . "/JEmpire/docs/" ?> --StefanGaffga

:War übrigens kein Brett, sondern war einfach von Sun so gemacht. Auf http://java.sun.com/docs/books/tutorial/deployment/deploymentInDepth/deployingWithoutCodebase.html steht, daß das seit "Java SE 6 update release 18", also seit ungefähr Frühjahr 2010 behoben ist. Für eigene Tests ist das eine gute Lösung; bis das alle Benutzer installiert haben, würde ich aber besser auf Java7 warten. -- ThomasBayen

Auf 64-Bit Systemen gibt es von Sun kein anständiges Plugin für Applets und Webstart. Lösungsvorschläge hierzu finden sich auf der Seite LinuxMit64Bit.

--

Vor kurzem habe ich bemerkt, daß meine Applikation auf einem meiner Systeme (Debian Lenny) nicht läuft. Es kommt die Meldung "Fehler: JAR-Resourcen in JNLP-Datei sind nicht von demselben Zertifikat signiert". Ich habe alle Webstart-Caches gelöscht und herumprobiert und bin zu der Einsicht gekommen, daß es nur daran liegen kann, daß das Lenny-System ein Java 1.6.0_12 und mein Entwicklung-System ein Java 1.6.0_16 installiert hat. Genau so steht es auch auf http://forums.sun.com/thread.jspa?threadID=5401355. Das Problem tritt offensichtlich mit bestimmten Java-Versionen auf, wenn man Dateien signiert, die bereits signiert sind. Dort gibt es noch ein paar Tips, was man machen kann.


Autor: ThomasBayen

[{Tag Java}]