$KK(Filter) $R(Objective) Describe the Web container request processing model; write and configure a filter; create a request or response wrapper; and given a design problem, describe how to apply a filter or a wrapper. $R\ $KKK(Was sind Filter) Filter setzen sich vor einem Servlet. Sie können Anfragen abblocken, bzw ändern und sie können Antworten ändern. Mehrere Filter können zu einer Filterkette zusammengebaut werden. $B(Bilder,filterDefinition.gif, Prinzip der Filter) Enthält ein Filter eine Anfrage, so hat er prinzipiell folgende Möglichkeiten: * Er generiert die Antwort selber * Er leitet die Anfrage (modifiziert oder nicht) zum nächsten Filter, oder falls er letzte Filter in der Kette ist an das Servlet * Er leitet die Angabe an eine ganz andere Ressource um. D.h. der Filter nimmt die Rolle eines Dispatchers ein. Typische Aufgaben eines Filters sind: * Berechtigungsüberprüfungen * Protokollierungen * Anhang z.B: Bilder in ein Standardformat konvertieren. * Daten komprimieren. * Daten verschlüsseln. * Triggern von Events $KKK(Das Request Processing Model) Wenn ein Servlet Container eine Anfrage erhält, passiert folgendes: # Anhand der servlet-mapping Elemente in Datei web.xml sucht er das Ziel-Servlet. # Anhand der filter-mappging Elemente in Datei web.xml sucht er die Filter die dem Ziel Servlet vorgeschaltet werden. Der Container laedt diese Filter entsprechend dem Elementen der Datei web.xml, instantiiert und initialisiert sie. # Der Container baut die gefundenen Filter zu einer Filterkette zusammen. # Die Anfrage wird an den ersten Filter geleitet. # Es ist dann die Aufgabe des jeweiligen Filters die Anfrage an den nächsten Filter weiterzuleiten (oder auch nicht). $KKK(Konfiguration einer Filterkette) Ein Filter wird in der Descriptor Datei nach folgender Syntax definiert $B(Bilder,filter.gif, Aufbau eines Filter Elementes) $S() Validator Filter Validates the requests com.manning.filters.ValidatorFilter locale USA $S\ Ein filter Element hat fast den gleichen Aufbau eines servlet Elements, und braucht daher keine weitere Erklärung. Entscheident welche Filter vor einem Servlet gestellt werden ist das filter-mapping Element. $B(Bilder,filterMapping.gif, Aufau eines Filter Mapping Elements) Beispiel: $S() ValidatorFilter reportServlet ValidatorFilter *.doc $S\ Das Element dispatcher kann innerhalb vom filter-mapping 4 mal vorkommen, und folgende Werte annehmen: $T(simple,cl,25.75) FORWARD | Filter wird angewendet, wenn die Anfrage auf das Servlet mittels forward Befehl und RequestDispatcher zugegriffen wird || INCLUDE | Filter wird angewendet, wenn die Anfrage auf das Servlet mittels include Befehl und RequestDispatcher zugegriffen wird || REQUEST | Dies ist die Standareinstellung und wird genommen, falls die Anfrage an das Servlet direkt vom Clienten kommt || ERROR | Dies wird genommen falls das Servlet ueber den error-mapping Mechanismus aufgerufen wird || $T\ Bemerkung: Der RequestDispatcher Mechanismus dient dazu Anfragen von einem Servlet an ein anderes einzubinden, ohne dass der Browser es mitbekommt (im Gegensatz zu sendRedirect()), Dieser Mechanismus wird später behandelt. So findet ein Servlet Container die Filter zu einem Servlet: # Jeder Filter dessen url-pattern das Servlet matcht, wird als Filter genommen. Die Regeln für das url-pattern sind dieselbe wie beim servlet-mapping Element # Jeder Filter dessen servlet-name dem zugehörigen Servlet entspricht, wird als Filter genommen. # Die Reihenfolge der Filter wird folgendermassen definiert ## Nehme zuerst die Filter die durch ein url-pattern gematcht wurden. ## Nehme danach die Filter die durch servlet-name gematcht wurden. ## lnnerhalb dieser 2 Gruppen entscheidet die Reihenfolge in der die Filter in der Datei web.xml definiert sind. $KKK(Das Filter Interface) Jeder Filter muss das folgende Interface erfüllen: $S() public interface Filter{ public void init(FilterConfig filterConfig) throws ServletException; public void doFilter( ServletRequest request, ServletResponse, FilterChain chain) throws java.IOException, ServletException; public void destroy(); } $S\ die Methoden init(), doFilter() und destroy() spiegeln den Lebenszyklus eines Filters wieder. init() Methode Die init(FilterConfig) Methode entspricht der init(ServletConfig) Methode eines Servlets. FilterConfig enthält alle Initialisierungsparameter aus der web.xml Datei. Das folgende FilterConfig Interface zeigt, wie man diese Initialisierungsparameter ausliest. $S() public interface FilterConfig{ public String getFilterName(); public String getInitParameter(String name); public Enumeration getInitParameterNames(); public ServletContext getServletContext(); } $S\ doFilter() Methode Die doFilter() Methode ist analog zur service() Methode eines Servlets. Beachte dass als Argument kein HttpServletRequest und HttpServletResponse besitzt, sondern ein ServletRequest bzw. ServletResponse übergeben wird. Im allgemeinen wird auf am Anfang einer doFilter() Methode, die Argumente zu den entsprechenden Http Typen gecastet. Zusätzlich hat die doFilter() Methode ein FilterChain Objekt als Argument. $S() public interface FilterChain{ public void doFilter ( ServletRequest request, ServletResponse response ) throws IOException, ServletException; } $S\ Das FilterChain Objekt dient dazu mit der doFilter Methode eine Anfrage an den nächsten Filter in der Filterkette (bzw. dem entgütigen Servlet) weiterzuleiten. destroy() Methode Die destroy() Methode wird als letzte Methode aufgerufen, kurz bevor der Filter zerstört wird. Sie ist analog der destroy() Methode eines Servlets. $KKK(Umgang mit ServletRequestWrappers bzw. -ResponseWrappers) Es existieren 4 verschiedene Wrapper Klassen: * ServletRequestWrapper implements ServletRequest * HttpServletRequestWrapper implements HttpServletRequest * ServletResponseWrapper implements ServletResponse * HttpServletRequestWrapper implements HttpServletResponse Eine Wrapperklasse hat als Constructor genau ein Argument, das das Objekt enthaelt, was der Wrapper umwickelt. Dieses Argument hat ein je nach Art des Wrappers eine konkrete Klasse des (Http) ServletRequest bzw. (Http) ServletResponse. Beispiel: Im unteren Beispiel, wird dem nächsten Filter kein HttpServletResponse Objekt mitgegeben, sondern einen Wrapper um das HttpServletResponse Objekt. $S() doFilter(ServletRequest req, ServletResponse resp, FilterChain chain){ HttpServletResponse response = (HttpServletResponse) resp ; HttpServletResponseWrapper wrapper = new HttpServletResponseWrapper(response) chain.doFilter(resp, wrapper); } $S\ Was haben wir dadurch gewonnen?. So wie das obige Beispiel implementiert ist, zunächst mal nichts. Der Wrapper hat dasselbe Interface wie das umwickelte Objekt. Die Anfragen an den Wrapper werden einfach an das umwickelte Objekt weitergeleitet. $B(Bilder,prinzipWrapper.gif,Grundprinzip der Wrapper) Der Programmierer wird i.a. nicht direkt die angegebenen Wrapper benutzen, sondern Unterklassen davon verwenden. $S() doFilter(ServletRequest req, ServletResponse resp, FilterChain chain){ HttpServletResponse response = (HttpServletResponse) resp ; HttpServletResponseWrapper wrapper = new UnterklassevonHttpServletResponseWrapper(response) chain.doFilter(resp, wrapper); } $S\ In diese Unterklasse kann man z.B. implementieren dass die erzeugten Fehler mitprotokolliert werden. Beispiel $B(Bilder,anwendungWrapper.gif,Anwendungsbeispiel eines ResponseWrappers) Ein Wrapper dient dazu das Verhalten des umwickelten Objekts seinen eigenen Bedürfnissen anzupassen, ohne das umwickelte Objekt ändern zu müssen. Man könnte z.B. auch einen ResponseWrapper implementieren, der mit getOutputStream() statt einen normalen OutputStream ein Stream erzeugt, der die enthaltene Daten komprimiert. Beachte HttpServletResponse ist ein Interface und keine Klasse. Der Wrapper weiss gar nicht, welche konkrete Klasse das Objekt besitzt, das er umwickelt. Der Wrapper kann aber trotzdem das Verhalten des umwickelten Objekts seinen Bedürfnissen anpassen.