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, __________ _____________________________