<jsptutorial />

Anwendungsarchitektur


Warum Architektur?

Architektur ist - etwas vereinfacht gesprochen - die Aufteilung einer Anwendung auf lose miteinander gekoppelte Komponenten. Je größer eine Anwendung wird, um so wichtiger wird es, dieser eine gute Architektur zugrunde zu legen, um bei Erweiterungen nicht an allen Komponenten Änderungen vornehmen zu müssen. Ist die Aufteilung der Komponenten unglücklich gewählt, wird man für zusätzliche Anforderungen immer öfter auf Workarounds zurückgreifen müssen und wiederholt die Erfahrung machen, dass simpel klingende Erweiterungen und Änderungen am System aufgrund der gegenseitigen Abhängigkeiten immer schwieriger und nur mit wachsenden Zeitaufwand umzusetzen sind.
Eine gute Architektur ermöglicht weitgehend voneinander losgelöste Komponenten, die über möglichst stabile Schnittstellen1 miteinander kommunizieren. Eine Anwendungsarchitektur ist logischerweise stark von der zugrunde liegenden Art der Anwendung abhängig. Für Webanwendungen wie wir sie hier im Tutorial behandeln, gab und gibt es jedoch einige grundlegende Gemeinsamkeiten und daraus entstandene architekturelle Empfehlungen.
Die folgenden Abschnitte geben weitgehend die Reihenfolge wieder, in der diese Ansätze entstanden sind. Das bedeutet aber keineswegs, dass ältere Modelle vollständig und für alle Anwendungen durch neuere Ansätze ersetzt wurden. Im Großen und Ganzen ergänzen spätere Ansätze eher die vorhergehenden für bestimmte Anforderungen.

Zum SeitenanfangZum Seitenanfang

Model 1

Servlet-only

Als ersten Standard für die Entwicklung webbasierter Anwendungen in Java wurde Anfang 1997 von SUN die Servlet-Technologie eingeführt, die den beginnenden Wildwuchs von java-basierten Server-Erweiterungen einfangen und in einer allgemein akzeptierten Spezifikation vereinheitlichen konnte. Die Version 2.0 der Spezifikation erschien nur wenig später - im Dezember 1997.
Die Entwicklung mit Servlets ähnelte dem zum damaligen Zeitpunkt weit verbreiteten CGI-Modell und läßt sich schematisch wie folgt skizzieren:
image_model_1.png
Dabei ist bei Architekturen nach dem Model 1 charakteristisch, dass für (nahezu) jede Seite eine JSP oder ein Servlet verwandt wird und dass die Links zu anderen Seiten der Anwendung zumeist fest in der JSP oder dem Servlet angegeben sind. Die Geschäftslogik liegt idealerweise außerhalb des Servlets oder der JSP und wird von dort aus lediglich angestoßen. In der Praxis wurden aber auch vielfach wesentliche Anwendungsbestandteile direkt innerhalb von JSPs (in Form von Skriptlets) oder in Servlets implementiert. Was die Architektur der Gesamtanwendung angeht, so waren damals dynamische Webanwendungen i.a.R. weitaus weniger komplex als heutige Webanwendungen, so dass das Model 1 häufig ausreichend war. Für einfachere Anwendungen ist das Model 1 auch heute noch völlig ausreichend.
Selbst bei einer sauberen Trennung zwischen reinem View-basierten Code und der Geschäftslogik blieb bei Servlets das offensichtliche Problem, dass letztlich immer HTML (jedenfalls eine Markup-Sprache) erzeugt werden musste, was in Servlets duch mehrere out.println()-Aufrufe aus dem Java-Code heraus erfolgte. Ein Beispiel für ein simples Servlet findet sich am Anfang des Kapitels Lebenszyklus von JSPs. Die Ausgabe von HTML-Code durch out.println()-Statements war extrem unflexibel. Für jede Änderung am Webdesign musste eine Java-Programmiererin diese an der richtigen Stelle vornehmen. Häufig enthielten Servlets vergleichsweise wenig Java-Code, aber jede Menge out.println()-Statements zur Ausgabe des Markup-Codes. Dies war fehleranfällig, aufwendig, schlecht zu warten und gräuslich anzusehen. Von einer Tool-Unterstützung ganz zu schweigen.
Servlets haben dennoch ihre Berechtigung, wie auch im weiteren Verlauf dieses Kapitels deutlich werden wird. Sie sind hervorragend für die Generierung binärer Inhalte wie bspw. Bilder oder PDFs geeignet. Und sie sind als FrontController für Web-Anwendungen der ideale Einstiegspunkt. Mehr dazu im Abschnitt zum "Model 2" weiter unten.

JSP-basierte Model 1-Architektur

Sowohl die zumeist in Perl geschriebenen CGI-Skripte als auch Servlets waren, wie schon geschrieben, ziemlich unübersichtlich und erforderten eine Unmenge von out.println()-Statements, um HTML-Code auszugeben. Dabei existierte spätestens 1995 mit dem Erscheinen der ersten ColdFusion-Version eine Alternative, in der ein Template verwendet wird, das aus HTML-Code und in diesem eingebetteten Programm-Code besteht. Diese Variante hat sich inzwischen durchgesetzt, und alle weit verbreiteten Web-Technologien wie JSP, ASP, PHP, Rails und ColdFusion verwenden Templates. Der große Vorteil bei diesem Ansatz ist, dass Web-Designerinnen mit ihren üblichen Tools weiter arbeiten können. Diese Tools ignorieren zumeist die eingestreuten Tags zur Repräsentation der Programmlogik und zeigen ansonsten den reinen HTML-Bestandteil wie gewöhnlich an.
Auch bei der JSP-basierten Model 1-Architektur war das Vorgehen seitenzentriert. Anstelle von einem Servlet pro Seite gab es nun eine JSP pro angezeigter Webseite. Zumeist lief oder läuft der Prozess so, dass die Webseiten von der Designerin kommen und von der Programmiererin anschließend der Programm-Code in die Seite eingebettet wird. Anstelle von HTML-Ausgaben im Java-Code hat man nun Java-Code in HTML eingebettet.
Schon schnell wurde als ein Problem erkannt, dass der Java-Code ziemlich umfangreich werden kann und zudem Web-Designerinnen möglichst wenig von diesem sehen wollen.2 Zudem wurde schnell klar, dass eine Trennung zwischen Code, der rein mit der Oberfäche zu tun hat, und Code, der die Geschäftslogik enthält, unerlässlich ist. Anderenorts gab es diese Trennung auch schon längst (MVC bspw. war zu dem Zeitpunkt schon weit verbreitet und auch jenseits von Smalltalk3 vielfach genutzt). Dass die Webgemeinde relativ spät auf den MVC-Zug aufsprang, erklärt sich vermutlich aus der Tatsache, dass server-basierte Elemente anfangs noch von relativ geringer Komplexität waren. Und während Software-Design-Prinzipien schon lange zum Handwerkszeug von Software-Entwicklerinnen gehörten, waren diese bei Web-Designerinnen unbekannt und anfangs auch nicht nötig. Wer Anwendungen aus der frühen Phase der java-basierten Webentwicklung gesehen hat, weiß, wie wenig sauber die Trennung der Schichten seinerzeit war und wie schwierig die Wartung von JSP-Anwendungen war, die Unmengen von Java-Code enthielten.
Bereits die Version JSP 1.0 enthielt die Möglichkeit, Beans aus JSPs heraus ohne expliziten Java-Code zu nutzen (s. dazu das Kapitel Beans in JSPs). Die von der Spezifikation mitgelieferten Tags machten es bspw. möglich, alle Formulardaten auszulesen und einer Bean in einem der vier Sichtbarkeitsbereiche zuzuordnen. Alleine damit kam man aber nicht zum Ziel, so dass auf jeden Fall ergänzender Java-Code in Skriptlets nötig war (bspw. für Schleifen, zur Konvertierung von Daten, zum Aufrufen der Geschäftslogik etc.). Einen deutlichen Schritt in die richtige Richtung hat SUN dann mit der Spezifikation 1.1 für JSPs getan. Hier wurden die sogenannten CustomTags eingeführt (s. Kapitel Tag-Libraries). Mit diesen war es nun möglich, häufig wiederkehrende Aufgaben in eigene CustomTag-Bibliotheken auszulagern. Schleifen und Verzweigungen sind hier zwei der wohl meist genutzten Beispiele. Schon bald gab es Bibliotheken mit häufiger genutzten Funktionalitäten.4
Damit wurde der Java-Anteil (wenn man denn vernünftigen Gebrauch von CustomTags machte) erheblich gesenkt. Allerdings waren obskurere Funktionen, für die sich die Schaffung eines eigenen Tags nicht lohnte, und v.a. der Aufruf der Geschäftslogik immer noch Java-Skriptlets vorbehalten. Auch die unschönen Bean-Tags wurden erst mit der Einführung der EL in der Spezifikation zu JSP 2.0 überflüssig, wenngleich sie natürlich immer noch nutzbar sind (zur Expression Language siehe das Kapitel Expression Language).


David López bezieht in seinem Blogbeitrag "DO logic in JSPs" die Position, dass man in JSPs Logik verwenden kann, bzw. sogar verwenden sollte. Er argumentiert, dass View-relevanter Code in die JSPs hineingehöre, da die JSPs eben die Views ausmachten. Soweit es sich ausschließlich um Code handelt, der tatsächlich lediglich die View betrifft (bspw. Java-Code für Schleifen bei der Ausgabe von Tabellen etc.), so kann man dies vertreten. Meine Erfahrung aus diversen Projekten zeigt allerdings, dass die Disziplin im Team schnell nachlässt und meist schon bald ("nur vorübergehend; können wir dann später, wenn wir mehr Zeit haben, ja wieder bereinigen..." - man hört es immer wieder, obwohl jeder weiß, dass es dieses Bereinigen nie geben wird) Code hinzugefügt wird, der doch nichts mehr mit der reinen Darstellung zu tun hat. Dennoch lohnt sich der Blogbeitrag, da er auf Auswüchse hinweist, in denen die Verrenkungen doch zu absurd sind. Allerdings hilft m.E. die Expression Language, die meisten dieser Auswüchse zu verhindern.

Zum SeitenanfangZum Seitenanfang

Model 2

Die seitenzentrierte Sichtweise aus den Model 1-Architekturen stößt bei größeren Anwendungen schnell an ihre Grenzen. Und so besann man sich auch in der Welt der Web-Entwicklung altbekannter Design-Muster und suchte nach Wegen, MVC in die Webwelt zu übertragen, in Form der Model 2-Architektur.

Ursprüngliches MVC

Model View Controller (kurz MVC) bezeichnet ein weit verbreitetes Architekturmuster, das bereits in den späten Siebzigern5 am Xerox Palo Alto Research Center (Xerox PARC) gefunden wurde.6
Das Model View Controller-Muster bietet eine Lösung für das Problem, die gleichen Daten auf unterschiedliche Weise präsentieren zu müssen. Bestimmend ist dabei, dass vielfach unterschiedliche Clients auf die Daten zugreifen. Ein weiterer wesentlicher Faktor ist, dass die View(s) i.a.R. häufiger geändert werden müssen als das Domänenmodell einer Anwendung und daher Änderungen an der View unabhängig von Änderungen am Domänenmodell durchführbar sein sollen. Die Lösung liegt in der Trennung der Verantwortlichkeiten in die drei namensgebenden Bestandteile Model, View und Controller.
Das Model enthält die Logik der Anwendung sowie den aktuellen Zustand. Es kennt weder den Controller noch die View. Bei dem Model können allerdings Observer-Objekte registriert werden, die bei Änderungen im Model-Zustand dann von diesem automatisch benachrichtigt werden (Beobachter- oder Observer-Muster). Dazu müssen die registrierten Objekte über eine wohldefinierte Schnittstelle verfügen, die das Model zur Benachrichtigung aufrufen kann.
Die View ist zuständig für die Darstellung des Model-Zustands, also i.a.R. der persistierten Daten. Dabei kann es zu einem Model eine beliebige Anzahl von Views geben. Bspw. für unterschiedliche Geräte (PDA, Desktop-PC) oder Ausgabeformate (PDF, HTML, Swing). Die Aufbereitung der Daten für die automatische Bearbeitung durch maschinelle Clients fällt ebenso in die Zuständigkeit der View. Die Views sind idealerweise als Observer bei dem sie interessierenden Model registriert, so dass sie umgehend auf Änderungen des Model-Zustandes reagieren können und die aktualisierten Daten zur Darstellung bringen.
Der Controller wiederum nimmt alle Eingaben der Nutzerin7 entgegen. Der Controller verarbeitet die Daten nicht weiter, sondern ruft geeignete Funktionalitäten (Services oder Methoden) des Models auf. Ggf. wandelt der Controller dazu die Eingabeparameter in Model-gemäße Attribute und Objekte um.
Das folgende Schaubild fasst das Zusammenspiel der drei beteiligten Komponenten zusammen:
image_mvc.png

Model 2 Grundlagen

Wirkliches MVC im urspünglichen Sinne ist in Web-Anwendungen nicht möglich. Dies liegt daran, dass das Model in Web-Anwendungen die View nicht darüber informieren kann, wenn sich Änderungen in seinem Status ergeben. Die Ursache hierfür ist das der Web-Kommunikation zugrundeliegende HTTP-Protokoll, das ein einfaches (aber sehr effektives) Request-Response-Protokoll ist (s. dazu mehr im Anhang I: HTTP-Grundlagen). Das heißt, dass die Anfragen immer vom Client ausgehen und der Server nur auf Anfragen hin eine Antwort liefert. Der Server kann nicht von sich aus aktiv werden und dem Client Daten schicken oder diesen über Änderungen informieren. Dies ist ein deutlicher Unterschied bspw. zu einer Swing-Anwendung, wo Views beim Model registriert und nachfolgend unmittelbar über Änderungen im Zustand des Models informiert werden können.
Da sich MVC aber als ein wirksames Muster für die Oberflächenprogrammierung erwiesen hat, wurde eine an die Beschränkungen des HTTP-Protokolls angepasste Variante geschaffen, eben das Model 2 (gelegentlich auch MVC2 genannt). Die Aufteilung sieht hier so aus, dass ein zentrales Dispatcher-Servlet als Controller fungiert. Das Dispatcher-Servlet nimmt die Anfragen und Eingaben der Nutzerin entgegen und entscheidet aufgrund von Angaben im Request oder der Request-URL, welches Handler-Servlet für die Bearbeitung zuständig ist und leitet die Anfrage an dieses Servlet weiter. Das Handler-Servlet liest die Daten aus dem Request aus (bspw. Nutzerinnen-Eingaben in ein Formular), wandelt diese in geeignete Datentypen für das Model um und ruft eine der Anfrage entsprechende Business-Methode des Models auf. Kommt der Methodenaufruf zurück, wertet das Handler-Servlet die Ergebnisse aus und bereitet ggf. Daten für die View in ein Format um, das für diese geignet ist. Aufgrund der Natur des HTTP-Protokolls kommen letztlich von der View Eingabewerte immer nur in Form von Strings an, und es können auch nur textuelle Daten der View übergeben werden.8 Der Controller entscheidet zudem, welche View angezogen wird, in unserem Fall also, an welche JSP oder welches Servlet der Request zur Erzeugung der Antwort weitergeleitet wird.
Das Model in der Model 2-Ausprägung von MVC entspricht dem oben beschriebenen Model des klassischen MVC. Allerdings können Webseiten nicht als Observer registriert werden. Ein Swing-basiertes Model sollte dennoch problemlos nutzbar sein, sofern dieses sich an die Vorgabe aus dem MVC-Muster gehalten hat, nichts über etwaige Views oder Controller zu wissen.
Die View kann immer nur den aktuellen Zustand des Models wiedergeben. Ob dabei direkt auf Objekte aus dem Model zugegriffen wird oder spezielle Datentransfer-Objekte genutzt werden, hängt stark von der zugrundeliegenden Technologie des Models ab. Nutzt dieses bspw. EJBs vor der 3er-Spezifikation, sollten immer Datentransfer-Objekte genutzt werden.

Zum SeitenanfangZum Seitenanfang

Struts

Wie auch die JavaServer Faces im nächsten Absatz ist das Struts-Framework keine grundlegende Neuerung gegenüber der Model 2-Architektur, sondern vielmehr eine konkrete Ausprägung dieser Architektur. Das Struts-Framework ist vermutlich das weit verbreiteste Model 2-Framework und wird seit fünf Jahren in einer Vielzahl von Projekten eingesetzt. Im Tutorial ist ein eigenes Kapitel zum Struts-Framework geplant, so dass hier nur ein Überblick über die Struts-spezifische Umsetzung des MVC-Musters gegeben wird. Wie man mit Struts programmiert, wird in dem erwähnten Kapitel beschrieben werden. Lohnenswert zu Struts ist auch ein Besuch auf Sebastian Hennebrüders Seite www.laliluna.de und natürlich der Struts Projekt-Seite.
image_struts_architecture.png
Den Controller bei Struts-basierten Anwendungen bildet zunächst einmal das ActionServlet (org.apache.struts.action.ActionServlet), das als FrontController agiert. Ferner gehören zum Controller Objekte der von der abstrakten Basis-Klasse org.apache.struts.action.Action abgeleiteten anwendungs-spezifischen Action-Klassen und der von org.apache.struts.action.ActionForm abgeleiteten ActionForm-Klassen. Das ActionServlet nimmt die Anfrage entgegen und ermittelt als erstes anhand eines in einer XML-Datei definierten Mappings, welche Aktion ausgeführt werden soll. Zu jeder Aktion gehört ein ActionForm- und ein Action-Objekt, die vom ActionServlet instanziiert werden. Vom welchem Typ diese Objekte sind, ist ebenfalls in der XML-Datei festgelegt (s. dazu das Beispiel weiter unten). Sind die Objekte erstellt, befüllt das ActionServlet das ActionForm-Objekt mit den Request-Parametern wie bspw. den Formulardaten und übergibt das Objekt an das zum Mapping gehörende Action-Objekt. Aus den Actions heraus wird dann die eigentliche Geschäftslogik aufgerufen. Die benötigten Argumente für den Aufruf der Geschäftslogik werden aus dem ActionForm-Objekt ausgelesen. Ergebnisse aus der Geschäftslogik werden anschließend von der Action ausgewertet und die für die nächste View benötigten Werte im ActionForm-Objekt abgelegt.
Ausgehend vom Ergebnis und Erfolg des Aufrufs der Geschäftslogik geben die Action-Klassen ein ActionForward-Objekt zurück, das vom FrontController, dem ActionServlet, wiederum zur Ermittlung der nächsten anzuzeigenden View genutzt wird.
Als View kommen standardmäßig JSPs zum Einsatz. Zur Unterstützung der Arbeit mit JSPs liefert Struts eigene Tag-Libraries mit, die besonders die Erstellung von Formularen und die Arbeit mit Beans vereinfachen. Teile der Tag-Bibliothek sind durch die JSTL und die EL zumindest für neuere Projekte überflüssig geworden (zu JSTL und EL s. die Kapitel "Expression Language" und "Java Standard Tag Library (JSTL)").
Das Model liegt - wie im Schaubild ersichtlich - komplett außerhalb der Zuständigkeit von Struts und wird von diesem lediglich innerhalb der Action-Klassen aufgerufen - in der Grafik wurde daher das Model mit abgerundeten Ecken dargestellt.
In der schon erwähnten XML-Datei9 werden die ActionForm- und Action-Klassen sowie das Zusammenspiel der einzelnen Bestandteile deklariert. Der folgende Ausschnitt aus einer Config-Datei zeigt beispielhaft je einen ActionForm- und einen Action-Eintrag:

<struts-config>

    <!-- Define the ActionForm-objects to be used 
            within Action-Mappings -->
    <form-beans>
       <form-bean name="mailForm" 
               type="org.jsptutorial.examples.struts.mail.MailForm" />   
       <!-- addtional form bean definitions... -->
    </form-beans>
    
    
    <!-- Define any frequently used forwards 
            as global forwards -->
    <global-forwards type="org.apache.struts.action.ActionForward">
        <forward name="login" path="/login.jsp" redirect="false" />
        <!-- addtional global forward definitions... -->
    </global-forwards>
    
    
    <!-- Map URLs to the approprate Action-Objects 
            and specify the ActionForm-objects to use -->
    <action-mappings>
        <action path="/sendMail"
                type="org.jsptutorial.examples.struts.mail.SendMailAction"
                name="mailForm"
                scope="request"
                input="/mail.jsp"
                unknown="false"
                validate="true">
            <!-- Add local forward definitions if appropriate -->
            <forward name="success" path="/showCloseWindow.jsp" 
                    redirect="false" />
            <forward name="failure" path="/editMail.jsp" 
                    redirect="false" />
        </action>
        <!-- addtional action mappings... -->
    </action-mappings>

</struts-config>

Struts ist in jüngerer Zeit wiederholt in die Kritik geraten, und andere Frameworks (wie WebWork, Spring MVC, Wicket, RIFE oder Stripes) versuchen, Schwächen von Struts auszugleichen. Durch die Anfang 2006 beschlossene Zusammenarbeit zwischen der Struts- und der WebWork-Community ist allerdings damit zu rechnen, dass Struts etliche Kritikpunkte aufgreift und korrigiert.10

Zum SeitenanfangZum Seitenanfang

JavaServer Faces

Wie schon am Anfang des Struts-Abschnittes erwähnt, sind die JavaServer Faces (JSF) ebenfalls eine Ausprägung der Model 2-Architektur. Dennoch unterscheidet sich die JSF-Vorgehensweise deutlich von der Struts-Vorgehensweise. Standen bei Struts die Actions, die Auswertung ganzer Formulare und deren Verarbeitung und Delegation an die Geschäftslogik im Mittelpunkt, so bilden bei JSF Komponenten den zentralen Bezugspunkt. Das Entwickeln mit JSF hat daher eine größere Ähnlichkeit mit der Eventgesteuerten GUI-Programmierung unter AWT, Swing oder SWT.11 Eine Besonderheit bei JavaServer Faces ist die genaue Definition eines Lebenszyklus, den alle Anfragen durchlaufen. Dieser umfasst insgesamt sechs Teilschritte, bspw. Schritte zur Wiederherstellung des Komponentenzustands, Validierung, Modelaktualisierung und natürlich das Rendern (Erzeugung des Markup-Codes) der View (s. Grafik).
image_jsf_lifecycle.png
Aus dem bisher Beschriebenen wird deutlich, dass JSF gegenüber Struts aus mehr, dafür aber spezialisierteren Komponenten besteht. Das hat sowohl Vor- als auch Nachteile. Der größte Nachteil ist natürlich, dass der Lernaufwand deutlich höher ist als bei Struts. Und bei den ersten Projekten dürfte auch der Code-Aufwand beachtlich sein. Doch mit zunehmender Erfahrung und mehreren aus vorherigen Projekten vorhandenen Komponenten wird dann auch der Vorteil ersichtlich: Durch die deutlich spezialisierteren Komponenten werden diese dem immer wieder beschworenen Anspruch an Wiederverwendbarkeit weitaus häufiger gerecht, als dies bei Struts-Anwendungen der Fall ist.
Spezielle Validatoren oder Konverter für Projekte innerhalb eines Unternehmens oder einer Branche dürften vielfach wiederverwendbar sein (bspw. wird die Prüfung einer ISBN-Nummer immer den gleichen Regeln unterliegen, egal in welchem Projekt man sie nutzt). Besonders stark allerdings kommt die Wiederverwendbarkeit bei den UI-Komponenten zum Tragen. Ein Blick auf die Webseite des MyFaces-Projekts dürfte deutlich machen, wie viele fertige Komponenten es gibt und wie viel HTML-Codierung dadurch eingespart werden kann.12
Die Komponenten, die das JSF-Framework nutzt bzw. teilweise bereits mitbringt, umfassen zunächst einmal das klassische FrontController-Servlet, darüber hinaus die spezifischen JSF-Komponenten Validatoren, Konverter, Backing Beans, Listener, UI-Komponenten und Renderer. Hinzu kommt noch eine deklarative Definition der Navigation, die dadurch ebenfalls von der Anwendungslogik entkoppelt ist. Gegenüber Struts ist das Zusammenspiel deutlich komplexer geworden und kaum mehr grafisch wiederzugeben.
Der Controller setzt sich bei JSF-Anwendungen somit aus mehreren Komponenten zusammen. Zentral ist hier das javax.faces.application.FacesServlet. Dieses bildet den FrontController und ist bei JSF v.a. für die Verwaltung des Lebenszyklus eines Requests verantwortlich. Der aktuelle Zustand der Request-Verarbeitung und Response-Generierung wird dabei jeweils in einem javax.faces.context.FacesContext-Objekt pro Anfrage verwaltet. Darüber hinaus gehören alle Validatoren und Konverter zum Controller. Wesentliche Elemente des Controllers sind zudem die an den Komponenten registrierten Listener. Während Validatoren und Konverter häufig wiederverwendbar und für einige übliche Prüfungen und Umwandlungen bereits Bestandteil des JSF-Standards sind, sind die Listener und Actions spezifisch für die jeweilige Anwendung zu schreiben. Diese reagieren auf Status-Veränderungen der Komponenten und auf Ereignisse wie Button-Klicks. Aus den speziellen Actions heraus, die es nur bei javax.faces.component.UICommand-Komponenten gibt, wird die Geschäftslogik aufgerufen. Schlussendlich gehört der NavigationHandler in Verbindung mit der Konfigurationsdatei13 ebenfalls zum Controller. Abhängig von den Ergebnissen der Action-Methoden, des Zustandes der Anwendung und der vorgenommenen Konfiguration entscheidet dieser über die nächste anzuziehende View.
Wie auch bei Struts setzen JavaServer Faces für die View primär auf JSPs. Alle Standard-konformen Implementierungen müssen zumindest auch JSPs unterstützen.14 Das Besondere an der View bei JavaServer Faces sind jedoch die UI-Komponenten. Diese bestehen zum einen aus einem Tag (in JSF 1.1 von javax.faces.webapp.UIComponentTag, ab JSF 1.2 von javax.faces.webapp.UIComponentELTag abgeleitet). Der Tag dient der Einbindung der Komponente in die JSP und besteht im Wesentlichen aus Settern und Gettern. Zum zweiten ist eine von javax.faces.component.UIComponent abgeleitete Klasse zu implementieren, die den Zustand der Komponente verwaltet und für das Rendern der Response bzw. das Auswerten der Nutzerinnen-Eingaben zuständig ist. Das Rendern kann auch an eine in der Konfigurationsdatei angegebene und von javax.faces.render.Renderer abgeleitete Klasse delegiert werden. Hier kommt es in der zweiten Phase des Lebenszyklus eines Requests zur Auswertung der komponentenspezifischen Eingaben der Nutzerin und in der letzten Phase des Lebenszyklus zur Erzeugung des Codes für die Response (zumeist dürfte dies HTML sein). Die Komponenten-Tags in den JSPs geben entsprechend ihrer Schachtelung den Komponentenbaum einer Seite vor. Dieser wird beim Erstaufruf einer JSF-Seite erzeugt und bei weiteren Anfragen an die Seite in der ersten Phase des JSF-Lebenszykluses wiederhergestellt.
Das Model setzt sich bei JSF-Anwendungen zum einen aus sogenannten Backing Beans und zum anderen aus der Geschäftslogik der Anwendung zusammen. Die Backing Beans sind Beans, die an Komponenten gebunden werden und z.B. mit den geänderten Werten eines Formulares gefüllt werden, falls alle Konvertierungen und Validierungen erfolgreich verlaufen sind. In der Regel wird man jedoch als Backing-Beans nicht direkt Klassen der Geschäftslogikschicht nutzen, sondern diese aus den Backing-Beans heraus aufrufen. Die konkrete Ausgestaltung des Models und die Anbindung der Geschäftslogik ist bei der Verwendung von JavaServer Faces der architekturell umstrittenste Punkt. Interessant in diesem Zusammenhang scheint das Projekt JBoss Seam zu sein, das eine enge Integration von EJB3- und JSF-Technologien ermöglicht, so dass ein einziges mit Annotationen versehenes POJO (Plain Old Java Object) sowohl als Backing Bean als auch als EJB3-Bean verwandt werden kann.
Für das JSP-Tutorial ist auch ein Bereich zu den JavaServer Faces geplant. Bis wir diesen erstellt haben, sei auf die Einführung von Matthias Fischer und auf die offizielle JSF-Seite von SUN verwiesen. Letztere enthält einen reichhaltigen Fundus an einführendem englischsprachigen Material.

Zum SeitenanfangZum Seitenanfang

Exkurs

Architektur relativiert

Eines vorne weg: Ich halte Architektur für wichtig - sogar für sehr wichtig.15 Allerdings halte ich Architektur noch viel mehr für völlig überschätzt.
Der Projektverlauf kann mit einer guten Architektur sicherlich positiv beeinflusst werden - letztlich sind aber der Prozess und vor allem das Team zumindest genau so wichtig, wenn nicht sogar wichtiger. Ich habe schon Projekte nach der oben etwas schlecht geredeten Model 1-Architektur gesehen, die dennoch für die Anwenderin hervorragend nutzbare Software hervorgebracht haben. Trotz bspw. Unmengen von Java-Code in den JSPs konnte der Wartungsalptraum dank eines hervorragend zusammenarbeitenden Teams in Grenzen gehalten werden. Ebenso habe ich sowohl mit Model 1 und Model 2 sauberere Lösungen gesehen, bei denen der Erfolg dennoch eher bescheiden war. Wenn die Chemie im Team und zwischen dem Team und seiner Umgebung16 nicht stimmt, ist ein Projekt auch mit einer durchdachten Architektur kaum zu retten.17
Häufig reichen schon kleine Dinge zur Verbesserung des Arbeits- und Teamklimas und der Motivation aus. Der berühmte Obstteller aus dem Dot-Com-Hype ist ein positives Beispiel für eine kleine Maßnahme zur Verbesserung der Arbeitsumgebung. Die Firmenleitungen zahlreicher damaliger Hype-Unternehmen dienen hingegen nur zu oft als Negativbeispiel.
Wer nun denkt, dass dies lediglich Kleinigkeiten seien, der sollte sich mal mit den Problemen vertraut machen, die Microsoft sich durch die Kürzung der Benefits eingehandelt hat. Bekannt wurde hierbei vor allem der Towel-Service: Das erneute kostenlose Waschen von Handtüchern in den Microsoft-Umkleidekabinen wurde auf einer Mitarbeiterversammlung bei der Vorstellung diverser Neuigkeiten am stärksten gefeiert.18 Hier geht es um die implizit mit solchen Maßnahmen ausgedrückte Wertschätzung, bzw. die mit dem Streichen oder Schaffen solcher kleinen Maßnahmen verbundene Veränderung der Wertschätzung. Die psychologische Wirkung, die durch die Schaffung einer angenehmen Arbeitsumgebung und kleiner Anreize, erzielt wird, sollte nicht unterschätzt werden.
Wenn die weichen Faktoren nicht stimmen, hat man ein gravierenderes Problem, als wenn die Architektur nicht ganz sauber eingehalten wird. Stimmen die Bedingungen nicht, kann ein Projekt fast nicht gelingen. Die vielfach gepriesene Sicht, andere Abteilungen als Kundinnen zu betrachten, finde ich in diesem Zusammenhang zumindest zweifelhaft. Ein gesundes kollegiales Verhältnis ist da allemal besser.19
Leider wird auf die Erarbeitung einer sauberen Architektur häufig viel, mitunter gar zu viel Zeit verwandt. Es werden Expertinnenkommittees und Architektur-Gremien geschaffen, es wird sich in Meetings getroffen und viel Papier gedruckt. Gleichzeitig wird erschreckend wenig Wert auf die Aufrechterhaltung eines guten bzw. die Schaffung eines besseren Arbeits- und Projektklimas gelegt. Wohlgemerkt: Hier geht es nicht um ein entweder-oder, sondern um ein sowohl-als auch. Ein gutes Team, das sein Projekt auf einer durchdachten Architektur aufsetzen kann, kann sicherlich am meisten bewegen.

Zum SeitenanfangZum Seitenanfang

Anmerkungen:

1) Stabile Schnittstellen bedeuten, dass die nach außen sichtbaren Klassen, Interfaces und Methoden allenfalls geringen Änderungen unterworfen sind. I.a.R. wird eine Schnittstelle einer Komponente so erweitert, dass sowohl die Nutzung der alten Methoden, als auch neuer Methoden möglich ist. Ein Schnittstelle ist dann abwärtskompatibel. Im Interesse der Stabilität kann es dennoch von Zeit zu Zeit notwendig sein, diese Abwärtskompatibilität bewusst zu brechen. (zurück)

2) Verständlicherweise wollen diese sich auf ihre Aufgabe konzentrieren. Alles in einer Webseite, das nicht reiner client-basierter Code wie HTML, JavaScript oder CSS ist, stört Designerinnen bei ihrer Arbeit nur. (zurück)

3) Das MVC-Konzept kommt ursprünglich aus der Smalltalk-Welt, wurde aber schnell auch in anderen GUI-orientierten Entwicklungsgemeinden wie bspw. in der Swing-Entwicklung aufgenommen. (zurück)

4) Als eine Kuriosität am Rande sei erwähnt, dass LiveSoftware zu seinem JSP-Container JRun CustomTags mitlieferte, die weitestgehend an die damals beliebte Coldfusion Markup Language CFML angelehnt waren. Allaire, das seinerzeit ColdFusion entwickelte und verkaufte, kaufte daraufhin LiveSoftware, um sich der Konkurrenz zu entledigen. Inzwischen wurde Allaire von Macromedia gekauft, die wiederum von Adobe gekauft wurden. Es gibt immer noch sowohl JRun als auch den ColdFusion-Server, beides J2EE-konforme Server, allerdings versteht nur der Letztere CFML-Tags. (zurück)

5) Wer sich für den historischen Kontext interessiert, dem empfehle ich die folgende Seite: Xerox Parc (engl.), die Links zu den Ursprüngen des Patterns im Xerox PARC enthält. BTW: Wer denkt, dass Apple, Atari oder Commodore graphische Desktops erfunden hätten, sollte auf Wikipedia den Eintrag zum Xerox Parc lesen: Xerox Parc auf de.wikipedia.org, bzw. etwas ausführlicher auf der englischen Wikipedia-Seite: Xerox Parc auf en.wikipedia.org. (zurück)

6) Bei Design- und Architekturmustern spricht man vom "Finden". Damit ist gemeint, dass niemand das Muster erfindet, sich das Muster ausdenkt oder dass ein Expertinnenkommittee das Muster sozusagen am Reißbrett entwirft, sondern dass vielmehr ein häufig wiederkehrendes Muster bei der Lösung ähnlich gelagerter Probleme gefunden wird. D.h. Muster sind immer schon bekannte Lösungen, die sich mehrfach als geeignet für gleichartige Probleme erwiesen haben. Zu jedem Muster gehört damit immer eine Beschreibung des Problems und der Faktoren (Kontext), die für das Problem ursächlich sind, sowie die Lösung für das Problem unter Berücksichtigung der aufgeführten ursächlichen Faktoren. (zurück)

7) Dies gilt genauso natürlich auch für Interaktionen und Anfragen automatischer Kanäle wie bspw. Web Services. (zurück)

8) Diese textuellen Daten für die View und von der View können freilich komplizierten Objektgraphen entsprechen. Es kommt nur darauf an, ein geeignetes textuelles Serialisierungsformat zu finden. Bei AJAX-Anwendungen kommt bspw. häufig mit JSON (JavaScript Object Notation) ein objektbasiertes Datenformat in Textform zum Einsatz. (zurück)

9) Bei der Nutzung von Modulen können Teile der Konfiguration in zusätzliche Dateien ausgelagert werden. (zurück)

10) Übrigens ist Ruby on Rails auch ein Vertreter dieser Art von Web-Frameworks, wobei Rails eben auf Ruby anstelle von Java als Programmiersprache setzt. Der Charme von Rails liegt darin, dass Rails sehr viele Annahmen macht und dadurch bspw. XML-Mappings eingespart werden können und sich die Entwicklungszeit verkürzen kann. Der Nachteil von Rails liegt allerdings ebenfalls darin, dass Rails sehr viele Annahmen macht und dadurch die Entwicklerin in ihren Möglichkeiten begrenzt. Das von manchen gegen Rails vorgebrachte Performance-Argument halte ich für wenig überzeugend, schließlich hat die Geschichte von Java gezeigt, wie sich über die Zeit die Performance einer Technologie mit zunehmender Reife verbessern kann. (zurück)

11) Erwähnt werden sollte, dass mit Tapestry ein weiteres java-basiertes Framework zur Verfügung steht, das ebenfalls komponentenbasiert ausgelegt ist. Ebenso verfolgt ASP.NET von Microsoft im Unterschied zum nicht .NET-basierten Vorgänger einen komponentenbasierten Ansatz. (zurück)

12) Auch das hat einen Nachteil. Web-Designerinnen werden ggf. nicht mehr mit ihren gewohnten Tools arbeiten können, da die meisten Design-Tools die JSF-UI-Komponenten nicht kennen und/oder verstehen. Die JSF-UI-Komponenten (z.B. alle von MyFaces oder der Referenzimplementierung von SUN) sind aber in aller Regel so ausgelegt, dass die visuelle Darstellung weitestgehend über CSS angepasst werden kann. Somit stehen der Designerin nach wie vor alle Möglichkeiten zur Formatierung offen - auch wenn die Tool-Unterstützung derzeit v.a. auf Java-IDEs wie Netbeans, JDeveloper oder Java Studio Creator beschränkt ist. (zurück)

13) Wie bei Struts ist auch bei JavaServer Faces die Nutzung mehrerer Konfigurationsdateien möglich. (zurück)

14) JSPs und JavaServer Faces vertrugen sich vor den neuen Spezifikationen JSP 2.1 und JSF 1.2 nicht sehr gut. Deshalb wurden auch alternative View-Technologien genutzt, wovon v.a. Facelets eine größere Verbreitung erlangt haben. (zurück)

15) Leider ist der Begriff Architektur allerdings vielfach eine nichtssagende Worthülse, die gerne in den Raum geworfen wird, ohne inhaltlich gefüllt zu werden. (zurück)

16) Die Umgebung besteht bspw. aus den Vorgesetzten, der Firmenleitung, der Firmenkultur, der Zusammenarbeit mit den Administratorinnen (idealerweise sind die Bestandteil des Teams), der Einbindung und Anzahl externer Projektmitarbeiterinnen, aber auch aus so schnöden Dingen wie Räumlichkeiten, Sitzordnung, Essensmöglichkeiten u.ä. (zurück)

17) Ähnlich auch Bruce Eckel in einem Artikel auf der Seite artima.com: "Usually the things that make or break a project are process and people issues. The way that you work on a day-to-day basis. Who your architects are, who your managers are, and who you are working with on the programming team. How you communicate, and most importantly how you solve process and people problems when they come up. The fastest way to get stuck is to think that it's all about the technology and to believe that you can ram your way through the other things. Those other things are the most likely ones to stop you cold." (zurück)

18) Links zur Wiederaufnahme des Services: ZDNet bzw. Seattle Post-Intelligencer; Links zur Unzufriedenheit und der symbolischen Bedeutung des Towel-Services: Seattle Post-Intelligencer und Seattle Times. (zurück)

19) Bisher habe ich weder in der IT noch in anderen Bereichen ein allzu hohes Ansehen der Kundinnen bei Dienstleisterinnen, Verkäuferinnen oder Auftragnehmerinnen gesehen. Kundenorientierung als Leitlinie interner Unternehmenskommunikation ist m.E. daher eine äußerst seltsame Vorgabe. (zurück)


www.jsptutorial.org
© 2005, 2006, 2007