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.

Dienstag, 8. Dezember 2009

Eclipse 3.5 Galileo, Software-Updates und Proxy-Verbindungen

Je nach Netzwerkumgebung gibt es mit Eclipse immer wieder Probleme beim Installieren von Plugins (über das Menü Help > Install New Software...) bzw. beim automatischen Aktualisieren bereits installierter Erweiterungen (über Help > Check for Updates). Grund sind meistens Proxies, die von Eclipse nicht unterstützte Protokolle verwenden, sowie Firewalls, die eigene Zertifikate für https-Verbindungen ausgeben.

Sofern man das Zertifikat der Firewall besitzt (eine Datei üblicherweise mit der Endung *.cer), kann man dieses in den Keystore der Java-Installation importieren. Welche Java-Installation von Eclipse verwendet wird, kann man unter About Eclipse > Installation Details > Configuration herausfinden. Unter Windows lautet der Aufruf des keytool-Kommandozeilenbefehls beispielsweise
C:\Programme\Java\jre6\bin\keytool -import -v
-file PfadZumZertifikat
-keystore C:\Programme\Java\jre6\lib\security\cacerts
Geben Sie das Keystore-Passwort ein: changeit
"changeit" ist das Standard-Passwort des KeyStores, sofern Sie es nicht geändert haben.


Ein anderes Problem stellen NTLMv2-Proxy-Server dar, die seit Eclipse 3.5 nicht mehr direkt unterstützt werden. Neben der korrekten Einrichtung der Proxy-Adresse und der Authentifizierungsdaten unter Preferences > General > Network Connections muss in der Datei eclipse.ini (im Eclipse-Programmverzeichnis) am Ende folgende Zeile hinzugefügt werden:
-Dorg.eclipse.ecf.provider.filetransfer.excludeContributors=org.eclipse.ecf.provider.filetransfer.httpclient
In Eclipse 3.5 war es in der o.g. Preferences-Seite zudem notwendig, den "Active Provider" auf "Native" zu stellen. In Eclipse 3.5.1 funktioniert auch die Einstellung "Manual".