Java-Anwendung sauber beenden mit addShutdownHook

Bei einfachen Java-Anwendungen macht man sich typischerweise wenig Gedanken um das saubere Beenden aller Prozesse. Man geht davon aus, dass der Nutzer weiß, was er tut, wenn er auf Beenden klickt und fragt zur Not vorher nochmal nach, ob er tatsächlich fortfahren will. Anders sieht das jedoch aus, wenn man mehrere Threads verwaltet - wie das zum Beispiel bei Serveranwendungen der Fall ist. Dann möchte man vor dem tatsächlichen Beenden lieber doch noch die einen oder anderen Aufräumarbeiten durchführen - zum Beispiel Logdateien flushen, laufende Serveranfragen beantworten oder temporäre Dateien wegräumen.

Die JVM-Runtime bietet für solche Fälle die Möglichkeit, sogenannte Shutdown-Hooks via Runtime.getRuntime().addShutdownHook() zu registrieren. Wenn die JVM beendet wird, werden die registrierten Hooks ausgeführt (im Grunde sind es Threads, deren run()-Methode aufgerufen wird).

Im folgenden Beispiel habe ich mal eine kleine Vorlage gebastelt, in der man sieht, wie man das ganze verwenden kann. In der Methode "startupMain()" implementiert man alle Initialisierungen, die beim Programmstart ausgeführt werden sollen, in der Methode "runMain()" führt man dann die tatsächliche Anwendung aus, während in der Methode "shutdownMain()" notwendige Deinitialisierungen durchgeführt werden können.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public class Main extends Object implements Runnable {

    // singleton instance
    protected static Main fInstance = null;

    static {
        // create singleton instance
        fInstance = new Main();
    }

    // prevent external instantiation
    protected Main() {
        super();
    }

    public static Main getInstance() {
        return fInstance;
    }

    public static void main(String[] args) {
        Main lMain = Main.getInstance();

        // call startup code
        lMain.startupMain(args);

        // register shutdown code
        Runtime.getRuntime().addShutdownHook(new Thread(lMain));
       
        // call main code
        lMain.runMain();
    }

    @Override
    public void run() {
        // call shutdown code
        shutdownMain();
    }    

    public synchronized void startupMain(String[] aArguments) {
        // startup code
        // ...
    }

    public synchronized void shutdownMain() {
        // shutdown code
        // ...
    }

    public void runMain() {
        // main code
        // ...
    }

}

Als Test habe ich mir eine einfache Anwendung geschrieben, die beim Starten das Wort "start", während des Laufens in einer Endlosschleife das Wort "sleep" und beim Beenden das Wort "stop" schreibt. Die drei Methoden sehen dabei wie folgt aus:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    public synchronized void startupMain(String[] aArguments) {
        // startup code
        // ...
        System.out.println("start");
    }

    public synchronized void shutdownMain() {
        // shutdown code
        // ...
        System.out.println("stop");
    }

    public void runMain() {
        // main code
        // ...
        while (true) {
            System.out.println("sleep");
            try {
                Thread.sleep(1000);
            }
            catch (Exception e) {}
        }
    }

Nach dem Starten verwende ich den Linuxbefehl "kill -SIGINT <Prozess-ID>", um die Anwendung wieder zu beenden. Dabei wird vor dem tatsächlichen Beenden noch der Shutdown-Hook ausgeführt. Im folgenden kleinen Video habe ich das ganze mal demonstriert:

Wie ihr seht, kann man mit einfachen Mitteln Java-Anwendungen sauber und ordentlich beenden. Es ist übrigens auch möglich, mehrere Shutdown-Hooks zu registrieren. Da jedoch deren Ausführungsreihenfolge nicht definiert ist, ist anzuraten, nur einen Shutdown-Hook für die gesamte Anwendung zu verwenden und in diesem zur Not weiteren Cleanup-Code aufzurufen. Da der Shutdown-Hook ein Thread ist, müsst ihr euch zudem um Themen wie Threadsicherheit kümmern.

Saubere Grüße, Kenny

Simples Failover-Cluster mit Floating IP realisieren

Immer wieder kommt es vor, dass der Wunsch aufkommt, die Verfügbarkeit eines internen Dienstes zu erhöhen. Mitunter ist das das allererste Mal, dass die Beteiligten sich überhaupt mit dem Thema Clustering auseinandersetzen müssen. Leider herrscht immernoch die Meinung vor, dass Clustering ein komplexes Thema sei, das man am besten weit nach hinten schiebt - dabei wird es umso einfacher, je früher man sich darum Gedanken macht. Denn dann kann man seine Anwendungen von vorne herein darauf vorbereiten, in einem Cluster lauffähig zu sein.

An dieser Stelle würde ich gern einmal eine simple Lösung zeigen, wie es möglich ist, ohne Einsatz eines Loadbalancers ein einfaches Failover-Cluster mit einer Floating IP (auch als virtuelle IP bezeichnet) zu realisieren.

In einer einfachen Form gibt es zwei Maschinen im Netzwerk, die die gleiche Aufgabe erfüllen und sich eine gemeinsame IP-Adresse teilen. Wenn eine der beiden Maschine startet, prüft sie, ob die gemeinsame IP-Adresse bereits verwendet wird. Ist das nicht der Fall, dann nimmt sie sich die IP-Adresse. Startet nun die zweite Maschine, so bekommt diese mit, dass die IP-Adresse bereits verwendet wird und schaltet sich in einen Wartezustand. In diesem prüft sie regelmäßig, ob die IP-Adresse noch verwendet wird. Sobald das nicht mehr der Fall ist, übernimmt sie die IP-Adresse und nutzt sie selbst.

Dieses Vorgehen kann man noch entsprechend gegen fälschliche IP-Adressübernahmen absichern: Beispielsweise sollte man mehr als nur einmal prüfen, ob die IP-Adresse noch verwendet wird, bevor man sie übernimmt. Ebenso kann man sich Protokolle überlegen, damit mehr als nur zwei Knoten im Failover-Cluster existieren können (z.B. durch die Einführung einer Knotengewichtung oder durch dynamische Reihenfolgen). Durch den Einsatz von STONITH-Mechanismen kann man zudem dafür sorgen, dass Clusterknoten mit einer Fehlfunktion das Cluster nicht stören, indem man sie zur Not gewaltsam aus dem Cluster entfernt. Aber für unser simples Beispiel geht es auch erstmal ohne.

Um einen einfachen, für den Client transparenten, Failover hinzukriegen, brauchen wir unter Linux im Grunde zwei Tools: "ip" und "arping". Das ip-Tool ist standardmäßig vorhanden und wird dazu verwendet, die Floating IP an ein Netzwerkinterface zu binden (z.B. "eth0"). Das arping-Tool muss man hingegen erst installieren. Dabei ist Vorsicht geboten, denn es gibt zwei verschiedene Implementierungen, wobei uns nur die aus den iputils der Linux Foundation interessiert - denn nur diese kennt den "-U" Parameter für Unsolicited ARP Requests (auch "Gratuitous ARP Messages" oder "ARP Announcements" genannt). Sinn und Zweck dieser ARP Requests ist es, den angeschlossenen Systemen mitzuteilen, dass IP-Pakete, die an die Floating IP gerichtet werden, nun an ein anderes Gerät zu routen sind.

Die folgenden beiden Befehle sind unter Linux ausreichend, um eine IP-Adresse zu übernehmen (wobei ihr "<IP>" durch die Floating IP und "<Interface>" durch den Namen des Netzwerkinterfaces ersetzen müsst):

1
2
  sudo /bin/ip addr add <IP>/32 dev <Interface>
  sudo /usr/bin/arping -U -c 5 -q -I <Interface> <IP>

Im unten stehenden Video habe ich einmal aufgenommen, wie das PHP-Script in der Datei "~/failover.phs" die oben beschriebene Funktionalität ausführt. Beim ersten Starten prüft es, ob die Floating IP ("192.168.123.10") in Verwendung ist und übernimmt diese. Der zweite Aufruf bekommt mit, dass die Floating IP in Verwendung ist und versetzt sich in den Wartemodus. Der permanent laufende Ping rechts oben zeigt, dass trotz des Herunterfahrens des ersten Rechners die IP-Adresse weiterhin verwendbar bleibt. In den CURL-Aufruf rechts unten sieht man, dass die HTTP-Anfragen zwar über dieselbe IP-Adresse gestellt, jedoch von verschiedenen Servern beantwortet werden.

Ausfallsichere Grüße, Kenny

P.S.: Ja, mit dem gleichen Knowhow kann man auch Angriffe auf Netzwerkdienste fahren, indem man die Pakete, die an den Dienst gerichtet sind, über den eigenen Rechner umleitet.

Accounts auf Windows 7 Loginseite verstecken

Zur Einschulung meines Neffen habe ich ihm einen aufgearbeiteten Computer geschenkt. Als Sechsjähriger sollte er natürlich nur einen begrenzten Zugriff auf Systemfunktionen (Administration, Softwareinstallation, etc.) haben, was über einen eingeschränkten Account realisiert werden sollte. Gleichzeitig sollte es aber möglich sein, dass er den Rechner einschaltet kann und beim Hochfahren sofort in seinen Account eingeloggt wird. Das wiederum funktioniert nur, wenn es auf der Loginseite nur einen Account gibt, der ohne Passwort angelegt wurde. Also musste eine Lösung her, in einem eingeschränkten Account viel Administration unterbinden zu können und gleichzeitig nur einen Account auf der Windows-Loginseite zu haben.

Der erste Schritt war, den (vorhandenen, aber nicht sichtbaren) Administratoraccount in Windows 7 zu aktivieren (falls ihr einfach nur Accounts auf der Loginseite ausblenden wollt, überspringt diesen Schritt). Dazu gebt ihr in das Suchfeld des Startmenüs die Buchstaben "cmd" ein. In der Liste darüber sollte euch die Kommandozeile als Ergebnis angezeigt werden. Macht einen Rechtsklick auf den Eintrag mit der Kommandozeile und führt sie als Administrator aus. In der Kommandozeile gebt ihr dann folgenden Befehl ein:

1
net user administrator /active:yes

Nun kann man sich nämlich als Administrator am System einloggen und ihm zum Beispiel ein Passwort geben. Weiterhin kann man nun den einzuschränkenden Account ordentlich konfigurieren (z.B. die Jugendschutzoptionen aktivieren). Leider hat man nun auf der Windows-Loginseite auch den Administrator-Account, der den automatischen Login verhindert. Um diesen wieder zu verstecken, wenn er nicht gebraucht wird, können wir ein wenig Registry-Magie einsetzen.

Wir erstellen uns eine "ha.reg"-Datei mit folgendem Inhalt (falls ihr einen anderen Account ausblenden wollt, ersetzt "Administrator" durch den Namen des entsprechenden Accounts):

1
2
3
4
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList]
"Administrator"=dword:00000000

Ebenso erstellen wir uns eine "sa.reg"-Datei mit diesem Inhalt (falls ihr einen anderen Account ausblenden wollt, ersetzt auch hier "Administrator" durch den Namen des entsprechenden Accounts):

1
2
3
4
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList]
"Administrator"=dword:00000001

Dazu basteln wir uns noch zwei Batch-Dateien, einmal eine "hideAdministrator.bat" (falls ihr den Administrator-Account oben nicht aktiviert habt, müsst ihr stattdessen eine Kommandozeile wie oben beschrieben als Administrator starten und in dieser direkt "regedit ha.reg" ausführen):

1
runas /user:administrator "regedit ha.reg"

Und einmal eine "showAdministrator.bat" (falls ihr den Administrator-Account oben nicht aktiviert habt, müsst ihr stattdessen eine Kommandozeile wie oben beschrieben als Administrator starten und in dieser direkt "regedit sa.reg" ausführen):

1
runas /user:administrator "regedit sa.reg"

Wenn wir nun mit dem eingeschränkten Account eingeloggt sind und den Administrator-Account auf der Windows-Loginseite verstecken wollen, rufen wir einfach die "hideAdministrator.bat"-Datei auf (z.B. per Doppelklick). In der aufpoppenden Kommandozeile werden wir nach dem Passwort des Administrator-Accounts gefragt, das wir noch mit Enter bestätigen. Anschließend ist der Administrator-Account auf der Windows-Loginseite versteckt und beim Hochfahren loggt sich das System automatisch in den eingeschränkten Account ein.

Sollten wir nun administrative Aufgaben wahrnehmen müssen, rufen wir einfach im eingeschränkten Account die "showAdministrator.bat"-Datei auf, geben das Administrator-Passwort ein und bestätigen mit Enter. Anschließend können wir einfach den Benutzer wechseln, die administrativen Aufgaben erledigen (z.B. Updates installieren, Software installieren, Konfigurationsänderungen vornehmen, etc.), danach wieder in den eingeschränkten Account wechseln und den Administrator-Account wieder verstecken.

Versteckte Grüße, Kenny

It’s really about time: Die Pebble Time Steel Smartwatch

Vor zweieinhalb Jahren hatte ich über die original Pebble Smartwatch berichtet - damals war ich schon positiv überrascht. In der Zeit danach hat die Pebble mit Updates und der wertigeren Pebble Steel kleinere Verbesserungen erhalten.

Doch die große Neuerung gab es vor wenigen Monaten, als auf Kickstarter erst die neue Pebble Time und kurz darauf auch die Pebble Time Steel angekündigt wurde. Natürlich war ich wieder mit von der Partie und sicherte mir eins der hochwertigen Pebble Time Steel Modelle, das nun vor ein paar Tagen bei mir eintraf.

Was einem als allererstes auffällt, ist, dass es dieses Mal keinerlei Probleme mit dem Zoll gab - man bietet nun EU-friendly Shipping an, wodurch man sich den ganzen Zollkram sparen kann und die Uhr per DHL Express bis zur Haustür geliefert bekommt. Nach dem Öffnen des Päckchens sieht man gleich den nächsten Unterschied: der Versandkarton ist nicht mehr gleichzeitig die Produktverpackung. Stattdessen erhält man eine hübsch anzusehende Designverpackung.

IMG_0274 IMG_0275

Pebble Time Steel Verpackung

In dem Päckchen befinden sich dann einmal die Pebble Time Steel selbst, ein Ladekabel (das inkompatibel zu dem der original Pebble ist), die Bedienungsanleitung und Sticker. Das Ladekabel mit den Magneten wird nun nicht mehr seitlich, sondern am Gehäuseboden der Uhr angeheftet. Das bedeutet leider, dass man die Uhr nun nicht mehr am Handgelenk lassen kann, während man sie lädt (z.B. wenn man am Notebook sitzt).

IMG_0278 IMG_0277 IMG_0276

Pebble Time Steel und Ladekabel

Auch ist es ein wenig schade, dass um das Display noch so viel schwarzer Raum gelassen wird. Die Uhr würde definitiv imposanter wirken, wenn das Display an allen Seiten bis zum Rand reichen würde. Glücklicherweise relativiert sich dieses Gefühl ein wenig dadurch, dass ich ein Ziffernblatt mit schwarzem Hintergrund verwende.

IMG_0289

Ziffernblatt mit schwarzem Hintergrund

Die Steel-Variante fühlt sich wunderbar hochwertig an. Sie hat ein angenehmes Gewicht und das Metall schmiegt sich dank der leichten Wölbung unaufdringlich ans Handgelenk. Selbst in das Echtleder-Armband ist das Pebble-Logo eingeprägt. In meinen Augen ist der Aufpreis für die Pebble Time Steel gegenüber der Pebble Time gut investiert.

Das farbige E-Paper Display der Pebble Time (Steel) ist indes definitiv das wahre Highlight der Uhr. Anfangs mag die Farbwiedergabe im Vergleich zur Farbqualität von LCDs etwas blass wirken, aber daran gewöhnt man sich recht schnell. Die farbliche Unterlegung von Systemzuständen ist definitiv schön anzusehen (und im Gegensatz zu LCDs auch in der Sonne sehr gut wahrnehmbar). Besonders kräftig und klar sehen die Farben nochmals mit aktivierter Hintergrundbeleuchtung aus.

IMG_0280 IMG_0281 IMG_0282
IMG_0287 IMG_0288

Farbige Darstellungen mit und ohne Hintergrundbeleuchtung

Ein paar Dinge sind mir weiterhin aufgefallen:

  • Es gibt nun eine animierte Anzeige während des Aufladens (ein offener Pappkaffeebecher, in den von oben Kaffee gefüllt wird).
  • Es gibt nun eine Information, wenn der Akku fertig aufgeladen ist (auf den Pappkaffeebecher wird ein Trinkaufsatz gesetzt).
  • Der Menüeintrag für die Einstellungen enthält eine Batteriefüllanzeige (in 10% Schritten).
  • Apps für die original Pebble laufen ohne Änderungen durch den Entwickler auch auf der Pebble Time (Steel). Dort werden sie dann einfach weiterhin nur in schwarz/weiß angezeigt. Das gilt auch für Apps, die eine Begleit-App (a.k.a. Companion App) auf dem Smartphone benötigen.
  • Während bei der original Pebble als Dumbwatch (mit deaktiviertem Bluetooth) eine Akkuladung mehrere Wochen hielt, ist der Akku bei der Pebble Time Steel auch als Dumbwatch bereits nach ca. 7-10 Tagen leer. Das ändert sich hoffentlich noch.

Insgesamt bin ich mit der Anschaffung der Pebble Time Steel sehr zufrieden. Das Farbdisplay ist kein Muss, macht jedoch optisch durchaus etwas her und lässt originale schwarz/weiß Apps dröge und altbacken aussehen. Durch den breiten Rand zwischen Display und Rahmen ist jedoch definitiv noch Verbesserungspotential für eine dritte Pebble-Generation vorhanden.

Smarte Grüße, Kenny

Interview bei Spreadaudio

An dieser Stelle wollte ich nur kurz darauf hinweisen, dass ich mit @SchneiderAaron von @spreadaudio ein Interview geführt habe, das nun veröffentlicht worden ist. In dem Gespräch zum Thema IT-Sicherheit geht es einmal querbeet von sicheren Passwörtern, über Virenscanner und Firewalls bis hin zur Ende-zu-Ende-Verschlüsselung.

Wer mal reinhören will, findet auf der Webseite von Spreadaudio eine Aufzeichnung des gesamten Interviews inklusive einer vollständigen Transkription und einer Datei mit weiteren Begriffserklärungen. :)

Update:
Leider stellt Spreadaudio seinen Betrieb ein. Das Interview findet man noch als Dreiteiler hier (Teil 1), hier (Teil 2) und hier (Teil 3).

Interviewte Grüße, Kenny

Seite 3 von 86« Erste...234...Letzte »