Groovy für Java-Entwickler

Grails

Dierk König

Groovy als Sprache bietet dynamische Eigenschaften, ausdrucksstarke Syntax, eingebaute Datentypen und Integration mit Java. Alle diese Eigenschaften und Vorzüge von Groovy bündeln sich in Grails, Groovys Webapplikations-Framework.

Eines der herausragenden Merkmale der Java-Enterprise-Plattform ist die Freiheit der Wahl. Sie erlaubt im Präsentationsbereich sowohl vorlagenorientierte Entwicklung (JSP) wie auch komponentenorientiertes Vorgehen (JSF), Flussorientierung wie bei Cocoon oder Varianten wie Sitemesh, WebWork, Tapestry, Tiles und viele andere mehr. Dazu kommen verschiedenste Lösungen für die Persistenz wie EJB, JDO, Hibernate und iBATIS. Das ergänzt um Spring und andere Container und Modularisierungslösungen ergibt eine unglaubliche Vielfalt an technologischen Umsetzungsmöglichkeiten für – so sollte man meinen – jeden Bedarf.

Trotzdem hat der Erfolg von Ruby on Rails gezeigt, das es jenseits der bestehenden Ansätze einen Bedarf gibt, der bis dato auf der Java-Enterprise-Plattform nicht adressiert werden konnte: den Bedarf an einem interaktiven System mit schnellem Feedback, leichtgewichtiger Modellierung, hoher Änderungsfreundlichkeit und Unterstützung von Web 2.0-Technologien. Diese Effekte werden vor allem durch den Einsatz einer dynamischen und ausdrucksstarken Sprache erreicht. Für die Java-Plattform ist Groovy eine solche Sprache, was die Idee nahelegt, Gleichartiges mit Groovy auf der Java-Plattform bereitzustellen. Aus dieser Überlegung ist Grails entstanden.

Grails ist zu dem Zweck entwickelt worden, viele Effekte von Ruby on Rails zu erreichen wie zum Beispiel die leichte Einarbeitung durch einheitliche Vorgaben (convention over configuration) und Entwicklungsunterstützung durch Teilautomatisierung der Erstellung von Artefakten aus Vorlagen (scaffolding).

Es gibt aber auch klare Unterschiede, die sich aus dem Aufbau auf die Java-Plattform ergeben, schließlich gibt es hier schon viele ausgereifte Bausteine, die man nur verwenden und nicht neu erfinden muss. Die Investitionen in Server-Infrastruktur, Security, Betrieb, Deployment und in die eingesetzten Java-Frameworks sollen erhalten werden. Weiterhin sind Java-Entwickler bestimmte Vorgehensweisen gewohnt, die man nicht ohne Not brechen will. Dazu zählt die Modellierung der Applikationsdomäne als Klassen im Sourcecode im Gegensatz zum Ansatz, das Applikationsmodell als Datenbank-Schema zu entwickeln.

Basierend auf diesen Überlegungen hat sich das Grails-Team entschieden, folgende Technologien und Pakete einzusetzen: Java EE, Groovy, Spring, Hibernate, Sitemesh, Prototype, Dojo, JUnit und Canoo WebTest.

Das Java EE Servlet API bildet die Basis für die Webapplikation. Grails erzeugt seine Applikationen als Standard-war-Datei und erlaubt damit ein Deployment in beliebige Java EE-Server. Darin ist die volle Groovy-Laufzeitumgebung enthalten, sodass am Server selbst keine speziellen Installationsschritte durchgeführt werden müssen. Während der Entwicklung wird die Applikation transparent in einem mitgelieferten Jetty Server ausgeführt.

Groovy wird für die Implementierung des Domänenmodells, der Applikationslogik in den Controller-Klassen und für die dynamischen Anteile der Views genutzt. Wer bereits Modellklassen in Java implementiert hat, kann diese weiterverwenden. Ebenfalls werden transaktionsgeschützte Services und zeitgesteuerte Jobs als Groovy Klassen implementiert. Alle diese Artefakte werden durch einfache Scaffolding-Befehle erzeugt und rein durch ihre Anordnung in den zugehörigen Directories klassifiziert. Die notwendigen Eigenschaften werden von Grails dynamisch injiziert. Vererbung zu diesem Zweck wird vermieden.

Spring verbindet die einzelnen Bausteine, wobei Grails nicht die deklarative Spring-Konfiguration per XML verwendet, sondern die Komponenten dynamisch ermittelt und programmatisch verbindet.
Hibernate sorgt für die transparente Persistenz der Objekte aus dem Domänenmodell, ohne dass der Programmierer selbst für das Mapping sorgen muss. Dies muss er nur erstellen, wenn er zusätzlich zu den Groovy-Klassen auch Java-Klassen in sein Modell aufnimmt. Während der Entwicklung dient die mitgelieferte HypersonicSQL als In-Memory-Datenbank.
Sitemesh gehört zu den weniger bekannten Frameworks. Es wirkt als Decorator für HTML-Seiten, um zum Beispiel ein einheitliches Layout aller Seiten der Applikation sicherzustellen. Mit Prototype und Dojo lassen sich Grails-Seiten um Ajax-Effekte ergänzen.

Testunterstützungen mit JUnit für Unit-Tests und Canoo WebTest für automatisierte Endbenutzertests runden das Applikations-Framework ab. Für beide Arten von Tests lassen sich die Standard-Artefakte per Scaffolding erstellen und beim Fortschreiten der Applikation erweitern. Es ist sogar eine testgetriebene Entwicklung möglich.

Einfacher Einstieg

Alle Informationen über Grails, die aktuelle Distribution und die Installationsanleitung finden sich unter grails.org. Nach der Installation kann man eine Grails-Applikation per Kommandozeile leicht wie folgt erzeugen: grails create-app. Am Prompt gibt man den gewünschten Namen der Applikation ein, sagen wir bookstore. Dann wird ein entsprechendes Unterverzeichnis mit der vollständigen Struktur einer Grails-Applikation angelegt. Nach cd bookstore können wir unsere bis dahin noch leere Applikation schon ausprobieren: grails run-app.

Die Applikation ist nun unter http://localhost:8080/bookstore mit einem Willkommensgruss sichtbar. Eine Buchhandlung hat sicher Bücher, also legen wir eine Buch-Klasse in dem Domänenmodell an:

grails create-domain-class

An der Eingabeaufforderung geben wir book ein, was Grails dazu veranlasst, diese Klasse und einen zugehörigen Unit-Test in den entsprechenden Verzeichnissen anzulegen. Die Modellklasse ist denkbar sparsam:

class Book { 
}	

Schlanker geht es nun wirklich nicht mehr: keine Oberklasse, keine strukturelle Duplikation in den Standard-Eigenschaften. Standardmäßig haben alle Modellklassen eine version und id Property vom Typ Long und eine toString()-Methode. Diese werden dynamisch injiziert, es sei denn, man stellt eine eigene Implementierung bereit. Erweitern wir nun unsere Klasse um Titel und Autor:

class Book { 
    String title
    String author
}

Nun gilt es, Objekte dieser Klasse in einer Webapplikation verwalten zu können, sie also anzulegen, zu speichern, aufzulisten, zu verändern und zu löschen (CRUD – create, read, update, delete). Zu jeder dieser Aktionen bedarf es einer ausführenden Logik (Controller Action) und einer View, über die die Aktionen auswählbar und die Ergebnisse sichtbar sind. Die damit verbundene Arbeit nimmt uns Grails ab: grails generate-all.
Wir werden nach der Modellklasse gefragt, für die Controller und Views erstellt werden sollen, und geben book ein. Ein nachfolgendes grails run-app startet eine vollständige datenbankgestützte Webanwendung unter http://localhost:8080/bookstore/book mit Aktionen, wie sie in Abbildung 1 angedeutet sind.

Abb. 1: Book-CRUD-Operationen

Nicht schlecht für zwei Zeilen Programmierung, vor allem wenn man bedenkt, wie viel Arbeit im Hintergrund geleistet werden muss. Grails hat unter grails-app/controller einen BookController mit acht Actions angelegt (index, list, show, delete, edit, update, create, save), der das persistente Domänenmodell bearbeitet und auf einen der Views (create, edit, list, show) weiterleitet, die als Groovy Server Page (GSP) unter grails-app/views/book angelegt wurden.

Ein großer Teil dessen, was Grails so angenehm macht, liegt in der Mächtigkeit der Controller und der Flexibilität der Views.

Controller

Wer etwas über Grails Controller lernen möchte, kann sich die sehr gute Dokumentation unter grails.org ansehen, oder einfach einen generierten Controller wie unseren BookController untersuchen. Alle Actions sind als Closures realisiert, die einer Property zugewiesen sind.

Im Scope der Closure liegen verschiedene Objekte, u.a. params, eine Map der übergebenen Parameter. Sie refenziert von Parameternamen auf Objekte! Nehmen wir an, unser Autor wäre kein String, sondern ein Objekt der Domänenklasse Author, dann würde params.author ein Objekt vom Typ Author referenzieren! Dieses persistente Objekt lässt sich nun leicht manipulieren, z.B. löschen per params.author.delete(), oder auf sonstige Weise weiterverwenden.

Controller sind auch der typische Platz, an dem mit persistenten Objekten aus dem Domänenmodell gearbeitet wird, wobei das Groovy Object Relational Mapping (GORM) auf Basis von Hibernate zum Einsatz kommt. Ein wichtiger Teil von GORM sind die dynamischen Finder-Methoden. Im obigen Fall lässt sich eine Liste aller Bücher eines Autors wie folgt ermitteln:

Book.findByAuthor( params.author )

Eine nachgeschaltete View kann dann genau diese Liste anzeigen. Nachgeschaltet ist die View mit dem gleichen Namen wie die Action. So wird nach Ausführung der list Action auf die list.gsp View weitergeleitet. Die Action gibt in diesem Fall eine Map mit Daten an die View zurück, die in deren Binding gestellt werden. Mit der render-Methode kann auch auf andere Views verzweigt werden und mit redirect lassen sich Actions verketten.

Grails Controller sind recht schlank, selbst die generierten. Dieses statische Scaffolding dient aber nur als Ausgangspunkt für spätere Anpassungen. Wem die Standardfunktionalität ausreicht, kann den gesamten Körper der Controller-Klasse durch das dynamische Scaffolding ersetzen und einzelne Actions lediglich wo nötig implementieren: def scaffold = Book.

Views: GSP

Über View-Technologien gehen die Meinungen besonders weit auseinander und jeder hat einen anderen Favoriten. Im Java-Umfeld sind jedoch JSP am weitesten verbreitet und deshalb lehnt sich Grails stark an diese Vorgabe an. Man kann Grails Views auch als JSP realisieren, die Groovy-Variante GSP ist jedoch leichtgewichtiger und flexibler.

Wieder geben die generierten Artefakte einen guten ersten Eindruck von der zur Verfügung stehenden Funktionalität, die für jeden leicht verständlich ist, der JSP kennt. Was GSP von JSP unterscheidet, ist vor allem die leichte Möglichkeit, Duplikation zu vermeiden. Wiederverwendbare Bausteine lassen sich je nach Bedarf in Templates oder Taglibs auslagern. Templates entsprechen den „partials“ in Rails: Teil-Views mit Bausteincharakter. Taglibs sind dagegen Erweiterungskomponenten mit übergreifendem Funktionscharakter. Sie werden einfach zum Beispiel als MyTagLib.groovy in das taglib-Verzeichnis gespeichert. Die Tags selbst sind Closures, die Properties der TagLib-Klasse zugewiesen werden. Das macht sie ohne weitere Konfiguration in jeder View verfügbar.

Und das ist erst der Anfang

Wir haben an der Oberfläche von Grails gekratzt und versucht, etwas von dem Gefühl der Leichtigkeit zu vermitteln, das sich bei der Arbeit mit Grails einstellt. Weitere Informationen gibt es online unter grails.org, bald als Buch [Graeme Rocher: The Definitive Guide to Grails, apress 2007] und als kurze Einführung in [Dierk König et al.: Groovy in Action, Manning 2006]. Online verfügbar sind auch ein Grails-Podcast und ein Screencast. Ein deutsches Buch ist in Arbeit.

Viele Aspekte wären noch zu beleuchten, wie die bidirektionale Referenzen im Domänenmodell, komplexe Queries mit dem CriteriaBuilder, Testunterstützung, Services und Transaktionen, Scheduling und Jobs, Ajax, Konfigurationen für Development, Staging und Produktion, Bootstrapping von Testdaten, Schema-Entwicklung, Internationalisierung, Filter, Security und die interaktive Konsole zur Live-Manipulation der Server-Objekte. Diese Dinge sind schon in der jetzigen Version 0.2.2 implementiert und die Version 0.3 steht kurz bevor. Die Roadmap bis 0.6 ist online einsehbar. Diese wird voraussichtlich auch den Funktionsumfang der Version 1.0 bilden.

Grails hat es geschafft, zwei Dinge miteinander zu verbinden, die lange unvereinbar schienen: die Mächtigkeit der Java-Enterprise-Plattform mit dynamischen Ausdrucksmöglichkeiten. Der Software-Stack von Grails besteht aus erprobten Java-Komponenten mit hoher Stabilität und Performanz. Darauf aufbauend gewährt ein flacher Groovy Layer einen neuen, vereinfachten Zugang zu dem darunter liegenden Engineering-Know-how. Viel Spaß!

Dierk König ist Softwareentwickler bei der Canoo Engineering AG in Basel, Committer in den Projekten Groovy und Grails sowie Autor des Buchs „Groovy in Action“.
Geschrieben von
Dierk König
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.