2007-12-29

MD5 in Java


MD5 (Message-Digest Algorithm 5) ist eine weit verbreitete, von Ronald L. Rivest entwickelte kryptographische Hash-Funktion. Sie erzeugt einen 128-Bit-Hashwert, der meistens als Folge von 16 (zweistelligen) Hexadezimalzahlen angegeben wird. Solche Werte (Hashes oder message digests) werden unter anderem zur Integritätsprüfung von Dateien eingesetzt.
Erwartungsgemäß gibt es Implementierungen für unzählige Sprachen. Java bietet seit Version 1.4 nativen Support in Form der Klasse java.security.MessageDigest .
Ich habe eine kleine Wrapperklasse geschrieben, die das Ermitteln von Digests ermöglicht. Um sie einzusetzen, müssen Sie die Klasse nur instantiieren und getChecksum() aufrufen. Da diese Methode ein byte-Array liefert, können Sie mittels toString() noch einen schön lesbaren String erzeugen.

2007-12-22

Fullscreen-Plug-in für Eclipse


Bei der Arbeit mit einer IDE kann man eigentlich nie genug Platz auf dem Bildschirm haben. Gerade Eclipse bietet unzählige Sichten an, die dem Entwickler beim Programmieren helfen sollen. Mit Hilfe des Eclipse Full Screen Plugins können Sie die Taskleiste sowie die Fenstertitelzeile ausblenden und Eclipse in einem Vollbildschirm-Modus betreiben. Leider steht das Plug-in derzeit nur in einer Version für Windows zur Verfügung.

2007-12-18

Defensives Programmieren


In meinem heutigen Eintrag möchte ich mich mit dem Thema Defensives Programmieren beschäftigen. Wenn Sie den Begriff (oder seine englische Entsprechung defensive programming) in das Eingabefeld der Suchmaschine Ihres Vertrauens eintragen, werden Sie sehr schnell entsprechende Wikipedia-Seiten finden. Die momentan aktuelle (nachgeschlagen am 18.12.2007) deutsche Fassung enthält eine aus meiner Sicht leider nur eingeschränkt tragfähige (weil unvollständige) Definition. Der Eintrag beschreibt nämlich (völlig zu Recht), was aus fachlicher Sicht zu tun ist, um angemessen auf Fehleingaben oder unvorhergesehene Ereignisse zu reagieren. Er lässt technische Belange aber nahezu vollständig außen vor.
Defensive Programmierung lässt sich jedoch nicht auf Bevor Du einen Drucker löscht, prüfe, ob er dem System überhaupt noch bekannt ist. reduzieren. Neben dieser fachlich motivierten Robustheit spielt die Qualität des Quelltextes eine entscheidende Rolle. Sie äußert sich unter anderem in seiner kompromisslosen Toleranz gegenüber Fehlern von innen und außen, getreu dem Motto Traue Nichts und Niemandem. Diesem Aspekt trägt die englische Fassung übrigens viel mehr Rechnung.
Welche Auswirkungen hat ein solcher Programmierstil? Flapsig ausgedrückt könnte man sagen, Sie müssen die Paranoia zum Maß aller Dinge machen. Da jeder Methodenaufruf fehlschlagen oder eine Ausnahme werfen kann, ist es unabdingbar, nicht nur sauber alle Rückgabewerte zu verarbeiten, sondern auch mit unerwarteten Exceptions zu rechnen. Denken Sie daran, dass in Java nicht nur dann eine Ausnahme geworfen werden kann, wenn dies mit throws explizit gekennzeichnet wird. Bitte sehen Sie sich die folgende kleine Klasse an.
   
package com.thomaskuenneth.demo;
   
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
   
public class BadFileDemo {
   
public static void main(String[] args) {
File f = new File(System.getProperty("user.home"), "BadFileDemo.txt");
try {
FileOutputStream fos = new FileOutputStream(f);
fos.write("Test\n".getBytes());
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
   
Auf den ersten Blick scheint es sich um ein recht ordentlich geschriebenes Stück Software zu handeln. Oder? Lassen Sie uns sehen, wie man es ein bisschen besser machen kann…
   
package com.thomaskuenneth.demo;
   
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
   
public class BetterFileDemo {
   
public static void main(String[] args) throws IOException {
File f = new File(System.getProperty("user.home", "."),
"BadFileDemo.txt");
if ((f.exists() == true) && (f.isDirectory() == true)) {
throw new IOException(f.getAbsolutePath()
+ " exists and is a directory");
}
FileOutputStream fos = null;
try {
fos = new FileOutputStream(f);
fos.write("Test\n".getBytes());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
fos = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
   
Haben Sie die Unterschiede bemerkt? Oder, anders gefragt, was sind denn die gröbsten Schnitzer im ersten Programm? Diese zweite Klasse wirkt zugegeben um einiges länger. Schuld daran ist der neue finally {}-Block, der um einiges sorgfältiger beim Schließen des Ausgabestroms zu Werke geht. Falls Sie sich fragen, ob der Aufwand nötig ist… Aber logo. Warum sollte diese Aktion nicht fehlschlagen können? Außerdem wird so ein großes Manko beseitigt. Wenn im ersten Programm während des Schreibens in den Strom ein Fehler auftritt, wird er nicht geschlossen. Nicht schön, nicht wahr? :-)
Ein weiterer, subtiler Schutz ist übrigens noch dazu gekommen. Finden Sie ihn?

2007-12-11

Vom sicheren Umgang mit Eclipse-Plug-ins


Dass sich der Funktionsumfang von Eclipse durch Plug-ins erweitern lässt, wird sehr oft als eine Schlüsselfunktion der IDE angesehen. Und mit Hilfe des Software Updates-Mechanismus geht das Ganze ja auch sehr bequem und komfortabel über die Bühne. Zumindest, wenn das Plug-in über eine Remote Site installiert werden kann.
Nun gibt es aber (immer noch) sehr viele (sehr gute) Plug-ins, die als .zip-Archiv verteilt werden. Nach dem Entpacken landen sie dann (etwas vorschnell) im Eclipse-Installationsverzeichnis. Mein Rat ist, sie stattdessen in einem eigenen Verzeichnis abzulegen. Gründe hierfür gibt es zahlreiche. Beispielsweise mischen Sie auf diese Weise nicht die Eclipse-Distribution mit Plug-ins von Drittanbietern. Wenn sie die IDE neu einrichten müssen, bleiben die zusätzlichen Plug-ins davon unberührt.
Bevor Sie die neue "Modulablage" Eclipse bekannt machen können, müssen Sie sie von Hand anlegen und präparieren. Legen Sie hierzu bitte ein Verzeichnis mit beliebigen Namen an, beispielsweise C:\Programme\Eclipse Plug-ins. In diesem erzeugen Sie bitte das Unterverzeichnis eclipse, das wiederum die beiden Verzeichnisse features und plugins enthält. In einem letzten Schritt legen Sie die leere Datei .eclipseextension an.
Wählen Sie nun Software Updates • Manage Configuration, woraufhin sich das Fenster Product Configuration öffnet. Klicken Sie anschließend mit der rechten Maustaste die Wurzel des Konfigurationsbaumes an und wählen dann Add • Extension Location.
Mit Hilfe der Dateiauswahlbox navigieren Sie zu dem Verzeichnis, das die Plug-ins aufnehmen soll. Bevor Sie der IDE den gewünschten Neustart gestatten, kopieren Sie das Plug-in in das neue Verzeichnis.

2007-11-29

JavaBeans (Teil 1)

Mit diesem Eintrag möchte ich eine lose Serie von Artikeln über JavaBeans beginnen. JavaBeans, oder kurz: Beans, sind (mit dem Ziel der Wiederverwendung entwickelte) Softwarekomponenten. Die Idee ist, kleine Einheiten (Komponenten) mit einem geeigneten Werkzeug zu einem größeren Ganzen (Applets und Anwendungen) zu kombinieren. Natürlich sind Komponenten keine Java-Erfindung. Andere Plattformen haben ihre eigene Komponentenarchitektur hervorgebracht. Ein äußerst erfolgreiches Beispiel ist das Component Object Model von Microsoft, das über viele Jahre der Standard für die Kommunikation über Anwendungsgrenzen hinweg unter Windows war, und selbst jetzt noch häufiger eingesetzt wird, als es sich der Betriebssystemhersteller vermutlich wünscht.
JavaBeans ist also eine Komponententechnologie für Java. Sie wird in praktisch allen modernen Anwendungen eingesetzt, ohne dass sich die Entwickler besonders darum kümmern. Ein Beispiel hierfür ist der selbstverständliche Umgang mit Gettern und Settern, aber auch das Auswählen von Swing-Komponenten aus den Paletten eines visuellen Editors. In den folgenden Teilen dieser kleinen Serie möchte ich Ihnen einige Einblicke in die Funktionsweise und die Implementierung von JavaBeans geben. Beispielsweise zeige ich Ihnen, wie Sie eigene visuelle Komponenten entwickeln und in die Palette eines GUI-Builders integrieren.
All dies möchte ich am Beispiel einer kleinen Komponente demonstrieren, die Sie im Screenshot etwas weiter oben sehen. Haben Sie eine Idee, um was es sich hierbei handelt?

Update 25.12.14 Screenshot entfernt

2007-11-28

Vereinfachte Verteilung mit One-JAR

Es ist allgemein bekannt, dass man auf sehr vielen Plattformen eine Java-Anwendung durch Doppelklick auf die zugehörige .jar-Datei starten kann. Das Pendant für die Kommandozeile lautet java -jar archiv.jar. Damit dies funktioniert, muss das Archiv die Textdatei /META-INF/MANIFEST.MF enthalten. Eine ihrer Zeilen lautet
Main-Class: com.domain.package.Main
Dem Attribut Main-Class wird also ein voll qualifizierter Klassenname zugewisen. Diese Klasse enthält die wohlbekannte main()-Methode, also den Einstiegspunkt in das Programm. Zusätzliche Bibliotheken, die die Anwendung benötigt, können ebenfalls in das oben genannte Manifest eingetragen werden. Hierfür wird das Attribut Class-Path verwendet. Es enthält eine durch Leerzeichen getrennte Liste von (das ist wahrscheinlich weniger bekannt!) URLs (Verzeichnisse und Archive), die nach Klassen durchsucht werden sollen. Diese dürfen sich aber nicht innerhalb des Hauptarchivs befinden. Der Versuch, .jar-Archive zu schachteln, führt also zu nicht funktionsfähigen Programmen.
Man kann natürlich die Frage stellen, ob das Schachteln von Archiven überhaupt nötig ist. Web Start-Anwendungen beispielsweise profitieren eher von der Aufteilung in unterschiedliche .jars, weil Basisbibliotheken u. U. schon einmal herunter geladen wurden und damit schon zur Verfügung stehen. Praktisch könnte eine einzelne, leicht handhabbare Datei hingegen sein, wenn die Anwendung beispielsweise auf einem USB-Stick eingesetzt werden soll. Denn beim Kopieren besteht die Gefahr, eine benötigte Bibliothek zu übersehen und zu vergessen. Dies würde dazu führen, dass Sie das Programm nicht verwenden können.
One-JAR von Simon Tuffs kann Programme und ihre Bibliotheken zu einem einzigen Archiv zusammen fassen. Das open source-Projekt setzt hierzu auf einen eigenen ClassLoader, der das Laden von Klassen und Ressourcen aus verschachtelten Archiven beherrscht. Damit der neue Klassenlader greift, muss das Manifest einer Anwendung so abgeändert werden, dass das Main-Class-Attribut auf eine von One-JAR zur Verfügung gestellte Bootstrap-Klasse zeigt. Ferner werden Bibliotheken in einem eigenen lib-Verzeichnis erwartet. Das Archiv mit der ursprünglichen Hauptklassen muss unter main abgelegt werden. Um dem Programmierer die Aufgabe so leicht wie möglich zu machen, stellt Simon Tuffs auch eine Ant-Integration zur Verfügung