Donnerstag, 22. Dezember 2011

JAXB und HashMaps

Die Technik ist zwar schon älter, aber vielleicht ist folgender Tipp trotzdem nützlich – zumal die entsprechende JAXB-Eigenschaft nicht sonderlich gut dokumentiert ist.

Wenn man Schlüssel-Wert-Paare aus einer XML-Datei in eine HashMap einlesen soll, ist das recht einfach, sofern man Einfluss auf die Struktur des XML-Dokuments hat und dieses in etwa so aussehen kann:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<meineEntitaet>
<paarliste>
<entry>
<key>MeinSchlüssel</key>
<value>MeinWert</value>
</entry>
<entry>
<key>...</key>
<value>...</value>
</entry>
...
</paarliste>
</meineEntitaet>

Die zugehörige Klasse muss dann wie folgt aufgebaut und mit JAXB-Annotationen versehen sein:
import java.util.*;
import javax.xml.bind.annotation.*;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class MeineEntitaet {

@XmlElementWrapper(name="paarliste")
private Map<String,String> map
= new HashMap<String,String>();

public Map<String,String> getMap() {
return map;
}

public void setMap(Map<String,String> map) {
this.map = map;
}
}

Die XML-Datei lässt sich dann mit folgender Anweisung in ein Objekt einlesen:
MeineEntitaet obj =
JAXB.unmarshal(
new File("beispiel.xml"),
MeineEntitaet.class);
System.out.println( obj.getMap() );

Genauso einfach lässt sich natürlich auch eine HashMap als XML schreiben:
MeineEntitaet obj = new MeineEntitaet();
obj.getMap().put("MeinSchlüssel", "MeinWert");
// JAXB.marshal(obj, System.out);
JAXB.marshal(obj, new File("beispiel.xml"));

Während man den XML-Element-Namen der Schlüssel-Wert-Paare-Liste mit der Annotation @XmlElementWrapper konfigurieren kann, sind die Elemente entry, key und value fest benannt. Um auch diese Namen zu verändern, muss man einen eigenen XmlAdapter implementieren.

Montag, 28. November 2011

Message Driven Beans anhalten und starten

Message Driven Beans (MDBs) werden meistens schon aktiv (d.h. vom Container aufgerufen, wenn über JMS Nachrichten für die Bean vorhanden sind), während das Deployment der Anwendung noch läuft. Das ist normalerweise unkritisch, aber es gibt Situationen, in denen man sicherstellen möchte/muss, dass die MDBs erst nach vollständigem Deployment (oder irgend einem anderen definierten Zeitpunkt) aktiv werden.

Nahezu jedes Messaging-System (JMS-Implementierung) bietet die Möglichkeit, über produktspezifische API oder externe Kommandos eine Queue anzuhalten und später wieder zu starten. Das betrifft aber die komplette Queue, d.h. es ist dann auch nicht mehr möglich, Nachrichten in die Queue zu schreiben.

Bei einigen Messaging-Systeme kann man daher via JMX die MBean einer MDB ermitteln und damit tatsächlich nur die MDB anhalten – also die Zustellung aus der Queue unterbinden. Das Schreiben in die Queue wäre dann immer noch möglich. (Das Problem, wie damit die MDB gleich zu Beginn des Deployments gestoppt wird, lassen wir mal außen vor.)

Leider sind beide Lösungen produktspezifisch. Eine portable Lösung ist bis inkl. Java EE 6 für Message Driven Beans nicht vorgesehen. Wie könnte eine selbst gebaute, portable Lösung aussehen?

Java SE 5 hat im Paket java.util.concurrent viele neue Klassen rund um Thread-Synchronisation und Sperren in die Java-Welt gebracht. Für unsere Zwecke ist ein CountDownLatch geeignet:

import java.util.concurrent.CountDownLatch;

@Singleton
public class AppStatus {

private static final CountDownLatch startSignal
= new CountDownLatch(1);

public void waitForAppInitialized() {
try {
startSignal.await();
} catch (InterruptedException e) {
throw new RuntimeException(
"Fehler beim Warten auf Sperren-Freigabe", e);
}
}

public void setAppIsInitialized() {
startSignal.countDown();
}

public boolean isAppInitialized() {
return (startSignal.getCount() == 0L);
}
}

Der CountDownLatch ist zu Beginn gesperrt. Zur Freigabe muss die Anwendung zu einem geeigneten Zeitpunkt die Methode setAppIsInitialized() aufrufen, beispielsweise in einem ServletContextListener oder in einem EJB-Timer.

Die zu blockierende MDB wartet dann bei jedem Aufruf zunächst darauf, ob die Sperre schon freigegeben wurde:

@MessageDriven
public class StartbareMDB implements MessageListener {

@EJB
private AppStatus status;

public void onMessage(Message msg) {

status.waitForAppInitialized();

// ... der eigentliche MDB-Code ...
}
}
Eine einfache, funktionierende Lösung mit Java-Bordmitteln.

Nachteil dieser Lösung ist, dass hier Threads des Containers blockiert werden. Man muss aufpassen, dass die Maximalzahl der blockierten MDB-Threads den Threadpool nicht überfordert (was ein Grund ist, warum man in Java EE-Containern nicht mit Threads herumspielen soll).

Außerdem ist der Performanceverlust nicht riesig, aber messbar. Für Höchstlastsysteme ist das also evtl. nicht geeignet. Zumal dort oft Clustering zum Einsatz kommt – und obige Lösung ist nur clusterfähig, wenn man sicherstellen kann, dass die Freigabe-Methode auf jedem Cluster-Knoten aufgerufen wird.

Als weitere (bewusste) Einschränkung ist zu beachten, dass der CountDownLatch nur einmalig nutzbar ist, er dient also wirklich nur als Start-Signal. Wenn man Message Driven Beans beliebig anhalten und starten möchte, muss man andere Sperren verwenden.

Fazit: Die hier vorgestellte Lösung funktioniert in vielen praktischen Situationen gut. Aber gibt es andere Ideen / Lösungen, die ähnlich einfach zu realisieren sind, die gezeigten Einschränkungen aber nicht aufweisen? Oder müssen wir auf Java EE 7 (oder eher 8) warten?

Donnerstag, 24. November 2011

Java für Mac OS X 10.7 "Lion"

Da Apple vor kurzem Java-Updates für Mac OS X veröffentlicht hat, gibt es an dieser Stelle eine kleine Erinnerung an die wichtige Änderung, die mit Mac OS X 10.7 "Lion" eingeführt wurde: Im Gegensatz zu allen anderen Mac OS X-Versionen davor (*) ist keine Java-Laufzeitumgebung mehr vorinstalliert.
(* Von der 10.0-Public Beta, die wir uns 2000 von der Apple Expo Paris mitgenommen haben, mal abgesehen.)

Beim ersten Aufruf einer Java-Anwendung erhält man einen Hinweis, dass die Java-Runtime benötigt wird. Bestätigt man dies, wird Java SE 6 heruntergeladen und installiert. Danach wird die ursprünglich aufgerufene Java-Anwendung gestartet.

Das aktuelle Java-Update von Apple enthält Java 1.6.0_29 und ist damit zeitlich erfreulich nah an Oracles Java 6-Update für andere Systeme. Java 7, für andere Systeme mittlerweile als erstes Update freigegeben, ist leider immer noch nicht final für Mac OS X verfügbar (immerhin gibt es eine Developer Preview von Oracle). Java 8, was sich derzeit noch in der Entwicklung befindet, ist aber schon als Build des OpenJDK 8 für Mac OS X erhältlich.

Dienstag, 25. Oktober 2011

Zeitdauern berechnen mit TimeUnit

Auf java.net ist gerade ein netter Blog-Artikel verlinkt, der das java.util.concurrent-Enum TimeUnit vorstellt. Aus diesem Anlass eine kleine Idee, wofür ich dieses Enum und seine Umwandlung-Methoden schon gut gebrauchen konnte. Wenn man Zeitdifferenzen berechnet, benötigt man häufiger Konstanten von folgender Art:
public static final long MS_PRO_TAG
= 1L * 24L * 60L * 60L * 1000L;
Das funktioniert zwar, ist aber fehleranfällig, weil man sich bei Anzahl und Wert der Faktoren leicht vertun kann. Mit folgendem Ausdruck kann eine beliebige Anzahl Tage (hier: 1) in Millisekunden umgerechnet werden:
public static final long MS_PRO_TAG
= TimeUnit.DAYS.toMillis(1L);
Ebenso lassen sich Sekunden in Stunden umrechnen etc.:
assert TimeUnit.SECONDS.toHours(7250L) == 2;
Wie der andere Blog-Autor schon schreibt: Eigentlich gehört dieses Enum ins Package java.lang (oder vielleicht noch besser nach java.util).

Donnerstag, 13. Oktober 2011

"reschedule-failed-timer" in GlassFish 3.1

In Stateless Session Beans, Singleton Beans und Message Driven Beans kann der EJB-Timer-Service genutzt werden. Ab EJB 3.1 ist es dabei sehr einfach geworden, wiederkehrende Intervall-Timer mit der @Schedule-Annotation zu definieren (eine programmatische Definition ist natürlich weiterhin möglich).

Wenn ein periodischer Timer eine Exception wirft, wird GlassFish sofort noch zweimal versuchen, die Timer-Methode auszuführen. Werden auch diese Aufrufe mit Exceptions abgebrochen, stoppt GlassFish den Timer komplett, d.h. auch nach Ablauf des nächsten Intervall-Zeitraums erfolgt kein Aufruf mehr! Ich bin mir nicht sicher, ob dieses Verhalten von der EJB-Spezifikation gedeckt ist – intuitiv dürfte man aber vermutlich erwarten, dass Intervall-Timer zuverlässig ausgeführt werden.

Seit GlassFish 3.1 gibt es eine Server-Property "reschedule-failed-timer", mit der dieses Verhalten konfiguriert werden kann. Über das Konfigurationsprogramm asadmin kann man mit

asadmin set configs.config.server-config.ejb-container.ejb-timer-service.property.reschedule-failed-timer=true

einstellen, dass auch per Exception abgebrochene Timer nach Ablauf des nächsten Intervall-Zeitraums wieder aufgerufen werden. Durch den Aufruf wird in domain.xml folgender Abschnitt eingetragen:
<ejb-container session-store="${com.sun.aas.instanceRoot}/session-store">
<ejb-timer-service>
<property name="reschedule-failed-timer" value="true"></property>
</ejb-timer-service>
</ejb-container>
Ohne das Setzen der Property bleibt ansonsten nur, den gesamten Timer-Methoden-Rumpf in try { ... } catch (Exception ...) einzufassen, damit garantiert keine Exception den Timer verlässt.

Mittwoch, 5. Oktober 2011

Oracle JDK7 für Mac OS X (Developer Preview)

Nachdem Java SE 7 schon seit einigen Monaten für Windows, Linux und Solaris verfügbar ist und eine Portierung des OpenJDK 7 für Mac OS X begonnen wurde, bietet Oracle nun eine Vorabversion des JDK 7 für Mac OS X an.

Die Installation ist denkbar einfach: Nach dem Download der DMG-Datei zieht (kopiert) man die enthaltene Paket-Datei einfach ins Verzeichnis /Library/Java/JavaVirtualMachines. Fertig! Das Verzeichnis sollte bereits existieren, wenn man das letzte Apple-Java-Update installiert hat, ansonsten muss man es von Hand anlegen.

Die neue Version wird sofort von den Java-Einstellungen erkannt, ein Neustart des Systems ist nicht notwendig. Anwendungen müssen beendet und neu gestartet werden, um das neue Java nutzen zu können.

much$ /usr/libexec/java_home --version 1.7
/Library/Java/JavaVirtualMachines/JDK 1.7.0 Developer Preview.jdk/Contents/Home

much$ /usr/libexec/java_home -v 1.7 --exec java -version
openjdk version "1.7.0-ea"
OpenJDK Runtime Environment (build 1.7.0-ea-b211)
OpenJDK 64-Bit Server VM (build 21.0-b17, mixed mode)

Donnerstag, 12. Mai 2011

Scala 2.9 und Akka 1.1

Ein halbes Jahr nach der letzten Version wurde heute Scala 2.9 veröffenticht.

Wichtigste Neuerung sind sicherlich die parallelen Kollektionen, die z.B. beim Sortieren, Filtern und Durchlaufen automatisch mehrere Prozessorkerne nutzen. Sofern die dabei ausgeführten Funktionen hinreichend komplex sind, lassen sich durch die Parallelisierung deutliche Geschwindigkeitssteigerungen erreichen. "Normale" sequentielle Kollektionen lassen sich mit einem Methodenaufruf in eine parallele Kollektion umwandeln und umgekehrt.

Hilfreich für die alltägliche Programmierung ist auch der neue App-Trait, der den veralteten, nicht so mächtigen und teilweise problematischen Application-Trait ablöst. Mit dem App-Trait lässt sich auf einfache und elegante Weise der Programm-Einstiegspunkt schreiben – er ist also eine Vereinfachung der main-Methode (die man aber immer noch von Hand programmieren kann).

Diese und viele weitere kleine Verbesserungen sind genauer in der Ankündigung der neuen Version 2.9 beschrieben.

Zeitgleich wurde die Gründung der Firma Typesafe bekannt gegeben, in der sich die Gründer und Entwickler von Scala und Akka zusammentun, um Dienstleistungen rund um die Scala-Technologie anzubieten. Als Berater stehen dieser neuen Firma recht bekannte Java-Größen wie James Gosling und Doug Lea zur Seite. Neben Dienstleistungen bietet Typesafe den Typesafe Stack an, ein vorkonfiguriertes Paket mit Scala 2.9 und Akka 1.1.

Akka ist eine Ereignis-gesteuertes Rahmenwerk, mit dem sich verteilte Anwendungen entwickeln lassen. Die Geschäftslogik bleibt dabei frei von den technischen Aspekten der Parallelisierung, Kommunikation, Ausfallsicherheit etc. – ideal für typische Server-Anwendungen. Bekannt geworden ist Akka durch die eigenen, hochskalierbaren und robusten Aktoren (Actors).

Im Typesafe Stack 1.0 sind sowohl die Aktoren von Scala als auch die von Akka mit ihrer bisherigen Funktionalität enthalten. Für zukünftige Scala-Versionen ist aber wohl geplant, diese Funktionalitäten zusammenzuführen.

Sonntag, 20. März 2011

Monaden in Scala

Am vergangenen Wochenende habe ich beim MATHEMA Campus 2011 einen Vortrag über Monaden in Scala gehalten (Folien hier).

Monaden sind ein etwas sperriges Konzept, das in rein funktionalen Sprachen wie Haskell u.a. für eine vernünftige Ein-/Ausgabeprogrammierung notwendig ist. Für Scala sind Monaden vielleicht nicht ganz so wichtig, aber auch mit Scala kann man sinnvoll monadisch programmieren – und das Schöne daran: Über die ganze komplizierte mathematische Theorie dahinter muss man sich keine Gedanken machen. Im Gegenteil, wer schonmal ein bisschen Scala programmiert hat, wird dabei vermutlich (unbewusst) auch Monaden genutzt haben.

Was sind diese Monaden? Ein abstrakter Datentyp für verkettbare Berechnungen mit folgenden Eigenschaften:
  • Ein Typkonstruktor wie List[A] (mit z.B. List[Int] als Ausprägung).
  • Eine Funktion, um einen Wert im Typ "einzuwickeln". Das kann der Konstruktor sein, z.B. new List(1) bzw. List(1), aber häufig wird diese Funktion return, unit, lift oder pure genannt.
  • Eine Funktion, um die enthaltenen Werte zu verrechnen, aber nach der Berechnung im Typ verpackt zu lassen. Übliche Namen sind bind oder (in Scala) flatMap.
Die Monadengesetze müssen von den Funktionen eingehalten werden, aber das lassen wir mal außen vor. Klingt kompliziert? Schauen wir uns das in der Praxis an:
case class MiniMonade[A](wert:A) {

def flatMap[B](f: A => MiniMonade[B]) = f(wert)

def map[B](f: A => B): MiniMonade[B]
= MiniMonade(f(wert))
}
Die Mini-Monade soll also genau einen Wert des generischen Typs "A" speichern und verarbeiten können. Listen sind auch Monaden und können entsprechend beliebig viele Werte verarbeiten. In unserer Monade ist zusätzlich noch die Funktion map implementiert, damit wir Objekte dieser Klasse in den for-Comprehensions von Scala einsetzen können. Und genau das ist auch der häufigste Anwendungsfall für Monaden in Scala:
val m1 = MiniMonade(2)
val m2 = MiniMonade(3)

val erg = for { x <- m1; y <- m2 } yield x*y;

println( erg )
In dieser for-Comprehension werden alle Werte aus den beiden Monaden-Objekten miteinander mit x*y verrechnet und landen anschließend (durch die Magie der Monaden-Funktionen) wieder in einem Monaden-Objekt. Da unsere Objekte jeweils nur einen Wert speichern, wird nur 2*3 berechnet:
HeartOfGold:~ much$ scala MiniMonade.scala
MiniMonade(6)
Das scheint unnötig viel Aufwand für eine simple Multiplikation zu sein... Aber folgendes Beispiel dürfte – so oder in ähnlicher Form – jeder schonmal programmiert haben, und das ergibt sicher mehr Sinn:
val zeilen = List(10,20)
val spalten = List(1,2)

val summen = for {z <- zeilen; s <- spalten} yield z+s;

println( summen )
// List(11, 12, 21, 22)
Andere gebräuchliche monadische Typen sind (neben vielen weiteren) Map und Option, und alle diese Klassen können in einer for-Comprehension kombiniert werden.

Die Verwendbarkeit in for-Comprehensions ist in Scala sicherlich der wichtigste Grund, warum man geeignete eigene Klassen monadisch machen sollte. Würden wir noch withFilter und foreach implementieren, könnten wir unsere Monade außerdem in weiteren for-Varianten einsetzen.

Beim diesjährigen Herbstcampus werde ich einen Einsteiger-Vortrag (OO-Vorkenntnisse reichen) zu diesem Thema halten.

Mittwoch, 9. Februar 2011

Freie Icons für Web-Oberflächen

Gute Web-Oberflächen zeichnen sich nicht nur durch durchdachte, einfach zu verstehende HTML-Formulare aus. Sie sollten auch ansprechend – "schön" – aussehen, weil die Benutzer dann garantiert lieber mit der Web-Anwendung arbeiten als mit lieblos gestalteten Seiten.

Ein wichtiger Aspekt dabei sind klar gestaltete Symbolgrafiken (Icons) – sei es für Status-Anzeigen oder für Schaltflächen. Wenn man künstlerisch nur eingeschränkt begabt ist, greift man besser auf fertige Grafiken zurück, als langweilige und schlecht zu erkennende Symbole selber zusammenzupixeln.

Seit langer Zeit nutze ich daher immer wieder gerne die famfamfam-Icons von Mark James. Die Mini- und Flaggen-Icons sind dabei komplett Public Domain, können also beliebig verwendet werden. Und auch die 1000 Silk-Icons stehen kostenfrei selbst für kommerzielle Anwendungen zur Verfügung. Der Autor bietet sie unter der Creative Commons Attribution 2.5-Lizenz an (wahlweise auch unter der Lizenz-Version 3.0) und verlangt lediglich einen Link auf seine Web-Seite.

Vielen Dank für die Blumen – äh – Icons!

Freitag, 14. Januar 2011

OpenJDK 7 für Mac OS X

Nachdem Apple vor knapp zwei Monaten Unterstützung für das OpenJDK-Projekt angekündigt hatte, wurde die Mac OS X-Portierung am Montag dieser Woche als offizielles OpenJDK-Projekt angenommen – und nur einen Tag später hat Apple den ersten offenen Code in das Projekt eingebracht. Im Wesentlichen entspricht diese erste Veröffentlichung der BSD-Portierung. Apple hat derzeit nur den Build-Prozess verändert, um ein Universal Binary mit einem .jdk-Bundle zu erzeugen, das zur neuen Java-Verzeichnisstruktur von Mac OS X passt (und entsprechend nach der Installation automatisch erkannt wird).

Jeder kann nun zum Mac OS X-Port beitragen und sich das aktuellste OpenJDK aus den Quelltexten bauen. Voraussetzung dafür sind u.a. Mac OS X ab Version 10.6.5 sowie Xcode ab Version 3.2.5. Genaueres ist im Wiki beschrieben; dort kann man auch den aktuellen Projekt-Status einsehen.

Wer das JDK 7 einfach ausprobieren möchte, ohne es selber bauen zu müssen, kann sich ein fertiges DMG von Google Code herunterladen. Der Installer für den Mac OS X-Branch enthält sowohl eine 32- als auch eine 64-Bit-JVM. Nach der schnellen und vollkommen unproblematischen Installation kann man das JDK 7 mit den üblichen Kommandos im Terminal testen:

much$ /usr/libexec/java_home --version 1.7
/Library/Java/JavaVirtualMachines/1.7.0.jdk/Contents/Home

much$ export JAVA_HOME=`/usr/libexec/java_home -v 1.7`
much$ $JAVA_HOME/bin/java -version
openjdk version "1.7.0-internal"
OpenJDK Runtime Environment (build 1.7.0-internal-b00)
OpenJDK 64-Bit Server VM (build 20.0-b03, mixed mode)

much$ /usr/libexec/java_home -v 1.7 --exec java -version
openjdk version "1.7.0-internal"
OpenJDK Runtime Environment (build 1.7.0-internal-b00)
OpenJDK 64-Bit Server VM (build 20.0-b03, mixed mode)

Für grafische Frontends wird noch kein Cocoa, sondern nur X11 unterstützt. Zum Ausprobieren der neuen Sprachfeaturen (Strings im switch etc.) reicht das aber vollkommen aus.

Wie bereits erwähnt wird das OpenJDK 7 automatisch von den Java-Einstellungen in Mac OS X erkannt. Wegen der noch unvollständigen Cocoa- bzw. Mac OS X-Integration sollte man die neue Version aber noch nicht als Default setzen, d.h. besser am Ende der Liste belassen.