fuhrparkverwaltung - architekturbeschreibunggeschäftslogikschicht: die geschäftslogikschicht ist...
TRANSCRIPT
Fuhrparkverwaltung
- Architekturbeschreibung -
im Studiengang Application Architectures / Master of Science
an der Fakultät Wirtschaftsinformatik der Hochschule Furtwangen University
vorgelegt von:
Michael Hupe, Florian Kalisch, Andreas Lauer,
Denis Radjenovic
Vorlesung : Softwarearchitektur
Betreuer : Prof. Dr. Ulf Schreier
eingereicht am : 30.06.2012 / Sommersemester 2012
I
Inhaltsverzeichnis
1 Einführung und Ziele ......................................................................................................... 1
1.1 Ziele des Dokuments ................................................................................................... 1
1.2 Architektonische Ziele ................................................................................................. 1
2 Allgemeine Festlegungen ................................................................................................... 2
2.1 Festlegung der Schichten.............................................................................................. 2
2.1.1 Client-Präsentationsschicht .................................................................................... 2
2.1.2 Play Framework 2.0 .............................................................................................. 3
2.1.3 Datenhaltungsschicht ............................................................................................ 3
2.2 Festlegung der Sprachen .............................................................................................. 3
2.3 Festlegung der Systeme ................................................................................................ 3
2.3.1 Systeme zur Entwicklung....................................................................................... 3
2.3.2 Systeme zum Betrieb ............................................................................................. 4
2.4 Festlegung der Bibliotheken ......................................................................................... 4
2.5 Festlegung der Struktursicht ......................................................................................... 5
2.6 Projekt- und Paketstruktur ........................................................................................... 5
3 Architekturrichtlinien ......................................................................................................... 7
3.1 Allgemein ................................................................................................................... 7
3.2 Präsentationslogik ....................................................................................................... 8
3.2.1 Templating allgemein ............................................................................................ 8
3.2.2 Scala Templating................................................................................................... 9
3.2.3 Einsatz von JavaScript ........................................................................................... 9
3.2.4 Tabellendarstellung per jQuery ............................................................................ 10
3.2.4.1 Definition der Daten in Form eines DataSets ................................................. 10
3.2.4.2 Definition der Tabellenstruktur ...................................................................... 11
3.2.4.3 Formatierung des Erscheinungsbildes der Tabelle ........................................... 12
3.2.4.4 Definition eines Handlers zur Abfrage selektierter Zeilen ................................ 13
3.2.5 Google Maps Integration ..................................................................................... 14
3.2.6 CSS .................................................................................................................... 15
3.2.7 HTTP-Routing und Controller-Handling .............................................................. 15
3.3 Fachlogik .................................................................................................................. 16
3.3.1 Fassade-Muster ................................................................................................... 16
3.3.2 Strategie-Muster .................................................................................................. 17
3.4 Datenzugriffslogik ..................................................................................................... 18
3.4.1 Finder ................................................................................................................. 19
II
3.5 Änderbarkeit ............................................................................................................. 20
3.6 Andere technische Richtlinien .................................................................................... 20
3.6.1 Code Konventionen ............................................................................................ 20
3.6.2 Flash, Session und Cache .................................................................................... 20
3.6.3 Testdaten ............................................................................................................ 22
4 Dekomposition ................................................................................................................ 23
4.1 Struktursicht .............................................................................................................. 23
4.1.1 Komponentenübersicht Fuhrparkverwaltung ........................................................ 23
4.1.2 Benutzer-Komponente ......................................................................................... 24
4.1.3 Reservierungs-Komponente ................................................................................. 24
4.1.4 Fahrzeug-Komponente ........................................................................................ 25
4.1.5 Rollen-Komponente ............................................................................................ 25
4.1.6 Führerschein-Komponente .................................................................................. 26
4.1.7 Standort-Komponente ......................................................................................... 26
4.2 Ablaufsicht ................................................................................................................ 27
4.3 Verteilungssicht ......................................................................................................... 28
4.3.1 Standalone Mode ................................................................................................ 28
4.3.2 Erstellen einer Standalone Version der Applikation ............................................... 28
4.3.3 Weitere Deploy-Möglichkeiten ............................................................................ 28
4.4 Datensicht ................................................................................................................. 29
5 Querschnittliche Systemaufgaben ..................................................................................... 30
5.1 Sicherheit .................................................................................................................. 30
5.2 Transaktionsmanagement .......................................................................................... 30
5.3 Protokollierung ......................................................................................................... 31
5.4 Ausnahmebehandlung ............................................................................................... 32
5.5 JNDI ........................................................................................................................ 34
6 Alternativen..................................................................................................................... 35
6.1 jQuery ....................................................................................................................... 35
6.2 Play Framework ........................................................................................................ 35
6.2.1 Business-Sicht ..................................................................................................... 35
6.2.2 Technische Sicht ................................................................................................. 36
6.2.3 Entwickler-Sicht .................................................................................................. 37
6.2.3.1 Entwurfsmuster ............................................................................................ 37
6.2.3.2 Extreme Zustandslosigkeit ............................................................................. 37
6.2.3.3 Vergleich mit JSF .......................................................................................... 38
6.2.4 Fazit ................................................................................................................... 39
III
Abbildungsverzeichnis
Abbildung 1: Schichtenarchitektur ............................................................................................ 2
Abbildung 2: Architekturübersicht ............................................................................................ 5
Abbildung 3: Paketstruktur ...................................................................................................... 5
Abbildung 4: Ablauf eines HTTP-Request ................................................................................ 7
Abbildung 5: Abstrakte Projektstruktur ..................................................................................... 8
Abbildung 6: Attributänderungen ........................................................................................... 20
Abbildung 7: Komponentenübersicht Fuhrparkverwaltung ...................................................... 23
Abbildung 8: Benutzer-Komponente ...................................................................................... 24
Abbildung 9: Reservierungs-Komponente ............................................................................... 24
Abbildung 10: Fahrzeug-Komponente .................................................................................... 25
Abbildung 11: Rollen-Komponente ........................................................................................ 25
Abbildung 12: Führerschein-Komponente .............................................................................. 26
Abbildung 13: Standort-Komponente ..................................................................................... 26
Abbildung 14: Sequenzdiagramm „Reservieren eines Fahrzeuges“ .......................................... 27
Abbildung 15: Datensicht ...................................................................................................... 29
Abbildung 16: View-Kompositum .......................................................................................... 37
Tabellenverzeichnis
Tabelle 1: Festlegung der verwendeten Sprachen ....................................................................... 3 Tabelle 2: Tabellenkonventionen in JPA ................................................................................. 19 Tabelle 3: Logging Level und ihr Einsatz ................................................................................ 31 Tabelle 4: Vergleich JSF und Play .......................................................................................... 38
IV
Listing-Verzeichnis
Listing 1: Einbindung der main.scala.html ................................................................................ 9
Listing 2: Definition der übergebenen Parameter ....................................................................... 9
Listing 3: Einbinden von Parameter innerhalb der Views ........................................................... 9
Listing 4: Prüfung ob DOM aufgebaut ist ................................................................................. 9
Listing 5: Einbinden des Datepickers ........................................................................................ 9
Listing 6: Exemplarische JavaScript DataSource Definition ..................................................... 10
Listing 7: Beispiel-DataSet anhand der Reservierungsdaten ..................................................... 11
Listing 8: jQuery Tabellenstruktur .......................................................................................... 11
Listing 9: Verankerung der DataTables im Html ..................................................................... 12
Listing 10: Setzen der Zeilenmarkierung ................................................................................. 13
Listing 11: Definition des Click Handlers ................................................................................ 13
Listing 12: Einbindung der Google Maps-API ........................................................................ 14
Listing 13: Funktion initialize() .............................................................................................. 14
Listing 14: Einbindung der Map in den HTML-Code .............................................................. 14
Listing 15: Funkion calcRoute() ............................................................................................. 14
Listing 16: Aufruf der Funktion calcRoute() ............................................................................ 15
Listing 17: Abbildung von HTTP-Routen auf Controller-Methoden ......................................... 15
Listing 18: Abstrakte Controller-Implementierung ................................................................... 16
Listing 19: Beispiel einer Fassaden-Klasse ............................................................................... 17
Listing 20: Beispiel eines Strategie-Interfaces........................................................................... 17
Listing 21: Beispiel einer Strategie-Implementierung ............................................................... 18
Listing 22: Beispiel der Verwendung eines Strategie-Interfaces ................................................. 18
Listing 23: Beispiel einer Finder-Implementierung .................................................................. 19
Listing 24: Flash-Beispiel ....................................................................................................... 21
Listing 25: Session-Beispiel .................................................................................................... 21
Listing 26: Cache-Beispiel ...................................................................................................... 21
Listing 27: Beispiel um Testdaten anzulegen ........................................................................... 22
Listing 28: Aufruf zum Starten eines Webservers .................................................................... 28
Listing 29: Erzeugen eines Zip-Files (enthält alle notwendigen JAR-Files)................................ 28
Listing 30: Authensisierungs-Annotation ................................................................................ 30
Listing 31: Beispiel @Transactional ........................................................................................ 30
Listing 32: Beispiel TxRunnable ............................................................................................. 30
Listing 33: Beispiel Transaktion mit try-finally ........................................................................ 31
Listing 34: Beispiel für Ausnahmebehandlung ......................................................................... 33
Listing 35: Beispiel Log an Throw .......................................................................................... 33
Listing 36: Beispiel "checked Exception"................................................................................. 33
Listing 37: Beispiel Destruktives Wrapping ............................................................................. 33
Listing 38: Datenbank über JNDI veröffentlichen ................................................................... 34
1
1 Einführung und Ziele
Dieses Dokument beschreibt die Architektur des Systems Fuhrparkverwaltung. Dabei werden die
Bausteine und deren Zusammenwirken vorgestellt, zu verwendende Architektur- und Entwurfs-
muster hervorgehoben, getroffene Entscheidungen begründet sowie dazu existierende Alternati-
ven vorgestellt.
1.1 Ziele des Dokuments
Die hier vorliegende Architekturbeschreibung gibt den Programmierern festgesetzte Richtlinien
vor, anhand welcher die Entwicklung des Systems auszurichten ist.
1.2 Architektonische Ziele
Dieses Unterkapitel stellt die architektonischen Zielsetzungen vor, unter welchen die Anwendung
entworfen wird. Die nachfolgende Auflistung gibt darüber Auskunft:
1. Komponenten und Wiederverwendbarkeit
Beim Design der Anwendung soll, im Rahmen der Dekomposition, die Aufteilung der
Funktionalitäten in Module erfolgen, welche als Bausteine für die Komponenten dienen.
Diese sollen eine starke Kohäsion und eine lose Kopplung (nach IEEE 610) aufweisen.
Für eine Verbesserung der Wiederverwendbarkeit ist die lose Kopplung auf Data Coup-
lin-Niveau anzustreben. Der Einsatz von Entwurfsmustern kann sich ebenfalls positiv
auswirken.
2. Einsatz von Entwurfsmustern
Der sinnvolle und zielgerichtete Einsatz von Entwurfsmustern soll angestrebt werden. Ein
blinder Einsatz dieser ist jedoch zu vermeiden, da es eventuell bessere Lösungen für den
konkreten Fall geben kann.
3. Flexibilität für zukünftige Ergänzungen
Eine Flexibilität für zukünftige Ergänzungen ist wichtig, um schnell auf sich ändernde
Anforderungen reagieren zu können. Erreicht wird das durch die zwei vorhergehend be-
schriebenen Punkte und eine vorausschauende Programmierart.
2
2 Allgemeine Festlegungen
Dieses Kapitel beschreibt die festgelegten Schichten, verwendete Sprachen, zum Einsatz kom-
mende Bibliotheken und Systeme. Dabei wird auf allgemeine Richtlinien der Architektur einge-
gangen. Diese umfassen sowohl die Projektstruktur, als auch Besonderheiten im Ablauf und der
Verteilung. Falls sich mindestens die Minor-Version einer eingebundenen Bibliothek ändert,
muss diese vor dem Produktiv-Einsatz in einem Test-System ausgiebig analysiert werden.
2.1 Festlegung der Schichten
Einen ersten groben Überblick über die Anwendungsarchitektur gibt Abbildung 1. Die Architek-
tur-Muster, Komponenten des Systems sowie deren Abhängigkeiten werden aufgezeigt. Wie in
Abbildung 1 zu sehen ist, teilt sich die gesamte Anwendung in fünf Schichten auf.
Abbildung 1: Schichtenarchitektur
Diese Schichten sind in den nachfolgenden Teilkapiteln ausführlicher beschrieben.
2.1.1 Client-Präsentationsschicht
Die Client-Präsentationsschicht dient zur Eingabe und Darstellung von Daten für den Benutzer.
Bei der Anwendung „Fuhrparkverwaltung“ dient ein JavaScript-fähiger Browser als Darstel-
lungsmedium zur Anzeige der Bildschirmmasken (Views). Die Bildschirmmasken sind HTML-
Dateien, deren Funktionalität durch JavaScript-Funktionen erweitert sein kann. Um ein einheit-
liches Look & Feel zu erreichen, kommt ein individuelles für die Anwendung entwickeltes CSS-
Design zum Einsatz. Die folgende Liste zählt alle verwendeten JavaScript-Bibliotheken auf:
jQuery (Version 1.7)
jQuery UI (Version 1.8)
DataTables (Version 1.9) Plug-In für jQuery UI
3
jQuery UI Timepicker (Version 0.3)1 Plug-In für jQuery UI
Google Maps API (Version 3)
2.1.2 Play Framework 2.0
Das Play Framework 2.0 stellt die zentrale Architektur der Anwendung zur Verfügung, welches
auf dem MVC-Muster basiert (Kapitel 3.1). Das Framework selber unterteilt sich in drei Schich-
ten. Wie in Abbildung 1 zu sehen ist, sind das folgende Schichten:
Server-Präsentationsschicht: Um dynamische Views zu erstellen, bietet das Play Framework
eine Template-Notation, die auf der Sprache Scala basiert.
Geschäftslogikschicht: Die Geschäftslogikschicht ist in Java mit simplen POJOs (Plain Old
Java Objects) umgesetzt.
Datenzugriffsschicht: Das Management der Daten erfolgt nicht durch einen Zugriff direkt
auf die Datenbank, sondern mit Hilfe des Java Persistence API konformen relationalen Map-
pers EBeans.
2.1.3 Datenhaltungsschicht
Für das Speichern und Laden der Daten ist eine PostgreSQL Datenbank in der Version 9.1.3
zuständig.
2.2 Festlegung der Sprachen
Folgende Tabelle fasst alle verwendeten Sprachen zur Entwicklung der Anwendung zusammen:
Sprache Verwendung
Java Geschäftslogik
Scala View-Templating
JavaScript, CSS, HTML Gestaltung und Funktionalität der Views
Tabelle 1: Festlegung der verwendeten Sprachen
2.3 Festlegung der Systeme
In diesem Kapitel werden die verwendeten Systeme zur Entwicklung und für den Betrieb der
Anwendung beschrieben. Das Play Framework bringt Techniken, Mechanismen und Systeme
mit, welche die Entwicklung vereinfachen und den Betrieb der Anwendung gewährleisten.
2.3.1 Systeme zur Entwicklung
Eclipse (Version 3.7 „Indigo“)
Play erlaubt eine Projekterstellung über die Konsole und auch eine Programmierung ohne jegli-
che IDE wäre möglich. Da eine IDE einige Vorzüge (z.B. Code-Completion, Debugging und
Syntax-Highlighting) mit sich bringt, bietet Play die Möglichkeit ein Projekt in ein Eclipse-Projekt
zu konvertieren.
1 http://fgelinas.com/code/timepicker/
4
Subversion (Version 1.7)
Die Versionspflege des Projektes erfolgt mittels Subversion. Die Verwaltung der Version kann
direkt über das Plugin „Subclipse“ in der Eclipse IDE stattfinden.
Simple Build Tool (SBT 0.11)
Dies ist ein auf Apache Ivy basierendes Dependency-Management System. Damit werden Ab-
hängigkeiten zu Bibliotheken (ähnlich Maven) verwaltet.
2.3.2 Systeme zum Betrieb
JBoss Netty (3.2)
JBoss Netty ist ein automatisch von Play eingebundener und vorkonfigurierter Application-
Server. Dieser unterstützt Features, wie z.B. Hot-Deployment und die Anzeige von Kompilie-
rungsfehlern im Browser.
PostgreSQL Datenbank (Version 9.1)
Für das Projekt kommt die PostgreSQL Datenbank zum Einsatz. Diese ist frei verfügbar und
kann über ein beiliegendes Administrations-Tool verwaltet werden.
2.4 Festlegung der Bibliotheken
Die Bibliotheken sollen an dieser Stelle nur kurz aufgelistet und beschrieben werden. Ihre Ver-
wendung ist in Kapitel 3 ausführlicher beschrieben.
jQuery (Version 1.7)
Dieses JavaScript-Framework ist die Basis für die Bibliotheken jQuery UI und DataTables.
jQuery UI (Version 1.8)
Erweitert jQuery um die Möglichkeit, Benutzeroberflächen zu gestalten und mit Funktionalität
zu füllen.
DataTables (Version 1.9)
Hierbei handelt es sich um ein Plugin für jQuery zur Darstellung von Tabellen.
jQuery UI Timepicker (Version 0.3)
Ermöglicht eine komfortable Zeiteingabe in die Views.
Google Maps API (Version 3)
Um eine Routenberechnung für die Reservierungen zu ermöglichen, kommt die Google Maps
API zum Einsatz.
JDBC Treiber (Level 4) für die PostgreSQL Datenbank (Version 9.1)
Notwendiger Treiber für den Zugriff auf die Datenbank.
5
2.5 Festlegung der Struktursicht
Die Struktursicht dient der Verdeutlichung, welche Komponenten in welcher Schicht zum Ein-
satz kommen (siehe Abbildung 2).
Präsentationssicht (Client)
Komponente Fuhrparkverwaltung
jQuery 1.7
Präsentationssicht(Server)
Datenhaltung PostgreSQL 9.1DB Schema
EBeans 2.7
Google Maps 3.0
Scala-Templating
jOuery UI 1.8
jOuery UI Timepicker 0.3
DataTables 1.9
Abbildung 2: Architekturübersicht
2.6 Projekt- und Paketstruktur
In diesem Kapitel wird die Projektstruktur der Anwendung detailliert dargestellt. Eine dazu gehö-
rende visuelle Übersicht gibt die Abbildung 3.
app
controllers
forms
security
model
model.komponente
entities
facades
views
views.komponente
conf public
routes app conf images javascript stylesheets
libs logs
Abbildung 3: Paketstruktur
6
In dem Ordner „app“ sind die Komponenten der Anwendung abgelegt. Die Komponenten unter-
teilen sich in die Pakete „models“, „controllers“, „views , „forms“, „security“ und „context“.
Eine Besonderheit stellt hierbei die Datei „Global.java“ dar, die sich im Root-Ordner „app“ be-
findet. Mit dieser Datei werde die Testdaten in die Datenbank geschrieben. Der Ort ist fest vom
Play Framework vorgeschrieben und lässt sich nicht verändern. Sollte diese Datei angepasst wer-
den, ist darauf zu achten das ihre Position beibehalten wird.
Im „models“-Paket liegen die Unterpakte für die verschiedenen Entitäts-Komponenten („reserva-
tion“, „user“ und „vehicle“). Eine Entität besteht aus den Paketen „entities“ und „facades“. „en-
tities“ ist prinzipiell ein Bestandteil einer Entität, wohingegen „facades“ nicht bei jeder Entität
vorhanden sein muss. Unter „entities“ liegt die Entitäten-Klasse der Komponente. Unter
„facades“ befindet sich eine Fassaden-Klasse, die statische Methoden für komplexe Funktionali-
täten zur jeweiligen Entität bereitstellt.
Unter „controllers“ liegen die einzelnen Controller-Klassen der Ansichten (Views). Diese Klassen
lassen sich nicht in eigene Pakete unterteilen. Dies scheint eine Restriktion des Play Frameworks
zu sein. Zu jedem HMTL-Formular gehört auch eine Form-Klasse die sich im Unterpaket
„forms“ befindet, welche die Anfrage auf diese Klasse abbildet und damit vom Controller ausge-
wertet werden kann.
In den „views“ liegen die Templates für die verschiedenen Ansichten. Unterteilt werden diese in
„admin“, „settings“ und „reservation“. Das Pakte „admin“ beinhaltet alle Ansichten die nur von
Rolle Administrator aufgerufen werden können, wohingegen „settings“ und „reservation“ für alle
Rollen zugänglich sind.
Weitere wichtige Ordner innerhalb des Projekts sind „conf“ mit den wichtigen Konfigurationsda-
teien und „public“, welches die zusätzlichen Bibliotheken beherbergt. Hierfür ist das „public“-
Verzeichnis noch in „stylesheets“ für CSS-Dateien, „javascripts“ für alle verwendeten Java Script
Bibliotheken (z.B. jQuery) und in „images“ für notwendige Bilder.
Alle verwendeten Java-Bibliotheken liegen im Verzeichnis „lib“. Protokollierungen zur Laufzeit
der Anwendung werden in dem Verzeichnis „logs“ abgelegt.
7
3 Architekturrichtlinien
3.1 Allgemein
Wie bereits erwähnt verwendet das Play Framework das MVC-Muster als zentrales Architektur-
muster. Das Sequenzdiagramm in
Abbildung 4 beschreibt den Ablauf eines HTTP-Request bis zu einem HTTP-Response und das
Zusammenspiel zwischen Model, View und Controller.
An dieser Stelle soll erwähnt werden, dass sich das Play Framework bei der Client-Server-
Kommunikation an den REST-Standard hält. Dabei verläuft diese Kommunikation komplett
zustandslos. Einer der Vorteile der zustandslosen Kommunikation ist die Skalierbarkeit der An-
wendung, zum Beispiel das Verteilen der Anfragen auf mehrere Server. Ein weiterer Vorteil ist
die Repräsentation der Daten in unterschiedlichen Formaten (HTML. JSON oder XML), die
sich je nach Bedarf anpassen lassen.
Browser routes ViewController Model
http Request
weiterleiten an Controller
update Model
retrieve Model
Überprüfung der übergeben Daten
render View (Übergabe der Daten)
http Response
Datenbank
synchonisieren
synchronisieren
Abbildung 4: Ablauf eines HTTP-Request
Das folgende Paket- und Klassendiagramm (Abbildung 5) zeigt eine abstrakte Struktur des Pro-
jektes. Daraus sollen die Beziehungen und Kardinalitäten der Komponenten und Klassen ersicht-
lich werden, welche bei der weiteren Entwicklung unbedingt eingehalten werden sollte.
8
Abbildung 5: Abstrakte Projektstruktur
3.2 Präsentationslogik
Im Bereich der Präsentationsschicht sind viele Richtlinien wie die Views aufgebaut sind und ge-
staltet werden. Jede Komponente hat dabei ihre eigenen Views („views.Komponentenname“). In
den nächsten Unterkapiteln werden genaueren Richtlinien und Vorgaben zur Gestaltung der
Views beschreiben. Dies soll einen gewissen Standard fördern und die Wartbarkeit verbessert.
3.2.1 Templating allgemein
Alle Views, bis auf „login.scala.html“ importieren die „main.scala.html“, da sie selber nur der
Content für den jeweiligen Bereich beinhalten.
Import der main-Datei geschieht folgender Maßen:
@main {
<!-- Content -->
}
9
Listing 1: Einbindung der main.scala.html
In der „main.scala.html“ wird der Header (Banner und Menü) sowie Footer gepflegt. Weiterhin
werden hier auch die Anmeldedaten (Benutzer, Rolle und Restriktion) aus der Session ausgelesen
und angezeigt.
3.2.2 Scala Templating
Am Anfang werden alle vom Controller übergebenen Parameter in der View definiert, damit
später per Annotation auf diese zugegriffen werden kann. Beispiele dafür sehen wie folgt aus.
Definition der übergebenen Parameter:
@(Parameter: Type, Parameter: List[Type])
Listing 2: Definition der übergebenen Parameter
Verwendung des Parameters:
@Parameter
@Parameter.get("Parameter")
Listing 3: Einbinden von Parameter innerhalb der Views
In der gesamten View kann nach der Definition der Parameter auf die Daten zugegriffen werden.
3.2.3 Einsatz von JavaScript
Der Einsatz von JavaScript dient der dynamischen Veränderung von Inhalt, Struktur und Layout
einer HTML Seite durch die Manipulation des korrespondierenden DOM-Baums. Auf diese
Funktionalität wird auch in dieser Anwendung zurückgegriffen, jedoch mit Hilfe der Library
jQuery, welche viele Best-Practices kapselt, eine browserübergreifende Kompatibilität gewährleis-
tet und eine vereinfachte Handhabung von JavaScript ermöglicht. Da JavaScript auf dem Client
abläuft, muss die hier entwickelte Anwendung JavaScript-Code generieren, welcher dann vom
Browser ausgeführt wird.
Grundsätzlich ist als Richtlinie bei der Verwendung von jQuery-Code zu beachten, dass dieser
immer innerhalb des Funktionskörpers aus Listing 4 gesetzt wird. Dies gewährleistet, dass jegli-
cher Zugriff auf den DOM-Baum erst geschieht, wenn dieser vollständig aufgebaut ist.
$(document).ready(function() {
// Handler for .ready() called.
});
Listing 4: Prüfung ob DOM aufgebaut ist
Der Einsatz von JavaScript erfolgt wie auch bei JSF und JSP direkt in der HTML-Datei und soll-
te direkt vor dem zu veränderten Objekt platziert werden.
<script>
$(function() {
$.datepicker.setDefaults($.datepicker.regional[""]);
$("#startdatepicker").datepicker($.datepicker.regional["de"]);
});
</script>
Listing 5: Einbinden des Datepickers
10
Bei größeren Scripten werden diese am Anfang, nach dem „Main-Import“, definiert oder in eine
separate Datei unter „public/javascripts“ abgelegt und eingebunden. Auf die Einbindung der
Tabelle per JavaScript wird im nächsten Absatz noch einmal genauer eingegangen, da diese eines
der Hauptelemente der Anwendung ist.
3.2.4 Tabellendarstellung per jQuery
Die Tabelle ist eines der Hauptobjekte der Anwendung und wird in vielen Views zur Darstellung
verwendet. Die Tabelle wird immer am Anfang der View definiert. Als Darstellungskomponente
für die Tabellenstrukturen wird auf das jQuery Plugin DataTables2 gesetzt.
Die Handhabung von Tabellen teilt sich in die nachfolgenden vier Teile auf:
1. Definition der Daten in Form eines DataSets
2. Definition der Tabellenstruktur und die Position dieser innerhalb der HTML Datei
3. Formatierung des Erscheinungsbildes der Tabelle
4. Definition eines geeigneten Handlers zum Auslesen des selektierten Datensatzes
3.2.4.1 Definition der Daten in Form eines DataSets
Die Daten müssen vom Server zur Anzeige auf den Client übertragen werden. Dazu sind prinzi-
piell mehrere Arten möglich, das DataSet zur Verfügung zu stellen.
1) Definition der Daten in Form eines JavaScript Arrays
2) Zugriff auf einen AJAX-DataSource
3) Datenübertragung mittels JASONP Aufruf
Diese Anwendung setzt auf die Datendefinition mittels JavaScript-Array (d.h. die erste Umset-
zungsmöglichkeit), da auf nicht gebrauchten Overhead wie AJAX verzichtet werden soll. Die
Daten sind dabei im Klartext auf der Client-Seite sichtbar. Sollten sich die Anforderungen zu-
künftig dahingehend ändern, dass die Daten nicht im Quellcode der HTML-Seite sichtbar sein
dürfen, muss dies über ein geeignetes DataSet-Handling gelöst werden. Weiterhin kann es zu
Problemen kommen, wenn die Anzahl anzuzeigender Daten die geschätzte Anzahl übersteigt.
Der Einstieg in die DataSet-Definition soll anhand eines exemplarischen, sich selbst erklärenden,
Datensatzes verdeutlicht werden, welcher nachfolgend dargestellt ist und stellvertretend für den
realen, generierten, Code stehen kann.
var dataSet = [
['Zeile1Spalte1', 'Zeile1Spalte2','Zeile1Spalte3','Zeile1Spalte4'],
['Zeile2Spalte1', 'Zeile2Spalte2','Zeile2Spalte3','Zeile2Spalte4']
];
Listing 6: Exemplarische JavaScript DataSource Definition
Zur Generierung wird auf die Scala-Notation zurückgegriffen, bei welcher mit einer for-Schleife über die anzuzeigenden Datenzeilen iteriert und jede relevante Spalte ausgegeben wird. Dieses Vorgehen zeigt das nachfolgende Listing.
2 http://datatables.net/
11
var aDataSet = [
@for(reservation <- reservationList) {
@if(reservation.getReservedBy().getId() == Long.valueOf(
session.get("user_id"))) {
['@reservation.getId()',
'@if(reservation.getPermittedBy() == null){offen} else {genehmigt}',
'@reservation.getPurpose().getType()',
'@reservation.getStartLocation().getAddress().getName()',
'@reservation.getEndLocation().getAddress().getName()',
'@reservation.getReservationStart()',
'@reservation.getReservationEnd()',
'@reservation.getVehicle().getName()',
'@reservation.getReservationComment().getContent()'
],}
}
];
Listing 7: Beispiel-DataSet anhand der Reservierungsdaten
Während bei den Spalten ab Spalte 2 eine beliebige Reihenfolge gewählt werden kann, so muss
unbedingt beachtet werden, dass die erste Spalte die ID der korrespondierenden Tabelle enthält.
3.2.4.2 Definition der Tabellenstruktur
Dieses Unterkapitel beschreibt die Konfiguration der Tabellen Komponente, welche eine Vielzahl
an möglichen Szenarien abdeckt und somit angepasst werden muss. Die folgenden Betrachtun-
gen beziehen sich auf das nachfolgende Listing.
1 $('#dynvehicletable').html( '<table cellpadding="0"
2 cellspacing="0" border="0" class="display"
3 id="vehicletable"></table>' );
4 $('#vehicletable').dataTable( {
5 "bJQueryUI": true,
6 "sPaginationType": "full_numbers",
7 "aaData": aDataSet,
8 "bScrollInfinite": true,
9 "bScrollCollapse": true,
10 "sScrollY": "200px",
11 "aoColumns": [
12 { "sTitle": "ID", "sClass": "left", "bVisible": false},
13 { "sTitle": "Name", "sClass": "left"},
14 { "sTitle": "Führerscheinklasse", "sClass": "left"}
15 ,
16 { "sTitle": "Kilometerstand", "sClass": "left"},
17 { "sTitle": "Monate in Benutzung", "sClass": "left" },
18 { "sTitle": "In Benutzung", "sClass": "left" },
19 ],
20 // sets the vehicle id into the id attribute of <tr>
21 "fnRowCallback": function( nRow, aData, iDisplayIndex ) {
22 $(nRow).attr("id", aDataSet[iDisplayIndex][0]);
23 return nRow;
24 }
25 });
Listing 8: jQuery Tabellenstruktur
12
Als Richtlinie sollte bei jeder Tabelle, die neue hinzugefügt wird, die folgende (sich in drei Teile
gliedernde) Konfiguration vorgenommen werden.
1. Zeilen 5 bis 10:
Diese Zeilen können ohne Anpassung übernommen werden, denn sie stellen ein einheit-
liches Erscheinungsbild der Tabellen sicher. Einzige Ausnahme bildet Zeile 7, welche das
anzuzeigende DataSet als Übergabe erwartet.
2. Zeilen 11 bis 19:
In diesem Bereich erfolgt die Definition der Spalten, welche von den anzuzeigenden Da-
ten abhängen. Zusätzlich wird die erste ID Spalte ausgeblendet („bVisbible“: false) und
die Textausrichtung in der Spalte auf linksbündig gesetzt („sClass“: left).
3. Zeilen 21 bis 23:
Innerhalb dieses Teilbereichs wird die CallBack Funktion fnRowCallBack definiert, wel-
che beim dynamischen Rendern jeder Zeile aufgerufen wird. Jede Zeile bekommt ein At-
tribut id mit dem Wert der Tabellen-ID zugewiesen.
Das folgende Container-Tag (div) ist innerhalb der HTML-Datei zu positionieren und enthält zur
Laufzeit die gerenderte Tabelle.
<div id="dynvehicletable"></div>
Listing 9: Verankerung der DataTables im Html
3.2.4.3 Formatierung des Erscheinungsbildes der Tabelle
Die Formatierung der Tabellen gliedert sich in die Teile
1. Anpassung des mitgelieferten CSS-Designs
2. Definition eines Click Handlers für das dynamische Setzen einer Zeilenmarkierung
Dieses Unterkapitel fokussiert auf den zweiten Punkt und erläutert die Click Handler Definition
näher. Die eigentliche Formatvorgabe für eine selektierte Zeile wird durch CSS festgelegt. Dazu
existiert die Klasse row_selected. Jede Zeile, welche diese Klasse zugewiesen bekommt, wird
als selektiert farblich markiert. Nachfolgendes Listing gibt die Richtlinie vor, wie die Selektier-
Funktionalität umgesetzt werden muss.
13
// Retrieve the datatable object and store it in the variable oTable
oTable = $('#vehicletable').dataTable();
/*--------------------------------------------------------------------
* Function: Click-Event-Handler for the table row (<tr>).
* Description:
* This click handler highlights/dehiglights the clicked
* row and checks the corresponding radio button.
*--------------------------------------------------------------------
*/
oTable.$('tr').click( function(event) {
// remove the existing selection
var theSelectedRadio = oTable.contents().find('.row_selected');
theSelectedRadio.removeClass('row_selected');
// highlight the table row current row
$(this).addClass('row_selected');
// at this point we are on level of the single row (<tr>)
// and we'll retrieve the underlying checkbox
var theCurrentRadio = $(this).contents().find('.tblradio');
theCurrentRadio.attr('checked', true);
});
Listing 10: Setzen der Zeilenmarkierung
3.2.4.4 Definition eines Handlers zur Abfrage selektierter Zeilen
Im Prozess-Kontext der Anwendung werden die Tabellen eingesetzt, um mehrere Daten in struk-
turierter Form darzustellen. Mittels der Selektion von Zeilen können Datensätze ausgewählt
werden und diese gilt es für einen weiteren Ablauf (beispielsweise Bearbeiten, Löschen, etc.) zu
identifizieren. Dazu ist ein Click Handler zu definieren, welcher die selektierten Zeilen anhand
der gesetzten CSS-Klasse (beschrieben in Kapitel 3.2.4.3) bestimmt. Nachfolgendes Listing gibt
hierzu einen Einblick.
/*--------------------------------------------------------------------
* Function: Click-Event-Handler for the button "getSelection"
* Description:
* Defines a event-handler for the click-event of corresponding
* button. It creates a string representation of the selected
* dataset and displays it at the end.
*--------------------------------------------------------------------
*/
$('#deleteVehicle').click( function () {
var $theSelectedRadio = oTable.$('.row_selected').attr('id');
if($theSelectedRadio != null)
{
window.location = "/deleteVehicle/" + $theSelectedRadio;
}
else
{
alert("Bitte waehlen Sie einen Datensatz aus.");
}
});
Listing 11: Definition des Click Handlers
14
3.2.5 Google Maps Integration
Folgende Listings beschreiben schematisch die Einbindung der Google Maps API in die Reser-
vierungs-View.
Um die Google Maps API zu verwenden, muss zunächst einen Remote-Verweis auf die Biblio-
thek erstellt werden.
<script type="text/javascript"
src="https://maps.google.com/maps/api/js?sensor=false">
</script>
Listing 12: Einbindung der Google Maps-API
Der JavaScript Code an sich besteht aus zwei Funktionen. Die Funktion „initialize()“ sorgt für
die Anzeige der Map (Karte) in der View. Dies geschieht durch eine Instanz der Klasse
„google.maps.Map“, die auch auf den Bereich in der View verweist. In der Reservations-View
heißt dieser Bereich „map_canvas“.
function initialize() {
…
//generiert ein MapObjekt
var map = new google.maps.Map(document.getElementById('map_canvas'),
myOptions);
…
}
Listing 13: Funktion initialize()
<div id="map_canvas"></div>
Listing 14: Einbindung der Map in den HTML-Code
Zur Berechnung der Route, dient die Funktion „calcRoute()“. Die Parameter „startingPoint“ und
„endPoint“ geben den Start und das Ziel der Route an. Gewonnen werden diese Parameter aus
den beiden Eingabefeldern „startLocation“ und „endLocation“ der View.
function calcRoute() {
//berechnet die route mit Hilfe eines startingPoint und endPoint
var endPoint = document.getElementById('endLocation').value;
var request = {
origin: startingPoint,
destination: endPoint,
travelMode: google.maps.DirectionsTravelMode.DRIVING
};
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
}
});
}
Listing 15: Funkion calcRoute()
Nach jeder Eingabe des Zielortes, erfolgt eine Neuberechnung der Route in der Map. Damit das
geschieht wird bei jeder Änderung des Zielorts (Event „onchange“) die Funktion „calcRoute()“
ausgeführt.
15
<li>
@select(step1Form("endLocation"),
options(models.reservation.entities.Location.list()),
'_label -> "Wo endet die Fahrt?", '_showConstraints -> false,
'onchange -> "calcRoute()")
</li>
Listing 16: Aufruf der Funktion calcRoute()
3.2.6 CSS
Alle CSS-Files werden unter „Public/Stylesheets“ abgelegt und in der „main.scala.html“ einge-
bunden. Es wird ein eigenständiges CSS entwickelt um das Look & Feel der Anwendung zu ver-
bessern und vereinheitlichen. Weiterhin kommt es zur Einbindung von eigenständigen CSS-
Dateien für die Datatables und jQuery UI Elemente.
In den Views selber ist es nicht gestattet CSS-Code direkt einzubinden. CSS-Elemente müssen
aussagekräftige Bezeichnungen besitzen.
3.2.7 HTTP-Routing und Controller-Handling
Alle Seiten, die über den Webbrowser erreicht werden sollen müssen unter „conf/routes“ einge-tragen werden und auf die entsprechende Controller-Funktion verweisen. Die Einbindung erfolgt
Beispielhaft wie im
Listing 17.
GET /URI controllers.ControllerName.controllerMethod1()
POST /URI controllers.ControllerName.controllerMethod2()
GET /URI/:id controllers.ControllerName.controllerMethod3(id:Long)
Listing 17: Abbildung von HTTP-Routen auf Controller-Methoden
Im Controller wird geregelt was dann im speziellen Fall mit der REST-Anfrage geschieht und
welche Daten an die View übertragen werden sollen.
Folgendes Listing zeigt die beispielhafte Implementierung eines Controllers. Zur Vereinfachung
der Auswertung von Formulareingaben bietet Play eine Kapselung der HTTP-Anfrage in eine
extra hierfür implementierte Form-Klasse. Durch diese Funktionalität werden die jeweiligen
Formularfelder auf die entsprechenden Attribute der Form-Klasse abgebildet. Bevor mit der
Form-Klasse im Controller gearbeitet werden kann, muss diese auf Eingabefehler überprüft wer-
den. Das kann über die Methode „hasErrors()“ realisiert werden. Als Rückgabewert dient eine
View.
16
public class ControllerName extends Controller {
static Form<FormClass> formObject = form(FormClass.class);
public static Result controllerMethod1() {
return ok(view.render(param1 ...));
}
public static Result controllerMethod2() {
Form< FormClass > submittedForm = formObject.bindFromRequest();
if (submittedForm.hasErrors()) {
return redirect(
routes.ControllerName.controllerMethod1());
}
return ok(view.render(param1 ...));
}
public static Result controllerMethod3(Long id) {
return ok(view.render(param1 ...));
}
}
Listing 18: Abstrakte Controller-Implementierung
3.3 Fachlogik
In diesem Kapitel sollen Besonderheiten der Fachlogik erläutert werden, wie z.B. der Einsatz von
Entwurfsmustern. Grundsätzlich ist der Einsatz von Entwurfsmustern bevorzugt, da diese von
Entwicklern in der Regel beherrscht werden und bekannt sind. Durch deren Einsatz kann eine
abstrakte Beschreibung von Problemen und Lösungen erfolgen. Jedoch sollte nicht jede Ge-
schäftsfunktion in ein Muster gepresst werden, wenn die Komplexität dadurch erhöht wird oder
die Lesbarkeit und Wartbarkeit des Codes darunter leiden.
3.3.1 Fassade-Muster
Der Sinn eines Fassade-Musters besteht grundlegend darin, komplexe Funktionalitäten zu kap-
seln und über eine Schnittstelle nach außen bereit zu stellen. Zum Einsatz kommt das Muster in
der Fuhrparkverwaltung bei den Komponenten: Geschäftsfunktionen, die mehrere Entitäten ei-
ner Komponente verwenden, müssen über eine Fassaden-Klasse als öffentliche und statische Me-
thoden angeboten werden. Somit wird erzielt, dass Zugriffe der Präsentationsschicht auf die
Fachlogik über eine zentrale Methode erfolgen. Das erlaubt die Kontrolle und Steuerung dieser
Zugriffe und vereinfacht die Nutzung für den Entwickler. Zu beachten ist, dass jede Komponente
nur über genau eine Fassaden-Klasse verfügen darf.
Eine Ausnahme stellen die einfachen CRUD-Methoden dar: diese können direkt bei den Entitä-
ten implementiert werden, da diese keine komplexen und zu kapselnde Funktionalitäten bieten.
Folgendes Listing zeigt eine Fassaden-Klasse am Beispiel der Reservierungs-Komponente:
17
public class ReservationFacade {
public static List<Reservation> findReservationByLocation(String
location) {
…
}
public static boolean acceptReservation(Long reservationId,
Long permittedById) {
…
}
public static boolean denyReservation(Long id) {
…
}
public static Reservation transformFormToModel(
ReservationStep1Form step1,
ReservationStep2Form step2, User user) {
…
}
public static boolean closeReservation(Long id) {
…
}
public static List<Reservation> findReservationForUser(Long id) {
…
}
public static List<Reservation> findReservationForVehicle(Long id) {
…
}
}
Listing 19: Beispiel einer Fassaden-Klasse
3.3.2 Strategie-Muster
Mit Hilfe des Strategie-Musters, können verschiedene Implementierungen für eine Geschäfts-
funktion angeboten werden. Diese können bei Bedarf ausgetauscht werden und erzeugen so eine
höhere Flexibilität gegenüber zukünftigen Änderungen. Voraussetzung dafür ist die Definition
einer Schnittstelle, welche eine solche Methode anbietet. Hier wird der Mechanismus der Poly-
morphie der Sprache Java ausgenutzt: der Zugriff auf die Methoden der Schnittstelle erfolgt über
eine Java-Interface Klasse. Nun kann jede beliebige Implementierungsklasse benutzt werden, die
dieses Interface implementiert. Bei Bedarf kann nun einfach die Implementierungsklasse ausge-
tauscht werden, ohne dass eine Änderung am Interface erfolgen muss.
Folgendes Listing zeigt die Definition eines solchen Interfaces:
public interface IVehicleFilter {
public List<String> getMatchingVehiclesForUser(
ReservationStep1Form step1, Long userId);
}
Listing 20: Beispiel eines Strategie-Interfaces
18
Nun muss noch eine Implementierungsklasse definiert werden:
public class VehicleFilter implements IVehicleFilter {
public List<String> getMatchingVehiclesForUser(
ReservationStep1Form step1, Long userId) {
…
}
Listing 21: Beispiel einer Strategie-Implementierung
Zum Einsatz kann dieses Strategie-Muster nun beispielsweise in der Fassaden-Klasse der Fahr-
zeug-Komponente kommen:
public class VehicleFacade {
public static final IVehicleFilter VEHICLE_FILTER =
new VehicleFilter();
}
Listing 22: Beispiel der Verwendung eines Strategie-Interfaces
Mit der öffentlichen und statischen Variable VEHICLE_FILTER, kann die Geschäftsfunktion
des Strategie-Musters nun benutzt werden.
3.4 Datenzugriffslogik
Um die Daten zu persistieren, bringt das Play Framework automatisch das Persistenz-
Framework EBeans mit, welches auch in der Anwendung zum Einsatz kommt. Die Entität „ve-
hicle“ soll exemplarisch als Beschreibung für alle weiteren Entitäten der Anwendung dienen.
Prinzipiell erbt jede Entität von der Basisklasse „play.db.ebean.Model“-Basisklasse. Dieses Vor-
gehen ermöglicht es Standard CRUD – SQL-Operationen (CREATE, READ, UPDATE, DE-
LETE) mit Funktionen wie save(), find(z.B. byId() oder all()), delete(), und update() automatisch
zu verwenden. Zudem lassen sich auch komplexere SQL-Befehle gestalten (z.B. Vehic-
le.find.where().eq("name", name).findUnique();).
Die Beziehung zu anderen Entitäten (@OneToOne, @OneToMany, @ManyToOne,
@ManyToMany), sowie die FetchTypes (LAZY und EAGER) und weitere Konfigurationen
lassen sich durch die Annotationen der Java Persistence API (JPA) kontrollieren. Das Einbinden
von „ja-vax.persistence.*“ ermöglicht den Zugriff auf die JPA. Als FetchType wird LAZY ver-
wendet, um bei @ManyToMany oder @OneToMany-Beziehungen die weiteren Entitäten erst
dann zu laden, wenn Sie auch von der Anwendung benötigt werden.
Die CascadeTypes sollen so verwendet werden, dass keine Datenleichen („Orphans“) entstehen.
Außerdem muss jedes ID-Feld einer Entität die Annotation @GeneratedValue erhalten, damit
das Persistenzframework sich um die Erstellung der IDs kümmert.
Die Namen der Tabellen definieren sich durch den Klassennamen der Entitäten. Die Spaltenna-
men der Tabellen durch deren Attribute. Es werden somit keine expliziten Namen vergeben. Hier
greift das Prinzip „Convention over Configuration“. Zu beachten gilt es, dass Entitätsnamen und
Attributnamen folgendermaßen als Tabellen- oder Spaltennamen in der Datenbank abgebildet
werden:
19
Name im Code der Anwendung Tabellen- oder Spaltename in der DB
ichBinCamelcase ich_bin_camelcase
monthInUse month_in_use
Tabelle 2: Tabellenkonventionen in JPA
3.4.1 Finder
Eine Besonderheit des Play-Frameworks und des Persistenzframeworks ist die Klasse „Finder“,
welche für den Zugriff auf die Entitäten in der Datenbank genutzt wird (vergleichbar mit dem
EntityManager bei JEE). Ein Finder muss für jede Entität definiert werden und benötigt eine
zusätzliche Typisierung: der erste Parameter beschreibt den Typ der ID der Entität (das Attribut
das mit @Id annotiert wurde) und den Klassennamen der Entität.
Folgendes Listing zeigt die Initialisierung eines Finders für die Entität „Reservation“.
public static Finder<Long, Reservation> find = new Finder<Long,
Reservation>(Long.class, Reservation.class);
Listing 23: Beispiel einer Finder-Implementierung
Der Finder bietet SQL-Funktionen gekapselt als Methoden an, welche auf der Entität angewen-
det werden können. Dadurch müssen keine expliziten SQL-Statements definiert werden, was die
Komplexität und die Fehleranfälligkeit verringert.
Explizite SQL-Statements sollten nur in Ausnahmefällen genutzt werden.
20
3.5 Änderbarkeit
Attributanpassungen geschehen erst in der untersten Schicht (Datenbankschema) und ziehen sich
dann durch alle Schichten nach oben durch (siehe Abbildung 6).
Abbildung 6: Attributänderungen
3.6 Andere technische Richtlinien
Dieses Kapitel erläutert weitere technische Richtlinien, speziell im Zusammenhang mit dem Play
Framework.
3.6.1 Code Konventionen
Prinzipiell wird sich an die Code Konventionen der jeweiligen Sprachen gehalten, wie z.B. die
Java Code Konventionen von Oracle3.
3.6.2 Flash, Session und Cache
Das Play Framework bietet drei Methoden an, um Daten kurzfristig oder über einen bestimmten
Zeitraum zu speichern, wobei hier keine Datenbank sondern Cookies zum Einsatz kommen. Alle
Varianten bieten das Speichern von Daten durch Schlüssel-Werte-Paare. Mit Flash und Session
können nur Strings gespeichert werden, mit dem Cache dagegen Objekte.
3 http://java.sun.com/docs/codeconv
21
Flash
mit Flash wird ein sehr kurzzeitiges Speicherformat beschrieben, das nur über die nächste
Anfrage oder Antwort besteht. Die beste Verwendung ist hier der Transport von Status-
Nachrichten (z.B. Anmeldung erfolgreich), welche dann vom Scala-Templating-
Mechanismus ausgewertet und angezeigt werden.
Beispiel:
// String in Flash speichern
public static Result login() {
flash("success", "Anmeldung erfolgreich");
return redirect("/home");
}
Listing 24: Flash-Beispiel
Session
Daten, die mit Hilfe der Session gespeichert werden, sind explizit nur für den zugehöri-
gen Nutzer gültig und zwar solange das Session-Objekt nicht wieder gelöscht wird (z.B.
beim Abmelden).
Beispiel:
// String in Session speichern
public static Result index() {
session("connected", "[email protected]");
return ok("Welcome!");
}
// Session löschen
public static Result index() {
session().clear();
return ok("Bye");
}
Listing 25: Session-Beispiel
Cache
Beim Cache ist zu beachten, dass die Daten nicht für den jeweiligen Benutzer gespeichert
werden, sondern es sich um einen anwendungsweiten Speicher handelt. Um hier die ge-
speicherten Daten wieder einem Nutzer zuordnen zu können, sollte zum Schlüssel des
jeweiligen Werts noch eine eindeutige Bezeichnung, wie z.B. die User-ID hinzugefügt
werden.
Beispiel:
// Objekt im Cache speichern
Cache.set("step1" + session().get("user_id"), step1);
// Objekt aus Cache löschen
Cache.set("step1" + session().get("user_id"), null, 0);
Listing 26: Cache-Beispiel
22
3.6.3 Testdaten
Sämtliche Testdaten, die im Entwicklungsprozess der Anwendung genutzt werden, können über
die Klasse „Global“ im Wurzelverzeichnis der Paketstruktur angelegt werden. Das Play Frame-
work 2.0 bietet zwar auch die Möglichkeit, Testdaten über die separate Datei „initial-data.yml“
in der YML-Syntax4 zu erzeugen, jedoch ist dieses Vorgehen für komplexe Beziehungsstrukturen
sehr fehleranfällig. Die Methode „onStart(…)“ der Klasse „Global“ wird nach jedem Deploy-
Vorgang ausgeführt. Das Play Framework parst diese Datei und speichert die entsprechenden
Entitäten in der Datenbank.
Als bessere Methode hat sich aber das manuelle Erzeugen der Model-Objekte und anschließende
Speichern in der Datenbank herausgestellt. Diese Methode sollte deswegen auch angewendet
werden.
Folgendes Listing 27 zeigt diese Methode:
public class Global extends GlobalSettings {
public void onStart(Application app) {
InitialData.insert(app);
}
static class InitialData {
public static void insert(Application app) {
if (Ebean.find(User.class).findRowCount() == 0) {
// Rollen einfuegen
Role role = Role.create("Fuhrparkverwalter",
"Verwaltet den Fuhrpark");
Role.save(role);
role = Role.create("Nutzer", "Standardnutzer");
Role.save(role);
Listing 27: Beispiel um Testdaten anzulegen
4 http://www.playframework.org/documentation/1.1/yaml
23
4 Dekomposition
Die Anwendung ist in mehrere Komponenten gegliedert. Dieses Kapitel zeigt eine Übersicht über
diese Gliederung, aber auch eine genauere Betrachtung der einzelnen Komponenten selber. Au-
ßerdem wird am Beispiel der Reservierung mit Hilfe eines Sequenzdiagrammes (Abbildung 14)
gezeigt, wie diese Komponenten beispielhaft durchlaufen werden.
4.1 Struktursicht
Auf den folgenden Seiten befinden sich eine Komponentenübersicht der kompletten Anwendung,
sowie eine genauere Abbildung der einzelnen Komponenten des Systems.
4.1.1 Komponentenübersicht Fuhrparkverwaltung
Benutzer
Fahrzeug
Reservierung
Rolle
Führerschein
Standort
G
G
GG
G
G
D
D
D
D
D
D
B
FB: BenutzerD: DatenbankG: GrafikF: FahrzeugV: Benutzer JobPositionR: RolleD: FührerscheinL: Location
V
V
Abbildung 7: Komponentenübersicht Fuhrparkverwaltung
24
4.1.2 Benutzer-Komponente
Benutzer
Statistik
Authentifikation
Kontakt
Job Position
G
A: RolleD: DatenbankF: FahrzeugG: GrafikL: FührerscheinR: ReservierungS: Standort
D
L
S
A
R
F
Abbildung 8: Benutzer-Komponente
4.1.3 Reservierungs-Komponente
Reservierung
Zweck BerichtB: BenutzerF: FahrzeugG: GrafikD: DatenbankS: Standort
F
B
D
G
S
Abbildung 9: Reservierungs-Komponente
25
4.1.4 Fahrzeug-Komponente
Fahrzeug
Wartung
B: Benutzer Jop PositionD: DatenbankF: FahrzeugG: GrafikL: FührerscheinR: RolleS: Standort
B
F
D
R
G
L
S
Abbildung 10: Fahrzeug-Komponente
4.1.5 Rollen-Komponente
Rolle
B: BenutzerD: DatenbankG: GrafikF: Fahrzeug
F
B
D
G
Abbildung 11: Rollen-Komponente
26
4.1.6 Führerschein-Komponente
Führerschein
B
D
G
F
B: BenutzerD: DatenbankF: FahrzeugG: Grafik
Abbildung 12: Führerschein-Komponente
4.1.7 Standort-Komponente
Standort
B: BenutzerD: DatenbankG: GrafikF: FahrzeugR: Reservierung
F
B
D
G
R
Abbildung 13: Standort-Komponente
27
4.2 Ablaufsicht
Für den Ablauf der Anwendung wird hier exemplarisch die Reservierung eines Fahrzeuges als
Sequenzdiagramm dargestellt.
User Reservation Fahrzeug
submitStep1
Benutzer Standort
hasError
getLocation()
getUser()
getVMatchingVehiclesForUser(User, Date, Prupose)
submitStep2
hasError
save(newReservation)
step2 (List<Vehicle>)
user
Location
List<Vehicles>
Abbildung 14: Sequenzdiagramm „Reservieren eines Fahrzeuges“
28
4.3 Verteilungssicht
Es gibt mit Play 2.0 mehrere Möglichkeiten der Verteilung auf verschiedene Webserver. In den
folgenden Absatz werden wir auf die diese Möglichkeiten genauer eingehen. Hilfe gibt es auch
auf der offiziellen Seite unter Production.
4.3.1 Standalone Mode
Die wohl einfachste Methode einen Webserver bereit zu stellen. Auf dem Rechner/Server muss
dafür Play installiert und die notwendigen Dateien vorhanden sein. Ist der Server soweit einge-
richtet kann durch das Kommando
[My application] $ play start
Listing 28: Aufruf zum Starten eines Webservers
ein eigenständiger Webserver gestartet werden. Dieser Server kann durch die „RUNNING_PID“
mit dem Comando „SIGTERM“ wieder gestoppt werden.
4.3.2 Erstellen einer Standalone Version der Applikation
Eine einfache Methode eine Play-Applikation zu deployen wird vom Framework durch das
Kommando
[My application] $ play dist
Listing 29: Erzeugen eines Zip-Files (enthält alle notwendigen JAR-Files)
bereitgestellt. Dadurch wird eine Binary-Version der Applikation ohne Play-Abhängigkeiten im
ZIP-Container erzeugt. Der Container enthält alle benötigten JAR-Files. Das ZIP-File kann so
problemlos auf einen Tomcat übertragen und auf diesem ausgeführt werden.
Aber auch über Maven lassen sich die notwendigen JAR-Files generieren. Hierfür gibt es auch
die entsprechende Dokumentation unter ProductionDist.
4.3.3 Weitere Deploy-Möglichkeiten
In der Play Dokumentation gibt es noch weitere Möglichkeiten die eigene Applikation zu
deployen. Eine die hier noch erwähnt werden sollte, ist die Möglichkeit die Play Applikation
direkt in die Cloud zu deployen, und zwar über den Dienst „Heroku“. Auch hierzu gibt es eine
entsprechende Dokumentation unter ProductionHeroku.
Mit dem Play Framework in der Version 2.0 ist es nicht möglich, die Anwendung in einem
deploy-fähigen Format (*.war) für einen Application-Server (z.B. Tomcat) zu erstellen. Diese
Funktion soll mit der Version 2.1 möglich sein.
29
4.4 Datensicht
Folgende Abbildung zeigt die Struktur der Datenbank der Fuhrparkverwaltung. Sichtbar werden
hier die Komponenten „reservation“, „location“, „vehicle“, „user“, „role“ und „driver_license“.
Außerhalb dieser Komponenten befinden sich vom Persistenzframework automatisch erstellte
Tabellen (z.B. „vehicle_purpose“), welche Many-to-many-Beziehungen abbilden. Falls in Zu-
kunft weitere Tabellen dazu kommen, sollten diese einer der bestehenden Komponente zugeord-
net werden, um die vorhandene Struktur beizubehalten.
Abbildung 15: Datensicht
30
5 Querschnittliche Systemaufgaben
Hier wird beschrieben, wie allgemeine und querschnittliche Systemaufgaben behandelt und gelöst
werden.
5.1 Sicherheit
Eine wichtige Aufgabe ist die Absicherung der Anwendung, so dass nur authentifizierte Nutzer
diese benutzen können. Diese muss bis auf die einzelnen Controller heruntergebrochen werden,
da sie mittels URLs angesteuert werden und bei nicht ordnungsgemäßer Absicherung eine Si-
cherheitslücke darstellen. Bewerkstelligt wird das durch die folgende Play-Annotation, mit wel-
cher jede Controller-Klasse annotiert werden muss.
@Security.Authenticated(Secured.class)
Listing 30: Authensisierungs-Annotation
Dadurch wird bei jedem Zugriff auf einen Controller zuerst die Klasse „Secured“ aufgerufen.
Darin befindet sich die überschriebene Methode „getUserName(…)“, mit der die Session auf
Informationen geprüft wird. Sind diese Informationen nicht vorhanden, wird der Nutzer über die
Methode „onUnauthorized(…)“ auf die Anmeldeseite weitergeleitet. Im anderen Fall wird dem
angemeldeten Nutzer die Controller-Funktionalität bereitgestellt.
5.2 Transaktionsmanagement
Das Standard-Persistenzframework Ebeans verwendet implizite Transaktionen. Somit müssen
Datenbankoperationen nicht explizit als Transaktionen definiert werden. EBeans kümmert sich
automatisch um Transaktionsoperationen wie „commit“ oder „roll-back“.
Sollte jedoch der Bedarf an expliziten Transaktionen bestehen, kann dies über verschiedene Mög-
lichkeiten erzielt werden:
@Transactional
public static Result save() {
...
}
Listing 31: Beispiel @Transactional
Durch die Annotation „@Transactional“ kümmert sich EBeans um die automatische Ausfüh-
rung der Transaktion im Rahmen der ausgeführten Methode oder Klasse.
Die folgende Art entspricht der programmatischen Methode von „@Transactional“:
Ebean.execute(new TxRunnable() {
public void run() {
// durchzuführende Transaktion
}
});
Listing 32: Beispiel TxRunnable
Beide Varianten können ohne Probleme gemischt werden.
31
Die letzte Art beschreibt die klassiche Variante mit try-finally-Block:
Ebean.beginTransaction();
try {
// fetch some stuff...
User u = Ebean.find(User.class, 1);
...
// save or delete stuff...
Ebean.save(u);
...
Ebean.commitTransaction();
} finally {
Ebean.endTransaction();
}
Listing 33: Beispiel Transaktion mit try-finally
Der Standard Isolation Level von Ebeans ist „READ_COMMITTED“. Um diesen zu ändern
muss in der obigen Methode die Transaktion beispielsweise mit „Ebe-
an.beginTransaction(Transaction.SERIALIZABLE)“ gestartet werden.
5.3 Protokollierung
Die Protokollierung von Ereignissen erfolgt standardmäßig in der Datei „application.log“. Alle
auftretenden Ausnahmen werden hier protokolliert. Sollen explizit bestimmte Ereignisse (z.B. das fehlerhafte Anmelden eines Nutzers) aufgezeichnet werden, kann dies über die Klasse „play.Logger“ erfolgen. Diese Klasse bietet unterschiedliche Stufen an:
Stufe Anwendungsgebiet
Logger.debug() Soll sehr intensiv für Debug und Entwicklerinformationen verwendet wer-den. Information. Diese werden im produktiven Umfeld nicht ausgegeben.
Logger.error()
Deutet auf einen Bug oder eine generelle Fehlerbedingung hin. Es muss sich dabei aber nicht unbedingt um einen Fehler handeln, welcher das Sys-tem zum Absturz bringt.
Logger.fatal() Ist in extremen Situationen einzusetzen.
Logger.info()
Der Einsatz ist für grundlegende Informationen gedacht. Kann vor und nach Code, welcher eine sehr lange Ausführungszeit besitzt, verwendet werden, um festzustellen, was die Anwendung gerade macht. Die Ausga-bemeldungen auf dieser Stufe sollten nicht allzu ausführlich sein.
Logger.warn()
Fehlfunktionen, die sich nicht negativ auf die Ausführung oder das zu er-wartende Resultat bezieht. Z.B. fehlende Konfiguration – es wird mit Defaultwerten weitergearbeitet.
Tabelle 3: Logging Level und ihr Einsatz
Je nach Situation ist der passende Logging-Level auszuwählen. Als Parameter der Methoden dienen ein String, welcher eine Nachricht aufnimmt und bei Bedarf, die Ausnahme, die geworfen wird. Das Mitübergeben der Ausnahme ist anzustreben.
32
5.4 Ausnahmebehandlung
Eine umfassende Fehlerbehandlung ist Merkmal und integraler Bestandteil einer Anwendung mit
hoher Qualitätsgüte. Dementsprechend wichtig ist die Vorgabe von Richtlinien in der Architek-
turbeschreibung, so dass die Ausnahmebehandlung konsequent und mit Verzicht auf Antipat-
terns umgesetzt werden kann.
Als Konsequenz aus dem Einsatz von Java auf Seiten des Backends, ergibt sich, dass die Java-
Typischen Ausnahmekategorien vorzufinden sind:
„checked exception“:
Diese Ausnahmen stellen ein erkanntes Problem dar, welches während der normalen Sys-
temausführung aufgetreten ist. Dabei kann es sich beispielsweise um fehlerhafte Benut-
zereingaben handeln. Eine der beiden nachfolgenden Reaktionen darauf ist möglich:
o Erneuter Versuch zu einem späteren Zeitpunkt
o Erneuter Versuch mit korrigierten Parametern
„unchecked exception“:
Diese Ausnahmen weisen auf ein unerwartetes Problem hin, welches sehr wahrscheinlich
durch einen Bug im Quellcode hervorgerufen wird.
Allgemein ist als Regel festzuhalten:
Wenn der Client-Code nichts zur Fehlerbehebung beitragen kann, dann ist eine „unche-
cked exception“ zu wählen.
Kann der Client-Code fehlerbehebende Maßnahmen auf Grundlage der Exception-
Information durchführen, dann ist eine „checked exception zu wählen“.
Die Frage ob ein Verhalten jetzt eine Ausnahme ist oder nicht muss immer im Kontext beurteilt
werden. Leitgedanke soll sein, dass wann immer möglich keine Implementierungsdetails nach
außen gegeben werden (Exception Wrapping).
Um die Aussagekraft der Ausnahmen zu erhöhen, sollen nach Möglichkeit „Nested-Exceptions“
verwendet werden. Den fachlichen Ausnahmen sind aussagekräftige Fehlermeldungen zuzuord-
nen. Eine strikte Trennung zwischen der eigentlichen Fehlermeldung und der Klasse der Aus-
nahmen sorgt für Transparenz und kann wie folgt erzielt werden:
Die Fehlermeldung dient dem Benutzer.
Die Fehlerklasse dient der Implementierung, um eventuell mit Hilfe von try-catch spezi-
fisch darauf zu reagieren.
Alle Ausnahmen, die auftreten können, müssen mit der in Kapitel 5.3 dargestellten Maßnahmen
protokolliert werden, damit eine spätere Analyse möglich ist.
Beispiel zum Protokollieren einer Ausnahme beim Parsen eines Datums:
33
public Date parseDateString(String date, String time) {
Date newDate = null;
try {
newDate = DATE_FORMAT.parse(date + " " + time);
} catch (ParseException e) {
Logger.error("Fehler beim parsen des Datums", e);
}
return newDate;
}
Listing 34: Beispiel für Ausnahmebehandlung
Die nachfolgende Beschreibung stellt existierende Anti-Patterns in Bezug auf die Ausnahmebe-
handlung dar. Diese sind zu vermeiden.
Log and Throw
catch (NoSuchMethodException e) {
LOG.error("Fehlermeldung", e);
throw e;
}
Listing 35: Beispiel Log an Throw
Obige Abbildung zeigt ein Beispiel für diese Art. Ein Loggen und gleichzeitiges Werfen der Aus-
nahme findet statt und ist eine der lästigsten Verwendungen, welche sich sehr negativ für den
Support und die Fehlerbehebung auswirken. Entweder sollte die Ausnahme aufgezeichnet oder
geworfen, aber nicht beides, werden.
Das Werfen von Exceptions
Ein Werfen der abstrakten Fehlerklasse Exception sagt lediglich aus, dass ein Fehler aufgetreten
ist, führt zu keinem Mehrgewinn an Information und ist zu vermeiden.
Das Werfen mehrerer „checked exceptions“
public void myFunction() throws MyException,
NotherExpression, YetAnotherException
{
}
Listing 36: Beispiel "checked Exception"
Das Werfen mehrerer, ähnlicher, Ausnahmen ist ebenfalls zu vermeiden und sollte über ein Kap-
seln (Wrapping) in einer eigenen Ausnahmeklasse vollzogen werden.
Destruktives Wrapping
catch (NoSuchMethodException e) {
throw new MyException("Error Message: " +
e.getMessage());
}
Listing 37: Beispiel Destruktives Wrapping
In jedem Fall ist diese Art Fehlerbehandlung zu vermeiden, da der Stack Trace zerstört wird.
34
5.5 JNDI
Falls die Datenbank per JNDI veröffentlicht werden soll, kann dies wie folgt geschehen:
db.default.driver=org.h2.Driver
db.default.url="jdbc:h2:mem:play"
db.default.jndiName=DefaultDS
Listing 38: Datenbank über JNDI veröffentlichen
Durch diese Methode wird die In-Memory Datenbank des Play Frameworks über den Name
DefaultDS im JNDI bekannt gemacht. Diese Methode kann mit jeder beliebigen angebundenen
Datenbank geschehen.
35
6 Alternativen
Dieses Kapitel Begründet, aus welchem Grund die einzelnen Bibliotheken, welche zum Einsatz
kommen, gewählt wurden, gibt eine Bewertung zu diesen ab und führt mögliche Alternativen an.
6.1 jQuery
Im Bereich der Client-Seitigen Bibliotheken gibt es sehr viele mögliche Alternativen. Die
Grundintension dieser besteht darin, die durch JavaScript vorgegebene Funktionalitäten, mit dem
Ziel der einfacheren Handhabung und browserübergreifenden und einheitlichen Ausführung, zu
kapseln.
Durch die hohe Vielzahl an vorhandenen Bibliotheken fällt die Auswahl nicht leicht. Der Einsatz
von jQuery ist aus folgenden Gründen sinnvoll:
Innerhalb des Open-Source Segments die am meisten verwendete Bibliothek
Leichte Einarbeitung möglich – viel qualitativ hochwertige Literatur vorhanden
Weist eine offene PlugIn-Architektur auf, wodurch beliebige Entwickler aus der Open-
Source Community an der Weiterentwicklung partizipieren können. Dies beschleunigt
die Verbesserung und Weiterentwicklung der jQuery Funktionalität.
Im Open Source Bereich existiert keine nennenswerte Alternative. Was in Erwägung gezogen
werden kann, wenn man auch die Bibliotheken unter kommerzieller Lizenz mit einbeziehen
möchte, ist ExtJS ab der Version 4.0. Ein Look-And-Feel, das einer Desktop-Anwendung nahe
kommt, sowie umfangreiche AJAX Unterstützung und eine MVC basierte (über REST angebun-
dene) Oberfläche wird geboten. Hauptsächlich der MVC bedingte Overhead und die Komplexität
der Bibliothek führte zu dem Entscheid, diese Bibliothek nicht einzusetzen.
6.2 Play Framework
Dieses Unterkapitel evaluiert das Play Framework in Bezug auf die Eignung für die Entwicklung
von Enterprise Applications. Dies ist notwendig, da die Architekten und Entwickler noch keine
Expertise darin besitzen und vor der Bewertung keine Aussage dazu treffen können.
6.2.1 Business-Sicht
Die Entwicklung von heutigen Enterprise Anwendungen sieht sich mit zwei hauptsächlichen
Herausforderungen konfrontiert:
1. Time-To-Market
Die Zeit zwischen Projektstart und der Einführung des Produkts am Markt, wird immer
wichtiger.
2. Skalierbarkeit
Ein weiterer wichtiger Aspekt moderner Anwendungen, ist die mögliche Skalierbarkeit
und Ausfallsicherheit. Bei höherer Last sollten mehr Ressourcen zur Verfügung stehen.
Die Auswahl eines geeigneten Frameworks kann nicht immer ganz autark - ohne Einbeziehung
des Projektkontexts - getroffen werden. Viele Faktoren, wie die Art des zu entwickelnden Front-
ends, das Backend und andere existierende Systeme (Integrationsaspekte) müssen mit berücksich-
tigt werden. So ist beispielsweise bei einem existierenden, komplexen, JavaEE Backends der Ein-
satz von Java Server Faces (JSF) sehr naheliegend.
36
Das Fuhrparkverwalngssystem baut auf keinen existierenden Systemen auf, so dass die Wahl
eines geeigneten Frameworks ohne Berücksichtigung von Einflussfaktoren getroffen werden
kann.
Welcher Play Framework wurde sehr schnell sehr bekannt. Da es noch sehr jung ist, lassen sich
keine repräsentativen Referenzapplikation für eine Bewertung heranziehen. Lediglich die nach-
folgend dargestellten Projekte zeigen, dass es bereits Produktivanwendungen gibt, die mit dem
Play Framework entwickelt wurden:
Französisches Job-Portal „Express Board“:
Dieses Job-Portal5 für Frankreich stellt eine Plattform für die Vermittlung von Jobs aus
dem Bereich der Softwareentwicklung zwischen Unternehmen und Technik-Freaks und
Enthusiasten dar. Die Realisierung geschah mit Play.
Plancruncher:
Die Webanwendung Plancruncher6 dient der einfachen Erstellung kurzer Businesspläne,
anhand eines Wizards. Auch diese Umsetzung erfolgte mit dem Play Framework.
Webseite des Play Frameworks:
Die Webseite des Play-Frameworks basiert selbst auf dem Play Framework und ist etwas
repräsentativer in Bezug auf Enterprise Anwendungen. Dies wird deutlich, wenn man
sich Zugriffszahlen betrachtet. So liegen die Zugriffszahlen bei 100.000 Zugriffen pro Tag,
welche ohne Performanzprobleme möglich sind.
6.2.2 Technische Sicht
Nachdem drei Echtanwendungen vorgestellt wurden, soll sich die Beurteilung des Play Frame-
works in Bezug auf den Einsatz für Enterprise Anwendungen an einer theoretischen Betrachtung
orientieren.
Es bietet einen sehr schnellen Entwicklungsstart dadurch, dass der leistungsstarke Appli-
kationsserver JBoss Netty, das Persistenzframework EBeans, eine In-Memory Daten-
bank, sowie ein Build-Tool (Simple Build Tool) mit ausgeliefert werden. Das beeinflusst
die Time-To-Market Zeit sehr positiv.
Trotzdem besteht volle Flexibilität
o Ein Deployment auf einen externen Applikationsserver ist möglich, wenngleich
die Play Version 2.0 noch Probleme mit der Bildung von Web Application Ar-
chivs (*.war) hat.
o Das Simple Build Tool ermöglicht das Einbinden von Maven Repositories mittels
Apache Ivy.
o Alternative Persistenzframeworks wie Hibernate, etc. können eingebunden wer-
den.
Webapplikationen stehen als zustandslose REST Services zur Verfügung. Dies wirkt sich
positiv auf den Aspekt der Skalierbarkeit von Enterprise Anwendungen aus, denn die Zu-
standslosigkeit erlaubt ein sehr einfaches Stacking mehrerer Applikationsserver, welche
über einen vorgeschalteten Front-Proxy verwaltet werden. Auch die Verfügbarkeit wird
dadurch beeinflusst, denn die Server können wechselseitig aus dem Verbund gelöst wer-
den, um beispielsweise ein Softwareupdate durchzuführen.
5 http://www.express-board.fr/ 6 http://plancruncher.com/
37
Modularisierung ist von Play über die sogenannten Play-Modules unterstützt. Diese kön-
nen zwar nicht ganz mit der Modularisierung aus der Objektorientierung verglichen wer-
den, jedoch versuchen sie der Entwicklung von Webapplikationen gerecht zu werden.
Funktionalität lässt sich in diesen kapseln und ist prinzipiell vergleichbar mit einem ei-
genständigen Play Projekt. Somit lässt sich die Wiederverwendbarkeit steigern. Viele der
Module stehen aber leider noch nicht für die Play Version 2.x zur Verfügung, da eine Por-
tierung noch nicht erfolgte.
6.2.3 Entwickler-Sicht
Durch das Play Framework werden an die Entwickler verschiedene Anforderungen gestellt, die
beachtet werden müssen. Die Wichtigsten soll dieses Kapitel erläutern.
6.2.3.1 Entwurfsmuster
Das MVC-Muster ist dasjenige, welches am offensichtlichsten und stärksten Einfluss auf die
Entwicklung mit Play ausübt. Dieses Muster hat sich zum Standard bei modernen Webanwen-
dungen entwickelt und bietet durch die klare Trennung von Model, View und Controller eine
lose Kopplung dieser Komponenten.
Die Views des Play Frameworks können nach dem Kompositum-Muster aufgebaut werden:
ViewKomponente
View ViewKompositum
*
Abbildung 16: View-Kompositum
Das erlaubt eine Verschachtelung und Wiederverwendung von sich wiederholenden Teilen einer
Webseite (z.B. Header und Footer).
6.2.3.2 Extreme Zustandslosigkeit
Die starke Zustandslosigkeit, wie sie auch bereits im vorhergehenden Kapitel in Bezug auf die
Skalierbarkeit genannt wurde, führt dazu, dass während der Entwicklung mehr zu beachten ist.
Beispielsweise muss jede Anfrage ausreichend viele Informationen enthalten, so dass diese verar-
beitet werden kann.
38
6.2.3.3 Vergleich mit JSF
Dieses Unterkapitel vergleicht die Programmierkonzepte der Java Server Faces (JSF) und des
Play Frameworks. Für eine gute Übersichtlichkeit liegt dieser Vergleich in Form einer Tabelle
vor, welche nachfolgend aufgeführt ist.
Java Server Faces (JSF) Play Framework (Play)
Basis Basiert auf der Servlet API (FacesServlet) und muss somit in einem Servlet Container ab-laufen.
Basiert nicht auf der Servlet API und benötigt keinen Serv-let Container zur Ausführung, kann aber, wenn nötig mit der
Servlet API zusammenspielen.
Zustandbehaftetkeit Konzipiert als zustandsbehaftet (stateful) mit folgenden Vortei-len:
Einfacheres Programmier-modell
und Nachteilen:
Layer 7 Load-Balancing
Session Failover
Aber auch stateless ist mit JSF
möglich.
Konzipiert als zustandlos (stateless) mit folgenden Vor-teilen:
Einfaches Load-Balancing durch Hinzufügen beliebig vieler Applikationsserver-Instanzen
und Nachteilen:
Komplexeres Program-miermodell
Templating (Composite Pattern)
Das Templating wird durch spezielle JSF Tags unterstützt um eine Gesamtseite aus Seiten-Fragmenten zusammenzuset-zen.
Das Templating geschieht durch Scala basierte Ausdrücke und ermöglicht ebenfalls das Zusammensetzen von Seiten-fragmenten zu einer Gesamt-seite.
Navigationslogik Die Logik zur Navigation zwi-schen den Seiten ist in einer Datei zentralisiert und ermög-licht eine leichtere Abänderung
des Navigationsflusses, da sich die Änderungen nicht durch mehrere Seiten ziehen. Eine visuelle Darstellung der Seiten-vernetzungen wird mitgeliefert.
Eine zentrale Navigationslogik ist nicht vorhanden und somit steckt das Wissen um den Sei-tenfluss in den einzelnen Seiten
und eine Änderung führt zu Änderungen in den Seiten. Eine visuelle Darstellung der Seitenvernetzung ist nicht mög-lich.
Mapping zwischen HTML/Entity Elementen
Die Zuordnung zwischen den Elementen der Präsentationsschicht und den korrespondierenden Elementen der Modelle geschieht in beiden Frameworks auf eine ähnliche Weise. JSF greift dabei auf eine Expression Language zurück, während in Play die Sprache Scala Anwendung findet.
Tabelle 4: Vergleich JSF und Play
39
Zusammenfassend kann festgehalten werden, dass die Frameworks sich hauptsächlich durch die
Zustandsbehaftung und die Umsetzung der Navigationslogik unterscheiden. Die Navigation in
JSF ist besser umgesetzt, während die Zustandslosigkeit in Play als bessere Lösung zu werten ist.
Beide Frameworks eignen sich gut für die Umsetzung von Enterprise Anwendungen, jedoch
kann dem Play Framework, durch die genannten Argumente, dennoch ein leichter Vorzug gege-
ben werden. Gerade durch den geringen Konfigurationsaufwand, kann zu Projektbeginn viel Zeit
gespart werden.
6.2.4 Fazit
Zusammenfassend bleibt noch die Frage offen, ob das Play Framework für den Einsatz bei der
Entwicklung von Enterprise Anwendungen empfohlen werden kann. Die betrachteten Punkte
legen dies nahe, womit prinzipiell eine Empfehlung ausgesprochen werden kann. Die mangelnde
Portierung der Module von Version 1.x auf 2.x wirkt sich aber stark auf die Produktivität und
Möglichkeiten aus, so dass der Einsatz erst ab Version 2.1 empfohlen werden kann.