Web Frameworks - Universität Münster

Transcrição

Web Frameworks - Universität Münster
Westfälische Wilhelms-Universität Münster
Ausarbeitung
Web Frameworks
im Rahmen des Seminars Softwaretechnik
Jan Ackermann
Themensteller: Prof. Dr. Herbert Kuchen
Betreuer: Dipl.-Wirt.Inform. Christoph Lembeck
Institut für Wirtschaftsinformatik
Praktische Informatik in der Wirtschaft
Inhaltsverzeichnis
1
Einleitung................................................................................................................... 3
2
Grundlagen ................................................................................................................ 4
3
4
5
2.1
Framework für Web Applikationen.................................................................. 4
2.2
Model-View-Controller .................................................................................... 5
Jakarta Struts.............................................................................................................. 7
3.1
Model 2 Architektur MVC in Struts ................................................................. 7
3.2
Struts Controller................................................................................................ 8
3.3
Struts Model.................................................................................................... 10
3.4
Struts View ..................................................................................................... 11
3.5
Validierung in Struts....................................................................................... 12
3.6
Tiles-Layoutmanagement ............................................................................... 12
JavaServer Faces...................................................................................................... 14
4.1
MVC in Faces ................................................................................................. 14
4.2
Der Lebenszyklus der Anfrageverarbeitung ................................................... 15
4.3
JSF Tags View ................................................................................................ 16
4.4
Managed Beans............................................................................................... 17
4.5
Validierung in Faces ....................................................................................... 18
4.6
Konvertierung ................................................................................................. 20
4.7
Eventhandling ................................................................................................. 21
4.8
Navigation....................................................................................................... 22
4.9
Lokalisierung .................................................................................................. 23
Fazit ......................................................................................................................... 24
Literaturverzeichnis ........................................................................................................ 26
II
Kapitel 1: Einleitung
1 Einleitung
In den letzen Jahren hat sich Java als eine führende Technologie für die Web–ApplicationDevelopment etabliert. Entwickler benutzen Technologien wie Servlets und JavaServer Pages,
um skalierbare und robuste browserbasierte Anwenderschnittstellen für zahllose Anwendungen mit großem Erfolg zu entwickeln. Aber immer komplexer werdende Webanwendungen
machten es notwendig, im Sinne der Wartbarkeit, Wiederverwendbarkeit, Erweiterbarkeit,
Konfigurierbarkeit und einfacher Entwicklung sich grundsätzliche Gedanken über die Struktur von Webanwendungen zu machen. Die Zeiten, in denen Java Entwickler eine einzige JSPSeite hatten, die sowohl Präsentationslogik, Geschäftslogik und Navigationslogik enthielt,
sind mit der Nutzung dieser Web-Frameworks vorbei. Die Entwicklung von zahlreichen WebFrameworks in der Umgebung von Java und J2EE unterstützt diese Annahme. Laut Entwickler des Struts Web-Frameworks Craig McClanahan ist diese aus jener Notwendigkeit heraus
entstanden. In dieser Seminararbeit soll die Funktionsweise der Web-Frameworks Jakarta
Struts und JavaServer Faces vorgestellt werden.
Das Open Source Framework Struts wurde von Craig McClanahan entwickelt und im Jahr
2000 der Apache Software Foundation zur Verfügung gestellt. Schnell wurde dieses inzwischen sehr häufig genutzte und beliebte Web-Framework zu einem Apache-Top-LevelProjekt. Craig McClanahan konnte nach Fertigstellung des Frameworks von Sun für JavaServer Faces als Specification Lean angeworben werden und ist nun maßgeblich neben Ed Burns
an der Entwicklung von JavaServer Faces beteiligt.
In dieser Arbeit wird in Kapitel 2.1 der Begriff Framework erläutert, um ein grundlegendes
Verständnis für die Struktur von Frameworks zu erhalten. In dem Kapitel 2.2 wird das Architekturmuster vorgestellt, welches als konzeptionelle Struktur diesen und fast allen WebFramewoks im Umfeld von Java zugrunde liegt. Auf dieser Grundlage werden die beiden
Web-Frameworks vorgestellt, um die Gemeinsamkeiten und Unterschiede aufzuzeigen. Begonnen wurde mit dem Framework Struts, um dann im zweiten Teil anhand von JavaServer
Faces einige Bestandteile vergleichend zu erläutern.
3
Kapitel 2: Grundlagen
2 Grundlagen
2.1 Framework für Web Applikationen
Ein Framework besteht aus einer Menge kooperierender Klassen, die ein wiederverwendbares
Design für einen bestimmten Anwendungsbereich darstellen. Durch ein Framework wird die
Architektur der Anwendung festgelegt. Das Framework definiert die Struktur im Großen, seine Unterteilung in Klassen und Objekte, die jeweiligen zentralen Zuständigkeiten, die Zusammenarbeit der Klassen und Objekte sowie den Kontrollfluss [GHJV96 S.37]. Ein Framework dient dem Anwendungsprogrammierer, der sich auf die Entwicklung der spezifischen
Anwendung konzentrieren kann um einen Geschäftswert zu liefern; denn die Entwurfsentscheidungen und Technik, die er nutzt, sind in dem Framework im Voraus festgelegt. Die in
einem Framework enthaltenen Entwurfsentscheidungen sind dabei in ihrem Anwendungsbereich allgemein anzutreffen. Frameworks betonen die Entwurfswiederverwendung gegenüber
der Codewiederverwendung von z.B. Klassen-Bibliotheken, obwohl ein Framework üblicherweise konkrete Unterklassen enthält, die sofort verwendet werden können.
Bei der Verwendung von Bibliotheken schreibt man die ausführende Anwendung selbst und
nutzt die Funktionalitäten der Bibliotheken. Mit dem Verwenden eines Frameworks wird der
frameworkspezifische Code zur Ausführung genutzt und mit anwendungsspezifischem Code
erweitert. Für die Erweiterung stehen verschiedene Techniken zur Verfügung, die durch das
Framework selbst festgelegt werden, wie zum Beispiel die Programmierung von Unterklassen
der abstrakten Frameworkklassen des Frameworks. Dieser Code enthält dann wieder Operationen und Aufrufkonventionen des Frameworks. Das Framework übernimmt also die globale
Steuerung und es werden Entwurfsentscheidungen des Programmierers massiv reduziert
[GHJV96 S.37]. Mit einem Framework können Anwendungen schneller entwickelt werden
und aufgrund ähnlicher Strukturen sind diese einfacher zu warten und konsistenter. Man verliert allerdings einige kreative Freiheit, da viele Entwurfsentscheidungen bereits für den Entwickler getroffen wurden.
Ein Frameworkentwurf ist ein komplexer Softwareentwurf, der für alle Anwendungen eines
Anwendungsbereichs (z.B. Web-Applikationen) funktionieren soll. Der Entwurf stützt sich
häufig auf ein komplexes System von zusammenspielenden Entwurfsmustern, um seine Anwendung robust zu machen. Jede substantielle Änderung am Framework würde seine Vorteile
deutlich reduzieren, da der Hauptbeitrag eines Frameworks zu einer Anwendung in der von
ihr definierten Architektur liegt. Deswegen sollte ein Framework so flexibel und erweiterbar
wie möglich entworfen werden. Laut [GHJV96] gewinnen Frameworks an Bedeutung, denn
mit ihrer Hilfe erreichen objektorientierte Systeme den höchsten Grad an Wiederverwendung.
4
Kapitel 2: Grundlagen
Die hier vorgestellten Frameworks fallen in den Anwendungsbereich der Java-basierten Frameworks für Web-Applikationen, und ihre konzeptionelle Struktur folgt dem Ansatz des Model-View-Controller Architekturmusters. Sie nutzen Technologien wie JavaServer Pages und
Java Servlets. Sie arbeiten im technischen Umfeld des web-typischen Request/ResponseZyklus des HTTP-Protokolls und werden häufig im J2EE Bereich eingesetzt. Dabei lassen
sich die entwickelten Web Frameworks vielfach einem der folgenden Typen zuordnen
[CS03]:
Ereignisgesteuerte Web-Frameworks folgen dem ereignisgesteuerten Programmiermodel. In
einer ereignisorientierten Umgebung definiert der Programmierer für spezielle Komponenten
vorab die Reaktion auf ein bestimmtes Ereignis, welche dann zur Laufzeit durch Benutzeraktion mit der Komponente ausgelöst werden kann. Für jede Komponente kann dabei eine individuelle Reaktion auf ein Ereignis implementiert werde. Eine Stärke des ereignisorientierten
Models besteht darin, dass der Vorteil der objektorientierten Programmierung, der Kapselung
von Objekten mit Zustand und Verhalten, auf die Programmierung von Oberflächen übertragen werden kann. Einige Frameworks weisen konzeptionelle Analogien zur ereignisgesteuerten Swing-Technologie auf.
Aktionsgesteuerte Web-Frameworks orientieren sich stärker an den technischen Besonderheiten des HTTP-Protokolls und definieren ihre Anwendungssteuerung entlang des webtypischen Request/Response-Zyklus. Konzeptionell lehnen sich diese Web-Frameworks stark
an eine Variante des Model-View-Controller Musters, die Sun Model 2 Architektur an. Eintreffende Requests werden auf Actions abgebildet, die global definiert werden. Der Request
wird immer als ganzes verstanden, eine Aufteilung in Komponenten und davon ausgehende
Ereignisse gibt es nicht.
2.2 Model-View-Controller
Den in der Seminararbeit vorgestellten Web-Frameworks liegt konzeptionell das ModelView-Controller Architekturmuster zugrunde. Architekturmuster beschreiben den Aufbau,
also die Struktur eines Softwaresystems, unterteilen das System in Subsysteme und spezifizieren deren Zuständigkeitsbereich. Das Model-View-Controller Architekturmuster, kurz MVC,
fand ihre erstmalige Ausprägung in der Programmiersprache Smalltalk-80 zur Konstruktion
von Benutzerschnittstellen [KP88]. Das MVC-Paradigma teilt die Zuständigkeiten in drei
Komponenten auf und entkoppelt sie, um die Flexibilität und Wiederverwendbarkeit zu erhöhen [GHJV96 S.5 ff].
Das Model kapselt die Daten und ist unabhängig von einer bestimmten Darstellung der Ausgabe oder einem bestimmten Verhalten der Eingabe. Von ihr abhängige Sichten und Kontrollen werden registriert und bei Datenänderung benachrichtigt. Das Model repräsentiert den
5
Kapitel 2: Grundlagen
aktuellen Zustand. Die View ist die Bildschirmrepräsentation einer Modelkomponente. Pro
Model kann es mehrere Sichten geben. Eine Sicht liest Daten aus dem Model aus und stellt
diese in der gewünschten Form dar. Die View- und Model-Komponenten werden durch den
Aufbau eines Protokolls zur Benachrichtigung entkoppelt. Bei Benachrichtigung durch das
Model besitzt jede Sicht die Möglichkeit, ihre Darstellung durch Update in einen konsistenten
Zustand zu bringen.
Abb. : Model-View-Controller
Der Controller bestimmt das Verhalten, mit der auf Benutzereingaben durch eine Benutzungsschnittstelle reagiert wird. Er ruft definierte Dienste der zugeordneten Sicht oder des
Models auf. Dabei ist jeder Controller genau einer Sicht zugeordnet und mehrere Controller
einem Model. Zu Verdeutlichung des dynamischen Verhaltens und des Zusammenspiels der
Objekte wird hier ein beispielhafter Durchlauf gezeigt. Ein Controller erhält eine Eingabe
(handleEvent) und ändert das Model (service). Das Model benachrichtigt (update) die registrierten Beobachter. Jeder Beobachter erfragt daraufhin vom Model den aktuellen Zustand
(getData) und bringt sich selbst auf den neuesten Stand (display).
Die Trennung in drei Komponenten bringt bei Java-basierten Web-Frameworks den Vorteil
der Arbeitsteilung mit technologiespezifischen Arbeitsfeldern. Page Autoren erstellen Webseiten (View) und besitzen Fähigkeiten im Bereich Javascript, JavaServer Pages und HTML.
Application Developer sind für die Speicherung der Daten und die Kapselung der Geschäftslogik verantwortlich. Sie entwerfen Schnittstellen zu den Modelkomponenten. Ihre Fähigkeiten liegen im Bereich der Anwendungsprogrammierung. Zudem kann man noch die Rolle des
Component Writer unterscheiden, dessen Fähigkeiten in dem Framework selbst liegen. Seine
Aufgabe besteht in der anwendungsspezifischen Erweiterung des Frameworks mit wiederverwendbaren Komponenten.
6
Kapitel 3: Jakarta Struts
3 Jakarta Struts
Struts ist ein aktionsgesteuertes Open Source Web-Framework der Apache Software Foundation. Es stützt sich mitunter auf die Java Technologien Java Servlets und JavaServer Pages der
Java 2 Platform Enterprise Edition (J2EE). Um die Funktionsweise von Struts aufzuzeigen,
werden der Anfrageverarbeitungszyklus und die Komponenten von Struts anhand des MVC
erläutert. Abschließend werden die Validierung und das Layoutmanagement beschrieben.
3.1 Model 2 Architektur MVC in Struts
Unter dem Namen Model 2 Architektur ist von Sun ein Architekturvorschlag des ModelView-Controller Paradigmas vorgestellt worden, welches im Rahmen der Servlet-Technologie
eine geeignete Umsetzung darstellt und in Struts umgesetzt ist.
Model 2 Architektur von Sun
Die Elemente der Model 2 Architektur und der Request-Response-Zyklus werden in der Abbildung dargestellt. Ein Client-Browser sendet eine Anfrage (post) an den Controller (ActionServlet). Die Controller-Komponente definiert die Abbildung von Anfragen auf bestimmte
Actions (ActionMapping). Das Controller-Servlet schickt die Anfrage an diese bestimmte
Actionklasse, in der die Ausführung der Action stattfindet. Hier werden die Benutzereingaben
ausgelesen, Geschäftslogik ausgeführt und die nächste View wird vorbereitet, indem die von
der View benötigten Modelelemente (JavaBeans) mit Daten gefüllt werden. In dem Controller
bestimmen Navigationsregeln welche View (JavaServer Page) als nächstes angezeigt werden
soll. Dazu benötigt das ActionServlet einen Rückgabewert (Forward) von der Action, der über
den nächsten Navigationsfall entscheidet. Die Action sendet also in Abhängigkeit von der
Ausführung einen Rückgabewert, der die nächste View bestimmt. Das Action-Servlet ruft die
7
Kapitel 3: Jakarta Struts
so bestimmte View auf, welche dann die Daten aus dem aktualisierten Model ausliest. Danach
wird die View als Antwort zurückgegeben.
3.2 Struts Controller
Die Controller-Komponente in der Model 2 Architektur wird durch ein Java Servlet realisiert,
eine Instanz der Klasse Action-Servlet. Als Java Servlet bezeichnet man im Rahmen der Java
2 Plattform Enterprise Edition (J2EE) von Sun Microsystems ein Java-Objekt, an das ein
Webserver Requests seiner Clients delegiert [HB04 Kapitel 2]. Bei der ersten Anfrage an ein
Java Servlet wird ein Session-Objekt erzeugt, in dessen Kontext die Requests verarbeitet werden. Das Servlet übernimmt also die Ablaufsteuerung des Web-Frameworks pro Client. Nach
der Verarbeitung des Request wird vom Servlet eine Antwort (Response) generiert. Die Antwort besteht bei Struts aus einer JavaServer Page. Ein JavaServlet wird im Deployment Descriptor (web.xml) eingebunden. Für Anfragen, die an das Servlet weitergeleitet werden sollen, wird hier ein URL-Pattern festgelegt, sowie die Servlet-Klasse und die Konfigurationsdatei struts-config eingebunden. Die Ablaufsteuerung des Servlets, und damit das Verhalten der
Web-Anwendung, wird nicht fest im Quellcode codiert, sondern in der konfigurierbaren
XML-Datei struts-config definiert. Die Ausführung einer Action wird definiert durch die Abbildung von URLs auf seine Action-Klassen (Action-Mapping). Die so definierten Actions
sind genau für die Verarbeitung eines bestimmten Benutzerereignisses (Request mit Action
URL) ausgelegt. Actions werden durch Action-Klassen repräsentiert, die von der Klasse action abgeleitet werden und die Methode execute überschreiben müssen. Soll eine Action ausgeführt werden, so wird die Methode execute der Action vom Controller ausgeführt.
<action path="/login" name="loginForm" scope="session"
input="/login.jsp" validate="false"
type="de.actions.Login"
parameter="method">
<forward name="showView" path="/loginSuccess.jsp"/>
<forward name="doAction" path="/myAction.do?method=loginSuccess"/>
</action>
Die Konfigurationsdatei struts-config.xml ist das zentrale Konstrukt des Controllers, in der
das Verhalten der Web-Anwendung durch Actiondefinitionen und Definition der Navigationsmöglichkeiten festgelegt werden. Innerhalb des Action-Mapping-Elements werden beliebig viele dieser Actions eingebunden. Das Codebeispiel zeigt, wie die Abbildung von Action
URLs auf Action Klassen erfolgt. Das Actionpath-Attribut gibt die URL des Requests an, auf
das das Mapping reagiert. Das Actiontype-Attribut gibt die Implementierungsklasse für die
aufzurufende Action an. Unter dem Actionname-Attribut bindet man die FormBean (siehe
Model) ein, auf der in der Actionklasse zugegriffen werden soll. Jede Action-Klasse, die innerhalb des Action-Mappings registriert wurde, steht dem Action Servlet zur Verfügung und
8
Kapitel 3: Jakarta Struts
kann ausgeführt werden. Bei der Navigation stehen dem Action Servlet alle Forwards der
Action und global definierte Forwards zu Verfügung. Ein Forward kann dabei auf eine JSPSeite oder wiederum auf eine Action verweisen. Auf diese Weise kann eine Reihe von Actions hintereinander ausgeführt werden. Ein Forward ist vom Typ String, der unter dem Attribut Forwardname festgelegt wird.
public class ExpertlistAction extends
org.apache.struts.actions.Action {
public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
String forward = "showView";
//if no errors the forward will set on success
LoginForm loginForm = (LoginForm) form;
…
//Die hier während der Validierung gesammelten Fehler können
in der View an entsprechender Stelle ausgegeben werden.
ActionErrors errors = new ActionErrors();
…
//An dieser Stelle wird beliebiger Code ausgeführt.
…
//Rückgabewert ist ein definierter Forward
return mapping.findForward(forward);
}
}
In der Action-Klasse wird die Geschäftslogik innerhalb der execute-Methode ausgeführt. Der
execute-Methode wird mitunter auch die ActionForm übergeben, welche durch eine FormBean repräsentiert wird und die Daten der View enthält. Registriert wurde die entsprechende
FormBean der Action in der struts-config. Die Daten können nun ausgelesen werden, und
entsprechende Geschäftslogik wird ausgeführt. Struts bietet keine Unterstützung, wie die Ausführung der Geschäftslogik zu implementieren ist. Zu empfehlen ist an dieser Stelle eine saubere Kapselung der Datenzugriffe und Geschäftslogik. Diese kann durch DAO’s [BG04] oder
im Zusammenhang mit J2EE durch ein Command Entwurfsmuster [ACM01] gewährleistet
werden. Der Vorteil ist darin zu sehen, dass die Actionklassen übersichtlich bleiben und das
Framework schlank bleibt. Weiterhin wird hierdurch eine saubere Schnittstelle zur Anwendung an sich geschaffen, und die Struktur der zugrunde liegenden Applikation kann sich ändern, ohne dass das Framework angepasst werden muss.
Um Daten der Anwendung in der View anzeigen zu können, muss das Model des Frameworks aktualisiert werden. Die Model-Komponente wird durch Beans repräsentiert, auf die in
der View zugegriffen werden kann. Dazu stellt Struts spezielle Tag-Libraries zur Verfügung.
9
Kapitel 3: Jakarta Struts
Über diese Tags wird dann in der View auf die Model-Komponente zugegriffen. Innerhalb
der Action-Methode müssen diese Daten aktualisiert werden.
Auf Grundlage des Ergebnisses der Verarbeitung wird in der Action-Klasse die Weiterleitung
durch einen String-Return (mapping.findForward) entschieden. Die Weiterleitung kann dabei
an ein Global-Forward oder an ein in dem Action-Mapping definierten Forward gerichtet sein.
3.3 Struts Model
Der Zugriff im Framework auf die Daten des Models erfolgt über JavaBeans und eine spezielle Form der JavaBean im Struts-Framework, der FormBean. JavaBeans sind ein Komponentenmodel der Firma Sun. Eine JavaBean ist im Wesentlichen eine beliebige Java-Klasse, die
den in der JavaBeans-Spezifikation beschriebenen Regeln folgt [HA96]. Eine JavaBean besteht aus bindenden Vereinbarungen, die jeder Programmierer einhalten muß, um eine JavaBean zu programmieren und auch veröffentlichen zu können. JavaBeans besitzen als definierte öffentliche Schnittstelle eine Menge privater Eigenschaften (Properties), die über öffentliche get() und set()- Methoden manipuliert bzw. ausgelesen werden können. Zudem können
sie noch beliebige Methoden besitzen die den Zustand der JavaBean beeinflussen. Innerhalb
der JavaBeans werden die Daten nicht gespeichert, sie dienen lediglich dem Transport. Die
Speicherung erfolgt innerhalb der Geschäftslogik.
Eine FormBean in der Struts-Terminologie ist eine JavaBean, deren Properties mit den UIKomponenten eines HTML-Formulares korrespondieren. Zur Implementierung einer FormBean erweitert man die Klasse ActionForm. Bei einer HTML Anfrage sorgt das Struts Framework nun dafür, dass die von Benutzer eingegebenen Daten aus dem HTML-Formular in
der FormBean gespeichert werden. Die FormBean repräsentiert also den serverseitigen Status
des HTML Formulares. Nun ist es möglich, die Daten, die nun in Java-Code vorliegen, zu
validieren, auszulesen, zu manipulieren oder zu löschen. Der Zugriff innerhalb der View erfolgt über spezielle Struts-Tags in den JavaServer Pages.
<form-beans>
<form-bean name="loginForm"
type="de.forms.LoginForm" />
<form-bean name="registrationForm"
type="de.forms.RegistrationForm" />
</form-beans>
Um eine FormBean nutzen zu können, sind zwei Schritte nötig und in der Konfigurationsdatei
struts-config.xml zu konfigurieren. Zum einen müssen innerhalb des <form-beans>-Tags alle
genutzten FormBeans durch Name (logische Ressource) und Klasse (reale Ressource) eingebunden werden. Zum anderen muss die Bean in den Gültigkeitsbereich einer Action geholt
werden. Dies geschieht innerhalb des ActionMappings (siehe Beispiel ActionMapping). Mit
10
Kapitel 3: Jakarta Struts
dem Attribut name wird durch die logische Ressource die FormBean eingebunden. Mit dem
Attribut validate wird festgelegt, ob das Validator-Framework die Daten des Formulare prüfen soll. Und mit dem Attribut scope wird der Zuständigkeitsbereich in Bezug auf das Servlet
festegelegt (Session, Request). Die zentral definierten FormBeans können somit für mehrere
Actions genutzt werden.
3.4 Struts View
Die View wird durch JavaServer Pages repräsentiert. Tag-Bibliotheken erlauben Struts
HTML-Output dynamisch zu gestalten. Es stehen zahlreiche Tag-Bibliotheken zur Verfügung, die verwendet werden können. Neben den Struts-eigenen wird in der Dokumentation
die Verwendung der Java Standard Tag Library (JSTL) angeraten. In diesen Taglibs stehen
dem Entwickler verschiedene Taggruppen zu Verfügung. Mit den Tags der Core-Gruppe der
JSTL können Daten angezeigt werden, und mit der Formatierungsgruppe lassen sich die Tags
länderspezifisch anpassen. Für die Dateieingabe in HTML-Formulare wird die Struts-HTML
TagLib verwendet. In der HTML-TagLib befinden sich für alle HTML-Tags entsprechende
Struts-Tags.
<%@ taglib prefix="fmt" uri="/WEB-INF/lib/fmt.tld" %>
<%@ taglib prefix="c" uri="/WEB-INF/lib/c.tld" %>
<%@ taglib prefix="html" uri=“/WEB-INF/lib/struts-html.tld" %>
<fmt:setBundle basename="properties.messages_de" var="loc"/>
<html:errors />
<html:form action="/userLogin">
<fmt:message key="login.username"/>
<html:text property="username" size="25"/>
<fmt:message key="login.password"/>
<html:password property="login.password" size="25"/>
<html:submit property="login"/>
</html:form>
Die Taglibs werden zu Beginn der JSP eingebunden. Das Beispiel beschreibt ein Login Formular mit zwei Eingabefeldern für Benutzername und Passwort. Formatierende HTML-Tags
wurden weggelassen. Die hier verwendeten Tags der HTML-Tag-Lib arbeiten wie folgt: Das
form-Tag erzeugt ein HTML-Formular und ist damit das zentrale Tag der HTML-Tag-Lib
von Struts. Mittels der Formulare werden die Benutzerdaten an den Server geschickt. Serverseitig repräsentiert eine FormBean den Inhalt des Formulars. Die Properties der FormBean
werden über das property-Attribut der Eingabefelder angesprochen.
Das error –Tag gibt alle Fehler aus, die im Struts-Context stehen (ActionErrors). Fehler, die
während der Verarbeitung in der Action-Methode oder während der Validierung der Form-
11
Kapitel 3: Jakarta Struts
Bean entstehen, können gesammelt, in den Struts-Kontext gelegt und über das html:error Tag
als Fehlermeldungen auf der JavaServer Page ausgegeben werden.
Die Ausgabe von Text durch das message-Tag der Formatierungsgruppe ermöglichst eine
lokalisierte Ausgabe. Die Lokalisierung ist der Prozess der Anpassung einer Applikation an
eine bestimmte Sprache (Siehe Kapitel 4.9). Sämtliche „sprachliche“ Ausgaben werden in
zentrale Dateien (MessageBundle) ausgelagert. Die Texte werden über einen Schlüssel (key)
referenziert. Soll die Sprache geändert werden, greift man auf ein anderes MessageBundle
zurück. In dem JavaServer Pages Beispiel wird über das fmt:setBundle-Tag die locale festgelegt und über das fmt:message-Tag der Text der entsprechende Datei ausgegeben.
3.5 Validierung in Struts
Struts bietet ein Validierungs-Framework, das eine serverseitige und optional eine clientseitige Auswertung mittels JavaScript unterstützt [BG04 S.125 ff]. Das Framework erlaubt eine
deklarative Validierung außerhalb von Java, die in einer oder mehreren XML-Dateien konfiguriert wird. Hierfür können für ein Struts-Formular einfache Ausprägungsregeln der Eigenschaften, wie z.B. required, minlength, maxlenght definiert werden. Seit Struts 1.2 kann man
zudem die Standardvalidatoren des Jakarta Common Validator-Projekts nutzen, die eine einfache Auswertung von Zahlentypen, Datumsangaben, eMail u.s.w. ermöglicht. Entspricht eine
Benutzereingabe nicht den Anforderungen der Regeln, so besteht die Möglichkeit, an entsprechender Stelle durch ein Error-Handling eine fehlerspezifische, festgelegte und internationalisierte Fehlermeldung in der View an entsprechender Stelle zu platzieren.
Das ValidationFramework ist optional und wird über die Plugin-Schnittstelle in das Struts
Framework eingebunden. Dazu wird ein entsprechendes Plugin-Tag in struts-config eingefügt. Das Framework ist zentral in Struts eingebunden und wird ausgeführt bevor die Action
ausgeführt wird. Um das Framework zu nutzen, muss die FormBean von der Klasse VaidatorForm abgeleitet sein und die Methode validate() ausführen. Die Vorteile des Frameworks
liegen zum einen in der Möglichkeit der clientseitigen Auswertung und zum andern in der
leichten Anpassbarkeit und Erweiterbarkeit. Eine große Hilfe sind auch die Standardvalidatoren, die einen häufig genutzten Bereich abdecken. Sollten diese den Anforderungen nicht entsprechen, ist eine Erweiterung durch eigene Validatoren möglich.
3.6 Tiles-Layoutmanagement
Das Tiles Layoutmanagement ermöglicht eine Trennung zwischen Layout und Inhalten der
View. Dazu wird eine Seite in verschiedene Bereiche aufgeteilt. Alle wiederkehrenden Elemente und die Festlegung der Bereiche werden in einem Template-Layout festgelegt. Die
12
Kapitel 3: Jakarta Struts
Templates sind dabei nichts anderes als JavaServer Pages, die an entsprechender Stelle Platzhalter „Tile“ enthalten, in denen dann der dynamische Inhalt eingefügt wird. Welche Inhalte
nun an die Stelle der Platzhalter eingefügt werden sollen, wird in einer XML-Datei festgelegt.
Die Inhalte sind ebenfalls JavaServer Pages, nur sind diese viel übersichtlicher, weil sie wenig
Layoutelemente enthalten.
<tiles-definitions>
<definition name="main.home" path="/mainFrameworkLayout.jsp">
<put name="leftBoxContent" value="/leftBox/home.jsp" />
<put name="mainBoxContent" value="/mainBox/home.jsp" />
</definition>
<definition name="main.home2" extends="main.hone">
<put name="mainBoxContent" value="/mainBox/home2.jsp"/>
</definition>
</tiles-definitions>
Unter dem Namen main.home ist das Template „mainFrameworkLayout.jsp“ zu erreichen. In
dem Layout sind die Bereiche left- und mainBoxContent enthalten, und der Pfad zu ihren Bereichsseiten definiert. Einzelne Definitionen kann man erweitern, indem man nur die sich ändernden Bereiche angibt. Dieses Framework ist voll in Struts integriert und wird wie das Validator Framework als Plugin in der struts-config eingebunden. Dieses Feature ermöglicht die
Wahrung eines konsistenten und zentralisierten Layouts. Durch konsequente Verwendung
von Tag-Bibliotheken erreicht man, dass sich in den JSP-Seiten kein Java-Code mehr befindet, sondern nur noch Tags. Mit der konsequenten Nutzung von Cascading-Style-Sheets lagert man den Hauptteil des Designs in separate Dateien aus. Mit dem TilesLayoutmanagement trennt man schließlich den Inhalt vom Layout. Diese Trennung von Inhalt, Layout und Design erbringt wesentliche Vorteile. Zum einen kann man viel Code wieder
verwenden. Dieses hat zum anderen den Vorteil eines konsistenten und einheitlichen Aussehens der Anwendung. Des Weiteren werden die einzelnen JSP-Seiten übersichtlicher, leichter
zu lesen und zu programmieren. Auf diese Weise kann sich der Entwickler auf die Erweiterung der Web-Anwendung mit Inhalt konzentrieren, ohne sich laufend um Design- und Layout-Elemente kümmern zu müssen. Ein Hauptvorteil ist sicherlich auch darin zu sehen, dass
sich eine Änderung des Layouts und Designs keine Änderung in jeder einzelnen JSP nach
sich zieht.
13
Kapitel 4: JavaServer Faces
4 JavaServer Faces
Mit JavaServer Faces erweitert Sun die Java 2 Enterprise Umgebung um ein ereignisgesteuertes javabasiertes Web-Framework. Neben der vereinfachten Webseitengestaltung lag das Augenmerk der Entwickler auch darin, eine Tool-gestützte Web-Applikation-Entwicklung zu
ermöglichen. Zudem unterliegt JSF im Rahmen des Java Community Process (JCP) einem
Standardisierungs-Prozess. JSF besteht aus einem erweiterbaren UserInterface-Komponenten
Model, einem flexiblen Rendering Model, einem Event Handling Model, einer Validierung
und Konvertierung der Komponenten, einer grundlegende Seitennavigationsunterstützung und
einer Lokalisierungsfähigkeit. Im Vergleich zu Struts zeigen sich viele Gemeinsamkeiten,
aber auch grundlegende Unterschiede. Im Folgenden werden nun die MVC-Elemente von JSF
vorgestellt und dann die Verarbeitung der Anfrage mit Hilfe des Lebenszyklus erklärt. Im
Weiteren werden dann wichtige Elemente von Web-Frameworks vergleichend zu Struts vorgestellt.
4.1 MVC in Faces
Die Controller-Komponente stellt bei JavaServer Faces das FacesServlet dar. Das Servlet übernimmt die globale Steuerung, und dessen Verhalten wird in der zentralen Konfigurationsdatei faces-config.xml definiert. Die Datei enthält Tags, welche die Applikation steuern und
definieren. In dem Applikation-Tag werden Einstellungen, die für die gesamte Applikation
global gelten, festgelegt. Neben der Möglichkeit, den standardmäßigen Navigation-Handler
oder View-Handler auszutauschen, werden hier Spracheinstellungen vorgenommen, die der
Lokalisierung der Anwendung dienen. Hinterlegt ist diesem Element eine als Singleton implementierte Klasse, auf die zur Laufzeit zugegriffen werden kann, um globale Änderungen
vorzunehmen. Mit dem Managed-Bean-Tag werden die Model-Komponenten eingebunden.
Die Managed Beans sind JavaBeans, ähnlich der FormBeans bei Struts. Sie repräsentieren den
serverseitigen Zustand der UI-Komponenten. Bei einer Anfrage stehen alle hier definierten
Beans zur Verfügung. Die Managed Beans übernehmen im Gegensatz zu den Struts FormBeans auch die Ausführung (Action), welche in Struts innerhalb der Actions ausgeführt wird.
In dem Navigation-Rule Tag werden die Entscheidungsfälle für die Navigation definiert. Der
Rückgabewert einer Model-Komponente legt dabei fest, welcher Navigationsfall ausgeführt
werden soll. Die Steuerung übernimmt der Faces NavigationHandler. Werden für die Validierung und Konvertierung neue Klassen angelegt, so werden diese über das Validator- bzw.
Converter-Tag eingebunden. Auf diese Weise werden alle benötigten Komponenten und
Klassen in der faces-config eingebunden, so dass sie bei Bedarf genutzt werden können.
14
Kapitel 4: JavaServer Faces
Die View-Komponente wird durch Renderer repräsentiert. Sie übersetzten die HTML TagLibElemente so, dass sie clientseitig von dem jeweiligen Browsertyp dargestellt werden. JavaServer Page ist nur eine Möglichkeit der Präsentation. Die Referenzimplementierung nutzt
JSP als Standard sowie die Möglichkeit, HTML zu rendern. Allerdings werden weitere Renderertypen entwickelt, die z.B. WML oder Macromedia Flash ermöglichen. Dies ist dadurch
möglich, dass alle UI-Elemente der View (Darstellung im Browser) auf UI-Komponenten
(Java-Objekte) abgebildet werden. Beim Einlesen des Requests werden die UI-Elemente einer
Seite auf einen UI-Komponenten-Baum abgebildet. Beim Zeichnen (rendern) der Elemente
werden die UI-Komponenten durch den JSP-Renderer in HTML dargestellt und an den Browser zurückgesendet.
4.2 Der Lebenszyklus der Anfrageverarbeitung
Abb.: Lebenszyklus der Anfrageverarbeitung
Die JSF-Applikation erzeugt für jede neue Anfrage ein Objekt mit dem aktuellen Kontext
(FacesContext). Eine Anfrage (Request) wird in diesen Kontext abgelegt und durchläuft den
Standard-Lebenszyklus der Anfrageverarbeitung in JSF, bestehend aus 6 Phasen [HM04 S. 41
ff]. In der ersten Phase werden die UI-Elemente einer JSP-Seite auf einen Komponentenbaum
abgebildet. Eine View besteht aus einer Menge einzelnen Komponenten, deren ValidierungsKlassen, Event-Listener und Konverter. Sobald der Komponentenbaum vollständig erzeugt
wurde, werden in der zweiten Phase die Anfrage-Werte übernommen und zu den jeweiligen
UI-Komponenten übertragen. In der dritten Phase werden die Benutzerangaben auf ihre formale Richtigkeit überprüft, um dann in der vierten Phase zu dem Model-Komponenten (JavaBeans) übertragen zu werden. In dieser Phase finden auch Konvertierungen statt, welche den
übertragen Datentyp (String) aus dem HTML-Formular in den gewünschten Datentyp der UIKomponente transformiert. In der fünften Phase wird die Anwendung ausgeführt, in dem die
Action-Methode aufgerufen wird. Durch das zugehörige ActionEvent (z.B. Abschicken eines
Formulares) wurde der Prozess der Anfrageverarbeitung angestoßen. Der Rückgabewert die15
Kapitel 4: JavaServer Faces
ser Methode wird an den NavigationHandler übergeben, der daraufhin einen entsprechenden
Navigation-Case aus der faces-config ausführt. Damit steht fest, welche Seite als nächstes
ausgeführt wird und die Response wird in Phase 6 gerendert.
Nach der 2. Phase wird die Verarbeitung immer wieder von der Event-Verarbeitung eines
Phase-Events unterbrochen. An diesen Stellen kann der Entwickler den Prozess abbrechen
und direkt zum Rendern der Response übergehen. Einen Abbruch kann es auch in den Phasen
geben. Wenn z.B. die Validierung der Daten fehlschlägt, wird eine ValidatorException geworfen, Fehlermeldungen in den Faceskontext geschrieben und zur Ursprungsseite zurückverlinkt. Die Fehlermeldungen (FaceMessages) können dann auf der View wiedergegeben werden. Innerhalb der einzelnen Phasen (2, 3 und 4) können ebenfalls spezielle Events verarbeitet
werden. Wie z.B. das ValueChangeEvent, welches dann ausgelöst wird, wenn ein Benutzer
einen Wert in der View verändert hat.
4.3 JSF Tags View
JSF wird mit zwei Tag Libraries ausgeliefert: jsf_core und html_basic. In jsf_core befinden
sich Tags, die unabhängig von der jeweiligen Sprache (HTML,WML etc.) benutzt werden
können. In html_basic sind alle Tags zur Darstellung der Standard HTML-Elemente zu finden. Um die Tag Libraries nutzen zu können, müssen sie auf der JSP-Seite eingebunden werden. Mit den Core Tags werden die wesentlichen Features von Faces, wie z.B. der Validator,
die Konvertierung oder das Eventhandling eingebunden. Diese Features werden im Folgenden
noch näher erklärt. In Struts ist das form-Tag das zentrale Tag und in Faces ist es das viewTag. Alle Faces Elemente innerhalb dieses Tags werden in den UI-Komponenten-Baum aufgenommen und stehen in Faces zur Verfügung.
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<html>
<body>
<f:view locale="de">
<h:form id="loginForm">
Username:
<h:inputText id="username" value="#{loginBean.username}"/>
Password:
<h:inputSecret id="password" value="#{loginBean.password}"/>
<h:commandButton id="submit" action="#{loginBean.login}"
value="#{message.submit}"/>
</h:form>
</f:view>
</body>
</html>
Die html_basic Tag Library enthält Tags für alle Kombinationen aus UI-Komponenten und
HTML Renderern, die durch die JSF-Spezifikation definiert wurden. Dazu gehören alle
16
Kapitel 4: JavaServer Faces
HTML-Form-Elemente sowie andere Standard-Elemente. Die UIForm-Komponente wird
durch das <h:form>-Tag in HTML repräsentiert. Innerhalb des Tags können nun EingabenElemente UIInput-Komponenten stehen. Über das commandButton-Tag wird das Formular
schließlich abgeschickt. Wie man an dem Beispiel sieht, muss kein action-Attribut angegeben
werden. Die HTML-Attribute method und action eines Formulares werden von JSF automatisch generiert. Die UI-Command-Komponente führt eine Aktion aus, wenn sie aktiviert wird.
Sie kann in Kombination mit einem HTML-Renderer die Ausprägungen commandButton und
commandLink annehmen. Über das action-Attribut wird die Action-Methode der ManagedBean referenziert. Diese Methode wird in Phase 5 des Lebenszyklus aufgerufen und ausgeführt. In dem Beispiel sind noch zwei UI-Input-Komponenten enthalten: Ein StandardEingabetextfeld und ein Passwort-feld. Über das value-Attribut werden externe Datenquellen
identifiziert. Man kann also über „Value Binding Expressions“ auf die Properties eines Model-Objektes (JavaBean) zugreifen.
4.4 Managed Beans
In der Faces Terminologie versteht man unter einer Managed Bean eine JavaBean mit einer
Menge von Properties, die sich entweder auf Werte von UI-Komponenten beziehen oder direkt mit Instanzen dieser Komponenten verbunden sind. Des Weiteren können sie noch applikationsspezifische Methoden besitzen. Diese Methoden können der Validierung, der Konvertierung, dem Event Handling und der Vorbereitung der Navigation dienen. Die Daten, sowie
die mit den Daten arbeitenden Methoden werden in einem Objekt gekapselt. So haben die
Methoden einen einfachen Zugang zu den Daten. In Struts erfolgte die Ausführung in einer
separaten Action-Klasse und die FormBean musste erst eingebunden werden.
<managed-bean>
<description>Die Bean überprüft das Login </description>
<managed-bean-name>loginBean</managed-bean-name>
<managed-bean-class>
de.myProject.model.LoginBean
</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
Sobald eine Anfrage eintrifft stehen alle, wie in dem Beispiel in der faces-config deklarierten
Managed Beans zur Verfügung. Aus der JSP gibt es zwei Möglichkeiten, Werte einer Komponente mit Properties einer Bean zu verbinden. Value Binding Expressions werden in der
JSF-Implementierung über die Klasse Value-Binding repräsentiert, welche ExpressionStrings
der Form #{myBean.myProperty} nutzt und den Zugriff auf die Properties dieser Bean erlaubt. Bei der Nutzung ist vor allem darauf zu achten, dass der richtige Datentyp zwischen
Bean und UI-Komponente ausgetauscht wird. Da in einer Webapplikation Benutzereingaben
17
Kapitel 4: JavaServer Faces
nur als String übergeben werden können, besitzt Faces die Möglichkeit, Konverter einzubinden, die eine parametrisierte, automatische Konvertierung ermöglichen (siehe Konverierung).
Dieses Verfahren wird ähnlich auch in Struts genutzt, aber Faces bietet noch eine weitere
Verbindungsmöglichkeit: Die Instanzgebundenen Komponenten, welche das Komponentenmodel von Faces nutzen. Ein Property der Managed Bean ist in diesem Fall vom Typ der
Komponente selbst. Die get()- und set()-Methoden des Propertys liefern also eine Instanz der
Komponente zurück. Der Vorteil der Instanzgebundenen Komponenten ist die volle Kontrolle
des Entwicklers über die UI-Komponente.
Bei der Method Binding Expression als Sonderform der Value Binding Expression werden
nicht Properties einer Managed Bean gebunden, sondern ihre Methoden. Die Expressions ermöglichen bestimmten Events innerhalb von Faces beliebige public-Methoden von Beans
aufzurufen. Die Method Binding Expressions werden bei den Tag-Attributen action, actionListener, validator und valueChangeListerner genutzt. Diese werden in den folgenden Kapiteln noch beschrieben.
Nach den Zugriffsmöglichkeiten der View auf die ManageBean werden nun Zugriffsmöglichkeiten aus Sicht der Managed Bean aufgezeigt. Die Klasse FaceContext und die über diese
Klasse referenzierten Klassen sind hier von zentraler Bedeutung. Dem FaceContext kann man
FaceMessages über addMessage() zuweisen. Dies ermöglicht das Sammeln von Nachrichten
und Fehlermeldungen, die dann über ein einfaches Tag in der View ausgegeben werden können. Weiter hat man Zugriff auf die Applikation-Instanz über getApplication(). Über diese
Klasse kann man auf die global definierte Länderkennung locale und die länderspezifischen
MessageBundle zugreifen und diese zur Laufzeit ändern. Zudem hat man über den FaceContext Zugriff auf den Komponentenbaum und seiner Wurzel, die UIViewRoot-Komponetente.
Über den Zugang zu der UIViewRoot-Komponente kann auf den aktuellen KomponentenBaum zugegriffen werden und sogar zur Laufzeit verändert werden. So können z.B. Komponenten einer JSP ein- und ausgeblendet werden. Der Zugriff auf den Komponentenbaum ist
für den Entwickler ein sehr mächtiges Instrument. Diese direkte Manipulation der View gibt
es in Struts nicht. So stellt sich Faces durch die Kombination aus Renderer und Manipulation
des Komponentenbaums als mächtiger dar.
4.5 Validierung in Faces
Für einfache Validierungsfälle wie z.B. die Überprüfung, ob eine Eingabe gemacht wurde, ob
die Länge den Anforderungen entspricht oder ob die Eingabe ein numerischer Typ ist, liefert
Faces Standardvalidatoren mit. Reicht diese recht dürftige Unterstützung durch Standardvalidatoren nicht aus, bieten sich in Faces mehrere Möglichkeiten der Erweiterung.
18
Kapitel 4: JavaServer Faces
Durch Implementierung einer Validator-Methode innerhalb der Managed Bean muss keine
eigene Validator-Klasse implementiert werden. In der Methode werden die notwendigen Validierungsregeln aufgenommen, und in dem entsprechenden Tag der JSP wird der Validator
als Attribut aufgenommen. Dies ist bei allen Tags möglich, deren Komponenten von UI-Input
abgeleitetet sind.
<h:form>
<h:messages style="color:red"/><br>
<h:inputText id="username" value="#{loginBean.username}"
validator="loginBean.checkUser"/>
</h:form>
UI-Input-Komponenten liegen immer innerhalb eines Form-Tags und werden über ein UICommand-Element abgeschickt. Damit wird die Verarbeitung gemäß dem gezeigten Lebenszyklus angestoßen. Die entsprechende Methode in der Managed Bean sieht demnach folgendermaßen aus:
public void userCheck( FacesContext faces, UIComponent input,
Object value) throws ValidatorException{
…
boolean Validierungsfehler = true;
if (Validierungsfehler){
FacesMessage message = new FacesMessage(…);
throw new ValidatorException(message);
}
}
Bei einem Fehler wird eine FaceMessage erzeugt und eine Validatorexception mit dieser
Message geworfen. Die UI-Komponente wird nun in einen Fehlerzustand gesetzt, die Nachricht im FacesContext gesammelt und der Lebenszyklus nach der Validierung abgebrochen,
indem die entsprechende JSP wiederholt dargestellt wird. Die entstandenen Fehlermeldungen
werden in diesem Beispiel mit Hilfe des <h:messages>-Tag ausgegeben. Die einfache und
unkomplizierte Validierung per Methode eignet sich immer dann, wenn die Validierung selten
oder nur einmalig vorkommt. Kommt eine spezielle Validierung häufiger vor, lohnt sich meist
der Mehraufwand, eine eigene Validierungsklasse zu erstellen. Eine Validierungsklasse implementiert das Interface Validator und muss die Methode validate enthalten.
public class UserCheck implements Validator{
public void validate ( FacesContext faces, UIComponent input,
Object value) throws ValidatorException {
…
boolean Validierungsfehler = true;
if (Validierungsfehler){
FacesMessage message = new FacesMessage(…);
throw new ValidatorException(message);
}
}
19
Kapitel 4: JavaServer Faces
Nach Erstellung der Klasse wird sie in der faces-config registriert, damit sie später über ein
eigenes Validator-Tag genutzt werden kann. Die Regiestrierung erfolgt über das <validator>Element:
<validator>
<validator-id>UserCheck</validator-id>
<validator-class>de.myProject.validator.UserCheck
</validator-class>
</validator>
Die Validator-id wird in den View-Komponenten durch das Validator-Tag, das bereits mit der
Referenzimplementierung mitgeliefert wird, genutzt.
<h:form>
<h:messages style="color:red"/><br>
<h:inputText id="username" value="#{loginBean.username}">
<f:validator validatorId="CheckUser"/>
</h:inputText>
</h:form>
Eine weitere Möglichkeit besteht darin, ein spezielles Custom Validator-Tag zu erstellen.
Dies ist dann sinnvoll, wenn man das Validator-Tag noch mit Attributen erweitern möchte. So
könnte man dem Validator ein Muster oder andere Parameter vorgeben. Damit erreicht man
höchste Flexibilität in der Gestaltung der Validierung. Allerdings muss man zusätzlich zur
Implementierung des Interfaces auch den Tag Handler um die Funktionalität erweitern. Die
Flexibilität bezahlt man also mit einem bestimmten Maß an zusätzlicher Arbeit. Allerdings
stellen sich die Validierungsmöglichkeiten als sehr flexibel dar und können somit evolutionär
mit der Entwicklung eines Webframeworks entsprechend erweitert werden.
4.6 Konvertierung
Bei Web-Applikationen gibt es zwei Sichten auf die Daten: Daten repräsentiert durch Datentypen innerhalb der Java-Objekte und Daten innerhalb der Präsentationssicht (Browser) repräsentiert durch einfachen Text. Daraus ergibt sich ein Konvertierungsproblem in Webapplikationen. Beispielweise wird ein in Textform angegebenes Datum auf der Präsentationsschicht
zur Verarbeitung in dem Datentyp java.util.Date umgewandelt werden. Die Konvertierung
wird nach der Validierung in der Phase 4 im Lebenszyklus der Anfrage vorgenommen. Java
Server Faces bietet eine Reihe von Standard-Konvertern, die automatisch eine Konvertierung
vornehmen und dem Entwickler damit für die meisten Fälle die Arbeit abnehmen. Bei einigen
muss noch nicht einmal ein Konverter explizit angegeben werden. Die in der Managed Bean
enthaltenden get und set Methoden für die Properties können nun direkt die Daten vom Typ
Integer oder Date des Beispieles einlesen und ausgeben, ohne sie selber konvertieren zu müs-
20
Kapitel 4: JavaServer Faces
sen. Diese automatische oder anpassbare Lösung erleichtert die schnelle Implementierung von
Webanwendungen.
<h:inputText id="intInput" value="#{myBean.intValue}"
required="true"/>
<h:inputText id="dateInput" value="#{myBean.myBirthday}"
required="true">
<f:convertDateTime pattern="dd.MM.yyyy"/>
</h:inputText>
Ist keine Konvertierung für einen Datentyp möglich, kann man, analog zur Vorgehensweise
bei der Validierung, JSF um Konvertierungsmethoden oder Klassen flexibel erweitern. Als
erstes kann man innerhalb der get und set Methode, den TextString manuell in den gewünschten Datentyp umwandeln und rückwandeln. Kommt eine bestimme Konvertierung häufiger
vor, ist es sinnvoll durch Implementierung des Converter-Interfaces einen eigenen Konverter
zu erstellen. Innerhalb dieses Konverters müssen zwei Methoden implementiert werden, welche die Um- und Rückwandlung übernehmen. Nach dem Einbinden des Konverters in der
faces-config kann er durch das Standard-Validator-Tag <f:converter> genutzt werden. Für
höchste Flexibilität besteht die Möglichkeit zudem noch ein Custom Converter-Tag mit spezifischen Attributen zu erstellen und eine angepasste Konvertierungsfunktionalität zu ermöglichen. Der Entwickler hat also auch hier die Möglichkeit zwischen einem einfachen Implementierungsaufwand und hoher Flexibilität und Wiederverwendbarkeit seiner Konvertierungsmethode zu wählen. Ein solches Konzept zur automatischen Konvertierung ist in Struts
nicht vorhanden. Hier beweist JavaServer Faces durch hohe Flexibilität und vielfach automatisierten Konvertierungen gegenüber Struts einen klaren Vorteil.
4.7 Eventhandling
In JavaServer Faces können von UI-Komponenten zwei Arten von Events ausgesendet werden: Action-Events und ValueChangeEvents. Die Events sind von der Klasse FacesEvent
abgeleitet. Neben FacesEvents existiert noch die Klasse PhaseEvent. PhaseEvents werden von
JSF nach Abarbeitung einer Phase der Anfrageverarbeitung versendet. Durch die Implementierung eines PhaseListeners und der Registrierung in der faces-config kann ein Entwickler
diese Events empfangen.
ActionEvents werden von Komponenten gesendet, die vom Typ UICommand sind. Das
HTML RenderKit der Referenzimplementierung enthält die beiden Tags commandLink und
commandButton, welche Action-Events senden können. Beide implementieren alle das Interface ActionSource, welches nur die Methode actionPerformed vorgibt. Auch hier besteht die
Möglichkeit, ein Event innerhalb einer ActionEvent-Handling-Methode der Managed Bean zu
verarbeiten oder eine eigene Event-Handling-Klasse zu implementieren. Um einen Action21
Kapitel 4: JavaServer Faces
Listener an eine Komponente zu binden, wird entweder das <f:actionListerner>-Tag verwendet, um die Event-Handling-Klasse zu referenzieren oder das actionListener-Attribut des Tags
der UICommand Komponente genutzt, um die ActionEvent-Handling-Methode der Managed
Bean zu referenzieren.
<h:form>
<h:commandLink id="komando" action="#{myBean.doit}"
actionListener="#{myBean.showMyId}"/>
</h:from>
Der ActionListener empfängt bei Ausführung der Action ein ActionEvent und kann entsprechen darauf reagieren. Ein ActionEvent kann man z.B. dafür verwenden, die Sprache der Web
Applikation zu ändern oder die ausgeführte Action in ein Logfile zu schreiben.
public void showMyId(ActionEvent event){
String id = new String(event.getComponent().getId());
Log.debug(" Der CommandLink mit der ID " + id + "wurde
ausgeführt");
}
ValueChangeEvents werden ähnlich verarbeitet wie ActionEvents. Die entsprechenden Tags
benutzen das Attribut valueChangeListener, um die Komponenten mit einer entsprechenden
Methode der Managed Bean zu verbinden. Über ein valueChangeEvent erfährt man zum einen, dass sich eine Komponente verändert hat und kann zudem auf den alten und neuen Wert
der Komponente zugreifen.
Innerhalb des <lifecycle>-Tag in der faces-config können sogenanne PhaseListener registriert
werden, die nach der Abarbeitung jeder Phase der Anfrageverarbeitung ein PhaseEvent empfangen. PhaseListener können für eine oder für alle Phasen registriert werden. Über PhaseEvents kann auf den aktuellen FacesContext zugegriffen werden und somit können die PhaseListener für beliebige Erweiterungen (Logging, Zugangskontrolle etc.) verwendet werden.
Gerade dieses ereignisgesteuerten Programmiermodel ermöglicht die in den Kapiteln Validierung und Konvertierung aufgezeigte Flexibilität. Dies stellt einen Vorteil im Vergleich zu
Struts dar, welches nur eine einfache Abbildung von Anfragen auf Aktionen unterstützt.
4.8 Navigation
Die Faces-Navigation oder die Navigation durch Aufruf des JSF NavigationsHandlers ist der
Standardfall für die Navigation in der JSF-Applikation. Nach Verarbeitung der ActionMethode liefert diese einen String als Rückgabewert. Dieser String wird dem NavigationHandler übergeben, der dann in den entsprechenden Navigationsregeln nach einer Weiterleitung sucht. Die Navigationsregeln werden in der faces-config definiert. Das navigation-ruleTag umschließt eine Regel. Das from-view-id-Tag legt fest, für welches view-Element diese
22
Kapitel 4: JavaServer Faces
Regel gilt (Vorgänger). Wird dieses Tag weggelassen, so gilt die Regel global. Mit beliebig
vielen navigation-case-Tags werden die Navigationsfälle definiert. Als Beispiel sei angenommen, dass je nach Erfolg „loginErfolg“ oder „loginFehler“ zurückgegeben wird. So könnte die Regel folgendermaßen lauten:
<navigation-rule>
<description>Das Verhalten bei login</description>
<from-view-id>/pages/myLoginPage.jsp</from-view-id>
<navigation-case>
<description>Login war erfolgreich</description>
<from-outcome>loginErfolg</from-outcome>
<to-view-id>/pages/myMainPage.jsp</to-view-id>
</navigation-case>
<navigation-case>
<description>Login ist fehlgeschlagen</description>
<from-outcome>loginFehler</from-outcome>
<to-view-id>/pages/myLoginPage.jsp</from-view-id>
</navigation-case>
<navigation-rule>
Bei Erfolg wird also auf die Hauptseite verwiesen und bei Misserfolg wiederum auf die Login-Seite. Hier könnten dann entsprechende Fehlermeldungen, wie „Benutzername unbekannt“,
in den FacesKontext geschrieben werden und auf der View ausgegeben werden. Die FacesNavigation stellt eine Reaktion auf die Geschäftslogik im weitesten Sinne dar. Das Navigationshandling ähnelt dem von Struts, der Unterschied liegt in der separaten Definition der Navigationsregeln und nicht innerhalb eines ActionMappings bezogen auf nur eine Action.
4.9 Lokalisierung
Die Lokalisierung ist der Prozess der Anpassung einer Applikation an eine bestimmte Sprache
oder Kultur und ist eines der wichtigsten Features heutiger Webframeworks. Wenn sämtliche
Sprachelemente in einer Applikation fest kodiert sind, so ist eine Lokalisierung mit einem
enormen Aufwand verbunden. Vorrausschauendes Programmieren kann diesen Aufwand sehr
vereinfachen. In Struts und Faces nutzt man RessouceBundles. Sämtliche „sprachliche“ Ausgaben werden dabei in zentrale Dateien ausgelagert. Die Texte werden über einen Schlüssel
referenziert. Nun ist es nur noch nötig, für jede zu unterstützende Sprache eine solche Datei
zu erstellen. Die Dateien haben die Form resources_de.properties für deutsche Texte, resources_en.properties für englische Texte u.s.w.. Wird eine locale nicht unterstützt, so fällt die
Sprachausgabe automatisch auf eine dafür definierte locale zurück. Um also eine weitere
Sprache zu unterstützen, schickt man einen ResourcenBundle einfach zum Übersetzer. Die
Unterstützung ist in Struts und Faces gleich.
23
Kapitel 5: Fazit
5 Fazit
Sowohl Struts als auch Faces erlauben durch Spezialisierung des Frameworks eine schnelle
Entwicklung von Webapplikationen. Die Frameworks stellen dem Entwickler eine robuste
Softwarearchitektur zur Verfügung, deren Funktionen dem Entwickler viel Arbeit abnehmen.
Durch die Vorgaben von Aufrufkonventionen und der vorgegebenen Konfigurierbarkeit wird
das arbeitsteilige Entwickeln erleichtert und durch ähnliche Strukturen der Model-, Controller- und Viewelemente stellt sich eine Routine ein, die konsistentes, fehlerarmes und schnelles
Entwickeln ermöglicht. Innerhalb ihrer Action-Methoden können beide Anwendungen jegliche javabasierte Geschäftslogik ausführen. Mit dieser Offenheit können sie mit jeder javabasierten Anwendung interagieren. Beide Systeme zeichnen sich auch durch eine hohe Flexibilität aus. Die Funktionen der Frameworks, wie z.B. die Validierung, können einfach durch eigene Komponenten erweitert werden. Hierbei zeichnen sich die flexiblen Erweiterungsmöglichkeiten bei Faces besonders aus.
Die Trennung in die Subsysteme Model, View und Controller ermöglicht ein rollenbasiertes
Entwickeln der Anwendung mit dem Vorteil, technologiespezifische Fähigkeiten der Entwickler der Teilsysteme zu nutzen und eine getrennte Entwicklung zu ermöglichen.
Neben vielen Gemeinsamkeiten in Bezug auf die zur Verfügung gestellte Funktionalität, liegt
der Hauptunterschied darin, dass Struts nach der Einordnung in Kapitel 2.1 ein aktionsgesteuertes und Faces ein ereignisgesteuertes Webframework ist. Neben den in den Unterkapiteln
von JavaServer Faces schon erwähnten Unterschieden stellt Struts mit dem Tiles-Framework
eine mächtige Komponente zur Verfügung, die ein Layoutmanagement ermöglicht, welches
die Webentwicklung wesentlich vereinfacht. Durch konsequente Nutzung des TilesLayoutmanagement und Cascading Style Sheets ist eine gute Trennung zwischen Layout,
Inhalt und Design möglich. Auf der anderen Seite stellt JSF durch das Komponentenmodel
und das Eventhandling Funktionalität zur Verfügung, die in Struts nicht implementiert ist.
Faces biete mehr Kontrolle über die Komponenten und die Möglichkeit, auf verschiedene
Events zu reagieren. Auch ein flexibles Renderingmodel ist Struts fremd.
Beide Frameworks bieten ihre Vorteile und haben neben vielen Gemeinsamkeiten auch einige
Unterschiede. Es stellt sich aber nicht nur die Frage, welches Framework man in Zukunft nutzen wird, das standardisierte oder das etablierte, sondern auch, ob man beide Frameworks
gemeinsam nutzt. In dem Jakarta Struts Projekt wird dafür an einer Integrationslibrary StrutsFaces gearbeitet. Mit dieser ist es möglich, die Vorteile beider Frameworks wie in Integrating
Struts, Tile, and JavaServer Faces [HA96] beschrieben, zu nutzen. So weist auch Craig McClanahan in seinem Weblog [MC04] darauf hin, dass die Entscheidung, ob man Struts oder
Faces nehmen sollte keine ausschließende sein muss. JSF werde sich in der View24
Kapitel 5: Fazit
Technologie weiterentwickeln und Craig McClanahan rät der Struts Community, den Entwicklungsfokus auf die Controller- und Modelkomponente zu legen. So wird es nach seiner
Meinung auch in Zukunft Platz für beide Frameworks geben.
Nach Meinung des Autors stellt sich JavaServer Faces als das mächtigere Framework dar,
welches sich allerdings noch in der Entwicklungsphase befindet. Es gilt als noch nicht ganz so
stabil wie Struts. So treten z.B. in der Manipulation des Komponentenbaums noch Fehler auf
[HM04]. Zudem ist die Literatur über JSF und die Entwicklung von Anwendung auf Basis
von JSF noch dünn besät. Langfristig wird diese Framework durch den Standardisierungsprozess auch bei der Entwicklung von Web-Anwendungen stark an Bedeutung gewinnen. Struts
hingegen ist ein etabliertes Framework, welches auch weiterhin seine Berechtigung hat und
sich durch sein einfaches Konzept auszeichnet, welches Entwicklern einen schnelleren Einstieg ermöglicht. Zudem hat sich eine Community um Struts herum gebildet. Literatur und
Beispielanwendungen sind häufig anzutreffen und die Entwicklung scheitet stetig durch eine
große Anzahl an Entwicklern fort. Eine Empfehlung, welches Framework vorzuziehen ist,
kann es an dieser Stelle also nicht geben.
25
Literaturverzeichnis
[ACM01] Deepak Alur, John Crupi, Dan Malks: Core J2EE Pattern - Best Practices
and Design Strategies, Sun Microsystems Press, 2001.
[BE04]
Hans Bergsten: JavaServer Faces, O´Reilly, 2004.
[BG04]
Vic Cekvenich, Wolfgang Gehner: Struts – Best Practices, dpunkt.verlag
GmbH, 2004.
[CA04]
Chuck Cavaness: Programming Jakarta Struts, 2nd Edition, O´Reilly, 2004.
[CS03]
Christian Sell: Eine Typologie für Web-Frameworks – Es muss nicht immer
Struts sein, Java-Magazin (Seite 25-35), 7/2003
[DE03]
Pierre Delisle: JavaServer PagesTM Standard Tag Library Specification,
Sun Microsystems, Release: November 2003.
[DP02]
Stefan Denninger, Ingo Peters: Enterprise JavaBeansTM 2.0, 2. Auflage,
Addison-Wesley, Seite 23-30, 2002.
[GHJV96] Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides: Entwurfsmuster – Elemente wiederverwendbarer objektorientierter Software, AddisonWesley, 1996.
[HA96]
Graham Hamilton: JavaBeansTM API – Spezifikation, Sun Microsystems,
1996.
[HB04]
Hans Bergsten: JavaServer Pages, 3rd Edition, O´Reilly, 2003.
[HM04]
Sven Haiges, Marcel May: JavaServer Faces – Web Development mit dem
Standard-Framework, Software & Support Verlag, 2004.
[KP88]
Glenn E. Krasner, Stephen T. Pope: A cookbook for thee model-view- controller user interface paradigm in Smalltalk-80, Journal of Object-Oriented
Programming,1988.
[MC04]
Craig McClanahan: Craig McClanahan's Weblog,
http://blogs.sun.com/roller/page/craigmcc/20040927, (01.12.2004).
[SM04]
Srikanth Shenoy, Nithin Mallya: Integrating Struts, Tile, and JavaServer
Faces, http://www-128.ibm.com/developerworks/java/library/j-integrate/,
(01.12.2004).
Münster, __________
_____________________________