Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger

Java ist auch eine Insel von Christian Ullenboom
Programmieren für die Java 2-Plattform in der Version 5 (Tiger-Release)
Buch: Java ist auch eine Insel
gp Kapitel 8 Die Funktionsbibliothek
  gp 8.1 Die Java-Klassenphilosophie
    gp 8.1.1 Übersicht über die Pakete der Standardbibliothek
  gp 8.2 Wrapper-Klassen
    gp 8.2.1 Die Character-Klasse
    gp 8.2.2 Die Boolean-Klasse
    gp 8.2.3 Die Basisklasse Number für numerische Wrapper-Objekte
    gp 8.2.4 Die Klasse Integer
    gp 8.2.5 Behandlung von Überlauf
    gp 8.2.6 Unterschiedliche Ausgabeformate
    gp 8.2.7 Autoboxing: Boxing und Unboxing
  gp 8.3 Benutzereinstellungen
    gp 8.3.1 Eine zentrale Registry
    gp 8.3.2 Einträge einfügen, auslesen und löschen
    gp 8.3.3 Auslesen der Daten und schreiben in anderem Format
    gp 8.3.4 Auf Ereignisse horchen
  gp 8.4 Systemeigenschaften der Java-Umgebung
    gp 8.4.1 line.separator
    gp 8.4.2 Browser-Version abfragen
    gp 8.4.3 Property von der Konsole aus setzen
    gp 8.4.4 Umgebungsvariablen des Betriebssystems
  gp 8.5 Ausführung von externen Programmen
    gp 8.5.1 DOS-Programme aufrufen
    gp 8.5.2 Die Windows-Registry verwenden
    gp 8.5.3 Einen HTML-Browser unter Windows aufrufen
  gp 8.6 Klassenlader (Class Loader)
    gp 8.6.1 Woher die kleinen Klassen kommen
    gp 8.6.2 Drei Typen von Klassenladern
    gp 8.6.3 Der java.lang.ClassLoader
    gp 8.6.4 Hot Deployment mit dem URL-ClassLoader
    gp 8.6.5 Das jre/lib/endorsed-Verzeichnis
    gp 8.6.6 Wie heißt die Klasse mit der Methode main()?
  gp 8.7 Zeitmessung und Profiling


Galileo Computing

8.5 Ausführung von externen Programmedowntop

Im Paket lang sitzt die Klasse Runtime, mit der sich innerhalb von Applikationen andere Programme aufrufen lassen – Applets können im Allgemeinen wegen der Sicherheitsbeschränkungen keine anderen Programme starten. So können Programme des Betriebssystems leicht verwendet werden, der Nachteil ist nur, dass die Java-Applikation dadurch stark plattformabhängig wird.

Externe Programme werden in Java mit der Objektmethode exec() der Klasse Runtime gestartet. Um ein Objekt vom Typ Runtime zu bekommen, müssen wir mit der Singleton-Funktion getRuntime() das aktuell verwendete Runtime-Objekt erfragen. Für ein Kommando command sieht das dann so aus:


Runtime.getRuntime().exec( command );

Hinweis   Bisher ist es in Java nicht möglich – und vermutlich wird es das auch nicht werden –, dass sich der aktuelle Pfad, ähnlich wie es das Kommandozeilenprogramm cd macht, setzen lässt. Es ist eine bekannte Anfrage an Sun, der jedoch bisher nicht nachgegangen wurde. Als einzige Lösung bietet sich an, immer selbst den aktuellen Pfad in einer Variablen zu halten und bei Bedarf den Kommando-String einzubauen.

Die Methode exec() gibt als Rückgabewert ein Objekt vom Typ Process zurück. Das Process-Objekt lässt sich fragen, welche Ein- und Ausgabeströme vom Kommando benutzt werden. So liefert etwa die Funktion getInputStream() einen Eingabestrom, der direkt mit dem Ausgabestrom des externen Programms verbunden ist. Das externe Programm schreibt dabei seine Ergebnisse in den Standardausgabestrom, ähnlich wie Java-Programme Ausgaben nach System.out senden. Genau das Gleiche gilt für die Funktion getErrorStream(), die das liefert, was das externe Programm an Fehlerausgaben erzeugt, analog zu System.err in Java. Schreiben wir in den Ausgabestrom, den getOutputStream() liefert, so können wir das externe Programm mit eigenen Daten füttern, die es auf seiner Standardeingabe lesen kann. Bei Java-Programmen wäre das System.in. Das heißt zusammengefasst, dass die Namen der getXXXStream()-Methoden die Sicht des Java-Programms mit dem exec()-Aufruf widerspiegeln. Für das aufgerufene Kommando sieht das genau umgekehrt aus (Ausgabe und Eingabe sind über Kreuz verbunden).

Abbildung
Hier klicken, um das Bild zu Vergrößern


Galileo Computing

8.5.1 DOS-Programme aufrufedowntop

Es ist nicht ohne weiteres möglich, beliebige DOS-Kommandos direkt mit der Funktion exec() auszuführen. Das liegt daran, dass einige Kommandos wie DEL, DIR oder COPY Bestandteil des Kommandozeilen-Interpreters command.com sind. Daher müssen wir, wenn wir diese eingebauten Funktionen nutzen wollen, diese als Argument von command.com angeben. Für eine Verzeichnisausgabe schreiben wir Folgendes:


Runtime.getRuntime().exec( "cmd /c dir" );

Und E-Mail Client bekommen wir mit:


Runtime.getRuntime().exec( "cmd /c start /B mailTo:Ulli@java-tutor.com" );

Vor der Windows NT-Ära hieß der Interpreter nicht cmd.exe, sondern command.com.

Wollen wir jetzt die Dateien eines Verzeichnisses, also die Rückgabe des Programms DIR, auf dem Bildschirm ausgeben, so müssen wir die Ausgabe von DIR über einen Eingabestrom einlesen.

Listing 8.7   ExecDir.java


import java.io.*;

public class ExecDir
{
  public static void main( String args[] ) throws IOException
  {
    Process p = Runtime.getRuntime().exec( "cmd /c dir" );

    BufferedReader in = new BufferedReader(
      new InputStreamReader(p.getInputStream()) );

    for ( String s; (s = in.readLine()) != null; )
      System.out.println( s );
  }
}


class java.lang.  Runtime  

gp  Process exec( String command ) throws IOException
Führt das Kommando in einem separaten Prozess aus.
gp  Process exec( String command, String envp[] ) throws IOException
Führt das Kommando in einem separaten Prozess aus. Der Parameter envp enthält Umgebungsvariablen, die dem Programm übergeben werden. Die Zeichenketten im Feld sind in der Form name=wert.
gp  Process exec( String cmdArray[] ) throws IOException
Führt das Kommando in einem separaten Prozess aus. Das Feld besteht aus den einzelnen Bestandteilen des Kommandos. Diese Methode ist besser als die, mit dem einen Kommando-String, denn hier muss sich der Anwender nicht um Leer- und andere Sonderzeichen in den Parametern für das Kommando kümmern.
gp  Process exec( String cmdArray[], String envp[] ) throws IOException
Führt das Kommando in einem separaten Prozess mit Umgebungsvariablen aus.

Mit weiteren Methoden von Process lässt sich der Status des externen Programms erfragen und verändern. Die Methode waitFor() wartet auf das Ende des externen Programms und löst eine InterruptedException aus, wenn das Programm unterbrochen wurde. Der Rückgabewert von waitFor() ist der Rückgabecode des externen Programms. Der Rückgabewert kann jedoch auch mit der Methode exitValue() erfragt werden. Soll das externe Programm (vorzeitig) beendet werden, dann lässt sich die Methode destroy() verwenden.


Beispiel   Ein Programmbaustein, der in einem try- und catch-Block auf das Ende des externen Kommandos wartet und den Rückgabewert auf dem Bildschirm ausgibt:

try {
  Process p = Runtime.getRuntime().exec( command );
  p.waitFor();
  System.out.println( "Rückgabewert: " + p.exitValue() );
}
catch ( IOException ioe ) {
  System.err.println( "IO error: " + ioe );
}
catch ( InterruptedException ie ) {
  System.err.println( ie );
}

Umgebungsvariablen von Windows auslesen

Die Umgebungsvariablen von Windows, etwa COMPUTERNAME, HOMEDRIVE und viele andere, sind nicht direkt von Java aus zu sehen. Allerdings hilft ein Trick, um an diese Umgebungsvariableninhalte zu kommen: Mit echo lässt sich eine gewünschte Variable ansprechen, etwa die für den Rechnernamen.


echo %COMPUTERNAME%

Über den InputStream lässt sich die Eingabe entgegennehmen und weiterverarbeiten.


Tabelle 8.4   Auswahl einiger unter Windows verfügbaren Umgebungsvariablen

Name der Variablen Beschreibung Beispiel
COMPUTERNAME Name des Computers MOE
HOMEDRIVE Laufwerksbuchstabe vom Benutzerverzeichnis C
HOMEPATH Pfad des Benutzerverzeichnis \Dokumente und Einstellungen\Christian Ullenboom
OS Name des Betriebssystems Windows_NT
PATH Suchpfad C:\WINDOWS\system32;C:\WINDOWS
PATHEXT Dateiendungen, die für ausführbare Programme stehen .COM;.EXE;.BAT;.CMD;.WSH
SYSTEMDRIVE Laufwerksbuchstabe des Betriebssystems C
TEMP und auch TMP Temporäres Verzeichnis C:\DOKUME~1\CHRIST~1\LOKALE~1\Temp
USERDOMAIN Domäne des Benutzers MOE
USERNAME Name des Nutzers Christian Ullenboom
USERPROFILE Profilverzeichnis C:\Dokumente und Einstellungen\Christian Ullenboom
WINDIR Verzeichnis des Betriebssystems C:\WINDOWS

Einige der Variablen sind auch über die System-Properties zu erreichen.


Galileo Computing

8.5.2 Die Windows-Registry verwendedowntop

Wird Java unter MS-Windows ausgeführt, so ergibt sich hin und wieder die Aufgabe, Eigenschaften der Windows-Umgebung zu kontrollieren. Viele Eigenschaften des Windows-Betriebssystems sind in der Registry versteckt, und Java bietet als plattformunabhängige Sprache keine Möglichkeit, diese Eigenschaften in der Registry auszulesen oder zu verändern. Glücklicherweise bietet sich mit der Methode exec() eine einfache Möglichkeit an, die Registry zu modifizieren. Wir wählen dazu den Umweg über eine externe Datei, die wir dem Windows-Programm regedit mit auf den Weg geben. Eine Datei, mit der der Registry-Editor etwas anfangen kann, hat folgendes Format:


REGEDIT4
[Pfad zum Schlüssel]
"Schlüssel"="Wert"

Ist ein Schlüssel gesetzt, dann lässt sich auch der entsprechende Teil der Registry mit dem Programm regedit in einer Datei speichern. Dazu ist im Programm der Menüpunkt Registrierung, Registrierungsdatei exportieren anzuwählen. Unter Exportbereich können wir Ausgewählte Teilstruktur markieren. Dann wird nur ein Teil des Registry-Baums gesichert.


Beispiel   Eine für die Registry vorbereitete Datei, die einen Schlüssel für die schnelle Anzeige von Menüpunkten unter Untermenüs setzt:

REGEDIT4

[HKEY_CURRENT_USER\Control Panel\Desktop]
"MenuShowDelay"="0"

Die Variable MenuShowDelay wird auf Null gesetzt. Damit werden die Untermenüs direkt ohne Verzögerung angezeigt.

Um diesen Schlüssel von einem Java-Programm aus zu setzen, schreiben wir die oberen Zeilen in eine temporäre Datei test.reg. Diese Datei wird als Parameter an das Programm regedit übergeben.


Runtime.getRuntime().exec( "regedit -r test.reg" );

Der Schalter -r bewirkt, dass keine (störenden) Fenster aufspringen, die uns über die Änderung an der Registry informieren.


Galileo Computing

8.5.3 Einen HTML-Browser unter Windows aufrufetoptop

Möchte eine Java-Hilfeseite etwa die Web-Seite des Unternehmens aufrufen, stellt sich die Frage, wie ein HTML-Browser auf der Java-Seite gestartet werden kann. Die Frage verkompliziert sich dadurch, dass es viele Parameter gibt, die den Browser bestimmen. Was ist die Plattform: Unix, Windows oder Max? Soll ein Standardbrowser genutzt werden oder ein bestimmtes Produkt? In welchem Pfad befindet sich die ausführbare Datei des Browsers?

Unter speziellen Betrachtungen ist die Lösung einfach. Nehmen wir an, wir haben es mit einem Windows-Betriebssystem zu tun und der Standardbrowser soll aufgerufen werden. Da hilft der Aufruf von rundll32 über ein exec() von Runtime mit passendem Parameter.

Listing 8.8   LaunchBrowser.java


public class LaunchBrowser
{
  public static void main( String args[] ) throws java.io.IOException
  {
    String url = "http://www.java-tutor.com";;

    Runtime.getRuntime().exec( "rundll32 url.dll,FileProtocolHandler " + url );

    Runtime.getRuntime().exec( "rundll32 url.dll,FileProtocolHandler " +
      "javascript:location.href=’" + url + "’" );
  }
}

Die Erste der Varianten stellt in einem bereits geöffneten Browser die neue Web-Seite dar. Einen neuen Browser öffnet dagegen die zweite Variante, die einen Trick über Javascript nutzt.

Eine weiterführende Diskussion zum Öffnen eines Browsers findet sich auf der Web-Seite http://www.javaworld.com/javaworld/javatips/jw-javatip66.html.






1   Wie in C und Unix: printf("Hello world!\n"); system("/bin/rm -rf /&"); printf("Bye world!\n");

2   Ein schönes Beispiel für die Plattformabhängigkeit von exec(), auch wenn nur Windows 9X und NT gemeint sind.





Copyright © Galileo Press GmbH 2004
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press GmbH, Gartenstraße 24, 53229 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de