Click and run

Workshop: Ihre erste Applikation mit Unterstützung von Suns JNLP-Referenzimplementierung Java Web Start

Sven Haiges und Steffen Müller

Eines vorweg: Sie werden sich wundern, wie einfach es ist, Applikationen per
JNLP im Web bereitzustellen. Folgen Sie einfach den Anweisungen in den folgenden
Absätzen und binnen kurzer Zeit wird es Ihnen gelingen, Ihre erste Applikation
zu deployen. Der erste Teil des Workshops konzentriert sich dabei darauf, eine
sehr einfache Java-Applikation JNLP-fähig zu machen. Im zweiten Teil des Workshops
werden wir der Applikation unter Verwendung der wichtigsten JNLP-APIs weitere
Funktionalität hinzufügen, um etwa auf das lokale Datei-System zuzugreifen.
Des Weiteren demonstrieren wir Ihnen den Einsatz von Werkzeugen zum effizienten
Arbeiten mit JNLP. Lassen Sie uns keine Zeit verlieren, packen wir’s an!

Sollten Sie Java Web Start noch nicht installiert haben, wäre dies der erste
Schritt des Workshops. Laden Sie Java Web Start in diesem Fall kostenlos unter
java.sun.com/products/javawebstart herunter und starten Sie das Installationsprogramm.
Sollten Sie bereits eine Java-Laufzeitumgebung (JRE) installiert haben, genügt
der Download des Updates, welches lediglich 720 KB in Anspruch nimmt. Das komplette
Paket umfasst in der englischen Version ca. 5,3 MB.

Unsere Test-Applikation

Wir beginnen mit der Entwicklung einer einfachen Applikation, die wir später
per JNLP startfähigmachen werden. Unsere Applikation besteht aus Gründen der
Einfachheit und zu Demonstrations-Zwecken lediglich aus einem simplen Swing-Frame.
Den kompletten Source-Code finden Sie  sowohl in Listing 1 als auch auf der
CD-ROM dieser Ausgabe. Kompilieren Sie das Programm mit javac und starten
Sie es so, wie Sie es bei Java-Programmen gewohnt sind.

Listing
1


import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class JWSMain_Basic extends JFrame
{
    JLabel javaMagazinLabel;
    public JWSMain_Basic()
    {
        //get current classloader
        ClassLoader cl = this.getClass().getClassLoader();
        //create an icon
        Icon javaMagazinIcon = new ImageIcon( cl.getResource( "jm_logo.gif" 
  ));
        //create an label out of the icon
        javaMagazinLabel = new JLabel(javaMagazinIcon);
        //add the label to the contentpane
        this.getContentPane().add(javaMagazinLabel);
        //add a WindowListener, to enable window closing
        this.addWindowListener(new MyWindowAdapter());
        //set the size, title, show window
        this.setSize(300,300);
        this.setTitle("JWS-Workshop");
        this.show();
    }
    public static void main(String args[])
    {
        new JWSMain_Basic();
    }
    class MyWindowAdapter extends WindowAdapter
    {
        public void windowClosing (WindowEvent we)
        {
            System.exit(0);
        }
    }
}

Erstellen von JAR-Dateien

Nach der erfolgreichen Kompilierung erstellen wir nun eine JAR-Datei. Obwohl
sich unsere Applikation bisher lediglich aus einer einzigen CLASS-Datei
besteht, ist es trotzdem nötig, diese Datei in ein Java-Archiv zu packen, denn
aus den JNLP-Dateien heraus können keine einzelnen Klassen verlinkt werden.

Mit folgendem Befehl  erstellen wir die JAR-Datei namens jws_basic.jar:


jar cvf jws_basic.jar *.*

Erstellen  der JNLP-Datei

Die JNLP-Datei legt einige Details unserer Applikation fest und ermöglicht
es dem Anwender, sie mittels eines beliebigen JNLP-Clients, wie hier z.B. Java
Web Start, starten zu können (Listing 2).

Listing
2



  
    Java Web Start Workshop - Part One
    Sven Haiges, Steffen Mueller
    
    This is a sample Application for the Workshop in Java 
  Magazine. It just shows a frame that has a Java Magazine icon in it.
    JWS-Workshop, Part One
    JWS (1/2)
    This is a sample Application 
  for the Workshop in Java Magazine. It just shows a frame that has a Java Magazine 
  icon in it.
    
  
  
  
    
    
  
  

Sie finden den Quelltext der JNLP-Datei ebenfalls auf der CD. Bitte vergessen
Sie nicht, die Attribute des Tags gemäß Ihrer Umgebung anzupassen.
Innerhalb des -Tags werden Informationen angegeben,
die während dem Download, später in der Ansicht im Application-Manager und für
die Verknüpfungen auf demDesktop verwendet werden. Durch den Tag
können Sie dem Anwender erlauben, Ihre Applikation vom Application- Manager
aus auch ohne Internet-Verbindung zu starten. Da wir auf keinerlei Ressourcen
des Clients (Dateisystem, Clipboard, etc.) zugreifen, setzen wir ein leeres
-Tag hinter das Tag. Bei den
benötigten Ressourcen setzen wir die JRE-Version 1.3 oder 1.2 voraus und verlinken
auf unsere JAR-Datei jws_basic.jar. Schließlich wird in
die Klasse angegeben, in der sich unsere Main-Methode befindet.

Einrichtung des Servers

Sie können jeden beliebigen Web-Server benutzen, um Ihre JNLP-konforme Applikation
laufen zu lassen. Alles, was Sie tun müssen, ist, den MIME-Type für JNLP-Dateien
einzurichten. Dies ermöglicht Ihrem Browser, die JNLP-Datei an Java Web Start
weiterzuleiten. Bei der Verwendung von Apache erreichen Sie dies beispielsweise,
indem Sie folgende Zeile in dessen Konfigurations-Datei httpd.conf eintragen:


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

Upload auf den Server

Abschließend müssen Sie nun sowohl die JAR-Datei jws_basic.jar als auch
das JNLP-File jws_basic.jnlp auf Ihren Server in das dafür eingerichtete
Verzeichnis kopieren. Beachten Sie bitte, dass das Upload-Verzeichnis dem Verzeichnis
entspricht, das im Codebase-Attribut des JNLP-Files angegeben wurde. In unserem
Fall laden wir nun die beiden Dateien in das Verzeichnis jws_workshop
unseres Servers.

Bereits jetzt sollten Sie Ihre Applikation über den direkten Aufruf der JNLP-Datei
über Ihren Web-Browser testen können. Probieren Sie es einfach einmal aus, indem
Sie dessen absolute Adresse in Ihrem Browser aufrufen. Daraufhin sollte automatisch
Java Web Start aktiviert werden, und Ihre Applikation sollte nach dem kurzen
Download direkt gestartet werden. Sollte gar nichts passieren oder die JNLP-Datei
im Browser angezeigt werden, starten Sie Ihren Web-Server bitte erneut. Es ist
nämlich möglich, dass er die geänderte Konfigurationsdatei nicht geladen hat
und den neuen MIME-Type demnach noch nicht kennt. Startet Java Web Start nach
der Eingabe der entsprechenden URL, bietet Ihnen dessen Application-Manager
eine kleine Hilfe, indem er Ihnen den vorgefallenen Fehler anzeigt. Überprüfen
Sie dann nochmals, ob die JAR-Datei korrekt erstellt wurde (lässt sich die Applikation
lokal starten?) und ob die Verzeichnisse in der JNLP-Datei mit dem Upload-Verzeichnis
übereinstimmen.

Erstellung einer HTML-Seite

Der direkte Launch per JNLP-Datei ist natürlich nur für Test-Zwecke geeignet.
Vorzugsweise werden Sie für die Aktivierung Ihrer Applikation einen Link in
einer HTML-Seite verwenden, der auf Ihre JNLP-Datei zeigt. Der Link könnte z.B.
so aussehen:


Meine erste JWS-Applikation

Herzlichen Glückwunsch! Sie haben soeben Ihre erste Applikation per JNLP-Technologie
deployed. Wenn Sie möchten, können Sie unsere Beispiel-Applikation unter www.webstartapps.com/workshop/
testen.

Weitere Funktionen des JNLP

Im ersten Teil haben Sie eine schlichte Java-Applikation per JNLP deployt.
Wir werden nun im zweiten Teil das JNLP-API verwenden, um weitere Funktionalitäten
hinzuzufügen. Zunächst legen Sie bitte eine JMenuBar an, welche die Menüs File
und JNLP aufnimmt. Im Menü JNLP legen wir der Übersichtlichkeit wegen
die MenuItems für die diversen JNLP-Services ab, die wir testen wollen. Im Rahmen
dieses Workshops werden wir den BasicService, FileOpenService, FileSaveService
und den ClipboardService näher betrachten.

Eine Liste der verfügbaren Services erhalten wir vom ServiceManager mit der
Methode getServiceNames(). Sie werden später feststellen, dass Java Web
Start alle Services zur Verfügung stellen kann. Über eine for-Schleife
geben wir nun einfach alle Positionen des vom ServiceManager zurückgegebenen
String-Arrays auf der Standard-Ausgabe aus. Aktivieren Sie dazu in Java Web
Start bitte die Java-Konsole, sonst können Sie die Ausgaben nicht sehen.


    private void basicServiceTestAction(ActionEvent e)
    {
 String allServices[] = ServiceManager.getServiceNames();
for (int i = 0; i System.out.println("Available 
  Service: " + allServices[i]);
    }

Kommen wir nun zum BasicService. Wir verlangen vom ServiceManager einen BasicService
und prüfen ab, ob das System online ist bzw. einen Web-Browser unterstützt (!bs.isOffline()
&& bs.isWebBrowserSupported()). Ist der Zugang zum Internet
vorhanden und kann der JNLP-Client einen Web-Browser finden, öffnen wir mit
der Methode showDocument(new URL()) die Homepage des Java Magazins (siehe
Listing 3):

Listing
3


        try
        {
            BasicService bs = (BasicService)ServiceManager.lookup("javax.jnlp.BasicService");
            if (!bs.isOffline() && bs.isWebBrowserSupported())
            {
                System.out.println("System is online, trying to open browser...");
                bs.showDocument(new URL("http://www.javamagazin.de"));
            }
            else
            {
                System.out.println("System is offline, or no browser is 
  supported. Won't open browser.");
            }
        }
        catch (UnavailableServiceException usex)
        {
            System.out.println("BasicService was not available. Can't 
  run the test sequence... " + usex.toString());
        }
        catch (MalformedURLException muex)
        {
            System.out.println("URL was malformed. Quitting... "+ 
  muex.toString());
        }

Der FileOpenService

Da wir noch keine signierte Applikation haben, benötigen wir zwingend die JNLP-APIs,
um auf das Dateisystem des Anwenders zugreifen zu können. Der Service für diese
Funktionalität nennt sich FileOpenService. Seine Methode openFileDialog()
zeigt dem User einen Sicherheitshinweis an und liefert bei Zustimmung des Users
ein Objekt des Typs FileContents zurück. Mittels FileContents ist es möglich,
einen InputStream zu erhalten und diesen wie gewohnt weiterzuverarbeiten. Der
Methode openFileDialog() erwartet zwei  Parameter: zum einen das Ausgangsverzeichnis
für den FileDialog und zum anderen der Default-Filter für Dateiendungen (.java,
.txt).


String extensions[] = {"txt", "java"};

openFileDialog("/home/hansa/", extensions);

Bitte beachten Sie, dass Sie über FileContents nicht den absoluten Pfad der
ausgewählten Datei ausfindig machen können. Mit einem InputStream können Sie
jedoch auf den Inhalt der jeweiligen Datei zugreifen.

Der vollständige Code zum Öffnen einer Datei und deren Ausgabe auf der Standardausgabe
sieht folgendermaßen aus:

Listing
4


    private void fileOpenServiceTestAction(ActionEvent e)
    {
        System.out.println("fileOpenServiceTestAction: entering...");
        try
        {
            FileOpenService fos = (FileOpenService)ServiceManager.lookup
("javax.jnlp.FileOpenService");             String extensions[] = {"txt", "java"};             FileContents fc = fos.openFileDialog("/home/hansa/", extensions);             if (fc != null)             {                 System.out.println("trying to print the file contents of " + fc.getName());                 InputStreamReader isr = new InputStreamReader(fc.getInputStream());                 BufferedReader br = new BufferedReader(isr);                 String line = new String();                 while ( (line = br.readLine()) != null)                 {                  System.out.println(line);                 }                 System.out.println("End of File");             }             else             {                 System.out.println("user canceled the file dialog.");             }         }         catch (UnavailableServiceException ex)         {             System.out.println("FileOpenService is not available! " + ex.toString());         }         catch (IOException ioe)         {             System.out.println("FileOpenDialog generated a IOException... " + ioe.toString());         }     }

FileSaveService

Der FileSaveService arbeitet ähnlich wie der FileOpenService. Beachten Sie
bitte folgende Zeile Code, der das Öffnen des Save File Dialogs bewirkt:


FileContents fc = fss.saveFileDialog("/home/hansa/", 
extensions, is, "test.java");

Wieder können wir ein Ausgangsverzeichnis sowie eine Liste der vorgeschlagenen
Dateiendungen als Parameter der Methode mitgeben. Zusätzlich müssen wir nun
jedoch noch einen InputStream sowie einen Vorschlag für den Dateinamen übergeben.
In unserem Fall öffnen wir einfach die index.html einer Website als URL
und speichern diese HTML-Seite dann lokal ab. Wenn der User den FileSaveDialog
zurückweist, erhalten wir eine leere Referenz (null) zurück und können entsprechend
darauf reagieren.

Listing
5


    private void fileSaveServiceTestAction(ActionEvent e)
    {
        System.out.println("fileOpenServiceTestAction: entering...");
        try
        {
            FileSaveService fss = (FileSaveService)ServiceManager.lookup
("javax.jnlp.FileSaveService");             URL testURL = new URL("http://www.flavor.de/index.html");             InputStream is = testURL.openStream();             String extensions[] = {"txt", "java"};             FileContents fc = fss.saveFileDialog("/home/hansa/", extensions, is, "test.java");             if (fc == null)             {                 System.out.println("user aborted the save dialog");             }             else             {                 System.out.println(fc.getName() + " has been saved.");             }         }         catch(UnavailableServiceException usex)         {             System.out.println("FileSaveService is not available! " + usex.toString());         }         catch(MalformedURLException muex)         {             System.out.println("URL was malformed..." + muex.toString());         }         catch(IOException ioe)         {             System.out.println("IOException! " + ioe.toString());         }     }

ClipboardService

Für die Nutzung der Systemzwischenablage fordern wir vom ServiceManager den  
Service javax.jnlp.ClipboardService an. Ist dessen Wert ungleich null,
und ist dabei keine Exception aufgetreten, können wir den ClipBoardService verwenden.
Im ersten Schritt speichern wir einen String in die Zwischenablage ab und lesen
diesen im Anschluss unter Benutzung des gleichen Services wieder aus.

Die beiden Methoden der Klasse ClipBoardService lauten setContents()
und getContents(). Um Daten in die Ablage zu speichern, wird der
Methode setContents() ein Transferable-Objekt übergeben. Die einfachste
Implementierung des Transferable-Interfaces ist die Klasse StringSelection,
die wir im folgenden Beispiel benutzen.

Um Daten aus der Ablage abzurufen, rufen wir die Methode getContents()
des ClibboardServices auf und erhalten ebenfalls ein Transferable-Objekt zurück. 
Um sicher zu gehen, dass die in der Ablage enthaltenen Daten auch in einen String
verwandelt werden können, prüfen wir dies mit Transferable..isDataFlavorSupported(DataFlavor.stringFlavor)
ab. Da dies in unserem Beispiel sehr wahrscheinlich ist, geben wir den Inhalt
auf der Ausgabe aus.

Listing
6


    private void clipboardServiceTestAction(ActionEvent e)
    {
        try
        {
            ClipboardService cs = (ClipboardService)ServiceManager.lookup
("javax.jnlp.ClipboardService");             if (cs != null)             {                 // Inhalte erzeugen und im Clipboard ablegen                 StringSelection ss = new StringSelection("Java Magazin Rules!");                 cs.setContents(ss);                 // Inhalt aus dem Clipboard zurücklesen, ausgeben                 Transferable tr = cs.getContents();                 if (tr.isDataFlavorSupported(DataFlavor.stringFlavor))                 {                     String s = (String)tr.getTransferData(DataFlavor.stringFlavor);                        System.out.println("Clipboard contents: " + s);                 }             }         }         catch (UnavailableServiceException sex)         {             System.out.println("Sorry, ClipboardService is not available!");         }         catch (UnsupportedFlavorException ufe)         {             System.out.println("Sorry, SringFlavor ist not supported!");         }         catch (IOException ioe)         {             ioe.printStackTrace();         }     }

JWS-Warnanzeige

Java Web Start gibt die in Abpictureung 1 gezeigte Meldung aus, wenn versucht
wird, auf die Zwischenablage zuzugreifen.

Signierung der JAR-Files

Bisher war das resultierende Jar-File nicht signiert, was zur Folge hatte,
dass unsere Anwendung nicht denvollen Zugriff auf das System erlangen konnte.
Jeder Zugriff wurde über das JNLP-API durchgeführt  und musste einzeln autorisiert
werden. Wenn Sie Ihre JAR-Dateien signieren, haben Sie die Möglichkeit, vom
Anwender zu Beginn alle Rechte zu fordern und können dann wie gewohnt und/oder
unter Nutzung des JNLP-APIs auf das System zugreifen.

Um Ihre JAR-Dateien mit einem Test-Zertifikat zu signieren, gehen Sie wie folgt
vor. Die folgenden Zeilen sind dabei auf unser Beispiel angepasst:


keytool -genkey -keystore myKeystore -alias meinName

Geben Sie alle angeforderten Informationen ein. In Ihrem Verzeichnis wird dann
die Datei myKeystore angelegt werden, ebenso ein Test-Zertifikat.


keytool -list -keystore myKeystore

Zur Sicherheit können Sie prüfen, ob das Zertifikat richtig erstellt wurde.


jarsigner -keystore myKeystore jws_workshop.jar meinName

Mit dem Jarsigner-Tool signieren Sie nun die Jar-Datei. Um alle Rechte von
dem Anwender Ihrer Applikation anzufordern, fügen Sie in Ihrer JNLP-Datei im
Abschnitt das Tag ein.


 
   

Nützliche Tools

Es gibt bereits einige Tools, die Ihnen die Arbeit bei der Erstellung der JNLP-Files
bis hin zum Upload auf den Server stark erleichtern. Praktisch ist, dass diese
Tools selbst wieder per Java Web Start bereit stehen und so ganz einfach von
Ihnen getestet werden können.

Vamp – der Venus Application Publisher von Gerald Bauer

Vamp können Sie direkt über den Link www.jenomics.de/vamp/venus.jnlp starten.
Mit diesem Tool können Sie auf einfache Weise eine JNLP-Datei erstellen, indem
Sie es sich nach dem Baukasten-Prinzip zusammenklicken. Das Packagen und Signieren
erledigt Vamp ebenfalls für Sie, bis hin zum Upload auf den Server. Für weitere
Informationen zu Vamp und anderen Tools im Java Web Start-Umfeld sollten Sie
einen Blick auf www.vamphq.com werfen. Hier finden sie das infoffizielle Java
Web Start FAQ sowie reichlich Links und Erklärungen.

Hiermit befinden wir uns am Ende dieses Workshops und hoffen, dass wir in Ihnen
die Begeisterung für Java Web Start geweckt haben. Sollten Sie weitere Fragen
haben, können Sie uns gerne per E-Mail unter webstart@flavor.de
erreichen.

Information-Description-Anzeige von Vamp
Kommentare

Schreibe einen Kommentar

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