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

 << zurück
Java ist auch eine Insel von Christian Ullenboom
Programmieren für die Java 2-Plattform in der Version 5
Java ist auch eine Insel

Java ist auch eine Insel
5., akt. und erw. Auflage
1454 S., mit CD, 49,90 Euro
Galileo Computing
ISBN 3-89842-747-1
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 Basisklasse Number für numerische Wrapper-Objekte
    gp 8.2.2 Die Klasse Integer
    gp 8.2.3 Wertebereich eines Typs und Überlaufkontrolle
    gp 8.2.4 Unterschiedliche Ausgabeformate
    gp 8.2.5 Autoboxing: Boxing und Unboxing
    gp 8.2.6 Die Character-Klasse
    gp 8.2.7 Die Boolean-Klasse
  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 Die Utility-Klasse System
    gp 8.4.1 Systemeigenschaften der Java-Umgebung
    gp 8.4.2 line.separator
    gp 8.4.3 Browser-Version abfragen
    gp 8.4.4 Property von der Konsole aus setzen
    gp 8.4.5 Umgebungsvariablen des Betriebssystems
    gp 8.4.6 Einfache Zeitmessung und Profiling
  gp 8.5 Ausführung von externen Programmen
    gp 8.5.1 Arbeiten mit dem ProcessBuilder
    gp 8.5.2 Die Rückgabe Process übernimmt die Prozesskontrolle
    gp 8.5.3 DOS-Programme aufrufen
    gp 8.5.4 Umgebungsvariablen und Startverzeichnis
    gp 8.5.5 Auf das Ende warten
    gp 8.5.6 Die Windows-Registry verwenden
    gp 8.5.7 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 Die wichtigsten 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 getContextClassLoader() vom Thread
    gp 8.6.7 Wie heißt die Klasse mit der Methode main()?
  gp 8.7 Annotationen
    gp 8.7.1 Die eingebauten Annotations-Typen aus java.lang
    gp 8.7.2 @Deprecated
    gp 8.7.3 Annotationen mit zusätzlichen Informationen
    gp 8.7.4 @SuppressWarnings


Galileo Computing

8.5 Ausführung von externen Programmedowntop

Aus Java lassen sich leicht externe Programme aufrufen, etwa Programme des Betriebssystems oder Skripte. Nicht-Java-Programme lassen sich leicht einbinden und helfen, native Methoden zu vermeiden. Der Nachteil ist, dass die Java-Applikation durch die Bindung an externe Programme stark plattformabhängig werden kann. Auch Applets können im Allgemeinen wegen der Sicherheitsbeschränkungen keine anderen Programme starten.

Zum Anstoßen der Ausführung gibt es im Paket java.lang zwei Klassen:

gp  Runtime erzeugt mit exec() einen neuen Prozess.
gp  ProcessBuilder seit Java 5 repräsentiert die Umgebungseigenschaften und übernimmt die Steuerung.

Galileo Computing

8.5.1 Arbeiten mit dem ProcessBuilder  downtop

Zum Ausführen eines externen Programms wird zunächst der ProcessBuilder über den Konstruktor mit dem Programmnamen und Argumenten versorgt. Ein anschließendes start() führt zu einem neuen Prozess auf der Betriebssystemseite und einer Abarbeitung des Kommandos.

new ProcessBuilder( kommando ).start();

Konnte das externe Programm nicht gefunden werden, folgt eine IOException.


class java.lang.  ProcessBuilder  

gp  ProcessBuilder( String... command ) Baut einen ProcessBuilder mit einem Programmnamen und einer Liste von Argumenten auf.
gp  start() Führt das Kommando in einem neuen Prozess aus.

Hinweis   Die Klasse ProcessBuilder gibt es erst seit Java 5. In den vorangehenden Java-Versionen wurden externe Programme mit der Objektmethode exec() der Klasse Runtime gestartet – ein Objekt vom Typ Runtime liefert die Singleton-Funktion getRuntime(). Für ein Kommando command sieht das Starten dann so aus:
Runtime.getRuntime().exec( command );


Galileo Computing

8.5.2 Die Rückgabe Process übernimmt die Prozesskontrolle  downtop

Die Methode start() 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 dies System.in. Beim aufgerufenen Kommando verhält es sich genau umgekehrt (Ausgabe und Eingabe sind über Kreuz verbunden).

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


Galileo Computing

8.5.3 DOS-Programme aufrufedowntop

Es ist nicht ohne weiteres möglich, unter Windows beliebige DOS-Kommandos direkt mit dem ProcessBuilder 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:

new ProcessBuilder( "cmd""/c""dir" ).start();

Und E-Mail Client bekommen wir mit:

new ProcessBuilder( "cmd""/c""start""/B""mailTo:Ulli@java-tutor.com" ).start();

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.9   ExecDir.java

import java.io.*;
import java.util.Scanner;
public class ExecDir
{
  public static void main( String[] args ) throws IOException
  {
    ProcessBuilder builder = new ProcessBuilder( "cmd""/c""dir" );
    builder.directory( new File("c:/") );
    Process p = builder.start();
    Scanner s = new Scanner( p.getInputStream() ).useDelimiter( "\\Z" );
    System.out.println( s.next() );
  }
}

Galileo Computing

8.5.4 Umgebungsvariablen und Startverzeichnis  downtop

Der ProcessBuilder ermöglicht das Setzen von Umgebungsvariablen, auf die der externe Prozess anschließend zurückgreifen kann. Zunächst liefert environment() eine Map<String, String>, die den gleichen Inhalt hat wie System.getenv(). Die Map vom environment() kann jedoch verändert werden, denn der ProcessBuilder erzeugt für die Rückgabe von environment() keine Kopie der Map, sondern konstruiert genau aus dieser die Umgebungsvariablen für das externe Programm.


Beispiel   Setze eine Umgebungsvariable. Der Effekt ist sichtbar, wenn die Zeile mit env.put() auskommentiert wird.
ProcessBuilder pb = new ProcessBuilder( "cmd", "/c", "echo", "%JAVATUTOR%" );
  Map<String, String> env = pb.environment();
env.put( "JAVATUTOR", "Christian Ullenboom" );
  Process p = pb.start();
String s = new BufferedReader(new InputStreamReader(p.getInputStream())).readLine();
System.out.println( s );

Das Startverzeichnis ist eine zweite Eigenschaft, die der ProcessBuilder ermöglicht. Besonders am Beispiel einer Verzeichnisausgabe ist das gut zu sehen.

ProcessBuilder builder = new ProcessBuilder( "cmd""/c""dir" );
  builder.directory( new File("c:/") );
  Process p = builder.start();

Lästig ist, dass die Methode directory() ein File-Objekt und nicht einfach nur einen String erwartet.


class java.lang.   ProcessBuilder  

gp  File directory() Liefert das aktuelle Verzeichnis des ProcessBuilders.
gp  ProcessBuilder directory( File directory ) Setzt ein neues Arbeitsverzeichnis für den ProcessBuilder.
gp  Map<String,String> environment() Liefert einen Assoziativspeicher der Umgebungsvariablen. Die Map lässt sich verändern und somit neue Umgebungsvariablen einführen.

Galileo Computing

8.5.5 Auf das Ende warten  downtop

Mit 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.

Achtung: waitFor() wartet ewig, sofern noch Daten abgeholt werden müssen, wenn etwa das Programm in den Ausgabestrom schreibt. Ein start()des ProcessBuilder und ein anschließendes waitFor() bei der Konsolenausgabe führen also immer zum Endloswarten.


Galileo Computing

8.5.6 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. (Die Schnittstelle java.rmi.registry.Registry ist eine Zentrale für entfernte Aufrufe und hat mit der Windows-Registry nichts zu tun. Auch das Paket java.util.prefs mit der Klasse Preferences erlaubt nur Modifikationen an einem ausgewählten Teil der Windows Registry.)

Um von Java auf alle Teile der Windows-Registry zuzugreifen, gibt es mehrere Möglichkeiten, unter anderem:

gp  Eine native Bibliothek wie das Windows Registry API Native Interface (http://java-tutor.com/go/jnireg), die frei zu benutzen ist und keiner besonderen Lizenz unterliegt.
gp  Für den Zugriff über die JNDI-API gibt es unter http://www.cogentlogic.com/jndi/ einen JNDI Service Provider for Windows Registries für teure 299 Kanadische Dollar.

Aufrufen von regedit und Übergeben einer Datei mit den Inhalten, die wir ändern wollen. Dieser Weg soll im Folgenden gezeigt werden.

Externe Dateien und regedit

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, 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 0 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.

new ProcessBuilder( "regedit"" _saito_fett_ -r _saito_fettout_ ""test.reg" ).start();

Der Schalter -r bewirkt, dass kein (störendes) Fenster aufspringt, welches uns über die Änderung an der Registry informiert.

Auch das Dientprogramm reg ist sehr hilfreich. So lässt sich für Registry-Anfragen einfach reg query nutzen.


Galileo Computing

8.5.7 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 mit passendem Parameter.

Listing 8.10   LaunchBrowser.java

public class LaunchBrowser
{
  public static void main( String[] args ) throws java.io.IOException
  {
    String url = "http://www.javatutor.de";
    new ProcessBuilder( "rundll32""url.dll,FileProtocolHandler"url ).start();
  }
}

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. Der BrowserLauncher unter http://browserlauncher.sourceforge.net/ ist eine Klasse, die für Windows, Unix und Macintosh funktioniert.




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.

 << zurück




Copyright © Galileo Press GmbH 2005
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, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de