WASS - prowadzenie badań w zakresie nauk społecznych przez Internet

Tomasz Zieliński

Grudzień 2002

 

Streszczenie

Praca została poświęcona aplikacji WASS będącej środowiskiem umożliwiającym prowadzenie badań w dziedzinie nauk społecznych przy pomocy komputera w środowisku rozproszonym. W pracy opisano wymagania stawiane takiemu środowisku, projekt systemu, sposób wykonania oraz przykładową realizację rzeczywistego badania w zakresie psychologii. Ponieważ WASS jest przykładem aplikacji internetowej, w pracy dokonano przeglądu najpopularniejszych technologii wykorzystywanych przy tworzeniu takich aplikacji.

Spis treści

1. Wstęp
    1.1. Cel pracy
    1.2. Struktura pracy

2. Tworzenie aplikacji internetowych
    2.1. Specyfika aplikacji internetowych
    2.2. Wymagania stawiane środowiskom tworzenia i działania aplikacji
    2.3. PHP
    2.4. ASP
    2.5. J2EE
    2.6. ASP.NET
    2.7. Turbina

3. Projekt
    3.1. Analiza wymagań
    3.2. Przypadki użycia
    3.3. Podział na moduły
    3.4. Model danych
    3.5. System bezpieczeństwa

4. Architektura Turbiny
    4.1. Metodologia MVC
    4.2. Model logiczny
    4.3. Obsługa żądania
    4.4. Serwisy
    4.5. Dostęp do danych
    4.6. Velocity
    4.7. Podsumowanie

5. Implementacja
    5.1. Zastosowane technologie
    5.2. Architektura aplikacji
    5.3. Moduł Security
    5.4. Moduł Storage
    5.5. Moduł User
    5.6. Moduł Admin Test
    5.7. Moduł Admin Research
    5.8. Moduł Admin Process
    5.9. Moduł Object Model
    5.10. Dokumentacja techniczna

6. Przykładowe realizacje
    6.1. Badanie 1
    6.2. Badanie 2

7. Ocena przydatności Turbiny
    7.1. Zalety Turbiny
    7.2. Wady Turbiny
    7.3. Przyszłość Turbiny

8. Podsumowanie

A. Model danych

B. Zawartość płyty

Bibliografia

 

1. Wstęp

Wraz z popularyzacją komputerów osobistych klasy PC i pojawieniem się graficznego interfejsu użytkownika wprowadzonego przez firmę Microsoft znacznie wzrosła liczba osób wykorzystujących komputer zarówno do pracy, jak i do rozrywki. Do grona użytkowników komputerów dołączyły osoby zajmujące się kierunkami uważanymi za humanistyczne, takimi jak psychologia i socjologia. Przedstawiciele nauk społecznych w swej pracy najczęściej wykorzystują edytory tekstu oraz pakiety statystyczne. Zwłaszcza pojawienie się tych drugich, takich jak Statistica i SPSS, ułatwiło analizę wyników badań, nie tylko poprzez obliczanie statystyk opisowych (średnia, mediana, odchylenia standardowe itp.), ale i używanie bardziej zaawansowanych metod, takich jak krokowa analiza regresji wielokrotnej, czy analiza czynnikowa.

Niestety ciągle konieczne jest żmudne wprowadzanie do programów statystycznych odpowiedzi osób badanych, które są zapisane w papierowych kwestionariuszach. Oczywiście najwygodniej byłoby gdyby zarówno badanie, jak i zbieranie odpowiedzi mogło odbywać się elektronicznie. Dlatego tak ważne wydaje się stworzenie środowiska pozwalającego na przeprowadzanie różnorakich badań psychologicznych i socjologicznych przy użyciu komputera. Poza skróceniem czasu obróbki danych, technologie informatyczne oferują takie możliwości jak dokładne sterowanie czasem ekspozycji obrazu, prezentację treści multimedialnych, czy interakcje między badanymi, które przy wykorzystaniu innych technik są kosztowne i kłopotliwe w realizacji podczas badań.

1.1. Cel pracy

Celem mojej pracy było stworzenie środowiska, pozwalającego na przeprowadzanie badań psychologicznych i socjologicznych przy użyciu komputera. Kluczowym elementem pracy było zaprojektowanie i zaimplementowanie systemu umożliwiającego realizację najpopu-larniejszych typów kwestionariuszy używanych w naukach społecznych. Stworzony system musiał być na tyle otwarty, by można go było łatwo rozwijać, poprzez dodawanie nowych, niedostępnych w "papierowych" badaniach elementów, wzbogacających warsztat badawczy naukowców. Narzędzie to musiało pozwalać na ochronę efektów pracy twórczej naukowców, jakimi są zaprojektowane badania oraz wyniki przeprowadzonych eksperymentów. W tym celu konieczne było zapewnienie odpowiedniego poziomu bezpieczeństwa systemu poprzez określenie sposobu autoryzacji i dostępu do elementów środowiska.

Zdecydowałem się na stworzenie wspomnianego środowiska w postaci aplikacji internetowej, którą nazwałem WASS (Web Application for Social Sciences), nawiązując w ten sposób do nazwy programu SPSS. Jako jedna z osób biorących udział w rozwoju narzędzia wspomagającego proces tworzenia aplikacji internetowych jakim jest Turbina [1], postanowiłem zrealizować tę pracę przy jego pomocy. Na podstawie zdobytych w czasie realizacji tego projektu doświadczeń, chciałem ocenić rzeczywistą przydatność Turbiny.

1.2. Struktura pracy

W rozdziale 2 pracy opisałem sposób tworzenia aplikacji internetowych. Dokonałem analizy specyfiki takich aplikacji, a także zdefiniowałem wymagania stawiane środowiskom tworzenia tego typu programów. Następnie opisałem najpopularniejsze technologie wykorzystywane przy konstruowaniu aplikacji internetowych, z punktu widzenia zdefiniowanych przeze mnie kryteriów.

W rozdziale 3 opisałem wymagania jakie musi spełniać środowisko wspomagające prowadzenie badań w naukach społecznych oraz przedstawiłem projekt takiego narzędzia. W projekcie znalazły się przypadki użycia, podział systemu na moduły oraz model danych.

W kolejnym rozdziale opisałem Turbinę, narzędzie przy pomocy którego powstał mój program. Omówiłem te elementy tego środowiska, które są istotne do zrozumienia sposobu w jakim zrealizowałem system WASS. Opis implementacji poszczególnych modułów umieściłem w rozdziale 5.

W rozdziale 6 przedstawiłem dwa przykładowe badania i sposób ich realizacji przy pomocy stworzonego przeze mnie systemu. Na podstawie doświadczeń zdobytych podczas powstawania systemu WASS, mogłem dokonać oceny przydatności Turbiny jako środowiska tworzenia aplikacji internetowych. Takiej ocenie poświęciłem rozdział 7 pracy. W rozdziale 8 zawarłem ostateczne podsumowanie całego projektu.

W pracy umieściłem ponadto dwa dodatki. W dodatku A opisałem wykorzystywane przez system tabele bazy danych. Dodatek B został zaś poświęcony zawartości dołączonej do pracy płyty CD-ROM.

2. Tworzenie aplikacji internetowych

2.1. Specyfika aplikacji internetowych

Trudno jest podać dokładną definicję aplikacji internetowej. Pierwszą próbą sformułowania takiej definicji mogłoby być stwierdzenie, iż jest to program, do którego dostęp odbywa się poprzez strony WWW [2]. Z jednej strony taki opis oddaje najbardziej charakterystyczną cechę aplikacji internetowych, z drugiej jest zbyt ogólny. Uważam bowiem, że nie należy traktować jako aplikacji internetowej strony pozwalającej na włączanie i wyłączanie światła w ogródku, gdyż w tym przypadku ta strona stanowi w istocie tylko interfejs do rzeczywistego urządzenia.

Można też twierdzić, że aplikacją internetową jest program generujący zawartość stron w odpowiedzi na akcje ze strony użytkownika. Ta definicja znakomicie pasuje do opisu różnego rodzaju portali i wortali. Niestety nie oddaje ona jednego ważnego aspektu takich aplikacji, a mianowicie, że poza generowaniem stron, mogą również następować zmiany w samym systemie. Aplikacje internetowe są to więc programy, do których pasują obie podane przeze mnie definicje. Opiszę teraz cechy charakterystyczne takich aplikacji.

Przede wszystkim komunikacja użytkownika z programem odbywa się poprzez strony prezentowane przez przeglądarkę internetową. Dostępne dla korzystającego z programu funkcjonalności powinny więc dać się opisać i zrealizować przy pomocy środków dostępnych w języku HTML [3] i JavaScript [4].

Prezentacja informacji może odbywać się przy pomocy odpowiednio sformatowanego tekstu, grafiki a nawet elementów multimedialnych. Powoduje to, że strona prezentacji może być dużo atrakcyjniejsza i ciekawsza niż jest to możliwe w tradycyjnych aplikacjach (oczywiście przy odpowiednio dużym nakładzie pracy programista C++ może uzyskać podobne efekty i w zwykłej aplikacji).

Sterowanie aplikacją musi odbywać się z użyciem rozwijanych list wyboru, przełączników i pól edycyjnych. Pojawia się tutaj jednak znacząca różnica w porównaniu z tradycyjnymi programami: jest nią praca sekwencyjna. Użytkownik wprowadza zmiany w atrybutach, a następnie musi zatwierdzić te zmiany przesyłając formularz do serwera i oczekiwać na reakcje systemu. W ogólnym przypadku dostępna jest dużo mniejsza "interakcyjność" systemu. Jednocześnie mamy jednak wyraźnie zdefiniowane fazy działania programu: prezentacja, modyfikacja atrybutów, zatwierdzenie, wykonanie, ponowna prezentacja.

Kolejną cechą aplikacji internetowych jest to, że rzeczywiste zmiany w systemie zachodzą na innym komputerze - maszynie będącej serwerem dla danej aplikacji. Następuje więc naturalne oddzielenie interfejsu od implementacji. Aplikacje internetowe są z definicji sieciowe i umożliwiają równoczesny dostęp wielu użytkownikom. Pojawiają się więc problemy zapewnienia bezpieczeństwa oraz programowania współbieżnego.

Ponieważ protokół HTTP [5] używany w komunikacji pomiędzy klientem, jakim jest przeglądarka WWW, a serwerem jest protokołem bezstanowym, więc aby kolejne strony były właściwą odpowiedzią na żądania klienta, z reguły konieczne jest przechowywanie przez system informacji o stanie klienta. Prawie każda aplikacja internetowa musi więc zapewnić przechowywanie tych informacji po stronie serwera, tak by móc identyfikować klientów i poprawnie reagować na ich akcje. Z użytkownikiem związana zostaje sesja opisująca historie jego działań w systemie, tymczasowe wyniki obliczeń itp.

Większość aplikacji internetowych wykorzystuje w czasie swojego działania bazy danych. Służą one najczęściej do przechowywania informacji o użytkownikach, dokumentach i zasobach, jakie obsługuje dana aplikacja. Trzeba tu wspomnieć, że takie środowiska bazodanowe jak Oracle czy SQLServer posiadają wbudowane narzędzia do generowania aplikacji internetowych operujących na danych zgromadzonych w bazach danych.

2.2 Wymagania stawiane środowiskom tworzenia i działania aplikacji

Specyfika aplikacji internetowych powoduje, że wykazują one duże podobieństwo. Analizując sposób działania większości aplikacji internetowych można odnaleźć następujące wspólne elementy:

...

Naturalną konsekwencją występowania wymienionych podobieństw było pojawienie się narzędzi wspomagających proces tworzenia aplikacji, tak by wyeliminować konieczność wielokrotnego pisania kodu o analogicznej funkcjonalności. ... Chciałbym przedstawić zagadnienia jakie należy rozważyć przy porównywaniu różnych środowisk lub przed podjęciem decyzji o wyborze jednej z dostępnych technologii.

W dalszej części pracy chciałbym omówić wybrane, najpopularniejsze środowiska tworzenia aplikacji internetowych z uwzględnieniem opisanych przeze mnie kryteriów.

2.3. PHP

PHP jest językiem programowania stworzonym specjalnie po to, by umożliwić dynamiczne generowanie stron WWW [8]. Elementy języka PHP zanurza się w kodzie HTML przy pomocy odpowiednich znaczników. W przypadku żądania prezentacji strony stworzonej w PHP, napotkane znaczniki HTML są przekazywane bez zmian, zaś kod należący do języka PHP zostaje przetworzony przez interpreter. PHP posiada typowe cechy języka skryptowego: jest interpretowany a nie kompilowany, nie posiada mechanizmów typowania, dopuszcza brak deklaracji zmiennych.

...

2.4. ASP

Technologię ASP (Active Server Pages) [11] wprowadziła na rynek firma Microsoft jako część projektu Active Platform. Projekt ten miał na celu stworzenie platformy rozwiązań biznesowych umożliwiającej w spójny sposób oprogramowanie zarówno strony klienta, jak i serwera. Najbardziej znane rozwiązanie wywodzące się z tego projektu to formatki ActiveX [12] oraz właśnie ASP. Strona w ASP składa się, podobnie jak to ma miejsce w przypadku PHP, z elementów języka HTML oraz kodu ujętego w odpowiednie znaczniki. W przypadku ASP można używać dwóch języków programowania: VBScript [13] i JScript [14], będących modyfikacjami VisualBasica i Javy. Podczas obsługi żądania klienta kod zawarty na stronie jest interpretowany. Znów mamy więc do czynienia z technologią opartą na interpretowanym języku skryptowym. Opiszę teraz analizowane przeze mnie cechy tego środowiska.

...

2.5. J2EE

Rozszerzenie Javy [17] o nazwie J2EE (Java 2 Extended Edition) [18] zostało opracowane przez firmę Sun Microsystem właśnie z myślą o tworzeniu oprogramowania na potrzeby Internetu. J2EE zawiera w sobie specyfikację takich rozwiązań jak serwlety, JSP i EJB, opisane przeze mnie w kolejnych podrozdziałach. Niektóre właściwości tych technologii są konsekwencją używania Javy jako języka programowania, dlatego cześć z nich opiszę już w tym miejscu.

...

Serwlety

Serwlety [19] są obiektami, które realizują żądania klientów poprzez wykonanie akcji po stronie serwera (stąd pochodzi ich nazwa) i przekazanie strony w HTML jako odpowiedzi. Serwlety są obiektami tworzonymi i zarządzanymi przez kontener serwletów [20]. Zadania kontenera serwletów to przede wszystkim:

...

JSP

O ile technologia serwletów należy do niskopoziomowych rozwiązań, o tyle JSP (Java Server Pages) [22] jest ekwiwalentem takich technologii jak PHP czy ASP. Strona JSP składa się z kodu HMTL, w którym w specjalnych znacznikach umieszczono kod Javy. Taka strona jest następnie automatycznie kompilowana przez serwer aplikacji do odpowiadającego jej funkcjo-nalnie serwletu, który następnie obsługuje żądania klientów. Dzięki temu istnieje możliwość wykrywania błędów już na etapie kompilacji, a ponadto strony JSP są w istocie wykonywane, a nie interpretowane, co wyraźnie wpływa na wzrost wydajności. A oto szczegółowy opis cech tego środowiska.

...

EJB

EJB (Enterprise Java Beans) [25] stanowi rozwinięcie koncepcji obiektów biznesowych opisanej przeze mnie w poprzednim podrozdziale. EJB ma pełnić rolę komponentu, który udostępnia klientowi pewne akcje. Specyfikacja EJB pozwala przed wszystkim na odseparowanie logiki aplikacji od systemu bezpieczeństwa, tworzenie i udostępnianie obiektów klientom i zarządzanie źródłami danych. Siła EJB polega głównie na tym, że wiele zadań jest wykonywanych przez narzędzia obsługujące środowisko działania EJB, a nie przez programistę. Trudno jest mi w zwięzły sposób oddać specyfikę korzystania z technologii EJB, ograniczę się więc tylko do opisu rozważanych przeze mnie kryteriów porównywania.

...

2.6. ASP.NET

Platforma .NET [27] firmy Microsoft, której częścią jest ASP.NET [28], została moim zdaniem stworzona jako odpowiedź na rosnącą popularność środowiska J2EE, o czym mogą świadczyć liczne podobieństwa pomiędzy obiema technologiami. Podstawową zmianą wprowadzoną w ASP.NET w stosunku do ASP było pojawienie się nowego języka programowania C# (choć nadal możliwe jest używanie VisualBasica). C# jest językiem obiektowym bardzo podobnym w swoich założeniach i wyglądzie do Javy. Strony stworzone w nowym ASP nie są już interpretowane, ale kompilowane do MSIL (Microsoft Intermediate Language), który w trakcie działania aplikacji jest zamieniany przez JIT (Just in Time Compiler) na kod wynikowy właściwy dla danej maszyny, co ma znaczący wpływ na poprawę wydajności. A oto podsumowanie możliwości tej platformy.

...

2.7. Turbina

Celem projektu Tubine [1,29] było stworzenie jądra - silnika (ang. engine) aplikacji internetowych. Turbina jest więc czymś więcej niż opisane wcześniej technologie, gdyż ma pełnić rolę szkieletu, na podstawie którego są tworzone aplikacje. W projekcie tym określono: sposób realizacji żądań klienta, podział programu na warstwy, dostęp do baz danych, sposób implementacji globalnych usług. Turbina została stworzona w Javie jako serwlet, posiada więc wszystkie opisane wcześniej zalety tej technologii. Ponieważ dokładnemu opisowi Turbiny poświęcę jeden z następnych rozdziałów, ograniczę się teraz do opisu analizowanych przeze mnie kryteriów.

...

Podsumowanie

Z prezentowanego przeze mnie opisu dostępnych środowisk tworzenia aplikacji internetowych wynika, że w przypadku małych i średnich aplikacji możliwości środowisk są porównywalne. Wybór konkretnej technologii może być podyktowany jej wcześniejszą znajomością przez programistę, czy też jego osobistymi upodobaniami. Ja jestem gorącym zwolennikiem technologii opartych na Javie (JSP, Turbina, Cocoon [32]) i namawiałbym każdego do pracy z użyciem jednego z nich. Jednak w przypadku naprawdę małych aplikacji (licznik, formularz rejestracji itp.) najszybciej pożądany efekt można uzyskać przy pomocy PHP.

ASP.NET i EJB zawierają w sobie rozwiązania, w których zakłada się, że aplikacje internetowe będą tworzone w oparciu o komponenty dostarczane przez różnych producentów, a nawet działające na różnych maszynach (np. w niepowiązanych ze sobą firmach). Nie jestem jednak przekonany, czy to podejście oddaje rzeczywistą potrzebę rynku, czy raczej pozostaje niepotrzebnie obciążającym te technologie wodotryskiem.

We wstępie napisałem, że jednym z celów tej pracy było stwierdzenie przydatności Turbiny w tworzeniu rzeczywistych aplikacji internetowych. Mam nadzieję, że to krótkie porównanie najpopularniejszych technologii pokazało, że Turbina w istocie zawiera wiele cech wymaganych od dobrego środowiska programistycznego i wybór przeze mnie tej technologii był w pełni uzasadniony.

3. Projekt

3.1 Analiza wymagań

WASS (Web Application for Social Sciences) ma być środowiskiem pozwalającym na przeprowadzanie badań psychologicznych i socjologicznych przy użyciu komputera. Metodologia prowadzenia badań w naukach społecznych ma kluczowe znaczenie przy definiowaniu wymagań stawianych temu systemowi, dlatego opiszę w jakim sposób są one realizowane. Typowy eksperyment psychologiczny składa się z następujących części:

Eksperyment w naukach społecznych ma więc modularną budowę. Podstawowym komponentem badania jest kwestionariusz - test (czyli ciąg pytań) wraz z towarzyszącą mu instrukcją. Testy różnią się między sobą sposobem, w jaki formułowane są w nich pytania (zwykły tekst, grafika, seria obrazków) oraz sposobem, w jaki udzielana jest na nie odpowiedź (testy wielokrotnego wyboru, zaznaczanie na skali, odpowiedzi opisowe).

Opisany przeze mnie uproszczony przebieg badania w naukach społecznych wskazuje, że najważniejszą cechą wymaganą od środowiska wspomagającego jego prowadzenie jest możliwość stworzenia biblioteki najczęściej używanych kwestionariuszy. Ponadto badacz powinien móc tworzyć swoje własne nowe kwestionariusze. Oba wymagania sprowadzają się do zaimplementowania sposobu, w jaki będzie można zrealizować najpopularniejsze typy testów (typ testu definiuje właśnie sposób zadawania pytań czy udzielania na nie odpowiedzi). Korzystając ze stworzonej bazy testów, badacz powinien móc konstruować badania, poprzez wybór pożądanych testów.

Niestety nie da się przewidzieć wszystkich zadań, jakie badacz będzie chciał przygotować dla badanego, ponieważ zależą one tylko od kreatywności i pomysłowości naukowca. Rozwiązaniem tego problemu mogłoby być stworzenie metajęzyka lub środowiska graficznego (np. w postaci pasków narzędzi) pozwalającego na oprogramowanie dowolnej interakcji z badanym. Uznałem jednak takie podejście za bezcelowe, gdyż użytkownicy tego systemu (czyli psychologowie czy socjologowie) nie będą zainteresowani opanowaniem takiego pseudo języka programowania. Rozszerzaniem systemu o nowe funkcjonalności powinni się zajmować programiści, którzy wykorzystując dostępne w środowisku podstawowe komponenty i mechanizmy będą mogli zrealizować dowolne pomysły naukowców. System powinien dostarczać programiście gotowe rozwiązania umożliwiające na przykład przechowywanie pytań, odpowiedzi badanych, automatyczne ocenianie, dostęp do plików multimedialnych, czy rejestracji badanych.

Dostęp do kwestionariuszy psychologicznych powinien być możliwy wyłącznie dla osób zawodowo zajmujących się psychologią (tak jak ma to miejsce w przypadku ich papierowych odpowiedników). Obecne zaś w systemie testy stworzone przez naukowców będące efektem ich pracy twórczej nie powinny być widoczne dla innych badaczy. Środowisko musi więc zapewniać ograniczanie dostępu do testów, badań oraz ich wyników.

Wymagania techniczne względem tworzonego środowiska są dużo łatwiejsze do określenia. Ponieważ WASS będzie korzystał z Turbiny, więc możliwe będzie jego uruchomienie na dowolnej platformie, dla której dostępna będzie Java i baza danych. Aplikacja powinna dać się uruchomić na istniejących przy wydziałach nauk społecznych serwerach WWW. Korzystający z systemu naukowcy i potencjalni badani to przede wszystkim użytkownicy Windows, nie ma więc specjalnej potrzeby optymalizacji interfejsu aplikacji dla różnych przeglądarek internetowych, choć oczywiście byłoby to dodatkowym atutem systemu.

3.2. Przypadki użycia

W środowisku można wyróżnić czterech podstawowych aktorów, których opisałem wraz z typowymi dla nich zadaniami.

Badany. Jest użytkownikiem, którego rola ogranicza się głównie do udzielania odpowiedzi na stawiane mu pytania (rysunek 1). Podejmowane przez niego akcje to:

Rysunek 1. Przypadki użycia dla badanego

Badacz. To kluczowy aktor w systemie, który tworzy nowe kwestionariusze i badania oraz analizuje ich wyniki (rysunek 2). Do zadań badacza należą:

Rysunek 2. Przypadki użycia dla badacza

Administrator. Należy do zaawansowanych użytkowników; poza konserwacją systemu, zarządza użytkownikami środowiska i ich uprawnieniami (rysunek 3). Wykonywane przez niego akcje to:

Rysunek 3. Przypadki użycia dla administratora

Projektant. Realizuje pomysły badaczy implementując nowe rodzaje testów. Wiąże się to z tworzeniem i modyfikacją elementów odpowiedzialnych za prezentację danego typu testów badanemu oraz za sposób w jaki się nimi zarządza.

3.3 Podział na moduły

Analiza opisanych przeze mnie przypadków użycia i wymagań stawianych przed systemem pozwala na wyodrębnienie w aplikacji następujących modułów (rysunek 4).

Rysunek 4. Podział na moduły

3.4. Model danych

W tworzonym środowisku kwestionariusze, badania i ich wyniki będą przechowywane w bazie danych. Ponieważ system ma umożliwiać przeprowadzanie różnorakich eksperymentów, konieczne było zaprojektowanie dość złożonej struktury bazy danych (rysunek 5).

Rysunek 5. Model danych

Opis testu pozwalający na jego identyfikacje znajdzie się w tabeli Test, zaś instrukcje wstępne w tabeli Test_Instruction. Z testem powiązane są pytania (elementy tabeli Question), zaś z nimi zbiór dopuszczalnych odpowiedzi przechowywany w tabeli Answer. W niektórych przypadkach znane są poprawne odpowiedzi na zadawane pytania i informacja o tym będzie odnotowana w tabeli Correct_Answer. Opisane tabele powinny pozwolić na przechowywanie w bazie danych dowolnego kwestionariusza począwszy od testu wielokrotnego wyboru, na teście z otwartymi pytaniami kończąc. Niektóre kwestionariusze są do siebie podobne (na przykład testy, w których odpowiada się poprzez wybranie jeden z dwóch odpowiedzi: TAK lub NIE), te podobieństwa zostaną opisane w tabeli Test_Type. Przechowywane w tej tabeli informacje o rodzajach testów posłużą do określenia sposobu, w jaki mają być prezentowane pytania czy też zbierane odpowiedzi.

Całe badanie będzie identyfikowane dzięki atrybutom zawartym w tabeli Research. Zostaną dla niego zdefiniowane instrukcje wstępne (elementy tabeli Research_Instruction) oraz sposób w jaki ma się odbywać rejestracja (Research_Registration). W jednym badaniu będzie można wyróżnić kilka jego wersji, różniących się między sobą na przykład kolejnością testów. Opis wersji badania znajdzie się w tabeli Research_Version, zaś informacja o przy-porządkowaniu do nich właściwych testów zostanie zapisana w tabeli Research_Content.

Przy rozpoczynaniu przez badanego nowego badania zostanie z nim związana sesja (Research_Session), w której znajdą się między innymi dostarczone w czasie rejestracji informacje o użytkowniku. Ponadto sesja pozwoli na identyfikację udzielanych przez badanego odpowiedzi, zapisywanych w tabeli Result.

3.5. System bezpieczeństwa

Dostępny w Turbinie model systemu bezpieczeństwa jest niewystarczający dla celów WASS i konieczne będzie jego rozszerzenie. Projektanci Turbiny stworzyli rozwiązanie oparte na pojęciach użytkownika, roli i prawa. W dystrybucji Turbiny nie są zdefiniowane jawnie żadne prawa - osoby wykorzystujące to narzędzie mogą je dowolnie tworzyć (prawa identyfikowane są poprzez swoją nazwę). Rola jest w Turbinie po prostu nazwanym zbiorem praw. Zostało jeszcze wprowadzone pojęcie grupy, przy czym wyboru nazwy twórcy Turbiny dokonali w niefortunny sposób. Grupa w Turbinie nie oznacza bowiem zbioru użytkowników, lecz pozwala na określenie jakie role są przypisane danemu użytkownikowi. W Turbinie użytkownik pełni jakąś rolę w pewnej grupie, zamiast grupa powinno więc być stosowane określenie domena.

Dostarczona w Turbinie implementacja systemu bezpieczeństwa pozwala na stwierdzenie w wygodny sposób, czy dany użytkownik posiada wymagane prawo w jakiejś grupie. Wspierany model systemu bezpieczeństwa jest wystarczający w aplikacji, w której kontroli podlegają konkretne działania klientów (na przykład ogranicza się dostęp do ekranu z listą użytkowników, czy akcji dodającej nowego użytkownika). Nie można go jednak zastosować w sytuacji, gdy konieczne jest ograniczenie dostępu do konkretnych zasobów, a taka potrzeba istnieje w przypadku aplikacji WASS (na przykład tylko właściciel powinien móc modyfikować swoje badanie).

W Turbinie przewidziano możliwość zaimplementowania własnej wersji serwisu odpowiadającego za system bezpieczeństwa, niestety wprowadzenie do niego nowej funkcjonalności (niedostępnej w standardowym API) nie jest wygodne, ponieważ wiąże się z koniecznością ciągłego rzutowania.

Dlatego postanowiłem wprowadzić rozwiązanie hybrydowe i tam gdzie to możliwe korzystać z dostępnego systemu bezpieczeństwa. Wystarcza on na przykład w zupełności do zapewnienia, by z modułu do zarządzania kontami badaczy mógł korzystać tylko administrator. W przypadku potrzeby ograniczenia dostępności jakiegoś zasobu wykorzystywane będą informacje powiązane z danym zasobem (np. testem czy badaniem) poprzez tabelę Security. Tabela ta będzie wiązać role użytkowników z zasobami systemu. Rysunek 6 prezentuje model danych odpowiadający opisanemu przeze mnie rozwiązaniu.

Rysunek 6. Tabele systemu bezpieczeństwa

4. Architektura Turbiny

Stworzona przeze mnie aplikacja powstała przy użyciu Turbiny, dlatego zanim przedstawię sposób implementacji WASS, chciałem lepiej opisać to narzędzie.

Ponieważ Turbina jest serwletem Javy, więc aby mógł powstać funkcjonalny system, potrzebne są dodatkowe komponenty, takie jak maszyna wirtualna Javy, kontener serwletów, czy baza danych. Miejsce w systemie Turbiny i aplikacji stworzonej przy jej pomocy schematycznie przedstawiłem na rysunku 7, gdzie nakładanie się elementów oznacza ich interakcje.

Rysunek 7. Miejsce Turbiny w systemie

Oto opis znaczenia i roli przedstawionych elementów:

4.1. Metodologia MVC

Korzystanie ze stron WWW jako interfejsu graficznego aplikacji powoduje, że w interakcji użytkownik - program pojawiają się dobrze zdefiniowane fazy:

W Turbinie tym fazom działania aplikacji zostały przyporządkowane różne elementy. Wprowadzone zostało pojęcie akcji (ang. action), obiektu dziedziczącego po klasie Action, która ma odpowiadać za realizację żądanych przez użytkownika zmian w systemie. Ekran (ang. screen), obiekt dziedziczący po klasie Screen, ma zaś prezentować stan systemu poprzez wygenerowanie odpowiedzi dla klienta - czyli najczęściej fragmentu kodu HTML. Dzięki istnieniu tych dwóch elementów, aplikacje tworzone w Turbinie są bardziej przejrzyste niż odpowiadające im strony JSP. W przypadku JSP programista najczęściej umieszcza na stronie formularz z ukrytym polem wskazującym, że ma zostać wykonana jakaś akcja. W kodzie odpowiedzialnym za wygenerowanie żądanej strony, umieszcza się ciąg instrukcji if-else, które sprawdzają przesłaną wartość tego ukrytego pola i przekazują sterowanie do miejsca realizującego wskazaną akcję, a dopiero potem następuje przetwarzanie kodu odpowiedzialnego za prezentację stanu systemu.

Akcje kontrolują stan systemu, a ekrany odpowiadają za prezentację. Zostały więc zdefiniowane dwa elementy modelu MVC (Model View Controller): kontroler i widok. Trzecim elementem - modelem - w przypadku aplikacji internetowej są dane opisujące stan systemu, a więc przede wszystkim te zgromadzone w bazie danych i w sesjach użytkowników. W przypadku Turbiny modelowi odpowiadają równoważniki (ang. peer), czyli obiektowe reprezentacje tabel oraz ich elementów. Na rysunku 8 przedstawiłem schematycznie realizację modelu MVC w przypadku Turbiny.

Rysunek 8. Model MVC

Wydaje się, że zgodność architektury Turbiny z metodologią MVC jest raczej konsekwencją wyróżnienia akcji i ekranów, niż wynikiem świadomej decyzji projektantów. Opiszę teraz dokładniej komponenty składające się na model MVC.

4.1.1 Model

Modelem są te elementy aplikacji, które mają wpływ na stan systemu. Niewątpliwie podstawowy wpływ na działanie aplikacji ma konfiguracja środowiska. Niestety w Turbinie jest ona tylko statyczna i odbywa się poprzez edycję pliku konfiguracyjnego. Dostęp do wartości atrybutów w czasie działania aplikacji umożliwia klasa TurbineResources.

Kolejnym miejscem przechowywania informacji o stanie systemu jest sesja użytkownika. Z użytkownikiem można związać nie tylko ulotne dane (tzn. dostępne do czasu wygaśnięcia sesji), ale również i takie, które będą automatycznie przechowywane przez Turbinę w bazie danych. Dostęp do obu rodzajów danych odbywa się na zasadzie słownika.

Najważniejszym elementem modelu są dane zgromadzone w bazach danych. W Turbinie dostęp do nich odbywa się poprzez ich obiektową reprezentację. Zdefiniowane zostały trzy podstawowe klasy obiektów: Peer, Critieria, BaseObject. Równoważnik (ang. peer) ma być widokiem tabeli z bazy danych, zawiera więc informacje o kolumnach i ich typie oraz pozwala na wykonywanie operacji na tabeli, takich jak wstawianie, usuwanie i wyszukiwanie danych. Przy wykonywaniu tych operacji można korzystać z języka SQL, ale zalecaną metodą jest używanie obiektowej reprezentacji zapytania SQL, jaką jest Criteria. Wynikiem zapytania dotyczącego danej tabeli jest lista sepulek - obiektów dziedziczących po klasie BaseObject i mających atrybuty odpowiadające kolumnom tabeli. Bardziej szczegółowemu opisowi dostępu do baz danych poświęcę jeden z następnych podrozdziałów.

4.1.2. Widok

Podstawowym elementem widoku są ekrany. W uproszczeniu, zadaniem programisty jest stworzenie klasy dziedziczącej po klasie Screen oraz metody generującej napis odpowiadający pożądanemu kodowi w HTML. Tworzenie aplikacji w ten sposób, choć zgodne z metodologią MVC nie pozwalałoby na rozdzielenie kodu logiki aplikacji od kodu w HTML-u.

Zalecane rozwiązanie polega na tworzeniu ekranów składających się z dwóch części: z obiektu Javy pobierającego informacje o stanie systemu i szablonu opisującego sposób ich prezentacji. Używa się bowiem w Turbinie jeszcze jednego elementu pośredniczącego - narzędzia renderującego (ang. template engine); może nim być Velocity, Webmacro, czy nawet JSP. Zadaniem tego elementu jest jak najlepsze odseparowanie kodu Javy od kodu części wizualnej strony. Do zadań obiektu implementującego ekran dziedziczący po klasie właściwej dla danego narzędzia (np. VelocityScreen) należą:

Następnie środowisko Turbiny uruchomi narzędzie renderujące, które na podstawie treści szablonu (głównie kod HTML) oraz obiektów przechowywanych w kontekście wygeneruje właściwy fragment strony WWW.

Narzędzia renderujące dopuszczają w szablonie - poza kodem HTML - właściwie tylko wywołania metod obiektów pobranych z kontekstów i rzutowanie ich wyników na napisy. Ograniczenie dostępnych w szablonie konstrukcji powoduje, że jego edycją mogą zajmować się webmasterzy, a nie programiści. Dzięki temu praca osób odpowiedzialnych za wygląd aplikacji może odbywać się niezależnie od pracy programistów. Velocity zostanie opisane dokładniej w jednym z następnych rozdziałów.

4.1.3. Kontroler

Zadaniem kontrolera jest reagowanie na życzenia użytkownika poprzez wykonywanie zmian w systemu. W Turbinie odbywa się to poprzez wywołanie właściwej akcji, czyli klasy dziedziczącej po Action i przeciążającą metodę doPerform zgodnie z logiką aplikacji. Aby zwiększyć podobieństwo do klasycznych aplikacji w modelu MVC, wprowadzono pewien odpowiednik sterowania poprzez zdarzenia (ang. action event).

Jeśli uzna się formularz na stronie WWW za komponent, to naciśnięcia przycisków go zatwierdzających mogą być traktowane jako zdarzenia. Możliwe jest związanie z formularzem tylko jednej akcji, posiadającej zestaw metod odpowiadających tym zdarzeniom (rozpoznawanym po nazwach przycisków). Podstawową korzyścią z takiego podejścia, jest zebranie metod obsługujących daną stronę czy formularz w jednym miejscu, przez co kod i budowa aplikacji stają się bardziej przejrzyste.

Choć akcje powinny zmieniać stan samego systemu, możliwa jest interakcja pomiędzy akcją a następującym po niej ekranem. Akcja może bowiem umieszczać obiekty w kontekście (a więc będą one dostępne w czasie renderowania strony WWW) oraz zmieniać ekran, jaki ma się pojawiać. Należy jednak bardzo ostrożnie korzystać z tych rozwiązań, ponieważ ich obecność zmniejsza czytelność kodu aplikacji.

4.2. Model logiczny

Podstawowym elementem zarządzającym przepływem sterowania i generowaniem odpowiedzi jest strona (ang. page). Klasa implementująca stronę jest jedna dla całej aplikacji. W większości zastosowań wystarcza użycie dostarczonej wraz z dystrybucją, domyślnej implementacji (DefaultPage). Ewentualne rozszerzenia tego obiektu pozwalają na realizację akcji związanych z obsługą każdego żądania - jako przykład może posłużyć dodanie rejestracji statystyk odwiedzin poszczególnych ekranów.

Kolejnym pojęciem wprowadzonym przez projektantów Turbiny jest układ (ang. layout). W dobrze zaprojektowanym portalu, wygląd kolejnych stron dotyczących tej samej usługi czy tematu jest bardzo podobny. Na kolejnych stronach użytkownik może odnaleźć w tym samym miejscu pasek tytułu, menu, reklamy, czy formularz wyszukiwania, dzięki czemu nie musi za każdym razem na nowo analizować budowy strony. Na tym właśnie polega rola układu, organizuje on kolejne komponenty na stronie, zapewniając grupie stron podobny wygląd.

Rysunek 9.Model logiczny

Ta część stron, która ulega zmianom i która jest odpowiedzialna za zapewnienie specyficznej logiki biznesowej aplikacji, to opisany już ekran. Elementy pojawiające się na wielu stronach to nawigacje (ang. navigations). Układ zależy od klasy go implementującej (nie ma właściwie potrzeby tworzenia własnych) oraz od szablonu opisującego położenie komponentów na stronie. W szablonie zostaje wskazane miejsca, gdzie mają zostać wyświetlone zawartości nawigacji oraz ekranu.

Nawigacja i ekran są do siebie bardzo podobne i zostały wyróżnione tylko ze względu na rolę jaką pełnią na stronach, ponieważ jak już wspominałem te same nawigacje mogą pojawiać się na wielu stronach, zaś ekran powinien odpowiadać jednej stronie o określonej funkcjonalności. Oba elementy są realizowane poprzez klas, których zadanie sprowadza się do uzupełnienia kontekstu właściwymi obiektami oraz z szablonów opisujących ich wygląd. Jedyne różnice pomiędzy ekranem a nawigacją są takie, że na stronie może znajdować się tylko jeden ekran, ale wiele nawigacji oraz, że dla nawigacji nie ma wsparcia ze strony systemu bezpieczeństwa. Wzajemne relacje opisanych elementów przedstawia rysunek 9.

Nie będę opisywał dalszych pojęć wprowadzonych przez twórców Turbiny, takich jak na przykład Factories czy Loaders, ani sposobu wiązania szablonów układu z właściwą stroną, ponieważ nie są one istotne dla zrozumienia budowy mojej aplikacji.

4.3. Obsługa żądania

4.3.1. Interpretacja adresu URL

Poprawne działanie aplikacji wymaga identyfikacji akcji, która ma być wykonana i ekranu, który ma zostać wyświetlony w odpowiedzi na żądanie klienta. Żądanie przesłane Turbinie składa się z informacji pochodzących z dwóch źródeł: adresu URL i wartości pól formularza.

Na przykładzie adresu :
http://msc.pl/bad/template/admin,Edit.vm/action/admin.Clear/id/1/cmd/a
opiszę sposób, w jaki adresy URL są interpretowane przez Turbinę.

Początek adresu wskazuje na serwer HTTP i ewentualnie aplikację (http://msc.pl/bad) i jest istotny z punktu widzenia wspomnianego serwera HTTP i ewentualnie kontenera serwletów.

Następny fragment: template/admin,Edit.vm, wskazuje na ekran, jaki ma zostać wyświetlony przez Turbinę - w tym przypadku jest to ekran Edit.vm z podkatalogu admin. Jeśli parametr template wskazuje na ekran, który jest szablonem, to Turbina spróbuje odnaleźć dla niego klasę implementującą (admin.Edit w naszym przykładzie), a w przypadku jej braku zastosuje domyślną klasę dla danego typu szablonów (np. VelocityScreen).

Kolejna część adresu, action/admin.Clear, identyfikuje akcję jaką należy wykonać przed przystąpieniem do generowania odpowiedzi. W naszym przykładzie tą akcją jest obiekt klasy Clear z pakietu admin. W URL poza wskazaniem akcji i ekranu może wystąpić jeszcze ciąg parametrów, zakodowanych jako KLUCZ/WARTOŚĆ. W przykładowym adresie przekazane zostały dwa parametry: id o wartości 1 i cmd o wartości a. Turbina w taki sam sposób traktuje parametry przekazane jako części adresu URL i te pochodzące z formularza. Wartości parametrów odczytuje się poprzez obiekt RunData przy użyciu jego metod getString(NAZWA), getInt(NAZWA) itp.

4.3.2 Przepływ sterowania

Opiszę teraz jak system reaguje na przesłane przykładowe żądanie o adresie:
http://msc.pl/bad/template/admin,Edit.vm/action/admin.Clear/id/1/cmd/a.

Kontener serwletów sprawdza, że kontekst bad odpowiada aplikacji z jakiegoś katalogu (np. właśnie bad) i że dotyczy serwletu Turbiny. Wywołana zostaje metoda doGet Turbiny z parametrem opisującym to żądanie (HttpServletRequest).

W metodzie doGet tworzony jest obiekt klasy RunData, który poza dostępem do parametrów przechowuje między innymi informacje o generowanej stronie, połączeniu z bazą danych, sesji i użytkowniku. Następnie sprawdza się czy akcja, którą należy wykonać, nie została zdefiniowana jako akcja logująca (poprzez odpowiedni wpis w pliku konfiguracyjnym). Jeśli tak, to uruchamia się ją, by podczas dalszej pracy były dostępne atrybuty użytkownika (w naszym przypadku akcja admin.Clear jest zwykłą akcją). Następnie Turbina sprawdza poprawność sesji użytkownika (SessionValidator) i tworzy opis uprawnień użytkownika - ACL (Access Control List). Jeśli oba działania zakończą się sukcesem, to odnajduje się klasę implementującą stronę i przekazuje do niej sterowanie poprzez wywołanie metody doBuild. Przedstawia to rysunek 10.

Rysunek 10. Przepływ sterowania I

Opiszę sposób działania strony na podstawie klasy DefaultPage. W metodzie doBuild tej klasy zostaje stworzony obiekt odpowiadający akcji, którą należy wykonać (w naszym przykładzie będzie to klasa admin.Clear), a następnie wywołuje się jego metodę doBuild. Akcja realizuje cel wyznaczony jej przez programistę i sterowanie wraca do strony. Strona pobiera obiekt klasy odpowiedzialnej za wygenerowanie ekranu (admin.Edit) i uzyskuje od niego nazwę układu, jaki ma być użyty. Strona przekazuje sterowanie do właściwego układu.

W obiekcie układu następuje analiza szablonu definiującego rodzaj i położenie elementów na stronie. Po napotkaniu elementu odpowiadającego nawigacji, zostaje odnaleziona właściwa dla niej klasa i wołana jest jej metoda doBuild. Podobnie dzieje się w miejscu wystąpienia ekranu. Zobrazowałem to na rysunku 11. Nawigacje i ekran w czasie swojego działania dopisują do przekazanego im obiektu RunData wygenerowane fragmenty kodu HTML.

Rysunek 11. Przepływ sterowania II

Sterowanie wraca wreszcie do strony, a następnie do Turbiny, która przepisuje wygenerowaną odpowiedź z obiektu RunData na obiekt HttpServletResponse. W tym krótkim opisie pominąłem lub uprościłem sposób odnajdowania, ładowania i przetwarzania klas implementujących akcje, ekrany i nawigacje, by pokazać tylko kluczowe etapy prowadzące do powstania wynikowej strony HTML.

4.4. Serwisy

Do poprawnego i wydajnego działania aplikacji często trzeba stworzyć globalnie dostępne elementy. Najbardziej charakterystycznymi przykładami takich elementów są pula połączeń (ang. connection pool) czy globalne bufory (ang. global cache). Wydaje się, że optymalną implementacją tych funkcjonalności jest pojedyncza instancja, inicjowana podczas startu Turbiny. Używany w wielu miejscach aplikacji "narzędziowy" kod warto umieścić w takim ciągle aktywnym obiekcie, by nie obciążać niepotrzebnie procesora powtarzającym się ładowaniem i inicjowaniem instancji jakiejś klasy.

Turbina oferują jednolite rozwiązanie tego zagadnienia w postaci serwisów (ang. services). Serwisy inicjowane są dopiero w chwili ich pierwszego użycia, wykrywane są przy tym wzajemne, cykliczne odwołania pomiędzy serwisami. Turbina informuje serwisy o kończeniu pracy, dzięki czemu mogą one zwolnić lub serializować używane zasoby. W Turbinie większość dostępnych usług zaimplementowano właśnie jako serwisy. A oto niektóre z nich:

4.5. Dostęp do danych

W dobrze zaprojektowanej aplikacji pomiędzy bazą danych a elementami z niej korzystającymi znajduje się dodatkowa warstwa pośrednicząca. Celem tej warstwy jest zebranie w jednym miejscu zapytań wyrażonych w SQL, tak by w razie modyfikacji struktury bazy danych możliwa była łatwa zmiana zależnego od niej kodu. Poza tą podstawową rolą często w tej warstwie implementuje się dodatkowe funkcjonalności zwiększające wydajność systemu, jak na przykład bufory do przekazywanych wyników zapytań.

W Turbinie znajduje się narzędzie służące do generacji takiej warstwy pośredniczącej; jest nim Torque. Torque na podstawie XMLowego opisu struktury bazy danych generuje kod SQL tworzący daną bazę (z uwzględnieniem specyfiki produktu) oraz wspomniane wcześniej obiektowe reprezentacje tabel i ich elementów (równoważniki i sepulki).

Opis przykładowej tabeli może wyglądać następująco:

 <table name="Test_Instruction" idMethod="autoincrement">
  <column name="id" required="true" autoIncrement="true" primaryKey="true" type="INTEGER"/>
  <column name="test_id" required="true" type="INTEGER"/>
  <column name="text" required="false" type="LONGVARCHAR"/>
  <foreign-key foreignTable="Test">
   <reference local="test_id" foreign="id"/>
  </foreign-key>
  <index name="index1">
   <index-column name="test_id"/>
  </index>
 </table>

Ten fragment kodu XML definiuje tabelę o nazwie Test_Instruction o następujących kolumnach: id, test_id i text. Na jego podstawie zostaje wygenerowany następujący kod SQL (dla bazy MySQL):

 CREATE TABLE Test_Instruction(
 id INTEGER NOT NULL AUTO_INCREMENT,
 test_id INTEGER NOT NULL,
 text MEDIUMTEXT,
 PRIMARY KEY(id),
 FOREIGN KEY (test_id) REFERENCES Test (id),
 INDEX index1 (test_id));

Torque tworzy również klasę TestInstructionPeer (dziedziczącą po klasie BasePeer), która pozwala na wykonywanie operacji na tej tabeli, dzięki udostępnieniu takich metod jak doSelect, doDelete, doInsert, doUpdate. Wynikiem instrukcji doSelect jest lista obiektów wygenerowanej klasy TestInstruction (dziedziczącej po klasie BaseObject) o metodach:

Na podstawie tego prostego przykładu można już zaobserwować podstawowe korzyści wynikające z użycia tego narzędzia:

Potrzebna jest również implementacja obiektowej reprezentacji samego zapytania, w przeciwnym bowiem przypadku, przy każdym wywołaniu metody doSelect konieczne byłoby wprowadzanie treści instrukcji select, co podważałoby sens istnienia całej warstwy. Tą obiektową reprezentacją instrukcji select są obiekty klasy Criteria. Można przy ich pomocy definiować kolejne warunki jakie mają być spełnione przez wyniki zapytania. Definiowanie warunków odbywa się z użyciem takich metod jak:

Nazwy kolumn powinny być odczytywane ze stałych zdefiniowanych w równoważniku danej tabeli. W naszym przykładzie kod, który wybiera instrukcje należące do testu pierwszego, może mieć postać:

 Criteria cr = new Criteria();
 cr.add(TestInstructionPeer.TEST_ID,1);
 cr.addAscendingOrderByColumn(TestInstructionPeer.SEQUENCE);
 List result=TestInstructionPeer.doSelect(cr);

Nie wszystko da się wyrazić przy pomocy obiektów klasy Criteria (lub nie zawsze jest to wygodne) - w takich sytuacjach można jako parametr metody doSelect przekazać napis będący instrukcją SQL. Czasem pojawia się potrzeba dodania dodatkowych metod do obiektów wygenerowanych przez Torque. Dlatego Torque generuje zawsze dwie klasy - w naszym przypadku byłyby to klasy: BaseTestInstruction i TestInstruction. Programista może dodawać metody do tej drugiej (która oryginalnie tylko dziedziczy po klasie BaseTestInstruction) i nie zostaną one utracone przy ponownym generowaniu klas (bo wygenerowana zostanie tylko klasa BaseTestInstruction).

Podstawową korzyścią wynikającą z używania Torque jest szybkość, z jaką może powstać prototyp aplikacji. Najważniejsze obiekty biznesowe (te przechowywane w bazie danych) są dostępne już w początkowej fazie tworzenia aplikacji, a przy ich pomocy można wygenerować szkielet aplikacji, który następnie uzupełnia się o coraz to nowe funkcjonalności.

4.6. Velocity

Velocity jest narzędziem służącym do generowania stron w HTML na podstawie dostarczonego szablonu. Projekt Velocity jest niezależny od Turbiny. Wykorzystywanie go w aplikacjach opartych na Turbinie jest tylko jednym z zastosowań tego narzędzia.

Szablon w Velocity składa się głównie z kodu w HTML. Zbiór dostępnych instrukcji jest bardzo ograniczony - ma on pozwalać na wygodne renderowanie stron WWW, a nie wykonywanie złożonych operacji. Oto lista podstawowych elementów języka:

Te elementy szablonów Velocity wystarczają w zupełności do stworzenia dowolnego ekranu korzystającego z informacji umieszczonych w kontekście. W przypadku wystąpienia błędów w szablonie informacje o nich zostają umieszczone w dzienniku zdarzeń tak, że możliwe jest określenie miejsc i przyczyn ich wystąpienia.

4.7. Podsumowanie

Mam nadzieję, że ten pobieżny opis Turbiny wystarcza do zrozumienia sposobu w jaki zaimplementowałem moją aplikację oraz pozwala na samodzielne tworzenie aplikacji z wykorzystaniem Turbiny.

5. Implementacja

5.1. Zastosowane technologie

Podstawowym narzędziem koniecznym do powstania WASS była oczywiście Turbina. W momencie powstawania tej pracy oficjalną dystrybucją Turbiny była jej wersja 2.0. Oprócz niej w sieci dostępna była również dopiero rozwijana wersja 3.0 Turbiny. Jako podstawę mojej aplikacji wybrałem wersję 2.0 z następujących powodów:

Używaną przeze mnie maszyną wirtualną Javy była wersja JDK 1.3.0. Jako kontener serwletów posłużył darmowy i dostępny wraz z dystrybucją Turbiny Tomcat. Pełnił on również funkcję serwera HTTP, choć nie ma żadnych przeciwwskazań, by wykorzystać w tym celu serwer Apache [33].

Jako narzędzie do renderowania stron zostało użyte Velocity, które oferuje możliwości wystarczające na potrzeby tej aplikacji. Wygląd generowanych stron oparty jest na stylach kaskadowych (CSS) [34], powinny więc być one poprawnie prezentowane przez większość przeglądarek.

Rolę serwera baz danych powierzyłem MySQL [35], którego dystrybucje są dostępne są na platformę Windows i Linux. Ta darmowa baza danych jest najprostsza, a dzięki temu bardzo wydajna, zaś analizując projekt mojej aplikacji nie widziałem potrzeby stosowania bardziej rozbudowanych silników bazodanowych (głównym ograniczeniem MySQL jest brak zagnieżdżonych zapytań SQL oraz więzów integralności). Ponadto śledząc listę dyskusyjną Turbiny nie spotkałem się z żadnymi doniesieniami na temat problemów w czasie integracji Turbiny z tym serwerem bazodanowym.

5.2. Architektura aplikacji

Aplikacje internetowe tworzone z wykorzystaniem Turbiny można podzielić na dwie grupy:

Analizując wymagania stawiane systemowi WASS nie widziałem potrzeby tworzenia własnego jądra (silnika) aplikacji. Wymagane funkcjonalności doskonale pasują do architektury opartej na ekranach prezentujących dane i akcjach dokonujących zmian w systemie.

Dlatego WASS składa się głównie z klas implementujących ekrany i akcje w sposób pozwalający na realizację stawianych przed systemem celów. Konsekwencją takiego podejścia jest jednak pewne "rozproszenie" aplikacji, bowiem zarówno ekrany, jak i akcje są między sobą słabo powiązane. Ponadto wyróżnione w projekcie moduły nie przekładają się na niezależne fragmenty kodu. I tak na przykład elementy modułu odpowiedzialne za system bezpieczeństwa znajdować się muszą w każdej klasie implementującej ekran czy akcję.

W kolejnych rozdziałach opiszę sposób w jaki zostały zrealizowane funkcje poszczególnych modułów aplikacji.

5.3. Moduł Security

Zdefiniowałem następujące prawa: czytanie, pisanie, usuwanie i wykonywanie, oraz stworzyłem na ich podstawie role: właściciel, pisarz, czytelnik i wykonujący. Te role przypisuje się użytkownikowi w kontekście konkretnych badań, testów czy półek. Ponadto zostały zdefiniowane globalne role administratora, badacza i badanego (rysunki 12 i 13). Służą one do kontroli dostępu na poziomie operacji.

Rysunek 12. Role i prawa w systemie

Model danych dla modułu Security jest zgodny z opisanym w projekcie aplikacji. Ponieważ identyfikatory dla testu i badania mogą przyjmować te same wartości (są to klucze pochodzące z różnych tabel), stworzyłem dodatkową tabelę security_obj, która umożliwia jednoznaczne wiązanie tych elementów z opisem uprawnień przechowywanym w tabeli security.

Rysunek 13. Przykład przypisania ról w aplikacji

W sepulce odpowiadającej tabeli security_obj, zaimplementowałem metody umożliwiające pobranie informacji o posiadanych przez użytkownika rolach i prawach. Dzięki temu, nie musiałem powtarzać tego samego kodu w klasach odpowiadających badaniu i testowi, lecz mogłem odwoływać się do metod powiązanych z nimi obiektów klasy SecurityObj. Kontrola dostępu na poziomie operacji odbywa się z wykorzystaniem obiektu ACL dostarczonego przez twórców Turbiny.

W klasach bazowych dla akcji i ekranów (są to MScAction i MScScreen) zaimplementowałem następujący schemat przebiegu autoryzacji:

 pobierz z sesji obiekt użytkownika;
 jeśli brak obiektu użytkownika, to przejdź do ekranu logowania;
 pobierz obiekt ACL dla użytkownika;
 jeśli brak obiektu ACL, to przejdź do ekranu logowania;
 pobierz wymagane prawo; /* metoda getPermission */
 pobierz zasób; /* metoda getSecurityObject */
 jeśli użytkownik posiada prawo w obiekcie ACL, to wykonaj akcje, wyświetl ekran;
 jeśli zasób jest różny od NULL, to
 {
  jeśli użytkownik posiada prawo do danego zasobu, to wykonaj akcje, wyświetl ekran;
 }
 przejdź do ekranu błędu dostępu;

W podklasach MScAction czy MScScreen wystarczy przeciążyć metodę getPermission (powinna ona przekazywać nazwę prawa wymaganego w danej akcji lub ekranie) oraz metodę getSecurityObject (przekazującą zasób, którego ma dotyczyć operacja).

5.4. Moduł Storage

Moduł ten ma umożliwiać umieszczanie plików multimedialnych w badaniach. Zdecydowałem się na przechowywanie plików na dysku, a nie w bazie danych. Rozwiązanie z plikami jest dużo prostsze i wydajniejsze niż to wykorzystujące bazę danych. Plik zostaje tylko opisany w bazie danych i skopiowany do odpowiedniego katalogu w poddrzewie aplikacji, a w przypadku odwołania do niego na podstawie informacji zapisanych w bazie danych zostaje odtworzona ścieżka do pliku i przedstawiona jako adres URL.

Operacje związane z modułem Storage (dodawanie i usuwanie plików, pobieranie odpowiadającym im adresów URL) odbywają się poprzez serwis MScStorage. Pliki są opisane w tabeli Item. Badacze mogą korzystać z niezależnych zbiorów plików w systemie, dzięki tabeli Shelf, która umożliwia tworzenie wirtualnych katalogów z zasobami (półek). Administracja plikami odbywa się z wykorzystaniem ekranów i akcji z pakietu admin.storage. Sposób udostępniania plików został zaprezentowany na rysunku 14.

Rysunek 14. Moduł Storage

Z przedstawionym rozwiązaniem wiąże się jednak ryzyko, że osoba nieupoważniona pozna treść zgromadzonych plików multimedialnych. Dostęp do plików odbywa się poprzez serwer HTTP, można więc wyobrazić sobie sytuacje, w której ktoś generuje kolejne nazwy zasobów, by w ten sposób odczytać wszystkie zgromadzone pliki. Nie stanowi to jednak naruszenia zasad bezpieczeństwa systemu, gdyż nie można w ten sposób, ani usunąć ani zmodyfikować przechowywanych zasobów.

Gdyby w przyszłości, zaistniała potrzeba ochrony treści plików mutlimedialnych (np. z powodu wagi zawartych w nich informacji lub ochrony praw autorskich), możliwe będzie stworzenie serwletu, który będzie obsługiwał żądania do zasobów. Jako serwlet będzie miał dostęp do tej samej sesji użytkownika co instancja Turbiny i dzięki zapisanym w niej informacjom będzie przekazywać tylko te pliki, do których użytkownik ma dostęp.

5.5. Moduł User

Moduł ten zawiera w sobie elementy odpowiedzialne za przeprowadzenie badania. Oparty jest głównie na ekranach i akcjach z pakietu user (pakiet ten zawiera dwa podpakiety test i admin, grupujące klasy zależne odpowiednio od testów i badań). Po wybraniu badania, w którym użytkownik chce wziąć udział i ewentualnej rejestracji, z klientem zostaje związany obiekt ResearchSession, który przechowuje między innymi opis badanego i stan samego badania (częściowe wyniki, bieżący test itp.). Stworzona sesja jest wykorzystywana przez wszystkie ekrany i akcje aż do zakończenia badania.

To jakie szablony i klasy zostaną użyte przy prezentacji zadań czy zbieraniu odpowiedzi, zależy od atrybutów rodzaju testu powiązanego z danym testem. Rysunek 15 prezentuje sposób nawigacji badanego w systemie. Nie będę wymieniał wszystkich zaimplementowanych ekranów i akcji należących do tego modułu, przynależą one do pakietów msc.modules.actions.user oraz msc.modules.screens.user i są dobrze opisane w załączonej na płycie dokumentacji wygenerowanej z użyciem Javadoc.

Rysunek 15. Sposób nawigacji w czasie badania

5.6. Moduł Admin Test

W module tym zostały zebrane akcje i ekrany pozwalające na definiowanie treści zadań Zostały one przypisane do pakietów msc.modules.actions.admin.test i msc.modul-es.screens.admin.test. Kluczowymi ekranami dla tego modułu są EditTestQuestions i EditQuestion. Pierwszy ekran pozwala na definiowanie przynależnych do testu pytań i ich kolejności, drugi zaś umożliwia modyfikację pytania i przypisanych do niego odpowiedzi. W opisie rodzaju testu można zdefiniować dla obu ekranów szablony inne niż domyślne (takie, które pozwalają na wprowadzenie danych w sposób charakterystyczny dla danego zadania), można również podać inne klasy implementujące wspomniane ekrany. W większości przypadków różnice pomiędzy rodzajami testów sprowadzać się będą do zmian sposobu ich prezentacji, dlatego wystarczy stworzyć nowe szablony edycyjne dla testu i jego pytań, a następnie opisać je w definicji typu testu. Opis wszystkich klas z przynależnych do modułu pakietów znajduje się w załączonej dokumentacji technicznej. Rysunek 16 przedstawia schemat nawigacji po tej części aplikacji.

Rysunek 16. Nawigacja w czasie administracji testami

5.7. Moduł Admin Research

Klasy implementujące zarządzanie badaniami umieściłem w pakietach msc.modu-les.actions.admin.research i msc.modules.screens.admin.research. Nie przewiduję potrzeby modyfikowania tej części aplikacji. Wszystkie badania powinny być komponowane w ten sam sposób, a różnice pomiędzy nimi muszą dać się wyrazić poprzez dobór odpowiednich testów. Sposób nawigacji po tej części aplikacji schematycznie prezentuje rysunek 17.

Rysunek 17. Nawigacja w czasie administracji badaniami

5.8. Moduł Admin Process

Klasy z pakietów msc.modules.actions.admin.process i msc.modules.scre-ens.admin.process odpowiadają za przetwarzanie zgromadzonych odpowiedzi badanych i ich prezentacje w pożądanej przez badacza postaci. Badacz oczekuje wyników w formie tabeli, w której kolumny odpowiadają wynikom jednego pytania, zaś wiersze są rezultatami kolejnych badanych osób.

W przypadku implementacji poprzednio opisanych zadań, struktura bazy danych w trzeciej postaci normalnej nie wywoływała wzrostu nakładów pracy podczas programowania. W tym jednak module, sposób przechowywania w bazie danych informacji o odpowiedziach nie daje się łatwo przełożyć na formę wymaganą przez badacza. W bazie danych znajdują się bowiem rekordy opisywane sesją, pytaniem i kontenerem testu (ponieważ test może wystąpić kilka razy w tym samym badaniu). Transformacji wyników do wymaganej postaci tabeli nie da się dokonać w oparciu o proste zapytania SQL, dlatego konieczne było zaimplementowanie jej w postaci kodu Javy. W klasie BaseProcessResult zaimplementowałem następujący algorytm przetwarzający wyniki:

 pobierz wersje badania;
 dla każdej wersji;
 {
  pobierz sesje, które do niej należą (i są np. poprawnie zakończone);
  stwórz słownik, w którym kluczami są sesje a wartościami listy wyników;
  pobierz testy należące do wersji i ustaw je według ich kolejności w badaniu;
  dla każdego testu;
  {
   pobierz pytania testu i ustaw je według ich kolejności w teście;
   dla każdego pytania;
   {
     pobierz odpowiedzi na to pytanie należące do wybranych sesji i posortuj je według sesji;
     przeglądaj odpowiedzi dodając wyniki do listy ze słownika dla danej sesji (brakujące wyniki uzupełniaj pustymi);
   }
  }
 }

W wyniku działania tego algorytmu dla każdej wersji badania powstaje słownik z listami wyników poszczególnych osób (ewentualnie uzupełnionymi pustymi wpisami, dzięki czemu kolejne elementy list odpowiadają tym samym pytaniom dla wszystkich osób). Na podstawie takiej reprezentacji odpowiedzi badanych w łatwy sposób można wygenerować żądaną tabelę. Wydaje mi się, że ten algorytm jest optymalny zarówno ze względu na przetwarzane wyniki (każdy z nich oglądany jest tylko raz), jak i ze względu na wykonywane zapytania (wykonywane są jednorazowo tylko zbiorcze zapytania: wszystkie testy, wszystkie pytania, wszystkie odpowiedzi).

Podczas transformacji wyników może być użyta funkcja oceniająca (kodująca) odpowiedzi badanych. Za jej dostarczenie odpowiada implementacja klasy o interfejsie Checker. Istnieje możliwość powiązania funkcji oceniającej z rodzajem testu, dzięki czemu podczas prezentacji wyników są one zakodowane w sposób interesujący badacza.

Moduł umożliwia oczywiście wygenerowanie tabeli z przetworzonymi wynikami do pliku tekstowego, który następnie może być analizowany z użyciem programów statystycznych.

5.9. Moduł Object Model

Warstwa pośrednicząca pomiędzy bazą danych a innymi elementami aplikacji została stworzona za pomocą Torque w sposób opisany przeze mnie w rozdziale 4.5. Wszystkie wykorzystywane w systemie tabele bazy danych, oraz funkcjonalności dodane do wygenerowanych przez Torque klas zostały opisane w Dodatku A.

5.10. Dokumentacja techniczna

Zrealizowana przeze mnie aplikacja składa się z ponad dwustu klas, dlatego nie będę opisywał ich wszystkich. Dokumentacja techniczna dla napisanych klas powstała przy pomocy programu Javadoc i znajduje się na dołączonej do pracy płycie w katalogu API. W przypadku ekranów opis klasy wzbogacony został o informacje dotyczące powiązanych z nimi szablonów (np. umieszczane w kontekście obiekty), dzięki czemu wygenerowana dokumentacja stanowi kompletne źródło informacji o napisanej aplikacji.

6. Przykładowe realizacje

6.1. Badanie 1

Pierwszy przykład nie jest tak naprawdę badaniem naukowym, ale pokazuje uniwersalność stworzonego przeze mnie systemu oraz łatwość realizacji typowego zadania.

6.1.1 Opis problemu

Zostałem poproszony o udostępnienie w Internecie testów z egzaminów wstępnych na Wydział Matematyki, Informatyki i Mechaniki Uniwersytetu Warszawskiego. Kandydaci na studia powinni mieć możliwość wybrania zestawu zadań z interesującego ich rocznika. Po wybraniu takiego zestawu, kandydat może poznać treść kolejnych zadań i udzielać na nie odpowiedzi wykorzystując w tym celu strony WWW. Po rozwiązaniu przez kandydata całego testu, powinno nastąpić automatyczne ocenianie udzielonych przez niego odpowiedzi. Uzyskany przez kandydata wynik będzie zaprezentowany na kolejnej stronie. Zadania egzaminacyjne składają się z krótkiego pytania oraz trzech wariantów odpowiedzi. Od osoby rozwiązującej zadanie oczekuje się, że wskaże które z nich są prawdziwe, a które fałszywe.

6.1.2. Analiza problemu

Z przedstawionego opisu, wynika, że problem sprowadza się do zrealizowania testu z pytaniami wielokrotnego wyboru oraz automatycznej oceny takiego testu. Powstałe testy powinny być dostępne dla dowolnych użytkowników sieci Internet.

6.1.3. Realizacja

Test wielokrotnego wyboru znajduje się w napisanej przeze mnie bibliotece podstawowych typów kwestionariuszy. Dzięki temu postawione zadanie można rozwiązać przy pomocy panelu administracyjnego dostępnego dla badaczy. Zdecydowałem, że pytania egzaminacyjne z kolejnych lat, będą przechowywane jako różne wersje tego samego badania.

Utworzyłem nowe badanie o nazwie "Egzaminy Wstępne". Ponieważ egzaminy miały być ogólnodostępne, w sposobie rejestracji do badania ustawiłem opcję pozwalającą na nieautoryzowane korzystanie z badania. Wybór wersji został określony jako dowolny, tak by kandydat mógł samemu wybrać, który z egzaminów chce rozwiązać (każda wersja to egzamin z innego roku). Wprowadziłem również tekst instrukcji wstępnej, w którym umieściłem informacje o tym w jaki sposób należy udzielać odpowiedzi na prezentowane zadania.

Dla każdego egzaminu wstępnego z lat ubiegłych utworzyłem nowy test o typie "Test Wielokrotnego Wyboru - Pełny", który opisuje kwestionariusze z właściwą konstrukcją pytań. Następnie ustaliłem funkcję oceniającą na "Duże i Małe punkty", która odpowiada sposobowi w jaki punktowane są rozwiązania zadań w czasie egzaminu. Dla testów nie definiowałem instrukcji wstępnej, gdyż wspólny tekst instrukcji został powiązany z samym badaniem. Testy oznaczyłem jako "wewnętrzne", a więc widoczne tylko z poziomu tego badania, gdyż nie przewiduję ich użycia w innych badaniach. Rysunki 18 i 19 prezentują wygląd ekranów dla tego badania.

W ten prostu sposób został osiągnięty zamierzony cel. Ewentualna analiza wyników uzyskiwanych przez kandydatów może pozwolić na znalezienie pytań sprawiających największą trudność (choć myślę, że lepiej w tym celu wykorzystać archiwalne wyniki rzeczywistych egzaminów).

Rysunek 18. Ekran prezentujący kandydatom instrukcję wstępną

Rysunek 19. Ekran prezentujący kandydatom pytania z egzaminu

6.2. Badanie 2

Badanie to zostało zaprojektowane przez profesora Janusza Grzelaka i jego współ-pracowników z Wydziału Psychologii Uniwersytetu Warszawskiego.

6.2.1. Opis problemu

Zaprojektowane badanie składa się z kilku zadań. W zadaniu pierwszym badanemu są prezentowane przez krótki czas kolejne ilustracje opatrzone napisami TAK i NIE. Na ilustracjach przedstawione są różne figury geometryczne. Występują na nich małe i duże koła, zakreślone i puste figury, małe i duże litery. Wszystkie ilustracje opatrzone napisem TAK posiadają jakąś wspólną cechę (np. figury były zakreskowane), zaś na tych oznaczonych tekstem NIE cecha ta nie występuje. Zadaniem badanego po obejrzeniu ilustracji jest wskazanie wspólnej dla nich cechy. W pierwszej części badania, uczestnik proszony jest o rozwiązanie kilku takich zadań.

W kolejnej części badania sprawdzany zostaje nastrój badanego. Prezentowane są mu różne stwierdzenia (np. "Podczas wykonywania zadań odczuwałem(am) złość") do których musi się on ustosunkować, zaznaczając na ile się z nimi zgadza (korzystając z liniowej skali).

Kolejnym elementem badania są pytania sprawdzające inteligencję badanego. Uczestnik musi na przykład wybrać z dostępnych odpowiedzi przeciwieństwa podanego słowa, zaznaczyć wniosek będący logiczną konsekwencją zaprezentowanego tekstu itp.

Na zakończenie badany znowu proszony jest o ustosunkowanie się do podanych stwierdzeń poprzez zaznaczenie swojej odpowiedzi na liniowej skali.

Całe badanie występuje w dwóch wersjach. Mają one taki sam przebieg, ale w jednej z nich prezentowane badanemu ilustracje nie mają żadnej wspólnej cechy, przez co uczestnik nie jest w stanie podać poprawnej odpowiedzi. W czasie analizowania wyników tego eksperymentu, porównywane są odpowiedzi osób, które miały szansę na rozwiązanie pierwszego zadania z tymi które były jej pozbawione.

6.2.2. Analiza problemu

Opis badania pozwala na jednoznaczne wyróżnienie testów jakie się na niego składają. Są to: test prezentujący ilustracje, test z liniową skalą badający nastrój, testy wyboru badające inteligencję, test z liniową skalą kończący badanie. Równie naturalne jest wydzielenie z badania dwóch jego wersji, które będą się różniły pomiędzy sobą tylko pierwszym z prezentowanych testów. Głównym problemem może być zrealizowanie zadania z ilustracjami, gdyż przy pomocy języka HTML nie można zapewnić ekspozycji obrazków przez ściśle określony czas.

6.2.3. Realizacja

W przygotowanej przez mnie bibliotece podstawowych typów testów znajdują się oczywiście i takie, które pozwalają na udzielanie odpowiedzi przy pomocy liniowej skali czy poprzez wybór z listy dopuszczalnych możliwości. Główne wyzwanie polega na stworzeniu nowego rodzaju testu, odpowiadającego pierwszej części badania - prezentującej ilustracje badanemu.

Zdecydowałem, że ilustracje będą przechowywane w systemie z użyciem modułu Storage, zaś prezentowane poprzez umieszczony na stronie aplet, który pozwoli na ścisłą kontrolę czasu prezentacji każdego z obrazków.

Stworzyłem klasę SlideQuestion dziedziczącą po ExtendedQuestion, która jest implementacją pytania zawierającego kilka plików graficznych. W klasie tej umieściłem metody pozwalające na ustalanie identyfikatorów obrazków przynależnych do pytania oraz na pobieranie obiektów klasy Item im odpowiadającym. Identyfikatory zasobów związanych z pytaniem zapisywałem na serializowanej liście w tabeli Question_Extenstion.

Następnym etapem pracy było stworzenie nowego szablonu edycji pytania, który pozwoliłby na wybór grafiki dołączanej do pytania. Nie musiałem tworzyć nowej akcji aktualizującej pytanie, gdyż istniejąca już w systemie akcja UpdateQuestion potrafiła zrealizować to zadanie (dzięki metodom ustalającym identyfikatory obrazków dodanym do klasy SlideQuestion).

Poza stworzeniem apletu, który będzie prezentował zawartość pytania w czasie badania, konieczne było jeszcze utworzenie szablonu prezentacji dla tego rodzaju testów, w którym umieściłem odwołanie do właściwego apletu. Był to ostatni etap pracy projektanta nad realizacją tego badania.

Korzystając ze stworzonych klas i szablonów mogłem zdefiniować nowy typ testów: "Pokaz slajdów". W atrybutach tego typu zapisałem informacje o klasie implementującej pytania, szablonie wykorzystywanym w czasie edycji pytania i szablonie prezentującym test badanemu. Od tej chwili w systemie były dostępne wszystkie wymagane przez to badanie rodzaje testów, mogłem więc przystąpić do stworzenia nowych testów, odpowiadających opisanym wcześniej częściom tego badania (pokaz ilustracji, badanie nastrojów, testy na inteligencję). Jako testy o charakterze ogólnym, zostały one udostępnione wszystkim badaczom, dzięki czemu będzie możliwe konstruowanie przy ich pomocy innych eksperymentów naukowych.

Utworzyłem nowe badanie o nazwie "Nastroje" i do jego podstawowej wersji przypisałem właściwe testy oraz ustaliłem kolejność w jakiej mają być prezentowane podczas eksperymentu. Korzystając z funkcji kopiowania wersji, mogłem przygotować kopię podstawowej wersji badania, w której to dokonałem zmiany pierwszego testu. Przy pomocy ekranu pozwalającego na edycję sposobu rejestracji do badania, zdefiniowałem wymagane atrybuty badanych (płeć, wykształcenie, wiek) oraz określiłem wybór wersji na losowy (tak by podobna liczba osób mogła brać udział w obu wersjach badania). W ten sposób uzyskałem badanie realizujące postawiony przez psychologów cel. Rysunki 20, 21 i 22 prezentują ekrany pochodzące z tego badania.

Rysunek 20. Przykładowe pytanie obrazkowe

Rysunek 21. Ekran prezentujący pytania o nastrój

Rysunek 22. Ekran prezentujący wyniki badania

7. Ocena przydatności Turbiny

Doświadczenie, które zdobyłem podczas pisania tej pracy pozwala mi na stwierdzenie, że Turbina jest znakomitym środowiskiem tworzenia aplikacji internetowych. Postaram się opisać zarówno największe zalety, jak i niedogodności tego narzędzia.

7.1. Zalety Turbiny

Znakomitym pomysłem twórców Turbiny był zaproponowany przez nich model logiczny oparty na akcjach i ekranach. Ten podział doskonale pasuje do specyfiki aplikacji internetowych i powoduje, że tworzone aplikacje mają przejrzystą budowę. Takie rozwiązanie uważam za dużo lepsze niż standardowe podejście stosowane na przykład na stronach JSP, gdzie początkowy kod strony odpowiedzialny jest za rozpoznanie żądania klienta, jego realizację i ewentualne prze-kierowanie do kolejnych stron. Metodologia tworzenia aplikacji internetowych korzystających z ekranów i akcji pozwala na wyraźne rozdzielenie elementów odpowiadających za zmianę stanu systemu od części wizualizujących ten stan.

To rozwiązanie ma oczywiście i swoje wady. Sposób pakietowania klas wprowadzony w Turbinie, w którym akcje muszą się znajdować w podpakietach modules.actions, a ekrany w modules.screens, powoduje, że klasy odpowiedzialne za implementację jednej funkcjonalności nie znajdują się w tym samym pakiecie (należy jednak pamiętać, że mają one wyznaczone inne role w aplikacji). Ponieważ najczęściej ekran prezentuje cechy jakiegoś obiektu, zaś akcja je modyfikuje, to by zwiększyć wydajność systemu, obiekt ten umieszcza się najczęściej w sesji użytkownika. Powoduje to powstanie niejawnej komunikacji pomiędzy ekranem a akcją, co może czasem zmniejszać czytelność kodu.

Podział warstwy prezentacji na klasy implementujące ekrany i szablony generujące kod w HTML to kolejna niewątpliwa zaleta Turbiny. Tę aplikację tworzyłem samodzielnie, przez co nie mogłem docenić podstawowej korzyści z takiego rozwiązania, jaką jest niezależna praca nad częścią wizualną i funkcjonalną programu. Wiem jednak o komercyjnych zastosowaniach Turbiny, w których za warstwę prezentacji tworzonych projektów byli odpowiedzialni webmasterzy pracujący równolegle z programistami implementującymi logikę aplikacji.

Kolejnym atutem Turbiny jest Torque pozwalający na generowanie obiektowej reprezentacji bazy danych. Nie będę powtarzał opisanych w poświęconym Torquowi rozdziale 4.5 zalet takiego sposobu dostępu do danych. Podkreślę jednak jeszcze raz łatwość z jaką można stworzyć szkielet (prototyp) aplikacji. Mając wygenerowane obiekty odpowiadające tabelom w bazie danych, wystarczy umieścić je w kontekście ekranów i na ich podstawie wygenerować właściwe formularze. Następnie w treści akcji można dokonać zmian w systemie, wołając metodę setProperties(obiekt) z RunData, a potem metodę save tego obiektu. Taka podstawowa wersja aplikacji pozwala na sprawdzenie funkcjonalności zaprojektowanych rozwiązań i umożliwia stworzenie pełnego systemu przez krokowe uzupełnianie istniejącego szkieletu (przede wszystkim o walidację danych, czy optymalizowanie dostępu do danych).

W przypadku aplikacji tworzonych z pomocą Turbiny faza projektowania może ograniczyć się tylko do zdefiniowania struktury danych oraz wymaganych funkcjonalności. Opis struktury danych pozwoli bowiem na wygenerowanie obiektów biznesowych, zaś specyfikacja funkcjonalna doskonale przekłada się na ekrany i akcje.

Również inne elementy Turbiny, takie jak Cache Service, Scheduler Service, Logging Service oraz zaimplementowany system bezpieczeństwa, skracają czas tworzenia szkieletu aplikacji i ułatwiają jego późniejszą modyfikację.

7.2. Wady Turbiny

Nie są to w istocie wady, ale raczej niedociągnięcia wywołane brakiem pewnych funkcjonalności lub niewygodą istniejących rozwiązań.

Elementem Turbiny, który może budzić największe zastrzeżenia, jest system bezpieczeństwa. Nieintuicyjne pojęcie grupy wprowadzone w systemie bezpieczeństwa Turbiny uważam za naprawdę zły pomysł. Nie widzę żadnej przewagi takiego rozwiązania nad klasycznym podejściem, w którym modeluje się użytkownika, grupę użytkowników oraz ich role i prawa. Ponadto brakuje jakiegokolwiek wsparcia w zakresie ograniczania dostępu do samych zasobów, które moim zdaniem jest konieczne w prawie każdej aplikacji

Choć w Turbinie można implementować własne rozwiązania odpowiedzialne za system bezpieczeństwa, to zbyt mało ogólne interfejsy elementów tego systemu uniemożliwiają wykonanie tego w sposób wygodny dla programisty. Bo cóż z tego, że można stworzyć własne klasy implementujące użytkownika, jego ACL czy Security Service, jeśli nie można korzystać z nich w aplikacji w sposób przezroczysty i konieczne jest ciągłe rzutowanie.

Zawarty w Turbinie Intake Service mający umożliwiać automatyczną walidację formularzy, jest narzędziem zupełnie nieużytecznym. Ilość pracy konieczna do zdefiniowania elementów, które miałyby być poddane walidacji, oraz do umieszczenia kodu odpowiadającego za ten proces, jest porównywalna do wysiłku jaki trzeba włożyć przy ręcznej implementacji takiej funkcjonalności. Wydaje mi się, że to Torque powinien być rozszerzony o tą cechę. Mógłby on generować na przykład takie implementacje obiektów biznesowych, które sprawdzają odpowiednie warunki w metodach ustawiających wartości ich atrybutów (oraz tworzyć polecenia SQL z właściwymi dla danej bazy danych więzami integralności). Ponadto brakuje wsparcia dla automatycznego przeładowywania ekranów z błędnie wypełnionymi formularzami.

Choć Turbina ma swoją oficjalną dystrybucję w wersji 2.1, to wydaje się, że jest ona ciągle narzędziem przeznaczonym głównie dla grona osób je rozwijających. W czasie pisania aplikacji wielokrotnie musiałem bowiem czytać źródła Turbiny, naprawiać znalezione w nich drobne błędy, konieczna była również modyfikacja szablonów Torque. Myślę, że rozwiązanie napotykanych problemów było możliwe głównie dlatego, że byłem zaangażowany w rozwój tego narzędzia i dobrze znałem jego budowę.

Pomimo tych niedogodności szczerze polecam Turbinę jako środowisko tworzenia aplikacji internetowych, zwłaszcza w sytuacji gdy planowana jest realizacja kilku projektów. W takim bowiem przypadku wkład pracy włożony w poznanie tego środowiska, procentuje przy kolejnych wdrożeniach. Ponadto możliwe jest wielokrotne wykorzystanie przygotowanych wcześniej rozwiązań, narzędzi i rozszerzeń Turbiny.

7.3. Przyszłość Turbiny

Aktualnie trwają prace nad wersja 3.0 Turbiny. W wersji tej wprowadzono inny model logiczny aplikacji oparty na potokach (ang. pipeling), podobnie jak ma to miejsce w Cocoonie. Nie jestem zwolennikiem takiego rozwiązania. Utracono bowiem w ten sposób, największą moim zdaniem zaletę Turbiny - wyróżnienie akcji i ekranu. Ponadto aplikacje stworzone w Turbinie wersji 2 nie będą mogły działać z Turbiną wersji 3, choć twórcy zapewniają, że powstaną narzędzia ułatwiające migracje aplikacji do nowszej wersji.

8. Podsumowanie

W ramach projektu magisterskiego udało mi się stworzyć środowisko umożliwiające projektowanie i prowadzenie badań w naukach społecznych z użyciem komputera i sieci Internet. Napisana przeze mnie aplikacja nie posiada żadnych odpowiedników ani w postaci komercyjnych rozwiązań, ani ogólnie dostępnych projektów. Wymienię najważniejsze osiągnięcia mojej pracy.

Ponadto do budowy środowiska wykorzystałem jedynie darmowe narzędzia i technologie.

Implementując aplikację WASS zrealizowałem wszystkie założone cele. Mam nadzieję, że stworzony przeze mnie system podniesie komfort pracy korzystającym z niego naukowcom.

Dodatek A
Model danych

Poniżej znajduje się opis wykorzystywanych przez system tabel baz danych, oraz funkcjonalności dodanych do odpowiadającym im równoważnikom i sepulkom.

Tabela Answer

Przechowuje powiązane z pytaniem zbiory dozwolonych odpowiedzi. Umożliwia realizację na przykład testów wyboru lub przechowywanie poprawnych odpowiedzi na pytania otwarte.

Kolumna

Typ

Opis

id

Identyfikator

Identyfikator odpowiedzi. Obecny po to, by ułatwić aktualizacje.

question_id

Klucz obcy

Identyfikator pytania, do którego należy odpowiedź (w tabeli Question).

sequence

Integer

Kolejność na liście odpowiedzi.

text

Text

Treść odpowiedzi.

Dodane funkcjonalności:

Tabela Correct_Answer

Pozwala na ustalenie, które z powiązanych z pytaniem odpowiedzi należą do zbioru poprawnych. Tabela jest potrzebna do realizacji automatycznego oceniania testów.

Kolumna

Typ

Opis

question_id

Klucz zewn.

Identyfikator pytania, którego poprawna odpowiedź jest opisywana (tabele Question). Ta kolumna jest redundantna; pojawia się by uprościć operacje na bazie danych.

answer_id

Klucz zewn.

Identyfikator poprawnej odpowiedzi (tabela Answer).

Brak dodanych funkcjonalności.

Tabela Item

W tabeli tej są przechowywane informacje o zasobach plikowych zgromadzonych w systemie.

Kolumna

Typ

Opis

id

Identyfikator

Identyfikuje zasób.

shelf_id

Klucz obcy

Identyfikator półki, na której znajduje się zasób (tabela Shelf).

name

Text

Nazwa zasobu.

file_name

Text

Nazwa pliku jaki odpowiada zasobowi na dysku.

Dodane funkcjonalności:

Tabela Question

Przechowuje informacje potrzebne do odtworzenia pytania. Jest to podstawowa tabela służąca do wypełniania testów treścią.

Kolumna

Typ

Opis

id

Identyfikator

Identyfikuje pytanie.

test_id

Klucz obcy

Identyfikator testu, do którego należy pytanie (tabela Test).

sequence

Integer

Kolejność pytania w teście.

type

Integer

Służy do rozróżniania klas implementujących dany rodzaj pytania.

text

Text

Treść pytania.

Dodane funkcjonalności:

Tabela Question_Extension

Tabela umożliwia przechowywanie danych powiązanych z pytaniem, które zależą od konkretnej implementacji pytania. Dzięki obecności tej tabeli w systemie, będzie możliwe tworzenie pytań zawierających dowolne elementy poza zwykłym tekstem pytania.

Kolumna

Typ

Opis

question_id

Klucz zewn.

Identyfikator pytania, z którym powiązane są dane.

item_id

Klucz obcy

Identyfikator zasobu (tabela Item). Pytania najczęściej zależeć będą właśnie od jakiegoś zasobu, dlatego została wprowadzona ta kolumna.

data

Binaria

W tej kolumnie będą mogły być serializowane atrybuty pytań wykraczające poza możliwości oferowane przez tabelę Question.

Dodane funkcjonalności:

 

Tabela Research

Umożliwia identyfikację badań i przechowuje ich podstawowe atrybuty.

Kolumna

Typ

Opis

id

Identyfikator

Identyfikator badania.

security_id

Klucz obcy

Identyfikator obiektu opisującego bezpieczeństwo dla tego badania (tabela SecurityObj).

name

Text

Nazwa badania.

purpose

Text

Cel w jakim stworzono badanie.

description

Text

Opis badania.

modified

Date

Data ostatniej modyfikacji.

modified_by

Klucz obcy

Użytkownik dokonujący ostatniej modyfikacji.

created

Date

Data utworzenia.

created_by

Klucz obcy

Użytkownik, który przygotował badanie.

Dodane funkcjonalności:

Tabela Research_Content

Tabela ta umożliwia przechowywanie informacji o testach przypisanych do danej wersji badania. Jej stworzenie było konieczne, ponieważ w każdej wersji badania ten sam test może wystąpić więcej niż raz.

Kolumna

Typ

Opis

id

Identyfikator

Wykorzystywany przy przechowywaniu wyników.

research_id

Klucz obcy

Identyfikator badania (tabela Research).

version_id

Klucz obcy

Identyfikator wersji badania (tabela Research_Version).

sequence

Integer

Kolejność testu w badaniu.

test_id

Klucz obcy

Identyfikator testu (tabela Test).

Dodane funkcjonalności:

Tabela Research_Instruction

Tabela wiąże z badaniem jego instrukcje wstępne.

Kolumna

Typ

Opis

id

Identyfikator

Identyfikator instrukcji (wprowadzony by ułatwić operacje na bazie danych).

research_id

Klucz obcy

Identyfikator badania (tabela Research).

sequence

Integer

Kolejność instrukcji.

text

Text

Treść instrukcji.

Brak dodanych funkcjonalności.

Tabela Research_Registration

W tej tabeli przechowywane są informacje o sposobie rejestracji do badania - czyli jakie informacje musi podać użytkownik i w jaki sposób będzie wybierana wersja badania.

Kolumna

Typ

Opis

id

Identyfikator

Wprowadzony by ułatwić operacje na bazie.

research_id

Klucz obcy

Identyfikator badania, którego opis rejestracji jest przechowywany (tabela Research).

mask

Integer

Maska bitowa kodująca jakie informacje są wymagane od badanego (wiek, płeć).

version_method

Integer

Maska bitowa kodująca sposób wyboru wersji.

Dodane funkcjonalności:

Tabela Research_Session

Ta tabela umożliwia identyfikowanie rozpoczętych badań. Wiąże z prowadzonym badaniem informacje o użytkowniku oraz umożliwia identyfikację udzielanych odpowiedzi. Jej stworzenie było konieczne, ponieważ większość badań będzie prowadzona z anonimowymi badanymi, a ponadto ten sam użytkownik może wielokrotnie brać udział w badaniu, a każda taka próba musi być opisywana niezależnie.

Kolumna

Typ

Opis

id

Identyfikator

Konieczny przy opisie odpowiedzi badanego.

research_id

Klucz obcy

Identyfikator rozpoczętego badania (tabela Research). Jest redundantny ponieważ wystar-czyłby identyfikator wersji, ale jego obecność ułatwia operacje na bazie danych.

version_id

Klucz obcy

Identyfikator wersji, która została przypisana do tego badania (tabela Research_Version).

date

Date

Data badania.

age

Integer

Wiek badanego. Najczęściej używane atrybuty są zapisywane w kolejnych kolumnach.

sex

Text

Płeć badanego.

Institution

Text

Miejsce zatrudnienia.

Education

Text

Wykształcenie badanego.

Occupation

Text

Zawód badanego.

Brak dodanych funkcjonalności.

Tabela Resarch_Version

Tabela pozwala na zdefiniowanie badań, które zawierają w sobie kilka wersji (np. różniących się od siebie jednym testem).

Kolumna

Typ

Opis

id

Identyfikator

Wykorzystywany przy przypisywaniu testów.

research_id

Klucz obcy

Identyfikator badania, do którego należy wersja (tabela Research).

name

Text

Nazwa wersji.

descrption

Text

Opis wersji.

Dodane funkcjonalności:

Tabela Result

W tej tabeli umieszczane są odpowiedzi badanego. Można w niej przechowywać odpowiedzi zarówno dla testów wyboru, jak i dla pytań otwartych.

Kolumna

Typ

Opis

id

Identyfikator

Identyfikator odpowiedzi.

session_id

Klucz obcy

Informacja o tym do jakiej instancji badania należy odpowiedź (tabela Research_Session).

content_id

Klucz obcy

Pozwala na rozróżnienie odpowiedzi na to samo pytania w różnych instancjach tego samego testu (tabela Research_Content).

question_id

Klucz obcy

Identyfikator pytania (tabela Question).

answer_id

Klucz obcy

Identyfikator odpowiedzi, jeśli był to test wyboru (tabela Answer).

value

Text

Odpowiedź na pytanie otwarte.

Brak dodanych funkcjonalności.

Tabela Security

Tabela pozwala na przypisywanie użytkownikowi ról w kontekście danego obiektu. Wykorzystywana jest przez moduł Security.

Kolumna

Typ

Opis

id

Identyfikator

Ułatwia operacje na bazie danych.

security_id

Klucz obcy

Identyfikuje obiekt, dla którego została zdefiniowana rola (tabela Security_Obj).

user

Klucz obcy

Identyfikuje użytkownika, któremu w kontekście danego obiektu została przyznana rola (tabela Turbine_User).

role

Klucz obcy

Nazwa przyznanej roli (tabela Turbine_Role).

Brak dodanych funkcjonalności.

Tabela Security_Obj

Dzięki tej tabeli możliwe było jednakowe traktowanie wszystkich obiektów, do których dostęp limitowany jest na poziomie zasobu. Z każdym takim obiektem wiązany jest odpowiadający mu obiekt przechowywany właśnie w tej tabeli, dzięki temu w systemie bezpieczeństwa nie ma potrzeby niezależnego analizowania badań czy testów.

Kolumna

Typ

Opis

id

Identyfikator

Identyfikuje obiekt opisujący bezpieczeństwo. Jest kluczem obcym dla tabeli Security wiążącej z nim role przyznane użytkownikom oraz dla tabel Test czy Research.

type

Integer

Pozwala na stwierdzenie czy obiekt odnosi się do badania, testu, czy półki.

Dodane funkcjonalności są odpowiedzialne za implementacje dostępu na poziomie zasobu. Są to między innymi:

Tabela Shelf

Umożliwia grupowanie zasobów dyskowych w zbiory oraz niezależne administrowanie takimi zbiorami.

Kolumna

Typ

Opis

id

Itentyfikator

Identyfikator półki.

security_id

Klucz obcy

Identyfikator obiektu opisującego dostęp do półki (tabela SecurityObj).

name

Text

Nazwa półki.

description

Text

Opis przeznaczenia półki.

Dodane funkcjonalności:

Tabela Test

Tabela przechowuje atrybuty testów umożliwiając ich identyfikację.

Kolumna

Typ

Opis

id

Identyfikator

Identyfikator testu.

type_id

Klucz obcy

Rodzaj testu (tabela Test_Type).

security_id

Klucz obcy

Identyfikator obiektu opisującego dostęp do testu (tabela Security_Obj).

mask

Integer

Maska bitowa z atrybutami testu.

modified

Date

Data ostatniej modyfikacji.

modified_by

Klucz obcy

Użytkownik dokonujący ostatniej modyfikacji.

created

Date

Data utworzenia.

created_by

Klucz obcy

Użytkownik, który stworzył test.

style

Text

Styl testu.

name

Text

Nazwa testu.

check_function

Text

Funkcja oceniająca.

description

Text

Opis testu.

Dodane funkcjonalności:

Tabela Test_Instruction

W tabeli znajdują się instrukcje wstępne testów.

Kolumna

Typ

Opis

id

Identyfikator

Identyfikator instrukcji.

test_id

Klucz obcy

Identyfikator testu, do którego należy instrukcja (tabela Test).

sequence

Integer

Kolejność instrukcji.

text

Text

Treść instrukcji.

Brak dodanych funkcjonalności.

Tabela Test_Type

Dzięki tej tabeli możliwe jest tworzenie rodzajów testów opisujących sposób tworzenia i prezentacji testu.

Kolumna

Typ

Opis

id

Identyfikator

Identyfikator typu testu.

name

Text

Nazwa typu.

description

Text

Opis przeznaczenia i charakterystyki typu.

modified

Date

Data ostatniej modyfikacji.

modified_by

Klucz obcy

Użytkownik dokonujący ostatniej modyfikacji.

created

Date

Data utworzenia.

created_by

Klucz obcy

Użytkownik który stworzył typ.

mask

Integer

Maska bitowa z atrybutami typu.

questions_number

Integer

Liczba pytań na stronie.

test_edit_tmpl

Text

Szablon edycji testu.

test_show_tmpl

Text

Szablon prezentacji testu.

test_class

Text

Klasa implementująca test.

test_show_class

Text

Klasa implementująca ekran do prezentacji testu.

Brak dodanych funkcjonalności.

Tabele Turbiny

W aplikacji wykorzystywane są również tabele charakterystyczne dla Turbiny. Ponieważ nie były one przeze mnie modyfikowane, więc ograniczę się do ich wymienienia:

Dodatek B
Zawartość płyty

Do pracy dołączyłem płytę CD-ROM, na której poza aplikacją WASS i jej kodem źródłowym umieściłem wszystkie narzędzia konieczne do poprawnej instalacji systemu na platformach Linux i Windows. Szczegółowy opis procesu instalacji znajduje się w pliku Readme.txt. Poniżej przedstawiam zawartość płyty:

Struktura katalogów aplikacji WASS

W poddrzewie webapps, katalogu Turbine znajduje się katalog msc zawierający wszystkie elementy składowe aplikacji WASS. Katalog ma następującą strukturę:

Bibliografia

[1] Strona domowa projektu Turbine,
http://jakarta.apache.org/turbine/

[2] Strona domowa World Wide Web Consortium,
http://www.w3.org/

[3] Strona domowa języka HTML,
http://www.w3.org/MarkUp/
Specyfikacja języka HTML 4.01,
http://www.w3.org/TR/html4/

[4] Opis języka Javascript,
http://wp.netscape.com/eng/mozilla/3.0/handbook/javascript/

[5] Specyfikacja Hypertext Transfer Protocol -- HTTP/1.1,
http://www.ietf.org/rfc/rfc2068.txt

[6] Specyfikacja standardu SSL 3.0,
http://home.netscape.com/eng/ssl3/

[7] Opis modelu MVC,
http://java.sun.com/blueprints/patterns/MVC-detailed.html

[8] Strona domowa języka PHP,
http://www.php.net/;
L. Atkinson, PHP 3, 2000, Helion

[9] Strona domowa produktu PHP Accelerator Cache,
http://www.php-accelerator.co.uk/

[10] Zend Accelerator, galeria kodu, tutoriale itp.,
http://www.zend.com

[11] Przewodnik po ASP,
http://msdn.microsoft.com/library/default.asp?URL=/library/psdk/iisref/aspguide.htm

[12] Strona domowa kontrolek ActiveX,
http://www.microsoft.com/com/tech/ActiveX.asp

[13] Strona domowa języka VBScript,
http://msdn.microsoft.com/scripting/vbscript/default.asp

[14] Porównanie języka JavaScript i JScript,
http://www.javacats.com/US/articles/Jsart.html

[15] Strona domowa firmy Microsoft,
www.microsoft.com

[16] D. J. Reilly, Designing Microsoft ASP.NET Applications, 2001, Microsoft Press.

[17] Strona domowa technologii Java,
http://java.sun.com/

[18] Strona domowa Java 2 Platform, Enterprise Edition,
http://java.sun.com/j2ee/

[19] Opis serwletów,
http://java.sun.com/products/servlet/index.html

[20] Strona domowa serwera Tomcat,
http://jakarta.apache.org/tomcat/

[21] Strona domowa standardu CGI,
http://www.w3.org/CGI/

[22] Strona domowa JSP,
http://java.sun.com/products/jsp/

[23] Opis Modelu 2 dla aplikacji JSP,
http://www.javaworld.com/javaworld/jw-12-1999/jw-12-ssj-jspmvc.html

[24] Strona domowa programu JBuilder,
http://www.borland.com/jbuilder

[25] Strona domowa EJB,
http://java.sun.com/products/ejb/

[26] Strona domowa serwerów aplikacji firmy IBM,
http://www.ibm.com/software/webservers/

[27] Strona domowa technologii .NET,
http://www.microsoft.com/net/

[28] Opis technologii APS.NET,
http://msdn.microsoft.com/library/default.asp?url=/nhp/Default.asp?contentid=28000440

[29] Strona domowa grupy Jakarta,
http://jakarta.apache.org/

[30] Strona domowa narzędzia Webmacro,
http://www.webmacro.org/

[31] Strona domowa narzędzia Velocity,
http://jakarta.apache.org/velocity/

[32] Strona domowa narzędzia Cocoon,
http://xml.apache.org/cocoon/

[33] Strona domowa serwera Apache,
http://httpd.apache.org/

[34] Strona domowa standardu Cascading Style Sheets,
http://www.w3.org/Style/CSS/

[35] Strona domowa serwera MySQL,
http://www.mysql.com/

Zielu