Freitag, 26. Februar 2010

Closures in JavaScript

Nachdem ich schon Beispiele für Closures (Funktionsabschlüsse) in JavaFX und Scala vorgestellt hatte, schauen wir uns dasselbe Beispiel in JavaScript (ECMAScript) an:
// closures.js

function zaehlerMitStartwert(startwert) {
return function() {
return startwert++
}
}

next1 = zaehlerMitStartwert(10)
next2 = zaehlerMitStartwert(20)

document.writeln( next1() ) // 10
document.writeln( next2() ) // 20
document.writeln( next2() ) // 21
document.writeln( next1() ) // 11

Sehr viel mehr gibt es dazu eigentlich nicht zu sagen, außer dass es
  1. wirklich so einfach ist (was auch zu Problemen führen kann)
  2. schon seit den ersten JavaScript-Versionen (und damit seit über 10 Jahren) zur Verfügung steht und
  3. im Gegensatz zu JavaFX Script und Scala dynamisch typisiert ist; zudem ist keine zusätzliche lokale Variable nötig, weil der Übergabeparameter startwert bereits eine veränderbare Variable ist. Beides ist im Hinblick auf stabile, wartbare Software nicht unbedingt als positiv zu bewerten.
Viele moderne JavaScript-Bibliotheken machen starken Gebrauch von solchen Funktionsliteralen und Closures, beispielsweise jQuery.

Dienstag, 16. Februar 2010

Hibernate/JPA, hashCode() und Eclipse

Entitäten in Hibernate/JPA haben oft einen synthetischen (technischen) Primärschlüssel, der im folgenden Beispiel als Long id implementiert wird. Sofern es keine zusätzlichen fachlichen Schlüsselkandidaten gibt, muss man die hashCode()-Methode für Hibernate/JPA so implementieren, dass sie ausschließlich mit dieser Id arbeitet. (Es gibt auf hibernate.org eine lange Diskussion zu diesem Thema, denn die "offiziell" vorgeschlagene Variante, "halb-eindeutige" Felder zu verwenden, macht in der Praxis meistens mehr Probleme als die Id-Variante.)

Damit man hashCode() (und das zwingend dazu gehörende equals()) nicht immer wieder von Hand neu schreiben muss, bietet Eclipse über Source > Generate hashCode() and equals() die Möglichkeit, die beiden Methoden mit wählbaren Attributen zu generieren. Eine Beispiel-Entität könnte dann wie folgt aussehen:
@Entity
public class Datensatz {

@Id @GeneratedValue
private Long id;

// weitere Felder, Getter, Setter, equals() etc. ...

/**
* Von Eclipse 3.5 generiert.
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((id == null) ? 0 : id.hashCode());
return result;
}
}
An sich liefert die Hashwert-Berechnung mittels Primzahlen eine gute Streuung, und der automatisch generierte Code beachtet auch, dass die Id null sein kann – nämlich bei noch nicht in der Datenbank gespeicherten (persistierten) Objekten.

Nun testen wir diese Entity-Klasse:
@Test
public void testAddToHashSet() {

Set<Datensatz> menge = new HashSet<Datensatz>();

Datensatz ds1 = new Datensatz();
Datensatz ds2 = new Datensatz();

assertTrue("Menge sollte leer sein", menge.isEmpty());

menge.add(ds1);

assertTrue("Menge sollte ein Element besitzen",
menge.size() == 1);
// ok

menge.add(ds2);

assertTrue("Menge sollte zwei Elemente besitzen",
menge.size() == 2);
// immer noch 1... Ups!?!
}
Immer, wenn man Assoziationen im Objekt-Modell aufbaut, bevor die Datensätze gespeichert sind (also z.B. bei Unit-Tests wie im obigen Beispiel), tritt das gezeigte Szenario auf. Wir haben hier zwei Objekte, die beide keine Id (=null) besitzen. Es sind aber trotzdem zwei nicht identische Objekte in separaten Speicherbereichen, die beim Persistieren entsprechend zwei Datensätze mit unterschiedlichen Primärschlüsseln (Ids) erzeugen würden. Leider kann sich das HashSet nur eines der beiden Objekte merken – und auch beim Persistieren einer Assoziation ginge so eines der Objekte verloren!

Eine Anpassung der generierten hashCode()-Methode ist denkbar einfach. Statt bei einer nicht vorhandenen Id die Zahl 0 für die Hashwert-Berechnung zu verwenden, nehmen wir den Hashwert des Objekts, der bei nicht identischen Objekten in den allermeisten Fällen unterschiedlich ist:
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((id == null) ? super.hashCode() : id.hashCode());
return result;
}
Eine vergleichbare Implementierung nutze ich seit Jahren ohne Probleme, weshalb ich diese Variante pauschal für die praktikabelste halte. In Einzelfällen mögen natürlich speziellere Implementierungen sinnvoller sein.

Mittwoch, 3. Februar 2010

HTML-Accesskey mit CSS darstellen

Mit dem Standard-HTML-Attribut accesskey lassen sich Tastaturkürzel (Shortcuts) definieren, mit denen man den Eingabefokus auf die zugehörigen Eingabeelemente setzen kann:
<label for="nachname" accesskey="n">Nachname:</label>
<input id="nachname" type="text">
Mit welcher Tastenkombination der Fokus gesetzt wird, ist browser- und systemabhängig. Obiges Kürzel aktiviert man im IE/Win mit Alt+N, im Firefox/Win mit Shift+Alt+N, im Firefox/Mac mit Ctrl+N, in Safari/Mac mit Ctrl+Alt+N...

Natürlich sollte man dem Anwender auch anzeigen, dass Tastaturkürzel vorhanden sind. Man kann diese Information zwar noch einmal statisch in den HTML-Quelltext schreiben (zusätzlich zum accesskey-Attribut). Mit einer einfachen CSS2-Regel kann man aber auf solche redundanten Angaben verzichten und die Kürzel an allen label-Elementen darstellen lassen, bei denen accesskey gesetzt ist:

label[accesskey]:after {
content: " [" attr(accesskey) "]";
text-transform: uppercase;
color: #999999;
font-size: x-small;
}

Die CSS-Regel basiert vor allem auf einem Attribut-Selektor und einem Pseudo-Element. Dadurch wird nach (:after) jedem label-Element, bei dem das accesskey-Attribut vorhanden ist, der Wert des Attributs in Großschreibung (uppercase) in den Dokument-Inhalt (content) eingefügt:



An sich sind diese Techniken recht alt, die entsprechenden Standards wurden schon vor Jahren offiziell verabschiedet (die HTML 4.01-Spezifikation ist über 10 Jahre alt, CSS 2 ebenso). Was macht dieses Thema wieder aktuell?

Google hat vor kurzem angekündigt, ab dem 1. März dieses Jahres ältere Browser-Versionen und insbesondere den Internet Explorer 6 (IE6) nicht mehr in seinen Web-Anwendungen zu unterstützen.
Dieser – eigentlich längst überfällige – Schritt dürfte auch andere Anbieter dazu bewegen, neuere IE-Versionen (oder Alternativen wie Firefox) vorauszusetzen. Und dann könnten auch endlich IE-Nutzer von Web-Standards wie den Attribut-Selektoren profitieren, die der IE6 leider seit Jahren ignoriert.

Sonntag, 31. Januar 2010

Closures in Scala

Als funktionale Sprache unterstützt Scala Funktionen höherer Ordnung (first-class functions) und Funktionsabschlüsse (Closures). In dem Beitrag über Closures in JavaFXScript hatte ich bereits gezeigt, wie dort Closures definiert und genutzt werden. Wie programmiert man nun Closures in Scala?
// closures1.scala

def zaehlerMitStartwert(startwert: Int): (() => Int) = {
var n = startwert
def nplus1(): Int = { n=n+1; n }
nplus1
}

val next1 = zaehlerMitStartwert(10)
val next2 = zaehlerMitStartwert(20)

println( next1() )
println( next2() )
println( next2() )
println( next1() )
Wir definieren eine Funktion zaehlerMitStartwert(), die den Startwert als Int-Parameter übergeben bekommt. Rückgabe dieser Funktion ist eine Funktion, die keine Parameter hat, aber einen Int-Wert zurückgibt.

Innerhalb der äußeren Funktion legen wir eine Zählvariable n an, da der Übergabeparameter startwert unveränderlich ist. Dann definieren wir eine verschachtelte Funktion nplus1(), die auf die Zählvariable n eins draufzählt und als letzten Ausdruck der Funktion das hochgezählte n zurückgibt. Hier findet der Funktionsabschluss statt - das Binden der Variablen n, die als lokale Variable in der umgebenden Funktion definiert ist. Als letzten Ausdruck in der äußeren Funktion geben wir die Funktion nplus1 als Ergebnis zurück.

Das ganze geht auch etwas kürzer und "funktionaler", wenn man die innere Funktion nicht explizit definiert, sondern als letzten Ausdruck der äußeren Funktion gleich ein entsprechendes Funktionsliteral hinschreibt:
// closures2.scala

def zaehlerMitStartwert(startwert: Int) = {
var n = startwert
() => { n=n+1; n }
}

val next1 = zaehlerMitStartwert(10)
val next2 = zaehlerMitStartwert(20)

println( next1() )
println( next2() )
println( next2() )
println( next1() )
Beide Skripte liefern dieselbe Ausgabe:
HeartOfGold:~ much$ scala closures2.scala
11
21
22
12
Wenn man den Scala-Interpreter mit scala -savecompiled closures2.scala aufruft, erhält man ein JAR-Archiv, in dem man sich die generierten Java-Bytecode-Dateien anschauen kann. In diesem Fall werden vier class-Dateien erzeugt.

Sonntag, 27. Dezember 2009

Scala-Servlets

Ein schönes Beispiel dafür, wie sich gewohnte Java-Programmierung in Scala "anfühlt", sind Servlets:
package com.muchsoft.scala.servlets

import javax.servlet.http.HttpServlet
import javax.servlet.http.{HttpServletRequest => Request,
HttpServletResponse => Response}

class MeinErstesScalaServlet extends HttpServlet {

override def doGet(request: Request, response: Response) {

val ausgabe =
<html>
<head><title>Hallo Scala</title></head>
<body>
<h1>Hallo Scala-Welt!</h1>
</body>
</html>

response.getWriter().print(ausgabe)
}
}
Das sieht doch fast wie Java aus, oder? Nicht ganz: Beim Import können wir Umdefinitionen vornehmen, das override vor der Methodendefinition ist zwingend notwendig, zudem ein Schlüsselwort und keine Annotation. Der Rückgabetyp der Methode doGet() ist nicht angegeben und entspricht dadurch dem Java-void. Für Scala hätten wir vor die öffnende geschweifte Methodenklammer :Unit= schreiben können.

Innerhalb von doGet() legen wir das XML-Literal ausgabe an (als nicht änderbaren Wert mit val; mit var angelegte Variablen versucht man in funktionalen Sprachen zu vermeiden). Dieses XML-Literal schreiben wir ganz normal in den Ausgabestrom des Response-Objekts. Der Typ von ausgabe ist scala.xml.Elem.

Die Struktur der Web-Applikation entspricht dem JavaEE-Standard:


Der vom Scala-Compiler erzeugte Java-Bytecode landet in WEB-INF/classes. Die Scala-Standardbibliothek scala-library.jar (aus dem Scala-Installationsverzeichnis) muss in WEB-INF/lib mit ausgeliefert werden. In WEB-INF/web.xml mappen wir die Klasse com.muchsoft.scala.servlets.MeinErstesScalaServlet auf die URL "hallo.scala". Nach dem Bereitstellen (Deployment) z.B. in Tomcat oder GlassFish kann das Servlet im Web-Browser dann mit der URL http://localhost:8080/halloscala/hallo.scala aufgerufen werden.

Zum Übersetzen der Servlet-Klasse muss sich noch die Servlet-API auf dem Build-Path (Classpath) befinden. Dazu kann man z.B. aus dem Tomcat-Installationsverzeichnis servlet-api.jar oder aus dem GlassFish-Verzeichnis javaee.jar als externe Bibliothek einbinden.

Nun verbessern wir das erste Scala-Servlet und trennen Darstellung und Steuerung etwas besser voneinander:
class MeinZweitesScalaServlet extends HttpServlet {

def ausgabe =
<html>
<head><title>Hallo Scala</title></head>
<body>
<h1>Hallo Scala-Welt!</h1>
<p>Zeit auf dem Server: {jetzt} </p>
</body>
</html>

def jetzt = new java.util.Date

override def doGet(request: Request, response: Response) {
response.getWriter().print(ausgabe)
}
}
ausgabe ist nun eine Funktion außerhalb von doGet(), die auf die Funktion jetzt zurückgreift, um einen aktuellen Zeitstempel auszugeben. Beide Funktionen sind ohne Parameterklammern definiert und müssen daher ohne Klammern aufgerufen werden. Hätten wir die Funktionen mit leeren Parameterklammern definiert, hätten wir es uns beim Aufruf aussuchen können, ob wir die Klammern hinschreiben oder nicht. Es hat sich die Konvention herausgebildet, die Klammern bei der Definition wegzulassen, wenn eine Funktion keine Nebenwirkungen (Seiteneffekte) hat.

Für eine "vollständige" Web-Applikation fehlt noch ein Formular. Bitteschön:
class MeinDrittesScalaServlet extends HttpServlet {

def ausgabe(benutzername: String) =
<html>
<head><title>Hallo Scala-Welt</title></head>
<body>
<h1>Hallo {benutzername}</h1>
<p>Zeit auf dem Server: {jetzt}</p>
<form method="GET" action="hallo3.scala">
<p>Wie heißt Du?
<input name="benutzer" />
<input type="submit" value="Abschicken" />
</p>
</form>
</body>
</html>

def jetzt = new java.util.Date

override def doGet(request: Request, response: Response) {

val param = request getParameter "benutzer"

val benutzername =
if ((param == null) || (param.isEmpty))
"Scala"
else
param capitalize

val antwort = ausgabe(benutzername)

response.getWriter().print(antwort)
}
}
ausgabe() bekommt nun einen String-Parameter übergeben, der in doGet() anhand des Request-Parameters "benutzer" ermittelt wird. Statt des ?:-Operators von Java, den es in Scala nicht gibt, verwenden wir ein besser lesbares if-else, das in Scala ein Ausdruck ist und entsprechend ein Ergebnis liefert.

Wenn diese dritte Servlet-Klasse in web.xml auf die URL "hallo3.scala" gemappt wird, kann der Aufruf im lokalen Applikations-Server mit http://localhost:8080/halloscala/hallo3.scala?benutzer=Thomas erfolgen.

In der Praxis wird man Servlets wohl eher nicht direkt programmieren, sondern ein Framework wie Struts, JSF, Wicket o.ä. einsetzen. Man sieht hier aber gut, wie problemlos man Scala in bestehende Java-(Web-)Anwendungen integrieren kann. Und wenn man Web-Applikationen so richtig funktional entwickeln möchte, kann man das Scala-Lift-Framework nutzen.

Samstag, 12. Dezember 2009

ECMAScript 5

Bis vor ein paar Jahren musste man regelmäßig darauf hinweisen, dass Java nicht JavaScript ist, und JavaScript wurde als Programmiersprache – trotz Objektbasierung und funktionaler Aspekte – nicht ernst genommen. Mit Web 2.0 und Ajax ist dies seit einiger Zeit definitiv anders. JavaScript ist im Frontend akzeptiert, und es gibt keine ernsthaften Diskussionen mehr, ob man es im Browser deaktivieren soll. RIA kommt ohne JavaScript nicht aus.

Vor einer Woche wurde nun die Spezifikation von ECMAScript 5, dem offiziellen Standard für JavaScript, freigegeben. Die neue ECMAScript-Version wurde ziemlich genau zehn Jahre nach der letzten Version, ECMAScript 3, veröffentlicht (Version 4 wurde ausgelassen). Neben vielen kleinen Verbesserungen und einem "strict"-Modus ist nun auch JSON im Standard enthalten. Mit diesem Datenformat können JavaScript-Objekte kompakt durch das Netz übertragen werden.

Für mich ist ECMAScript insofern interessant, als es nun über zehn Jahre her ist, dass ich für den Web-Browser iCab eine JavaScript-Engine (Interpreter) zunächst auf Basis von ECMAScript 2, nach 1999 dann aufbauend auf ECMAScript 3 entwickelt hatte. iCab hat seine Rendering Engine (und damit auch die JavaScript-Laufzeitumgebung) zwar mittlerweile auf Apples WebKit umgestellt, aber die Implementierung einer so zentralen Browser-Komponente gab einen tollen Einblick hinter die technischen Kulissen auf das, wie das Web bis (und gerade) heute funktioniert.

Wie die Zeit vergeht...

Donnerstag, 10. Dezember 2009

Hallo Java EE 6!

Dreieinhalb Jahre nach Java EE 5 hat Sun heute die endgültige Spezifikation von Java EE 6 freigegeben. Bestandteil davon sind u.a. die Spezifikationen von EJB 3.1, JPA 2.0 und JSF 2.0.

Der Download des Java EE 6 SDK enthält den Application Server GlassFish v3 als Referenzimplementation (neben Beispielen samt Dokumentation).

Ebenfalls verfügbar ist die an JEE 6 und GlassFish v3 angepasste Entwicklungsumgebung NetBeans 6.8. Eclipse-Anwender finden hier das entsprechende Plugin.

Wer bereits jetzt Java-Enterprise-Projekte auf Basis von JEE 5 entwickelt, dem dürfte die Umstellung auf die neue Version nicht allzu schwer fallen – sofern der eingesetzte Application Server kompatibel zur neuen Spezifikation ist.

Eine dreiteilige Einführung in Java EE 6 hat Sun hier veröffentlicht.