Subsections


3 Projekt systemu

W poprzednich rozdziałach naszkicowano cele systemu oraz przedstawiono istniejące środowiska o podobnych zastosowaniach. W oparciu o te dane można określić wymaganą funkcjonalność, potrzebną do zrealizowania celów. W kolejnych podrozdziałach zostanie przedstawiony projekt bardziej złożonych części systemu.

Techniczne, szczegółowe informacje na temat zastosowanych rozwiązań znajdują się w kolejnym rozdziale (rozdz. 4).


1 Wymagania

System oraz język LSP przede wszystkim musi realizować wszystkie założenia przedstawione we wstępie. Musi zatem zapewniać następującą funkcjonalność:

W kolejnych rozdziałach szczegółowo przedstawiono projekt interpretera, założenia systemu autoryzacji oraz wymagania dotyczące rozszerzeń i funkcjonalności specyficznej dla aplikacji WWW.


2 Interpreter LSP

1 Parser

W systemie LSP została zastosowana technologia TWIG (zob. p. 2.1.1), gdyż daje ona te same możliwości co DOM, a jednocześnie nie posiada jego wad oraz znacznie lepiej używa się jej w Perlu. Ze względu na brak możliwości wielokrotnego przetwarzania węzłów w istniejącej implementacji TWIG, w LSP zastosowano własną o podobnej zasadzie działania.

TWIG ma oczywiście ograniczenia wynikające z niemożliwości sięgnięcia do już przetworzonych węzłów, ale konstrukcja systemu LSP nie wymaga takich operacji, w związku z czym jest to najlepsze rozwiązanie dla tego zastosowania.

Rysunek 3.1: Schemat modelu przetwarzania TWIG
Image twig.png

Rysunek 3.1 przedstawia zasadę działania modelu TWIG. Strumień wejściowy XML (składający się z odpowiadających sobie otwierających i zamykających znaczników, oznaczonych odpowiednio kolorami białym i czarnym) jest w miarę wczytywania przekształcany na drzewo struktury. W drzewie tym pewne węzły (oznaczone szarym kolorem) do przetworzenia wymagają wyników przetwarzania całego swojego poddrzewa. Pozostałe nie mają takich ograniczeń i ich poddrzewa można usunąć z pamięci (na diagramie niepotrzebne węzły są objęte szarym prostokątem).

W trakcie przetwarzania kod odpowiadający za obsługę poszczególnych węzłów generuje dokument wyjściowy, na diagramie przedstawiony jako ciąg szarych pudełek. Elementy wyjściowe tworzą kolejny strumień, który może być przesłany do procesora XSLT, przetworzony na inny format dokumentu wewnątrz LSP, bądź też po prostu przesyłany do użytkownika.

Dzięki takiej konstrukcji LSP może zarówno przetwarzać duże dane wejściowe, jak i generować bardzo duże dokumenty, nie zużywając ogromnych ilości pamięci.

2 Język

Zgodnie z założeniami instrukcje języka powinny być zapisywane jako węzły dokumentu XML. LSP musi także zawierać operacje na zmiennych (służących między innymi do przechowywania danych wejściowych) oraz konstrukcje językowe reprezentujące same zmienne. Ponieważ zapisywanie tych bardzo częstych operacji jako węzłów XML byłoby niewygodne, postanowiłem do tego celu wykorzystać standard XPath -- stanowiący również część XSLT i innych języków operujących na XML, jak np. XQL[*].

XPath wykorzystuje się w LSP do adresowania dokumentów XML wczytywanych z dysku i tworzonych na podstawie danych pobieranych z baz SQL, jak również do obsługi zmiennych. Dzięki wykorzystaniu istniejącego standardu, rozwiązuje się problem przetwarzania dokumentu w celu dokonania wartościowania zmiennych, gdyż można do tego celu wykorzystać gotowe biblioteki.


3 Mechanizm działania

Działanie interpretera przy wykorzystaniu drzewa struktury sprowadza się do zdefiniowania procedur obsługi węzłów będących instrukcjami języka. Dzięki użyciu XML można wykorzystać istniejące metody dostępu do parametrów instrukcji (czyli atrybutów elementów drzewa).

Pozostała treść aplikacji, czyli węzły XML nie należące do LSP oraz tekst (czyli węzły tekstowe), jest wykorzystywana zgodnie z zasadą działania instrukcji LSP, do której przynależy. W najprostszym przypadku jest ona -- po zinterpretowaniu wszystkich wyrażeń XPath -- kopiowana do dokumentu wyjściowego.

Działanie każdej instrukcji języka LSP obejmuje więc następujące etapy:

  1. Operacje początkowe

    W kilku przypadkach instrukcje LSP wymagają wykonania pewnych operacje przed przeczytaniem treści, na przykład wstawienia elementów do dokumentu wyjściowego.

  2. Przetworzenie poddrzewa

    Ten etap może być wykonywany wielokrotnie, zależnie od zasady działania odpowiedniej instrukcji języka. Przykładowo podczas pobierania danych z bazy, zawartość węzła zostanie przetworzona dla każdego rekordu wynikowego przekazanego przez zapytanie.

  3. Zakończenie

    Po zakończeniu przetwarzania poddrzewa mogą być wykonywane operacje, które do działania potrzebują całości wygenerowanych danych, jak na przykład przetwarzanie XSLT.

4 Podstawowe instrukcje języka

Pozostaje sformułowanie podstawowej funkcjonalności języka, tj kluczowych instrukcji. Poniższa lista zawiera grupy funkcji, które musi realizować główna część LSP, w kolejnych podrozdziałach są również omówione specyficzne instrukcje wymagane do zrealizowania pozostałych funkcji systemu. Pełny opis języka znajduje się w dodatku A.

Poza instrukcjami potrzebnymi do realizacji wymagań, wymienionymi w tym oraz w kolejnych podrozdziałach, język zawiera również kilka instrukcji dodanych w celu umożliwienia lepszego wykorzystania możliwości środowiska LSP. Są one opisane w rozdziale 4 (oraz w opisie języka, w dodatku A).


3 Przetwarzanie danych

Środowisko LSP ma służyć do tworzenia aplikacji bazodanowych, więc kluczowym elementem jest pobieranie danych i ich przetwarzanie. Możliwe jest pobieranie danych z relacyjnych baz SQL oraz z statycznych plików XML. Dane mogą być przetwarzane za pomocą XSLT. Jeżeli te możliwości nie są wystarczające dla potrzeb aplikacji, to jest możliwe proste dodawanie nowych źródeł danych, jak również funkcji przetwarzających.


1 SQL

Pobieranie danych z baz SQL możliwe jest dzięki instrukcji QUERY (A.4.2). Programista musi jedynie wyspecyfikować bazę danych, z której chce pobierać dane, oraz wykonywać zapytania. Rekordy pobierane z bazy są automatycznie zamieniane na postać XML i przypisywane na określoną przez programistę zmienną.

Możliwe jest też pobieranie i przetwarzanie dokumentów XML przechowywanych w bazie SQL.


2 XML

LSP potrafi pobierać dokumenty XML z dysku i przypisywać je do zmiennych (za pomocą instrukcji LOAD - A.4.9). Następnie można je wykorzystywać w aplikacji za pomocą wyrażeń XPath. LOAD może działać podobnie jak QUERY - możliwe jest podanie maski nazwy pliku. W takim przypadku zawartość węzła zostanie przetworzona wielokrotnie, dla każdego pasującego pliku.

Możliwe jest też zapisywanie zmiennych zawierających dokumenty XML na dysku za pomocą operacji STORE (A.4.12). Zasada działania tej instrukcji jest podobna do zasady działania operacji SET, jakkolwiek wartość nie jest przypisywana do zmiennej tylko do pliku.


3 XSLT

Integracja LSP z XSLT umożliwia przetwarzanie wyników działania przy użyciu arkusza stylów. Służy do tego instrukcja TRANSFORM (A.4.14). Zawartość takiego węzła jest przetwarzana, a następnie wynik jest wykorzystywany jako wejście dla procesora XSLT.


4 Rozszerzalność

LSP zapewnia kilka możliwości rozszerzenia, m.in prosty mechanizm służący (przede wszystkim) do pobierania danych z innych źródeł niż wymienione wcześniej. Służy do tego instrukcja CALL (A.4.13). Funkcja ta działa podobnie jak QUERY, tyle że zamiast wywoływać zapytania SQL, wywołuje (stworzoną przez twórcę aplikacji) funkcję, napisaną w Perlu i przekazującą wynik działania w postaci tablicy haszującej[*]. Umożliwia to dodanie nowego źródła danych bez konieczności głębszego poznawania działania LSP, a także proste dodawanie funkcji nie będących źródłami danych, ale realizujących jakąś specyficzną funkcjonalność potrzebną do działania aplikacji.


4 Autoryzacja

LSP dostarcza złożony system autoryzacji, który stanowi dobrą podstawę do zabezpieczenia aplikacji. System ten jest dość uniwersalny, choć mogą znaleźć się zastosowania wymagające bardziej złożonych mechanizmów.


1 Uwierzytelnianie

System wspiera logowanie użytkowników poprzez przekazanie specjalnych parametrów określających nazwę użytkownika oraz hasło. W celu przekazania tych informacji można skorzystać ze specjalnie do tego celu stworzonych typów danych login i password instrukcji PARAM (A.4.3). System przechwyci takie parametry i spróbuje zalogować użytkownika do systemu. Jeżeli użytkownik jest nieokreślony, a w niektórych zastosowaniach użytkownik zawsze będzie nieokreślony, system autoryzacji zakłada, że nie ma on żadnych uprawnień.


2 Założenia systemu autoryzacji


Podstawowe pojęcia

Przykładowo, rekord opisujący dane klienta jest obiektem -- rekordem typu dane klienta. Funkcja wykonująca pewne obliczenia dla użytkownika też jest obiektem, klasy np. funkcja matematyczna.

Obiektem z punktu widzenia systemu autoryzacji jest wszystko to do czego aplikacja może chcieć mieć dostęp. Klasy obiektów, obiekty same w sobie są definiowane przez aplikację, system autoryzacji dostarcza tylko ogólnych metod weryfikacji praw dostępu do funkcji i danych.


Ogólny schemat dostępu do obiektu

Niech użytkownik X dysponuje zestawem uprawnień Y (listy uprawnień są obsługiwane przez system autoryzacji, więc z punktu widzenia systemu użytkownik to tak naprawdę identyfikator listy uprawnień). Użytkownik ten chce wykonać pewną operację A na obiekcie O. Obiekt O jest klasy C. System ma dostarczyć mechanizm do weryfikacji, czy użytkownik określony przez identyfikator Y może wykonać operację A na obiekcie klasy C.

W skrócie można ten schemat opisać w następujący sposób: użytkownik może mieć dostęp do pewnych klas obiektów przynależących do określonych grup (oraz ich podgrup).


3 Hierarchia obiektów

Rysunek 3.2: Diagram hierarchii obiektów
Image autoryzacja.gif

Diagram 3.2 przedstawia przykładowy model hierarchii obiektów w systemie LSP.


Uwagi

Zależności między grupami są częścią systemu autoryzacji (ale są konfigurowane przez aplikację), przynależności obiektów do grup są określane wyłącznie przez aplikację.


Rozszerzony schemat dostępu do obiektu

Użytkownik określany identyfikatorem Y chce wykonać akcję A na obiekcie klasy C, który znajduje się (lub np. jest tworzony) w grupie G. System sprawdza listy uprawnień, znajdując takie, które są przypisane do tego konkretnego użytkownika, określają prawa do wykonywania akcji A na obiektach klasy C lub zgodnych (można użyć '*' jako nazwy klasy lub akcji, oznacza to prawo do wszystkich klas lub akcji). Grupa określona w danym wpisie w bazie uprawnień musi być nadgrupą grupy G. Jeżeli grupa w tabeli nie jest określona, oznacza to grupę domyślną, czyli grupa G musi być podgrupą jednej z grup, do których należy użytkownik Y.


4 Uprawnienia do obiektów

Rysunek 3.3: Schemat zależności autoryzacyjnych
Image prawa.png

Diagram 3.3 ilustruje schemat działania mechanizmów autoryzacyjnych.

Aplikacja sprawdza czy pewien jej obiekt, który jest klasy Klasa i należy do grupy Grupa, może być udostępniony użytkownikowi Użytkownik o profilu dostępu Profil. Dodatkowym parametrem jest Akcja, którą użytkownik chce na tym obiekcie wykonać. System autoryzacji przechowuje listy dostępu określające wszystkie możliwe sytuacje, w których powinien zezwolić na dostęp, z dodatkowo określonym poziomem Poziom, który może być dowolnie wykorzystany przez aplikację.

Przykładowo użytkownik JanKowalski, który jest przypisany do profilu Klient chce zmodyfikować pewien dokument w systemie. Dokument ten należy do klasy Dokument. Uprawnienia określają, że może to zrobić dla np. grupy OponyWiosenneSA, czyli jego firmy. Dodatkowo, określają też że dla żądanej operacji (akcji) typu Modyfikacja ma zapewniony dostęp na poziomie 5. Aplikacja do modyfikacji dokumentu wymaga poziomu 3, więc uprawnienia zostają przyznane, jakkolwiek zostają zablokowane niektóre elementy dokumentu, wymagające poziomu 6.

Gdyby ten sam użytkownik usiłował wykonać identyczną operację na dokumencie należącym do innej firmy, dostęp zostałby zablokowany.

Klasa obiektu, operacja oraz poziomy uprawnień są określone w aplikacji. Grupa jest pobierana z bazy danych bądź z dokumentu, natomiast uprawnienia użytkownika z tabeli autoryzacyjnej w bazie systemu LSP. Sama aplikacja nie musi sprawdzać kim jest jej użytkownik, polityka bezpieczeństwa jest więc w przejrzysty sposób podzielona na definiowanie zabezpieczeń w aplikacji oraz przyznawanie uprawnień użytkownikom.


5 Elementy autoryzacyjne języka LSP

W celu wykorzystania mechanizmów autoryzacyjnych, spora część instrukcji języka LSP została rozszerzona o wspólny zestaw atrybutów autoryzacyjnych (A.3.1), umożliwiających zdefiniowanie do jakiej klasy obiektów wymagane są uprawnienia, aby można było wykonać daną funkcję, do jakiej grupy należy ten obiekt oraz jakiego poziomu operacja jest wymagana.

Najprostszym przykładem zastosowania jest instrukcja IF, umożliwiająca uzależnienie przetworzenia jej zawartości od spełnienia wymagań autoryzacyjnych.

Można prosto pokazać jak przydaje się rozróżnienie klasy obiektu, grupy oraz poziomu. Klasa obiektu jest na stale przypisana do fragmentu aplikacji o ograniczonym dostępie. Grupa może wynikać z przetwarzania danych pochodzących z bazy SQL i chęci pokazywania jedynie tych informacji, które użytkownik może zobaczyć. Poziom z kolei może powodować udostępnianie bardziej zaawansowanych funkcji lub bardziej szczegółowych danych.


5 Formularze HTML

Dla ułatwienia tworzenia i przetwarzania formularzy, LSP zawiera instrukcje umożliwiające tworzenie list wyboru i pól wprowadzania tekstu na podstawie informacji pobieranych z bazy danych. Formularze takie mogą być też automatycznie obsługiwane, w przypadku operacji wstawiania oraz aktualizowania danych działających tylko na jednej tabeli.


1 Komponenty formularzy

Formularz generowany przez LSP umożliwia reprezentację jednego rekordu z jednej tabeli z bazy SQL. Nie jest możliwe edytowanie w ten sposób plików XML; to niestety zbyt skomplikowane zagadnienie. Sam formularz jest obsługiwany za pomocą instrukcji FORM (A.4.17). Instrukcja ta wymaga podania nazwy tabeli, z której pobierane będą dane, nazwy klucza oraz identyfikatora rekordu do edycji. W bardziej skomplikowanych sytuacjach można też wykorzystać zapytanie SQL do wyboru rekordu. Jeśli podany zostanie klucz oraz pusty identyfikator, to zostanie stworzony formularz nowego rekordu (z pustymi bądź domyślnymi wartościami pól).

Formularze mogą zawierać trzy rodzaje komponentów odpowiadających danym z bazy: pola tekstowe (INPUT - A.4.18), pola wyboru (LINK - A.4.19) oraz pola logiczne (BOOLEAN - A.4.21). Pola wyboru umożliwiają powiązanie z co najwyżej jednym kluczem obcym. Wszystkie komponenty mogą mieć zdefiniowane wartości domyślne (w przypadku list wyboru określa się domyślną wartość klucza obcego). Pola tekstowe mogą być różnych typów, odpowiadających typom zmiennych obsługiwanych przez LSP.

Dodatkowo jest też obsługiwana instrukcja BUTTON (A.4.20), umożliwiający wstawianie do formularzy przycisków, których wybranie spowoduje przekazanie wartości z formularza do wybranego podprogramu LSP bądź wywołanie automatycznej obsługi formularzy.


2 Automatyczna obsługa

Dzięki wbudowanym zaawansowanym mechanizmom obsługi sesji, wszystkie dane o formularzu, który został wygenerowany dla użytkownika, mogą zostać przechowane właśnie w sesji. System może stwierdzić na podstawie zachowanych danych do jakiej tabeli powinien wstawić dane przesyłane przez użytkownika oraz czy przesyłane dane są poprawne (tzn. czy użytkownik nie usiłuje przesłać danych niezgodnych z wygenerowanym formularzem, np. o nieodpowiednich typach, lub, w przypadku list wyboru, o wartości nie będącej prawidłowym kluczem obcym). Pełna specyfikacja formularza, zachowana w sesji, jest porównywana z przesłanymi danymi. Po wykorzystaniu, informacje o formularzu są usuwane, dzięki temu automatycznie uzyskuje się zabezpieczenie przed wielokrotnym przetworzeniem tego samego formularza.

Po weryfikacji przesłane dane są tłumaczone na odpowiednie instrukcje SQL i wykonywane. Mechanizm ten umożliwia jedynie operacje na pojedynczych tabelach i pojedynczych rekordach. Ponieważ jednak właśnie takie operacje stanowią olbrzymią większość wszystkich operacji na danych w typowych aplikacjach bazodanowych, więc możliwości te bardzo ułatwiają tworzenie takich programów. Bardziej zaawansowane operacje można zaimplementować zapisując je w LSP, bądź też jako rozszerzenia systemu -- w Perlu.


6 Generowanie dokumentów w wielu formatach

W przypadku bardzo prostych aplikacji, jak również na etapie tworzenia prototypów systemu, może nie być wymagane operowanie wyłącznie na dokumentach XML i przetwarzanie ich za pomocą XSLT. Niezależnie od tego przydatne jest tworzenie dokumentów w postaci PDF czy też tabeli w postaci arkuszy Excel. W celu umożliwienia wykorzystania takich funkcji w prostych aplikacjach, LSP zawiera moduł przekształcający minimalny podzbiór HTML na TeX (i pośrednio także PDF) oraz XLS.

Generowanie dokumentów jest uaktywniane na podstawie rozszerzenia pliku zażądanego przez użytkownika z przeglądarki WWW. Rozszerzenia xml, html, lsp powodują wygenerowanie dokumentu w formacie HTML. Na podstawie nazwy żądanego pliku, system określa aplikację LSP która powinna zostać uruchomiona w celu wygenerowania treści dokumentu (Aplikacje te na dysku posiadają rozszerzenie lsp).

Dla innych formatów można użyć rozszerzenia tex, pdf bądź xls. Tak więc aby z aplikacji wygenerować dokument PDF, należy po prostu skierować użytkownika do dokumentu o nazwie identycznej z aplikacją, która generuje treść tego dokumentu, ale o rozszerzeniu pdf zamiast lsp bądź xml.

1 LaTeX/PDF

LSP umożliwia przekształcanie wynikowego dokumentu z HTML na LaTeX oraz, wykorzystując program pdflatex, do postaci PDF. Obsługiwane znaczniki to bardzo skromny podzbiór możliwości formatujących HTML (elementy B, I, CODE, PRE, CENTER, BR, P, NBSP) oraz obsługa prostych (nie zagnieżdżonych) tabel (elementy TABLE, TH, TR, TD).

Przetwarzanie takie odbywa się po stworzeniu całego dokumentu HTML przez aplikację LSP. Znaczniki nie obsługiwane przez aplikację zostaną automatycznie usunięte. Aplikacja może też kontrolować, które części dokumentu mają być dostępne w różnych formatach, wykorzystując systemową zmienną format (zob. p. A.2).

2 Excel

Podczas generowania dokumentów w formacie XLS wykorzystywany jest również podzbiór HTML. W tym przypadku jednak obsługiwane są jedynie znaczniki służące do obsługi tabel (identyczne jak w przypadku TeX oraz PDF). Poszczególne tabele w dokumencie przekształcane są na odrębne arkusze. Wszelkie formatowanie jest ignorowane.


7 Rozszerzenia LSP

W p. 3.3.4 przedstawiono mechanizm rozszerzania LSP poprzez definiowanie nowych źródeł danych, umożliwiający również tworzenie ogólnych rozszerzeń. Poza tą możliwością istnieją jeszcze dwa mechanizmy.


1 Nowe formaty wyjściowe

Pisząc odpowiedni filtr można prosto dodać obsługę nowego formatu wyjściowego. Filtry są programami zupełnie niezależnymi od całego LSP, są wykonywane przez środowisko w przypadku zażądania odpowiedniego typu dokumentu. Filtr otrzymuje na standardowym wejściu wygenerowaną przez aplikację LSP treść dokumentu i powinien przekazać wynik, wypisując go na standardowe wyjście.

Dzięki tej bardzo prostej metodzie, można bardzo poszerzyć możliwości aplikacji nie wykorzystujących XSLT, a także zrealizować przekształcenia trudne bądź mało wydajne przy zastosowaniu XSLT (np. zamiana standardu kodowania dokumentu).


2 Rozszerzenia języka

LSP umożliwia także tworzenie bibliotek znaczników, całkowicie zintegrowanych z systemem. Wymaga to dogłębnego zapoznania się z środowiskiem LSP, w szczególności, w przeciwieństwie do pozostałych technik rozszerzeń, konieczna jest dobra znajomość źródeł systemu. Jednak po zapoznaniu się ze sposobem realizacji istniejących instrukcji, pisanie kolejnych jest już łatwe.

Mechanizm działania wszystkich instrukcji jest przedstawiony w p. 3.2.3. Nie jest on skomplikowany, tak więc ich implementacja też nie może być bardzo skomplikowana. Najprostsza instrukcja -- kopiująca po prostu zawartość -- to jeden wiersz kodu. Trudniejsze jest tworzenie instrukcji korzystających ze zmiennych, systemów autoryzacji i uwierzytelniania, różnych źródeł danych.

Niestety nie ma tu miejsca na szczegółowe opisanie całego kodu systemu. Szczegółowe opisy znajdują się w komentarzach zawartych w tym kodzie i tam należy szukać pomocy przy pisaniu nowych modułów.

8 Uwagi

W tej części pracy przedstawiono jedynie wybrane, najbardziej złożone fragmenty systemu. Pominięto problemy związane z tworzeniem środowiska, ale nie dotyczące bezpośrednio wskazanych we wstępie celów systemu LSP. Niektóre z tych zagadnień, związane z implementacją, są przedstawione w kolejnym rozdziale.



Footnotes

...XQL[*]
XQL - XML Query Language, język zapisu kwerend pobierających dane z dokumentów XML.
... haszującej[*]
Tablice haszujące w Perlu to tablice indeksowane dowolnymi typami danych, tutaj napisami -- nazwami pól.