r15 05 (15)


W niniejszym rozdziale:

Rozdział 15.

WebMacro

Szkielet programistyczny WebMacro, dostępny pod adresem http://www.webmacro.org, pochodzi z tej samej rodziny, co Tea, ale charakteryzuje się podejściem opartym w większym stopniu na serwletach. WebMacro zostało utworzone przez Justina Wellsa z firmy Semiotek jako część kontraktu na stworzenie witryny firmy. Następnie udostępnione zostało jako Open Source w celu poprawienia go i podniesienia pozycji firmy. Obecnie istnieją plany włączenia WebMacro do Apache Jakarta Project dostępnym pod adresem http://jakarta.apache.org w celu uzyskania szerszego wsparcia programistycznego. Aktualnie w projekcie Jakarta tworzony jest klon WebMacro o nazwie Velocity.

WebMacro często określa się jako mechanizm szablonów, co jest ogólną nazwą systemów wykonujących zadania zamiany tekstu wewnątrz szablonów stron WWW. Dostępne są także inne mechanizmy szablonów Open Source, najbardziej znany z nich to FreeMarker (http://freemarker.sourceforge.net). Jednak w niniejszej książce opisane zostanie WebMacro, ponieważ posiada ono największą popularność, jest wykorzystywane w dużych komercyjnych witrynach takich jak AltaVista, zostało zintegrowane z dużymi szkieletami Open Source takimi jak Turbine (http://java.apache.org/turbine) i Melati (http://www.melati.org) oraz zostało wykorzystane jako podstawa znanych projektów Open Source takich jak JetSpeed (http://java.apache.org/jetspeed). Podobnie jak Tea, WebMacro jest rozprowadzane według licencji typu Apache, tak więc może zostać bez problemu wykorzystane w połączeniu z aplikacjami komercyjnymi.

Niniejszy rozdział opisuje WebMacro 0.94, wersję próbną z października 2000. Na pewno dużo szczegółów zmieni się. Jeżeli przykładowy kod tu umieszczony nie będzie działał z ostateczną wersją, należy przeczytać dokumentacje dołączoną do WebMacro aby określić, co się zmieniło. WebMacro wymaga Servlet API w wersji 2.0 lub późniejszej i JDK 1.1.7 lub późniejszego.

Szkielet WebMacro

Szkielet WebMacro działa w następujący sposób: serwlet odbiera żądanie od klienta, serwlet wykonuje logikę konieczną do obsługi żądania (taką jak wykorzystanie klas wspierających lub elementów takich, jak EJB), po czym tworzy obiekt kontekstowy wypełniony „obiektami odpowiedzi” zawierającymi wyniki logiki, które powinny zostać wyświetlone klientowi. Następnie serwlet wybiera plik szablonu (zazwyczaj w oparciu o wyniki logiki) po czym przepycha obiekty odpowiedzi przez plik szablonu tworząc zawartość wyświetlaną klientowi.

Programista Javy tworzy serwlet i logikę w czystej Javie, a inżynier szablonów tworzy plik szablonu wyświetlający dane. Szablon składa się z zawartości HTML i XML wypełnionej prostą logiką do podstawiania i niewielkimi możliwościami skryptowymi. Składnia jest zgodna z edytorami HTML i XML, omija nawiasy kątowe, aby zapewnić, że analizatory HTML i XML nie będą popełniać omyłek. Programista przekazuje inżynierowi szablonów listę zastosowanych zmiennych, a także listę właściwości i metod tych zmiennych.

Model ten posiada pewne podobieństwa z modelem TeaServlet, z tą różnicą, że WebMacro domyślnie wykorzystuje model przepychania w większym stopniu oparty na serwletach, nie obsługuje zagnieżdżania szablonów i wykorzystuje bardziej skomplikowaną składnię skryptową. Zdaniem autorów, WebMacro posiada przewagę nad Tea przy tworzeniu wysoko funkcjonalnych stron WWW, które posiadają pewien punkt oznaczający zakończenie pracy nad nimi, Tea natomiast przoduje w tworzeniu stron, w których stale dodawana jest nowa zawartość szablonów, konieczne jest zagnieżdżanie szablonów i wymagane jest mniejsze zaangażowanie programistyczne.

Powitanie przy pomocy WebMacro

Przykład 15.1 przedstawia prosty serwlet wykorzystujący system szablonów WebMacro. Przykład 15.2 przedstawia plik szablonu witaj.wm. Wspólnie wyświetlają one aktualna datę i godzinę W następnym podrozdziale opisane zostaną miejsca, w których powinny one zostać umieszczone.

Przykład 15.1.

Prosty serwlet prowadzący szablon Witaj

import java.io.*;

import java.util.*;

import javax.servlet.*;

import javax.servlet.http.*;

import org.webmacro.*;

import org.webmacro.servlet.*;

public class WMWitaj extends HttpServlet {

public void doGet(HttpServletRequest zad, HttpServletResponse odp)

throws ServletException, IOException {

FastWriter wyj = new FastWriter(odp.getOutputStream(),

odp.getCharacterEncoding());

try {

WebMacro wm = new WM(); // opcjonalnie WM("/ścieżka/do/pliku/konfiguracyjnego")

Context k = wm.getWebContext(zad, odp);

k.put("data", new Date());

Template scab = wm.getTemplate("witaj.wm");

szab.write(wyj, k);

wyj.flush();

}

catch (WebMacroException w) {

throw new ServletException(w);

}

}

}

Przykład 15.2.

Prosty szablon Witaj

## witaj.wm

#set $Response.ContentType = "text/html"

<HTML><HEAD><TITLE>Test WebMacro</TITLE></HEAD><BODY>

Witaj! <P>

Obecny czas to $data. <BR>

(Dla Was, kujony to $date.Time milisekund.) <P>

</BODY></HTML>

Na początku opisany zostanie serwlet. Jest to normalny serwlet, będący rozszerzeniem HttpServlet i wykorzystujący metodę doGet(). Na pierwszy rzut oka można jednak zauważyć, że jego logika jest inna. Pobiera on FastWriter zamiast normalnego PrintWriter. Pozwala to na specjalną optymalizację pozwalającą na uniknięcie kosztu konwersji Unicode dla zawartości statycznej. Działa on jak zwykłe urządzenie zapisujące z jednym ulepszeniem takim, że WebMacro może przepchnąć wcześniej zakodowane bajty i wywołać setAsciiHack(true) w celu przyśpieszenia wyświetlania danych Latin-1 lub US-ASCII. Należy jedynie pamiętać, by (przynajmniej obecnie) wywołać metodę flush() urządzenia zapisującego w celu wysłania zbuforowanej zawartości urządzenia do klienta.

Kod wewnątrz bloku try tworzy nowy obiekt WebMacro, który działa jako jego podstawowy zaczep do systemu WebMacro. WebMacro to interfejs, tak więc serwlet właściwie konstruuje egzemplarz konkretnej klasy WM, która implementuje interfejs WebMacro. Następnie serwlet wywołuje wm.getWebContext(zad, odp) w celu odczytania kontekstu WebContext, w którym umieszczone zostaną obiekty odpowiedzi, które zostaną przekazane szablonowi. Kontekst działa podobnie jak tablica asocjacyjna Hashtable. Posiada on metodę put(Object, Object), którą serwlet wykorzystuje do umieszczenia obiektu Date w kontekście, pod nazwą data. Obiekt ten zostanie później udostępniony szablonowi działającemu w obrębie tego kontekstu. Użytkownicy zaawansowani mogą zainteresować się faktem, że WebContext jest rozszerzeniem Context, a serwlet mógłby wywoływać kontekst nieświadomy sieci WWW — Context przy pomocy getContext(). Własność ta jest przydatna w niektórych sytuacjach, takich jak zastosowania offline lub niezwiązane z serwletami.

W celu pobrania szablonu, serwlet wywołuje wm.getTemplate("witaj.wm"). Metoda ta pobiera nazwę szablonu do odczytania, łącznie z rozszerzeniem pliku. Szablon może posiadać dowolne rozszerzenie, ale większość użytkowników wykorzystuje standardową konwencję .wm. Posiadając szablon, serwlet może wywołać jego metodę write() i przekazać jako jej parametry FastWriter do zapisu i WebContext wypełniony obiektami odpowiedzi. Wyświetlane dane powinny również zostać ujęte jako łańcuch, przy pomocy metody Template String evaluate(Context kontekst).

Jeżeli dowolna metoda spowoduje wyjątek WebMacroException, serwlet został przygotowany na wywołanie go wewnątrz ServletException. Prawie każda metoda WebMacro może wywołać WebMacroException lub pewne jego podklasy. Konstruktor WM() może wywołać InitException jeżeli, na przykład, pożądany plik konfiguracyjny nie może zostać odnaleziony. Metoda getTemplate() może wywołać NotFoundException, jeżeli niemożliwe jest odnalezienie szablonu. Natomiast metoda write() może wywołać ContextException, jeżeli pożądane dane szablonu nie znajdowały się w kontekście, a także IOException, jeżeli wystąpił problem z zapisem do klienta. Wszystkie zdefiniowane przez WebMacro wyjątki są rozszerzeniami WebMacroException, który nie jest wyjątkiem czasu wykonania, i często stosuje się obsługę tego ogólnego wyjątku na końcu metody doGet().

Stosując inne podejście, można utworzyć serwlet obsługujący WebMacro będący rozszerzeniem superklasy org.webmacro.servlet.WMServlet, jak przedstawiono w przykładzie 15.3.

Przykład 15.3.

Inne podejście do tworzenia serwletu WebMacro

import java.io.*;

import java.util.*;

import javax.servlet.*;

import javax.servlet.http.*;

import org.webmacro.*;

import org.webmacro.servlet.*;

public class WMSerwletWitaj extends WMServlet {

public Template handle(WebContext kontekst) throws HandlerException {

try {

kontekst.put("data", new Date());

return getTemplate("witaj.wm");

}

catch (NotFoundException w) {

throw new HandlerException(w.getMessage());

}

}

}

W powyższej metodzie, serwlet jest rozszerzeniem WMServlet i implementuje pojedynczą metodę handle(). Superklasa tworzy automatycznie obiekt WebMacro i przekazuje mu jako parametr WebContext. Servlet musi wykonać jedynie swoją logikę, wypełnić WebContext odpowiednimi obiektami odpowiedzi oraz zwrócić szablon wykorzystywany do utworzenia strony (lub null, jeżeli serwlet wewnętrznie obsługuje tworzenie strony). Metody start() i stop() również mogą zostać wykorzystane przez serwlet, zamiast zwykłych metod init() i destroy(). Jeżeli potrzebne będą obiekty HttpServletRequest i HttpServletResponse, mogą one zostać odczytane z WebContext przy pomocy metod getRequest() i getResponse().

Wykorzystanie superklasy WMServlet może okazać się wygodniejsze niż samodzielna obsługa obiektów WebMacro. Jego ceną jest utrata mocy. Konieczne jest wykorzystanie samodzielnego podejścia do umieszczania na stronie dwóch niezależnych szablonów, przepuszczenia wyświetlanych danych przez filtr taki jak GZIPOutputStream, wykonania tworzenia offline, rozróżnienia między żądaniami GET i POST oraz określenia, czy serwlet musi być rozszerzeniem innej niestandardowej superklasy.

Teraz opisany zostanie szablon. Wygląda on jak zwykła strona HTML poza niewielkimi fragmentami. W głównej części strony można dostrzec obiekt Date, dodany wcześniej do kontekstu pod nazwą data, dołączony do strony przy pomocy składni $data. W następnej linii można zauważyć, że właściwość time obiektu Date (która przechowuje czas w formie licznika milisekund) została dołączona przy pomocy składni $data.Time. Jest to prosta składnia podstawienia wykorzystywana przez WebMacro — $nazwazmiennej wyświetla wartość zmiennej (po konwersji do String, jeżeli jest to konieczne), a $nazwazmiennej.Wlasciwosc wyświetla wartość właściwości. Podwłaściwości właściwości są również dostępne przy pomocy składni $nazwazmiennej.Wlasciwosc.Podwlasciwosc, a tak naprawdę można uzyskać dostęp do większej ilości danych niż podstawowe właściwości, poprzez zaawansowane działanie refleksji WebMacro, co zostanie przedstawione w dalszej części. W tym momencie należy jedynie pamiętać, że podczas odczytywania podstawowej właściwości jej nazwa musi zaczynać się od wielkiej litery.

Przyglądając się szablonowi dokładniej, można dostrzec, że na początku znajduje się komentarz zawierający nazwę pliku. Komentarze w WebMacro rozpoczynają się od ## i mają długość jednej linii. Zaraz pod komentarzem znajduje się polecenie #set, które w WebMacro nazywane jest instrukcją. Nadaje ona właściwości ContentType obiektu Response wartość "text/html", co jest równoznaczne z wywołaniem response.setContentType("text/html"). Zmienna $Response reprezentuje odpowiedź serwletu i podobnie jak $Request jest dostępna we wszystkich obiektach WebContext. WebMacro posiada kilka instrukcji służących do manipulacji zmiennymi, dołączania plików i tworzenia pętli. Zostaną one opisane szczegółowo w dalszej części niniejszego rozdziału.

Instalacja WebMacro

W celu uruchomienia serwletu WebMacro i szablonu konieczne jest wykonanie niewielkiej pracy związanej z instalacją. Po pierwsze należy pobrać dystrybucję z witryny http://www.webmacro.org i rozpakować ją. Następnie należy umieścić webmacro.jar i collections.jar w ścieżce klas serwera. Następnie należy odnaleźć plik WebMacro.properties znajdujący się wewnątrz dystrybucji i skopiować go do katalogu znajdującego się w ścieżce klas serwera. Proszę zauważyć, że ponieważ klasy w webmacro.jar wykorzystują swój własny mechanizm ładowania klas w celu odnalezienia pliku, plik ten musi znajdować się w ścieżce klas mechanizmu ładującego webmacro.jar. W celu zapewnienia tej własności, należy umieścić oba te pliki w systemowej ścieżce klas, gdzie mogą zostać odnalezione przez podstawowy mechanizm ładowania klas, lub umieścić oba w katalogu WEB-INF, gdzie zostaną odnalezione przez mechanizm aplikacji WWW. (webmacro.jar należy umieścić w katalogu WEB-INF/lib, a WebMacro.properties w katalogu WEB-INF/classes.)

Domyślny plik WebMacro.properties zawarty w dystrybucji zawiera długą listę opcji konfiguracyjnych, których pierwsza część jest przedstawiona w przykładzie 15.4. Większość aspektów tej klasy jest dobrze udokumentowana w samym pliku. Wszystko, co należy teraz skonfigurować, to parametr TemplatePath, określający katalog lub katalogi, w których przechowywane są szablony.

Przykład 15.4.

Standardowy plik WebMacro.properties

# UWAGA DLA UŻYTKOWNIKÓW NT

#

# Proszę pamiętać, że znak \ to znak ucieczkowy w plikach właściwości Javy

# Należy je zdublować (\\) lub wykorzystać w pliku znak Uniksowy (/)

# Oba powinny działać. Również podczas określania TemplatePath, proszę pamiętać

# o stosowaniu znaku oddzielającego NT (;), a nie Uniksa (:)

###########################################################

#

# KONFIGURACJA PODSTAWOWA:

#

# Należy co najmniej określić TemplatePath! Jest to lista katalogów, która będzie

# przeglądana w poszukiwaniu szablonów, jeżeli podana zostanie ścieżka względna

# Jest to lista oddzielana przez : (UNIX) lub ; (NT).

TemplatePath = /tomcat/webapps/webmacro/WEB-INF/szablony;/local/webmacro/szablony

# WebMacro kompiluje i przechowuje szablony w celu osiągnięcia maksymalnej wydajności.

# Podczas programowania poleca się wyłączenie tego przez ustawienie wartości na 0

# tak, że zmiany w szablonach natychmiastowo odbijają się w witrynie.

# W systemach produkcyjnych jest to ilość milisekund wolnego czasu, przez który szablon

# szablon umieszczony w pamięci podręcznej będzie przechowywany np. 600000 to 10 minut.

TemplateExpireTime = 0

# TemplateExpireTime == 600000

# LogLevel może wynosić: ALL, DEBUG, EXCEPTION, ERROR, WARNING, INFO, or NONE

# w porządku od największej do najmniejszej ilości wyświetlanych informacji.

LogLevel = EXCEPTION

# LogTraceExceptions powoduje umieszczanie stosów wyjątków w pliku dziennika,

# co powoduje zwiększenie długości wyjątków i ich wskazywanie na konkretną linię lub

# metodę, która powoduje błąd.

LogTraceExceptions = TRUE

# Usunięcie komentarza powoduje zapisywanie w pliku dziennika, nie w stderr.

# Jeżeli standardowy błąd już zapisuje w przydatnym dzienniku, nie trzeba tego robić,

# ale duża część mechanizmów serwletów po prostu połyka standardowy błąd.

# LogFile = /usr/local/webmacro/wm.log

# Ustawienie szablonu (związanego z TemplateDirectory) wykorzystywanego do błędów.

# Można dokonać edycji aby dostosować sposób wyświetlania niepowodzeń skryptu

ErrorTemplate = blad.wm

Zaawansowany użytkownik może utworzyć wiele wersji powyższego pliku i przełączać się pomiędzy nimi w celu dokonania szybkiej i kompletnej zmiany wyglądu witryny (zmiana TemplatePath), lub po prostu by przesunąć się z trybu programowania do produkcji (zmiana właściwości takich jak TemplateExpireTime). Ta zamiana może zostać wykonana również na poziomie serwlet-do-serwletu ponieważ konstruktor WM() pobiera opcjonalny argument typu String, który określa położenie pliku konfiguracyjnego, który powinien zostać odczytany. Jeżeli serwlet potrzebuje bezpośredniego dostępu do właściwości w tym pliku, są one dostępne przy pomocy metody getConfig(String klucz) obecną zarówno w interfejsie WebMacro i klasie WMServlet. Pozwala to plikowi konfiguracyjnemu na przechowywanie ekwiwalentów parametrów inicjacji kontekstu, poza parametrami przywiązanymi do konkretnej konfiguracji — na przykład wskazującymi na testową bazę danych w trakcie programowania, a na produkcyjną bazę danych po udostępnieniu.

Kiedy wszystkie pliki zostaną właściwie zainstalowane, wywoływanie serwletów obsługujących WebMacro jest wykonywane tak, jak wywoływanie wszystkich innych serwletów. Należy wywołać serwlet jako http://localhost:8080/servlet/WMWitaj lub, w przypadku serwletów umieszczonych w kontekście /webmacro, jak przedstawiono w pliku WebMacro.properties, URL wynosi http://localhost:8080/webmacro/servlet/WMWitaj. Proszę spojrzeć na rysunek 15.1.

Rysunek 15.1.

Test WebMacro

0x01 graphic

Język szablonów WebMacro

Język szablonów WebMacro przypomina składnię Perla i preprocesora C, która jest znajoma większości użytkowników. Zmienne rozpoczynają się znakiem dolara ($), a kończą pustym miejscem lub różnymi znakami interpunkcyjnymi takim jak <, / i ". Pozwala to na tworzenie łatwych do odczytania podstawień, na przykład:

$Request.ContextPath/servlet/WMWitaj

<A HREF="$url">$url</A>

Kiedy jest to potrzebne, można wykorzystać nawiasy w celu wyraźnego oddzielenia nazwy zmiennej i wyjaśnienia analizy. Nawiasy są usuwane i niewyświetlane. Na przykład:

#set $przedrostek = "wyb"

#set $przyrostek = "aczanie"

Błądzenie to rzecz ludzka, $(przedrostek)$przyrostek — boska.

Mechanizm WebMacro nie wykorzystuje klasy java.beans.Introspector w celu uzyskania dostępu do właściwości obiektu; zamiast tego wykonuje bardziej wyczerpujące przeszukiwanie refleksyjne. Kiedy napisze się $Request.ContextPath, WebMacro po pierwsze odnajduje obiekt określany jako $Request, po czym próbuje odnaleźć właściwość przy pomocy następującego wzoru poszukiwań:

request.ContextPath

request.getContextPath()

request.get("ContextPath");

Jeżeli utworzy się dłuższe podstawienie, takie jak $Request.Header.Accept, WebMacro dodaje następujący wzór poszukiwań na końcu listy:

Request.getHeader("Accept")

Przydzielenia zmiennych wykorzystują podobny wzór poszukiwań.

Przy pomocy WebMacro możliwe jest bezpośrednie wywoływanie metod na wszystkich obiektach w zakresie (czego nie można było w jasny sposób wykonać w Tea). Na przykład, poniższe podstawienie odnajduje listę produktów w zapasie, wyszukuje produkt zawias i zwraca jego numer części:

$Zapas.Produkty.znajdzProdukt("zawias").NumerCzesci

Własność ta może okazać się przydatna, kiedy metody dostępu nie są zgodne z wzorem nazywania, którego spodziewa się WebMacro. Z drugiej strony, bezpośrednie wywoływanie metod oznacza, że w szablonie WebMacro nie może istnieć całkowite zagnieżdżanie.

Narzędzia kontekstu WebMacro

Jedną z potężnych cech WebMacro jest możliwość udostępnienia przez WebContext niewielkiej liczby zmiennych nazywanych narzędziami kontekstu, wszystkim szablonom, a narzędzia te są zawsze dołączane bez konieczności umieszczenia ich w kontekście przez wywołujący serwlet. Lista narzędzi, które powinny zostać dołączone jest określana w pliku WebMacro.properties jako WebContextTools. Domyślnie WebMacro dostarcza następujących narzędzi:

$Request

Odwołanie do HttpServletRequest serwletu. Może zostać wykorzystane do uzyskania dostępu do nagłówka Accept żądania przy pomocy $Request.Header.Accept lub równoważnie $Request.getHeader("Accept").

$Response

Odwołanie do HttpServletResponse serwletu. Może zostać wykorzystane do ustawienia Content-Type odpowiedzi przy pomocy #set $Response.ContentType = "text/html".

$Session

Odwołanie do HttpSession użytkownika. Może zostać wykorzystane do odczytania wartości sesji przy pomocy $Session.Attribute.Count lub równoważnie $Session.getAttribute("Count").

$Form

Narzędzie służące do uzyskania dostępu do danych formularza żądania. Może zostać wykorzystane do pobrania parametru numerczesci przy pomocy $Form.numerczesci. Skrót dla $Request.getParameter("numerczesci") lub $Request.Parameter.numerczesci.

$FormList

Narzędzie służące do uzyskania dostępu do danych formularza żądania, kiedy dane formularza posiadają więcej niż jedną wartość. Stosowane w połączeniu z instrukcją #foreach.

$Cookie

Narzędzie służące do odczytywania i ustawiania cookies. Może zostać wykorzystane do ustawienia cookie przy pomocy $Cookie.set("nazwa", "wartosc") lub #set $Cookie.nazwa = "wartosc". Cookies są odczytywane przy pomocy $Cookie.get("nazwa").Wartosc lub $Cookie.nazwa.Wartosc.

$CGI

Narżedzie służące do uzyskiwania dostępu do informacji żądania przy pomocy nazwa w stylu CGI. Może zostać wykorzystane przez inżynierów szablonów znających CGI do uzyskania dostępu do zmiennych takich, jak katalog macierzysty dokumentów — $CGI.DOCUMENT_ROOT.

Dodatkowe narzędzia kontekstu mogą zostać udostępnione poprzez utworzenie klasy wykorzystującej org.webmacro.ContextTool i dodanie klasy do listy WebContextTools. Można napisać lub pobrać narzędzia odpowiedzialne za działania matematyczne, internacjonalizację, dostęp do bazy danych lub nawet tworzenie obiektów HTML przy pomocy ECS opisanego w następnym rozdziale. W wielu aspektach narzędzia kontekstu mają takie znaczenie dla WebMacro, jak biblioteki znaczników dla JSP.

Przykład 15.5 przedstawia proste narzędzie kontekstu wykonujące arytmetykę na liczbach typu integer. To narzędzie o nazwie MatTool często okazuje się przydatne, ponieważ język szablonów WebMacro został tak uproszczony, że nie zawiera nawet podstawowych działań arytmetycznych.

Przykład 15.5.

Narzędzie kontekstu służące do wykonywania arytmetyki na liczbach integer (skomplikowany kalkulator)

import org.webmacro.*;

public class MatTool implements ContextTool {

/**

* Dla każdego żądania utworzony zostanie nowy obiekt-narzędzie poprzez wywołanie tej

* metody. ContextTool jest właściwie fabryką wykorzystywaną do tworzenia obiektów

* wykorzystywanych w szablonach. Niektóre obiekty mogą po prostu zwracać siebie

* przez tę metodę; inne mogą tworzyć nowe egzemplarze obiektów w celu utrzymania

* stanu jeden-na żądanie.

*/

public Object init(Context k) {

return this;

}

public static int dodaj(int x, int y) {

return x + y;

}

public static int odejmij(int x, int y) {

return x - y;

}

public static int pomnoz(int x, int y) {

return x * y;

}

public static int podziel(int x, int y) {

return x / y;

}

public static int modul(int x, int y) {

return x % y;

}

public static boolean mniejszeNiz(int x, int y) {

return (x < y);

}

public static boolean wiekszeNiz(int x, int y) {

return (x > y);

}

}

Kiedy narzędzie to zostanie dodane do listy WebContextTools (proszę nie zapomnieć o tym kroku), wszystkie szablony mogą wykonywać podstawowe działania matematyczne. Na przykład, wyświetlenie roku z obiektu Date wymaga dodania 1900 do właściwości Year:

Obecny rok to $Mat.dodaj($data.Year, 1900).

Instrukcje WebMacro

Instrukcje to wyrażenia WebMacro wykonujące pewne operacje, warunkowo dołączające tekst lub powtarzające blok wewnątrz szablonu. Lista dostępnych instrukcji jest przechowywana w pliku WebMacro.properties jako właściwość Directives. Wszystkie instrukcje rozpoczynają się znakiem #. Niektóre instrukcje działają na bloku, i bloki takie mogą zostać zaznaczone przy pomocy zakręconych nawiasów, { i }, lub słów kluczowych #begin i #end. Słowa kluczowe nie są tak proste w napisaniu jak nawiasy lecz powodują mniejszą ilość problemów z dołączonym JavaScriptem.

Istnieje siedem popularnych instrukcji. Podobnie jak w przypadku narzędzi kontekstu, można utworzyć swoje własne instrukcje dodawane do domyślnych, chociaż nie jest to tak popularne. Poniżej przedstawiona jest domyślna siódemka.

#if

#if (warunek) { ... } #else { ... }

Instrukcja #if, samodzielna lub zastosowana w połączeniu z instrukcją #else, może zostać wykorzystana do warunkowego dołączania tekstu. Tekst jest dołączany, jeżeli warunek jest prawdziwy, a nie dołączany, jeżeli fałszywy. Warunek jest uważany za prawdziwy, jeżeli posiada niezerową wartość inną niż boolowskie false. Warunek #if może wykorzystywać znajome operatory boolowskie &&, || i !, a także nawiasy w celu określenia porządku. Obiekty mogą być porównywane jako część warunku przy pomocy operatorów == i !=, które właściwie wywołują metodę equals(),wykonujacą porównanie. Nie istnieje operator dla porównań większe-niż i mniejsze-niż, ponieważ obiekty nie są zobowiązane do bycia porównywalnym w ten sposób. MatTool zawiera także porównania do użytku z liczbami typu integer.

#if ($Klient.winienPieniadze() && $Klient.Nazwa != "Jason") {

Zapłać koniecznie!

}

#else {

Witamy!

}

#set

#set $wlasciwosc = wartosc

Instrukcja #set przypisuje wartość danej zmiennej lub właściwości zmiennej. Właściwość musi zostać pomyślnie odnaleziona przez logikę refleksyjną WebMacro, oraz musi posiadać własność publicznego ustawiania w pewien sposób. Jeżeli takiej zmiennej nie ma w zakresie, tworzona jest nowa zmienna i przypisana jej zostaje podana wartość. Zmiennym w ukryty sposób przypisywany jest typ String lub Integer. Typ String to typ domyślny, chyba że wartość może zostać zanalizowana jako Integer i nie jest otoczona podwójnymi nawiasami, Dla ułatwienia, wartości Integer mogą zostać przekonwertowane do wartości String, kiedy jest to potrzebne. Ustawiane mogą być również tablice, kiedy jest to potrzebne. Należy użyć lewego ukośnika w celu wyłączenia znaku dolara:

#set $liczba1 = 4

#set $liczba2 = 7

#set $cena = "90"

#set $faktura = "Jesteś winny \$$cena"

#set $cytat = "$liczba1 mil i $liczba2 lat temu..."

#set $wszystko = [ $liczba1, $liczba2, $cytat ] ## składnia tablicy

#foreach

#foreach $rzecz in $lista { ... }

Instrukcja #foreach iteruje według listy, dołączając swój blok kodu raz dla każdego elementu na liście. Przy każdej pętli zmienna $rzecz pobiera wartość następnego egzemplarza a $lista. Lista może być tablicą zadeklarowaną wewnątrz WebMacro lub obiektem Javy, który spełnia jeden z poniższych warunków (przeszukiwane przez refleksję w tej kolejności):

  1. Obiekt sam w sobie jest tablicą.

  2. Obiekt sam w sobie to Iterator.

  3. Obiekt sam w sobie to Enumeration.

  4. Obiekt posiada metodę Iterator iterator().

  5. Obiekt posiada metodę Enumeration elements().

Poniższy kod wyświetla preferowane przez klienta lokalizację (jeżeli takie istnieją):

#set $tablica = $Request.Locales

<UL>

#foreach $element in #tablica {

<LI>$element

}

</UL>

#parse

#parse plik

Instrukcja #parse dołącza zawartość docelowego pliku w miejscu instrukcji tak, jak by był on częścią obecnego szablonu. Dostarcza to łatwego mechanizmu dołączania popularnego kodu szablonów do różnych plików szablonów. Plik może zostać określony przy pomocy ścieżki bezpośredniej lub pośredniej umieszczonej wewnątrz TemplatePath:

#set $tytul = "Tytuł strony"

#parse "naglowek.wm" ##zmienna $tytul jest widoczna w naglowek.wm

#include

#include url

Instrukcja #include dołącza zawartość docelowego URL-a w miejscu instrukcji, ale nie próbuje analizować jego zawartości. Dostarcza to łatwego mechanizmu dołączania JavaScriptu i innych rzeczy, których składnia może wchodzić w konflikt z WebMacro, Jeżeli URL nie posiada protokołu, przyjmuje się file::

#include "http://webmacro.org/CREDITS ## Dołączenie surowego tekstu

#param

#param $nazwa = wartosc

Instrukcja #param określa wartości wewnątrz szablonu, które mogą być przeglądane przez serwlet wywołujący szablon. Dostarczają one autorowi szablonu metody przekazywania informacji wspierającemu programiście Javy. Informacje te mogą zostać wykorzystane do określenia typu informacji, który ma zostać umieszczony w kontekście:

#param $autor = "Maria Kowalska"

#param $wymagane = [ "uzyt", "dokument", "sesja" ]

Serwlet może pobrać wartość przez wywołanie Object getParam(String) na obiekcie Template. Metoda ta zwraca String lub Integer, jeżeli istnieje jedna wartość i Object[] zawierający obiekty String i/lub Integer, jeżeli wartość jest listą:

String autor = (String) szab.getParam("autor");

Object[] wymagane = (Object[]) szab.getParam("wymagane");

#use

#use 'analizator'

#begin

...

#end

Ostatnią z instrukcji jest #use, która pozwala blokowi tekstu szablonu (oznaczonemu przez znaczniki #begin i #end) na bycie zanalizowanym przez alternatywny analizator. Własność ta pozwala na rozszerzenie lub nawet całkowitą wymianę składni WebMacro. Generalnie nie jest ona jednak stosowana do tak dużych zadań. Jej dwa najbardziej popularne zastosowania to dosłowne dołączenie bloku tekstu (przy pomocy analizatora text) lub usunięcia bloku tekstu (przy pomocy analizatora null):

#use 'text'

#begin

Cały tekst tu umieszczony jest dołączany bez zmian

## Komentarze również ponieważ format komentarza to kwestia analizatora

#end

#use 'null'

#begin

Tekst w tym miejscu można uznać za „wykomentowany”

#end

Plik WebMacro.properties zawiera listę dostępnych domyślnych analizatorów we właściwości Parsers.

Szablony WebMacro

Aby zademonstrować narzędzia kontekstu i instrukcje dostępne szablonom WebMacro, przykład 15.6 przedstawia prosty szablon wyświetlający informacje z żądania.

Przykład 15.6.

Przeglądanie żądania przy pomocy WebMacro

## przegl.wm

#set $Response.ContentType = "text/html"

<HTML><HEAD><TITLE>Przegladanie!</TITLE></HEAD>

<BODY>

## Szablon przeglądający pozwalający na przyzwyczajenie się do WebMacro

<H1>Rozne informacje</H1>

##Lancuch zapytania: $Request.QueryString<BR>

##Uzytkownik zdalny: $Request.RemoteUser<BR>

## WebMacro jeszcze nie obsługuje właściwości isXXX() trzeba użyć wywołania metody

## Nie posiada też aktualnie elseif (jest dodawane)

##if ($Request.isRequestedSessionIdFromCookie()) {

## Sesja dzieki cookies!

##}

##else {

##if ($Request.isRequestedSessionIdFromURL()) {

## Sesja dzieki przepisywaniu URL!

## }

## #else {

## Brak sesji, wspolczucia.

## }

##}

<H1>Informacja o parametrach</H1>

#foreach $paramName in $Request.ParameterNames {

$paramName: $Request.getParameter($paramName) <BR>

}

<H1>Informacja o naglowku</H1>

#foreach $headerName in $Request.HeaderNames {

$headerName: $Request.getHeader($headerName) <BR>

}

<H1>Informacja o cookie</H1>

#foreach $cookie in $Request.Cookies {

$cookie.Name: $cookie.Value <BR>

}

</BODY></HTML>

Rysunek 15.2 przedstawia przykładową stronę wyświetlaną przez powyższy przykład.

Rysunek 15.2.

Przeglądanie z WebMacro

0x01 graphic

Powyższy szablon demonstruje instrukcję #set ustawiającą typ zawartości odpowiedzi. Wykorzystuje instrukcje #if i #else w celu określenia, czy klient utworzył sesję przy pomocy cookie, czy przepisywania URL-a, czy też nie jest częścią sesji. Wykorzystuje także instrukcję #foreach do wykonania pętli na wartościach parametrów, nagłówka i cookies obecnych w żądaniu.

Warto zauważyć pewne sztuczki — po pierwsze, podstawowa metoda dostępu o nazwie według wzoru isWlasciwosc() nie jest automatycznie odnajdywana przez WebMacro i musi zostać osobno wywołana poprzez wywoływanie metod. Po drugie, obecnie nie istnieje instrukcja #elseif, tak więc konstrukcja if/elseif/else musi być wykonywana poprzez zagnieżdżanie.

Gotowy do ponownego wykorzystania serwlet MacroPrzegl

Szablon z przykładu 15.6 może być uważany za „samodzielny”, ponieważ nie wykorzystuje on żadnych zmiennych dostarczanych przez serwlet. Samodzielne szablony nie mogą być wywoływane bezpośrednio i wymagają serwletu, który je wywoła, ale ponieważ szablon nie ma żadnych specjalnych wymagań, serwlet ten może być ogólnym i możliwym do ponownego wykorzystania serwletem MacroPrzegl, jak przedstawiono w przykładzie 15.7.

Przykład 15.7.

Ogólnie możliwy do ponownego wykorzystania serwlet WebMacro

import java.io.*;

import javax.servlet.*;

import javax.servlet.http.*;

import org.webmacro.*;

import org.webmacro.servlet.*;

import org.webmacro.engine.*;

import org.webmacro.broker.*;

// Rozszerzanie com.oreilly.servlet.CacheHttpServlet może poprawić czas odpowiedzi

public class MacroPrzegl extends HttpServlet {

WebMacro wm; // główny zaczep WebMacro

public void init() throws ServletException {

try {

wm = new WM();

}

catch (InitException w) {

throw new ServletException(w);

}

}

public void doGet(HttpServletRequest zad, HttpServletResponse odp)

throws ServletException, IOException {

FastWriter wyj = new FastWriter(odp.getOutputStream(),

odp.getCharacterEncoding());

// Nazwa szablonu jest pobierana jako dodatkowy element ścieżki

// /servlet/MacroPrzegl/szab.wm

// Lub jako ścieżka serwletu poprzez zasadę *.wm

// /szab.wm

String szablon = zad.getPathInfo();

if (szablon == null) {

szablon = zad.getServletPath();

szablon = szablon.substring(1); // odcięcie początkowego "/"

}

// Jeżeli ciągle brak szablonu, problem

if (szablon == null) {

throw new ServletException(

"Nie określono żadnego szablonu jako dodatkowej ścieżki lub serwletu");

}

try {

Template szab = wm.getTemplate(szablon);

WebContext kontekst = wm.getWebContext(zad, odp);

szab.write(wyj, kontekst);

}

catch (WebMacroException w) {

throw new ServletException(w);

}

finally {

wyj.flush();

}

}

public void destroy() {

super.destroy();

if (wm != null) wm.destroy();

}

}

Powyższy serwlet wywołuje dowolny szablon, którego nazwa zostanie przekazana jako dodatkowa informacja o ścieżce, lub jeżeli jej nie ma, po prostu szablon, na który wskazuje ścieżka serwletu (poprzez dopasowanie rozszerzeń plików). Ułatwieniem może okazać się zarejestrowanie powyższego serwletu tak, aby obsługiwał wszystkie żądania *.wm przy pomocy fragmentu pliku web.xml przedstawionego w przykładzie 15.8. Pozwala to plikom szablonów WebMacro na bycie wywoływanym bezpośrednio przy pomocy URL-i takich jak /przegl.wm lub webmacro/przegl.wm, podczas gdy w rzeczywistości serwlet MacroPrzegl wykonuje całą czarną robotę.

Przykład 15.8.

Rejestrowanie MacroPrzegl w celu obsługi *.wm

<servlet>

<servlet-name>

mp

</servlet-name>

<servlet-class>

MacroPrzegl

</servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>

mp

</servlet-name>

<url-pattern>

*.wm

</url-pattern>

</servlet-mapping>

Przydatnym może kazać się rozszerzenie serwletu MacroPrzegl tak, aby wykonywał pewną standardową logikę na każdym żądaniu i przypuszczalnie utworzył zbiór popularnych obiektów dostępnych w kontekście wszystkim szablonów systemowym. Serwlet podobny do powyższego, połączony z omówionymi wcześniej narzędziami kontekstu, pozwala szablonom WebMacro na działanie z modelem przepychania podobnym do Tea (i to właściwie jest sposób, w jaki AltaVista wykorzystuje WebMacro).

Przetwarzanie szablonów

WebMacro wykonuje w ukryciu dużą ilość analizy szablonów, o którą programiści i projektanci nie muszą się martwić, ale warto poznać mechanizmy tych działań w celu maksymalnego ich wykorzystania. WebMacro analizuje szablony podczas ich pierwszego wykorzystania, a następnie umieszcza reprezentację odpowiedniego szablonu w pamięci, w celu ich szybkiego wykonywania. WebMacro automatycznie przeładowuje i ponownie analizuje zawartość szablonu po zmianie pliku szablonu, ale dla zachowania wydajności sprawdza znaczniki czasu jedynie co określony czas, wymieniony jako TemplateExpireTime w WebMacro.properties. Domyślnie czas przechowywania wynosi 0 milisekund tak, aby znaczniki czasy były sprawdzane na każde żądanie. Jest to ułatwienie dla programowania, ale należy się upewnić, że dla wykorzystania produkcyjnego znacznik czasu zostanie zwiększony. Dla użytkowników zaawansowanych obiekty szablonów posiadają metodę parse(), która wymusza pobranie i analizę. Metoda ta może zostać wykorzystana do analizy wszystkich szablonów podczas uruchomienia, lub wymuszenia wcześniejszej analizy, jeżeli szablon został zmieniony.

Kiedy w szablonach występują błędy, mogą wydarzyć się różne rzeczy. Jeżeli zmienna, do której następuje odwołanie, lub właściwość posiada wartość null lub nie istnieje, WebMacro traktuje tę niepomyślną zamianę jako błąd niekrytyczny. WebMacro generuje stronę w najlepszy możliwy sposób, ale zapisuje wiadomość WARN w dzienniku, a na wygenerowanej stronie umieszcza komentarz HTML/XML w miejscu błędu (podejście to posiada pewne wady, jeżeli generowana strona nie jest typu HTML ani XML):

<!-- warning: attempt to write out undefined variable Request.ContentType: java.lang.NullPointerException -->.

Jeżeli szablon zawiera błąd składni, WebMacro traktuje go jako błąd krytyczny i zapisuje wiadomość ERROR w dzienniku zdarzeń, a na wygenerowanej stronie wyświetla opis błędu. W przypadku niektórych typów błędów, takich jak nieodnalezienie szablonu przez serwlet, WebMacro wyświetla domyślny szablon błędu, konfigurowany przy pomocy właściwości ErrorTemplate w WebMacro.properties.

Oczywiście większość błędów w witrynie WebMacro powinna zostać usunięta na etapie kodu serwletu — niewłaściwe parametry, uszkodzone bazy danych, brakujące pliki i wszystkie inne błędy, które powinny zostać poprawione przed przekazaniem kontroli szablonowi. WebMacro posiada duże możliwości w tym względzie. Serwlet może wykorzystać zbiór standardowych szablonów WebMacro do wyświetlenia informacji o tych błędach, wybierając, do którego szablonu przekazać kontrolę i co zawrzeć w kontekście, zależnie od błędu. Na przykład, jeżeli wystąpił błąd bazy danych , kontrola powinna zostać przekazana do pliku sqlException.wm razem ze stosem ścieżek wyjątków do wyświetlenia.

Aplikacja „Narzędzia”

Aby dokonać podsumowania opisu WebMacro, opisany zostanie sposób przetworzenia aplikacji „Narzędzia” z poprzedniego rozdziału przy pomocy WebMacro zamiast Tea. Jest to najprostsze do zrozumienia, jeżeli na początku spojrzy się na szablon, przedstawiony w przykładzie 15.9.

Przykład 15.9.

Szablon WebMacro aplikacji „Narzędzia”

## widoknarz.wm

#set $Response.ContentType = "text/html"

#set tytul = "Lista narzędzi"

#set tytul2 = "Lista narzędzi służących do tworzenia zawartości"

#set opis = Bez narzędzi, ludzie nie są niczym więcej niż zwierzętami. I to \

dość słabymi. Poniżej przedstawiono listę opartych na serwletach \

narzędzi do tworzenia zawartości, które można wykorzystać w celu \

wzmocnienia się."

#parse "naglowek.wm"

## Zdefiniowanie wartości, które powinny zostać odczytane przez serwlet

#param $domyslnyStan = "ZYJE"

#foreach $narzedzie in $narzedzia {

<HR SIZE=2 ALIGN=LEFT>

<H3>

$narzedzia.Nazwa

#if ($narzedzie.czyNowy(45)) {

<FONT COLOR=#FF0000><B> (Nowość!) </B></FONT>

}

#else {

#if ($narzedzie.czyUaktualniony(45)) {

<FONT COLOR=#ff0000><B> (Uaktualnienie!) </B></FONT>

}

}

</H3>

<A HREF="$narzedzie.DomURL">$narzedzie.DomURL</A><BR>

$narzedzie.Komentarz

}

#parse "stopka.wm"

Początek powyższego szablonu przypisuje wartości tytułom i opisom stron (przy pomocy znaków \ jako znaków kontynuacji opisu). Zmienne te są wykorzystywane wewnątrz zanalizowanego szablonu naglowek.wm w celu utworzenia struktury strony otaczającej podstawową zawartość. Zmienne są również widoczne wewnątrz szablonu stopka.wm przeanalizowanego na końcu szablonu, chociaż stopka nie wykorzystuje ich. Szablony nagłówka i stopki są przedstawione odpowiednio w przykładach 15.10 i 15.11.

Szablon widoknarz.wm wykorzystuje instrukcję #param w celu zdefiniowania ZYJE jako stałej wartości parametru szablonu domyslnyStan, pozwalając serwletowi wywołującemu ten szablon na poznanie domyślnego stanu narzędzi, które powinna wyświetlać niniejsza strona.

Następnie szablon wykorzystuje instrukcję #foreach w celu dokonania działań na całej liście narzedzie przekazanej przez serwlet. Zmienna narzędzi może być tablicą, Iterator, Enumeration lub obiektem takim jak Vector() lub List() posiadającym metodę iterator() lub elements() — nie jest to ważne dla szablonu. Dla każdego egzemplarza narzędzi, szablon wyświetla jego nazwę, informację, czy jest nowy lub uaktualniony, jego URL i ostatecznie komentarz na temat narzędzia. Szablon wywołuje metody czyNowy(int) i czyUaktualniony(int) w celu określenia, czy zawartość powinna zostać uznana za nową lub uaktualnioną, Szablon powinien mieć dostęp do $narzedzie.CzasUtworzeniaDni i $narzedzie.CzasModyfikacjiDni, jednak wymagałoby to obsługi narzędzia kontekstu MatTool z przykładu 15.5 w celu wykonania porównania mniejsze-niż.

Przykład 15.10.

Plik naglowek.wm

## naglowek.wm

<HTML><HEAD><TITLE>$tytul</TITLE></HEAD>

<BODY BGCOLOR="#FFFFFF" BACKGROUND="/obrazki/tlo.gif"

LINK="#003333" ALINK="#669999" VLINK="#333333">

<IMG SRC="/obrazki/banner.gif" WIDTH=600 HEIGHT=87 BORDER=0><BR>

<TABLE>

<TR>

<TD WIDTH=125 VALIGN=TOP>

<BR><BR><BR>

<FONT FACE="Arial,Helvetica" SIZE="+1" COLOR="#FF0000">

<A HREF="/indeks.html">Strona główna</A><BR>

<A HREF="/hosting.html">Hosting</A><BR>

<A HREF="/mechanizmy.html">Mechanizmy</A><BR>

</FONT>

</TD>

<TD WIDTH=475>

<TABLE CELLPADDING=5><TR><TD WIDTH=600 BGCOLOR="#006699" VALIGN=TOP>

<B><FONT FACE="Arial,Helvetica" SIZE="+2">

<% tytul %>

</FONT></B>

</TD></TR></TABLE>

<B><FONT FACE="Arial,Helvetica" SIZE="+1" COLOR="#003366">

<% tytul2 %>

</FONT></B><P>

<P>

<FONT FACE="Arial,Helvetica">

$opis

Przykład 15.11.

Plik stopka.wm

## stopka.wm

</FONT>

</TD>

</TR>

<TR>

<TD></TD>

<TD WIDTH=475 ALIGN=CENTER COLSPAN=3>

<HR>

<FONT FACE="Arial,Helvetica">

<A HREF="/indeks.html">Strona główna</A>&nbsp;&nbsp;

<A HREF="/hosting.html">Hosting</A>&nbsp;&nbsp;

<A HREF="/mechanizmy.html">mechanizmy</A>&nbsp;&nbsp;<P>

</FONT>

<TABLE WIDTH=100%>

<TR>

<TD WIDTH=260 ALIGN=LEFT VALIGN=TOP>

<FONT FACE="Arial,Helvetica">

<A HREF="/wlasnosc.html">Własność</A> &copy; 2000 Jason Hunter<BR>

Wszystkie prawa zastrzeżone.</TD>

<TD WIDTH=5></FONT></TD>

<TD WIDTH=230 ALIGN=RIGHT VALIGN=TOP>

<FONT FACE="Arial,Helvetica">

Kontakt: <A HREF="mailto:webmaster@servlets.com">webmaster@servlets.com</A>

</FONT></TD>

</TR>

</TABLE>

</TD>

</TR>

</TABLE>

</BODY>

</HTML>

Kod klasy Narzedzie pozostaje taki sam jak w przypadku aplikacji Tea, chociaż przy stosowaniu WebMacro nie są konieczne podstawowe metody dostępu, a funkcje czyNowy(int) i czyUaktualniony(int) są widoczne w szablonie. Kod klasy SerwletNarz jest przedstawiony w przykładzie 15.12.

Przykład 15.12.

Serwlet prowadzący aplikację „Narzędzia”

import org.webmacro.*;

import org.webmacro.servlet.*;

import org.webmacro.util.*;

import java.io.*;

import java.sql.*;

import java.util.*;

import javax.servlet.*;

public class SerwletNarz extends WMServlet {

private Log dziennik;

private Narzedzie[] narzedzia;

public void start() throws ServletException {

// Załadowanie danych narzędzi do init w celu zachowania prostoty

String plikNarz = getInitParameter("plikNarz"); // z web.xml

if (plikNarz == null) {

throw new ServletException(

"Plik danych narzędzi musi być określony w parametrze inicjacji plikNarz");

}

dziennik = new Log(getServletName(), "Dziennik błędów przykładu Narzędzia");

dziennik.debug("Ładowanie narzędzi z " + plikNarz);

try {

narzedzia = Narzedzie.ladujNarzedzia(plikNarz);

if (narzedzia.length == 0) {

dziennik.warning("Nie znaleziono żadnych narzędzi w " + plikNarz);

}

else {

dziennik.info(narzedzia.length + " narzędzi znalezionych w " + plikNarz);

}

}

catch (Exception w) {

dziennik.error(w);

throw new ServletException(w);

}

}

// Tworzenie kontekstu dostarcza funkcji dostępnych z szablonów.

public Template handle(WebContext kontekst) throws HandlerException {

// Często przekazuje się żądanie odpowiedź i aplikację, nawet jeżeli nie są

// wykorzystane wszystkie obiekty, ponieważ mogą zostać wykorzystane później

try {

Template widok = getTemplate("widoknarz.wm");

String stan = kontekst.getRequest().getParameter("stan");

if (stan == null) {

stan = (String)widok.getParam("domyslnyStan");

}

if (stan == null) {

kontekst.put("narzedzia", pobierzNarzedzia());

}

else {

kontekst.put("narzedzia", pobierzNarzedzia(stan));

}

return view;

}

catch (WebMacroException w) {

dziennik.exception(w);

throw new HandlerException(w.getMessage());

}

catch (IOException w) {

dziennik.exception(w);

throw new HandlerException(w.getMessage());

}

}

public Narzedzie[] pobierzNarzedzia() {

return narzedzia;

}

public Narzedzie[] pobierzNarzedzie(String stan) {

List lista = new LinkedList();

for (int i = 0; i < narzedzia.length; i++) {

if (narzedzia[i].getStateFlag().equalsIgnoreCase(state)) {

lista.add(tools[i]);

}

}

return (Narzedzie[]) lista.toArray(new Narzedzie[0]);

}

}

Serwlet jest rozszerzeniem WMServlet i w związku z tym definiuje metodę start() zamiast init() oraz metodę handle() zamiast doGet() i doPost(). Metoda start() odczytuje parametr inicjacji plikNarz i ładuje dane narzędzi z pliku przy pomocy Narzedzie.ladujNarzedzia(plikNarz). Metoda ta tworzy również egzemplarz Log i wykorzystuje go do zapisywania raportów na temat pracy, ostrzeżeń i komunikatów o błędach.

Metoda handle() ładuje szablon widoknarz.wm, po czym odczytuje parametr żądania stan w celu określenia stanu narzędzi, które powinny być wyświetlane. Jeżeli taki parametr nie istnieje, serwlet wykorzystuje domyślną wartość określoną wewnątrz samego szablonu. Następnie serwlet umieszcza w WebContext listę odpowiednich narzędzi jako zmienną o nazwie narzedzie i zwraca szablon. Każdy wywołany wyjątek jest zapisywany w dzienniku zdarzeń i przekazywany jako HandlerException.

Metody pobierzNarzedzia() umieszczone na końcu serwletu są jedynie metodami wspierającymi. Nie są one dostępne szablonowi, chociaż mogłyby zostać uwidocznione poprzez zawarcie w kontekście obiektu lookup zawierającego te metody. Następnie szablon mógłby wykonywać własną obsługę parametru stan:

#set $stan = $Form.stan;

#if (!stan) {

#set $narzedzia = $lookup.pobierzNarzedzia("zyje")

}

#else {

#set $narzedzia = $lookup.pobierzNarzedzia($stan)

}

Wybór pomiędzy podejściem opartym na przeciąganiu i modelem przepychania przedstawionym powyżej jest w większość rzeczą gustu. WebMacro popiera raczej model przepychania, a Tea — przeciągania; jednak oba narzędzia obsługują oba modele.

Można wykorzystać klasę com.oreilly.servlet.CacheHttpServlet, opisaną w rozdziale 3, „Okres trwałości serwletu” w celu zapisania wyświetlanych danych w pamięci podręcznej i poprawienia wydajności szablonów. Technika ta jest najlepsza w przypadku szablonów, które wyświetlają dane wymagające dłuższego czasu przygotowania, a zmieniają się stosunkowo rzadko, na przykład szablony odczytujące wyniki z bazy danych. Aby skorzystać z pamięci podręcznej należy utworzyć swój serwlet jako rozszerzenie CacheHttpServlet (wiąże się to z niemożnością skorzystania z WMServlet i koniecznością samodzielnej obsługi szablonów) oraz wykorzystać metodę getLastModified(). Jeżeli dane pochodzą z bazy danych, metoda getLastModified() może zwrócić czas ostatniego uaktualnienia bazy (poprzez znajdującą się w kontekście zmienną serwletu wykonującego uaktualnienie) lub, jeżeli czas uaktualnienia nie może zostać określony, metoda może po prostu zwrócić aktualny czas minus pewną wartość, tak więc uaktualnienia mogą być wykonywane w regularnych odstępach czasu. Jeżeli dane pochodzą z pliku, metoda może zwrócić ostatni czas modyfikacji pliku (przypuszczalnie sprawdzając ją jedynie co pewien czas w celu poprawienia wydajności).

Filtry

W trakcie pisania niniejszego tekstu, proces tworzenia WebMacro dopiero od niedługiego czasu był udostępniony większej ilości osób i został przeniesiony ze stosunkowo restrykcyjnej licencji GPL do mniej ograniczającej licencji w stylu Apache'a. Wynikiem udostępnienia narzędzia większej ilości programistów jest aktualna ich praca nad wieloma interesującymi i przydatnymi rozszerzeniami.

Najbardziej istotne rozszerzenie zawiera dołączany mechanizm filtrów. Jego ideą jest wyświetlanie zmiennej poprzez filtr kontrolujący sposób jej wyświetlania. Standardowe filtry wykonują następujące działania:

Filtry niestandardowe

Filtry niestandardowe wykonują konkretne działania. Na przykład, zmienna klient może zostać przefiltrowana przez szablon klienta zaprojektowany w celu wyświetlania zmiennej i jej właściwości w oparciu o zewnętrzny plik szablonu. Szablon klienta może nawet przefiltrować adres klienta poprzez zewnętrzny szablon adresu. Pozwala to na ponowne stosowanie i łatwe dostosowywanie logiki wyświetlania. Filtry mogą być także łączone w łańcuchy. Pozwoliłoby to na przykład na zarówno lokalizację jak i wyłączenie zmiennej, określoną wcześniej wartością, jeżeli zmienna posiadałaby wartość null.

Możliwe zastosowania filtrów znajdują się ciągle jedynie w wyobraźni ludzi. Interesujące może okazać się śledzenie, które zastosowania filtrów WebMacro staną się popularne.

Archiwum collections.jar zawiera klasy Java Collections (wprowadzone w JDK 1.2) utworzone do stosowania z wcześniejszym JDK 1.1. Ten plik JAR nie jest wymagany, jeżeli dysponuje się kompilacją WebMacro przeznaczoną konkretnie dla JDK 1.2; jednak w trakcie tworzenie niniejszej książki domyślna kompilacja webmacro.jar była przystosowana dla JDK 1.1.7 i w związku z tym ten plik jest wymagany nawet podczas korzystania z JDK 1.2 lub późniejszego.

Jednak z powodu dużych nacisków operacje arytmetyczne są dodawane i mogą być dostępne w momencie wydania książki

Dołączany mechanizm analizatora może zostać zastąpiony przez docelowe instrukcje. Na przykład #use 'text' może zostać zastąpiony przez #text, a #use 'null' przez #comment.

W WebMacro 0.94 (według tej wersji sprawdzany był kod w niniejszym rozdziale) występuje błąd, w którym błędy składni szablonów mogą spowodować wyświetlenie przez WebMacro pustej strony zamiast strony zawierającej opis błędu Bez wątpienia błąd ten zostanie naprawiony w następnych wersjach.

2 Część I Podstawy obsługi systemu WhizBang (Nagłówek strony)

2 H:\Książki\!Wit\Java Servlet Programming\5 do merytorycznej\r15-05.doc



Wyszukiwarka

Podobne podstrony:
r15-05, ## Documents ##, flash5biblia
r19 05 (15)
Pius XI 1931 05 15 Encyklika Quadragesimo Anno 1
2003 05 15
05 15 86
R15-05(2), Informacje dot. kompa
MB (Lab) - Różne ściągi, liczby, Gęstość/obj:BetonZwykły2,8(2,0-2,2) Cement3,05-3,15(1,1-1,2) Cerami
D og egzamin 12-05-15, PEDAGOGIKA, I ROK, W szkoła
Przedtermin& 05 15
r20 05 (15)
r15 05 (23)
DGP 2014 05 15 ubezpieczenia i swiadczenia
2012 05 15 Zajęcia w KSP i Muzeum Policji sprawozdanie Sine Cura Suwałki
Wykład 05, 15
2 1 VII 05 15
Materiały Dzidowski 2013 05 15
Farma kliniczna wykłady Wykład 05 15

więcej podobnych podstron