![]() | ![]() |
|
||||||||||||||||||||||||||||||||||||
![]() | ![]() |
![]() | ![]() | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ![]() | ![]() |
Neben dem Level und der eigentlichen Mitteilung enthält eine Logmeldung ausserdem einen Zeitstempel, den laufenden Thread sowie die absendende Klasse und Methode. Die Ausgabe einer Logmeldung hat folgendes Format: Level (Uhrzeit) Thread Klasse.Methode: Mitteilung Uhrzeit, Thread und Klasse werden automatisch generiert. Leider gibt es in Java keine Möglichkeit die umgebende Methode zu ermitteln, so dass diese immer von Hand angegeben werden muß. Erzeugen von Logmeldungen
Kommen wir zum eigentlichen Erzeugen einer Meldung. Dies sollte
immer mit Hilfe eines
Der Selbstbezug auf die Klasse beim Erstellen des
Beispiel 1 zeigt drei typische Aufrufe
der
Dieser Aufruf ist durch die Abfrage von
Im Prinzip ist die Ausgabe des Methodenaufrufs (Zeilen 12-16)
völlig identisch. Sie enthält jedoch einen zusätzlichen Kniff: Der
Wert des Parameters
Konfiguration des Logging Systems
Betrachten wir als nächstes die Konfiguration des Logging
Systems. Was passiert eigentlich mit den generierten Meldungen? Es
würde an dieser Stelle zu weit führen, die mehrstufigen Filter im
einzelnen zu erläutern. Details hierzu finden Sie in der
API Referenz zur
Mit der Version 0.98 der qflib wurde im
Die folgenden Beispiele illustrieren die typischen Anwendungsfälle
und erläutern die Grundlagen, auf denen
Am einfachsten ist die Ausgabe auf
Das Erstellen einer Logdatei geschieht am einfachsten mittels der
Methode
Zeile 22 zeigt, wie die Verbindung mit dem Logserver qflog hergestellt werden
kann. Hierzu finden Sie die Details in der API Referenz zu
Vor dem Beenden des Programms ist es sinnvoll, das Logging sauber
zu beenden (Zeilen 31-33). Zunächst wird mit Hilfe von
Einstellen der
|
|
Beispiel 3: Einstellen der level für die
Logger |
Beispiel 3 erläutert zwei der
Möglichkeiten, die Generierung der Meldungen zu konfigurieren:
Durch direkte Angabe der Level im Quellcode und über die
Kommandozeile. In Zeile 12 wird zunächst der Level für alle
Klassen auf Log.MSGDETAIL
angehoben. Zeile 13
beschränkt die Meldungen aus der qflib auf
Fehlermeldungen. Zeilen 14 und 15 erlauben den Klassen aus
mypackage
Meldungen bis zum Level
Log.MTD
, für die Klasse
mypackage.NewClass
sogar bis
Log.DBGDETAIL
. Wichtig ist der Punkt ('.') am Ende
der Packageangabe in Zeilen 13 und 14. Die Reihenfolge dieser
Aufrufe ist übrigens völlig unerheblich.
Diese Methode ist wenig elegant, da Änderungen an den
Einstellungen nur über eine Anpassung des Programmcodes und
Neucompilierung erfolgen können. Besser ist es, die Einstellungen
in eine Property
Datei zu stellen, diese beim
Programmstart zu laden und die Properties
direkt an
Logger.setLogLevels zu übergeben.
Des weiteren kann der ArgsParser aus dem de.qfs.lib.util
Package der qflib
verwendet werden, um die Einstellungen beim Aufruf des Programms
über die Kommandozeile vorzunehmen. Zeilen 17-23 demonstrieren den
Einsatz des ArgsParsers
. Den zu Zeilen 12-15
identischen Effekt erzielt man dann mit einem Aufruf von
|
Am komfortabelsten ist der Einsatz des Logservers qflog, mit dessen Hilfe die Einstellungen über eine grafische Oberfläche selbst noch zur Laufzeit des Programms vorgenommen werden können. Was von Ihrer Seite für seinen Einsatz zu tun ist, wurde bereits im Beispiel 2 gezeigt. Genaueres zu Installation und Bedienung von qflog finden Sie im qflog Handbuch.
Das Logfenster von qflog läßt sich auch direkt in Ihr Programm integrieren, und zwar sehr einfach, wie das folgende Beispiel zeigt:
|
Beispiel 4: Einbinden der LogView
Komponente |
In Zeile 12 wird die LogView
Komponente initialisiert
und damit ist auch schon alles getan. Das Öffnen des Logfensters
wie in Zeile 13 werden Sie in einer echten Anwendung vermutlich
nicht generell beim Programmstart durchführen wollen, sondern
z.B. von einem Menü aus aufrufen.
Ein Applet zu schreiben, das in allen gängigen Browsern läuft ist ungefähr so schwierig, wie eine interessante Webseite zu designen, die überall gleich aussieht. Es gibt einige versteckte Inkompatibilitäten zwischen den VM Implementationen im Netscape Navigator, Microsofts Internet Explorer und dem Java Plugin von SUN, das zudem noch in Versionen von 1.1 bis 1.3 verfügbar ist.
Ein weiteres Problem ist die Sandbox, die die Möglichkeiten eines Applets aus Sicherheitsgründen einschränkt. Ein signiertes Applet kann zwar aus der Sandbox ausbrechen, aber das Signieren ist nicht gerade einfach und natürlich ist das Vorgehen für jede VM anders.
All das macht das Schreiben und Debuggen von Applets nicht einfacher, so dass Logging eine große Hilfe wäre. Leider litt auch die qflib unter diesen Problemen (und leidet z.T. immer noch), aber wir haben mit Version 0.97.0 versucht, Lösungen zu finden.
Das größte Problem bestand darin, dass Microsoft ihren Internet
Explorer bis vor kurzem ohne RMI Unterstützung ausgeliefert
haben. Da es eine indirekte RMI-Abhängigkeit in der
Logger
Klasse gab, war es nicht möglich, das
de.qfs.lib.log
Package in einem Applet zu nutzen, das im Internet
Explorer laufen sollte, selbst wenn man Logmeldungen nur auf die
Java Konsole ausgeben wollte. In Version 0.97.0 sind daher alle
RMI-abhängigen Klassen aus dem de.qfs.lib.log
Package entfernt
worden.
Trotzdem sind die RMI Klassen nötig um Verbindung zu qflog aufnehmen zu können. Zum Glück stellen Microsoft wenigstens ein Paket zum Herunterladen auf ihrer Java Resources Seite zur Verfügung, mit dessen Hilfe sich die RMI Funktionalität im Internet Explorer nachrüsten läßt. Es reicht aus, dieses Paket auf dem Entwicklungsrechner zu installieren, für den späteren Einsatz eines Applets ist es nicht erforderlich.
Das nächste Problem unter dem qflib leidet ist die Einschränkung
der Kommunikation über das Netzwerk durch die Sandbox. Ein
unsigniertes Applet darf lediglich Verbindungen zu dem Rechner
aufnehmen, von dem es heruntergeladen wurde und es darf nicht
selbst auf Verbindungen von aussen warten. Dadurch muss qflog
auf dem Rechner gestartet werden, auf dem der Webserver für die
Applets liegt und RMI Callbacks, die für die Kontrolle der Level
der Logger
im Applet nötig wären, funktionieren
nicht. Letzteres gilt allerdings nicht für den Internet Explorer,
sofern die RMI Klassen installiert sind, der einen Workaround
für diesen Zweck implementiert hat. Trotzdem planen wir für die
Zukunft einen alternativen Polling Mechanismus, der nicht mehr von
Callbacks abhängig sein wird.
Es folgt ein Beispiel Applet, das alles Nötige beinhaltet, um Logging wenigstens so weit wie möglich zu nutzen:
|
Beispiel 1: "Hello world" Applet |
Wie Sie in Zeile 10 sehen, dürfen Sie keine RMI-abhängigen
Klassen direkt importieren, da sonst die Initialisierung des
Applets mit einer ClassNotFoundException
scheitert,
wenn das Applet in einem Internet Explorer ohne RMI
läuft. Stattdessen müssen Sie beim Aufruf den vollen Klassennamen
wie in den Zeilen 42 und 60 verwenden. Dadurch kann die
ClassNotFoundException
abgefangen und ohne Gefahr
ignoriert werden.
Der Rest des Applets ist ziemlich offensichtlich und enthält keine
neuen Konzepte. Ein Blick auf die Zeilen 34-38 und die
setLogLevels
Methode ab Zeile 82 kann dennoch ganz
interessant sein. Sie demonstrieren eine Möglichkeit, wie man den
Ausgabelevel für die Java Konsole und die initialen Level der
Logger
mittels Applet Parametern festlegen kann. Das
folgende HTML Beispiel macht hiervon Gebrauch (Zeilen 11-13):
|
Beispiel 2: HTML Seite für das "Hello world" Applet |
de.qfs.lib.util
Im Folgenden wollen wir den Einsatz einiger wichtiger Klassen aus
dem de.qfs.lib.util
Package anhand
von Beispielen erläutern.
ArgsParser
Eine immer wiederkehrende Aufgabenstellung ist das Auswerten von
Optionen, die einem Programm auf der Kommandozeile übergeben
werden. Mit dem ArgsParser
ist es
sehr einfach möglich, festzulegen, welche Optionen zugelassen
sind und welche davon Parameter erlauben oder benötigen. Nach der
Auswertung stellt der ArgsParser
die Optionen in
einer Hashtable
zur Verfügung.
Darüber hinaus ist es möglich, weitere Optionen aus einer Property Datei zu lesen, mehrmaliges Auftreten der gleichen Option mit verschiedenen Parametern auszuwerten und beliebige ähnliche Optionen anhand eines simplen Wildcard Mechanismus zuzulassen.
Das folgende Beispiel zeigt den Einsatz eines
ArgsParsers
für ein Programm, das einen Aufruf der
Form
|
erwartet, d.h. mit den Optionen version
,
dir
und option
, wobei dir
und option
Parameter erwarten und option
mehrfach auftreten darf. Darüber hinaus soll die Konfiguration des
Logging Systems über Optionen, die mit log-
beginnen
möglich sein (siehe auch Beispiel 3 des
de.qfs.lib.log
Packages). Nach den Optionen wird die Angabe eines
Dateinamens erwartet.
|
Beispiel 1: Kommandozeile mit Hilfe eines
ArgsParsers auswerten |
Der Aufruf
|
führt im Beispiel 1 dazu, dass
filename
den Wert "myfile"
annimmt und
die Hashtable
options
wie folgt
aufgebaut ist:
Key | Value |
---|---|
"dir" |
"/home" |
"option" |
["opt1", "opt2"] |
Aufbauend auf dem ArgsParser
wurde mit Version 0.98
die neue Klasse LogSetup
eingeführt, die diverse
Argumente auswertet und das Logging entsprechend konfiguriert. So
ist es z.B. möglich, diverse Parameter der Log
Klasse
anzugeben (Ausgabelevel etc.), ebenso wie die Level der
Logger
. Ausgaben lassen sich in ein oder mehrere
Dateien umleiten, die Verbindung mit dem Logserver qflog läßt
sich herstellen und sogar die LogView
Komponente des
Logservers direkt in die Anwendung einbinden.
Die genauen Angaben über die Optionen und deren Bedeutung
entnehmen Sie bitte der API
Referenz zu LogSetup
. Das folgende
Beispiel zeigt, wie einfach es ist, LogSetup
in Ihre
Anwendung einzubinden:
|
Beispiel 2: Einbinden der LogSetup Klasse
|
MapResourceBundle
Java bietet mit dem ResourceBundle
Mechanismus
eine weitreichende Unterstützung von länderspezifischer
Lokalisierung. Das MapResourceBundle
erweitert diesen
um einige nützliche Funktionen:
jar
ArchivenExceptions
beim Abfragen von
ResourcenIcons
|
Beispiel 3: Lokalisierung mit dem
MapResourceBundle |
In Zeile 12 wird das MapResourceBundle
zunächst mit
den Properties der qflib bestückt. Anschließend (Zeile 15)
werden eigene Properties aus mypackage
hinzugefügt,
die durchaus Werte aus der qflib überschreiben können, um diese
an das eigene Programm anzupassen. Die übergebenen Klassen dienen
zum Auffinden der Property Dateien in jar
Archiven. Sie müssen so gewählt sein, dass sie im selben Archiv
liegen wie die Property Datei.
Das so initialisierte MapResourceBundle
kann nun zum
Beispiel an die Message
Klasse aus
dem de.qfs.lib.gui
Package zur Ausgabe
von lokalisierten Fehlerdialogen weitergereicht werden.
Zeile 21 demonstriert die Abfrage eines Wertes aus den Properties,
bei der der Defaultwert angegeben wird, für den Fall, dass
der Schlüssel des Wertes nicht vorhanden ist. Das vereinfacht die
Handhabung im Vergleich zu Exceptions
erheblich.
Damit die Abfrage des Icons
(Zeile 22) funktioniert,
muß in mypackage/resources/myproperties
dem Schlüssel
"myicons.arrow"
der Pfad der Grafikdatei mit dem
entsprechenden Icon zugeordnet sein, zum Beispiel
"/mypackage/myicons/arrow.gif".
de.qfs.lib.gui
Das de.qfs.lib.gui
Package enthält
unter anderem eine Erweiterung der Swing JTable
um
Fähigkeiten zur Sortierung und zum Filtern von Zeilen. Obwohl dies
ein sehr komplexer Mechanismus ist, ist das Interface mit dem sich
der Anwender auseinandersetzen muss recht einfach, da die
Defaulteinstellungen für den typischen Anwendungsfall ausreichen.
|
Beispiel 1: Verwendung eines
SortedTableHelpers um eine Tabelle zu
sortieren |
Beispiel 1 zeigt, wie Sie eine Tabelle mit
der Standardfunktionalität zur Sortierung erzeugen. Diese hat
keinen Filter, sortiert wird in Abhängigkeit der Klasse von
Objekten einer Spalte, wie sie von
TableModel.getColumnClass
zurückgeliefert
wird. Hierfür ist der DefaultTableModelSorter
zuständig.
Ein komplexeres Demo, das auch einen Filter implementiert, ist als
SortedTable.java
im demo
Verzeichnis enthalten. Wenn Sie es kompilieren und starten,
erhalten Sie ein Fenster mit einer Tabelle, in der Sie die
verschiedenen Funktionen ausprobieren können. Die Tabelle erlaubt
Mehrfachselektion von Zeilen, so dass Sie den Effekt der
Sortierung auf die Selektion sehen können.
Die Spalte für die Sortierung wird durch einfachen Klick in den Spaltenkopf bestimmt. Ein weiterer Klick in den selben Kopf kehrt die Sortierrichtung um. Ein kleiner Pfeil im Spaltenkopf zeigt die aktuelle Sortierung an. Des weiteren können Sie mit einem Doppelklick in den Spaltenkopf die Spalte auf die Breite anpassen, die zur Anzeige für die aktuell sichtbaren Zellen dieser Spalte benötigt wird.
Eine sortierte Tabelle behält beim Umsortieren die Selektion ihrer
Zeilen bei, wie Sie leicht nachvollziehen können indem Sie ein
paar Zeilen selektieren und dann die Sortierung ändern. Sollten
Sie das ListSelectionModel
für die Zeilen der Tabelle
ändern, nachdem Sie die Sortierung aktiviert haben, müssen Sie
helper.saveSelection(true)
aufrufen, um diesen Effekt
beizubehalten.
Mit Hilfe der ComboBox oben im Fenster können Sie zwischen verschiedenen Filtereinstellungen wählen.
Es gibt einen wichtigen Punkt bei der Implementierung einer
sortierten Tabelle dessen Sie sich bewusst sein sollten: Das
TableModel
das die Tabelle sieht ist nicht mehr das
original Model mit dem sie erzeugt wurde, sondern ein FilteredAndSortedTableModel
das zwischen
die Tabelle und das Model geschoben wird. Da die Sortierung und
Filterung von diesem FilteredAndSortedTableModel
bestimmt werden, ohne die Daten im original Model zu ändern,
entsprechen Zeilennummern, die von der Tabelle geliefert werden
(z.B. bei getSelectedRows()
) nicht mehr den
Zeilennummern im original Model. Zum übersetzen müssen Sie
helper.getSortedTableModel().getMappedRow(row)
verwenden. Mit Hilfe des
Dump Buttons im Demo können Sie diesen Effekt
nachvollziehen, da damit die Indizes der selektierten Zeilen und
deren Umsetzung auf die original Model Koordinaten auf
System.err
ausgegeben werden.
Copyright © 2003 Quality First Software GmbH. Diese Seiten befolgen w3c Standards und sind für Auflösungen ab 640x480 aufwärts ausgelegt. Sie wurden in aktuellen Browsern mit CSS Stylesheets getestet. |