ObrázokAk začnete pracovať s aplikačnými servermi postavenými na Jave, skôr alebo neskôr sa stretnete s technológiou servletov. Servlet je v podstate Java trieda, ktorá nejako rozširuje možnosti servera alebo v ňom vytvára novú službu. Servlety môžu fungovať pre rôzne protokoly, ale pomerne často sa využívajú spolu s protokolom HTTP. Tak ako prídu Servlety, môže prísť časom aj problém, že chcete zmeniť spracovanie požiadavky alebo výsledku práce servletu bez toho, aby ste zasiahli do neho samotného (lebo nechcete alebo nemôžete). Našťastie aj na to sa myslelo, a preto si teraz niečo povieme o servlet filtroch.

V zásade servlet predstavuje službu, ktorá príjme nejaký vstup a môže vygenerovať nejaký výstup. Pre jednoduchosť budeme uvažovať v ďalších odsekoch, že ide o HTTP požiadavku. Takúto požiadavku si viete predstaviť ako množinu informácií, ktorá príde na server, tam sa tieto informácie vyhodnotia, vygeneruje sa odpoveď a tá sa pošle späť. Filtre, o ktorých tu budem teraz hovoriť, je možné nasadiť na aplikačný server, a tak odchytiť tieto množiny informácií a nejako ich pozmeniť predtým alebo potom, než ich spracuje server.

Rozhranie javax.servlet.Filter je súčasťou Java EE API, a teda by ho mal poznať každý správny javovský server. Obsahuje tri metódy, z ktorých je najpodstatnejšia doFilter, ktorá získa v parametroch objekt reprezentujúci požiadavku, objekt pre odpoveď a tiež objekt typu FilterChain, čo je reťaz objektov, ktoré budú ďalej spracovávať požiadavku. doFilter je presne tá metóda, v ktorej viete overiť, či má požiadavka správne bezpečnostné informácie (a zakázať ďalšie spracovanie, ak nie), alebo ju presmerovať na inú adresu, prípadne čokoľvek, čo budete potrebovať (a java to umožňuje). Podstatné je, aby ste pre ďalšie spracovanie požiadavky zavolali metódu doFilter nad objektom FilterChain. Asi už tušíte, prečo má táto trieda „Chain“ v názve. Je to preto, lebo reprezentuje reťaz takýchto filtrov, ktoré sa postupne volajú a objekty reprezentujúce požiadavku si postupne posielajú, až ten posledný filter (resp. java server) pošle údaje servletu. Takže tiež z toho vyplýva, že filtrov môže byť viac, a vtedy by ste mali mať pomerne jasno v tom, v akom poradí sú usporiadané (ako dosiahnete určité usporiadanie je už závislé na konkrétnej implementácii servera). To poradie môže byť niekedy dôležité, pretože napríklad potrebujete najprv overiť, či má požiadavka správne informácie z pohľadu zabezpečenia a až potom urobiť jej presmerovanie.

Ok. Takže máte metódu doFilter vášho filtra a v nej voláte doFilter nad objektom FilterChain. Čo sa stane po tom, ako to zavoláte? Váš filter bude čakať. Bude čakať, kým objekty, požiadavky a odpovede prelezú cez všetky filtre až do servletu a vrátia sa späť. A to presne v opačnom poradí. A teda v nejakom momente metóda doFilter nad reťazou filtrov skončí a vy sa opäť nachádzate v kóde vášho filtra, tentokrát s objektami požiadavky a výsledku po spracovaní servletom. To je druhý moment, kedy môže byť filter užitočný. Viete napríklad do výsledku pridať nejakú informáciu, ktorá môže súvisieť s bezpečnosťou, upraviť cookies alebo niečo podobné. Po skončení vašej metódy doFilter ešte môže nasledovať kód filtrov, ktoré boli pred vami a potom sa už výsledok odošle klientovi.

Filtrom teda viete vykonať nejakú zmenu pred tým a po tom, ako požiadavku spracuje servlet, prípadne iné filtre, ktoré sú v reťazci za vami. Čo ale robiť, ak chcete ovplyvniť samotný proces spracovania niekde nižšie v reťazi alebo v samotnom servlete, a to opäť len pomocou filtra? Už určite tušíte, že som túto otázku položil, lebo sa niečo také dá. A robí sa to pomocou objektov požiadavky a odpovede, ktoré som tu už spomínal ale zatiaľ som o nich veľa nepovedal.

Keďže Java je čiste objektový jazyk, tak filter dostáva informácie požiadavky a odpovede vo forme objektov. Sú to objekty, ktoré implementujú dve rozhrania: ServletRequest a ServletResponse (alebo konkrétnejšie rozhrania od nich odvodené). Z takýchto objektov potom viete získavať data, meniť ich a hlavne preposielať ďalej do reťaze filtrov. Ako vám ale pomôžu pri ovplyvnení spracovania požiadavky? Tu prichádza na scénu návrhový vzor Decorator.

Decorator je vzor z rodiny zabaľovacích (wrapper) vzorov. Jeho hlavný účel je zabaliť pôvodný objekt do nového objektu, ktorý navonok silne pripomína pôvodný (mal by mať minimálne všetky metódy ako pôvodný), ale zároveň pridáva nejaké správanie naviac (alebo mení existujúce správanie). Dosť to pripomína dedenie, pretože získavate objekt podobný pôvodnému, pričom môžete pozmeniť správanie, ale v tomto prípade ide o asociáciu (pôvodný objekt je vnorený v novom), čo je väzba, ktorá sa za behu dá meniť. Tvorcovia Javy s takým niečim už rátali, a preto pripravili triedy ServletRequestWrapper a ServletResponseWrapper (prípadne ich konkrétnejšie podoby HttpServletRequestWrapper a HttpServletResponseWrapper). To sú triedy, ktoré už daný vzor implementujú, ale nepridávajú nič naviac. Vy si len zvolíte správnu triedu, od nej odvodíte svoju (môžete použiť aj anonymné metódy) a upravíte správanie v prekrytej metóde (alebo pridáte nejakú metódu novú).

Samotné vytvorenie takýchto objektov nestačí. Potrebujete ich ešte poslať do spracovania a v tomto bode opäť prichádzajú na scénu filtre. Metóda doFilter je presne tá metóda, kde si viete vytvoriť inštanciu vašej decorator triedy, zabaliť do nej pôvodnú požiadavku alebo odpoveď a poslať ju v reťazi filtrov ďalej. Takto vaše objekty putujú ďalej cez filtre a v závislosti podľa typu servletu až do neho, pričom váš kód, ktorý je v nich obsiahnutý, umožňuje meniť ich správanie pri tomto spracovaní.

Filtre a zabaľovacie objekty sú mocné nástroje na to, keď chcete ovplyvniť správanie sa servera. Spolu s modulárnou štruktúrou, ktorá vám umožňuje server jednoducho pridať a odobrať, vytvárajú podmienky, v ktorých viete ľahko meniť správanie servera bez toho, aby ste museli zasiahnuť hlboko do jeho implementácie.